From ae500b63a746c0c3e8f02f375da2b02721d9370d Mon Sep 17 00:00:00 2001 From: Maycon Santos Date: Tue, 29 Nov 2022 11:49:18 +0100 Subject: [PATCH] User custom loopback address (#589) We will probe a set of addresses and port to define the one available for our DNS service if none is available, we return an error --- client/internal/dns/server.go | 57 +++++++++++++++++++----------- client/internal/dns/server_test.go | 6 ++-- client/internal/engine_test.go | 8 +++++ 3 files changed, 47 insertions(+), 24 deletions(-) diff --git a/client/internal/dns/server.go b/client/internal/dns/server.go index 91a38cd4a..494472cff 100644 --- a/client/internal/dns/server.go +++ b/client/internal/dns/server.go @@ -15,9 +15,10 @@ import ( ) const ( - port = 53 - customPort = 5053 - defaultIP = "127.0.0.1" + defaultPort = 53 + customPort = 5053 + defaultIP = "127.0.0.1" + customIP = "127.0.0.153" ) // Server is a dns server interface @@ -54,13 +55,8 @@ type muxUpdate struct { // NewDefaultServer returns a new dns server func NewDefaultServer(ctx context.Context, wgInterface *iface.WGIface) (*DefaultServer, error) { mux := dns.NewServeMux() - listenIP := defaultIP - if runtime.GOOS != "darwin" && wgInterface != nil { - listenIP = wgInterface.GetAddress().IP.String() - } dnsServer := &dns.Server{ - Addr: fmt.Sprintf("%s:%d", listenIP, port), Net: "udp", Handler: mux, UDPSize: 65535, @@ -78,8 +74,7 @@ func NewDefaultServer(ctx context.Context, wgInterface *iface.WGIface) (*Default registeredMap: make(registrationMap), }, wgInterface: wgInterface, - runtimePort: port, - runtimeIP: listenIP, + runtimePort: defaultPort, } hostmanager, err := newHostManager(wgInterface) @@ -92,19 +87,15 @@ func NewDefaultServer(ctx context.Context, wgInterface *iface.WGIface) (*Default // Start runs the listener in a go routine func (s *DefaultServer) Start() { - s.runtimePort = port - udpAddr := net.UDPAddrFromAddrPort(netip.MustParseAddrPort(s.server.Addr)) - probeListener, err := net.ListenUDP("udp", udpAddr) + + ip, port, err := s.getFirstListenerAvailable() if err != nil { - log.Warnf("using a custom port for dns server") - s.runtimePort = customPort - s.server.Addr = fmt.Sprintf("%s:%d", s.runtimeIP, customPort) - } else { - err = probeListener.Close() - if err != nil { - log.Errorf("got an error closing the probe listener, error: %s", err) - } + log.Error(err) + return } + s.runtimeIP = ip + s.runtimePort = port + s.server.Addr = fmt.Sprintf("%s:%d", s.runtimeIP, s.runtimePort) log.Debugf("starting dns on %s", s.server.Addr) @@ -119,6 +110,30 @@ func (s *DefaultServer) Start() { }() } +func (s *DefaultServer) getFirstListenerAvailable() (string, int, error) { + ips := []string{defaultIP, customIP} + if runtime.GOOS != "darwin" && s.wgInterface != nil { + ips = append([]string{s.wgInterface.GetAddress().IP.String()}, ips...) + } + ports := []int{defaultPort, customPort} + for _, port := range ports { + for _, ip := range ips { + addrString := fmt.Sprintf("%s:%d", ip, port) + udpAddr := net.UDPAddrFromAddrPort(netip.MustParseAddrPort(addrString)) + probeListener, err := net.ListenUDP("udp", udpAddr) + if err == nil { + err = probeListener.Close() + if err != nil { + log.Errorf("got an error closing the probe listener, error: %s", err) + } + return ip, port, nil + } + log.Warnf("binding dns on %s is not available, error: %s", addrString, err) + } + } + return "", 0, fmt.Errorf("unable to find an unused ip and port combination. IPs tested: %v and ports %v", ips, ports) +} + func (s *DefaultServer) setListenerStatus(running bool) { s.listenerIsRunning = running } diff --git a/client/internal/dns/server_test.go b/client/internal/dns/server_test.go index b0b8cd1ec..9b65f1ae5 100644 --- a/client/internal/dns/server_test.go +++ b/client/internal/dns/server_test.go @@ -257,7 +257,7 @@ func TestDNSServerStartStop(t *testing.T) { d := net.Dialer{ Timeout: time.Second * 5, } - addr := fmt.Sprintf("127.0.0.1:%d", port) + addr := fmt.Sprintf("%s:%d", dnsServer.runtimeIP, dnsServer.runtimePort) conn, err := d.DialContext(ctx, network, addr) if err != nil { t.Log(err) @@ -297,7 +297,7 @@ func getDefaultServerWithNoHostManager(ip string) *DefaultServer { } dnsServer := &dns.Server{ - Addr: fmt.Sprintf("%s:%d", ip, port), + Addr: fmt.Sprintf("%s:%d", ip, defaultPort), Net: "udp", Handler: mux, UDPSize: 65535, @@ -314,7 +314,7 @@ func getDefaultServerWithNoHostManager(ip string) *DefaultServer { localResolver: &localResolver{ registeredMap: make(registrationMap), }, - runtimePort: port, + runtimePort: defaultPort, runtimeIP: listenIP, } } diff --git a/client/internal/engine_test.go b/client/internal/engine_test.go index 9e80f144d..895bfb3ac 100644 --- a/client/internal/engine_test.go +++ b/client/internal/engine_test.go @@ -71,6 +71,10 @@ func TestEngine_SSH(t *testing.T) { WgPort: 33100, }, nbstatus.NewRecorder()) + engine.dnsServer = &dns.MockServer{ + UpdateDNSServerFunc: func(serial uint64, update nbdns.Config) error { return nil }, + } + var sshKeysAdded []string var sshPeersRemoved []string @@ -385,6 +389,10 @@ func TestEngine_Sync(t *testing.T) { WgPort: 33100, }, nbstatus.NewRecorder()) + engine.dnsServer = &dns.MockServer{ + UpdateDNSServerFunc: func(serial uint64, update nbdns.Config) error { return nil }, + } + defer func() { err := engine.Stop() if err != nil {