Skip to content

Commit

Permalink
Revert "Replace multiple "resolver.*" fn cals with single "dns.Exchan…
Browse files Browse the repository at this point in the history
…ge()" fn."

This reverts commit 58eb054

Due to numerous issues related to getting DNS configuration we're returning back usage of system dns resolver

Signed-off-by: Yevhen Vydolob <[email protected]>
  • Loading branch information
evidolob committed Jan 29, 2025
1 parent c9dd0cb commit 3b1806e
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 179 deletions.
201 changes: 123 additions & 78 deletions pkg/services/dns/dns.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
package dns

import (
"context"
"encoding/json"
"errors"
"fmt"
"net"
"net/http"
"strings"
"sync"

"github.com/areYouLazy/libhosty"
"github.com/containers/gvisor-tap-vsock/pkg/types"
"github.com/miekg/dns"
log "github.com/sirupsen/logrus"
Expand All @@ -18,34 +17,13 @@ import (
type dnsHandler struct {
zones []types.Zone
zonesLock sync.RWMutex
udpClient *dns.Client
tcpClient *dns.Client
hostsFile *HostsFile
dnsConfig *dnsConfig
}

func newDNSHandler(zones []types.Zone) (*dnsHandler, error) {
dnsConfig, err := newDNSConfig()
if err != nil {
return nil, err
}

hostsFile, err := NewHostsFile("")
if err != nil {
return nil, err
}

return &dnsHandler{
zones: zones,
tcpClient: &dns.Client{Net: "tcp"},
udpClient: &dns.Client{Net: "udp"},
dnsConfig: dnsConfig,
hostsFile: hostsFile,
}, nil
}

func (h *dnsHandler) handle(w dns.ResponseWriter, dnsClient *dns.Client, r *dns.Msg, responseMessageSize int) {
m := h.addAnswers(dnsClient, r)
func (h *dnsHandler) handle(w dns.ResponseWriter, r *dns.Msg, responseMessageSize int) {
m := new(dns.Msg)
m.SetReply(r)
m.RecursionAvailable = true
h.addAnswers(m)
edns0 := r.IsEdns0()
if edns0 != nil {
responseMessageSize = int(edns0.UDPSize())
Expand All @@ -57,25 +35,23 @@ func (h *dnsHandler) handle(w dns.ResponseWriter, dnsClient *dns.Client, r *dns.
}

func (h *dnsHandler) handleTCP(w dns.ResponseWriter, r *dns.Msg) {
h.handle(w, h.tcpClient, r, dns.MaxMsgSize)
h.handle(w, r, dns.MaxMsgSize)
}

func (h *dnsHandler) handleUDP(w dns.ResponseWriter, r *dns.Msg) {
h.handle(w, h.udpClient, r, dns.MinMsgSize)
h.handle(w, r, dns.MinMsgSize)
}

func (h *dnsHandler) addLocalAnswers(m *dns.Msg, q dns.Question) bool {
// resolve only ipv4 requests
if q.Qtype != dns.TypeA {
return false
}

h.zonesLock.RLock()
defer h.zonesLock.RUnlock()

for _, zone := range h.zones {
zoneSuffix := fmt.Sprintf(".%s", zone.Name)
if strings.HasSuffix(q.Name, zoneSuffix) {
if q.Qtype != dns.TypeA {
return false
}
for _, record := range zone.Records {
withoutZone := strings.TrimSuffix(q.Name, zoneSuffix)
if (record.Name != "" && record.Name == withoutZone) ||
Expand Down Expand Up @@ -107,55 +83,127 @@ func (h *dnsHandler) addLocalAnswers(m *dns.Msg, q dns.Question) bool {
m.Rcode = dns.RcodeNameError
return true
}
ip, err := h.hostsFile.LookupByHostname(q.Name)
if err != nil {
// ignore only ErrHostnameNotFound error
if !errors.Is(err, libhosty.ErrHostnameNotFound) {
log.Errorf("Error during looking in hosts file records: %v", err)
}
} else {
m.Answer = append(m.Answer, &dns.A{
Hdr: dns.RR_Header{
Name: q.Name,
Rrtype: dns.TypeA,
Class: dns.ClassINET,
Ttl: 0,
},
A: ip,
})
return true
}
}
return false
}

func (h *dnsHandler) addAnswers(dnsClient *dns.Client, r *dns.Msg) *dns.Msg {
m := new(dns.Msg)
m.SetReply(r)
m.RecursionAvailable = true

func (h *dnsHandler) addAnswers(m *dns.Msg) {
for _, q := range m.Question {
if done := h.addLocalAnswers(m, q); done {
return m
return
}

// ignore IPv6 request, we support only IPv4 requests for now
} else if q.Qtype == dns.TypeAAAA {
return m
resolver := net.Resolver{
PreferGo: false,
}
}
for _, nameserver := range h.dnsConfig.Nameservers() {
msg := r.Copy()
r, _, err := dnsClient.Exchange(msg, nameserver)
// return first good answer
if err == nil {
return r
switch q.Qtype {
case dns.TypeA:
ips, err := resolver.LookupIPAddr(context.TODO(), q.Name)
if err != nil {
m.Rcode = dns.RcodeNameError
return
}
for _, ip := range ips {
if len(ip.IP.To4()) != net.IPv4len {
continue
}
m.Answer = append(m.Answer, &dns.A{
Hdr: dns.RR_Header{
Name: q.Name,
Rrtype: dns.TypeA,
Class: dns.ClassINET,
Ttl: 0,
},
A: ip.IP.To4(),
})
}
case dns.TypeCNAME:
cname, err := resolver.LookupCNAME(context.TODO(), q.Name)
if err != nil {
m.Rcode = dns.RcodeNameError
return
}
m.Answer = append(m.Answer, &dns.CNAME{
Hdr: dns.RR_Header{
Name: q.Name,
Rrtype: dns.TypeCNAME,
Class: dns.ClassINET,
Ttl: 0,
},
Target: cname,
})
case dns.TypeMX:
records, err := resolver.LookupMX(context.TODO(), q.Name)
if err != nil {
m.Rcode = dns.RcodeNameError
return
}
for _, mx := range records {
m.Answer = append(m.Answer, &dns.MX{
Hdr: dns.RR_Header{
Name: q.Name,
Rrtype: dns.TypeMX,
Class: dns.ClassINET,
Ttl: 0,
},
Mx: mx.Host,
Preference: mx.Pref,
})
}
case dns.TypeNS:
records, err := resolver.LookupNS(context.TODO(), q.Name)
if err != nil {
m.Rcode = dns.RcodeNameError
return
}
for _, ns := range records {
m.Answer = append(m.Answer, &dns.NS{
Hdr: dns.RR_Header{
Name: q.Name,
Rrtype: dns.TypeNS,
Class: dns.ClassINET,
Ttl: 0,
},
Ns: ns.Host,
})
}
case dns.TypeSRV:
_, records, err := resolver.LookupSRV(context.TODO(), "", "", q.Name)
if err != nil {
m.Rcode = dns.RcodeNameError
return
}
for _, srv := range records {
m.Answer = append(m.Answer, &dns.SRV{
Hdr: dns.RR_Header{
Name: q.Name,
Rrtype: dns.TypeSRV,
Class: dns.ClassINET,
Ttl: 0,
},
Port: srv.Port,
Priority: srv.Priority,
Target: srv.Target,
Weight: srv.Weight,
})
}
case dns.TypeTXT:
records, err := resolver.LookupTXT(context.TODO(), q.Name)
if err != nil {
m.Rcode = dns.RcodeNameError
return
}
m.Answer = append(m.Answer, &dns.TXT{
Hdr: dns.RR_Header{
Name: q.Name,
Rrtype: dns.TypeTXT,
Class: dns.ClassINET,
Ttl: 0,
},
Txt: records,
})
}
log.Debugf("Error during DNS Exchange: %s", err)
}

// return the error if none of configured nameservers has right answer
m.Rcode = dns.RcodeNameError
return m
}

type Server struct {
Expand All @@ -165,10 +213,7 @@ type Server struct {
}

func New(udpConn net.PacketConn, tcpLn net.Listener, zones []types.Zone) (*Server, error) {
handler, err := newDNSHandler(zones)
if err != nil {
return nil, err
}
handler := &dnsHandler{zones: zones}
return &Server{udpConn: udpConn, tcpLn: tcpLn, handler: handler}, nil
}

Expand Down
61 changes: 0 additions & 61 deletions pkg/services/dns/dns_config_unix.go

This file was deleted.

34 changes: 0 additions & 34 deletions pkg/services/dns/dns_config_windows.go

This file was deleted.

9 changes: 3 additions & 6 deletions pkg/services/dns/dns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,10 @@ var _ = ginkgo.Describe("dns add test", func() {
Qclass: 1,
}

r := server.handler.addAnswers(server.handler.tcpClient, m)
server.handler.addAnswers(m)

gomega.Expect(r.Answer[0].Header().Name).To(gomega.Equal("redhat.com."))
gomega.Expect(r.Answer[0].String()).To(gomega.SatisfyAny(gomega.ContainSubstring("34.235.198.240"), gomega.ContainSubstring("52.200.142.250")))
gomega.Expect(m.Answer[0].Header().Name).To(gomega.Equal("redhat.com."))
gomega.Expect(m.Answer[0].String()).To(gomega.SatisfyAny(gomega.ContainSubstring("34.235.198.240"), gomega.ContainSubstring("52.200.142.250")))
})
})

Expand All @@ -231,9 +231,6 @@ func TestDNS(t *testing.T) {
log.Infof("starting test DNS servers")
nameserver, cleanup, err := startDNSServer()
require.NoError(t, err)
if len(nameserver) == 0 {
t.Skip("Failed to setup start DNS server, skipping test")
}
defer cleanup()
time.Sleep(100 * time.Millisecond)
log.Infof("test DNS servers started")
Expand Down

0 comments on commit 3b1806e

Please sign in to comment.