diff options
Diffstat (limited to 'cmd/prognosis/resolver.go')
| -rw-r--r-- | cmd/prognosis/resolver.go | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/cmd/prognosis/resolver.go b/cmd/prognosis/resolver.go new file mode 100644 index 0000000..095cc20 --- /dev/null +++ b/cmd/prognosis/resolver.go @@ -0,0 +1,67 @@ +package main + +import ( + "bufio" + "context" + "net" + "os" + "path/filepath" + "strings" + "time" +) + +// configureResolver teaches Go's resolver where the nameservers are on Android. +// +// Android has no /etc/resolv.conf. Go's pure-Go resolver falls back to +// localhost, so every lookup fails with "dial tcp [::1]:53: connection +// refused". Termux does ship one, at $PREFIX/etc/resolv.conf, which Go never +// consults. Reading it here uses whatever nameservers are actually configured +// rather than hardcoding any. +// +// A no-op everywhere /etc/resolv.conf exists, which is every other platform we +// build for. +func configureResolver() { + if _, err := os.Stat("/etc/resolv.conf"); err == nil { + return + } + prefix := os.Getenv("PREFIX") + if prefix == "" { + return + } + servers := nameservers(filepath.Join(prefix, "etc", "resolv.conf")) + if len(servers) == 0 { + return + } + net.DefaultResolver = &net.Resolver{ + PreferGo: true, + Dial: func(ctx context.Context, network, _ string) (net.Conn, error) { + d := net.Dialer{Timeout: 5 * time.Second} + var err error + for _, s := range servers { + var conn net.Conn + conn, err = d.DialContext(ctx, network, net.JoinHostPort(s, "53")) + if err == nil { + return conn, nil + } + } + return nil, err + }, + } +} + +func nameservers(path string) []string { + f, err := os.Open(path) + if err != nil { + return nil + } + defer f.Close() + var out []string + sc := bufio.NewScanner(f) + for sc.Scan() { + fields := strings.Fields(sc.Text()) + if len(fields) >= 2 && fields[0] == "nameserver" { + out = append(out, fields[1]) + } + } + return out +} |
