Skip to content

Commit

Permalink
Merge pull request #339 from evidolob/replace-dns
Browse files Browse the repository at this point in the history
Replace dns "resolver" calls with "dns.Exchange" func
  • Loading branch information
openshift-merge-bot[bot] authored Sep 18, 2024
2 parents 2d3bdad + be5257a commit 3c875de
Show file tree
Hide file tree
Showing 30 changed files with 5,029 additions and 142 deletions.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ require (
github.com/onsi/gomega v1.34.1
github.com/opencontainers/go-digest v1.0.0
github.com/pkg/errors v0.9.1
github.com/qdm12/dns/v2 v2.0.0-rc6
github.com/sirupsen/logrus v1.9.3
github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8
Expand All @@ -38,6 +39,7 @@ require (
github.com/nxadm/tail v1.4.8 // indirect
github.com/pierrec/lz4/v4 v4.1.14 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/qdm12/gosettings v0.4.1 // indirect
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect
github.com/vishvananda/netns v0.0.4 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/qdm12/dns/v2 v2.0.0-rc6 h1:h5KpuqZ3IMoSbz2a0OkHzIVc9/jk2vuIm9RoKJuaI78=
github.com/qdm12/dns/v2 v2.0.0-rc6/go.mod h1:Oh34IJIG55BgHoACOf+cgZCgDiFuiJZ6r6gQW58FN+k=
github.com/qdm12/gosettings v0.4.1 h1:c7+14jO1Y2kFXBCUfS2+QE2NgwTKfzcdJzGEFRItCI8=
github.com/qdm12/gosettings v0.4.1/go.mod h1:uItKwGXibJp2pQ0am6MBKilpjfvYTGiH+zXHd10jFj8=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091 h1:1zN6ImoqhSJhN8hGXFaJlSC8msLmIbX8bFqOfWLKw0w=
Expand Down
215 changes: 73 additions & 142 deletions pkg/services/dns/dns.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package dns

import (
"context"
"encoding/json"
"fmt"
"net"
Expand All @@ -15,15 +14,31 @@ import (
)

type dnsHandler struct {
zones []types.Zone
zonesLock sync.RWMutex
zones []types.Zone
zonesLock sync.RWMutex
udpClient *dns.Client
tcpClient *dns.Client
nameserver string
}

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)
func newDNSHandler(zones []types.Zone) (*dnsHandler, error) {

nameserver, port, err := getDNSHostAndPort()
if err != nil {
return nil, err
}

return &dnsHandler{
zones: zones,
tcpClient: &dns.Client{Net: "tcp"},
udpClient: &dns.Client{Net: "udp"},
nameserver: net.JoinHostPort(nameserver, port),
}, nil

}

func (h *dnsHandler) handle(w dns.ResponseWriter, dnsClient *dns.Client, r *dns.Msg, responseMessageSize int) {
m := h.addAnswers(dnsClient, r)
edns0 := r.IsEdns0()
if edns0 != nil {
responseMessageSize = int(edns0.UDPSize())
Expand All @@ -35,167 +50,80 @@ func (h *dnsHandler) handle(w dns.ResponseWriter, r *dns.Msg, responseMessageSiz
}

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

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

func (h *dnsHandler) addAnswers(m *dns.Msg) {
func (h *dnsHandler) addLocalAnswers(m *dns.Msg, q dns.Question) bool {
h.zonesLock.RLock()
defer h.zonesLock.RUnlock()
for _, q := range m.Question {
for _, zone := range h.zones {
zoneSuffix := fmt.Sprintf(".%s", zone.Name)
if strings.HasSuffix(q.Name, zoneSuffix) {
if q.Qtype != dns.TypeA {
return
}
for _, record := range zone.Records {
withoutZone := strings.TrimSuffix(q.Name, zoneSuffix)
if (record.Name != "" && record.Name == withoutZone) ||
(record.Regexp != nil && record.Regexp.MatchString(withoutZone)) {
m.Answer = append(m.Answer, &dns.A{
Hdr: dns.RR_Header{
Name: q.Name,
Rrtype: dns.TypeA,
Class: dns.ClassINET,
Ttl: 0,
},
A: record.IP,
})
return
}
}
if !zone.DefaultIP.Equal(net.IP("")) {

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) ||
(record.Regexp != nil && record.Regexp.MatchString(withoutZone)) {
m.Answer = append(m.Answer, &dns.A{
Hdr: dns.RR_Header{
Name: q.Name,
Rrtype: dns.TypeA,
Class: dns.ClassINET,
Ttl: 0,
},
A: zone.DefaultIP,
A: record.IP,
})
return
return true
}
m.Rcode = dns.RcodeNameError
return
}
}

resolver := net.Resolver{
PreferGo: false,
}
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
}
if !zone.DefaultIP.Equal(net.IP("")) {
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,
A: zone.DefaultIP,
})
return true
}
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,
})
m.Rcode = dns.RcodeNameError
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
for _, q := range m.Question {
if done := h.addLocalAnswers(m, q); done {
return m

// ignore IPv6 request, we support only IPv4 requests for now
} else if q.Qtype == dns.TypeAAAA {
return m
}
}

r, _, err := dnsClient.Exchange(r, h.nameserver)
if err != nil {
log.Errorf("Error during DNS Exchange: %s", err)
m.Rcode = dns.RcodeNameError
return m
}

return r
}

type Server struct {
Expand All @@ -205,7 +133,10 @@ type Server struct {
}

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

Expand Down
18 changes: 18 additions & 0 deletions pkg/services/dns/dns_config_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//go:build !windows

package dns

import (
"github.com/miekg/dns"
)

func getDNSHostAndPort() (string, string, error) {
conf, err := dns.ClientConfigFromFile("/etc/resolv.conf")
if err != nil {
return "", "", err
}
// TODO: use all configured nameservers, instead just first one
nameserver := conf.Servers[0]

return nameserver, conf.Port, nil
}
26 changes: 26 additions & 0 deletions pkg/services/dns/dns_config_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//go:build windows

package dns

import (
"net/netip"
"strconv"

qdmDns "github.com/qdm12/dns/v2/pkg/nameserver"
)

func getDNSHostAndPort() (string, string, error) {
nameservers := qdmDns.GetDNSServers()

var nameserver netip.AddrPort
for _, n := range nameservers {
// return first non ipv6 nameserver
if n.Addr().Is4() {
nameserver = n
break
}
}

return nameserver.Addr().String(), strconv.Itoa(int(nameserver.Port())), nil

}
Loading

0 comments on commit 3c875de

Please sign in to comment.