Skip to content

Commit

Permalink
all: add dns64 support
Browse files Browse the repository at this point in the history
  • Loading branch information
EugeneOne1 committed Jan 16, 2023
1 parent cd76a30 commit 1215316
Show file tree
Hide file tree
Showing 8 changed files with 397 additions and 21 deletions.
32 changes: 32 additions & 0 deletions internal/aghnet/prefixset.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package aghnet

import (
"net/netip"
)

// PrefixSet is a set of prefixes.
//
// TODO(e.burkov): Put into golibs.
type PrefixSet interface {
// Contains returns true if ip is within at least a single prefix in the
// set.
Contains(ip netip.Addr) (ok bool)
}

// SlicePrefixSet is the [PrefixSet] implementation that checks an address
// through a slice of [netip.Prefix].
type SlicePrefixSet []netip.Prefix

// type check
var _ PrefixSet = (SlicePrefixSet)(nil)

// Contains implements the [PrefixSet] interface for [SlicePrefixSet].
func (s SlicePrefixSet) Contains(ip netip.Addr) (ok bool) {
for _, n := range s {
if n.Contains(ip) {
return true
}
}

return false
}
6 changes: 6 additions & 0 deletions internal/dnsforward/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,13 +224,19 @@ type ServerConfig struct {
// resolving PTR queries for local addresses.
LocalPTRResolvers []string

// DNS64Prefixes is a slice of NAT64 prefixes to be used for DNS64.
DNS64Prefixes []string

// ResolveClients signals if the RDNS should resolve clients' addresses.
ResolveClients bool

// UsePrivateRDNS defines if the PTR requests for unknown addresses from
// locally-served networks should be resolved via private PTR resolvers.
UsePrivateRDNS bool

// UseDNS64 defines if DNS64 is enabled for incoming requests.
UseDNS64 bool

// ServeHTTP3 defines if HTTP/3 is be allowed for incoming requests.
ServeHTTP3 bool

Expand Down
62 changes: 44 additions & 18 deletions internal/dnsforward/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@ type dnsContext struct {
// response is modified by filters.
origResp *dns.Msg

// unreversedReqIP stores an IP address obtained from PTR request if it
// parsed successfully and belongs to one of locally-served IP ranges as per
// RFC 6303.
// unreversedReqIP stores an IP address obtained from a PTR request if it
// parsed successfully and belongs to one of locally served IP ranges. It
// also filled with unmapped version of the address if it's within DNS64
// prefixes.
unreversedReqIP net.IP

// err is the error returned from a processing function.
Expand Down Expand Up @@ -133,8 +134,8 @@ func (s *Server) handleDNSRequest(_ *proxy.Proxy, pctx *proxy.DNSContext) error
return nil
}

// processRecursion checks the incoming request and halts it's handling if s
// have tried to resolve it recently.
// processRecursion checks the incoming request and halts its handling if s have
// tried to resolve it recently.
func (s *Server) processRecursion(dctx *dnsContext) (rc resultCode) {
pctx := dctx.proxyCtx

Expand Down Expand Up @@ -377,7 +378,8 @@ func (s *Server) dhcpHostToIP(host string) (ip netip.Addr, ok bool) {
}

// processDHCPHosts respond to A requests if the target hostname is known to
// the server.
// the server. It responds with a mapped IP address if the DNS64 is enabled and
// the request is for AAAA.
//
// TODO(a.garipov): Adapt to AAAA as well.
func (s *Server) processDHCPHosts(dctx *dnsContext) (rc resultCode) {
Expand Down Expand Up @@ -409,13 +411,25 @@ func (s *Server) processDHCPHosts(dctx *dnsContext) (rc resultCode) {
log.Debug("dnsforward: dhcp record for %q is %s", reqHost, ip)

resp := s.makeResponse(req)
if q.Qtype == dns.TypeA {
switch q.Qtype {
case dns.TypeA:
a := &dns.A{
Hdr: s.hdr(req, dns.TypeA),
A: ip.AsSlice(),
}
resp.Answer = append(resp.Answer, a)
case dns.TypeAAAA:
if len(s.dns64Prefs) > 0 {
aaaa := &dns.AAAA{
Hdr: s.hdr(req, dns.TypeAAAA),
AAAA: s.mapDNS64(ip).AsSlice(),
}
resp.Answer = append(resp.Answer, aaaa)
}
default:
// Go on.
}

dctx.proxyCtx.Res = resp

return resultCodeSuccess
Expand Down Expand Up @@ -452,15 +466,28 @@ func (s *Server) processRestrictLocal(dctx *dnsContext) (rc resultCode) {
return resultCodeSuccess
}

// A DNS64 MUST examine the requested address to see whether its prefix
// matches any of the locally configured Pref64::/n or the default
// Well-Known Prefix.
if addr, ok := netip.AddrFromSlice(ip); ok && addr.Is6() && s.withinDNS64OrWellKnown(addr) {
log.Debug("dnsforward: stripping %s which is within DNS64", ip)

ip = ip[nat64PrefixLen:]

// Consider a DNS64-prefixed address as a locally-served one since those
// queries should never be sent to the global DNS.
dctx.unreversedReqIP = ip
}

// Restrict an access to local addresses for external clients. We also
// assume that all the DHCP leases we give are locally-served or at least
// don't need to be accessible externally.
// shouldn't be accessible externally.
if !s.privateNets.Contains(ip) {
log.Debug("dnsforward: addr %s is not from locally-served network", ip)

return resultCodeSuccess
}

log.Debug("dnsforward: addr %s is from locally-served network", ip)

if !dctx.isLocalClient {
log.Debug("dnsforward: %q requests an internal ip", pctx.Addr)
pctx.Res = s.genNXDomain(req)
Expand Down Expand Up @@ -508,7 +535,7 @@ func (s *Server) processDHCPAddrs(dctx *dnsContext) (rc resultCode) {
return resultCodeSuccess
}

// TODO(a.garipov): Remove once we switch to netip.Addr more fully.
// TODO(a.garipov): Remove once we switch to [netip.Addr] more fully.
ipAddr, err := netutil.IPToAddrNoMapped(ip)
if err != nil {
log.Debug("dnsforward: bad reverse ip %v from dhcp: %s", ip, err)
Expand Down Expand Up @@ -556,10 +583,6 @@ func (s *Server) processLocalPTR(dctx *dnsContext) (rc resultCode) {
s.serverLock.RLock()
defer s.serverLock.RUnlock()

if !s.privateNets.Contains(ip) {
return resultCodeSuccess
}

if s.conf.UsePrivateRDNS {
s.recDetector.add(*pctx.Req)
if err := s.localResolvers.Resolve(pctx); err != nil {
Expand Down Expand Up @@ -636,9 +659,8 @@ func (s *Server) processUpstream(dctx *dnsContext) (rc resultCode) {

origReqAD := false
if s.conf.EnableDNSSEC {
if req.AuthenticatedData {
origReqAD = true
} else {
origReqAD = req.AuthenticatedData
if !req.AuthenticatedData {
req.AuthenticatedData = true
}
}
Expand All @@ -655,6 +677,10 @@ func (s *Server) processUpstream(dctx *dnsContext) (rc resultCode) {
return resultCodeError
}

if s.performDNS64(prx, dctx) == resultCodeError {
return resultCodeError
}

dctx.responseFromUpstream = true
dctx.responseAD = pctx.Res.AuthenticatedData

Expand Down
Loading

0 comments on commit 1215316

Please sign in to comment.