proxy: autodetect traceroute args on startup (#69)
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -54,6 +55,7 @@ type settingType struct {
|
||||
listen string
|
||||
allowedIPs []string
|
||||
tr_bin string
|
||||
tr_flags []string
|
||||
tr_raw bool
|
||||
}
|
||||
|
||||
@@ -62,6 +64,9 @@ var setting settingType
|
||||
// Wrapper of tracer
|
||||
func main() {
|
||||
parseSettings()
|
||||
tracerouteAutodetect()
|
||||
|
||||
fmt.Printf("Listening on %s...\n", setting.listen)
|
||||
|
||||
var l net.Listener
|
||||
var err error
|
||||
|
||||
@@ -4,16 +4,18 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/google/shlex"
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
type viperSettingType struct {
|
||||
BirdSocket string `mapstructure:"bird_socket"`
|
||||
Listen string `mapstructure:"listen"`
|
||||
AllowedIPs string `mapstructure:"allowed_ips"`
|
||||
TracerouteBin string `mapstructure:"traceroute_bin"`
|
||||
TracerouteRaw bool `mapstructure:"traceroute_raw"`
|
||||
BirdSocket string `mapstructure:"bird_socket"`
|
||||
Listen string `mapstructure:"listen"`
|
||||
AllowedIPs string `mapstructure:"allowed_ips"`
|
||||
TracerouteBin string `mapstructure:"traceroute_bin"`
|
||||
TracerouteFlags string `mapstructure:"traceroute_flags"`
|
||||
TracerouteRaw bool `mapstructure:"traceroute_raw"`
|
||||
}
|
||||
|
||||
// Parse settings with viper, and convert to legacy setting format
|
||||
@@ -39,9 +41,12 @@ func parseSettings() {
|
||||
pflag.String("allowed", "", "IPs allowed to access this proxy, separated by commas. Don't set to allow all IPs.")
|
||||
viper.BindPFlag("allowed_ips", pflag.Lookup("allowed"))
|
||||
|
||||
pflag.String("traceroute_bin", "traceroute", "traceroute binary file, set either in parameter or environment variable BIRDLG_TRACEROUTE_BIN")
|
||||
pflag.String("traceroute_bin", "", "traceroute binary file, set either in parameter or environment variable BIRDLG_TRACEROUTE_BIN")
|
||||
viper.BindPFlag("traceroute_bin", pflag.Lookup("traceroute_bin"))
|
||||
|
||||
pflag.String("traceroute_flags", "", "traceroute flags, repeat for multiple flags.")
|
||||
viper.BindPFlag("traceroute_flags", pflag.Lookup("traceroute_flags"))
|
||||
|
||||
pflag.Bool("traceroute_raw", false, "whether to display traceroute outputs raw; set via parameter or environment variable BIRDLG_TRACEROUTE_RAW")
|
||||
viper.BindPFlag("traceroute_raw", pflag.Lookup("traceroute_raw"))
|
||||
|
||||
@@ -65,7 +70,13 @@ func parseSettings() {
|
||||
setting.allowedIPs = []string{""}
|
||||
}
|
||||
|
||||
var err error
|
||||
setting.tr_bin = viperSettings.TracerouteBin
|
||||
setting.tr_flags, err = shlex.Split(viperSettings.TracerouteFlags)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
setting.tr_raw = viperSettings.TracerouteRaw
|
||||
|
||||
fmt.Printf("%#v\n", setting)
|
||||
|
||||
@@ -5,28 +5,81 @@ import (
|
||||
"net/http"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/google/shlex"
|
||||
)
|
||||
|
||||
func tracerouteTryExecute(cmd []string, args [][]string) ([]byte, string) {
|
||||
var output []byte
|
||||
var errString = ""
|
||||
for i := range cmd {
|
||||
var err error
|
||||
var cmdCombined = cmd[i] + " " + strings.Join(args[i], " ")
|
||||
func tracerouteArgsToString(cmd string, args []string, target []string) string {
|
||||
var cmdCombined = append([]string{cmd}, args...)
|
||||
cmdCombined = append(cmdCombined, target...)
|
||||
return strings.Join(cmdCombined, " ")
|
||||
}
|
||||
|
||||
instance := exec.Command(cmd[i], args[i]...)
|
||||
output, err = instance.CombinedOutput()
|
||||
if err == nil {
|
||||
return output, ""
|
||||
}
|
||||
errString += fmt.Sprintf("+ (Try %d) %s\n%s\n\n", (i + 1), cmdCombined, output)
|
||||
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 nil, errString
|
||||
|
||||
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) {
|
||||
@@ -44,52 +97,30 @@ func tracerouteHandler(httpW http.ResponseWriter, httpR *http.Request) {
|
||||
}
|
||||
|
||||
var result []byte
|
||||
var errString string
|
||||
skippedCounter := 0
|
||||
|
||||
if runtime.GOOS == "freebsd" || runtime.GOOS == "netbsd" || runtime.GOOS == "openbsd" {
|
||||
result, errString = tracerouteTryExecute(
|
||||
[]string{
|
||||
setting.tr_bin,
|
||||
setting.tr_bin,
|
||||
},
|
||||
[][]string{
|
||||
append([]string{"-q1", "-w1"}, args...),
|
||||
args,
|
||||
},
|
||||
)
|
||||
} else if runtime.GOOS == "linux" {
|
||||
result, errString = tracerouteTryExecute(
|
||||
[]string{
|
||||
setting.tr_bin,
|
||||
setting.tr_bin,
|
||||
setting.tr_bin,
|
||||
},
|
||||
[][]string{
|
||||
append([]string{"-q1", "-N32", "-w1"}, args...),
|
||||
append([]string{"-q1", "-w1"}, args...),
|
||||
args,
|
||||
},
|
||||
)
|
||||
} else {
|
||||
if setting.tr_bin == "" {
|
||||
httpW.WriteHeader(http.StatusInternalServerError)
|
||||
httpW.Write([]byte("traceroute not supported on this node.\n"))
|
||||
return
|
||||
}
|
||||
if errString != "" {
|
||||
|
||||
result, err = tracerouteTryExecute(setting.tr_bin, setting.tr_flags, args)
|
||||
if err != nil {
|
||||
httpW.WriteHeader(http.StatusInternalServerError)
|
||||
httpW.Write([]byte(errString))
|
||||
httpW.Write([]byte(fmt.Sprintf("Error executing traceroute: %s\n\n", err.Error())))
|
||||
}
|
||||
|
||||
if result != nil {
|
||||
if setting.tr_raw {
|
||||
httpW.Write(result)
|
||||
} else {
|
||||
errString = string(result)
|
||||
errString = regexp.MustCompile(`(?m)^\s*(\d*)\s*\*\n`).ReplaceAllStringFunc(errString, func(w string) string {
|
||||
resultString := string(result)
|
||||
resultString = regexp.MustCompile(`(?m)^\s*(\d*)\s*\*\n`).ReplaceAllStringFunc(resultString, func(w string) string {
|
||||
skippedCounter++
|
||||
return ""
|
||||
})
|
||||
httpW.Write([]byte(strings.TrimSpace(errString)))
|
||||
httpW.Write([]byte(strings.TrimSpace(resultString)))
|
||||
if skippedCounter > 0 {
|
||||
httpW.Write([]byte("\n\n" + strconv.Itoa(skippedCounter) + " hops not responding."))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user