From 049775319b3ff254db63d9e8952a5ec6266c9716 Mon Sep 17 00:00:00 2001 From: Yuhui Xu Date: Sun, 25 Dec 2022 15:41:29 -0600 Subject: [PATCH 1/4] proxy: autodetect traceroute args on startup (#69) --- README.md | 24 +++++++-- proxy/main.go | 5 ++ proxy/settings.go | 23 ++++++--- proxy/traceroute.go | 121 ++++++++++++++++++++++++++++---------------- 4 files changed, 119 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index 1148216..7f1e084 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,8 @@ Configuration is handled by [viper](https://github.com/spf13/viper), any config | name_filter | --name-filter | BIRDLG_NAME_FILTER | protocol names to hide in summary tables (RE2 syntax); defaults to none if not set | | timeout | --time-out | BIRDLG_TIMEOUT | time before request timed out, in seconds; defaults to 120 if not set | +### Examples + Example: the following command starts the frontend with 2 BIRD nodes, with domain name "gigsgigscloud.dn42.lantian.pub" and "hostdare.dn42.lantian.pub", and proxies are running on port 8000 on both nodes. ```bash @@ -122,16 +124,32 @@ Configuration can be set in: Configuration is handled by [viper](https://github.com/spf13/viper), any config format supported by it can be used. -> Note: the config system is replaced with viper only recently (2022-07-08). If some config items do not work, please open an issue, and use commit [892a7bee22a1bb02d3b4da6d270c65b6e4e1321a](https://github.com/xddxdd/bird-lg-go/tree/892a7bee22a1bb02d3b4da6d270c65b6e4e1321a) (last version before config system replace) for the time being. - | Config Key | Parameter | Environment Variable | Description | | ---------- | --------- | -------------------- | ----------- | | allowed_ips | --allowed | ALLOWED_IPS | IPs allowed to access this proxy, separated by commas. Don't set to allow all IPs. (default "") | | bird_socket | --bird | BIRD_SOCKET | socket file for bird, set either in parameter or environment variable BIRD_SOCKET (default "/var/run/bird/bird.ctl") | | listen | --listen | BIRDLG_PROXY_PORT | listen address, set either in parameter or environment variable BIRDLG_PROXY_PORT(default "8000") | -| traceroute_bin | --traceroute_bin | BIRDLG_TRACEROUTE_BIN | traceroute binary file, set either in parameter or environment variable BIRDLG_TRACEROUTE_BIN(default "traceroute") | +| traceroute_bin | --traceroute_bin | BIRDLG_TRACEROUTE_BIN | traceroute binary file, set either in parameter or environment variable BIRDLG_TRACEROUTE_BIN | +| traceroute_flags | --traceroute_flags | BIRDLG_TRACEROUTE_FLAGS | traceroute flags, repeat for multiple flags. | | traceroute_raw | --traceroute_raw | BIRDLG_TRACEROUTE_RAW | whether to display traceroute outputs raw (default false) | +### Traceroute Binary Autodetection + +If `traceroute_bin` or `traceroute_flags` is not set, then on startup, the proxy will try to `traceroute 127.0.0.1` with different traceroute binaries and arguments, in order to use the most optimized setting available, while maintaining compatibility with multiple variants of traceroute binaries. + +Traceroute binaries will be autodetected in the following order: + +1. If `traceroute_bin` is set: + 1. `[traceroute_bin] -q1 -N32 -w1 127.0.0.1` (Corresponds to Traceroute on Debian) + 2. `[traceroute_bin] -q1 -w1 127.0.0.1` (Corresponds to Traceroute on FreeBSD) + 3. `[traceroute_bin] 127.0.0.1` (Corresponds to Busybox Traceroute) +2. `mtr -w -c1 -Z1 -G1 -b 127.0.0.1` (MTR) +3. `traceroute -q1 -N32 -w1 127.0.0.1` (Corresponds to Traceroute on Debian) +4. `traceroute -q1 -w1 127.0.0.1` (Corresponds to Traceroute on FreeBSD) +5. `traceroute 127.0.0.1` (Corresponds to Busybox Traceroute) + +### Examples + Example: start proxy with default configuration, should work "out of the box" on Debian 9 with BIRDv1: ```bash diff --git a/proxy/main.go b/proxy/main.go index 0ec64c9..24a8b96 100644 --- a/proxy/main.go +++ b/proxy/main.go @@ -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 diff --git a/proxy/settings.go b/proxy/settings.go index 931e217..c2a822c 100644 --- a/proxy/settings.go +++ b/proxy/settings.go @@ -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) diff --git a/proxy/traceroute.go b/proxy/traceroute.go index 4349de4..41c5c21 100644 --- a/proxy/traceroute.go +++ b/proxy/traceroute.go @@ -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], " ") - - instance := exec.Command(cmd[i], args[i]...) - output, err = instance.CombinedOutput() - if err == nil { - return output, "" +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 } - errString += fmt.Sprintf("+ (Try %d) %s\n%s\n\n", (i + 1), cmdCombined, output) + 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 } - return nil, errString + 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.")) } From dba2af763431386e3f69f9a53f7c544700ef0837 Mon Sep 17 00:00:00 2001 From: Yuhui Xu Date: Tue, 27 Dec 2022 15:38:41 -0600 Subject: [PATCH 2/4] proxy: fix description for --traceroute_flags (#70) --- README.md | 4 +--- proxy/settings.go | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7f1e084..fd012cd 100644 --- a/README.md +++ b/README.md @@ -58,8 +58,6 @@ Configuration can be set in: Configuration is handled by [viper](https://github.com/spf13/viper), any config format supported by it can be used. -> Note: the config system is replaced with viper only recently (2022-07-08). If some config items do not work, please open an issue, and use commit [892a7bee22a1bb02d3b4da6d270c65b6e4e1321a](https://github.com/xddxdd/bird-lg-go/tree/892a7bee22a1bb02d3b4da6d270c65b6e4e1321a) (last version before config system replace) for the time being. - | Config Key | Parameter | Environment Variable | Description | | ---------- | --------- | -------------------- | ----------- | | servers | --servers | BIRDLG_SERVERS | server name prefixes, separated by comma | @@ -130,7 +128,7 @@ Configuration is handled by [viper](https://github.com/spf13/viper), any config | bird_socket | --bird | BIRD_SOCKET | socket file for bird, set either in parameter or environment variable BIRD_SOCKET (default "/var/run/bird/bird.ctl") | | listen | --listen | BIRDLG_PROXY_PORT | listen address, set either in parameter or environment variable BIRDLG_PROXY_PORT(default "8000") | | traceroute_bin | --traceroute_bin | BIRDLG_TRACEROUTE_BIN | traceroute binary file, set either in parameter or environment variable BIRDLG_TRACEROUTE_BIN | -| traceroute_flags | --traceroute_flags | BIRDLG_TRACEROUTE_FLAGS | traceroute flags, repeat for multiple flags. | +| traceroute_flags | --traceroute_flags | BIRDLG_TRACEROUTE_FLAGS | traceroute flags, supports multiple flags separated with space. | | traceroute_raw | --traceroute_raw | BIRDLG_TRACEROUTE_RAW | whether to display traceroute outputs raw (default false) | ### Traceroute Binary Autodetection diff --git a/proxy/settings.go b/proxy/settings.go index c2a822c..946744f 100644 --- a/proxy/settings.go +++ b/proxy/settings.go @@ -44,7 +44,7 @@ func parseSettings() { 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.") + pflag.String("traceroute_flags", "", "traceroute flags, supports multiple flags separated with space.") 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") From e7010f75f83e1fd50f36220b26510b25a253178b Mon Sep 17 00:00:00 2001 From: Lan Tian Date: Fri, 6 Jan 2023 23:05:05 -0600 Subject: [PATCH 3/4] release: v1.2.0 --- RELEASE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE b/RELEASE index 56130fb..79127d8 100644 --- a/RELEASE +++ b/RELEASE @@ -1 +1 @@ -v1.1.1 +v1.2.0 From 49a05767c13fbe5ab4ad7527b56161ea1e6f5bac Mon Sep 17 00:00:00 2001 From: Lan Tian Date: Sun, 8 Jan 2023 01:16:23 -0600 Subject: [PATCH 4/4] ci: bump version for go-release-action --- .github/workflows/release.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 7e8ea27..e84314e 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -19,14 +19,14 @@ jobs: goos: windows steps: - uses: actions/checkout@v3 - - uses: wangyoucao577/go-release-action@v1.30 + - uses: wangyoucao577/go-release-action@v1.34 with: github_token: ${{ secrets.GITHUB_TOKEN }} goos: ${{ matrix.goos }} goarch: ${{ matrix.goarch }} project_path: "./frontend" binary_name: "bird-lg-go" - - uses: wangyoucao577/go-release-action@v1.30 + - uses: wangyoucao577/go-release-action@v1.34 with: github_token: ${{ secrets.GITHUB_TOKEN }} goos: ${{ matrix.goos }}