mirror of
https://github.com/netbirdio/netbird.git
synced 2024-11-29 11:33:48 +01:00
217 lines
6.7 KiB
Go
217 lines
6.7 KiB
Go
//go:build !android
|
|
|
|
package dns
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net"
|
|
"net/netip"
|
|
"time"
|
|
|
|
"github.com/godbus/dbus/v5"
|
|
"github.com/miekg/dns"
|
|
log "github.com/sirupsen/logrus"
|
|
"golang.org/x/sys/unix"
|
|
|
|
nbdns "github.com/netbirdio/netbird/dns"
|
|
)
|
|
|
|
const (
|
|
systemdDbusManagerInterface = "org.freedesktop.resolve1.Manager"
|
|
systemdResolvedDest = "org.freedesktop.resolve1"
|
|
systemdDbusObjectNode = "/org/freedesktop/resolve1"
|
|
systemdDbusGetLinkMethod = systemdDbusManagerInterface + ".GetLink"
|
|
systemdDbusFlushCachesMethod = systemdDbusManagerInterface + ".FlushCaches"
|
|
systemdDbusResolvConfModeProperty = systemdDbusManagerInterface + ".ResolvConfMode"
|
|
systemdDbusLinkInterface = "org.freedesktop.resolve1.Link"
|
|
systemdDbusRevertMethodSuffix = systemdDbusLinkInterface + ".Revert"
|
|
systemdDbusSetDNSMethodSuffix = systemdDbusLinkInterface + ".SetDNS"
|
|
systemdDbusSetDefaultRouteMethodSuffix = systemdDbusLinkInterface + ".SetDefaultRoute"
|
|
systemdDbusSetDomainsMethodSuffix = systemdDbusLinkInterface + ".SetDomains"
|
|
systemdDbusResolvConfModeForeign = "foreign"
|
|
)
|
|
|
|
type systemdDbusConfigurator struct {
|
|
dbusLinkObject dbus.ObjectPath
|
|
routingAll bool
|
|
}
|
|
|
|
// the types below are based on dbus specification, each field is mapped to a dbus type
|
|
// see https://dbus.freedesktop.org/doc/dbus-specification.html#basic-types for more details on dbus types
|
|
// see https://www.freedesktop.org/software/systemd/man/org.freedesktop.resolve1.html on resolve1 input types
|
|
// systemdDbusDNSInput maps to a (iay) dbus input for SetDNS method
|
|
type systemdDbusDNSInput struct {
|
|
Family int32
|
|
Address []byte
|
|
}
|
|
|
|
// systemdDbusLinkDomainsInput maps to a (sb) dbus input for SetDomains method
|
|
type systemdDbusLinkDomainsInput struct {
|
|
Domain string
|
|
MatchOnly bool
|
|
}
|
|
|
|
func newSystemdDbusConfigurator(wgInterface WGIface) (hostManager, error) {
|
|
iface, err := net.InterfaceByName(wgInterface.Name())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
obj, closeConn, err := getDbusObject(systemdResolvedDest, systemdDbusObjectNode)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer closeConn()
|
|
|
|
var s string
|
|
err = obj.Call(systemdDbusGetLinkMethod, dbusDefaultFlag, iface.Index).Store(&s)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
log.Debugf("got dbus Link interface: %s from net interface %s and index %d", s, iface.Name, iface.Index)
|
|
|
|
return &systemdDbusConfigurator{
|
|
dbusLinkObject: dbus.ObjectPath(s),
|
|
}, nil
|
|
}
|
|
|
|
func (s *systemdDbusConfigurator) supportCustomPort() bool {
|
|
return true
|
|
}
|
|
|
|
func (s *systemdDbusConfigurator) applyDNSConfig(config hostDNSConfig) error {
|
|
parsedIP, err := netip.ParseAddr(config.serverIP)
|
|
if err != nil {
|
|
return fmt.Errorf("unable to parse ip address, error: %s", err)
|
|
}
|
|
ipAs4 := parsedIP.As4()
|
|
defaultLinkInput := systemdDbusDNSInput{
|
|
Family: unix.AF_INET,
|
|
Address: ipAs4[:],
|
|
}
|
|
err = s.callLinkMethod(systemdDbusSetDNSMethodSuffix, []systemdDbusDNSInput{defaultLinkInput})
|
|
if err != nil {
|
|
return fmt.Errorf("setting the interface DNS server %s:%d failed with error: %s", config.serverIP, config.serverPort, err)
|
|
}
|
|
|
|
var (
|
|
searchDomains []string
|
|
matchDomains []string
|
|
domainsInput []systemdDbusLinkDomainsInput
|
|
)
|
|
for _, dConf := range config.domains {
|
|
if dConf.disabled {
|
|
continue
|
|
}
|
|
domainsInput = append(domainsInput, systemdDbusLinkDomainsInput{
|
|
Domain: dns.Fqdn(dConf.domain),
|
|
MatchOnly: dConf.matchOnly,
|
|
})
|
|
|
|
if dConf.matchOnly {
|
|
matchDomains = append(matchDomains, dConf.domain)
|
|
continue
|
|
}
|
|
searchDomains = append(searchDomains, dConf.domain)
|
|
}
|
|
|
|
if config.routeAll {
|
|
log.Infof("configured %s:%d as main DNS forwarder for this peer", config.serverIP, config.serverPort)
|
|
err = s.callLinkMethod(systemdDbusSetDefaultRouteMethodSuffix, true)
|
|
if err != nil {
|
|
return fmt.Errorf("setting link as default dns router, failed with error: %s", err)
|
|
}
|
|
domainsInput = append(domainsInput, systemdDbusLinkDomainsInput{
|
|
Domain: nbdns.RootZone,
|
|
MatchOnly: true,
|
|
})
|
|
s.routingAll = true
|
|
} else if s.routingAll {
|
|
log.Infof("removing %s:%d as main DNS forwarder for this peer", config.serverIP, config.serverPort)
|
|
}
|
|
|
|
log.Infof("adding %d search domains and %d match domains. Search list: %s , Match list: %s", len(searchDomains), len(matchDomains), searchDomains, matchDomains)
|
|
err = s.setDomainsForInterface(domainsInput)
|
|
if err != nil {
|
|
log.Error(err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *systemdDbusConfigurator) setDomainsForInterface(domainsInput []systemdDbusLinkDomainsInput) error {
|
|
err := s.callLinkMethod(systemdDbusSetDomainsMethodSuffix, domainsInput)
|
|
if err != nil {
|
|
return fmt.Errorf("setting domains configuration failed with error: %s", err)
|
|
}
|
|
return s.flushCaches()
|
|
}
|
|
|
|
func (s *systemdDbusConfigurator) restoreHostDNS() error {
|
|
log.Infof("reverting link settings and flushing cache")
|
|
if !isDbusListenerRunning(systemdResolvedDest, s.dbusLinkObject) {
|
|
return nil
|
|
}
|
|
err := s.callLinkMethod(systemdDbusRevertMethodSuffix, nil)
|
|
if err != nil {
|
|
return fmt.Errorf("unable to revert link configuration, got error: %s", err)
|
|
}
|
|
return s.flushCaches()
|
|
}
|
|
|
|
func (s *systemdDbusConfigurator) flushCaches() error {
|
|
obj, closeConn, err := getDbusObject(systemdResolvedDest, systemdDbusObjectNode)
|
|
if err != nil {
|
|
return fmt.Errorf("got error while attempting to retrieve the object %s, err: %s", systemdDbusObjectNode, err)
|
|
}
|
|
defer closeConn()
|
|
ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Second)
|
|
defer cancel()
|
|
|
|
err = obj.CallWithContext(ctx, systemdDbusFlushCachesMethod, dbusDefaultFlag).Store()
|
|
if err != nil {
|
|
return fmt.Errorf("got error while calling the FlushCaches method with context, err: %s", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *systemdDbusConfigurator) callLinkMethod(method string, value any) error {
|
|
obj, closeConn, err := getDbusObject(systemdResolvedDest, s.dbusLinkObject)
|
|
if err != nil {
|
|
return fmt.Errorf("got error while attempting to retrieve the object, err: %s", err)
|
|
}
|
|
defer closeConn()
|
|
|
|
ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Second)
|
|
defer cancel()
|
|
|
|
if value != nil {
|
|
err = obj.CallWithContext(ctx, method, dbusDefaultFlag, value).Store()
|
|
} else {
|
|
err = obj.CallWithContext(ctx, method, dbusDefaultFlag).Store()
|
|
}
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("got error while calling command with context, err: %s", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func getSystemdDbusProperty(property string, store any) error {
|
|
obj, closeConn, err := getDbusObject(systemdResolvedDest, systemdDbusObjectNode)
|
|
if err != nil {
|
|
return fmt.Errorf("got error while attempting to retrieve the systemd dns manager object, error: %s", err)
|
|
}
|
|
defer closeConn()
|
|
|
|
v, e := obj.GetProperty(property)
|
|
if e != nil {
|
|
return fmt.Errorf("got an error getting property %s: %v", property, e)
|
|
}
|
|
|
|
return v.Store(store)
|
|
}
|