Skip to content

Commit

Permalink
User custom loopback address (#589)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
mlsmaycon authored Nov 29, 2022
1 parent 20a73e3 commit ae500b6
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 24 deletions.
57 changes: 36 additions & 21 deletions client/internal/dns/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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)
Expand All @@ -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)

Expand All @@ -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
}
Expand Down
6 changes: 3 additions & 3 deletions client/internal/dns/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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,
Expand All @@ -314,7 +314,7 @@ func getDefaultServerWithNoHostManager(ip string) *DefaultServer {
localResolver: &localResolver{
registeredMap: make(registrationMap),
},
runtimePort: port,
runtimePort: defaultPort,
runtimeIP: listenIP,
}
}
8 changes: 8 additions & 0 deletions client/internal/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit ae500b6

Please sign in to comment.