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
This commit is contained in:
Maycon Santos 2022-11-29 11:49:18 +01:00 committed by GitHub
parent 20a73e3e14
commit ae500b63a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 47 additions and 24 deletions

View File

@ -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
}

View File

@ -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,
}
}

View File

@ -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 {