From: Dan Fuhry Date: Fri, 26 Jul 2024 16:37:07 +0000 (-0400) Subject: dns_cache: bypass systemd-resolved X-Git-Url: https://go.fuhry.dev/?a=commitdiff_plain;h=e899cf9bedbc04b940eb4f084733a074cad1502e;p=runtime.git dns_cache: bypass systemd-resolved On Linux systems, the stub resolv.conf points at systemd-resolved which uses the hostsfile. We don't want this - we need the system's addresses as described by the network's DNS server. --- diff --git a/mtls/provider_file.go b/mtls/provider_file.go index 6d5e591..a787f42 100644 --- a/mtls/provider_file.go +++ b/mtls/provider_file.go @@ -13,6 +13,7 @@ import ( "go.fuhry.dev/runtime/mtls/certutil" "go.fuhry.dev/runtime/mtls/fsnotify" + "go.fuhry.dev/runtime/utils/fsutil" ) type FileBackedCertificate struct { @@ -75,7 +76,7 @@ func newFileBackedCertificateFromBaseDir(mtlsRootPath string, serviceIdentity st rootPath := path.Join(mtlsRootPath, "rootca.pem") for _, file := range []string{leafPath, chainPath, keyPath, rootPath} { - if err := fileExistsAndIsReadable(file); err != nil { + if err := fsutil.FileExistsAndIsReadable(file); err != nil { return nil, err } } @@ -102,7 +103,7 @@ func LoadUserIdentityFromFilesystem() (*FileBackedCertificate, error) { rootPath := path.Join(defaultMtlsRootPath, "rootca.pem") for _, file := range []string{fullChainPath, keyPath, rootPath} { - if err := fileExistsAndIsReadable(file); err != nil { + if err := fsutil.FileExistsAndIsReadable(file); err != nil { return nil, err } } @@ -125,7 +126,7 @@ func LoadSSLCertificateFromFilesystem(certName string) (*FileBackedCertificate, rootPath := "/etc/ssl/certs/ISRG_Root_X1.pem" for _, file := range []string{leafPath, chainPath, keyPath, rootPath} { - if err := fileExistsAndIsReadable(file); err != nil { + if err := fsutil.FileExistsAndIsReadable(file); err != nil { return nil, err } } @@ -449,23 +450,6 @@ func (c *FileBackedCertificate) notifyEvent(filePath string, op fsnotify.Op) { } } -func fileExistsAndIsReadable(path string) error { - stat, err := os.Stat(path) - if err != nil { - return err - } - if !stat.Mode().IsRegular() { - return fmt.Errorf("%q is not a regular file", path) - } - fp, err := os.Open(path) - if err != nil { - return err - } - fp.Close() - - return nil -} - func appendMtlsCertificateDir(path string) error { stat, err := os.Stat(path) if err != nil { diff --git a/net/dns/dns_cache.go b/net/dns/dns_cache.go index 2cd3237..0270b0d 100644 --- a/net/dns/dns_cache.go +++ b/net/dns/dns_cache.go @@ -11,12 +11,28 @@ import ( lru "github.com/hashicorp/golang-lru" "github.com/miekg/dns" + "go.fuhry.dev/runtime/utils/fsutil" "go.fuhry.dev/runtime/utils/log" ) var dnsCache *lru.Cache var dnsCacheInit sync.Once +var loopbackIPv4 = net.IPNet{ + IP: net.IP{127, 0, 0, 0}, + Mask: net.IPMask{255, 0, 0, 0}, +} + +var localIPv6 = net.IPNet{ + IP: net.IP{ + 0xfe, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + }, + Mask: net.CIDRMask(64, 128), +} + func ResolveDualStack(hostname string) (string, string, error) { var msg *dns.Msg var err error @@ -53,19 +69,37 @@ func ResolveDualStack(hostname string) (string, string, error) { for _, rr := range msg.Answer { switch a := rr.(type) { case *dns.A: - ip4 = a.A.String() + if !loopbackIPv4.Contains(a.A) { + ip4 = a.A.String() + } case *dns.AAAA: - ip6 = a.AAAA.String() + if !localIPv6.Contains(a.AAAA) { + ip6 = a.AAAA.String() + } } } + if ip4 == "" && ip6 == "" { + return "", "", fmt.Errorf( + "did not receive any valid, non-loopback/local-scope answers for %q", + hostname, + ) + } + return ip4, ip6, nil } func doDualStackQuery(hostname string) (*dns.Msg, error) { var msg *dns.Msg - cc, err := dns.ClientConfigFromFile("/etc/resolv.conf") + // On Linux systems, the stub resolv.conf points at systemd-resolved which uses the hosts + // file. We don't want this - we need the system's addresses as described by the network's + // DNS server. + resolvConfPath := "/run/systemd/resolve/resolv.conf" + if err := fsutil.FileExistsAndIsReadable(resolvConfPath); err != nil { + resolvConfPath = "/etc/resolv.conf" + } + cc, err := dns.ClientConfigFromFile(resolvConfPath) if err != nil { return nil, err } diff --git a/utils/fsutil/file.go b/utils/fsutil/file.go new file mode 100644 index 0000000..c7fefd8 --- /dev/null +++ b/utils/fsutil/file.go @@ -0,0 +1,23 @@ +package fsutil + +import ( + "fmt" + "os" +) + +func FileExistsAndIsReadable(path string) error { + stat, err := os.Stat(path) + if err != nil { + return err + } + if !stat.Mode().IsRegular() { + return fmt.Errorf("%q is not a regular file", path) + } + fp, err := os.Open(path) + if err != nil { + return err + } + fp.Close() + + return nil +}