From dc05556c5afa69f3dcf360ad650447cd752a09d9 Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Wed, 27 Feb 2019 11:15:18 +0300 Subject: [PATCH 1/8] Fix #542 - Add Bootstrap DNS resolver settings --- config.go | 3 ++- control.go | 40 ++++++++++++++++++++++++++++++++++++++++ dns.go | 2 +- dnsforward/dnsforward.go | 2 +- openapi/openapi.yaml | 24 ++++++++++++++++++++++++ 5 files changed, 68 insertions(+), 3 deletions(-) diff --git a/config.go b/config.go index 87e5c6a8..4f34f1c9 100644 --- a/config.go +++ b/config.go @@ -61,6 +61,7 @@ type dnsConfig struct { } var defaultDNS = []string{"tls://1.1.1.1", "tls://1.0.0.1"} +var defaultBootstrap = []string{"1.1.1.1"} type tlsConfigSettings struct { Enabled bool `yaml:"enabled" json:"enabled"` // Enabled is the encryption (DOT/DOH/HTTPS) status @@ -114,7 +115,7 @@ var config = configuration{ QueryLogEnabled: true, Ratelimit: 20, RefuseAny: true, - BootstrapDNS: "8.8.8.8:53", + BootstrapDNS: defaultBootstrap, }, UpstreamDNS: defaultDNS, }, diff --git a/control.go b/control.go index fd1759e3..480f9fdc 100644 --- a/control.go +++ b/control.go @@ -437,6 +437,45 @@ func checkDNS(input string) error { return nil } +func handleSetBootstrapDNS(w http.ResponseWriter, r *http.Request) { + body, err := ioutil.ReadAll(r.Body) + if err != nil { + errorText := fmt.Sprintf("Failed to read request body: %s", err) + log.Println(errorText) + http.Error(w, errorText, http.StatusBadRequest) + return + } + // if empty body -- user is asking for default servers + hosts := strings.Fields(string(body)) + + if len(hosts) == 0 { + config.DNS.BootstrapDNS = defaultBootstrap + } else { + config.DNS.BootstrapDNS = hosts + } + + err = writeAllConfigs() + if err != nil { + errorText := fmt.Sprintf("Couldn't write config file: %s", err) + log.Println(errorText) + http.Error(w, errorText, http.StatusInternalServerError) + return + } + err = reconfigureDNSServer() + if err != nil { + errorText := fmt.Sprintf("Couldn't reconfigure the DNS server: %s", err) + log.Println(errorText) + http.Error(w, errorText, http.StatusInternalServerError) + return + } + _, err = fmt.Fprintf(w, "OK %d bootsrap servers\n", len(hosts)) + if err != nil { + errorText := fmt.Sprintf("Couldn't write body: %s", err) + log.Println(errorText) + http.Error(w, errorText, http.StatusInternalServerError) + } +} + func handleGetVersionJSON(w http.ResponseWriter, r *http.Request) { now := time.Now() if now.Sub(versionCheckLastTime) <= versionCheckPeriod && len(versionCheckJSON) != 0 { @@ -1317,6 +1356,7 @@ func registerControlHandlers() { http.HandleFunc("/control/querylog_disable", postInstall(optionalAuth(ensurePOST(handleQueryLogDisable)))) http.HandleFunc("/control/set_upstream_dns", postInstall(optionalAuth(ensurePOST(handleSetUpstreamDNS)))) http.HandleFunc("/control/test_upstream_dns", postInstall(optionalAuth(ensurePOST(handleTestUpstreamDNS)))) + http.HandleFunc("/control/set_bootstrap_dns", postInstall(optionalAuth(ensurePOST(handleSetBootstrapDNS)))) http.HandleFunc("/control/i18n/change_language", postInstall(optionalAuth(ensurePOST(handleI18nChangeLanguage)))) http.HandleFunc("/control/i18n/current_language", postInstall(optionalAuth(ensureGET(handleI18nCurrentLanguage)))) http.HandleFunc("/control/stats_top", postInstall(optionalAuth(ensureGET(handleStatsTop)))) diff --git a/dns.go b/dns.go index b7f0d130..c70a4300 100644 --- a/dns.go +++ b/dns.go @@ -61,7 +61,7 @@ func generateServerConfig() dnsforward.ServerConfig { for _, u := range config.DNS.UpstreamDNS { opts := upstream.Options{ Timeout: dnsforward.DefaultTimeout, - Bootstrap: []string{config.DNS.BootstrapDNS}, + Bootstrap: config.DNS.BootstrapDNS, } dnsUpstream, err := upstream.AddressToUpstream(u, opts) if err != nil { diff --git a/dnsforward/dnsforward.go b/dnsforward/dnsforward.go index 99f09e6d..30dd5449 100644 --- a/dnsforward/dnsforward.go +++ b/dnsforward/dnsforward.go @@ -66,7 +66,7 @@ type FilteringConfig struct { Ratelimit int `yaml:"ratelimit"` RatelimitWhitelist []string `yaml:"ratelimit_whitelist"` RefuseAny bool `yaml:"refuse_any"` - BootstrapDNS string `yaml:"bootstrap_dns"` + BootstrapDNS []string `yaml:"bootstrap_dns"` dnsfilter.Config `yaml:",inline"` } diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index f1e23f86..067def2a 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -142,6 +142,30 @@ paths: 8.8.4.4: OK "192.168.1.104:53535": "Couldn't communicate with DNS server" + /set_bootstrap_dns: + post: + tags: + - global + operationId: setBootstrapDNS + summary: 'Set bootstrap DNS for DNS-over-HTTPS and DNS-over-TLS upstreams, empty value will reset it to default values' + consumes: + - text/plain + parameters: + - in: body + name: upstream + description: 'Bootstrap servers, separated by newline or space, port is optional after colon' + schema: + # TODO: use JSON + type: string + example: | + 1.1.1.1 + 1.0.0.1 + 8.8.8.8 8.8.4.4 + 192.168.1.104:53535 + responses: + 200: + description: OK + /version.json: get: tags: From bf893d488afbb306e341f5bcc8e651053d92de97 Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Wed, 27 Feb 2019 12:58:42 +0300 Subject: [PATCH 2/8] Refactoring for set upstream and bootstrap DNS --- control.go | 105 +++++++++++++++++++++++++++++------------------------ 1 file changed, 58 insertions(+), 47 deletions(-) diff --git a/control.go b/control.go index 480f9fdc..726bf2b7 100644 --- a/control.go +++ b/control.go @@ -323,44 +323,94 @@ func sortByValue(m map[string]int) []string { // ----------------------- func handleSetUpstreamDNS(w http.ResponseWriter, r *http.Request) { + setDNSServers(&w, r, true) +} + +func handleSetBootstrapDNS(w http.ResponseWriter, r *http.Request) { + setDNSServers(&w, r, false) +} + +// setDNSServers sets upstream and bootstrap DNS servers +func setDNSServers(w *http.ResponseWriter, r *http.Request, upstreams bool) { body, err := ioutil.ReadAll(r.Body) if err != nil { errorText := fmt.Sprintf("Failed to read request body: %s", err) log.Println(errorText) - http.Error(w, errorText, http.StatusBadRequest) + http.Error(*w, errorText, http.StatusBadRequest) return } // if empty body -- user is asking for default servers hosts := strings.Fields(string(body)) - if len(hosts) == 0 { - config.DNS.UpstreamDNS = defaultDNS + // bootstrap servers are plain DNS only. We should remove tls:// https:// and sdns:// hosts from slice + bootstraps := []string{} + if !upstreams && len(hosts) > 0 { + for _, host := range hosts { + err = checkBootstrapDNS(host) + if err != nil { + log.Tracef("%s can not be used as bootstrap DNS cause: %s", host, err) + continue + } + hosts = append(bootstraps, host) + } + } + + // count of upstream or bootstrap servers + var count int + if upstreams { + count = len(hosts) } else { - config.DNS.UpstreamDNS = hosts + count = len(bootstraps) + } + + if upstreams { + if count == 0 { + config.DNS.UpstreamDNS = defaultDNS + } else { + config.DNS.UpstreamDNS = hosts + } + } else { + if count == 0 { + config.DNS.BootstrapDNS = defaultBootstrap + } else { + config.DNS.BootstrapDNS = bootstraps + } } err = writeAllConfigs() if err != nil { errorText := fmt.Sprintf("Couldn't write config file: %s", err) log.Println(errorText) - http.Error(w, errorText, http.StatusInternalServerError) + http.Error(*w, errorText, http.StatusInternalServerError) return } err = reconfigureDNSServer() if err != nil { errorText := fmt.Sprintf("Couldn't reconfigure the DNS server: %s", err) log.Println(errorText) - http.Error(w, errorText, http.StatusInternalServerError) + http.Error(*w, errorText, http.StatusInternalServerError) return } - _, err = fmt.Fprintf(w, "OK %d servers\n", len(hosts)) + + _, err = fmt.Fprintf(*w, "OK %d servers\n", count) if err != nil { errorText := fmt.Sprintf("Couldn't write body: %s", err) log.Println(errorText) - http.Error(w, errorText, http.StatusInternalServerError) + http.Error(*w, errorText, http.StatusInternalServerError) } } +func checkBootstrapDNS(host string) error { + // Check if host is ip without port + if net.ParseIP(host) != nil { + return nil + } + + // Check if host is ip with port + _, _, err := net.SplitHostPort(host) + return err +} + func handleTestUpstreamDNS(w http.ResponseWriter, r *http.Request) { body, err := ioutil.ReadAll(r.Body) if err != nil { @@ -437,45 +487,6 @@ func checkDNS(input string) error { return nil } -func handleSetBootstrapDNS(w http.ResponseWriter, r *http.Request) { - body, err := ioutil.ReadAll(r.Body) - if err != nil { - errorText := fmt.Sprintf("Failed to read request body: %s", err) - log.Println(errorText) - http.Error(w, errorText, http.StatusBadRequest) - return - } - // if empty body -- user is asking for default servers - hosts := strings.Fields(string(body)) - - if len(hosts) == 0 { - config.DNS.BootstrapDNS = defaultBootstrap - } else { - config.DNS.BootstrapDNS = hosts - } - - err = writeAllConfigs() - if err != nil { - errorText := fmt.Sprintf("Couldn't write config file: %s", err) - log.Println(errorText) - http.Error(w, errorText, http.StatusInternalServerError) - return - } - err = reconfigureDNSServer() - if err != nil { - errorText := fmt.Sprintf("Couldn't reconfigure the DNS server: %s", err) - log.Println(errorText) - http.Error(w, errorText, http.StatusInternalServerError) - return - } - _, err = fmt.Fprintf(w, "OK %d bootsrap servers\n", len(hosts)) - if err != nil { - errorText := fmt.Sprintf("Couldn't write body: %s", err) - log.Println(errorText) - http.Error(w, errorText, http.StatusInternalServerError) - } -} - func handleGetVersionJSON(w http.ResponseWriter, r *http.Request) { now := time.Now() if now.Sub(versionCheckLastTime) <= versionCheckPeriod && len(versionCheckJSON) != 0 { From 87c8114291179880a75f83943e33551774ae09f0 Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Wed, 27 Feb 2019 13:12:06 +0300 Subject: [PATCH 3/8] Use gotools --- control.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/control.go b/control.go index 726bf2b7..e9890575 100644 --- a/control.go +++ b/control.go @@ -391,7 +391,6 @@ func setDNSServers(w *http.ResponseWriter, r *http.Request, upstreams bool) { http.Error(*w, errorText, http.StatusInternalServerError) return } - _, err = fmt.Fprintf(*w, "OK %d servers\n", count) if err != nil { errorText := fmt.Sprintf("Couldn't write body: %s", err) @@ -400,6 +399,7 @@ func setDNSServers(w *http.ResponseWriter, r *http.Request, upstreams bool) { } } +// checkBootstrapDNS checks if host is plain DNS func checkBootstrapDNS(host string) error { // Check if host is ip without port if net.ParseIP(host) != nil { From 3a9d436f8ae72a74f9e248d857c3d875aa81fcec Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Wed, 27 Feb 2019 16:15:36 +0300 Subject: [PATCH 4/8] Add schema migration --- control.go | 52 ++++++++++++++++++------------------------ dhcp.go | 16 ++++++------- go.mod | 1 + upgrade.go | 66 +++++++++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 91 insertions(+), 44 deletions(-) diff --git a/control.go b/control.go index e9890575..dd368380 100644 --- a/control.go +++ b/control.go @@ -57,10 +57,10 @@ func returnOK(w http.ResponseWriter) { } } -func httpError(w http.ResponseWriter, code int, format string, args ...interface{}) { +func httpError(w *http.ResponseWriter, code int, format string, args ...interface{}) { text := fmt.Sprintf(format, args...) log.Println(text) - http.Error(w, text, code) + http.Error(*w, text, code) } // --------------- @@ -78,7 +78,7 @@ func writeAllConfigsAndReloadDNS() error { func httpUpdateConfigReloadDNSReturnOK(w http.ResponseWriter, r *http.Request) { err := writeAllConfigsAndReloadDNS() if err != nil { - httpError(w, http.StatusInternalServerError, "Couldn't write config file: %s", err) + httpError(&w, http.StatusInternalServerError, "Couldn't write config file: %s", err) return } returnOK(w) @@ -334,9 +334,7 @@ func handleSetBootstrapDNS(w http.ResponseWriter, r *http.Request) { func setDNSServers(w *http.ResponseWriter, r *http.Request, upstreams bool) { body, err := ioutil.ReadAll(r.Body) if err != nil { - errorText := fmt.Sprintf("Failed to read request body: %s", err) - log.Println(errorText) - http.Error(*w, errorText, http.StatusBadRequest) + httpError(w, http.StatusBadRequest, "Failed to read request body: %s", err) return } // if empty body -- user is asking for default servers @@ -379,23 +377,17 @@ func setDNSServers(w *http.ResponseWriter, r *http.Request, upstreams bool) { err = writeAllConfigs() if err != nil { - errorText := fmt.Sprintf("Couldn't write config file: %s", err) - log.Println(errorText) - http.Error(*w, errorText, http.StatusInternalServerError) + httpError(w, http.StatusInternalServerError, "Couldn't write config file: %s", err) return } err = reconfigureDNSServer() if err != nil { - errorText := fmt.Sprintf("Couldn't reconfigure the DNS server: %s", err) - log.Println(errorText) - http.Error(*w, errorText, http.StatusInternalServerError) + httpError(w, http.StatusInternalServerError, "Couldn't reconfigure the DNS server: %s", err) return } _, err = fmt.Fprintf(*w, "OK %d servers\n", count) if err != nil { - errorText := fmt.Sprintf("Couldn't write body: %s", err) - log.Println(errorText) - http.Error(*w, errorText, http.StatusInternalServerError) + httpError(w, http.StatusInternalServerError, "Couldn't write body: %s", err) } } @@ -574,7 +566,7 @@ func handleFilteringAddURL(w http.ResponseWriter, r *http.Request) { f := filter{} err := json.NewDecoder(r.Body).Decode(&f) if err != nil { - httpError(w, http.StatusBadRequest, "Failed to parse request body json: %s", err) + httpError(&w, http.StatusBadRequest, "Failed to parse request body json: %s", err) return } @@ -975,7 +967,7 @@ func handleInstallGetAddresses(w http.ResponseWriter, r *http.Request) { ifaces, err := getValidNetInterfacesForWeb() if err != nil { - httpError(w, http.StatusInternalServerError, "Couldn't get interfaces: %s", err) + httpError(&w, http.StatusInternalServerError, "Couldn't get interfaces: %s", err) return } @@ -987,7 +979,7 @@ func handleInstallGetAddresses(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") err = json.NewEncoder(w).Encode(data) if err != nil { - httpError(w, http.StatusInternalServerError, "Unable to marshal default addresses to json: %s", err) + httpError(&w, http.StatusInternalServerError, "Unable to marshal default addresses to json: %s", err) return } } @@ -996,7 +988,7 @@ func handleInstallConfigure(w http.ResponseWriter, r *http.Request) { newSettings := firstRunData{} err := json.NewDecoder(r.Body).Decode(&newSettings) if err != nil { - httpError(w, http.StatusBadRequest, "Failed to parse new config json: %s", err) + httpError(&w, http.StatusBadRequest, "Failed to parse new config json: %s", err) return } @@ -1010,14 +1002,14 @@ func handleInstallConfigure(w http.ResponseWriter, r *http.Request) { if restartHTTP { err = checkPortAvailable(newSettings.Web.IP, newSettings.Web.Port) if err != nil { - httpError(w, http.StatusBadRequest, "Impossible to listen on IP:port %s due to %s", net.JoinHostPort(newSettings.Web.IP, strconv.Itoa(newSettings.Web.Port)), err) + httpError(&w, http.StatusBadRequest, "Impossible to listen on IP:port %s due to %s", net.JoinHostPort(newSettings.Web.IP, strconv.Itoa(newSettings.Web.Port)), err) return } } err = checkPacketPortAvailable(newSettings.DNS.IP, newSettings.DNS.Port) if err != nil { - httpError(w, http.StatusBadRequest, "Impossible to listen on IP:port %s due to %s", net.JoinHostPort(newSettings.DNS.IP, strconv.Itoa(newSettings.DNS.Port)), err) + httpError(&w, http.StatusBadRequest, "Impossible to listen on IP:port %s due to %s", net.JoinHostPort(newSettings.DNS.IP, strconv.Itoa(newSettings.DNS.Port)), err) return } @@ -1032,7 +1024,7 @@ func handleInstallConfigure(w http.ResponseWriter, r *http.Request) { if config.DNS.Port != 0 { err = startDNSServer() if err != nil { - httpError(w, http.StatusInternalServerError, "Couldn't start DNS server: %s", err) + httpError(&w, http.StatusInternalServerError, "Couldn't start DNS server: %s", err) return } } @@ -1057,7 +1049,7 @@ func handleTLSStatus(w http.ResponseWriter, r *http.Request) { func handleTLSValidate(w http.ResponseWriter, r *http.Request) { data, err := unmarshalTLS(r) if err != nil { - httpError(w, http.StatusBadRequest, "Failed to unmarshal TLS config: %s", err) + httpError(&w, http.StatusBadRequest, "Failed to unmarshal TLS config: %s", err) return } @@ -1070,7 +1062,7 @@ func handleTLSValidate(w http.ResponseWriter, r *http.Request) { if !alreadyRunning { err = checkPortAvailable(config.BindHost, data.PortHTTPS) if err != nil { - httpError(w, http.StatusBadRequest, "port %d is not available, cannot enable HTTPS on it", data.PortHTTPS) + httpError(&w, http.StatusBadRequest, "port %d is not available, cannot enable HTTPS on it", data.PortHTTPS) return } } @@ -1082,7 +1074,7 @@ func handleTLSValidate(w http.ResponseWriter, r *http.Request) { func handleTLSConfigure(w http.ResponseWriter, r *http.Request) { data, err := unmarshalTLS(r) if err != nil { - httpError(w, http.StatusBadRequest, "Failed to unmarshal TLS config: %s", err) + httpError(&w, http.StatusBadRequest, "Failed to unmarshal TLS config: %s", err) return } @@ -1095,7 +1087,7 @@ func handleTLSConfigure(w http.ResponseWriter, r *http.Request) { if !alreadyRunning { err = checkPortAvailable(config.BindHost, data.PortHTTPS) if err != nil { - httpError(w, http.StatusBadRequest, "port %d is not available, cannot enable HTTPS on it", data.PortHTTPS) + httpError(&w, http.StatusBadRequest, "port %d is not available, cannot enable HTTPS on it", data.PortHTTPS) return } } @@ -1109,7 +1101,7 @@ func handleTLSConfigure(w http.ResponseWriter, r *http.Request) { config.TLS = data err = writeAllConfigsAndReloadDNS() if err != nil { - httpError(w, http.StatusInternalServerError, "Couldn't write config file: %s", err) + httpError(&w, http.StatusInternalServerError, "Couldn't write config file: %s", err) return } marshalTLS(w, data) @@ -1328,7 +1320,7 @@ func marshalTLS(w http.ResponseWriter, data tlsConfig) { } err := json.NewEncoder(w).Encode(data) if err != nil { - httpError(w, http.StatusInternalServerError, "Failed to marshal json with TLS status: %s", err) + httpError(&w, http.StatusInternalServerError, "Failed to marshal json with TLS status: %s", err) return } } @@ -1338,12 +1330,12 @@ func marshalTLS(w http.ResponseWriter, data tlsConfig) { // -------------- func handleDOH(w http.ResponseWriter, r *http.Request) { if r.TLS == nil { - httpError(w, http.StatusNotFound, "Not Found") + httpError(&w, http.StatusNotFound, "Not Found") return } if !isRunning() { - httpError(w, http.StatusInternalServerError, "DNS server is not running") + httpError(&w, http.StatusInternalServerError, "DNS server is not running") return } diff --git a/dhcp.go b/dhcp.go index a67b0ef6..6098a1a2 100644 --- a/dhcp.go +++ b/dhcp.go @@ -37,7 +37,7 @@ func handleDHCPStatus(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") err := json.NewEncoder(w).Encode(status) if err != nil { - httpError(w, http.StatusInternalServerError, "Unable to marshal DHCP status json: %s", err) + httpError(&w, http.StatusInternalServerError, "Unable to marshal DHCP status json: %s", err) return } } @@ -46,14 +46,14 @@ func handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) { newconfig := dhcpd.ServerConfig{} err := json.NewDecoder(r.Body).Decode(&newconfig) if err != nil { - httpError(w, http.StatusBadRequest, "Failed to parse new DHCP config json: %s", err) + httpError(&w, http.StatusBadRequest, "Failed to parse new DHCP config json: %s", err) return } if newconfig.Enabled { err := dhcpServer.Start(&newconfig) if err != nil { - httpError(w, http.StatusBadRequest, "Failed to start DHCP server: %s", err) + httpError(&w, http.StatusBadRequest, "Failed to start DHCP server: %s", err) return } } @@ -72,7 +72,7 @@ func handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) { ifaces, err := getValidNetInterfaces() if err != nil { - httpError(w, http.StatusInternalServerError, "Couldn't get interfaces: %s", err) + httpError(&w, http.StatusInternalServerError, "Couldn't get interfaces: %s", err) return } @@ -87,7 +87,7 @@ func handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) { } addrs, err := iface.Addrs() if err != nil { - httpError(w, http.StatusInternalServerError, "Failed to get addresses for interface %s: %s", iface.Name, err) + httpError(&w, http.StatusInternalServerError, "Failed to get addresses for interface %s: %s", iface.Name, err) return } @@ -105,7 +105,7 @@ func handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) { ipnet, ok := addr.(*net.IPNet) if !ok { // not an IPNet, should not happen - httpError(w, http.StatusInternalServerError, "SHOULD NOT HAPPEN: got iface.Addrs() element %s that is not net.IPNet, it is %T", addr, addr) + httpError(&w, http.StatusInternalServerError, "SHOULD NOT HAPPEN: got iface.Addrs() element %s that is not net.IPNet, it is %T", addr, addr) return } // ignore link-local @@ -122,7 +122,7 @@ func handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) { err = json.NewEncoder(w).Encode(response) if err != nil { - httpError(w, http.StatusInternalServerError, "Failed to marshal json with available interfaces: %s", err) + httpError(&w, http.StatusInternalServerError, "Failed to marshal json with available interfaces: %s", err) return } } @@ -153,7 +153,7 @@ func handleDHCPFindActiveServer(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") err = json.NewEncoder(w).Encode(result) if err != nil { - httpError(w, http.StatusInternalServerError, "Failed to marshal DHCP found json: %s", err) + httpError(&w, http.StatusInternalServerError, "Failed to marshal DHCP found json: %s", err) return } } diff --git a/go.mod b/go.mod index cba63387..ebc1b9f3 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( github.com/kardianos/service v0.0.0-20181115005516-4c239ee84e7b github.com/krolaw/dhcp4 v0.0.0-20180925202202-7cead472c414 github.com/miekg/dns v1.1.1 + github.com/pkg/errors v0.8.0 github.com/shirou/gopsutil v2.18.10+incompatible github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 // indirect github.com/stretchr/testify v1.2.2 diff --git a/upgrade.go b/upgrade.go index 0b3ddc5c..b431dc71 100644 --- a/upgrade.go +++ b/upgrade.go @@ -1,6 +1,7 @@ package main import ( + "errors" "fmt" "io/ioutil" "os" @@ -10,7 +11,7 @@ import ( yaml "gopkg.in/yaml.v2" ) -const currentSchemaVersion = 2 // used for upgrading from old configs to new config +const currentSchemaVersion = 3 // used for upgrading from old configs to new config // Performs necessary upgrade operations if needed func upgradeConfig() error { @@ -59,12 +60,17 @@ func upgradeConfig() error { func upgradeConfigSchema(oldVersion int, diskConfig *map[string]interface{}) error { switch oldVersion { case 0: - err := upgradeSchema0to2(diskConfig) + err := upgradeSchema0to3(diskConfig) if err != nil { return err } case 1: - err := upgradeSchema1to2(diskConfig) + err := upgradeSchema1to3(diskConfig) + if err != nil { + return err + } + case 2: + err := upgradeSchema2to3(diskConfig) if err != nil { return err } @@ -135,12 +141,60 @@ func upgradeSchema1to2(diskConfig *map[string]interface{}) error { return nil } -// jump two schemas at once -- this time we just do it sequentially -func upgradeSchema0to2(diskConfig *map[string]interface{}) error { +// Third schema upgrade: +// Bootstrap DNS becomes an array +func upgradeSchema2to3(diskConfig *map[string]interface{}) error { + log.Printf("%s(): called", _Func()) + + // Let's read dns configuration from diskConfig + dnsConfig, ok := (*diskConfig)["dns"] + if !ok { + return errors.New("no DNS configuration in config file") + } + + // Convert interface{} to map[string]interface{} + newDNSConfig := make(map[string]interface{}) + + switch v := dnsConfig.(type) { + case map[interface{}]interface{}: + for k, v := range v { + newDNSConfig[fmt.Sprint(k)] = v + } + default: + return errors.New("DNS configuration is not a map") + } + + // Replace bootstrap_dns value filed with new array contains old bootstrap_dns inside + if bootstrapDNS, ok := (newDNSConfig)["bootstrap_dns"]; ok { + newBootstrapConfig := []string{fmt.Sprint(bootstrapDNS)} + (newDNSConfig)["bootstrap_dns"] = newBootstrapConfig + (*diskConfig)["dns"] = newDNSConfig + } else { + return errors.New("no bootstrap DNS in DNS config") + } + + // Bump schema version + (*diskConfig)["schema_version"] = 3 + + return nil +} + +// jump three schemas at once -- this time we just do it sequentially +func upgradeSchema0to3(diskConfig *map[string]interface{}) error { err := upgradeSchema0to1(diskConfig) if err != nil { return err } - return upgradeSchema1to2(diskConfig) + return upgradeSchema1to3(diskConfig) +} + +// jump two schemas at once -- this time we just do it sequentially +func upgradeSchema1to3(diskConfig *map[string]interface{}) error { + err := upgradeSchema1to2(diskConfig) + if err != nil { + return err + } + + return upgradeSchema2to3(diskConfig) } From 141b14c94a1ef319188e555a51044d4b52f9dddf Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Wed, 27 Feb 2019 16:19:45 +0300 Subject: [PATCH 5/8] Remove unuseful library --- go.mod | 1 - upgrade.go | 7 +++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index ebc1b9f3..cba63387 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,6 @@ require ( github.com/kardianos/service v0.0.0-20181115005516-4c239ee84e7b github.com/krolaw/dhcp4 v0.0.0-20180925202202-7cead472c414 github.com/miekg/dns v1.1.1 - github.com/pkg/errors v0.8.0 github.com/shirou/gopsutil v2.18.10+incompatible github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 // indirect github.com/stretchr/testify v1.2.2 diff --git a/upgrade.go b/upgrade.go index b431dc71..8932b9c7 100644 --- a/upgrade.go +++ b/upgrade.go @@ -1,7 +1,6 @@ package main import ( - "errors" "fmt" "io/ioutil" "os" @@ -149,7 +148,7 @@ func upgradeSchema2to3(diskConfig *map[string]interface{}) error { // Let's read dns configuration from diskConfig dnsConfig, ok := (*diskConfig)["dns"] if !ok { - return errors.New("no DNS configuration in config file") + return fmt.Errorf("no DNS configuration in config file") } // Convert interface{} to map[string]interface{} @@ -161,7 +160,7 @@ func upgradeSchema2to3(diskConfig *map[string]interface{}) error { newDNSConfig[fmt.Sprint(k)] = v } default: - return errors.New("DNS configuration is not a map") + return fmt.Errorf("DNS configuration is not a map") } // Replace bootstrap_dns value filed with new array contains old bootstrap_dns inside @@ -170,7 +169,7 @@ func upgradeSchema2to3(diskConfig *map[string]interface{}) error { (newDNSConfig)["bootstrap_dns"] = newBootstrapConfig (*diskConfig)["dns"] = newDNSConfig } else { - return errors.New("no bootstrap DNS in DNS config") + return fmt.Errorf("no bootstrap DNS in DNS config") } // Bump schema version From 1223965cd43a50b96e7f76f78d936f6995370b65 Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Wed, 27 Feb 2019 16:42:50 +0300 Subject: [PATCH 6/8] Code simplify --- control.go | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/control.go b/control.go index dd368380..e5d88082 100644 --- a/control.go +++ b/control.go @@ -354,23 +354,19 @@ func setDNSServers(w *http.ResponseWriter, r *http.Request, upstreams bool) { } // count of upstream or bootstrap servers - var count int - if upstreams { - count = len(hosts) - } else { + count := len(hosts) + if !upstreams { count = len(bootstraps) } if upstreams { - if count == 0 { - config.DNS.UpstreamDNS = defaultDNS - } else { + config.DNS.UpstreamDNS = defaultDNS + if count != 0 { config.DNS.UpstreamDNS = hosts } } else { - if count == 0 { - config.DNS.BootstrapDNS = defaultBootstrap - } else { + config.DNS.BootstrapDNS = defaultBootstrap + if count != 0 { config.DNS.BootstrapDNS = bootstraps } } From a9839e95a0f1b3a0d8af09cdaa94308cb2f49c16 Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Wed, 27 Feb 2019 16:50:19 +0300 Subject: [PATCH 7/8] pointer is unuseful for httpError func --- control.go | 44 ++++++++++++++++++++++---------------------- dhcp.go | 16 ++++++++-------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/control.go b/control.go index e5d88082..3136ae2c 100644 --- a/control.go +++ b/control.go @@ -57,10 +57,10 @@ func returnOK(w http.ResponseWriter) { } } -func httpError(w *http.ResponseWriter, code int, format string, args ...interface{}) { +func httpError(w http.ResponseWriter, code int, format string, args ...interface{}) { text := fmt.Sprintf(format, args...) log.Println(text) - http.Error(*w, text, code) + http.Error(w, text, code) } // --------------- @@ -78,7 +78,7 @@ func writeAllConfigsAndReloadDNS() error { func httpUpdateConfigReloadDNSReturnOK(w http.ResponseWriter, r *http.Request) { err := writeAllConfigsAndReloadDNS() if err != nil { - httpError(&w, http.StatusInternalServerError, "Couldn't write config file: %s", err) + httpError(w, http.StatusInternalServerError, "Couldn't write config file: %s", err) return } returnOK(w) @@ -323,15 +323,15 @@ func sortByValue(m map[string]int) []string { // ----------------------- func handleSetUpstreamDNS(w http.ResponseWriter, r *http.Request) { - setDNSServers(&w, r, true) + setDNSServers(w, r, true) } func handleSetBootstrapDNS(w http.ResponseWriter, r *http.Request) { - setDNSServers(&w, r, false) + setDNSServers(w, r, false) } // setDNSServers sets upstream and bootstrap DNS servers -func setDNSServers(w *http.ResponseWriter, r *http.Request, upstreams bool) { +func setDNSServers(w http.ResponseWriter, r *http.Request, upstreams bool) { body, err := ioutil.ReadAll(r.Body) if err != nil { httpError(w, http.StatusBadRequest, "Failed to read request body: %s", err) @@ -381,7 +381,7 @@ func setDNSServers(w *http.ResponseWriter, r *http.Request, upstreams bool) { httpError(w, http.StatusInternalServerError, "Couldn't reconfigure the DNS server: %s", err) return } - _, err = fmt.Fprintf(*w, "OK %d servers\n", count) + _, err = fmt.Fprintf(w, "OK %d servers\n", count) if err != nil { httpError(w, http.StatusInternalServerError, "Couldn't write body: %s", err) } @@ -562,7 +562,7 @@ func handleFilteringAddURL(w http.ResponseWriter, r *http.Request) { f := filter{} err := json.NewDecoder(r.Body).Decode(&f) if err != nil { - httpError(&w, http.StatusBadRequest, "Failed to parse request body json: %s", err) + httpError(w, http.StatusBadRequest, "Failed to parse request body json: %s", err) return } @@ -963,7 +963,7 @@ func handleInstallGetAddresses(w http.ResponseWriter, r *http.Request) { ifaces, err := getValidNetInterfacesForWeb() if err != nil { - httpError(&w, http.StatusInternalServerError, "Couldn't get interfaces: %s", err) + httpError(w, http.StatusInternalServerError, "Couldn't get interfaces: %s", err) return } @@ -975,7 +975,7 @@ func handleInstallGetAddresses(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") err = json.NewEncoder(w).Encode(data) if err != nil { - httpError(&w, http.StatusInternalServerError, "Unable to marshal default addresses to json: %s", err) + httpError(w, http.StatusInternalServerError, "Unable to marshal default addresses to json: %s", err) return } } @@ -984,7 +984,7 @@ func handleInstallConfigure(w http.ResponseWriter, r *http.Request) { newSettings := firstRunData{} err := json.NewDecoder(r.Body).Decode(&newSettings) if err != nil { - httpError(&w, http.StatusBadRequest, "Failed to parse new config json: %s", err) + httpError(w, http.StatusBadRequest, "Failed to parse new config json: %s", err) return } @@ -998,14 +998,14 @@ func handleInstallConfigure(w http.ResponseWriter, r *http.Request) { if restartHTTP { err = checkPortAvailable(newSettings.Web.IP, newSettings.Web.Port) if err != nil { - httpError(&w, http.StatusBadRequest, "Impossible to listen on IP:port %s due to %s", net.JoinHostPort(newSettings.Web.IP, strconv.Itoa(newSettings.Web.Port)), err) + httpError(w, http.StatusBadRequest, "Impossible to listen on IP:port %s due to %s", net.JoinHostPort(newSettings.Web.IP, strconv.Itoa(newSettings.Web.Port)), err) return } } err = checkPacketPortAvailable(newSettings.DNS.IP, newSettings.DNS.Port) if err != nil { - httpError(&w, http.StatusBadRequest, "Impossible to listen on IP:port %s due to %s", net.JoinHostPort(newSettings.DNS.IP, strconv.Itoa(newSettings.DNS.Port)), err) + httpError(w, http.StatusBadRequest, "Impossible to listen on IP:port %s due to %s", net.JoinHostPort(newSettings.DNS.IP, strconv.Itoa(newSettings.DNS.Port)), err) return } @@ -1020,7 +1020,7 @@ func handleInstallConfigure(w http.ResponseWriter, r *http.Request) { if config.DNS.Port != 0 { err = startDNSServer() if err != nil { - httpError(&w, http.StatusInternalServerError, "Couldn't start DNS server: %s", err) + httpError(w, http.StatusInternalServerError, "Couldn't start DNS server: %s", err) return } } @@ -1045,7 +1045,7 @@ func handleTLSStatus(w http.ResponseWriter, r *http.Request) { func handleTLSValidate(w http.ResponseWriter, r *http.Request) { data, err := unmarshalTLS(r) if err != nil { - httpError(&w, http.StatusBadRequest, "Failed to unmarshal TLS config: %s", err) + httpError(w, http.StatusBadRequest, "Failed to unmarshal TLS config: %s", err) return } @@ -1058,7 +1058,7 @@ func handleTLSValidate(w http.ResponseWriter, r *http.Request) { if !alreadyRunning { err = checkPortAvailable(config.BindHost, data.PortHTTPS) if err != nil { - httpError(&w, http.StatusBadRequest, "port %d is not available, cannot enable HTTPS on it", data.PortHTTPS) + httpError(w, http.StatusBadRequest, "port %d is not available, cannot enable HTTPS on it", data.PortHTTPS) return } } @@ -1070,7 +1070,7 @@ func handleTLSValidate(w http.ResponseWriter, r *http.Request) { func handleTLSConfigure(w http.ResponseWriter, r *http.Request) { data, err := unmarshalTLS(r) if err != nil { - httpError(&w, http.StatusBadRequest, "Failed to unmarshal TLS config: %s", err) + httpError(w, http.StatusBadRequest, "Failed to unmarshal TLS config: %s", err) return } @@ -1083,7 +1083,7 @@ func handleTLSConfigure(w http.ResponseWriter, r *http.Request) { if !alreadyRunning { err = checkPortAvailable(config.BindHost, data.PortHTTPS) if err != nil { - httpError(&w, http.StatusBadRequest, "port %d is not available, cannot enable HTTPS on it", data.PortHTTPS) + httpError(w, http.StatusBadRequest, "port %d is not available, cannot enable HTTPS on it", data.PortHTTPS) return } } @@ -1097,7 +1097,7 @@ func handleTLSConfigure(w http.ResponseWriter, r *http.Request) { config.TLS = data err = writeAllConfigsAndReloadDNS() if err != nil { - httpError(&w, http.StatusInternalServerError, "Couldn't write config file: %s", err) + httpError(w, http.StatusInternalServerError, "Couldn't write config file: %s", err) return } marshalTLS(w, data) @@ -1316,7 +1316,7 @@ func marshalTLS(w http.ResponseWriter, data tlsConfig) { } err := json.NewEncoder(w).Encode(data) if err != nil { - httpError(&w, http.StatusInternalServerError, "Failed to marshal json with TLS status: %s", err) + httpError(w, http.StatusInternalServerError, "Failed to marshal json with TLS status: %s", err) return } } @@ -1326,12 +1326,12 @@ func marshalTLS(w http.ResponseWriter, data tlsConfig) { // -------------- func handleDOH(w http.ResponseWriter, r *http.Request) { if r.TLS == nil { - httpError(&w, http.StatusNotFound, "Not Found") + httpError(w, http.StatusNotFound, "Not Found") return } if !isRunning() { - httpError(&w, http.StatusInternalServerError, "DNS server is not running") + httpError(w, http.StatusInternalServerError, "DNS server is not running") return } diff --git a/dhcp.go b/dhcp.go index 6098a1a2..a67b0ef6 100644 --- a/dhcp.go +++ b/dhcp.go @@ -37,7 +37,7 @@ func handleDHCPStatus(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") err := json.NewEncoder(w).Encode(status) if err != nil { - httpError(&w, http.StatusInternalServerError, "Unable to marshal DHCP status json: %s", err) + httpError(w, http.StatusInternalServerError, "Unable to marshal DHCP status json: %s", err) return } } @@ -46,14 +46,14 @@ func handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) { newconfig := dhcpd.ServerConfig{} err := json.NewDecoder(r.Body).Decode(&newconfig) if err != nil { - httpError(&w, http.StatusBadRequest, "Failed to parse new DHCP config json: %s", err) + httpError(w, http.StatusBadRequest, "Failed to parse new DHCP config json: %s", err) return } if newconfig.Enabled { err := dhcpServer.Start(&newconfig) if err != nil { - httpError(&w, http.StatusBadRequest, "Failed to start DHCP server: %s", err) + httpError(w, http.StatusBadRequest, "Failed to start DHCP server: %s", err) return } } @@ -72,7 +72,7 @@ func handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) { ifaces, err := getValidNetInterfaces() if err != nil { - httpError(&w, http.StatusInternalServerError, "Couldn't get interfaces: %s", err) + httpError(w, http.StatusInternalServerError, "Couldn't get interfaces: %s", err) return } @@ -87,7 +87,7 @@ func handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) { } addrs, err := iface.Addrs() if err != nil { - httpError(&w, http.StatusInternalServerError, "Failed to get addresses for interface %s: %s", iface.Name, err) + httpError(w, http.StatusInternalServerError, "Failed to get addresses for interface %s: %s", iface.Name, err) return } @@ -105,7 +105,7 @@ func handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) { ipnet, ok := addr.(*net.IPNet) if !ok { // not an IPNet, should not happen - httpError(&w, http.StatusInternalServerError, "SHOULD NOT HAPPEN: got iface.Addrs() element %s that is not net.IPNet, it is %T", addr, addr) + httpError(w, http.StatusInternalServerError, "SHOULD NOT HAPPEN: got iface.Addrs() element %s that is not net.IPNet, it is %T", addr, addr) return } // ignore link-local @@ -122,7 +122,7 @@ func handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) { err = json.NewEncoder(w).Encode(response) if err != nil { - httpError(&w, http.StatusInternalServerError, "Failed to marshal json with available interfaces: %s", err) + httpError(w, http.StatusInternalServerError, "Failed to marshal json with available interfaces: %s", err) return } } @@ -153,7 +153,7 @@ func handleDHCPFindActiveServer(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") err = json.NewEncoder(w).Encode(result) if err != nil { - httpError(&w, http.StatusInternalServerError, "Failed to marshal DHCP found json: %s", err) + httpError(w, http.StatusInternalServerError, "Failed to marshal DHCP found json: %s", err) return } } From bc325de13f2714961fdf32ef79fc3451d8db1f83 Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Wed, 27 Feb 2019 18:49:53 +0300 Subject: [PATCH 8/8] Add missed logging --- control.go | 1 + 1 file changed, 1 insertion(+) diff --git a/control.go b/control.go index 52f7932f..2a32b0b4 100644 --- a/control.go +++ b/control.go @@ -338,6 +338,7 @@ func handleSetUpstreamDNS(w http.ResponseWriter, r *http.Request) { } func handleSetBootstrapDNS(w http.ResponseWriter, r *http.Request) { + log.Tracef("%s %v", r.Method, r.URL) setDNSServers(w, r, false) }