Skip to content

Commit

Permalink
feat: support dns request binding source (#180)
Browse files Browse the repository at this point in the history
* feat: support dns request binding source

* chore: mark experimental

* chore: update readme

---------

Co-authored-by: Senchong Chen <[email protected]>
Co-authored-by: r3inbowari <[email protected]>
  • Loading branch information
3 people authored Feb 23, 2024
1 parent dab8089 commit 06ba5cf
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 34 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Flags:
eg: --proxy=socks://10.20.0.101:7890
eg: --proxy=http://10.20.0.101:7890
--source=SOURCE Bind a source interface for the speedtest.
--dns-bind-source DNS request binding source.(Experimental)
eg: --source=10.20.0.101
-m --multi Enable multi-server mode.
-t --thread=THREAD Set the number of concurrent connections.
Expand Down
58 changes: 30 additions & 28 deletions speedtest.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,24 @@ import (
)

var (
showList = kingpin.Flag("list", "Show available speedtest.net servers.").Short('l').Bool()
serverIds = kingpin.Flag("server", "Select server id to run speedtest.").Short('s').Ints()
customURL = kingpin.Flag("custom-url", "Specify the url of the server instead of getting a list from speedtest.net.").String()
savingMode = kingpin.Flag("saving-mode", "Test with few resources, though low accuracy (especially > 30Mbps).").Bool()
jsonOutput = kingpin.Flag("json", "Output results in json format.").Bool()
location = kingpin.Flag("location", "Change the location with a precise coordinate. Format: lat,lon").String()
city = kingpin.Flag("city", "Change the location with a predefined city label.").String()
showCityList = kingpin.Flag("city-list", "List all predefined city labels.").Bool()
proxy = kingpin.Flag("proxy", "Set a proxy(http[s] or socks) for the speedtest.").String()
source = kingpin.Flag("source", "Bind a source interface for the speedtest.").String()
multi = kingpin.Flag("multi", "Enable multi-server mode.").Short('m').Bool()
thread = kingpin.Flag("thread", "Set the number of concurrent connections.").Short('t').Int()
search = kingpin.Flag("search", "Fuzzy search servers by a keyword.").String()
noDownload = kingpin.Flag("no-download", "Disable download test.").Bool()
noUpload = kingpin.Flag("no-upload", "Disable upload test.").Bool()
pingMode = kingpin.Flag("ping-mode", "Select a method for Ping. (support icmp/tcp/http)").Default("http").String()
debug = kingpin.Flag("debug", "Enable debug mode.").Short('d').Bool()
showList = kingpin.Flag("list", "Show available speedtest.net servers.").Short('l').Bool()
serverIds = kingpin.Flag("server", "Select server id to run speedtest.").Short('s').Ints()
customURL = kingpin.Flag("custom-url", "Specify the url of the server instead of getting a list from speedtest.net.").String()
savingMode = kingpin.Flag("saving-mode", "Test with few resources, though low accuracy (especially > 30Mbps).").Bool()
jsonOutput = kingpin.Flag("json", "Output results in json format.").Bool()
location = kingpin.Flag("location", "Change the location with a precise coordinate. Format: lat,lon").String()
city = kingpin.Flag("city", "Change the location with a predefined city label.").String()
showCityList = kingpin.Flag("city-list", "List all predefined city labels.").Bool()
proxy = kingpin.Flag("proxy", "Set a proxy(http[s] or socks) for the speedtest.").String()
source = kingpin.Flag("source", "Bind a source interface for the speedtest.").String()
dnsBindSource = kingpin.Flag("dns-bind-source", "DNS request binding source.(Experimental)").Bool()
multi = kingpin.Flag("multi", "Enable multi-server mode.").Short('m').Bool()
thread = kingpin.Flag("thread", "Set the number of concurrent connections.").Short('t').Int()
search = kingpin.Flag("search", "Fuzzy search servers by a keyword.").String()
noDownload = kingpin.Flag("no-download", "Disable download test.").Bool()
noUpload = kingpin.Flag("no-upload", "Disable upload test.").Bool()
pingMode = kingpin.Flag("ping-mode", "Select a method for Ping. (support icmp/tcp/http)").Default("http").String()
debug = kingpin.Flag("debug", "Enable debug mode.").Short('d').Bool()
)

func main() {
Expand All @@ -41,17 +42,18 @@ func main() {
// 0. speed test setting
var speedtestClient = speedtest.New(speedtest.WithUserConfig(
&speedtest.UserConfig{
UserAgent: speedtest.DefaultUserAgent,
Proxy: *proxy,
Source: *source,
Debug: *debug,
PingMode: parseProto(*pingMode), // TCP as default
SavingMode: *savingMode,
CityFlag: *city,
LocationFlag: *location,
Keyword: *search,
NoDownload: *noDownload,
NoUpload: *noUpload,
UserAgent: speedtest.DefaultUserAgent,
Proxy: *proxy,
Source: *source,
DnsBindSource: *dnsBindSource,
Debug: *debug,
PingMode: parseProto(*pingMode), // TCP as default
SavingMode: *savingMode,
CityFlag: *city,
LocationFlag: *location,
Keyword: *search,
NoDownload: *noDownload,
NoUpload: *noUpload,
}))
speedtestClient.SetNThread(*thread)

Expand Down
32 changes: 26 additions & 6 deletions speedtest/speedtest.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package speedtest

import (
"context"
"fmt"
"net"
"net/http"
Expand Down Expand Up @@ -35,12 +36,13 @@ type Speedtest struct {
}

type UserConfig struct {
T *http.Transport
UserAgent string
Proxy string
Source string
Debug bool
PingMode Proto
T *http.Transport
UserAgent string
Proxy string
Source string
DnsBindSource bool
Debug bool
PingMode Proto

SavingMode bool

Expand Down Expand Up @@ -107,6 +109,24 @@ func (s *Speedtest) NewUserConfig(uc *UserConfig) {
} else {
dbg.Printf("Warning: skipping parse the source address. err: %s\n", err.Error())
}
if uc.DnsBindSource {
net.DefaultResolver.Dial = func(ctx context.Context, network, dnsServer string) (net.Conn, error) {
dialer := &net.Dialer{
Timeout: 5 * time.Second,
LocalAddr: func(network string) net.Addr {
switch network {
case "udp", "udp4", "udp6":
return &net.UDPAddr{IP: net.ParseIP(address)}
case "tcp", "tcp4", "tcp6":
return &net.TCPAddr{IP: net.ParseIP(address)}
default:
return nil
}
}(network),
}
return dialer.DialContext(ctx, network, dnsServer)
}
}
}

if len(uc.Proxy) > 0 {
Expand Down

0 comments on commit 06ba5cf

Please sign in to comment.