mirror of
https://github.com/netbirdio/netbird.git
synced 2024-12-12 18:00:49 +01:00
trying to bind the DNS resolver dialer to an interface
This commit is contained in:
parent
79f60b86c4
commit
64084ca130
@ -42,9 +42,10 @@ func RunClientMobile(ctx context.Context, config *Config, statusRecorder *peer.S
|
||||
return runClient(ctx, config, statusRecorder, mobileDependency)
|
||||
}
|
||||
|
||||
func RunClientiOS(ctx context.Context, config *Config, statusRecorder *peer.Status, fileDescriptor int32, routeListener routemanager.RouteListener, dnsManager dns.IosDnsManager) error {
|
||||
func RunClientiOS(ctx context.Context, config *Config, statusRecorder *peer.Status, fileDescriptor int32, routeListener routemanager.RouteListener, dnsManager dns.IosDnsManager, interfaceName string) error {
|
||||
mobileDependency := MobileDependency{
|
||||
FileDescriptor: fileDescriptor,
|
||||
InterfaceName: interfaceName,
|
||||
RouteListener: routeListener,
|
||||
DnsManager: dnsManager,
|
||||
}
|
||||
|
@ -53,6 +53,9 @@ type DefaultServer struct {
|
||||
permanent bool
|
||||
hostsDnsList []string
|
||||
hostsDnsListLock sync.Mutex
|
||||
|
||||
interfaceName string
|
||||
wgAddr string
|
||||
}
|
||||
|
||||
type handlerWithStop interface {
|
||||
@ -66,7 +69,7 @@ type muxUpdate struct {
|
||||
}
|
||||
|
||||
// NewDefaultServer returns a new dns server
|
||||
func NewDefaultServer(ctx context.Context, wgInterface WGIface, customAddress string) (*DefaultServer, error) {
|
||||
func NewDefaultServer(ctx context.Context, wgInterface WGIface, customAddress string, interfaceName string, wgAddr string) (*DefaultServer, error) {
|
||||
var addrPort *netip.AddrPort
|
||||
if customAddress != "" {
|
||||
parsedAddrPort, err := netip.ParseAddrPort(customAddress)
|
||||
@ -83,13 +86,13 @@ func NewDefaultServer(ctx context.Context, wgInterface WGIface, customAddress st
|
||||
dnsService = newServiceViaListener(wgInterface, addrPort)
|
||||
}
|
||||
|
||||
return newDefaultServer(ctx, wgInterface, dnsService), nil
|
||||
return newDefaultServer(ctx, wgInterface, dnsService, interfaceName, wgAddr), nil
|
||||
}
|
||||
|
||||
// NewDefaultServerPermanentUpstream returns a new dns server. It optimized for mobile systems
|
||||
func NewDefaultServerPermanentUpstream(ctx context.Context, wgInterface WGIface, hostsDnsList []string) *DefaultServer {
|
||||
log.Debugf("host dns address list is: %v", hostsDnsList)
|
||||
ds := newDefaultServer(ctx, wgInterface, newServiceViaMemory(wgInterface))
|
||||
ds := newDefaultServer(ctx, wgInterface, newServiceViaMemory(wgInterface), "", "")
|
||||
ds.permanent = true
|
||||
ds.hostsDnsList = hostsDnsList
|
||||
ds.addHostRootZone()
|
||||
@ -97,7 +100,7 @@ func NewDefaultServerPermanentUpstream(ctx context.Context, wgInterface WGIface,
|
||||
return ds
|
||||
}
|
||||
|
||||
func newDefaultServer(ctx context.Context, wgInterface WGIface, dnsService service) *DefaultServer {
|
||||
func newDefaultServer(ctx context.Context, wgInterface WGIface, dnsService service, interfaceName string, wgAddr string) *DefaultServer {
|
||||
ctx, stop := context.WithCancel(ctx)
|
||||
defaultServer := &DefaultServer{
|
||||
ctx: ctx,
|
||||
@ -108,6 +111,8 @@ func newDefaultServer(ctx context.Context, wgInterface WGIface, dnsService servi
|
||||
registeredMap: make(registrationMap),
|
||||
},
|
||||
wgInterface: wgInterface,
|
||||
interfaceName: interfaceName,
|
||||
wgAddr: wgAddr,
|
||||
}
|
||||
|
||||
return defaultServer
|
||||
@ -295,7 +300,7 @@ func (s *DefaultServer) buildUpstreamHandlerUpdate(nameServerGroups []*nbdns.Nam
|
||||
continue
|
||||
}
|
||||
|
||||
handler := newUpstreamResolver(s.ctx)
|
||||
handler := newUpstreamResolver(s.ctx, s.interfaceName, s.wgAddr)
|
||||
for _, ns := range nsGroup.NameServers {
|
||||
if ns.NSType != nbdns.UDPNameServerType {
|
||||
log.Warnf("skiping nameserver %s with type %s, this peer supports only %s",
|
||||
@ -468,7 +473,7 @@ func (s *DefaultServer) upstreamCallbacks(
|
||||
}
|
||||
|
||||
func (s *DefaultServer) addHostRootZone() {
|
||||
handler := newUpstreamResolver(s.ctx)
|
||||
handler := newUpstreamResolver(s.ctx, s.interfaceName, s.wgAddr)
|
||||
handler.upstreamServers = make([]string, len(s.hostsDnsList))
|
||||
for n, ua := range s.hostsDnsList {
|
||||
handler.upstreamServers[n] = fmt.Sprintf("%s:53", ua)
|
||||
|
@ -4,14 +4,19 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/netip"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/libp2p/go-netroute"
|
||||
"github.com/miekg/dns"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -40,12 +45,80 @@ type upstreamResolver struct {
|
||||
reactivate func()
|
||||
}
|
||||
|
||||
func newUpstreamResolver(parentCTX context.Context) *upstreamResolver {
|
||||
// func newUpstreamResolver(parentCTX context.Context) *upstreamResolver {
|
||||
// ctx, cancel := context.WithCancel(parentCTX)
|
||||
// return &upstreamResolver{
|
||||
// ctx: ctx,
|
||||
// cancel: cancel,
|
||||
// upstreamClient: &dns.Client{},
|
||||
// upstreamTimeout: upstreamTimeout,
|
||||
// reactivatePeriod: reactivatePeriod,
|
||||
// failsTillDeact: failsTillDeact,
|
||||
// }
|
||||
// }
|
||||
|
||||
func getInterfaceIndex(interfaceName string) (int, error) {
|
||||
iface, err := net.InterfaceByName(interfaceName)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return iface.Index, nil
|
||||
}
|
||||
|
||||
func newUpstreamResolver(parentCTX context.Context, interfaceName string, wgAddr string) *upstreamResolver {
|
||||
ctx, cancel := context.WithCancel(parentCTX)
|
||||
|
||||
// Specify the local IP address you want to bind to
|
||||
localIP, _, err := net.ParseCIDR(wgAddr) // Should be our interface IP
|
||||
if err != nil {
|
||||
log.Errorf("error while parsing CIDR: %s", err)
|
||||
}
|
||||
index, err := getInterfaceIndex(interfaceName)
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
port := rand.Intn(4001) + 1000
|
||||
log.Debugf("UpstreamResolver interface name: %s, index: %d, ip: %s, port: %d", interfaceName, index, localIP, port)
|
||||
if err != nil {
|
||||
log.Debugf("unable to get interface index for %s: %s", interfaceName, err)
|
||||
}
|
||||
localIFaceIndex := index // Should be our interface index
|
||||
// Create a custom dialer with the LocalAddr set to the desired IP
|
||||
dialer := &net.Dialer{
|
||||
LocalAddr: &net.UDPAddr{
|
||||
IP: localIP,
|
||||
Port: port, // Let the OS pick a free port
|
||||
},
|
||||
Control: func(network, address string, c syscall.RawConn) error {
|
||||
var operr error
|
||||
fn := func(s uintptr) {
|
||||
operr = syscall.SetsockoptInt(int(s), unix.IPPROTO_IP, unix.IP_BOUND_IF, localIFaceIndex)
|
||||
}
|
||||
|
||||
if err := c.Control(fn); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return operr
|
||||
},
|
||||
}
|
||||
// pktConn, err := dialer.Dial("udp", "100.127.136.151:10053")
|
||||
// if err != nil {
|
||||
// log.Errorf("error while dialing: %s", err)
|
||||
//
|
||||
// } else {
|
||||
// pktConn.Write([]byte("hello"))
|
||||
// pktConn.Close()
|
||||
// }
|
||||
|
||||
// Create a new DNS client with the custom dialer
|
||||
client := &dns.Client{
|
||||
Dialer: dialer,
|
||||
}
|
||||
|
||||
return &upstreamResolver{
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
upstreamClient: &dns.Client{},
|
||||
upstreamClient: client,
|
||||
upstreamTimeout: upstreamTimeout,
|
||||
reactivatePeriod: reactivatePeriod,
|
||||
failsTillDeact: failsTillDeact,
|
||||
@ -61,7 +134,7 @@ func (u *upstreamResolver) stop() {
|
||||
func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
||||
defer u.checkUpstreamFails()
|
||||
|
||||
log.WithField("question", r.Question[0]).Trace("received an upstream question")
|
||||
log.WithField("question", r.Question[0]).Debug("received an upstream question")
|
||||
|
||||
select {
|
||||
case <-u.ctx.Done():
|
||||
@ -70,6 +143,19 @@ func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
||||
}
|
||||
|
||||
for _, upstream := range u.upstreamServers {
|
||||
log.Debugf("querying the upstream %s", upstream)
|
||||
rr, errR := netroute.New()
|
||||
if errR != nil {
|
||||
log.Errorf("unable to create networute: %s", errR)
|
||||
} else {
|
||||
add := netip.MustParseAddrPort(upstream)
|
||||
_, gateway, preferredSrc, errR := rr.Route(add.Addr().AsSlice())
|
||||
if errR != nil {
|
||||
log.Errorf("getting routes returned an error: %v", errR)
|
||||
} else {
|
||||
log.Infof("upstream %s gateway: %s, preferredSrc: %s", add.Addr(), gateway, preferredSrc)
|
||||
}
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(u.ctx, u.upstreamTimeout)
|
||||
rm, t, err := u.upstreamClient.ExchangeContext(ctx, r, upstream)
|
||||
|
||||
@ -87,7 +173,7 @@ func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
||||
return
|
||||
}
|
||||
|
||||
log.Tracef("took %s to query the upstream %s", t, upstream)
|
||||
log.Debugf("took %s to query the upstream %s", t, upstream)
|
||||
|
||||
err = w.WriteMsg(rm)
|
||||
if err != nil {
|
||||
|
@ -206,7 +206,7 @@ func (e *Engine) Start() error {
|
||||
} else {
|
||||
// todo fix custom address
|
||||
if e.dnsServer == nil {
|
||||
e.dnsServer, err = dns.NewDefaultServer(e.ctx, e.wgInterface, e.config.CustomDNSAddress)
|
||||
e.dnsServer, err = dns.NewDefaultServer(e.ctx, e.wgInterface, e.config.CustomDNSAddress, e.mobileDep.InterfaceName, wgAddr)
|
||||
if err != nil {
|
||||
e.close()
|
||||
return err
|
||||
|
@ -16,4 +16,5 @@ type MobileDependency struct {
|
||||
DnsReadyListener dns.ReadyListener
|
||||
DnsManager dns.IosDnsManager
|
||||
FileDescriptor int32
|
||||
InterfaceName string
|
||||
}
|
||||
|
@ -67,8 +67,9 @@ func NewClient(cfgFile, deviceName string, osVersion string, osName string, rout
|
||||
}
|
||||
|
||||
// Run start the internal client. It is a blocker function
|
||||
func (c *Client) Run(fd int32) error {
|
||||
func (c *Client) Run(fd int32, interfaceName string) error {
|
||||
log.Infof("Starting NetBird client")
|
||||
log.Debugf("Tunnel uses interface: %s", interfaceName)
|
||||
cfg, err := internal.UpdateOrCreateConfig(internal.ConfigInput{
|
||||
ConfigPath: c.cfgFile,
|
||||
})
|
||||
@ -97,7 +98,7 @@ func (c *Client) Run(fd int32) error {
|
||||
// todo do not throw error in case of cancelled context
|
||||
ctx = internal.CtxInitState(ctx)
|
||||
c.onHostDnsFn = func([]string) {}
|
||||
return internal.RunClientiOS(ctx, cfg, c.recorder, fd, c.routeListener, c.dnsManager)
|
||||
return internal.RunClientiOS(ctx, cfg, c.recorder, fd, c.routeListener, c.dnsManager, interfaceName)
|
||||
}
|
||||
|
||||
// Stop the internal client and free the resources
|
||||
|
Loading…
Reference in New Issue
Block a user