131 lines
3.2 KiB
Go
131 lines
3.2 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"os/exec"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/google/shlex"
|
|
)
|
|
|
|
func tracerouteArgsToString(cmd string, args []string, target []string) string {
|
|
var cmdCombined = append([]string{cmd}, args...)
|
|
cmdCombined = append(cmdCombined, target...)
|
|
return strings.Join(cmdCombined, " ")
|
|
}
|
|
|
|
func tracerouteTryExecute(cmd string, args []string, target []string) ([]byte, error) {
|
|
instance := exec.Command(cmd, append(args, target...)...)
|
|
output, err := instance.CombinedOutput()
|
|
if err == nil {
|
|
return output, nil
|
|
}
|
|
|
|
return output, err
|
|
}
|
|
|
|
func tracerouteDetect(cmd string, args []string) bool {
|
|
target := []string{"127.0.0.1"}
|
|
success := false
|
|
if result, err := tracerouteTryExecute(cmd, args, target); err == nil {
|
|
setting.tr_bin = cmd
|
|
setting.tr_flags = args
|
|
success = true
|
|
fmt.Printf("Traceroute autodetect success: %s\n", tracerouteArgsToString(cmd, args, target))
|
|
} else {
|
|
fmt.Printf("Traceroute autodetect fail, continuing: %s (%s)\n%s", tracerouteArgsToString(cmd, args, target), err.Error(), result)
|
|
}
|
|
|
|
return success
|
|
}
|
|
|
|
func tracerouteAutodetect() {
|
|
if setting.tr_bin != "" && setting.tr_flags != nil {
|
|
return
|
|
}
|
|
|
|
// Traceroute (custom binary)
|
|
if setting.tr_bin != "" {
|
|
if tracerouteDetect(setting.tr_bin, []string{"-q1", "-N32", "-w1"}) {
|
|
return
|
|
}
|
|
if tracerouteDetect(setting.tr_bin, []string{"-q1", "-w1"}) {
|
|
return
|
|
}
|
|
if tracerouteDetect(setting.tr_bin, []string{}) {
|
|
return
|
|
}
|
|
}
|
|
|
|
// MTR
|
|
if tracerouteDetect("mtr", []string{"-w", "-c1", "-Z1", "-G1", "-b"}) {
|
|
return
|
|
}
|
|
|
|
// Traceroute
|
|
if tracerouteDetect("traceroute", []string{"-q1", "-N32", "-w1"}) {
|
|
return
|
|
}
|
|
if tracerouteDetect("traceroute", []string{"-q1", "-w1"}) {
|
|
return
|
|
}
|
|
if tracerouteDetect("traceroute", []string{}) {
|
|
return
|
|
}
|
|
|
|
// Unsupported
|
|
setting.tr_bin = ""
|
|
setting.tr_flags = nil
|
|
println("Traceroute autodetect failed! Traceroute will be disabled")
|
|
}
|
|
|
|
func tracerouteHandler(httpW http.ResponseWriter, httpR *http.Request) {
|
|
query := string(httpR.URL.Query().Get("q"))
|
|
query = strings.TrimSpace(query)
|
|
|
|
if query == "" {
|
|
invalidHandler(httpW, httpR)
|
|
} else {
|
|
args, err := shlex.Split(query)
|
|
if err != nil {
|
|
httpW.WriteHeader(http.StatusInternalServerError)
|
|
httpW.Write([]byte(fmt.Sprintf("failed to parse args: %s\n", err.Error())))
|
|
return
|
|
}
|
|
|
|
var result []byte
|
|
skippedCounter := 0
|
|
|
|
if setting.tr_bin == "" {
|
|
httpW.WriteHeader(http.StatusInternalServerError)
|
|
httpW.Write([]byte("traceroute not supported on this node.\n"))
|
|
return
|
|
}
|
|
|
|
result, err = tracerouteTryExecute(setting.tr_bin, setting.tr_flags, args)
|
|
if err != nil {
|
|
httpW.WriteHeader(http.StatusInternalServerError)
|
|
httpW.Write([]byte(fmt.Sprintf("Error executing traceroute: %s\n\n", err.Error())))
|
|
}
|
|
|
|
if result != nil {
|
|
if setting.tr_raw {
|
|
httpW.Write(result)
|
|
} else {
|
|
resultString := string(result)
|
|
resultString = regexp.MustCompile(`(?m)^\s*(\d*)\s*\*\n`).ReplaceAllStringFunc(resultString, func(w string) string {
|
|
skippedCounter++
|
|
return ""
|
|
})
|
|
httpW.Write([]byte(strings.TrimSpace(resultString)))
|
|
if skippedCounter > 0 {
|
|
httpW.Write([]byte("\n\n" + strconv.Itoa(skippedCounter) + " hops not responding."))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|