From d9ab78b2eae0e62e41b31f89babaaafa0337b3f4 Mon Sep 17 00:00:00 2001 From: Sam Therapy Date: Wed, 29 Jun 2022 23:14:49 +0200 Subject: [PATCH 1/4] Attempt to add windows DNS config Signed-off-by: Sam Therapy --- cli.go | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/cli.go b/cli.go index 6b18497..3f24d31 100644 --- a/cli.go +++ b/cli.go @@ -6,6 +6,7 @@ import ( "math/rand" "runtime" "strings" + "unsafe" "git.froth.zone/sam/awl/util" "github.com/miekg/dns" @@ -182,14 +183,77 @@ func parseArgs(args []string) (util.Answers, error) { } } if resp.Answers.Server == "" { - resolv, err := dns.ClientConfigFromFile("/etc/resolv.conf") + var resolv *dns.ClientConfig + if runtime.GOOS == "windows" { + resolv, err = WindowsDnsClientConfig() + } else { + resolv, err = dns.ClientConfigFromFile("/etc/resolv.conf") + } if err != nil { // Query Google by default, needed for Windows since the DNS library doesn't support Windows // TODO: Actually find where windows stuffs its dns resolvers resp.Answers.Server = "8.8.4.4" } else { - resp.Answers.Server = resolv.Servers[rand.Intn(len(resolv.Servers))] + resp.Answers.Server = resolv.Servers[rand.Intn(len(resolv.Servers)-1)] } } return util.Answers{Server: resp.Answers.Server, Request: resp.Answers.Request, Name: resp.Answers.Name}, nil } + +/* +"Stolen" from +https://gist.github.com/moloch--/9fb1c8497b09b45c840fe93dd23b1e98 +*/ + +// WindowsDnsClientConfig - returns all DNS server addresses using windows fuckery. +func WindowsDnsClientConfig() (*dns.ClientConfig, error) { + l := uint32(20000) + b := make([]byte, l) + + // Windows is an utter fucking trash fire of an operating system. + if err := windows.GetAdaptersAddresses(windows.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])), &l); err != nil { + return nil, err + } + var addresses []*windows.IpAdapterAddresses + for addr := (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])); addr != nil; addr = addr.Next { + addresses = append(addresses, addr) + } + + resolvers := map[string]bool{} + for _, addr := range addresses { + for next := addr.FirstUnicastAddress; next != nil; next = next.Next { + if addr.OperStatus != windows.IfOperStatusUp { + continue + } + if next.Address.IP() != nil { + for dnsServer := addr.FirstDnsServerAddress; dnsServer != nil; dnsServer = dnsServer.Next { + ip := dnsServer.Address.IP() + if ip.IsMulticast() || ip.IsLinkLocalMulticast() || ip.IsLinkLocalUnicast() || ip.IsUnspecified() { + continue + } + if ip.To16() != nil && strings.HasPrefix(ip.To16().String(), "fec0:") { + continue + } + resolvers[ip.String()] = true + } + break + } + } + } + + // Take unique values only + servers := []string{} + for server := range resolvers { + servers = append(servers, server) + } + + // TODO: Make configurable, based on defaults in https://github.com/miekg/dns/blob/master/clientconfig.go + return &dns.ClientConfig{ + Servers: servers, + Search: []string{}, + Port: "53", + Ndots: 1, + Timeout: 5, + Attempts: 1, + }, nil +} -- 2.43.0 From f1c3edf41c392db35baf716bf768e75e149f8c06 Mon Sep 17 00:00:00 2001 From: Sam Therapy Date: Wed, 29 Jun 2022 23:16:34 +0200 Subject: [PATCH 2/4] Fix import Signed-off-by: Sam Therapy --- cli.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cli.go b/cli.go index 3f24d31..c9686c0 100644 --- a/cli.go +++ b/cli.go @@ -12,6 +12,7 @@ import ( "github.com/miekg/dns" "github.com/urfave/cli/v2" "golang.org/x/net/idna" + "golang.org/x/sys/windows" ) // Do all the magic CLI crap -- 2.43.0 From ce2688cf1ac9935ab6ec226c4a441d6a44e211af Mon Sep 17 00:00:00 2001 From: Sam Therapy Date: Thu, 30 Jun 2022 12:01:05 +0200 Subject: [PATCH 3/4] Fix Win, Add Plan 9 Signed-off-by: Sam Therapy --- .drone.yml | 2 +- cli.go | 76 ++++----------------------------------------- conf/docs.go | 6 ++++ conf/notwin.go | 52 +++++++++++++++++++++++++++++++ conf/notwin_test.go | 18 +++++++++++ conf/win.go | 70 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 153 insertions(+), 71 deletions(-) create mode 100644 conf/docs.go create mode 100644 conf/notwin.go create mode 100644 conf/notwin_test.go create mode 100644 conf/win.go diff --git a/.drone.yml b/.drone.yml index 10c02d1..1ccb75b 100644 --- a/.drone.yml +++ b/.drone.yml @@ -2,7 +2,7 @@ kind: pipeline type: docker name: default steps: - - name: test + - name: Test image: golang commands: - go test ./... \ No newline at end of file diff --git a/cli.go b/cli.go index c9686c0..dd291d0 100644 --- a/cli.go +++ b/cli.go @@ -6,13 +6,13 @@ import ( "math/rand" "runtime" "strings" - "unsafe" + "git.froth.zone/sam/awl/conf" "git.froth.zone/sam/awl/util" + "github.com/miekg/dns" "github.com/urfave/cli/v2" "golang.org/x/net/idna" - "golang.org/x/sys/windows" ) // Do all the magic CLI crap @@ -113,7 +113,7 @@ func prepareCLI() *cli.App { }, &cli.BoolFlag{ Name: "tc", - Usage: "set tc (TrunCated) flag (default: not set)", + Usage: "set TC (TrunCated) flag (default: not set)", }, &cli.BoolFlag{ Name: "z", @@ -184,77 +184,13 @@ func parseArgs(args []string) (util.Answers, error) { } } if resp.Answers.Server == "" { - var resolv *dns.ClientConfig - if runtime.GOOS == "windows" { - resolv, err = WindowsDnsClientConfig() - } else { - resolv, err = dns.ClientConfigFromFile("/etc/resolv.conf") - } - if err != nil { // Query Google by default, needed for Windows since the DNS library doesn't support Windows - // TODO: Actually find where windows stuffs its dns resolvers + resolv, err := conf.GetDNSConfig() + if err != nil { // Query Google by default resp.Answers.Server = "8.8.4.4" } else { - resp.Answers.Server = resolv.Servers[rand.Intn(len(resolv.Servers)-1)] + resp.Answers.Server = resolv.Servers[rand.Intn(len(resolv.Servers))] } } return util.Answers{Server: resp.Answers.Server, Request: resp.Answers.Request, Name: resp.Answers.Name}, nil } - -/* -"Stolen" from -https://gist.github.com/moloch--/9fb1c8497b09b45c840fe93dd23b1e98 -*/ - -// WindowsDnsClientConfig - returns all DNS server addresses using windows fuckery. -func WindowsDnsClientConfig() (*dns.ClientConfig, error) { - l := uint32(20000) - b := make([]byte, l) - - // Windows is an utter fucking trash fire of an operating system. - if err := windows.GetAdaptersAddresses(windows.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])), &l); err != nil { - return nil, err - } - var addresses []*windows.IpAdapterAddresses - for addr := (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])); addr != nil; addr = addr.Next { - addresses = append(addresses, addr) - } - - resolvers := map[string]bool{} - for _, addr := range addresses { - for next := addr.FirstUnicastAddress; next != nil; next = next.Next { - if addr.OperStatus != windows.IfOperStatusUp { - continue - } - if next.Address.IP() != nil { - for dnsServer := addr.FirstDnsServerAddress; dnsServer != nil; dnsServer = dnsServer.Next { - ip := dnsServer.Address.IP() - if ip.IsMulticast() || ip.IsLinkLocalMulticast() || ip.IsLinkLocalUnicast() || ip.IsUnspecified() { - continue - } - if ip.To16() != nil && strings.HasPrefix(ip.To16().String(), "fec0:") { - continue - } - resolvers[ip.String()] = true - } - break - } - } - } - - // Take unique values only - servers := []string{} - for server := range resolvers { - servers = append(servers, server) - } - - // TODO: Make configurable, based on defaults in https://github.com/miekg/dns/blob/master/clientconfig.go - return &dns.ClientConfig{ - Servers: servers, - Search: []string{}, - Port: "53", - Ndots: 1, - Timeout: 5, - Attempts: 1, - }, nil -} diff --git a/conf/docs.go b/conf/docs.go new file mode 100644 index 0000000..c57cfb5 --- /dev/null +++ b/conf/docs.go @@ -0,0 +1,6 @@ +/* +Helper functions for getting local nameservers + +Currently supported: Unix, Windows, Plan 9 (tested on 9front) +*/ +package conf diff --git a/conf/notwin.go b/conf/notwin.go new file mode 100644 index 0000000..0f61861 --- /dev/null +++ b/conf/notwin.go @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: BSD-3-Clause +//go:build !windows +// +build !windows + +package conf + +import ( + "os" + "runtime" + "strings" + + "github.com/miekg/dns" +) + +// Get the DNS configuration, either from /etc/resolv.conf or somewhere else +func GetDNSConfig() (*dns.ClientConfig, error) { + if runtime.GOOS == "plan9" { + dat, err := os.ReadFile("/net/ndb") + if err != nil { + return nil, err + } + return getPlan9Config(string(dat)) + } else { + return dns.ClientConfigFromFile("/etc/resolv.conf") + } +} + +// Plan 9 stores its network data in /net/ndb, which seems to be formatted a specific way +func getPlan9Config(str string) (*dns.ClientConfig, error) { + str = strings.ReplaceAll(str, "\n", "") + spl := strings.FieldsFunc(str, split) + servers := []string{} + for _, option := range spl { + if strings.HasPrefix(option, "dns=") { + servers = append(servers, strings.TrimPrefix(option, "dns=")) + } + } + + // TODO: read more about how customizable Plan 9 is + return &dns.ClientConfig{ + Servers: servers, + Search: []string{}, + Port: "53", + Ndots: 1, + Timeout: 5, + Attempts: 1, + }, nil +} + +func split(r rune) bool { + return r == ' ' || r == '\t' +} diff --git a/conf/notwin_test.go b/conf/notwin_test.go new file mode 100644 index 0000000..5845b99 --- /dev/null +++ b/conf/notwin_test.go @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: BSD-3-Clause +package conf + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetPlan9Config(t *testing.T) { + ndb := `ip=192.168.122.45 ipmask=255.255.255.0 ipgw=192.168.122.1 + sys=chog9 + dns=192.168.122.1` + + act, err := getPlan9Config(ndb) + assert.Nil(t, err) + assert.Equal(t, act.Servers[0], "192.168.122.1") +} diff --git a/conf/win.go b/conf/win.go new file mode 100644 index 0000000..2e5d23c --- /dev/null +++ b/conf/win.go @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: BSD-3-Clause +//go:build windows + +package conf + +import ( + "strings" + "unsafe" + + "github.com/miekg/dns" + "golang.org/x/sys/windows" +) + +/* +"Stolen" from +https://gist.github.com/moloch--/9fb1c8497b09b45c840fe93dd23b1e98 +*/ + +// WindowsDnsClientConfig - returns all DNS server addresses using windows fuckery. +func GetDNSConfig() (*dns.ClientConfig, error) { + l := uint32(20000) + b := make([]byte, l) + + // Windows is an utter fucking trash fire of an operating system. + if err := windows.GetAdaptersAddresses(windows.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])), &l); err != nil { + return nil, err + } + var addresses []*windows.IpAdapterAddresses + for addr := (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])); addr != nil; addr = addr.Next { + addresses = append(addresses, addr) + } + + resolvers := map[string]bool{} + for _, addr := range addresses { + for next := addr.FirstUnicastAddress; next != nil; next = next.Next { + if addr.OperStatus != windows.IfOperStatusUp { + continue + } + if next.Address.IP() != nil { + for dnsServer := addr.FirstDnsServerAddress; dnsServer != nil; dnsServer = dnsServer.Next { + ip := dnsServer.Address.IP() + if ip.IsMulticast() || ip.IsLinkLocalMulticast() || ip.IsLinkLocalUnicast() || ip.IsUnspecified() { + continue + } + if ip.To16() != nil && strings.HasPrefix(ip.To16().String(), "fec0:") { + continue + } + resolvers[ip.String()] = true + } + break + } + } + } + + // Take unique values only + servers := []string{} + for server := range resolvers { + servers = append(servers, server) + } + + // TODO: Make configurable, based on defaults in https://github.com/miekg/dns/blob/master/clientconfig.go + return &dns.ClientConfig{ + Servers: servers, + Search: []string{}, + Port: "53", + Ndots: 1, + Timeout: 5, + Attempts: 1, + }, nil +} -- 2.43.0 From 2e2d5187d1840b0a68f86500543571f09c9a98a1 Mon Sep 17 00:00:00 2001 From: Sam Therapy Date: Thu, 30 Jun 2022 22:26:40 +0200 Subject: [PATCH 4/4] Fix testing on windows, add better Plan 9 support Signed-off-by: Sam Therapy --- cli.go | 1 + cli_test.go | 1 + conf/notwin.go | 27 --------------------------- conf/notwin_test.go | 18 ------------------ conf/plan9.go | 40 ++++++++++++++++++++++++++++++++++++++++ conf/plan9_test.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ go.mod | 2 +- 7 files changed, 88 insertions(+), 46 deletions(-) delete mode 100644 conf/notwin_test.go create mode 100644 conf/plan9.go create mode 100644 conf/plan9_test.go diff --git a/cli.go b/cli.go index dd291d0..948991f 100644 --- a/cli.go +++ b/cli.go @@ -1,4 +1,5 @@ // SPDX-License-Identifier: BSD-3-Clause + package main import ( diff --git a/cli_test.go b/cli_test.go index dce74a8..b496ce2 100644 --- a/cli_test.go +++ b/cli_test.go @@ -1,4 +1,5 @@ // SPDX-License-Identifier: BSD-3-Clause + package main import ( diff --git a/conf/notwin.go b/conf/notwin.go index 0f61861..7f8aa7a 100644 --- a/conf/notwin.go +++ b/conf/notwin.go @@ -7,7 +7,6 @@ package conf import ( "os" "runtime" - "strings" "github.com/miekg/dns" ) @@ -24,29 +23,3 @@ func GetDNSConfig() (*dns.ClientConfig, error) { return dns.ClientConfigFromFile("/etc/resolv.conf") } } - -// Plan 9 stores its network data in /net/ndb, which seems to be formatted a specific way -func getPlan9Config(str string) (*dns.ClientConfig, error) { - str = strings.ReplaceAll(str, "\n", "") - spl := strings.FieldsFunc(str, split) - servers := []string{} - for _, option := range spl { - if strings.HasPrefix(option, "dns=") { - servers = append(servers, strings.TrimPrefix(option, "dns=")) - } - } - - // TODO: read more about how customizable Plan 9 is - return &dns.ClientConfig{ - Servers: servers, - Search: []string{}, - Port: "53", - Ndots: 1, - Timeout: 5, - Attempts: 1, - }, nil -} - -func split(r rune) bool { - return r == ' ' || r == '\t' -} diff --git a/conf/notwin_test.go b/conf/notwin_test.go deleted file mode 100644 index 5845b99..0000000 --- a/conf/notwin_test.go +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -package conf - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestGetPlan9Config(t *testing.T) { - ndb := `ip=192.168.122.45 ipmask=255.255.255.0 ipgw=192.168.122.1 - sys=chog9 - dns=192.168.122.1` - - act, err := getPlan9Config(ndb) - assert.Nil(t, err) - assert.Equal(t, act.Servers[0], "192.168.122.1") -} diff --git a/conf/plan9.go b/conf/plan9.go new file mode 100644 index 0000000..cb507fb --- /dev/null +++ b/conf/plan9.go @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: BSD-3-Clause + +package conf + +import ( + "fmt" + "strings" + + "github.com/miekg/dns" +) + +// Plan 9 stores its network data in /net/ndb, which seems to be formatted a specific way +// Yoink it and use it. +// +// See ndb(7). +func getPlan9Config(str string) (*dns.ClientConfig, error) { + str = strings.ReplaceAll(str, "\n", "") + spl := strings.FieldsFunc(str, splitChars) + var servers []string + for _, option := range spl { + if strings.HasPrefix(option, "dns=") { + servers = append(servers, strings.TrimPrefix(option, "dns=")) + } + } + if len(servers) == 0 { + return nil, fmt.Errorf("plan9: no DNS servers found") + } + + // TODO: read more about how customizable Plan 9 is + return &dns.ClientConfig{ + Servers: servers, + Search: []string{}, + Port: "53", + }, nil +} + +// Split the string at either space or tabs +func splitChars(r rune) bool { + return r == ' ' || r == '\t' +} diff --git a/conf/plan9_test.go b/conf/plan9_test.go new file mode 100644 index 0000000..fa81fd2 --- /dev/null +++ b/conf/plan9_test.go @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: BSD-3-Clause + +package conf + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetPlan9Config(t *testing.T) { + ndbs := []struct { + in string + want string + }{ + {`ip=192.168.122.45 ipmask=255.255.255.0 ipgw=192.168.122.1 + sys=chog9 + dns=192.168.122.1`, "192.168.122.1"}, + {`ipnet=murray-hill ip=135.104.0.0 ipmask=255.255.0.0 + dns=135.104.10.1 + ntp=ntp.cs.bell-labs.com + ipnet=plan9 ip=135.104.9.0 ipmask=255.255.255.0 + ntp=oncore.cs.bell-labs.com + smtp=smtp1.cs.bell-labs.com + ip=135.104.9.6 sys=anna dom=anna.cs.bell-labs.com + smtp=smtp2.cs.bell-labs.com`, "135.104.10.1"}, + } + + for _, ndb := range ndbs { + act, err := getPlan9Config(ndb.in) + assert.Nil(t, err) + assert.Equal(t, ndb.want, act.Servers[0]) + } + + invalid := `sys = spindle + dom=spindle.research.bell-labs.com + bootf=/mips/9powerboot + ip=135.104.117.32 ether=080069020677 + proto=il` + + act, err := getPlan9Config(invalid) + assert.ErrorContains(t, err, "no DNS servers found") + assert.Nil(t, act) + +} diff --git a/go.mod b/go.mod index 1ce1512..ebe8a60 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect - golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b // indirect + golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b golang.org/x/text v0.3.7 // indirect golang.org/x/tools v0.1.11 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect -- 2.43.0