From 8cfc895b24f94e0af0f3508a23df630475176381 Mon Sep 17 00:00:00 2001 From: Viktor Liu Date: Sun, 19 Jan 2025 19:59:30 +0100 Subject: [PATCH] Add reverse dns zone --- client/internal/dns.go | 85 +++++++++++++++++++++++++++++++++++++++ client/internal/engine.go | 9 +++-- 2 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 client/internal/dns.go diff --git a/client/internal/dns.go b/client/internal/dns.go new file mode 100644 index 00000000000..b9b8a1ca93e --- /dev/null +++ b/client/internal/dns.go @@ -0,0 +1,85 @@ +package internal + +import ( + "net" + "slices" + "strings" + + "github.com/miekg/dns" + log "github.com/sirupsen/logrus" + + nbdns "github.com/netbirdio/netbird/dns" +) + +func createPTRRecord(aRecord nbdns.SimpleRecord, ipNet *net.IPNet) (nbdns.SimpleRecord, bool) { + ip := net.ParseIP(aRecord.RData) + if ip == nil || ip.To4() == nil { + return nbdns.SimpleRecord{}, false + } + + if !ipNet.Contains(ip) { + return nbdns.SimpleRecord{}, false + } + + ipOctets := strings.Split(ip.String(), ".") + slices.Reverse(ipOctets) + rdnsName := dns.Fqdn(strings.Join(ipOctets, ".") + ".in-addr.arpa") + + return nbdns.SimpleRecord{ + Name: rdnsName, + Type: int(dns.TypePTR), + Class: aRecord.Class, + TTL: aRecord.TTL, + RData: dns.Fqdn(aRecord.Name), + }, true +} + +func addReverseZone(config *nbdns.Config, ipNet *net.IPNet) { + networkIP := ipNet.IP.Mask(ipNet.Mask) + + maskOnes, _ := ipNet.Mask.Size() + // round up to nearest byte + octetsToUse := (maskOnes + 7) / 8 + + octets := strings.Split(networkIP.String(), ".") + if octetsToUse > len(octets) { + log.Warnf("invalid network mask size for reverse DNS: %d", maskOnes) + return + } + + reverseOctets := make([]string, octetsToUse) + for i := 0; i < octetsToUse; i++ { + reverseOctets[octetsToUse-1-i] = octets[i] + } + + zoneName := dns.Fqdn(strings.Join(reverseOctets, ".") + ".in-addr.arpa") + + for _, zone := range config.CustomZones { + if zone.Domain == zoneName { + log.Debugf("reverse DNS zone %s already exists", zoneName) + return + } + } + + var records []nbdns.SimpleRecord + + for _, zone := range config.CustomZones { + for _, record := range zone.Records { + if record.Type != int(dns.TypeA) { + continue + } + + if ptrRecord, ok := createPTRRecord(record, ipNet); ok { + records = append(records, ptrRecord) + } + } + } + + reverseZone := nbdns.CustomZone{ + Domain: zoneName, + Records: records, + } + + config.CustomZones = append(config.CustomZones, reverseZone) + log.Debugf("added reverse DNS zone: %s with %d records", zoneName, len(records)) +} diff --git a/client/internal/engine.go b/client/internal/engine.go index b3689c91153..dceb08ca583 100644 --- a/client/internal/engine.go +++ b/client/internal/engine.go @@ -972,7 +972,7 @@ func (e *Engine) updateNetworkMap(networkMap *mgmProto.NetworkMap) error { protoDNSConfig = &mgmProto.DNSConfig{} } - if err := e.dnsServer.UpdateDNSServer(serial, toDNSConfig(protoDNSConfig)); err != nil { + if err := e.dnsServer.UpdateDNSServer(serial, toDNSConfig(protoDNSConfig, e.wgInterface.Address().Network)); err != nil { log.Errorf("failed to update dns server, err: %v", err) } @@ -1041,7 +1041,7 @@ func toRouteDomains(myPubKey string, protoRoutes []*mgmProto.Route) []string { return dnsRoutes } -func toDNSConfig(protoDNSConfig *mgmProto.DNSConfig) nbdns.Config { +func toDNSConfig(protoDNSConfig *mgmProto.DNSConfig, network *net.IPNet) nbdns.Config { dnsUpdate := nbdns.Config{ ServiceEnable: protoDNSConfig.GetServiceEnable(), CustomZones: make([]nbdns.CustomZone, 0), @@ -1081,6 +1081,9 @@ func toDNSConfig(protoDNSConfig *mgmProto.DNSConfig) nbdns.Config { } dnsUpdate.NameServerGroups = append(dnsUpdate.NameServerGroups, dnsNSGroup) } + + addReverseZone(&dnsUpdate, network) + return dnsUpdate } @@ -1387,7 +1390,7 @@ func (e *Engine) readInitialSettings() ([]*route.Route, *nbdns.Config, error) { return nil, nil, err } routes := toRoutes(netMap.GetRoutes()) - dnsCfg := toDNSConfig(netMap.GetDNSConfig()) + dnsCfg := toDNSConfig(netMap.GetDNSConfig(), e.wgInterface.Address().Network) return routes, &dnsCfg, nil }