make things a bit less ugly

This commit is contained in:
Nils 2023-02-07 19:17:30 +01:00
parent c6ffa0e628
commit 6c7564062f
Signed by: byreqz
GPG Key ID: 396A62D7D436749E
2 changed files with 56 additions and 58 deletions

View File

@ -77,6 +77,7 @@ https://[address]/[command]/[host](_[port]),[host].../[options]
- ping - ping
- mtr - mtr
- traceroute - traceroute
- nping
- [host] = can be one or more hosts query, seperated by a comma - [host] = can be one or more hosts query, seperated by a comma
- [port] = port to be queried, optional - [port] = port to be queried, optional
- [options] = options to run the command with, seperated by a comma - [options] = options to run the command with, seperated by a comma

113
main.go
View File

@ -13,78 +13,70 @@ import (
flag "github.com/spf13/pflag" flag "github.com/spf13/pflag"
) )
var logstdout = log.New() var logStdout = log.New()
var logfile = log.New() var logFile = log.New()
var listenport int var listenPort = 8080 // port to listen on
var disablexforwardedfor bool var disableXForwardedFor bool // whether to disable parsing the X-Forwarded-For header or not
var allowprivate bool var allowPrivate bool // whether to allow private IP ranges or not
func init() { func init() {
logstdout.SetFormatter(&log.TextFormatter{ logStdout.SetFormatter(&log.TextFormatter{
FullTimestamp: true}) FullTimestamp: true})
logstdout.SetOutput(os.Stdout) logStdout.SetOutput(os.Stdout)
logstdout.SetLevel(log.InfoLevel) logStdout.SetLevel(log.InfoLevel)
var logfilepath string
if _, exists := os.LookupEnv("PROBEHOST_LOGPATH"); exists { logFilePath := "probehost2.log"
logfilepath, _ = os.LookupEnv("PROBEHOST_LOGPATH") if val, exists := os.LookupEnv("PROBEHOST_LOGPATH"); exists {
} else { logFilePath = val
logfilepath = "probehost2.log"
} }
if exists, _ := os.LookupEnv("PROBEHOST_ALLOW_PRIVATE"); exists == "true" {
allowprivate = true _, allowPrivate = os.LookupEnv("PROBEHOST_ALLOW_PRIVATE")
} else { _, disableXForwardedFor = os.LookupEnv("PROBEHOST_DISABLE_X_FORWARDED_FOR")
allowprivate = false
} if val, exists := os.LookupEnv("PROBEHOST_LISTEN_PORT"); exists {
if envvalue, exists := os.LookupEnv("PROBEHOST_LISTEN_PORT"); exists {
var err error var err error
listenport, err = strconv.Atoi(envvalue) listenPort, err = strconv.Atoi(val)
if err != nil { if err != nil {
logstdout.Fatal("Failed to read PROBEHOST_LISTEN_PORT: ", err.Error()) logStdout.Fatal("Failed to read PROBEHOST_LISTEN_PORT: ", err.Error())
} }
} else {
listenport = 8000
} }
if exists, _ := os.LookupEnv("PROBEHOST_DISABLE_X_FORWARDED_FOR"); exists == "true" {
disablexforwardedfor = true flag.StringVarP(&logFilePath, "logFilePath", "o", logFilePath, "sets the output file for the log")
} else { flag.IntVarP(&listenPort, "port", "p", listenPort, "sets the port to listen on")
disablexforwardedfor = false flag.BoolVarP(&disableXForwardedFor, "disable-x-forwarded-for", "x", disableXForwardedFor, "whether to show x-forwarded-for or the requesting IP")
} flag.BoolVarP(&allowPrivate, "allow-private", "l", allowPrivate, "whether to show lookups of private IP ranges")
flag.StringVarP(&logfilepath, "logfilepath", "o", logfilepath, "sets the output file for the log")
flag.IntVarP(&listenport, "port", "p", listenport, "sets the port to listen on")
flag.BoolVarP(&disablexforwardedfor, "disable-x-forwarded-for", "x", disablexforwardedfor, "whether to show x-forwarded-for or the requesting IP")
flag.BoolVarP(&allowprivate, "allow-private", "l", allowprivate, "whether to show lookups of private IP ranges")
flag.Parse() flag.Parse()
logpath, err := os.OpenFile(logfilepath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0660) logpath, err := os.OpenFile(logFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0660)
if err != nil { if err != nil {
logstdout.Fatal("Failed to initialize the logfile: ", err.Error()) logStdout.Fatal("Failed to initialize the logFile: ", err.Error())
} }
logfile.SetLevel(log.InfoLevel) logFile.SetLevel(log.InfoLevel)
logfile.SetOutput(logpath) logFile.SetOutput(logpath)
logfile.Info("probehost2 initialized") logFile.Info("probehost2 initialized")
} }
// runner runs the given command with the given args and returns stdout as string. Also logs all executed commands and their exit state.
func runner(remoteip string, command string, args ...string) string { func runner(remoteip string, command string, args ...string) string {
logfile.WithFields(log.Fields{ logFile.WithFields(log.Fields{
"remote_ip": remoteip, "remote_ip": remoteip,
"command": fmt.Sprint(command, args), "command": fmt.Sprint(command, args),
}).Info("request initiated:") }).Info("request initiated:")
cmd, err := exec.Command(command, args...).Output() cmd, err := exec.Command(command, args...).Output()
if err != nil { if err != nil {
logstdout.WithFields(log.Fields{ logStdout.WithFields(log.Fields{
"remote_ip": remoteip, "remote_ip": remoteip,
"command": fmt.Sprint(command, args), "command": fmt.Sprint(command, args),
"error": err.Error(), "error": err.Error(),
}).Warn("request failed:") }).Warn("request failed:")
logfile.WithFields(log.Fields{ logFile.WithFields(log.Fields{
"remote_ip": remoteip, "remote_ip": remoteip,
"command": fmt.Sprint(command, args), "command": fmt.Sprint(command, args),
"error": err.Error(), "error": err.Error(),
}).Warn("request failed:") }).Warn("request failed:")
} else { } else {
logfile.WithFields(log.Fields{ logFile.WithFields(log.Fields{
"remote_ip": remoteip, "remote_ip": remoteip,
"command": fmt.Sprint(command, args), "command": fmt.Sprint(command, args),
}).Info("request succeeded:") }).Info("request succeeded:")
@ -92,20 +84,21 @@ func runner(remoteip string, command string, args ...string) string {
return string(cmd) return string(cmd)
} }
// validatehosts checks the given host+port combinations for validity and returns valid hosts + valid ports seperately.
func validatehosts(hosts []string) ([]string, []string) { func validatehosts(hosts []string) ([]string, []string) {
var validhosts []string var validHosts []string
var validports []string var validPorts []string
for _, host := range hosts { for _, host := range hosts {
split := strings.Split(host, "_") split := strings.Split(host, "_")
host = split[0] host = split[0]
if hostparse := net.ParseIP(host); hostparse != nil { if hostparse := net.ParseIP(host); hostparse != nil {
if (net.IP.IsPrivate(hostparse) || net.IP.IsLoopback(hostparse)) && allowprivate { if (net.IP.IsPrivate(hostparse) || net.IP.IsLoopback(hostparse)) && allowPrivate {
validhosts = append(validhosts, host) validHosts = append(validHosts, host)
} else if !(net.IP.IsPrivate(hostparse) || net.IP.IsLoopback(hostparse)) { } else if !(net.IP.IsPrivate(hostparse) || net.IP.IsLoopback(hostparse)) {
validhosts = append(validhosts, host) validHosts = append(validHosts, host)
} }
} else if _, err := net.LookupIP(host); err == nil { } else if _, err := net.LookupIP(host); err == nil {
validhosts = append(validhosts, host) validHosts = append(validHosts, host)
} else { } else {
continue continue
} }
@ -115,17 +108,18 @@ func validatehosts(hosts []string) ([]string, []string) {
port = split[1] port = split[1]
_, err := strconv.Atoi(port) // validate if port is just an int _, err := strconv.Atoi(port) // validate if port is just an int
if err == nil { if err == nil {
validports = append(validports, port) validPorts = append(validPorts, port)
} else { } else {
validports = append(validports, "0") validPorts = append(validPorts, "0")
} }
} else { } else {
validports = append(validports, "0") validPorts = append(validPorts, "0")
} }
} }
return validhosts, validports return validHosts, validPorts
} }
// parseopts matches the given user options to the valid optionmap.
func parseopts(options []string, cmdopts map[string]string) []string { func parseopts(options []string, cmdopts map[string]string) []string {
var opts []string var opts []string
for _, opt := range options { for _, opt := range options {
@ -134,6 +128,7 @@ func parseopts(options []string, cmdopts map[string]string) []string {
return opts return opts
} }
// prerunner processes the incoming request to send it to runner.
func prerunner(req *http.Request, cmd string, cmdopts map[string]string, defaultopts []string) string { func prerunner(req *http.Request, cmd string, cmdopts map[string]string, defaultopts []string) string {
geturl := strings.Split(req.URL.String(), "/") geturl := strings.Split(req.URL.String(), "/")
targets := strings.Split(geturl[2], ",") targets := strings.Split(geturl[2], ",")
@ -146,11 +141,9 @@ func prerunner(req *http.Request, cmd string, cmdopts map[string]string, default
} }
var res string var res string
var args []string var args []string
var remoteaddr string remoteaddr := req.RemoteAddr
if req.Header.Get("X-Forwarded-For") != "" && !disablexforwardedfor { if req.Header.Get("X-Forwarded-For") != "" && !disableXForwardedFor {
remoteaddr = req.Header.Get("X-Forwarded-For") remoteaddr = req.Header.Get("X-Forwarded-For")
} else {
remoteaddr = req.RemoteAddr
} }
for i, host := range hosts { for i, host := range hosts {
runargs := append(args, opts...) runargs := append(args, opts...)
@ -163,6 +156,7 @@ func prerunner(req *http.Request, cmd string, cmdopts map[string]string, default
return res return res
} }
// ping is the response handler for the ping command. It defines the allowed options.
func ping(w http.ResponseWriter, req *http.Request) { func ping(w http.ResponseWriter, req *http.Request) {
cmd := "ping" cmd := "ping"
cmdopts := map[string]string{ cmdopts := map[string]string{
@ -179,6 +173,7 @@ func ping(w http.ResponseWriter, req *http.Request) {
} }
} }
// mtr is the response handler for the mtr command. It defines the allowed options.
func mtr(w http.ResponseWriter, req *http.Request) { func mtr(w http.ResponseWriter, req *http.Request) {
cmd := "mtr" cmd := "mtr"
cmdopts := map[string]string{ cmdopts := map[string]string{
@ -195,6 +190,7 @@ func mtr(w http.ResponseWriter, req *http.Request) {
} }
} }
// traceroute is the response handler for the traceroute command. It defines the allowed options.
func traceroute(w http.ResponseWriter, req *http.Request) { func traceroute(w http.ResponseWriter, req *http.Request) {
cmd := "traceroute" cmd := "traceroute"
cmdopts := map[string]string{ cmdopts := map[string]string{
@ -211,6 +207,7 @@ func traceroute(w http.ResponseWriter, req *http.Request) {
} }
} }
// nping is the response handler for the nping command. It defines the allowed options.
func nping(w http.ResponseWriter, req *http.Request) { func nping(w http.ResponseWriter, req *http.Request) {
cmd := "nping" cmd := "nping"
cmdopts := map[string]string{ cmdopts := map[string]string{
@ -233,7 +230,7 @@ func main() {
http.HandleFunc("/tracert/", traceroute) http.HandleFunc("/tracert/", traceroute)
http.HandleFunc("/traceroute/", traceroute) http.HandleFunc("/traceroute/", traceroute)
http.HandleFunc("/nping/", nping) http.HandleFunc("/nping/", nping)
logstdout.Info("Serving on :", listenport) logStdout.Info("Serving on :", listenPort)
logfile.Info("Serving on :", listenport) logFile.Info("Serving on :", listenPort)
_ = http.ListenAndServe(fmt.Sprint(":", listenport), nil) _ = http.ListenAndServe(fmt.Sprint(":", listenPort), nil)
} }