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 +}