From daae040f9cb2e9dbcbfd03e31d4e899fce2049c0 Mon Sep 17 00:00:00 2001 From: Eugene Bujak Date: Fri, 1 Feb 2019 19:25:04 +0300 Subject: [PATCH] Check if IP:port combinations are possible before returning OK on /install/configure --- app.go | 16 +++++++++------- control.go | 17 ++++++++++++++--- helpers.go | 14 ++++++++++++-- 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/app.go b/app.go index 6fa8ef34..71f3ee82 100644 --- a/app.go +++ b/app.go @@ -116,14 +116,16 @@ func run(args options) { log.Fatal(err) } - err = startDNSServer() - if err != nil { - log.Fatal(err) - } + if !config.firstRun { + err = startDNSServer() + if err != nil { + log.Fatal(err) + } - err = startDHCPServer() - if err != nil { - log.Fatal(err) + err = startDHCPServer() + if err != nil { + log.Fatal(err) + } } // Update filters we've just loaded right away, don't wait for periodic update timer diff --git a/control.go b/control.go index 38464a90..1f64ae6c 100644 --- a/control.go +++ b/control.go @@ -723,7 +723,7 @@ func handleInstallGetAddresses(w http.ResponseWriter, r *http.Request) { // fill out the fields // find out if port 80 is available -- if not, fall back to 3000 - if checkPortAvailable(80) { + if checkPortAvailable("", 80) { data.Web.Port = 80 } else { data.Web.Port = 3000 @@ -731,7 +731,7 @@ func handleInstallGetAddresses(w http.ResponseWriter, r *http.Request) { // find out if port 53 is available -- if not, show a big warning data.DNS.Port = 53 - if !checkPortAvailable(53) { + if !checkPacketPortAvailable("", 53) { data.DNS.Warning = "Port 53 is not available for binding -- this will make DNS clients unable to contact AdGuard Home." } @@ -764,7 +764,18 @@ func handleInstallConfigure(w http.ResponseWriter, r *http.Request) { } spew.Dump(newSettings) - // TODO: validate that hosts and ports are bindable + // validate that hosts and ports are bindable + + if !checkPortAvailable(newSettings.Web.IP, newSettings.Web.Port) { + httpError(w, http.StatusBadRequest, "Impossible to listen on IP:port %s:%d", newSettings.Web.IP, newSettings.Web.Port) + return + } + + if !checkPacketPortAvailable(newSettings.DNS.IP, newSettings.DNS.Port) { + httpError(w, http.StatusBadRequest, "Impossible to listen on IP:port %s:%d", newSettings.DNS.IP, newSettings.DNS.Port) + return + } + config.firstRun = false config.BindHost = newSettings.Web.IP config.BindPort = newSettings.Web.Port diff --git a/helpers.go b/helpers.go index f83b9821..9dbd59b7 100644 --- a/helpers.go +++ b/helpers.go @@ -12,6 +12,7 @@ import ( "path" "path/filepath" "runtime" + "strconv" "strings" "github.com/hmage/golibs/log" @@ -259,8 +260,17 @@ func findIPv4IfaceAddr(ifaces []netInterface) string { } // checkPortAvailable is not a cheap test to see if the port is bindable, because it's actually doing the bind momentarily -func checkPortAvailable(port int) bool { - ln, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) +func checkPortAvailable(host string, port int) bool { + ln, err := net.Listen("tcp", net.JoinHostPort(host, strconv.Itoa(port))) + if err != nil { + return false + } + ln.Close() + return true +} + +func checkPacketPortAvailable(host string, port int) bool { + ln, err := net.ListenPacket("udp", net.JoinHostPort(host, strconv.Itoa(port))) if err != nil { return false }