diff --git a/cmd/sniproxy/main.go b/cmd/sniproxy/main.go index af97d36..4daa605 100644 --- a/cmd/sniproxy/main.go +++ b/cmd/sniproxy/main.go @@ -11,17 +11,17 @@ import ( "strings" "time" + prometheusmetrics "github.com/deathowl/go-metrics-prometheus" "github.com/google/uuid" "github.com/knadh/koanf" "github.com/knadh/koanf/parsers/yaml" "github.com/knadh/koanf/providers/env" "github.com/knadh/koanf/providers/file" "github.com/knadh/koanf/providers/rawbytes" - "github.com/rs/zerolog" - - prometheusmetrics "github.com/deathowl/go-metrics-prometheus" + "github.com/pkg/profile" "github.com/prometheus/client_golang/prometheus" "github.com/rcrowley/go-metrics" + "github.com/rs/zerolog" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/spf13/cobra" @@ -49,6 +49,32 @@ var defaultConfig []byte var nocolorLog = strings.ToLower(os.Getenv("NO_COLOR")) == "true" var logger = zerolog.New(os.Stderr).With().Timestamp().Logger().Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339, NoColor: nocolorLog}) +func enableProfile(profileType string) interface{ Stop() } { + switch profileType { + case "": + return nil + case "cpu": + return profile.Start(profile.CPUProfile) + case "mem": + return profile.Start(profile.MemProfile) + case "block": + return profile.Start(profile.BlockProfile) + case "mutex": + return profile.Start(profile.MutexProfile) + case "trace": + return profile.Start(profile.TraceProfile) + case "threadcreate": + return profile.Start(profile.ThreadcreationProfile) + case "goroutine": + return profile.Start(profile.GoroutineProfile) + case "clock": + return profile.Start(profile.ClockProfile) + default: + logger.Error().Msgf("unknown profile type: %s", profileType) + } + return nil +} + func main() { cmd := &cobra.Command{ @@ -59,6 +85,7 @@ func main() { flags := cmd.Flags() config := flags.StringP("config", "c", "", "path to YAML configuration file") _ = flags.Bool("defaultconfig", false, "write the default config yaml file to stdout") + prof := flags.String("prof", "", "enable profiling. can be one of: [cpu, mem, block, mutex, trace, threadcreate, goroutine, clock]") _ = flags.BoolP("version", "v", false, "show version info and exit") if err := cmd.Execute(); err != nil { logger.Error().Msgf("failed to execute command: %s", err) @@ -75,6 +102,10 @@ func main() { fmt.Fprint(os.Stdout, string(defaultConfig)) return } + ret := enableProfile(*prof) + if ret != nil { + defer ret.Stop() + } k := koanf.New(".") // load the defaults diff --git a/go.mod b/go.mod index 970aaca..2cb8f44 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( github.com/miekg/dns v1.1.62 github.com/mosajjal/doqd v0.0.0-20230911082614-66fb2db2687f github.com/oschwald/maxminddb-golang v1.13.1 + github.com/pkg/profile v1.7.0 github.com/prometheus/client_golang v1.20.5 github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 github.com/rs/zerolog v1.33.0 @@ -33,6 +34,7 @@ require ( github.com/cloudflare/circl v1.5.0 // indirect github.com/cloudflare/odoh-go v1.0.1-0.20230926114050-f39fa019b017 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/felixge/fgprof v0.9.3 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect diff --git a/go.sum b/go.sum index f25f4c0..b8fe35b 100644 --- a/go.sum +++ b/go.sum @@ -37,6 +37,9 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cisco/go-hpke v0.0.0-20230407100446-246075f83609 h1:+zUH9Y9OFBb59WFBFAQJTK25GGTby/g0DU7P+Pz1WaI= github.com/cisco/go-hpke v0.0.0-20230407100446-246075f83609/go.mod h1:RJ2C6TWlNvW2BlTT+YcexuRwIyzXter42/IRyb2sOTg= github.com/cisco/go-tls-syntax v0.0.0-20200617162716-46b0cfb76b9b h1:Ves2turKTX7zruivAcUOQg155xggcbv3suVdbKCBQNM= @@ -69,6 +72,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= +github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/folbricht/routedns v0.1.96 h1:K2RZUHjd2n/5Sdn1Q5lQF9GFLf0+ctdmk9RQryVg7Bk= @@ -125,6 +130,7 @@ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8 github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -170,6 +176,7 @@ github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKe github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hjson/hjson-go/v4 v4.0.0 h1:wlm6IYYqHjOdXH1gHev4VoXCaW20HdQAGCxdOEEg2cs= github.com/hjson/hjson-go/v4 v4.0.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E= +github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/infobloxopen/go-trees v0.0.0-20221216143356-66ceba885ebc h1:RhT2pjLo3EVRmldbEcBdeRA7CGPWsNEJC+Y/N1aXQbg= @@ -283,6 +290,8 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA= +github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= @@ -477,6 +486,7 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/pkg/conf.go b/pkg/conf.go index e1aada5..ce18530 100644 --- a/pkg/conf.go +++ b/pkg/conf.go @@ -56,10 +56,6 @@ type Config struct { } const ( - // DNSBootStrapIPv4 is the default DNS ipv4 server to use for DoH and DoT - DNSBootStrapIPv4 = "1.1.1.1" - // DNSBootstrapIPv6 is the default DNS ipv6 server to use for DoH and DoT - DNSBootstrapIPv6 = "2606:4700:4700::1111" // DNSTimeout is the default timeout for DNS queries DNSTimeout = 10 * time.Second // HTTPReadTimeout is the default timeout for HTTP requests diff --git a/pkg/dns.go b/pkg/dns.go index 731b008..3343921 100644 --- a/pkg/dns.go +++ b/pkg/dns.go @@ -29,6 +29,28 @@ type DNSClient struct { var dnsLock sync.RWMutex +// findBootstrapIP tries to resolve well-known DNS resolvers +// to their IP addresses +// +// dns.quad9.net -> 9.9.9.9, 2620:fe::9 +// one.one.one.one -> 1.1.1.1, 2606:4700:4700::1111 +// dns.google -> 8.8.8.8, 2001:4860:4860::8888 +func findBootstrapIP(fqdn string, version int) string { + wellKnownDomains := map[string]map[int]string{ + "dns.quad9.net": {4: "9.9.9.9", 6: "2620:fe::9"}, + "one.one.one.one": {4: "1.1.1.1", 6: "2606:4700:4700::1111"}, + "dns.google": {4: "8.8.8.8", 6: "2001:4860:4860::8888"}, + } + if version != 4 && version != 6 { + return "" + } + if ips, ok := wellKnownDomains[fqdn]; !ok { + return "" + } else { + return ips[version] + } +} + // pickSrcAddr picks a random source address from the list of configured source addresses. // version specifies the IP version to pick, 4 or 6. If 0, any version is picked. func (c *Config) pickSrcAddr(version string) net.IP { @@ -430,10 +452,10 @@ func NewDNSClient(C *Config, uri string, skipVerify bool, proxy string) (*DNSCli return nil, err } var ldarr net.IP - bootstrapAddr := DNSBootStrapIPv4 + bootstrapAddr := findBootstrapIP(parsedURL.Host, 4) if parsedURL.Scheme == "tls6" || parsedURL.Scheme == "tcp-tls6" { ldarr = C.pickSrcAddr("ipv6only") - bootstrapAddr = DNSBootstrapIPv6 + bootstrapAddr = findBootstrapIP(parsedURL.Host, 6) } else { ldarr = C.pickSrcAddr("ipv4only") } @@ -459,7 +481,7 @@ func NewDNSClient(C *Config, uri string, skipVerify bool, proxy string) (*DNSCli opt := rdns.DoHClientOptions{ Method: "POST", // TODO: support anything other than POST TLSConfig: tlsConfig, - BootstrapAddr: DNSBootStrapIPv4, + BootstrapAddr: findBootstrapIP(parsedURL.Host, 4), Transport: transport, LocalAddr: C.pickSrcAddr("ipv4only"), //TODO:support IPv6 Dialer: *dialer,