From 2dc2a0946a28f41736228db1065654716907c5b8 Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Tue, 26 Feb 2019 15:32:56 +0300 Subject: [PATCH 01/95] Fix #595 - Start using GO 1.12 --- .travis.yml | 6 +++--- README.md | 2 +- app.go | 11 +++++++++++ go.mod | 2 ++ 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6d690463..f4319221 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: go sudo: false go: - - 1.11.x + - 1.12.x - 1.x os: - linux @@ -38,7 +38,7 @@ matrix: # Release build configuration - name: release go: - - 1.11.x + - 1.12.x os: - linux @@ -66,7 +66,7 @@ matrix: - name: docker if: type != pull_request AND (branch = master OR tag = true) go: - - 1.11.x + - 1.12.x os: - linux services: diff --git a/README.md b/README.md index 054fc951..84f1a194 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ Alternatively, you can use our [official Docker image](https://hub.docker.com/r/ You will need: - * [go](https://golang.org/dl/) v1.11 or later. + * [go](https://golang.org/dl/) v1.12 or later. * [node.js](https://nodejs.org/en/download/) v10 or later. You can either install it via the provided links or use [brew.sh](https://brew.sh/) if you're on Mac: diff --git a/app.go b/app.go index 0b55b6fa..1178678e 100644 --- a/app.go +++ b/app.go @@ -71,6 +71,9 @@ func run(args options) { // configure log level and output configureLogger(args) + // enable TLS 1.3 + enableTLS13() + // print the first message after logger is configured log.Printf("AdGuard Home, version %s\n", VersionString) log.Tracef("Current working directory is %s", config.ourWorkingDir) @@ -291,6 +294,14 @@ func configureLogger(args options) { } } +// TODO after GO 1.13 release TLS 1.3 will be enabled by default. Remove this afterward +func enableTLS13() { + err := os.Setenv("GODEBUG", os.Getenv("GODEBUG")+",tls13=1") + if err != nil { + log.Fatalf("Failed to enable TLS 1.3: %s", err) + } +} + func cleanup() { log.Printf("Stopping AdGuard Home") diff --git a/go.mod b/go.mod index cba63387..2f28b7e8 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,7 @@ module github.com/AdguardTeam/AdGuardHome +go 1.12 + require ( github.com/AdguardTeam/dnsproxy v0.11.1 github.com/StackExchange/wmi v0.0.0-20180725035823-b12b22c5341f // indirect From 5bc6d00aa03baa826ed84b3c134ed80db05e1388 Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Tue, 26 Feb 2019 18:19:05 +0300 Subject: [PATCH 02/95] Fix #596 - Intelligent Optimal DNS Resolution --- config.go | 1 + control.go | 36 ++++++++++++++++++++++++++++++++++++ dnsforward/dnsforward.go | 2 ++ openapi/openapi.yaml | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+) diff --git a/config.go b/config.go index 87e5c6a8..2df9ec07 100644 --- a/config.go +++ b/config.go @@ -114,6 +114,7 @@ var config = configuration{ QueryLogEnabled: true, Ratelimit: 20, RefuseAny: true, + AllServers: false, BootstrapDNS: "8.8.8.8:53", }, UpstreamDNS: defaultDNS, diff --git a/control.go b/control.go index fd1759e3..70ff0e7c 100644 --- a/control.go +++ b/control.go @@ -94,6 +94,7 @@ func handleStatus(w http.ResponseWriter, r *http.Request) { "running": isRunning(), "bootstrap_dns": config.DNS.BootstrapDNS, "upstream_dns": config.DNS.UpstreamDNS, + "all_servers": config.DNS.AllServers, "version": VersionString, "language": config.Language, } @@ -361,6 +362,38 @@ func handleSetUpstreamDNS(w http.ResponseWriter, r *http.Request) { } } +func handleAllServersEnable(w http.ResponseWriter, r *http.Request) { + config.DNS.AllServers = true + httpUpdateConfigReloadDNSReturnOK(w, r) +} + +func handleAllServersDisable(w http.ResponseWriter, r *http.Request) { + config.DNS.AllServers = false + httpUpdateConfigReloadDNSReturnOK(w, r) +} + +func handleAllServersStatus(w http.ResponseWriter, r *http.Request) { + data := map[string]interface{}{ + "enabled": config.DNS.AllServers, + } + jsonVal, err := json.Marshal(data) + if err != nil { + errorText := fmt.Sprintf("Unable to marshal status json: %s", err) + log.Println(errorText) + http.Error(w, errorText, 500) + return + } + + w.Header().Set("Content-Type", "application/json") + _, err = w.Write(jsonVal) + if err != nil { + errorText := fmt.Sprintf("Unable to write response json: %s", err) + log.Println(errorText) + http.Error(w, errorText, 500) + return + } +} + func handleTestUpstreamDNS(w http.ResponseWriter, r *http.Request) { body, err := ioutil.ReadAll(r.Body) if err != nil { @@ -1317,6 +1350,9 @@ 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/all_servers/enable", postInstall(optionalAuth(ensurePOST(handleAllServersEnable)))) + http.HandleFunc("/control/all_servers/disable", postInstall(optionalAuth(ensurePOST(handleAllServersDisable)))) + http.HandleFunc("/control/all_servers/status", postInstall(optionalAuth(ensureGET(handleAllServersStatus)))) 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/dnsforward/dnsforward.go b/dnsforward/dnsforward.go index 99f09e6d..bf975ac5 100644 --- a/dnsforward/dnsforward.go +++ b/dnsforward/dnsforward.go @@ -67,6 +67,7 @@ type FilteringConfig struct { RatelimitWhitelist []string `yaml:"ratelimit_whitelist"` RefuseAny bool `yaml:"refuse_any"` BootstrapDNS string `yaml:"bootstrap_dns"` + AllServers bool `yaml:"all_servers"` dnsfilter.Config `yaml:",inline"` } @@ -163,6 +164,7 @@ func (s *Server) startInternal(config *ServerConfig) error { CacheEnabled: true, Upstreams: s.Upstreams, Handler: s.handleDNSRequest, + AllServers: s.AllServers, } if s.TLSListenAddr != nil && s.CertificateChain != "" && s.PrivateKey != "" { diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index f1e23f86..e83d6360 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -111,6 +111,39 @@ paths: 200: description: OK + /all_servers/enable: + post: + tags: + - global + operationId: allServersEnable + summary: 'Enable parallel queries' + responses: + 200: + description: OK + + /all_servers/disable: + post: + tags: + - global + operationId: allServersDisable + summary: 'Disable parallel queries' + responses: + 200: + description: OK + + /all_servers/status: + get: + tags: + - global + operationId: allServersStatus + summary: 'Get parallel queries status' + responses: + 200: + description: OK + examples: + application/json: + enabled: false + /test_upstream_dns: post: tags: From dc05556c5afa69f3dcf360ad650447cd752a09d9 Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Wed, 27 Feb 2019 11:15:18 +0300 Subject: [PATCH 03/95] 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 5ba43a59f4ea6035b4428c9bde9dfa2c65bb8beb Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Wed, 27 Feb 2019 11:31:25 +0300 Subject: [PATCH 04/95] Fix server reconfig --- dns.go | 1 + 1 file changed, 1 insertion(+) diff --git a/dns.go b/dns.go index b7f0d130..6dfa2e8c 100644 --- a/dns.go +++ b/dns.go @@ -71,6 +71,7 @@ func generateServerConfig() dnsforward.ServerConfig { } newconfig.Upstreams = append(newconfig.Upstreams, dnsUpstream) } + newconfig.AllServers = config.DNS.AllServers return newconfig } From 2a93e45b671b422bf384548b221360d0c8e22d33 Mon Sep 17 00:00:00 2001 From: Carl Bennett Date: Tue, 26 Feb 2019 17:28:34 -0600 Subject: [PATCH 05/95] Fix typo in client/src/__locales/en.json --- client/src/__locales/en.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index 4d8ac38c..45c33828 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -215,7 +215,7 @@ "encryption_config_saved": "Encryption config saved", "encryption_server": "Server name", "encryption_server_enter": "Enter your domain name", - "encryption_server_desc": "In order to use HTTPS, you need yo enter the server name that matches your SSL certificate.", + "encryption_server_desc": "In order to use HTTPS, you need to enter the server name that matches your SSL certificate.", "encryption_redirect": "Redirect to HTTPS automatically", "encryption_redirect_desc": "If checked, AdGuard Home will automatically redirect you from HTTP to HTTPS addresses.", "encryption_https": "HTTPS port", @@ -247,4 +247,4 @@ "form_error_password": "Password mismatched", "reset_settings": "Reset settings", "update_announcement": "AdGuard Home {{version}} is now available! <0>Click here for more info." -} \ No newline at end of file +} From bf893d488afbb306e341f5bcc8e651053d92de97 Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Wed, 27 Feb 2019 12:58:42 +0300 Subject: [PATCH 06/95] 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 d218e047a3de91895b873d627de557722c84814c Mon Sep 17 00:00:00 2001 From: Simon Zolin Date: Wed, 27 Feb 2019 13:07:29 +0300 Subject: [PATCH 07/95] + add tests for validateCertificates() --- control_test.go | 81 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 control_test.go diff --git a/control_test.go b/control_test.go new file mode 100644 index 00000000..725457b9 --- /dev/null +++ b/control_test.go @@ -0,0 +1,81 @@ +package main + +import ( + "testing" + "time" +) + +/* Tests performed: +. Bad certificate +. Bad private key +. Valid certificate & private key */ +func TestValidateCertificates(t *testing.T) { + var data tlsConfig + + // bad cert + data.CertificateChain = "bad cert" + data.PrivateKey = "" + data = validateCertificates(data) + if !(data.WarningValidation != "" && + !data.ValidCert && + !data.ValidChain) { + t.Fatalf("bad cert: validateCertificates(): %v", data) + } + + // bad priv key + data.CertificateChain = "" + data.PrivateKey = "bad priv key" + data = validateCertificates(data) + if !(data.WarningValidation != "" && + !data.ValidKey) { + t.Fatalf("bad priv key: validateCertificates(): %v", data) + } + + // valid cert & priv key + data.CertificateChain = `-----BEGIN CERTIFICATE----- +MIICKzCCAZSgAwIBAgIJAMT9kPVJdM7LMA0GCSqGSIb3DQEBCwUAMC0xFDASBgNV +BAoMC0FkR3VhcmQgTHRkMRUwEwYDVQQDDAxBZEd1YXJkIEhvbWUwHhcNMTkwMjI3 +MDkyNDIzWhcNNDYwNzE0MDkyNDIzWjAtMRQwEgYDVQQKDAtBZEd1YXJkIEx0ZDEV +MBMGA1UEAwwMQWRHdWFyZCBIb21lMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB +gQCwvwUnPJiOvLcOaWmGu6Y68ksFr13nrXBcsDlhxlXy8PaohVi3XxEmt2OrVjKW +QFw/bdV4fZ9tdWFAVRRkgeGbIZzP7YBD1Ore/O5SQ+DbCCEafvjJCcXQIrTeKFE6 +i9G3aSMHs0Pwq2LgV8U5mYotLrvyFiE8QPInJbDDMpaFYwIDAQABo1MwUTAdBgNV +HQ4EFgQUdLUmQpEqrhn4eKO029jYd2AAZEQwHwYDVR0jBBgwFoAUdLUmQpEqrhn4 +eKO029jYd2AAZEQwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQB8 +LwlXfbakf7qkVTlCNXgoY7RaJ8rJdPgOZPoCTVToEhT6u/cb1c2qp8QB0dNExDna +b0Z+dnODTZqQOJo6z/wIXlcUrnR4cQVvytXt8lFn+26l6Y6EMI26twC/xWr+1swq +Muj4FeWHVDerquH4yMr1jsYLD3ci+kc5sbIX6TfVxQ== +-----END CERTIFICATE-----` + data.PrivateKey = `-----BEGIN PRIVATE KEY----- +MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBALC/BSc8mI68tw5p +aYa7pjrySwWvXeetcFywOWHGVfLw9qiFWLdfESa3Y6tWMpZAXD9t1Xh9n211YUBV +FGSB4ZshnM/tgEPU6t787lJD4NsIIRp++MkJxdAitN4oUTqL0bdpIwezQ/CrYuBX +xTmZii0uu/IWITxA8iclsMMyloVjAgMBAAECgYEAmjzoG1h27UDkIlB9BVWl95TP +QVPLB81D267xNFDnWk1Lgr5zL/pnNjkdYjyjgpkBp1yKyE4gHV4skv5sAFWTcOCU +QCgfPfUn/rDFcxVzAdJVWAa/CpJNaZgjTPR8NTGU+Ztod+wfBESNCP5tbnuw0GbL +MuwdLQJGbzeJYpsNysECQQDfFHYoRNfgxHwMbX24GCoNZIgk12uDmGTA9CS5E+72 +9t3V1y4CfXxSkfhqNbd5RWrUBRLEw9BKofBS7L9NMDKDAkEAytQoIueE1vqEAaRg +a3A1YDUekKesU5wKfKfKlXvNgB7Hwh4HuvoQS9RCvVhf/60Dvq8KSu6hSjkFRquj +FQ5roQJBAMwKwyiCD5MfJPeZDmzcbVpiocRQ5Z4wPbffl9dRTDnIA5AciZDthlFg +An/jMjZSMCxNl6UyFcqt5Et1EGVhuFECQQCZLXxaT+qcyHjlHJTMzuMgkz1QFbEp +O5EX70gpeGQMPDK0QSWpaazg956njJSDbNCFM4BccrdQbJu1cW4qOsfBAkAMgZuG +O88slmgTRHX4JGFmy3rrLiHNI2BbJSuJ++Yllz8beVzh6NfvuY+HKRCmPqoBPATU +kXS9jgARhhiWXJrk +-----END PRIVATE KEY-----` + data = validateCertificates(data) + notBefore, _ := time.Parse(time.RFC3339, "2019-02-27T09:24:23Z") + notAfter, _ := time.Parse(time.RFC3339, "2046-07-14T09:24:23Z") + if !(data.WarningValidation != "" /* self signed */ && + data.ValidCert && + !data.ValidChain && + data.ValidKey && + data.KeyType == "RSA" && + data.Subject == "CN=AdGuard Home,O=AdGuard Ltd" && + data.Issuer == "CN=AdGuard Home,O=AdGuard Ltd" && + data.NotBefore == notBefore && + data.NotAfter == notAfter && + // data.DNSNames[0] == && + data.usable) { + t.Fatalf("valid cert & priv key: validateCertificates(): %v", data) + } +} From 87c8114291179880a75f83943e33551774ae09f0 Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Wed, 27 Feb 2019 13:12:06 +0300 Subject: [PATCH 08/95] 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 766fbab0718f2b02fb3864e521820033ab015e36 Mon Sep 17 00:00:00 2001 From: Simon Zolin Date: Wed, 27 Feb 2019 14:11:41 +0300 Subject: [PATCH 09/95] * validateCertificates(): change input parameters; added short description --- app.go | 4 ++-- control.go | 31 +++++++++++++++++-------------- control_test.go | 16 ++++++---------- 3 files changed, 25 insertions(+), 26 deletions(-) diff --git a/app.go b/app.go index 0b55b6fa..07c67916 100644 --- a/app.go +++ b/app.go @@ -178,13 +178,13 @@ func run(args options) { } address := net.JoinHostPort(config.BindHost, strconv.Itoa(config.TLS.PortHTTPS)) // validate current TLS config and update warnings (it could have been loaded from file) - data := validateCertificates(config.TLS) + data := validateCertificates(config.TLS.CertificateChain, config.TLS.PrivateKey, config.TLS.ServerName) if !data.usable { log.Fatal(data.WarningValidation) os.Exit(1) } config.Lock() - config.TLS = data // update warnings + config.TLS.tlsConfigStatus = data // update warnings config.Unlock() // prepare certs for HTTPS server diff --git a/control.go b/control.go index fd1759e3..f6b4bab1 100644 --- a/control.go +++ b/control.go @@ -1025,7 +1025,7 @@ func handleTLSValidate(w http.ResponseWriter, r *http.Request) { } } - data = validateCertificates(data) + data.tlsConfigStatus = validateCertificates(data.CertificateChain, data.PrivateKey, data.ServerName) marshalTLS(w, data) } @@ -1051,7 +1051,7 @@ func handleTLSConfigure(w http.ResponseWriter, r *http.Request) { } restartHTTPS := false - data = validateCertificates(data) + data.tlsConfigStatus = validateCertificates(data.CertificateChain, data.PrivateKey, data.ServerName) if !reflect.DeepEqual(config.TLS.tlsConfigSettings, data.tlsConfigSettings) { log.Printf("tls config settings have changed, will restart HTTPS server") restartHTTPS = true @@ -1078,21 +1078,24 @@ func handleTLSConfigure(w http.ResponseWriter, r *http.Request) { } } -func validateCertificates(data tlsConfig) tlsConfig { +/* Process certificate data and its private key. +CertificateChain, PrivateKey parameters are optional. +On error, return partially set object + with 'WarningValidation' field containing error description. +*/ +func validateCertificates(CertificateChain, PrivateKey, ServerName string) tlsConfigStatus { var err error - - // clear out status for certificates - data.tlsConfigStatus = tlsConfigStatus{} + var data tlsConfigStatus // check only public certificate separately from the key - if data.CertificateChain != "" { - log.Tracef("got certificate: %s", data.CertificateChain) + if CertificateChain != "" { + log.Tracef("got certificate: %s", CertificateChain) // now do a more extended validation var certs []*pem.Block // PEM-encoded certificates var skippedBytes []string // skipped bytes - pemblock := []byte(data.CertificateChain) + pemblock := []byte(CertificateChain) for { var decoded *pem.Block decoded, pemblock = pem.Decode(pemblock) @@ -1127,7 +1130,7 @@ func validateCertificates(data tlsConfig) tlsConfig { // spew.Dump(parsedCerts) opts := x509.VerifyOptions{ - DNSName: data.ServerName, + DNSName: ServerName, } log.Printf("number of certs - %d", len(parsedCerts)) @@ -1164,13 +1167,13 @@ func validateCertificates(data tlsConfig) tlsConfig { } // validate private key (right now the only validation possible is just parsing it) - if data.PrivateKey != "" { + if PrivateKey != "" { // now do a more extended validation var key *pem.Block // PEM-encoded certificates var skippedBytes []string // skipped bytes // go through all pem blocks, but take first valid pem block and drop the rest - pemblock := []byte(data.PrivateKey) + pemblock := []byte(PrivateKey) for { var decoded *pem.Block decoded, pemblock = pem.Decode(pemblock) @@ -1202,8 +1205,8 @@ func validateCertificates(data tlsConfig) tlsConfig { } // if both are set, validate both in unison - if data.PrivateKey != "" && data.CertificateChain != "" { - _, err = tls.X509KeyPair([]byte(data.CertificateChain), []byte(data.PrivateKey)) + if PrivateKey != "" && CertificateChain != "" { + _, err = tls.X509KeyPair([]byte(CertificateChain), []byte(PrivateKey)) if err != nil { data.WarningValidation = fmt.Sprintf("Invalid certificate or key: %s", err) return data diff --git a/control_test.go b/control_test.go index 725457b9..c5df3b45 100644 --- a/control_test.go +++ b/control_test.go @@ -10,12 +10,10 @@ import ( . Bad private key . Valid certificate & private key */ func TestValidateCertificates(t *testing.T) { - var data tlsConfig + var data tlsConfigStatus // bad cert - data.CertificateChain = "bad cert" - data.PrivateKey = "" - data = validateCertificates(data) + data = validateCertificates("bad cert", "", "") if !(data.WarningValidation != "" && !data.ValidCert && !data.ValidChain) { @@ -23,16 +21,14 @@ func TestValidateCertificates(t *testing.T) { } // bad priv key - data.CertificateChain = "" - data.PrivateKey = "bad priv key" - data = validateCertificates(data) + data = validateCertificates("", "bad priv key", "") if !(data.WarningValidation != "" && !data.ValidKey) { t.Fatalf("bad priv key: validateCertificates(): %v", data) } // valid cert & priv key - data.CertificateChain = `-----BEGIN CERTIFICATE----- + CertificateChain := `-----BEGIN CERTIFICATE----- MIICKzCCAZSgAwIBAgIJAMT9kPVJdM7LMA0GCSqGSIb3DQEBCwUAMC0xFDASBgNV BAoMC0FkR3VhcmQgTHRkMRUwEwYDVQQDDAxBZEd1YXJkIEhvbWUwHhcNMTkwMjI3 MDkyNDIzWhcNNDYwNzE0MDkyNDIzWjAtMRQwEgYDVQQKDAtBZEd1YXJkIEx0ZDEV @@ -46,7 +42,7 @@ LwlXfbakf7qkVTlCNXgoY7RaJ8rJdPgOZPoCTVToEhT6u/cb1c2qp8QB0dNExDna b0Z+dnODTZqQOJo6z/wIXlcUrnR4cQVvytXt8lFn+26l6Y6EMI26twC/xWr+1swq Muj4FeWHVDerquH4yMr1jsYLD3ci+kc5sbIX6TfVxQ== -----END CERTIFICATE-----` - data.PrivateKey = `-----BEGIN PRIVATE KEY----- + PrivateKey := `-----BEGIN PRIVATE KEY----- MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBALC/BSc8mI68tw5p aYa7pjrySwWvXeetcFywOWHGVfLw9qiFWLdfESa3Y6tWMpZAXD9t1Xh9n211YUBV FGSB4ZshnM/tgEPU6t787lJD4NsIIRp++MkJxdAitN4oUTqL0bdpIwezQ/CrYuBX @@ -62,7 +58,7 @@ O5EX70gpeGQMPDK0QSWpaazg956njJSDbNCFM4BccrdQbJu1cW4qOsfBAkAMgZuG O88slmgTRHX4JGFmy3rrLiHNI2BbJSuJ++Yllz8beVzh6NfvuY+HKRCmPqoBPATU kXS9jgARhhiWXJrk -----END PRIVATE KEY-----` - data = validateCertificates(data) + data = validateCertificates(CertificateChain, PrivateKey, "") notBefore, _ := time.Parse(time.RFC3339, "2019-02-27T09:24:23Z") notAfter, _ := time.Parse(time.RFC3339, "2046-07-14T09:24:23Z") if !(data.WarningValidation != "" /* self signed */ && From f4a6ca726c56febfac49ff72cb05533f404ae4c9 Mon Sep 17 00:00:00 2001 From: Simon Zolin Date: Wed, 27 Feb 2019 14:31:53 +0300 Subject: [PATCH 10/95] * validateCertificates(): split the function's code --- control.go | 240 ++++++++++++++++++++++++++++------------------------- 1 file changed, 128 insertions(+), 112 deletions(-) diff --git a/control.go b/control.go index f6b4bab1..57e614ca 100644 --- a/control.go +++ b/control.go @@ -1078,135 +1078,151 @@ func handleTLSConfigure(w http.ResponseWriter, r *http.Request) { } } +// Return 0 on success +func verifyCertChain(data *tlsConfigStatus, certChain string, serverName string) int { + log.Tracef("got certificate: %s", certChain) + + // now do a more extended validation + var certs []*pem.Block // PEM-encoded certificates + var skippedBytes []string // skipped bytes + + pemblock := []byte(certChain) + for { + var decoded *pem.Block + decoded, pemblock = pem.Decode(pemblock) + if decoded == nil { + break + } + if decoded.Type == "CERTIFICATE" { + certs = append(certs, decoded) + } else { + skippedBytes = append(skippedBytes, decoded.Type) + } + } + + var parsedCerts []*x509.Certificate + + for _, cert := range certs { + parsed, err := x509.ParseCertificate(cert.Bytes) + if err != nil { + data.WarningValidation = fmt.Sprintf("Failed to parse certificate: %s", err) + return 1 + } + parsedCerts = append(parsedCerts, parsed) + } + + if len(parsedCerts) == 0 { + data.WarningValidation = fmt.Sprintf("You have specified an empty certificate") + return 1 + } + + data.ValidCert = true + + // spew.Dump(parsedCerts) + + opts := x509.VerifyOptions{ + DNSName: serverName, + } + + log.Printf("number of certs - %d", len(parsedCerts)) + if len(parsedCerts) > 1 { + // set up an intermediate + pool := x509.NewCertPool() + for _, cert := range parsedCerts[1:] { + log.Printf("got an intermediate cert") + pool.AddCert(cert) + } + opts.Intermediates = pool + } + + // TODO: save it as a warning rather than error it out -- shouldn't be a big problem + mainCert := parsedCerts[0] + _, err := mainCert.Verify(opts) + if err != nil { + // let self-signed certs through + data.WarningValidation = fmt.Sprintf("Your certificate does not verify: %s", err) + } else { + data.ValidChain = true + } + // spew.Dump(chains) + + // update status + if mainCert != nil { + notAfter := mainCert.NotAfter + data.Subject = mainCert.Subject.String() + data.Issuer = mainCert.Issuer.String() + data.NotAfter = notAfter + data.NotBefore = mainCert.NotBefore + data.DNSNames = mainCert.DNSNames + } + + return 0 +} + +// Return 0 on success +func validatePkey(data *tlsConfigStatus, pkey string) int { + // now do a more extended validation + var key *pem.Block // PEM-encoded certificates + var skippedBytes []string // skipped bytes + + // go through all pem blocks, but take first valid pem block and drop the rest + pemblock := []byte(pkey) + for { + var decoded *pem.Block + decoded, pemblock = pem.Decode(pemblock) + if decoded == nil { + break + } + if decoded.Type == "PRIVATE KEY" || strings.HasSuffix(decoded.Type, " PRIVATE KEY") { + key = decoded + break + } else { + skippedBytes = append(skippedBytes, decoded.Type) + } + } + + if key == nil { + data.WarningValidation = "No valid keys were found" + return 1 + } + + // parse the decoded key + _, keytype, err := parsePrivateKey(key.Bytes) + if err != nil { + data.WarningValidation = fmt.Sprintf("Failed to parse private key: %s", err) + return 1 + } + + data.ValidKey = true + data.KeyType = keytype + return 0 +} + /* Process certificate data and its private key. -CertificateChain, PrivateKey parameters are optional. +All parameters are optional. On error, return partially set object with 'WarningValidation' field containing error description. */ -func validateCertificates(CertificateChain, PrivateKey, ServerName string) tlsConfigStatus { - var err error +func validateCertificates(certChain, pkey, serverName string) tlsConfigStatus { var data tlsConfigStatus // check only public certificate separately from the key - if CertificateChain != "" { - log.Tracef("got certificate: %s", CertificateChain) - - // now do a more extended validation - var certs []*pem.Block // PEM-encoded certificates - var skippedBytes []string // skipped bytes - - pemblock := []byte(CertificateChain) - for { - var decoded *pem.Block - decoded, pemblock = pem.Decode(pemblock) - if decoded == nil { - break - } - if decoded.Type == "CERTIFICATE" { - certs = append(certs, decoded) - } else { - skippedBytes = append(skippedBytes, decoded.Type) - } - } - - var parsedCerts []*x509.Certificate - - for _, cert := range certs { - parsed, err := x509.ParseCertificate(cert.Bytes) - if err != nil { - data.WarningValidation = fmt.Sprintf("Failed to parse certificate: %s", err) - return data - } - parsedCerts = append(parsedCerts, parsed) - } - - if len(parsedCerts) == 0 { - data.WarningValidation = fmt.Sprintf("You have specified an empty certificate") + if certChain != "" { + if verifyCertChain(&data, certChain, serverName) != 0 { return data } - - data.ValidCert = true - - // spew.Dump(parsedCerts) - - opts := x509.VerifyOptions{ - DNSName: ServerName, - } - - log.Printf("number of certs - %d", len(parsedCerts)) - if len(parsedCerts) > 1 { - // set up an intermediate - pool := x509.NewCertPool() - for _, cert := range parsedCerts[1:] { - log.Printf("got an intermediate cert") - pool.AddCert(cert) - } - opts.Intermediates = pool - } - - // TODO: save it as a warning rather than error it out -- shouldn't be a big problem - mainCert := parsedCerts[0] - _, err := mainCert.Verify(opts) - if err != nil { - // let self-signed certs through - data.WarningValidation = fmt.Sprintf("Your certificate does not verify: %s", err) - } else { - data.ValidChain = true - } - // spew.Dump(chains) - - // update status - if mainCert != nil { - notAfter := mainCert.NotAfter - data.Subject = mainCert.Subject.String() - data.Issuer = mainCert.Issuer.String() - data.NotAfter = notAfter - data.NotBefore = mainCert.NotBefore - data.DNSNames = mainCert.DNSNames - } } // validate private key (right now the only validation possible is just parsing it) - if PrivateKey != "" { - // now do a more extended validation - var key *pem.Block // PEM-encoded certificates - var skippedBytes []string // skipped bytes - - // go through all pem blocks, but take first valid pem block and drop the rest - pemblock := []byte(PrivateKey) - for { - var decoded *pem.Block - decoded, pemblock = pem.Decode(pemblock) - if decoded == nil { - break - } - if decoded.Type == "PRIVATE KEY" || strings.HasSuffix(decoded.Type, " PRIVATE KEY") { - key = decoded - break - } else { - skippedBytes = append(skippedBytes, decoded.Type) - } - } - - if key == nil { - data.WarningValidation = "No valid keys were found" + if pkey != "" { + if validatePkey(&data, pkey) != 0 { return data } - - // parse the decoded key - _, keytype, err := parsePrivateKey(key.Bytes) - if err != nil { - data.WarningValidation = fmt.Sprintf("Failed to parse private key: %s", err) - return data - } - - data.ValidKey = true - data.KeyType = keytype } // if both are set, validate both in unison - if PrivateKey != "" && CertificateChain != "" { - _, err = tls.X509KeyPair([]byte(CertificateChain), []byte(PrivateKey)) + if pkey != "" && certChain != "" { + _, err := tls.X509KeyPair([]byte(certChain), []byte(pkey)) if err != nil { data.WarningValidation = fmt.Sprintf("Invalid certificate or key: %s", err) return data From 5cb6d97cd7b80047cfff2628cb56f1d54735e3d0 Mon Sep 17 00:00:00 2001 From: Simon Zolin Date: Mon, 25 Feb 2019 16:44:22 +0300 Subject: [PATCH 11/95] * use new logger - AdguardTeam/golibs/log --- app.go | 30 ++++---- config.go | 24 +++---- control.go | 139 +++++++++++++++++++++++------------- dhcp.go | 8 +-- dhcpd/check_other_dhcp.go | 2 +- dhcpd/dhcpd.go | 2 +- dhcpd/helpers.go | 2 +- dhcpd/standalone/main.go | 2 +- dns.go | 2 +- dnsfilter/dnsfilter.go | 2 +- dnsfilter/dnsfilter_test.go | 2 +- dnsforward/dnsforward.go | 2 +- dnsforward/querylog.go | 2 +- dnsforward/querylog_file.go | 42 +++++------ dnsforward/querylog_top.go | 2 +- filter.go | 2 +- go.mod | 2 +- helpers_test.go | 2 +- i18n.go | 2 +- service.go | 2 +- upgrade.go | 2 +- 21 files changed, 157 insertions(+), 118 deletions(-) diff --git a/app.go b/app.go index 0b55b6fa..a9ced17f 100644 --- a/app.go +++ b/app.go @@ -3,7 +3,6 @@ package main import ( "crypto/tls" "fmt" - stdlog "log" "net" "net/http" "os" @@ -15,9 +14,8 @@ import ( "syscall" "time" + "github.com/AdguardTeam/golibs/log" "github.com/gobuffalo/packr" - - "github.com/hmage/golibs/log" ) // VersionString will be set through ldflags, contains current version @@ -73,9 +71,9 @@ func run(args options) { // print the first message after logger is configured log.Printf("AdGuard Home, version %s\n", VersionString) - log.Tracef("Current working directory is %s", config.ourWorkingDir) + log.Debug("Current working directory is %s", config.ourWorkingDir) if args.runningAsService { - log.Printf("AdGuard Home is running as a service") + log.Info("AdGuard Home is running as a service") } config.firstRun = detectFirstRun() @@ -110,7 +108,7 @@ func run(args options) { err = filter.load() if err != nil { // This is okay for the first start, the filter will be loaded later - log.Printf("Couldn't load filter %d contents due to %s", filter.ID, err) + log.Debug("Couldn't load filter %d contents due to %s", filter.ID, err) // clear LastUpdated so it gets fetched right away } @@ -161,7 +159,7 @@ func run(args options) { // add handlers for /install paths, we only need them when we're not configured yet if config.firstRun { - log.Printf("This is the first launch of AdGuard Home, redirecting everything to /install.html ") + log.Info("This is the first launch of AdGuard Home, redirecting everything to /install.html ") http.Handle("/install.html", preInstallHandler(http.FileServer(box))) registerInstallHandlers() } @@ -263,7 +261,11 @@ func configureLogger(args options) { ls.LogFile = args.logFile } - log.Verbose = ls.Verbose + level := log.INFO + if ls.Verbose { + level = log.DEBUG + } + log.SetLevel(level) if args.runningAsService && ls.LogFile == "" && runtime.GOOS == "windows" { // When running as a Windows service, use eventlog by default if nothing else is configured @@ -287,20 +289,20 @@ func configureLogger(args options) { if err != nil { log.Fatalf("cannot create a log file: %s", err) } - stdlog.SetOutput(file) + log.SetOutput(file) } } func cleanup() { - log.Printf("Stopping AdGuard Home") + log.Info("Stopping AdGuard Home") err := stopDNSServer() if err != nil { - log.Printf("Couldn't stop DNS server: %s", err) + log.Error("Couldn't stop DNS server: %s", err) } err = stopDHCPServer() if err != nil { - log.Printf("Couldn't stop DHCP server: %s", err) + log.Error("Couldn't stop DHCP server: %s", err) } } @@ -373,7 +375,7 @@ func loadOptions() options { if v == "--"+opt.longName || (opt.shortName != "" && v == "-"+opt.shortName) { if opt.callbackWithValue != nil { if i+1 >= len(os.Args) { - log.Printf("ERROR: Got %s without argument\n", v) + log.Error("Got %s without argument\n", v) os.Exit(64) } i++ @@ -386,7 +388,7 @@ func loadOptions() options { } } if !knownParam { - log.Printf("ERROR: unknown option %v\n", v) + log.Error("unknown option %v\n", v) printHelp() os.Exit(64) } diff --git a/config.go b/config.go index 87e5c6a8..f9ba9b28 100644 --- a/config.go +++ b/config.go @@ -10,7 +10,7 @@ import ( "github.com/AdguardTeam/AdGuardHome/dhcpd" "github.com/AdguardTeam/AdGuardHome/dnsfilter" "github.com/AdguardTeam/AdGuardHome/dnsforward" - "github.com/hmage/golibs/log" + "github.com/AdguardTeam/golibs/log" yaml "gopkg.in/yaml.v2" ) @@ -152,7 +152,7 @@ func getLogSettings() logSettings { } err = yaml.Unmarshal(yamlFile, &l) if err != nil { - log.Printf("Couldn't get logging settings from the configuration: %s", err) + log.Error("Couldn't get logging settings from the configuration: %s", err) } return l } @@ -160,19 +160,19 @@ func getLogSettings() logSettings { // parseConfig loads configuration from the YAML file func parseConfig() error { configFile := config.getConfigFilename() - log.Printf("Reading config file: %s", configFile) + log.Debug("Reading config file: %s", configFile) yamlFile, err := readConfigFile() if err != nil { - log.Printf("Couldn't read config file: %s", err) + log.Error("Couldn't read config file: %s", err) return err } if yamlFile == nil { - log.Printf("YAML file doesn't exist, skipping it") + log.Error("YAML file doesn't exist, skipping it") return nil } err = yaml.Unmarshal(yamlFile, &config) if err != nil { - log.Printf("Couldn't parse config file: %s", err) + log.Error("Couldn't parse config file: %s", err) return err } @@ -199,19 +199,19 @@ func (c *configuration) write() error { c.Lock() defer c.Unlock() if config.firstRun { - log.Tracef("Silently refusing to write config because first run and not configured yet") + log.Debug("Silently refusing to write config because first run and not configured yet") return nil } configFile := config.getConfigFilename() - log.Tracef("Writing YAML file: %s", configFile) + log.Debug("Writing YAML file: %s", configFile) yamlText, err := yaml.Marshal(&config) if err != nil { - log.Printf("Couldn't generate YAML file: %s", err) + log.Error("Couldn't generate YAML file: %s", err) return err } err = safeWriteFile(configFile, yamlText) if err != nil { - log.Printf("Couldn't save YAML config: %s", err) + log.Error("Couldn't save YAML config: %s", err) return err } @@ -221,14 +221,14 @@ func (c *configuration) write() error { func writeAllConfigs() error { err := config.write() if err != nil { - log.Printf("Couldn't write config: %s", err) + log.Error("Couldn't write config: %s", err) return err } userFilter := userFilter() err = userFilter.save() if err != nil { - log.Printf("Couldn't save the user filter: %s", err) + log.Error("Couldn't save the user filter: %s", err) return err } diff --git a/control.go b/control.go index fd1759e3..52b85615 100644 --- a/control.go +++ b/control.go @@ -24,8 +24,8 @@ import ( "time" "github.com/AdguardTeam/AdGuardHome/dnsforward" + "github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/dnsproxy/upstream" - "github.com/hmage/golibs/log" "github.com/joomcode/errorx" "github.com/miekg/dns" govalidator "gopkg.in/asaskevich/govalidator.v4" @@ -52,14 +52,14 @@ func returnOK(w http.ResponseWriter) { _, err := fmt.Fprintf(w, "OK\n") if err != nil { errorText := fmt.Sprintf("Couldn't write body: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, http.StatusInternalServerError) } } func httpError(w http.ResponseWriter, code int, format string, args ...interface{}) { text := fmt.Sprintf(format, args...) - log.Println(text) + log.Info(text) http.Error(w, text, code) } @@ -69,7 +69,7 @@ func httpError(w http.ResponseWriter, code int, format string, args ...interface func writeAllConfigsAndReloadDNS() error { err := writeAllConfigs() if err != nil { - log.Printf("Couldn't write all configs: %s", err) + log.Error("Couldn't write all configs: %s", err) return err } return reconfigureDNSServer() @@ -85,6 +85,7 @@ func httpUpdateConfigReloadDNSReturnOK(w http.ResponseWriter, r *http.Request) { } func handleStatus(w http.ResponseWriter, r *http.Request) { + log.Tracef("") data := map[string]interface{}{ "dns_address": config.DNS.BindHost, "http_port": config.BindPort, @@ -101,7 +102,7 @@ func handleStatus(w http.ResponseWriter, r *http.Request) { jsonVal, err := json.Marshal(data) if err != nil { errorText := fmt.Sprintf("Unable to marshal status json: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, 500) return } @@ -109,18 +110,20 @@ func handleStatus(w http.ResponseWriter, r *http.Request) { _, err = w.Write(jsonVal) if err != nil { errorText := fmt.Sprintf("Unable to write response json: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, 500) return } } func handleProtectionEnable(w http.ResponseWriter, r *http.Request) { + log.Tracef("") config.DNS.ProtectionEnabled = true httpUpdateConfigReloadDNSReturnOK(w, r) } func handleProtectionDisable(w http.ResponseWriter, r *http.Request) { + log.Tracef("") config.DNS.ProtectionEnabled = false httpUpdateConfigReloadDNSReturnOK(w, r) } @@ -129,22 +132,25 @@ func handleProtectionDisable(w http.ResponseWriter, r *http.Request) { // stats // ----- func handleQueryLogEnable(w http.ResponseWriter, r *http.Request) { + log.Tracef("") config.DNS.QueryLogEnabled = true httpUpdateConfigReloadDNSReturnOK(w, r) } func handleQueryLogDisable(w http.ResponseWriter, r *http.Request) { + log.Tracef("") config.DNS.QueryLogEnabled = false httpUpdateConfigReloadDNSReturnOK(w, r) } func handleQueryLog(w http.ResponseWriter, r *http.Request) { + log.Tracef("") data := dnsServer.GetQueryLog() jsonVal, err := json.Marshal(data) if err != nil { errorText := fmt.Sprintf("Couldn't marshal data into json: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, http.StatusInternalServerError) return } @@ -153,12 +159,13 @@ func handleQueryLog(w http.ResponseWriter, r *http.Request) { _, err = w.Write(jsonVal) if err != nil { errorText := fmt.Sprintf("Unable to write response json: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, http.StatusInternalServerError) } } func handleStatsTop(w http.ResponseWriter, r *http.Request) { + log.Tracef("") s := dnsServer.GetStatsTop() // use manual json marshalling because we want maps to be sorted by value @@ -200,30 +207,32 @@ func handleStatsTop(w http.ResponseWriter, r *http.Request) { _, err := w.Write(statsJSON.Bytes()) if err != nil { errorText := fmt.Sprintf("Couldn't write body: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, http.StatusInternalServerError) } } // handleStatsReset resets the stats caches func handleStatsReset(w http.ResponseWriter, r *http.Request) { + log.Tracef("") dnsServer.PurgeStats() _, err := fmt.Fprintf(w, "OK\n") if err != nil { errorText := fmt.Sprintf("Couldn't write body: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, http.StatusInternalServerError) } } // handleStats returns aggregated stats data for the 24 hours func handleStats(w http.ResponseWriter, r *http.Request) { + log.Tracef("") summed := dnsServer.GetAggregatedStats() statsJSON, err := json.Marshal(summed) if err != nil { errorText := fmt.Sprintf("Unable to marshal status json: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, 500) return } @@ -231,7 +240,7 @@ func handleStats(w http.ResponseWriter, r *http.Request) { _, err = w.Write(statsJSON) if err != nil { errorText := fmt.Sprintf("Unable to write response json: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, 500) return } @@ -239,6 +248,7 @@ func handleStats(w http.ResponseWriter, r *http.Request) { // HandleStatsHistory returns historical stats data for the 24 hours func handleStatsHistory(w http.ResponseWriter, r *http.Request) { + log.Tracef("") // handle time unit and prepare our time window size timeUnitString := r.URL.Query().Get("time_unit") var timeUnit time.Duration @@ -260,14 +270,14 @@ func handleStatsHistory(w http.ResponseWriter, r *http.Request) { startTime, err := time.Parse(time.RFC3339, r.URL.Query().Get("start_time")) if err != nil { errorText := fmt.Sprintf("Must specify valid start_time parameter: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, http.StatusBadRequest) return } endTime, err := time.Parse(time.RFC3339, r.URL.Query().Get("end_time")) if err != nil { errorText := fmt.Sprintf("Must specify valid end_time parameter: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, http.StatusBadRequest) return } @@ -282,7 +292,7 @@ func handleStatsHistory(w http.ResponseWriter, r *http.Request) { statsJSON, err := json.Marshal(data) if err != nil { errorText := fmt.Sprintf("Unable to marshal status json: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, http.StatusInternalServerError) return } @@ -291,7 +301,7 @@ func handleStatsHistory(w http.ResponseWriter, r *http.Request) { _, err = w.Write(statsJSON) if err != nil { errorText := fmt.Sprintf("Unable to write response json: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, http.StatusInternalServerError) return } @@ -323,10 +333,11 @@ func sortByValue(m map[string]int) []string { // ----------------------- func handleSetUpstreamDNS(w http.ResponseWriter, r *http.Request) { + log.Tracef("") body, err := ioutil.ReadAll(r.Body) if err != nil { errorText := fmt.Sprintf("Failed to read request body: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, http.StatusBadRequest) return } @@ -342,30 +353,31 @@ func handleSetUpstreamDNS(w http.ResponseWriter, r *http.Request) { err = writeAllConfigs() if err != nil { errorText := fmt.Sprintf("Couldn't write config file: %s", err) - log.Println(errorText) + log.Error(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) + log.Error(errorText) http.Error(w, errorText, http.StatusInternalServerError) return } _, err = fmt.Fprintf(w, "OK %d servers\n", len(hosts)) if err != nil { errorText := fmt.Sprintf("Couldn't write body: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, http.StatusInternalServerError) } } func handleTestUpstreamDNS(w http.ResponseWriter, r *http.Request) { + log.Tracef("") body, err := ioutil.ReadAll(r.Body) if err != nil { errorText := fmt.Sprintf("Failed to read request body: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, 400) return } @@ -373,7 +385,7 @@ func handleTestUpstreamDNS(w http.ResponseWriter, r *http.Request) { if len(hosts) == 0 { errorText := fmt.Sprintf("No servers specified") - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, http.StatusBadRequest) return } @@ -383,7 +395,7 @@ func handleTestUpstreamDNS(w http.ResponseWriter, r *http.Request) { for _, host := range hosts { err = checkDNS(host) if err != nil { - log.Println(err) + log.Info("%v", err) result[host] = err.Error() } else { result[host] = "OK" @@ -393,7 +405,7 @@ func handleTestUpstreamDNS(w http.ResponseWriter, r *http.Request) { jsonVal, err := json.Marshal(result) if err != nil { errorText := fmt.Sprintf("Unable to marshal status json: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, http.StatusInternalServerError) return } @@ -402,13 +414,13 @@ func handleTestUpstreamDNS(w http.ResponseWriter, r *http.Request) { _, err = w.Write(jsonVal) if err != nil { errorText := fmt.Sprintf("Couldn't write body: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, http.StatusInternalServerError) } } func checkDNS(input string) error { - log.Printf("Checking if DNS %s works...", input) + log.Debug("Checking if DNS %s works...", input) u, err := upstream.AddressToUpstream(input, upstream.Options{Timeout: dnsforward.DefaultTimeout}) if err != nil { return fmt.Errorf("failed to choose upstream for %s: %s", input, err) @@ -433,11 +445,12 @@ func checkDNS(input string) error { } } - log.Printf("DNS %s works OK", input) + log.Debug("DNS %s works OK", input) return nil } func handleGetVersionJSON(w http.ResponseWriter, r *http.Request) { + log.Tracef("") now := time.Now() if now.Sub(versionCheckLastTime) <= versionCheckPeriod && len(versionCheckJSON) != 0 { // return cached copy @@ -449,7 +462,7 @@ func handleGetVersionJSON(w http.ResponseWriter, r *http.Request) { resp, err := client.Get(versionCheckURL) if err != nil { errorText := fmt.Sprintf("Couldn't get version check json from %s: %T %s\n", versionCheckURL, err, err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, http.StatusBadGateway) return } @@ -461,7 +474,7 @@ func handleGetVersionJSON(w http.ResponseWriter, r *http.Request) { body, err := ioutil.ReadAll(resp.Body) if err != nil { errorText := fmt.Sprintf("Couldn't read response body from %s: %s", versionCheckURL, err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, http.StatusBadGateway) return } @@ -470,7 +483,7 @@ func handleGetVersionJSON(w http.ResponseWriter, r *http.Request) { _, err = w.Write(body) if err != nil { errorText := fmt.Sprintf("Couldn't write body: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, http.StatusInternalServerError) } @@ -483,16 +496,19 @@ func handleGetVersionJSON(w http.ResponseWriter, r *http.Request) { // --------- func handleFilteringEnable(w http.ResponseWriter, r *http.Request) { + log.Tracef("") config.DNS.FilteringEnabled = true httpUpdateConfigReloadDNSReturnOK(w, r) } func handleFilteringDisable(w http.ResponseWriter, r *http.Request) { + log.Tracef("") config.DNS.FilteringEnabled = false httpUpdateConfigReloadDNSReturnOK(w, r) } func handleFilteringStatus(w http.ResponseWriter, r *http.Request) { + log.Tracef("") data := map[string]interface{}{ "enabled": config.DNS.FilteringEnabled, } @@ -505,7 +521,7 @@ func handleFilteringStatus(w http.ResponseWriter, r *http.Request) { if err != nil { errorText := fmt.Sprintf("Unable to marshal status json: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, 500) return } @@ -514,13 +530,14 @@ func handleFilteringStatus(w http.ResponseWriter, r *http.Request) { _, err = w.Write(jsonVal) if err != nil { errorText := fmt.Sprintf("Unable to write response json: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, 500) return } } func handleFilteringAddURL(w http.ResponseWriter, r *http.Request) { + log.Tracef("") f := filter{} err := json.NewDecoder(r.Body).Decode(&f) if err != nil { @@ -542,7 +559,7 @@ func handleFilteringAddURL(w http.ResponseWriter, r *http.Request) { for i := range config.Filters { if config.Filters[i].URL == f.URL { errorText := fmt.Sprintf("Filter URL already added -- %s", f.URL) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, http.StatusBadRequest) return } @@ -556,19 +573,19 @@ func handleFilteringAddURL(w http.ResponseWriter, r *http.Request) { ok, err := f.update(true) if err != nil { errorText := fmt.Sprintf("Couldn't fetch filter from url %s: %s", f.URL, err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, http.StatusBadRequest) return } if f.RulesCount == 0 { errorText := fmt.Sprintf("Filter at the url %s has no rules (maybe it points to blank page?)", f.URL) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, http.StatusBadRequest) return } if !ok { errorText := fmt.Sprintf("Filter at the url %s is invalid (maybe it points to blank page?)", f.URL) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, http.StatusBadRequest) return } @@ -577,7 +594,7 @@ func handleFilteringAddURL(w http.ResponseWriter, r *http.Request) { err = f.save() if err != nil { errorText := fmt.Sprintf("Failed to save filter %d due to %s", f.ID, err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, http.StatusBadRequest) return } @@ -588,7 +605,7 @@ func handleFilteringAddURL(w http.ResponseWriter, r *http.Request) { err = writeAllConfigs() if err != nil { errorText := fmt.Sprintf("Couldn't write config file: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, http.StatusInternalServerError) return } @@ -596,23 +613,24 @@ func handleFilteringAddURL(w http.ResponseWriter, r *http.Request) { err = reconfigureDNSServer() if err != nil { errorText := fmt.Sprintf("Couldn't reconfigure the DNS server: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, http.StatusInternalServerError) } _, err = fmt.Fprintf(w, "OK %d rules\n", f.RulesCount) if err != nil { errorText := fmt.Sprintf("Couldn't write body: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, http.StatusInternalServerError) } } func handleFilteringRemoveURL(w http.ResponseWriter, r *http.Request) { + log.Tracef("") parameters, err := parseParametersFromBody(r.Body) if err != nil { errorText := fmt.Sprintf("failed to parse parameters from body: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, 400) return } @@ -649,10 +667,11 @@ func handleFilteringRemoveURL(w http.ResponseWriter, r *http.Request) { } func handleFilteringEnableURL(w http.ResponseWriter, r *http.Request) { + log.Tracef("") parameters, err := parseParametersFromBody(r.Body) if err != nil { errorText := fmt.Sprintf("failed to parse parameters from body: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, 400) return } @@ -688,10 +707,11 @@ func handleFilteringEnableURL(w http.ResponseWriter, r *http.Request) { } func handleFilteringDisableURL(w http.ResponseWriter, r *http.Request) { + log.Tracef("") parameters, err := parseParametersFromBody(r.Body) if err != nil { errorText := fmt.Sprintf("failed to parse parameters from body: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, 400) return } @@ -725,10 +745,11 @@ func handleFilteringDisableURL(w http.ResponseWriter, r *http.Request) { } func handleFilteringSetRules(w http.ResponseWriter, r *http.Request) { + log.Tracef("") body, err := ioutil.ReadAll(r.Body) if err != nil { errorText := fmt.Sprintf("Failed to read request body: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, 400) return } @@ -738,6 +759,7 @@ func handleFilteringSetRules(w http.ResponseWriter, r *http.Request) { } func handleFilteringRefresh(w http.ResponseWriter, r *http.Request) { + log.Tracef("") force := r.URL.Query().Get("force") updated := refreshFiltersIfNecessary(force != "") fmt.Fprintf(w, "OK %d filters updated\n", updated) @@ -748,23 +770,26 @@ func handleFilteringRefresh(w http.ResponseWriter, r *http.Request) { // ------------ func handleSafeBrowsingEnable(w http.ResponseWriter, r *http.Request) { + log.Tracef("") config.DNS.SafeBrowsingEnabled = true httpUpdateConfigReloadDNSReturnOK(w, r) } func handleSafeBrowsingDisable(w http.ResponseWriter, r *http.Request) { + log.Tracef("") config.DNS.SafeBrowsingEnabled = false httpUpdateConfigReloadDNSReturnOK(w, r) } func handleSafeBrowsingStatus(w http.ResponseWriter, r *http.Request) { + log.Tracef("") data := map[string]interface{}{ "enabled": config.DNS.SafeBrowsingEnabled, } jsonVal, err := json.Marshal(data) if err != nil { errorText := fmt.Sprintf("Unable to marshal status json: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, 500) } @@ -772,7 +797,7 @@ func handleSafeBrowsingStatus(w http.ResponseWriter, r *http.Request) { _, err = w.Write(jsonVal) if err != nil { errorText := fmt.Sprintf("Unable to write response json: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, 500) return } @@ -782,10 +807,11 @@ func handleSafeBrowsingStatus(w http.ResponseWriter, r *http.Request) { // parental // -------- func handleParentalEnable(w http.ResponseWriter, r *http.Request) { + log.Tracef("") parameters, err := parseParametersFromBody(r.Body) if err != nil { errorText := fmt.Sprintf("failed to parse parameters from body: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, 400) return } @@ -828,11 +854,13 @@ func handleParentalEnable(w http.ResponseWriter, r *http.Request) { } func handleParentalDisable(w http.ResponseWriter, r *http.Request) { + log.Tracef("") config.DNS.ParentalEnabled = false httpUpdateConfigReloadDNSReturnOK(w, r) } func handleParentalStatus(w http.ResponseWriter, r *http.Request) { + log.Tracef("") data := map[string]interface{}{ "enabled": config.DNS.ParentalEnabled, } @@ -842,7 +870,7 @@ func handleParentalStatus(w http.ResponseWriter, r *http.Request) { jsonVal, err := json.Marshal(data) if err != nil { errorText := fmt.Sprintf("Unable to marshal status json: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, 500) return } @@ -851,7 +879,7 @@ func handleParentalStatus(w http.ResponseWriter, r *http.Request) { _, err = w.Write(jsonVal) if err != nil { errorText := fmt.Sprintf("Unable to write response json: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, 500) return } @@ -862,23 +890,26 @@ func handleParentalStatus(w http.ResponseWriter, r *http.Request) { // ------------ func handleSafeSearchEnable(w http.ResponseWriter, r *http.Request) { + log.Tracef("") config.DNS.SafeSearchEnabled = true httpUpdateConfigReloadDNSReturnOK(w, r) } func handleSafeSearchDisable(w http.ResponseWriter, r *http.Request) { + log.Tracef("") config.DNS.SafeSearchEnabled = false httpUpdateConfigReloadDNSReturnOK(w, r) } func handleSafeSearchStatus(w http.ResponseWriter, r *http.Request) { + log.Tracef("") data := map[string]interface{}{ "enabled": config.DNS.SafeSearchEnabled, } jsonVal, err := json.Marshal(data) if err != nil { errorText := fmt.Sprintf("Unable to marshal status json: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, 500) return } @@ -887,7 +918,7 @@ func handleSafeSearchStatus(w http.ResponseWriter, r *http.Request) { _, err = w.Write(jsonVal) if err != nil { errorText := fmt.Sprintf("Unable to write response json: %s", err) - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, 500) return } @@ -908,6 +939,7 @@ type firstRunData struct { } func handleInstallGetAddresses(w http.ResponseWriter, r *http.Request) { + log.Tracef("") data := firstRunData{} // find out if port 80 is available -- if not, fall back to 3000 @@ -943,6 +975,7 @@ func handleInstallGetAddresses(w http.ResponseWriter, r *http.Request) { } func handleInstallConfigure(w http.ResponseWriter, r *http.Request) { + log.Tracef("") newSettings := firstRunData{} err := json.NewDecoder(r.Body).Decode(&newSettings) if err != nil { @@ -1001,10 +1034,12 @@ func handleInstallConfigure(w http.ResponseWriter, r *http.Request) { // TLS // --- func handleTLSStatus(w http.ResponseWriter, r *http.Request) { + log.Tracef("") marshalTLS(w, config.TLS) } func handleTLSValidate(w http.ResponseWriter, r *http.Request) { + log.Tracef("") data, err := unmarshalTLS(r) if err != nil { httpError(w, http.StatusBadRequest, "Failed to unmarshal TLS config: %s", err) @@ -1030,6 +1065,7 @@ func handleTLSValidate(w http.ResponseWriter, r *http.Request) { } func handleTLSConfigure(w http.ResponseWriter, r *http.Request) { + log.Tracef("") data, err := unmarshalTLS(r) if err != nil { httpError(w, http.StatusBadRequest, "Failed to unmarshal TLS config: %s", err) @@ -1287,6 +1323,7 @@ func marshalTLS(w http.ResponseWriter, data tlsConfig) { // DNS-over-HTTPS // -------------- func handleDOH(w http.ResponseWriter, r *http.Request) { + log.Tracef("") if r.TLS == nil { httpError(w, http.StatusNotFound, "Not Found") return diff --git a/dhcp.go b/dhcp.go index a67b0ef6..fe780305 100644 --- a/dhcp.go +++ b/dhcp.go @@ -10,7 +10,7 @@ import ( "time" "github.com/AdguardTeam/AdGuardHome/dhcpd" - "github.com/hmage/golibs/log" + "github.com/AdguardTeam/golibs/log" "github.com/joomcode/errorx" ) @@ -60,7 +60,7 @@ func handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) { if !newconfig.Enabled { err := dhcpServer.Stop() if err != nil { - log.Printf("failed to stop the DHCP server: %s", err) + log.Error("failed to stop the DHCP server: %s", err) } } config.DHCP = newconfig @@ -131,7 +131,7 @@ func handleDHCPFindActiveServer(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) + log.Error(errorText) http.Error(w, errorText, http.StatusBadRequest) return } @@ -139,7 +139,7 @@ func handleDHCPFindActiveServer(w http.ResponseWriter, r *http.Request) { interfaceName := strings.TrimSpace(string(body)) if interfaceName == "" { errorText := fmt.Sprintf("empty interface name specified") - log.Println(errorText) + log.Error(errorText) http.Error(w, errorText, http.StatusBadRequest) return } diff --git a/dhcpd/check_other_dhcp.go b/dhcpd/check_other_dhcp.go index b2d64b9f..46fbec57 100644 --- a/dhcpd/check_other_dhcp.go +++ b/dhcpd/check_other_dhcp.go @@ -9,7 +9,7 @@ import ( "os" "time" - "github.com/hmage/golibs/log" + "github.com/AdguardTeam/golibs/log" "github.com/krolaw/dhcp4" ) diff --git a/dhcpd/dhcpd.go b/dhcpd/dhcpd.go index 0fcb8168..05d753b8 100644 --- a/dhcpd/dhcpd.go +++ b/dhcpd/dhcpd.go @@ -7,7 +7,7 @@ import ( "sync" "time" - "github.com/hmage/golibs/log" + "github.com/AdguardTeam/golibs/log" "github.com/krolaw/dhcp4" ) diff --git a/dhcpd/helpers.go b/dhcpd/helpers.go index 24cfb029..c3e9f4fe 100644 --- a/dhcpd/helpers.go +++ b/dhcpd/helpers.go @@ -4,7 +4,7 @@ import ( "fmt" "net" - "github.com/hmage/golibs/log" + "github.com/AdguardTeam/golibs/log" "github.com/joomcode/errorx" ) diff --git a/dhcpd/standalone/main.go b/dhcpd/standalone/main.go index 9154e063..9dd37285 100644 --- a/dhcpd/standalone/main.go +++ b/dhcpd/standalone/main.go @@ -8,7 +8,7 @@ import ( "time" "github.com/AdguardTeam/AdGuardHome/dhcpd" - "github.com/hmage/golibs/log" + "github.com/AdguardTeam/golibs/log" "github.com/krolaw/dhcp4" ) diff --git a/dns.go b/dns.go index b7f0d130..8cf5c40d 100644 --- a/dns.go +++ b/dns.go @@ -8,7 +8,7 @@ import ( "github.com/AdguardTeam/AdGuardHome/dnsfilter" "github.com/AdguardTeam/AdGuardHome/dnsforward" "github.com/AdguardTeam/dnsproxy/upstream" - "github.com/hmage/golibs/log" + "github.com/AdguardTeam/golibs/log" "github.com/joomcode/errorx" ) diff --git a/dnsfilter/dnsfilter.go b/dnsfilter/dnsfilter.go index dd5fe2e4..561ccb04 100644 --- a/dnsfilter/dnsfilter.go +++ b/dnsfilter/dnsfilter.go @@ -17,7 +17,7 @@ import ( "time" "github.com/bluele/gcache" - "github.com/hmage/golibs/log" + "github.com/AdguardTeam/golibs/log" "golang.org/x/net/publicsuffix" ) diff --git a/dnsfilter/dnsfilter_test.go b/dnsfilter/dnsfilter_test.go index b617dd41..85e0c4bf 100644 --- a/dnsfilter/dnsfilter_test.go +++ b/dnsfilter/dnsfilter_test.go @@ -18,7 +18,7 @@ import ( "os" "runtime" - "github.com/hmage/golibs/log" + "github.com/AdguardTeam/golibs/log" "github.com/shirou/gopsutil/process" "go.uber.org/goleak" ) diff --git a/dnsforward/dnsforward.go b/dnsforward/dnsforward.go index 99f09e6d..26f7dfb4 100644 --- a/dnsforward/dnsforward.go +++ b/dnsforward/dnsforward.go @@ -13,7 +13,7 @@ import ( "github.com/AdguardTeam/AdGuardHome/dnsfilter" "github.com/AdguardTeam/dnsproxy/proxy" "github.com/AdguardTeam/dnsproxy/upstream" - "github.com/hmage/golibs/log" + "github.com/AdguardTeam/golibs/log" "github.com/joomcode/errorx" "github.com/miekg/dns" ) diff --git a/dnsforward/querylog.go b/dnsforward/querylog.go index 52fa115c..14325354 100644 --- a/dnsforward/querylog.go +++ b/dnsforward/querylog.go @@ -10,7 +10,7 @@ import ( "time" "github.com/AdguardTeam/AdGuardHome/dnsfilter" - "github.com/hmage/golibs/log" + "github.com/AdguardTeam/golibs/log" "github.com/miekg/dns" ) diff --git a/dnsforward/querylog_file.go b/dnsforward/querylog_file.go index 8aadd5ae..97f86cf0 100644 --- a/dnsforward/querylog_file.go +++ b/dnsforward/querylog_file.go @@ -9,8 +9,8 @@ import ( "sync" "time" + "github.com/AdguardTeam/golibs/log" "github.com/go-test/deep" - "github.com/hmage/golibs/log" ) var ( @@ -28,7 +28,7 @@ func (l *queryLog) flushLogBuffer() error { l.logBufferLock.Unlock() err := l.flushToFile(flushBuffer) if err != nil { - log.Printf("Saving querylog to file failed: %s", err) + log.Error("Saving querylog to file failed: %s", err) return err } return nil @@ -46,17 +46,17 @@ func (l *queryLog) flushToFile(buffer []*logEntry) error { for _, entry := range buffer { err := e.Encode(entry) if err != nil { - log.Printf("Failed to marshal entry: %s", err) + log.Error("Failed to marshal entry: %s", err) return err } } elapsed := time.Since(start) - log.Printf("%d elements serialized via json in %v: %d kB, %v/entry, %v/entry", len(buffer), elapsed, b.Len()/1024, float64(b.Len())/float64(len(buffer)), elapsed/time.Duration(len(buffer))) + log.Debug("%d elements serialized via json in %v: %d kB, %v/entry, %v/entry", len(buffer), elapsed, b.Len()/1024, float64(b.Len())/float64(len(buffer)), elapsed/time.Duration(len(buffer))) err := checkBuffer(buffer, b) if err != nil { - log.Printf("failed to check buffer: %s", err) + log.Error("failed to check buffer: %s", err) return err } @@ -73,13 +73,13 @@ func (l *queryLog) flushToFile(buffer []*logEntry) error { _, err = zw.Write(b.Bytes()) if err != nil { - log.Printf("Couldn't compress to gzip: %s", err) + log.Error("Couldn't compress to gzip: %s", err) zw.Close() return err } if err = zw.Close(); err != nil { - log.Printf("Couldn't close gzip writer: %s", err) + log.Error("Couldn't close gzip writer: %s", err) return err } } else { @@ -90,18 +90,18 @@ func (l *queryLog) flushToFile(buffer []*logEntry) error { defer fileWriteLock.Unlock() f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) if err != nil { - log.Printf("failed to create file \"%s\": %s", filename, err) + log.Error("failed to create file \"%s\": %s", filename, err) return err } defer f.Close() n, err := f.Write(zb.Bytes()) if err != nil { - log.Printf("Couldn't write to file: %s", err) + log.Error("Couldn't write to file: %s", err) return err } - log.Printf("ok \"%s\": %v bytes written", filename, n) + log.Debug("ok \"%s\": %v bytes written", filename, n) return nil } @@ -115,21 +115,21 @@ func checkBuffer(buffer []*logEntry, b bytes.Buffer) error { entry := &logEntry{} err := d.Decode(entry) if err != nil { - log.Printf("Failed to decode: %s", err) + log.Error("Failed to decode: %s", err) return err } if diff := deep.Equal(entry, buffer[i]); diff != nil { - log.Printf("decoded buffer differs: %s", diff) + log.Error("decoded buffer differs: %s", diff) return fmt.Errorf("decoded buffer differs: %s", diff) } i++ } if i != l { err := fmt.Errorf("check fail: %d vs %d entries", l, i) - log.Print(err) + log.Error("%v", err) return err } - log.Printf("check ok: %d entries", i) + log.Debug("check ok: %d entries", i) return nil } @@ -150,11 +150,11 @@ func (l *queryLog) rotateQueryLog() error { err := os.Rename(from, to) if err != nil { - log.Printf("Failed to rename querylog: %s", err) + log.Error("Failed to rename querylog: %s", err) return err } - log.Printf("Rotated from %s to %s successfully", from, to) + log.Debug("Rotated from %s to %s successfully", from, to) return nil } @@ -163,7 +163,7 @@ func (l *queryLog) periodicQueryLogRotate() { for range time.Tick(queryLogRotationPeriod) { err := l.rotateQueryLog() if err != nil { - log.Printf("Failed to rotate querylog: %s", err) + log.Error("Failed to rotate querylog: %s", err) // do nothing, continue rotating } } @@ -198,7 +198,7 @@ func (l *queryLog) genericLoader(onEntry func(entry *logEntry) error, needMore f f, err := os.Open(file) if err != nil { - log.Printf("Failed to open file \"%s\": %s", file, err) + log.Error("Failed to open file \"%s\": %s", file, err) // try next file continue } @@ -209,7 +209,7 @@ func (l *queryLog) genericLoader(onEntry func(entry *logEntry) error, needMore f if enableGzip { zr, err := gzip.NewReader(f) if err != nil { - log.Printf("Failed to create gzip reader: %s", err) + log.Error("Failed to create gzip reader: %s", err) continue } defer zr.Close() @@ -231,7 +231,7 @@ func (l *queryLog) genericLoader(onEntry func(entry *logEntry) error, needMore f var entry logEntry err := d.Decode(&entry) if err != nil { - log.Printf("Failed to decode: %s", err) + log.Error("Failed to decode: %s", err) // next entry can be fine, try more continue } @@ -260,7 +260,7 @@ func (l *queryLog) genericLoader(onEntry func(entry *logEntry) error, needMore f perunit = elapsed / time.Duration(i) avg = sum / time.Duration(i) } - log.Printf("file \"%s\": read %d entries in %v, %v/entry, %v over %v, %v avg", file, i, elapsed, perunit, over, max, avg) + log.Debug("file \"%s\": read %d entries in %v, %v/entry, %v over %v, %v avg", file, i, elapsed, perunit, over, max, avg) } return nil } diff --git a/dnsforward/querylog_top.go b/dnsforward/querylog_top.go index 25ad9791..a2ffffdc 100644 --- a/dnsforward/querylog_top.go +++ b/dnsforward/querylog_top.go @@ -10,7 +10,7 @@ import ( "time" "github.com/bluele/gcache" - "github.com/hmage/golibs/log" + "github.com/AdguardTeam/golibs/log" "github.com/miekg/dns" ) diff --git a/filter.go b/filter.go index 84db3a47..280c403f 100644 --- a/filter.go +++ b/filter.go @@ -12,7 +12,7 @@ import ( "time" "github.com/AdguardTeam/AdGuardHome/dnsfilter" - "github.com/hmage/golibs/log" + "github.com/AdguardTeam/golibs/log" ) var ( diff --git a/go.mod b/go.mod index cba63387..49f35dc7 100644 --- a/go.mod +++ b/go.mod @@ -2,12 +2,12 @@ module github.com/AdguardTeam/AdGuardHome require ( github.com/AdguardTeam/dnsproxy v0.11.1 + github.com/AdguardTeam/golibs v0.1 github.com/StackExchange/wmi v0.0.0-20180725035823-b12b22c5341f // indirect github.com/bluele/gcache v0.0.0-20171010155617-472614239ac7 github.com/go-ole/go-ole v1.2.1 // indirect github.com/go-test/deep v1.0.1 github.com/gobuffalo/packr v1.19.0 - github.com/hmage/golibs v0.0.0-20190121112702-20153bd03c24 github.com/joomcode/errorx v0.1.0 github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 // indirect github.com/kardianos/service v0.0.0-20181115005516-4c239ee84e7b diff --git a/helpers_test.go b/helpers_test.go index 66fc3d27..e70b2d5f 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -3,7 +3,7 @@ package main import ( "testing" - "github.com/hmage/golibs/log" + "github.com/AdguardTeam/golibs/log" ) func TestGetValidNetInterfacesForWeb(t *testing.T) { diff --git a/i18n.go b/i18n.go index 4ed850a3..962443d6 100644 --- a/i18n.go +++ b/i18n.go @@ -6,7 +6,7 @@ import ( "net/http" "strings" - "github.com/hmage/golibs/log" + "github.com/AdguardTeam/golibs/log" ) // -------------------- diff --git a/service.go b/service.go index fd233f4e..d0bb7f67 100644 --- a/service.go +++ b/service.go @@ -4,7 +4,7 @@ import ( "os" "runtime" - "github.com/hmage/golibs/log" + "github.com/AdguardTeam/golibs/log" "github.com/kardianos/service" ) diff --git a/upgrade.go b/upgrade.go index 0b3ddc5c..c988700a 100644 --- a/upgrade.go +++ b/upgrade.go @@ -6,7 +6,7 @@ import ( "os" "path/filepath" - "github.com/hmage/golibs/log" + "github.com/AdguardTeam/golibs/log" yaml "gopkg.in/yaml.v2" ) From 01548c236e3b444bc29af8f91ef2df5a12258efb Mon Sep 17 00:00:00 2001 From: Simon Zolin Date: Wed, 27 Feb 2019 16:04:05 +0300 Subject: [PATCH 12/95] * update go.sum --- go.sum | 2 -- 1 file changed, 2 deletions(-) diff --git a/go.sum b/go.sum index 5ba6426d..3f19484f 100644 --- a/go.sum +++ b/go.sum @@ -26,8 +26,6 @@ github.com/gobuffalo/packd v0.0.0-20181031195726-c82734870264 h1:roWyi0eEdiFreSq github.com/gobuffalo/packd v0.0.0-20181031195726-c82734870264/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI= github.com/gobuffalo/packr v1.19.0 h1:3UDmBDxesCOPF8iZdMDBBWKfkBoYujIMIZePnobqIUI= github.com/gobuffalo/packr v1.19.0/go.mod h1:MstrNkfCQhd5o+Ct4IJ0skWlxN8emOq8DsoT1G98VIU= -github.com/hmage/golibs v0.0.0-20190121112702-20153bd03c24 h1:yyDtaSMcAZdm1I6uL8YLghpWiJljfBHs8NC/P86PYQk= -github.com/hmage/golibs v0.0.0-20190121112702-20153bd03c24/go.mod h1:H6Ev6svFxUVPFThxLtdnFfcE9e3GWufpfmcVFpqV6HM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= From 3a9d436f8ae72a74f9e248d857c3d875aa81fcec Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Wed, 27 Feb 2019 16:15:36 +0300 Subject: [PATCH 13/95] 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 14/95] 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 15/95] 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 16/95] 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 523c5ef10a064cd9f75742fc84d6ecbf0a764e58 Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Wed, 27 Feb 2019 17:28:10 +0300 Subject: [PATCH 17/95] Refactor httpErrors --- control.go | 206 ++++++++++++++--------------------------------------- 1 file changed, 55 insertions(+), 151 deletions(-) diff --git a/control.go b/control.go index 70ff0e7c..23caf56e 100644 --- a/control.go +++ b/control.go @@ -51,9 +51,7 @@ var client = &http.Client{ func returnOK(w http.ResponseWriter) { _, err := fmt.Fprintf(w, "OK\n") 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) } } @@ -101,17 +99,13 @@ func handleStatus(w http.ResponseWriter, r *http.Request) { jsonVal, err := json.Marshal(data) if err != nil { - errorText := fmt.Sprintf("Unable to marshal status json: %s", err) - log.Println(errorText) - http.Error(w, errorText, 500) + httpError(w, http.StatusInternalServerError, "Unable to marshal status json: %s", err) return } w.Header().Set("Content-Type", "application/json") _, err = w.Write(jsonVal) if err != nil { - errorText := fmt.Sprintf("Unable to write response json: %s", err) - log.Println(errorText) - http.Error(w, errorText, 500) + httpError(w, http.StatusInternalServerError, "Unable to write response json: %s", err) return } } @@ -144,18 +138,14 @@ func handleQueryLog(w http.ResponseWriter, r *http.Request) { jsonVal, err := json.Marshal(data) if err != nil { - errorText := fmt.Sprintf("Couldn't marshal data into json: %s", err) - log.Println(errorText) - http.Error(w, errorText, http.StatusInternalServerError) + httpError(w, http.StatusInternalServerError, "Couldn't marshal data into json: %s", err) return } w.Header().Set("Content-Type", "application/json") _, err = w.Write(jsonVal) if err != nil { - errorText := fmt.Sprintf("Unable to write response json: %s", err) - log.Println(errorText) - http.Error(w, errorText, http.StatusInternalServerError) + httpError(w, http.StatusInternalServerError, "Unable to write response json: %s", err) } } @@ -200,9 +190,7 @@ func handleStatsTop(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") _, err := w.Write(statsJSON.Bytes()) 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) } } @@ -211,9 +199,7 @@ func handleStatsReset(w http.ResponseWriter, r *http.Request) { dnsServer.PurgeStats() _, err := fmt.Fprintf(w, "OK\n") 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) } } @@ -223,17 +209,13 @@ func handleStats(w http.ResponseWriter, r *http.Request) { statsJSON, err := json.Marshal(summed) if err != nil { - errorText := fmt.Sprintf("Unable to marshal status json: %s", err) - log.Println(errorText) - http.Error(w, errorText, 500) + httpError(w, http.StatusInternalServerError, "Unable to marshal status json: %s", err) return } w.Header().Set("Content-Type", "application/json") _, err = w.Write(statsJSON) if err != nil { - errorText := fmt.Sprintf("Unable to write response json: %s", err) - log.Println(errorText) - http.Error(w, errorText, 500) + httpError(w, http.StatusInternalServerError, "Unable to write response json: %s", err) return } } @@ -260,40 +242,31 @@ func handleStatsHistory(w http.ResponseWriter, r *http.Request) { // parse start and end time startTime, err := time.Parse(time.RFC3339, r.URL.Query().Get("start_time")) if err != nil { - errorText := fmt.Sprintf("Must specify valid start_time parameter: %s", err) - log.Println(errorText) - http.Error(w, errorText, http.StatusBadRequest) + httpError(w, http.StatusBadRequest, "Must specify valid start_time parameter: %s", err) return } endTime, err := time.Parse(time.RFC3339, r.URL.Query().Get("end_time")) if err != nil { - errorText := fmt.Sprintf("Must specify valid end_time parameter: %s", err) - log.Println(errorText) - http.Error(w, errorText, http.StatusBadRequest) + httpError(w, http.StatusBadRequest, "Must specify valid end_time parameter: %s", err) return } data, err := dnsServer.GetStatsHistory(timeUnit, startTime, endTime) if err != nil { - errorText := fmt.Sprintf("Cannot get stats history: %s", err) - http.Error(w, errorText, http.StatusBadRequest) + httpError(w, http.StatusBadRequest, "Cannot get stats history: %s", err) return } statsJSON, err := json.Marshal(data) if err != nil { - errorText := fmt.Sprintf("Unable to marshal status json: %s", err) - log.Println(errorText) - http.Error(w, errorText, http.StatusInternalServerError) + httpError(w, http.StatusInternalServerError, "Unable to marshal status json: %s", err) return } w.Header().Set("Content-Type", "application/json") _, err = w.Write(statsJSON) if err != nil { - errorText := fmt.Sprintf("Unable to write response json: %s", err) - log.Println(errorText) - http.Error(w, errorText, http.StatusInternalServerError) + httpError(w, http.StatusInternalServerError, "Unable to write response json: %s", err) return } } @@ -326,9 +299,7 @@ func sortByValue(m map[string]int) []string { func handleSetUpstreamDNS(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) + httpError(w, http.StatusBadRequest, "Failed to read request body: %s", err) return } // if empty body -- user is asking for default servers @@ -342,23 +313,17 @@ func handleSetUpstreamDNS(w http.ResponseWriter, r *http.Request) { 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", len(hosts)) 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) } } @@ -378,18 +343,14 @@ func handleAllServersStatus(w http.ResponseWriter, r *http.Request) { } jsonVal, err := json.Marshal(data) if err != nil { - errorText := fmt.Sprintf("Unable to marshal status json: %s", err) - log.Println(errorText) - http.Error(w, errorText, 500) + httpError(w, http.StatusInternalServerError, "Unable to marshal status json: %s", err) return } w.Header().Set("Content-Type", "application/json") _, err = w.Write(jsonVal) if err != nil { - errorText := fmt.Sprintf("Unable to write response json: %s", err) - log.Println(errorText) - http.Error(w, errorText, 500) + httpError(w, http.StatusInternalServerError, "Unable to write response json: %s", err) return } } @@ -397,17 +358,13 @@ func handleAllServersStatus(w http.ResponseWriter, r *http.Request) { func handleTestUpstreamDNS(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, 400) + httpError(w, http.StatusBadRequest, "Failed to read request body: %s", err) return } hosts := strings.Fields(string(body)) if len(hosts) == 0 { - errorText := fmt.Sprintf("No servers specified") - log.Println(errorText) - http.Error(w, errorText, http.StatusBadRequest) + httpError(w, http.StatusBadRequest, "No servers specified") return } @@ -425,18 +382,14 @@ func handleTestUpstreamDNS(w http.ResponseWriter, r *http.Request) { jsonVal, err := json.Marshal(result) if err != nil { - errorText := fmt.Sprintf("Unable to marshal status json: %s", err) - log.Println(errorText) - http.Error(w, errorText, http.StatusInternalServerError) + httpError(w, http.StatusInternalServerError, "Unable to marshal status json: %s", err) return } w.Header().Set("Content-Type", "application/json") _, err = w.Write(jsonVal) 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) } } @@ -481,9 +434,7 @@ func handleGetVersionJSON(w http.ResponseWriter, r *http.Request) { resp, err := client.Get(versionCheckURL) if err != nil { - errorText := fmt.Sprintf("Couldn't get version check json from %s: %T %s\n", versionCheckURL, err, err) - log.Println(errorText) - http.Error(w, errorText, http.StatusBadGateway) + httpError(w, http.StatusBadGateway, "Couldn't get version check json from %s: %T %s\n", versionCheckURL, err, err) return } if resp != nil && resp.Body != nil { @@ -493,18 +444,14 @@ func handleGetVersionJSON(w http.ResponseWriter, r *http.Request) { // read the body entirely body, err := ioutil.ReadAll(resp.Body) if err != nil { - errorText := fmt.Sprintf("Couldn't read response body from %s: %s", versionCheckURL, err) - log.Println(errorText) - http.Error(w, errorText, http.StatusBadGateway) + httpError(w, http.StatusBadGateway, "Couldn't read response body from %s: %s", versionCheckURL, err) return } w.Header().Set("Content-Type", "application/json") _, err = w.Write(body) 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) } versionCheckLastTime = now @@ -537,18 +484,14 @@ func handleFilteringStatus(w http.ResponseWriter, r *http.Request) { config.RUnlock() if err != nil { - errorText := fmt.Sprintf("Unable to marshal status json: %s", err) - log.Println(errorText) - http.Error(w, errorText, 500) + httpError(w, http.StatusInternalServerError, "Unable to marshal status json: %s", err) return } w.Header().Set("Content-Type", "application/json") _, err = w.Write(jsonVal) if err != nil { - errorText := fmt.Sprintf("Unable to write response json: %s", err) - log.Println(errorText) - http.Error(w, errorText, 500) + httpError(w, http.StatusInternalServerError, "Unable to write response json: %s", err) return } } @@ -562,21 +505,19 @@ func handleFilteringAddURL(w http.ResponseWriter, r *http.Request) { } if len(f.URL) == 0 { - http.Error(w, "URL parameter was not specified", 400) + http.Error(w, "URL parameter was not specified", http.StatusBadRequest) return } if valid := govalidator.IsRequestURL(f.URL); !valid { - http.Error(w, "URL parameter is not valid request URL", 400) + http.Error(w, "URL parameter is not valid request URL", http.StatusBadRequest) return } // Check for duplicates for i := range config.Filters { if config.Filters[i].URL == f.URL { - errorText := fmt.Sprintf("Filter URL already added -- %s", f.URL) - log.Println(errorText) - http.Error(w, errorText, http.StatusBadRequest) + httpError(w, http.StatusBadRequest, "Filter URL already added -- %s", f.URL) return } } @@ -588,30 +529,22 @@ func handleFilteringAddURL(w http.ResponseWriter, r *http.Request) { // Download the filter contents ok, err := f.update(true) if err != nil { - errorText := fmt.Sprintf("Couldn't fetch filter from url %s: %s", f.URL, err) - log.Println(errorText) - http.Error(w, errorText, http.StatusBadRequest) + httpError(w, http.StatusBadRequest, "Couldn't fetch filter from url %s: %s", f.URL, err) return } if f.RulesCount == 0 { - errorText := fmt.Sprintf("Filter at the url %s has no rules (maybe it points to blank page?)", f.URL) - log.Println(errorText) - http.Error(w, errorText, http.StatusBadRequest) + httpError(w, http.StatusBadRequest, "Filter at the url %s has no rules (maybe it points to blank page?)", f.URL) return } if !ok { - errorText := fmt.Sprintf("Filter at the url %s is invalid (maybe it points to blank page?)", f.URL) - log.Println(errorText) - http.Error(w, errorText, http.StatusBadRequest) + httpError(w, http.StatusBadRequest, "Filter at the url %s is invalid (maybe it points to blank page?)", f.URL) return } // Save the filter contents err = f.save() if err != nil { - errorText := fmt.Sprintf("Failed to save filter %d due to %s", f.ID, err) - log.Println(errorText) - http.Error(w, errorText, http.StatusBadRequest) + httpError(w, http.StatusBadRequest, "Failed to save filter %d due to %s", f.ID, err) return } @@ -620,44 +553,36 @@ func handleFilteringAddURL(w http.ResponseWriter, r *http.Request) { config.Filters = append(config.Filters, f) 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) } _, err = fmt.Fprintf(w, "OK %d rules\n", f.RulesCount) 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) } } func handleFilteringRemoveURL(w http.ResponseWriter, r *http.Request) { parameters, err := parseParametersFromBody(r.Body) if err != nil { - errorText := fmt.Sprintf("failed to parse parameters from body: %s", err) - log.Println(errorText) - http.Error(w, errorText, 400) + httpError(w, http.StatusBadRequest, "failed to parse parameters from body: %s", err) return } url, ok := parameters["url"] if !ok { - http.Error(w, "URL parameter was not specified", 400) + http.Error(w, "URL parameter was not specified", http.StatusBadRequest) return } if valid := govalidator.IsRequestURL(url); !valid { - http.Error(w, "URL parameter is not valid request URL", 400) + http.Error(w, "URL parameter is not valid request URL", http.StatusBadRequest) return } @@ -670,8 +595,7 @@ func handleFilteringRemoveURL(w http.ResponseWriter, r *http.Request) { // Remove the filter file err := os.Remove(filter.Path()) if err != nil && !os.IsNotExist(err) { - errorText := fmt.Sprintf("Couldn't remove the filter file: %s", err) - http.Error(w, errorText, http.StatusInternalServerError) + httpError(w, http.StatusInternalServerError, "Couldn't remove the filter file: %s", err) return } } @@ -684,15 +608,13 @@ func handleFilteringRemoveURL(w http.ResponseWriter, r *http.Request) { func handleFilteringEnableURL(w http.ResponseWriter, r *http.Request) { parameters, err := parseParametersFromBody(r.Body) if err != nil { - errorText := fmt.Sprintf("failed to parse parameters from body: %s", err) - log.Println(errorText) - http.Error(w, errorText, 400) + httpError(w, http.StatusBadRequest, "failed to parse parameters from body: %s", err) return } url, ok := parameters["url"] if !ok { - http.Error(w, "URL parameter was not specified", 400) + http.Error(w, "URL parameter was not specified", http.StatusBadRequest) return } @@ -723,15 +645,13 @@ func handleFilteringEnableURL(w http.ResponseWriter, r *http.Request) { func handleFilteringDisableURL(w http.ResponseWriter, r *http.Request) { parameters, err := parseParametersFromBody(r.Body) if err != nil { - errorText := fmt.Sprintf("failed to parse parameters from body: %s", err) - log.Println(errorText) - http.Error(w, errorText, 400) + httpError(w, http.StatusBadRequest, "failed to parse parameters from body: %s", err) return } url, ok := parameters["url"] if !ok { - http.Error(w, "URL parameter was not specified", 400) + http.Error(w, "URL parameter was not specified", http.StatusBadRequest) return } @@ -760,9 +680,7 @@ func handleFilteringDisableURL(w http.ResponseWriter, r *http.Request) { func handleFilteringSetRules(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, 400) + httpError(w, http.StatusBadRequest, "Failed to read request body: %s", err) return } @@ -796,17 +714,13 @@ func handleSafeBrowsingStatus(w http.ResponseWriter, r *http.Request) { } jsonVal, err := json.Marshal(data) if err != nil { - errorText := fmt.Sprintf("Unable to marshal status json: %s", err) - log.Println(errorText) - http.Error(w, errorText, 500) + httpError(w, http.StatusInternalServerError, "Unable to marshal status json: %s", err) } w.Header().Set("Content-Type", "application/json") _, err = w.Write(jsonVal) if err != nil { - errorText := fmt.Sprintf("Unable to write response json: %s", err) - log.Println(errorText) - http.Error(w, errorText, 500) + httpError(w, http.StatusInternalServerError, "Unable to write response json: %s", err) return } } @@ -817,9 +731,7 @@ func handleSafeBrowsingStatus(w http.ResponseWriter, r *http.Request) { func handleParentalEnable(w http.ResponseWriter, r *http.Request) { parameters, err := parseParametersFromBody(r.Body) if err != nil { - errorText := fmt.Sprintf("failed to parse parameters from body: %s", err) - log.Println(errorText) - http.Error(w, errorText, 400) + httpError(w, http.StatusBadRequest, "failed to parse parameters from body: %s", err) return } @@ -874,18 +786,14 @@ func handleParentalStatus(w http.ResponseWriter, r *http.Request) { } jsonVal, err := json.Marshal(data) if err != nil { - errorText := fmt.Sprintf("Unable to marshal status json: %s", err) - log.Println(errorText) - http.Error(w, errorText, 500) + httpError(w, http.StatusInternalServerError, "Unable to marshal status json: %s", err) return } w.Header().Set("Content-Type", "application/json") _, err = w.Write(jsonVal) if err != nil { - errorText := fmt.Sprintf("Unable to write response json: %s", err) - log.Println(errorText) - http.Error(w, errorText, 500) + httpError(w, http.StatusInternalServerError, "Unable to write response json: %s", err) return } } @@ -910,18 +818,14 @@ func handleSafeSearchStatus(w http.ResponseWriter, r *http.Request) { } jsonVal, err := json.Marshal(data) if err != nil { - errorText := fmt.Sprintf("Unable to marshal status json: %s", err) - log.Println(errorText) - http.Error(w, errorText, 500) + httpError(w, http.StatusInternalServerError, "Unable to marshal status json: %s", err) return } w.Header().Set("Content-Type", "application/json") _, err = w.Write(jsonVal) if err != nil { - errorText := fmt.Sprintf("Unable to write response json: %s", err) - log.Println(errorText) - http.Error(w, errorText, 500) + httpError(w, http.StatusInternalServerError, "Unable to write response json: %s", err) return } } From 5ad9f8ead26b85c4475363df94bf13f2600c84d8 Mon Sep 17 00:00:00 2001 From: Simon Zolin Date: Wed, 27 Feb 2019 17:36:02 +0300 Subject: [PATCH 18/95] * tlsConfigStatus.usable is public, renamed ("ValidPair") and is exported to json ("valid_pair") --- app.go | 2 +- config.go | 2 +- control.go | 2 +- control_test.go | 2 +- openapi/openapi.yaml | 4 ++++ 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app.go b/app.go index 07c67916..90575090 100644 --- a/app.go +++ b/app.go @@ -179,7 +179,7 @@ func run(args options) { address := net.JoinHostPort(config.BindHost, strconv.Itoa(config.TLS.PortHTTPS)) // validate current TLS config and update warnings (it could have been loaded from file) data := validateCertificates(config.TLS.CertificateChain, config.TLS.PrivateKey, config.TLS.ServerName) - if !data.usable { + if !data.ValidPair { log.Fatal(data.WarningValidation) os.Exit(1) } diff --git a/config.go b/config.go index 87e5c6a8..1afc8f17 100644 --- a/config.go +++ b/config.go @@ -87,7 +87,7 @@ type tlsConfigStatus struct { KeyType string `yaml:"-" json:"key_type,omitempty"` // KeyType is one of RSA or ECDSA // is usable? set by validator - usable bool + ValidPair bool `yaml:"-" json:"valid_pair"` // ValidPair is true if both certificate and private key are correct // warnings WarningValidation string `yaml:"-" json:"warning_validation,omitempty"` // WarningValidation is a validation warning message with the issue description diff --git a/control.go b/control.go index 57e614ca..eba3fd6e 100644 --- a/control.go +++ b/control.go @@ -1227,7 +1227,7 @@ func validateCertificates(certChain, pkey, serverName string) tlsConfigStatus { data.WarningValidation = fmt.Sprintf("Invalid certificate or key: %s", err) return data } - data.usable = true + data.ValidPair = true } return data diff --git a/control_test.go b/control_test.go index c5df3b45..b823b252 100644 --- a/control_test.go +++ b/control_test.go @@ -71,7 +71,7 @@ kXS9jgARhhiWXJrk data.NotBefore == notBefore && data.NotAfter == notAfter && // data.DNSNames[0] == && - data.usable) { + data.ValidPair) { t.Fatalf("valid cert & priv key: validateCertificates(): %v", data) } } diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index f1e23f86..4cf406e0 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -1247,6 +1247,10 @@ definitions: type: "string" example: "You have specified an empty certificate" description: "warning_validation is a validation warning message with the issue description" + valid_pair: + type: "boolean" + example: "true" + description: "valid_pair is true if both certificate and private key are correct" NetInterface: type: "object" description: "Network interface info" From 1ed3a9673dfca48deed23099105d336ee632a9ff Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Wed, 27 Feb 2019 17:39:07 +0300 Subject: [PATCH 19/95] Add handles logging --- control.go | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/control.go b/control.go index 23caf56e..b17e1c2e 100644 --- a/control.go +++ b/control.go @@ -83,6 +83,7 @@ func httpUpdateConfigReloadDNSReturnOK(w http.ResponseWriter, r *http.Request) { } func handleStatus(w http.ResponseWriter, r *http.Request) { + log.Tracef("") data := map[string]interface{}{ "dns_address": config.DNS.BindHost, "http_port": config.BindPort, @@ -111,11 +112,13 @@ func handleStatus(w http.ResponseWriter, r *http.Request) { } func handleProtectionEnable(w http.ResponseWriter, r *http.Request) { + log.Tracef("") config.DNS.ProtectionEnabled = true httpUpdateConfigReloadDNSReturnOK(w, r) } func handleProtectionDisable(w http.ResponseWriter, r *http.Request) { + log.Tracef("") config.DNS.ProtectionEnabled = false httpUpdateConfigReloadDNSReturnOK(w, r) } @@ -124,16 +127,19 @@ func handleProtectionDisable(w http.ResponseWriter, r *http.Request) { // stats // ----- func handleQueryLogEnable(w http.ResponseWriter, r *http.Request) { + log.Tracef("") config.DNS.QueryLogEnabled = true httpUpdateConfigReloadDNSReturnOK(w, r) } func handleQueryLogDisable(w http.ResponseWriter, r *http.Request) { + log.Tracef("") config.DNS.QueryLogEnabled = false httpUpdateConfigReloadDNSReturnOK(w, r) } func handleQueryLog(w http.ResponseWriter, r *http.Request) { + log.Tracef("") data := dnsServer.GetQueryLog() jsonVal, err := json.Marshal(data) @@ -150,6 +156,7 @@ func handleQueryLog(w http.ResponseWriter, r *http.Request) { } func handleStatsTop(w http.ResponseWriter, r *http.Request) { + log.Tracef("") s := dnsServer.GetStatsTop() // use manual json marshalling because we want maps to be sorted by value @@ -196,6 +203,7 @@ func handleStatsTop(w http.ResponseWriter, r *http.Request) { // handleStatsReset resets the stats caches func handleStatsReset(w http.ResponseWriter, r *http.Request) { + log.Tracef("") dnsServer.PurgeStats() _, err := fmt.Fprintf(w, "OK\n") if err != nil { @@ -205,6 +213,7 @@ func handleStatsReset(w http.ResponseWriter, r *http.Request) { // handleStats returns aggregated stats data for the 24 hours func handleStats(w http.ResponseWriter, r *http.Request) { + log.Tracef("") summed := dnsServer.GetAggregatedStats() statsJSON, err := json.Marshal(summed) @@ -222,6 +231,7 @@ func handleStats(w http.ResponseWriter, r *http.Request) { // HandleStatsHistory returns historical stats data for the 24 hours func handleStatsHistory(w http.ResponseWriter, r *http.Request) { + log.Tracef("") // handle time unit and prepare our time window size timeUnitString := r.URL.Query().Get("time_unit") var timeUnit time.Duration @@ -297,6 +307,7 @@ func sortByValue(m map[string]int) []string { // ----------------------- func handleSetUpstreamDNS(w http.ResponseWriter, r *http.Request) { + log.Tracef("") body, err := ioutil.ReadAll(r.Body) if err != nil { httpError(w, http.StatusBadRequest, "Failed to read request body: %s", err) @@ -328,16 +339,19 @@ func handleSetUpstreamDNS(w http.ResponseWriter, r *http.Request) { } func handleAllServersEnable(w http.ResponseWriter, r *http.Request) { + log.Tracef("") config.DNS.AllServers = true httpUpdateConfigReloadDNSReturnOK(w, r) } func handleAllServersDisable(w http.ResponseWriter, r *http.Request) { + log.Tracef("") config.DNS.AllServers = false httpUpdateConfigReloadDNSReturnOK(w, r) } func handleAllServersStatus(w http.ResponseWriter, r *http.Request) { + log.Tracef("") data := map[string]interface{}{ "enabled": config.DNS.AllServers, } @@ -356,6 +370,7 @@ func handleAllServersStatus(w http.ResponseWriter, r *http.Request) { } func handleTestUpstreamDNS(w http.ResponseWriter, r *http.Request) { + log.Tracef("") body, err := ioutil.ReadAll(r.Body) if err != nil { httpError(w, http.StatusBadRequest, "Failed to read request body: %s", err) @@ -424,6 +439,7 @@ func checkDNS(input string) error { } func handleGetVersionJSON(w http.ResponseWriter, r *http.Request) { + log.Tracef("") now := time.Now() if now.Sub(versionCheckLastTime) <= versionCheckPeriod && len(versionCheckJSON) != 0 { // return cached copy @@ -463,16 +479,19 @@ func handleGetVersionJSON(w http.ResponseWriter, r *http.Request) { // --------- func handleFilteringEnable(w http.ResponseWriter, r *http.Request) { + log.Tracef("") config.DNS.FilteringEnabled = true httpUpdateConfigReloadDNSReturnOK(w, r) } func handleFilteringDisable(w http.ResponseWriter, r *http.Request) { + log.Tracef("") config.DNS.FilteringEnabled = false httpUpdateConfigReloadDNSReturnOK(w, r) } func handleFilteringStatus(w http.ResponseWriter, r *http.Request) { + log.Tracef("") data := map[string]interface{}{ "enabled": config.DNS.FilteringEnabled, } @@ -497,6 +516,7 @@ func handleFilteringStatus(w http.ResponseWriter, r *http.Request) { } func handleFilteringAddURL(w http.ResponseWriter, r *http.Request) { + log.Tracef("") f := filter{} err := json.NewDecoder(r.Body).Decode(&f) if err != nil { @@ -569,6 +589,7 @@ func handleFilteringAddURL(w http.ResponseWriter, r *http.Request) { } func handleFilteringRemoveURL(w http.ResponseWriter, r *http.Request) { + log.Tracef("") parameters, err := parseParametersFromBody(r.Body) if err != nil { httpError(w, http.StatusBadRequest, "failed to parse parameters from body: %s", err) @@ -606,6 +627,7 @@ func handleFilteringRemoveURL(w http.ResponseWriter, r *http.Request) { } func handleFilteringEnableURL(w http.ResponseWriter, r *http.Request) { + log.Tracef("") parameters, err := parseParametersFromBody(r.Body) if err != nil { httpError(w, http.StatusBadRequest, "failed to parse parameters from body: %s", err) @@ -643,6 +665,7 @@ func handleFilteringEnableURL(w http.ResponseWriter, r *http.Request) { } func handleFilteringDisableURL(w http.ResponseWriter, r *http.Request) { + log.Tracef("") parameters, err := parseParametersFromBody(r.Body) if err != nil { httpError(w, http.StatusBadRequest, "failed to parse parameters from body: %s", err) @@ -678,6 +701,7 @@ func handleFilteringDisableURL(w http.ResponseWriter, r *http.Request) { } func handleFilteringSetRules(w http.ResponseWriter, r *http.Request) { + log.Tracef("") body, err := ioutil.ReadAll(r.Body) if err != nil { httpError(w, http.StatusBadRequest, "Failed to read request body: %s", err) @@ -689,6 +713,7 @@ func handleFilteringSetRules(w http.ResponseWriter, r *http.Request) { } func handleFilteringRefresh(w http.ResponseWriter, r *http.Request) { + log.Tracef("") force := r.URL.Query().Get("force") updated := refreshFiltersIfNecessary(force != "") fmt.Fprintf(w, "OK %d filters updated\n", updated) @@ -699,16 +724,19 @@ func handleFilteringRefresh(w http.ResponseWriter, r *http.Request) { // ------------ func handleSafeBrowsingEnable(w http.ResponseWriter, r *http.Request) { + log.Tracef("") config.DNS.SafeBrowsingEnabled = true httpUpdateConfigReloadDNSReturnOK(w, r) } func handleSafeBrowsingDisable(w http.ResponseWriter, r *http.Request) { + log.Tracef("") config.DNS.SafeBrowsingEnabled = false httpUpdateConfigReloadDNSReturnOK(w, r) } func handleSafeBrowsingStatus(w http.ResponseWriter, r *http.Request) { + log.Tracef("") data := map[string]interface{}{ "enabled": config.DNS.SafeBrowsingEnabled, } @@ -729,6 +757,7 @@ func handleSafeBrowsingStatus(w http.ResponseWriter, r *http.Request) { // parental // -------- func handleParentalEnable(w http.ResponseWriter, r *http.Request) { + log.Tracef("") parameters, err := parseParametersFromBody(r.Body) if err != nil { httpError(w, http.StatusBadRequest, "failed to parse parameters from body: %s", err) @@ -773,11 +802,13 @@ func handleParentalEnable(w http.ResponseWriter, r *http.Request) { } func handleParentalDisable(w http.ResponseWriter, r *http.Request) { + log.Tracef("") config.DNS.ParentalEnabled = false httpUpdateConfigReloadDNSReturnOK(w, r) } func handleParentalStatus(w http.ResponseWriter, r *http.Request) { + log.Tracef("") data := map[string]interface{}{ "enabled": config.DNS.ParentalEnabled, } @@ -803,16 +834,19 @@ func handleParentalStatus(w http.ResponseWriter, r *http.Request) { // ------------ func handleSafeSearchEnable(w http.ResponseWriter, r *http.Request) { + log.Tracef("") config.DNS.SafeSearchEnabled = true httpUpdateConfigReloadDNSReturnOK(w, r) } func handleSafeSearchDisable(w http.ResponseWriter, r *http.Request) { + log.Tracef("") config.DNS.SafeSearchEnabled = false httpUpdateConfigReloadDNSReturnOK(w, r) } func handleSafeSearchStatus(w http.ResponseWriter, r *http.Request) { + log.Tracef("") data := map[string]interface{}{ "enabled": config.DNS.SafeSearchEnabled, } @@ -845,6 +879,7 @@ type firstRunData struct { } func handleInstallGetAddresses(w http.ResponseWriter, r *http.Request) { + log.Tracef("") data := firstRunData{} // find out if port 80 is available -- if not, fall back to 3000 @@ -880,6 +915,7 @@ func handleInstallGetAddresses(w http.ResponseWriter, r *http.Request) { } func handleInstallConfigure(w http.ResponseWriter, r *http.Request) { + log.Tracef("") newSettings := firstRunData{} err := json.NewDecoder(r.Body).Decode(&newSettings) if err != nil { @@ -938,10 +974,12 @@ func handleInstallConfigure(w http.ResponseWriter, r *http.Request) { // TLS // --- func handleTLSStatus(w http.ResponseWriter, r *http.Request) { + log.Tracef("") marshalTLS(w, config.TLS) } func handleTLSValidate(w http.ResponseWriter, r *http.Request) { + log.Tracef("") data, err := unmarshalTLS(r) if err != nil { httpError(w, http.StatusBadRequest, "Failed to unmarshal TLS config: %s", err) @@ -967,6 +1005,7 @@ func handleTLSValidate(w http.ResponseWriter, r *http.Request) { } func handleTLSConfigure(w http.ResponseWriter, r *http.Request) { + log.Tracef("") data, err := unmarshalTLS(r) if err != nil { httpError(w, http.StatusBadRequest, "Failed to unmarshal TLS config: %s", err) @@ -1224,6 +1263,7 @@ func marshalTLS(w http.ResponseWriter, data tlsConfig) { // DNS-over-HTTPS // -------------- func handleDOH(w http.ResponseWriter, r *http.Request) { + log.Tracef("") if r.TLS == nil { httpError(w, http.StatusNotFound, "Not Found") return From eb22d9cdd9d74a150bd31ef0efb497e3bdc9fae1 Mon Sep 17 00:00:00 2001 From: Simon Zolin Date: Wed, 27 Feb 2019 17:55:23 +0300 Subject: [PATCH 20/95] * use golibs v0.1.0 --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 49f35dc7..17d3e7f6 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module github.com/AdguardTeam/AdGuardHome require ( github.com/AdguardTeam/dnsproxy v0.11.1 - github.com/AdguardTeam/golibs v0.1 + github.com/AdguardTeam/golibs v0.1.0 github.com/StackExchange/wmi v0.0.0-20180725035823-b12b22c5341f // indirect github.com/bluele/gcache v0.0.0-20171010155617-472614239ac7 github.com/go-ole/go-ole v1.2.1 // indirect diff --git a/go.sum b/go.sum index 3f19484f..08cbdd65 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/AdguardTeam/dnsproxy v0.11.1 h1:qO5VH0GYF9vdksQRG8frEfJ+CJjsPBwuct8FH6Mij7o= github.com/AdguardTeam/dnsproxy v0.11.1/go.mod h1:lEi2srAWwfSQWoy8GeZR6lwS+FSMoiZid8bQPreOLb0= +github.com/AdguardTeam/golibs v0.1.0 h1:Mo1QNKC8eSbqczhxfdBXYCrUMwvgCyCwZFyWv+2Gdng= +github.com/AdguardTeam/golibs v0.1.0/go.mod h1:zhi6xGwK4cMpjDocybhhLgvcGkstiSIjlpKbvyxC5Yc= github.com/StackExchange/wmi v0.0.0-20180725035823-b12b22c5341f h1:5ZfJxyXo8KyX8DgGXC5B7ILL8y51fci/qYz2B4j8iLY= github.com/StackExchange/wmi v0.0.0-20180725035823-b12b22c5341f/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY= From 1626b6bd5aace36f86cc7ea9c399396b4aa1f73b Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Wed, 27 Feb 2019 18:09:57 +0300 Subject: [PATCH 21/95] Fix empty logging --- control.go | 80 +++++++++++++++++++++++++++--------------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/control.go b/control.go index b17e1c2e..ed5fc682 100644 --- a/control.go +++ b/control.go @@ -83,7 +83,7 @@ func httpUpdateConfigReloadDNSReturnOK(w http.ResponseWriter, r *http.Request) { } func handleStatus(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) data := map[string]interface{}{ "dns_address": config.DNS.BindHost, "http_port": config.BindPort, @@ -112,13 +112,13 @@ func handleStatus(w http.ResponseWriter, r *http.Request) { } func handleProtectionEnable(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) config.DNS.ProtectionEnabled = true httpUpdateConfigReloadDNSReturnOK(w, r) } func handleProtectionDisable(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) config.DNS.ProtectionEnabled = false httpUpdateConfigReloadDNSReturnOK(w, r) } @@ -127,19 +127,19 @@ func handleProtectionDisable(w http.ResponseWriter, r *http.Request) { // stats // ----- func handleQueryLogEnable(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) config.DNS.QueryLogEnabled = true httpUpdateConfigReloadDNSReturnOK(w, r) } func handleQueryLogDisable(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) config.DNS.QueryLogEnabled = false httpUpdateConfigReloadDNSReturnOK(w, r) } func handleQueryLog(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) data := dnsServer.GetQueryLog() jsonVal, err := json.Marshal(data) @@ -156,7 +156,7 @@ func handleQueryLog(w http.ResponseWriter, r *http.Request) { } func handleStatsTop(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) s := dnsServer.GetStatsTop() // use manual json marshalling because we want maps to be sorted by value @@ -203,7 +203,7 @@ func handleStatsTop(w http.ResponseWriter, r *http.Request) { // handleStatsReset resets the stats caches func handleStatsReset(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) dnsServer.PurgeStats() _, err := fmt.Fprintf(w, "OK\n") if err != nil { @@ -213,7 +213,7 @@ func handleStatsReset(w http.ResponseWriter, r *http.Request) { // handleStats returns aggregated stats data for the 24 hours func handleStats(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) summed := dnsServer.GetAggregatedStats() statsJSON, err := json.Marshal(summed) @@ -231,7 +231,7 @@ func handleStats(w http.ResponseWriter, r *http.Request) { // HandleStatsHistory returns historical stats data for the 24 hours func handleStatsHistory(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) // handle time unit and prepare our time window size timeUnitString := r.URL.Query().Get("time_unit") var timeUnit time.Duration @@ -307,7 +307,7 @@ func sortByValue(m map[string]int) []string { // ----------------------- func handleSetUpstreamDNS(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) body, err := ioutil.ReadAll(r.Body) if err != nil { httpError(w, http.StatusBadRequest, "Failed to read request body: %s", err) @@ -339,19 +339,19 @@ func handleSetUpstreamDNS(w http.ResponseWriter, r *http.Request) { } func handleAllServersEnable(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) config.DNS.AllServers = true httpUpdateConfigReloadDNSReturnOK(w, r) } func handleAllServersDisable(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) config.DNS.AllServers = false httpUpdateConfigReloadDNSReturnOK(w, r) } func handleAllServersStatus(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) data := map[string]interface{}{ "enabled": config.DNS.AllServers, } @@ -370,7 +370,7 @@ func handleAllServersStatus(w http.ResponseWriter, r *http.Request) { } func handleTestUpstreamDNS(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) body, err := ioutil.ReadAll(r.Body) if err != nil { httpError(w, http.StatusBadRequest, "Failed to read request body: %s", err) @@ -439,7 +439,7 @@ func checkDNS(input string) error { } func handleGetVersionJSON(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) now := time.Now() if now.Sub(versionCheckLastTime) <= versionCheckPeriod && len(versionCheckJSON) != 0 { // return cached copy @@ -479,19 +479,19 @@ func handleGetVersionJSON(w http.ResponseWriter, r *http.Request) { // --------- func handleFilteringEnable(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) config.DNS.FilteringEnabled = true httpUpdateConfigReloadDNSReturnOK(w, r) } func handleFilteringDisable(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) config.DNS.FilteringEnabled = false httpUpdateConfigReloadDNSReturnOK(w, r) } func handleFilteringStatus(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) data := map[string]interface{}{ "enabled": config.DNS.FilteringEnabled, } @@ -516,7 +516,7 @@ func handleFilteringStatus(w http.ResponseWriter, r *http.Request) { } func handleFilteringAddURL(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) f := filter{} err := json.NewDecoder(r.Body).Decode(&f) if err != nil { @@ -589,7 +589,7 @@ func handleFilteringAddURL(w http.ResponseWriter, r *http.Request) { } func handleFilteringRemoveURL(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) parameters, err := parseParametersFromBody(r.Body) if err != nil { httpError(w, http.StatusBadRequest, "failed to parse parameters from body: %s", err) @@ -627,7 +627,7 @@ func handleFilteringRemoveURL(w http.ResponseWriter, r *http.Request) { } func handleFilteringEnableURL(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) parameters, err := parseParametersFromBody(r.Body) if err != nil { httpError(w, http.StatusBadRequest, "failed to parse parameters from body: %s", err) @@ -665,7 +665,7 @@ func handleFilteringEnableURL(w http.ResponseWriter, r *http.Request) { } func handleFilteringDisableURL(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) parameters, err := parseParametersFromBody(r.Body) if err != nil { httpError(w, http.StatusBadRequest, "failed to parse parameters from body: %s", err) @@ -701,7 +701,7 @@ func handleFilteringDisableURL(w http.ResponseWriter, r *http.Request) { } func handleFilteringSetRules(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) body, err := ioutil.ReadAll(r.Body) if err != nil { httpError(w, http.StatusBadRequest, "Failed to read request body: %s", err) @@ -713,7 +713,7 @@ func handleFilteringSetRules(w http.ResponseWriter, r *http.Request) { } func handleFilteringRefresh(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) force := r.URL.Query().Get("force") updated := refreshFiltersIfNecessary(force != "") fmt.Fprintf(w, "OK %d filters updated\n", updated) @@ -724,19 +724,19 @@ func handleFilteringRefresh(w http.ResponseWriter, r *http.Request) { // ------------ func handleSafeBrowsingEnable(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) config.DNS.SafeBrowsingEnabled = true httpUpdateConfigReloadDNSReturnOK(w, r) } func handleSafeBrowsingDisable(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) config.DNS.SafeBrowsingEnabled = false httpUpdateConfigReloadDNSReturnOK(w, r) } func handleSafeBrowsingStatus(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) data := map[string]interface{}{ "enabled": config.DNS.SafeBrowsingEnabled, } @@ -757,7 +757,7 @@ func handleSafeBrowsingStatus(w http.ResponseWriter, r *http.Request) { // parental // -------- func handleParentalEnable(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) parameters, err := parseParametersFromBody(r.Body) if err != nil { httpError(w, http.StatusBadRequest, "failed to parse parameters from body: %s", err) @@ -802,13 +802,13 @@ func handleParentalEnable(w http.ResponseWriter, r *http.Request) { } func handleParentalDisable(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) config.DNS.ParentalEnabled = false httpUpdateConfigReloadDNSReturnOK(w, r) } func handleParentalStatus(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) data := map[string]interface{}{ "enabled": config.DNS.ParentalEnabled, } @@ -834,19 +834,19 @@ func handleParentalStatus(w http.ResponseWriter, r *http.Request) { // ------------ func handleSafeSearchEnable(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) config.DNS.SafeSearchEnabled = true httpUpdateConfigReloadDNSReturnOK(w, r) } func handleSafeSearchDisable(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) config.DNS.SafeSearchEnabled = false httpUpdateConfigReloadDNSReturnOK(w, r) } func handleSafeSearchStatus(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) data := map[string]interface{}{ "enabled": config.DNS.SafeSearchEnabled, } @@ -879,7 +879,7 @@ type firstRunData struct { } func handleInstallGetAddresses(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) data := firstRunData{} // find out if port 80 is available -- if not, fall back to 3000 @@ -915,7 +915,7 @@ func handleInstallGetAddresses(w http.ResponseWriter, r *http.Request) { } func handleInstallConfigure(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) newSettings := firstRunData{} err := json.NewDecoder(r.Body).Decode(&newSettings) if err != nil { @@ -974,12 +974,12 @@ func handleInstallConfigure(w http.ResponseWriter, r *http.Request) { // TLS // --- func handleTLSStatus(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) marshalTLS(w, config.TLS) } func handleTLSValidate(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) data, err := unmarshalTLS(r) if err != nil { httpError(w, http.StatusBadRequest, "Failed to unmarshal TLS config: %s", err) @@ -1005,7 +1005,7 @@ func handleTLSValidate(w http.ResponseWriter, r *http.Request) { } func handleTLSConfigure(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) data, err := unmarshalTLS(r) if err != nil { httpError(w, http.StatusBadRequest, "Failed to unmarshal TLS config: %s", err) @@ -1263,7 +1263,7 @@ func marshalTLS(w http.ResponseWriter, data tlsConfig) { // DNS-over-HTTPS // -------------- func handleDOH(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) if r.TLS == nil { httpError(w, http.StatusNotFound, "Not Found") return From 7b64f9ff4282b6e582976cf66d632a30bc585503 Mon Sep 17 00:00:00 2001 From: Simon Zolin Date: Wed, 27 Feb 2019 18:28:09 +0300 Subject: [PATCH 22/95] * use dnsproxy v0.11.2 --- control.go | 2 +- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/control.go b/control.go index 52b85615..919602be 100644 --- a/control.go +++ b/control.go @@ -24,8 +24,8 @@ import ( "time" "github.com/AdguardTeam/AdGuardHome/dnsforward" - "github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/dnsproxy/upstream" + "github.com/AdguardTeam/golibs/log" "github.com/joomcode/errorx" "github.com/miekg/dns" govalidator "gopkg.in/asaskevich/govalidator.v4" diff --git a/go.mod b/go.mod index 17d3e7f6..d824b5b7 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,7 @@ module github.com/AdguardTeam/AdGuardHome require ( - github.com/AdguardTeam/dnsproxy v0.11.1 + github.com/AdguardTeam/dnsproxy v0.11.2 github.com/AdguardTeam/golibs v0.1.0 github.com/StackExchange/wmi v0.0.0-20180725035823-b12b22c5341f // indirect github.com/bluele/gcache v0.0.0-20171010155617-472614239ac7 diff --git a/go.sum b/go.sum index 08cbdd65..6e4a79f1 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/AdguardTeam/dnsproxy v0.11.1 h1:qO5VH0GYF9vdksQRG8frEfJ+CJjsPBwuct8FH6Mij7o= -github.com/AdguardTeam/dnsproxy v0.11.1/go.mod h1:lEi2srAWwfSQWoy8GeZR6lwS+FSMoiZid8bQPreOLb0= +github.com/AdguardTeam/dnsproxy v0.11.2 h1:S/Ag2q9qoZsmW1fvMohPZP7/5amEtz8NmFCp8kxUalQ= +github.com/AdguardTeam/dnsproxy v0.11.2/go.mod h1:EPp92b5cYR7HZpO+OQu6xC7AyhUoBaXW3sfa3exq/0I= github.com/AdguardTeam/golibs v0.1.0 h1:Mo1QNKC8eSbqczhxfdBXYCrUMwvgCyCwZFyWv+2Gdng= github.com/AdguardTeam/golibs v0.1.0/go.mod h1:zhi6xGwK4cMpjDocybhhLgvcGkstiSIjlpKbvyxC5Yc= github.com/StackExchange/wmi v0.0.0-20180725035823-b12b22c5341f h1:5ZfJxyXo8KyX8DgGXC5B7ILL8y51fci/qYz2B4j8iLY= From f21daae02368841bdb7b8bff05bf208e3b9ab136 Mon Sep 17 00:00:00 2001 From: Simon Zolin Date: Wed, 27 Feb 2019 18:28:52 +0300 Subject: [PATCH 23/95] * control: print HTTP request with log.Tracef() --- control.go | 74 +++++++++++++++++++++++++++--------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/control.go b/control.go index 919602be..2b175e3e 100644 --- a/control.go +++ b/control.go @@ -85,7 +85,7 @@ func httpUpdateConfigReloadDNSReturnOK(w http.ResponseWriter, r *http.Request) { } func handleStatus(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) data := map[string]interface{}{ "dns_address": config.DNS.BindHost, "http_port": config.BindPort, @@ -117,13 +117,13 @@ func handleStatus(w http.ResponseWriter, r *http.Request) { } func handleProtectionEnable(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) config.DNS.ProtectionEnabled = true httpUpdateConfigReloadDNSReturnOK(w, r) } func handleProtectionDisable(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) config.DNS.ProtectionEnabled = false httpUpdateConfigReloadDNSReturnOK(w, r) } @@ -132,19 +132,19 @@ func handleProtectionDisable(w http.ResponseWriter, r *http.Request) { // stats // ----- func handleQueryLogEnable(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) config.DNS.QueryLogEnabled = true httpUpdateConfigReloadDNSReturnOK(w, r) } func handleQueryLogDisable(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) config.DNS.QueryLogEnabled = false httpUpdateConfigReloadDNSReturnOK(w, r) } func handleQueryLog(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) data := dnsServer.GetQueryLog() jsonVal, err := json.Marshal(data) @@ -165,7 +165,7 @@ func handleQueryLog(w http.ResponseWriter, r *http.Request) { } func handleStatsTop(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) s := dnsServer.GetStatsTop() // use manual json marshalling because we want maps to be sorted by value @@ -214,7 +214,7 @@ func handleStatsTop(w http.ResponseWriter, r *http.Request) { // handleStatsReset resets the stats caches func handleStatsReset(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) dnsServer.PurgeStats() _, err := fmt.Fprintf(w, "OK\n") if err != nil { @@ -226,7 +226,7 @@ func handleStatsReset(w http.ResponseWriter, r *http.Request) { // handleStats returns aggregated stats data for the 24 hours func handleStats(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) summed := dnsServer.GetAggregatedStats() statsJSON, err := json.Marshal(summed) @@ -248,7 +248,7 @@ func handleStats(w http.ResponseWriter, r *http.Request) { // HandleStatsHistory returns historical stats data for the 24 hours func handleStatsHistory(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) // handle time unit and prepare our time window size timeUnitString := r.URL.Query().Get("time_unit") var timeUnit time.Duration @@ -333,7 +333,7 @@ func sortByValue(m map[string]int) []string { // ----------------------- func handleSetUpstreamDNS(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) body, err := ioutil.ReadAll(r.Body) if err != nil { errorText := fmt.Sprintf("Failed to read request body: %s", err) @@ -373,7 +373,7 @@ func handleSetUpstreamDNS(w http.ResponseWriter, r *http.Request) { } func handleTestUpstreamDNS(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) body, err := ioutil.ReadAll(r.Body) if err != nil { errorText := fmt.Sprintf("Failed to read request body: %s", err) @@ -450,7 +450,7 @@ func checkDNS(input string) error { } func handleGetVersionJSON(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) now := time.Now() if now.Sub(versionCheckLastTime) <= versionCheckPeriod && len(versionCheckJSON) != 0 { // return cached copy @@ -496,19 +496,19 @@ func handleGetVersionJSON(w http.ResponseWriter, r *http.Request) { // --------- func handleFilteringEnable(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) config.DNS.FilteringEnabled = true httpUpdateConfigReloadDNSReturnOK(w, r) } func handleFilteringDisable(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) config.DNS.FilteringEnabled = false httpUpdateConfigReloadDNSReturnOK(w, r) } func handleFilteringStatus(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) data := map[string]interface{}{ "enabled": config.DNS.FilteringEnabled, } @@ -537,7 +537,7 @@ func handleFilteringStatus(w http.ResponseWriter, r *http.Request) { } func handleFilteringAddURL(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) f := filter{} err := json.NewDecoder(r.Body).Decode(&f) if err != nil { @@ -626,7 +626,7 @@ func handleFilteringAddURL(w http.ResponseWriter, r *http.Request) { } func handleFilteringRemoveURL(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) parameters, err := parseParametersFromBody(r.Body) if err != nil { errorText := fmt.Sprintf("failed to parse parameters from body: %s", err) @@ -667,7 +667,7 @@ func handleFilteringRemoveURL(w http.ResponseWriter, r *http.Request) { } func handleFilteringEnableURL(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) parameters, err := parseParametersFromBody(r.Body) if err != nil { errorText := fmt.Sprintf("failed to parse parameters from body: %s", err) @@ -707,7 +707,7 @@ func handleFilteringEnableURL(w http.ResponseWriter, r *http.Request) { } func handleFilteringDisableURL(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) parameters, err := parseParametersFromBody(r.Body) if err != nil { errorText := fmt.Sprintf("failed to parse parameters from body: %s", err) @@ -745,7 +745,7 @@ func handleFilteringDisableURL(w http.ResponseWriter, r *http.Request) { } func handleFilteringSetRules(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) body, err := ioutil.ReadAll(r.Body) if err != nil { errorText := fmt.Sprintf("Failed to read request body: %s", err) @@ -759,7 +759,7 @@ func handleFilteringSetRules(w http.ResponseWriter, r *http.Request) { } func handleFilteringRefresh(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) force := r.URL.Query().Get("force") updated := refreshFiltersIfNecessary(force != "") fmt.Fprintf(w, "OK %d filters updated\n", updated) @@ -770,19 +770,19 @@ func handleFilteringRefresh(w http.ResponseWriter, r *http.Request) { // ------------ func handleSafeBrowsingEnable(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) config.DNS.SafeBrowsingEnabled = true httpUpdateConfigReloadDNSReturnOK(w, r) } func handleSafeBrowsingDisable(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) config.DNS.SafeBrowsingEnabled = false httpUpdateConfigReloadDNSReturnOK(w, r) } func handleSafeBrowsingStatus(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) data := map[string]interface{}{ "enabled": config.DNS.SafeBrowsingEnabled, } @@ -807,7 +807,7 @@ func handleSafeBrowsingStatus(w http.ResponseWriter, r *http.Request) { // parental // -------- func handleParentalEnable(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) parameters, err := parseParametersFromBody(r.Body) if err != nil { errorText := fmt.Sprintf("failed to parse parameters from body: %s", err) @@ -854,13 +854,13 @@ func handleParentalEnable(w http.ResponseWriter, r *http.Request) { } func handleParentalDisable(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) config.DNS.ParentalEnabled = false httpUpdateConfigReloadDNSReturnOK(w, r) } func handleParentalStatus(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) data := map[string]interface{}{ "enabled": config.DNS.ParentalEnabled, } @@ -890,19 +890,19 @@ func handleParentalStatus(w http.ResponseWriter, r *http.Request) { // ------------ func handleSafeSearchEnable(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) config.DNS.SafeSearchEnabled = true httpUpdateConfigReloadDNSReturnOK(w, r) } func handleSafeSearchDisable(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) config.DNS.SafeSearchEnabled = false httpUpdateConfigReloadDNSReturnOK(w, r) } func handleSafeSearchStatus(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) data := map[string]interface{}{ "enabled": config.DNS.SafeSearchEnabled, } @@ -939,7 +939,7 @@ type firstRunData struct { } func handleInstallGetAddresses(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) data := firstRunData{} // find out if port 80 is available -- if not, fall back to 3000 @@ -975,7 +975,7 @@ func handleInstallGetAddresses(w http.ResponseWriter, r *http.Request) { } func handleInstallConfigure(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) newSettings := firstRunData{} err := json.NewDecoder(r.Body).Decode(&newSettings) if err != nil { @@ -1034,12 +1034,12 @@ func handleInstallConfigure(w http.ResponseWriter, r *http.Request) { // TLS // --- func handleTLSStatus(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) marshalTLS(w, config.TLS) } func handleTLSValidate(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) data, err := unmarshalTLS(r) if err != nil { httpError(w, http.StatusBadRequest, "Failed to unmarshal TLS config: %s", err) @@ -1065,7 +1065,7 @@ func handleTLSValidate(w http.ResponseWriter, r *http.Request) { } func handleTLSConfigure(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) data, err := unmarshalTLS(r) if err != nil { httpError(w, http.StatusBadRequest, "Failed to unmarshal TLS config: %s", err) @@ -1323,7 +1323,7 @@ func marshalTLS(w http.ResponseWriter, data tlsConfig) { // DNS-over-HTTPS // -------------- func handleDOH(w http.ResponseWriter, r *http.Request) { - log.Tracef("") + log.Tracef("%s %v", r.Method, r.URL) if r.TLS == nil { httpError(w, http.StatusNotFound, "Not Found") return From 24edf7eeb66668893b9add03003309d755295088 Mon Sep 17 00:00:00 2001 From: Simon Zolin Date: Wed, 27 Feb 2019 18:46:04 +0300 Subject: [PATCH 24/95] * helper functions return 'error', not 'int' --- control.go | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/control.go b/control.go index 540dee3f..0a074592 100644 --- a/control.go +++ b/control.go @@ -1114,8 +1114,7 @@ func handleTLSConfigure(w http.ResponseWriter, r *http.Request) { } } -// Return 0 on success -func verifyCertChain(data *tlsConfigStatus, certChain string, serverName string) int { +func verifyCertChain(data *tlsConfigStatus, certChain string, serverName string) error { log.Tracef("got certificate: %s", certChain) // now do a more extended validation @@ -1142,14 +1141,14 @@ func verifyCertChain(data *tlsConfigStatus, certChain string, serverName string) parsed, err := x509.ParseCertificate(cert.Bytes) if err != nil { data.WarningValidation = fmt.Sprintf("Failed to parse certificate: %s", err) - return 1 + return errors.New("") } parsedCerts = append(parsedCerts, parsed) } if len(parsedCerts) == 0 { data.WarningValidation = fmt.Sprintf("You have specified an empty certificate") - return 1 + return errors.New("") } data.ValidCert = true @@ -1192,11 +1191,10 @@ func verifyCertChain(data *tlsConfigStatus, certChain string, serverName string) data.DNSNames = mainCert.DNSNames } - return 0 + return nil } -// Return 0 on success -func validatePkey(data *tlsConfigStatus, pkey string) int { +func validatePkey(data *tlsConfigStatus, pkey string) error { // now do a more extended validation var key *pem.Block // PEM-encoded certificates var skippedBytes []string // skipped bytes @@ -1219,19 +1217,19 @@ func validatePkey(data *tlsConfigStatus, pkey string) int { if key == nil { data.WarningValidation = "No valid keys were found" - return 1 + return errors.New("") } // parse the decoded key _, keytype, err := parsePrivateKey(key.Bytes) if err != nil { data.WarningValidation = fmt.Sprintf("Failed to parse private key: %s", err) - return 1 + return errors.New("") } data.ValidKey = true data.KeyType = keytype - return 0 + return nil } /* Process certificate data and its private key. @@ -1244,14 +1242,14 @@ func validateCertificates(certChain, pkey, serverName string) tlsConfigStatus { // check only public certificate separately from the key if certChain != "" { - if verifyCertChain(&data, certChain, serverName) != 0 { + if verifyCertChain(&data, certChain, serverName) != nil { return data } } // validate private key (right now the only validation possible is just parsing it) if pkey != "" { - if validatePkey(&data, pkey) != 0 { + if validatePkey(&data, pkey) != nil { return data } } From bc325de13f2714961fdf32ef79fc3451d8db1f83 Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Wed, 27 Feb 2019 18:49:53 +0300 Subject: [PATCH 25/95] 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) } From 241e7ca20c6ee3a53cd59922c44dfe9fe35698d7 Mon Sep 17 00:00:00 2001 From: Simon Zolin Date: Wed, 27 Feb 2019 18:53:16 +0300 Subject: [PATCH 26/95] * control: move TLS handlers to a separate file --- control.go | 320 +--------------------------------------------- control_tls.go | 338 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 339 insertions(+), 319 deletions(-) create mode 100644 control_tls.go diff --git a/control.go b/control.go index 0a074592..9342aefd 100644 --- a/control.go +++ b/control.go @@ -3,21 +3,12 @@ package main import ( "bytes" "context" - "crypto" - "crypto/ecdsa" - "crypto/rsa" - "crypto/tls" - "crypto/x509" - "encoding/base64" "encoding/json" - "encoding/pem" - "errors" "fmt" "io/ioutil" "net" "net/http" "os" - "reflect" "sort" "strconv" "strings" @@ -26,7 +17,6 @@ import ( "github.com/AdguardTeam/AdGuardHome/dnsforward" "github.com/AdguardTeam/dnsproxy/upstream" "github.com/AdguardTeam/golibs/log" - "github.com/joomcode/errorx" "github.com/miekg/dns" govalidator "gopkg.in/asaskevich/govalidator.v4" ) @@ -1030,312 +1020,6 @@ func handleInstallConfigure(w http.ResponseWriter, r *http.Request) { } } -// --- -// TLS -// --- -func handleTLSStatus(w http.ResponseWriter, r *http.Request) { - log.Tracef("%s %v", r.Method, r.URL) - marshalTLS(w, config.TLS) -} - -func handleTLSValidate(w http.ResponseWriter, r *http.Request) { - log.Tracef("%s %v", r.Method, r.URL) - data, err := unmarshalTLS(r) - if err != nil { - httpError(w, http.StatusBadRequest, "Failed to unmarshal TLS config: %s", err) - return - } - - // check if port is available - // BUT: if we are already using this port, no need - alreadyRunning := false - if httpsServer.server != nil { - alreadyRunning = true - } - 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) - return - } - } - - data.tlsConfigStatus = validateCertificates(data.CertificateChain, data.PrivateKey, data.ServerName) - marshalTLS(w, data) -} - -func handleTLSConfigure(w http.ResponseWriter, r *http.Request) { - log.Tracef("%s %v", r.Method, r.URL) - data, err := unmarshalTLS(r) - if err != nil { - httpError(w, http.StatusBadRequest, "Failed to unmarshal TLS config: %s", err) - return - } - - // check if port is available - // BUT: if we are already using this port, no need - alreadyRunning := false - if httpsServer.server != nil { - alreadyRunning = true - } - 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) - return - } - } - - restartHTTPS := false - data.tlsConfigStatus = validateCertificates(data.CertificateChain, data.PrivateKey, data.ServerName) - if !reflect.DeepEqual(config.TLS.tlsConfigSettings, data.tlsConfigSettings) { - log.Printf("tls config settings have changed, will restart HTTPS server") - restartHTTPS = true - } - config.TLS = data - err = writeAllConfigsAndReloadDNS() - if err != nil { - httpError(w, http.StatusInternalServerError, "Couldn't write config file: %s", err) - return - } - marshalTLS(w, data) - // this needs to be done in a goroutine because Shutdown() is a blocking call, and it will block - // until all requests are finished, and _we_ are inside a request right now, so it will block indefinitely - if restartHTTPS { - go func() { - time.Sleep(time.Second) // TODO: could not find a way to reliably know that data was fully sent to client by https server, so we wait a bit to let response through before closing the server - httpsServer.cond.L.Lock() - httpsServer.cond.Broadcast() - if httpsServer.server != nil { - httpsServer.server.Shutdown(context.TODO()) - } - httpsServer.cond.L.Unlock() - }() - } -} - -func verifyCertChain(data *tlsConfigStatus, certChain string, serverName string) error { - log.Tracef("got certificate: %s", certChain) - - // now do a more extended validation - var certs []*pem.Block // PEM-encoded certificates - var skippedBytes []string // skipped bytes - - pemblock := []byte(certChain) - for { - var decoded *pem.Block - decoded, pemblock = pem.Decode(pemblock) - if decoded == nil { - break - } - if decoded.Type == "CERTIFICATE" { - certs = append(certs, decoded) - } else { - skippedBytes = append(skippedBytes, decoded.Type) - } - } - - var parsedCerts []*x509.Certificate - - for _, cert := range certs { - parsed, err := x509.ParseCertificate(cert.Bytes) - if err != nil { - data.WarningValidation = fmt.Sprintf("Failed to parse certificate: %s", err) - return errors.New("") - } - parsedCerts = append(parsedCerts, parsed) - } - - if len(parsedCerts) == 0 { - data.WarningValidation = fmt.Sprintf("You have specified an empty certificate") - return errors.New("") - } - - data.ValidCert = true - - // spew.Dump(parsedCerts) - - opts := x509.VerifyOptions{ - DNSName: serverName, - } - - log.Printf("number of certs - %d", len(parsedCerts)) - if len(parsedCerts) > 1 { - // set up an intermediate - pool := x509.NewCertPool() - for _, cert := range parsedCerts[1:] { - log.Printf("got an intermediate cert") - pool.AddCert(cert) - } - opts.Intermediates = pool - } - - // TODO: save it as a warning rather than error it out -- shouldn't be a big problem - mainCert := parsedCerts[0] - _, err := mainCert.Verify(opts) - if err != nil { - // let self-signed certs through - data.WarningValidation = fmt.Sprintf("Your certificate does not verify: %s", err) - } else { - data.ValidChain = true - } - // spew.Dump(chains) - - // update status - if mainCert != nil { - notAfter := mainCert.NotAfter - data.Subject = mainCert.Subject.String() - data.Issuer = mainCert.Issuer.String() - data.NotAfter = notAfter - data.NotBefore = mainCert.NotBefore - data.DNSNames = mainCert.DNSNames - } - - return nil -} - -func validatePkey(data *tlsConfigStatus, pkey string) error { - // now do a more extended validation - var key *pem.Block // PEM-encoded certificates - var skippedBytes []string // skipped bytes - - // go through all pem blocks, but take first valid pem block and drop the rest - pemblock := []byte(pkey) - for { - var decoded *pem.Block - decoded, pemblock = pem.Decode(pemblock) - if decoded == nil { - break - } - if decoded.Type == "PRIVATE KEY" || strings.HasSuffix(decoded.Type, " PRIVATE KEY") { - key = decoded - break - } else { - skippedBytes = append(skippedBytes, decoded.Type) - } - } - - if key == nil { - data.WarningValidation = "No valid keys were found" - return errors.New("") - } - - // parse the decoded key - _, keytype, err := parsePrivateKey(key.Bytes) - if err != nil { - data.WarningValidation = fmt.Sprintf("Failed to parse private key: %s", err) - return errors.New("") - } - - data.ValidKey = true - data.KeyType = keytype - return nil -} - -/* Process certificate data and its private key. -All parameters are optional. -On error, return partially set object - with 'WarningValidation' field containing error description. -*/ -func validateCertificates(certChain, pkey, serverName string) tlsConfigStatus { - var data tlsConfigStatus - - // check only public certificate separately from the key - if certChain != "" { - if verifyCertChain(&data, certChain, serverName) != nil { - return data - } - } - - // validate private key (right now the only validation possible is just parsing it) - if pkey != "" { - if validatePkey(&data, pkey) != nil { - return data - } - } - - // if both are set, validate both in unison - if pkey != "" && certChain != "" { - _, err := tls.X509KeyPair([]byte(certChain), []byte(pkey)) - if err != nil { - data.WarningValidation = fmt.Sprintf("Invalid certificate or key: %s", err) - return data - } - data.ValidPair = true - } - - return data -} - -// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates -// PKCS#1 private keys by default, while OpenSSL 1.0.0 generates PKCS#8 keys. -// OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three. -func parsePrivateKey(der []byte) (crypto.PrivateKey, string, error) { - if key, err := x509.ParsePKCS1PrivateKey(der); err == nil { - return key, "RSA", nil - } - if key, err := x509.ParsePKCS8PrivateKey(der); err == nil { - switch key := key.(type) { - case *rsa.PrivateKey: - return key, "RSA", nil - case *ecdsa.PrivateKey: - return key, "ECDSA", nil - default: - return nil, "", errors.New("tls: found unknown private key type in PKCS#8 wrapping") - } - } - if key, err := x509.ParseECPrivateKey(der); err == nil { - return key, "ECDSA", nil - } - - return nil, "", errors.New("tls: failed to parse private key") -} - -// unmarshalTLS handles base64-encoded certificates transparently -func unmarshalTLS(r *http.Request) (tlsConfig, error) { - data := tlsConfig{} - err := json.NewDecoder(r.Body).Decode(&data) - if err != nil { - return data, errorx.Decorate(err, "Failed to parse new TLS config json") - } - - if data.CertificateChain != "" { - certPEM, err := base64.StdEncoding.DecodeString(data.CertificateChain) - if err != nil { - return data, errorx.Decorate(err, "Failed to base64-decode certificate chain") - } - data.CertificateChain = string(certPEM) - } - - if data.PrivateKey != "" { - keyPEM, err := base64.StdEncoding.DecodeString(data.PrivateKey) - if err != nil { - return data, errorx.Decorate(err, "Failed to base64-decode private key") - } - - data.PrivateKey = string(keyPEM) - } - - return data, nil -} - -func marshalTLS(w http.ResponseWriter, data tlsConfig) { - w.Header().Set("Content-Type", "application/json") - if data.CertificateChain != "" { - encoded := base64.StdEncoding.EncodeToString([]byte(data.CertificateChain)) - data.CertificateChain = encoded - } - if data.PrivateKey != "" { - encoded := base64.StdEncoding.EncodeToString([]byte(data.PrivateKey)) - data.PrivateKey = encoded - } - err := json.NewEncoder(w).Encode(data) - if err != nil { - httpError(w, http.StatusInternalServerError, "Failed to marshal json with TLS status: %s", err) - return - } -} - // -------------- // DNS-over-HTTPS // -------------- @@ -1401,9 +1085,7 @@ func registerControlHandlers() { http.HandleFunc("/control/dhcp/set_config", postInstall(optionalAuth(ensurePOST(handleDHCPSetConfig)))) http.HandleFunc("/control/dhcp/find_active_dhcp", postInstall(optionalAuth(ensurePOST(handleDHCPFindActiveServer)))) - http.HandleFunc("/control/tls/status", postInstall(optionalAuth(ensureGET(handleTLSStatus)))) - http.HandleFunc("/control/tls/configure", postInstall(optionalAuth(ensurePOST(handleTLSConfigure)))) - http.HandleFunc("/control/tls/validate", postInstall(optionalAuth(ensurePOST(handleTLSValidate)))) + RegisterTLSHandlers() http.HandleFunc("/dns-query", postInstall(handleDOH)) } diff --git a/control_tls.go b/control_tls.go new file mode 100644 index 00000000..d444fe07 --- /dev/null +++ b/control_tls.go @@ -0,0 +1,338 @@ +// Control: TLS configuring handlers + +package main + +import ( + "context" + "crypto" + "crypto/ecdsa" + "crypto/rsa" + "crypto/tls" + "crypto/x509" + "encoding/base64" + "encoding/json" + "encoding/pem" + "errors" + "fmt" + "net/http" + "reflect" + "strings" + "time" + + "github.com/AdguardTeam/golibs/log" + "github.com/joomcode/errorx" +) + +// RegisterTLSHandlers registers HTTP handlers for TLS configuration +func RegisterTLSHandlers() { + http.HandleFunc("/control/tls/status", postInstall(optionalAuth(ensureGET(handleTLSStatus)))) + http.HandleFunc("/control/tls/configure", postInstall(optionalAuth(ensurePOST(handleTLSConfigure)))) + http.HandleFunc("/control/tls/validate", postInstall(optionalAuth(ensurePOST(handleTLSValidate)))) +} + +func handleTLSStatus(w http.ResponseWriter, r *http.Request) { + log.Tracef("%s %v", r.Method, r.URL) + marshalTLS(w, config.TLS) +} + +func handleTLSValidate(w http.ResponseWriter, r *http.Request) { + log.Tracef("%s %v", r.Method, r.URL) + data, err := unmarshalTLS(r) + if err != nil { + httpError(w, http.StatusBadRequest, "Failed to unmarshal TLS config: %s", err) + return + } + + // check if port is available + // BUT: if we are already using this port, no need + alreadyRunning := false + if httpsServer.server != nil { + alreadyRunning = true + } + 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) + return + } + } + + data.tlsConfigStatus = validateCertificates(data.CertificateChain, data.PrivateKey, data.ServerName) + marshalTLS(w, data) +} + +func handleTLSConfigure(w http.ResponseWriter, r *http.Request) { + log.Tracef("%s %v", r.Method, r.URL) + data, err := unmarshalTLS(r) + if err != nil { + httpError(w, http.StatusBadRequest, "Failed to unmarshal TLS config: %s", err) + return + } + + // check if port is available + // BUT: if we are already using this port, no need + alreadyRunning := false + if httpsServer.server != nil { + alreadyRunning = true + } + 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) + return + } + } + + restartHTTPS := false + data.tlsConfigStatus = validateCertificates(data.CertificateChain, data.PrivateKey, data.ServerName) + if !reflect.DeepEqual(config.TLS.tlsConfigSettings, data.tlsConfigSettings) { + log.Printf("tls config settings have changed, will restart HTTPS server") + restartHTTPS = true + } + config.TLS = data + err = writeAllConfigsAndReloadDNS() + if err != nil { + httpError(w, http.StatusInternalServerError, "Couldn't write config file: %s", err) + return + } + marshalTLS(w, data) + // this needs to be done in a goroutine because Shutdown() is a blocking call, and it will block + // until all requests are finished, and _we_ are inside a request right now, so it will block indefinitely + if restartHTTPS { + go func() { + time.Sleep(time.Second) // TODO: could not find a way to reliably know that data was fully sent to client by https server, so we wait a bit to let response through before closing the server + httpsServer.cond.L.Lock() + httpsServer.cond.Broadcast() + if httpsServer.server != nil { + httpsServer.server.Shutdown(context.TODO()) + } + httpsServer.cond.L.Unlock() + }() + } +} + +func verifyCertChain(data *tlsConfigStatus, certChain string, serverName string) error { + log.Tracef("got certificate: %s", certChain) + + // now do a more extended validation + var certs []*pem.Block // PEM-encoded certificates + var skippedBytes []string // skipped bytes + + pemblock := []byte(certChain) + for { + var decoded *pem.Block + decoded, pemblock = pem.Decode(pemblock) + if decoded == nil { + break + } + if decoded.Type == "CERTIFICATE" { + certs = append(certs, decoded) + } else { + skippedBytes = append(skippedBytes, decoded.Type) + } + } + + var parsedCerts []*x509.Certificate + + for _, cert := range certs { + parsed, err := x509.ParseCertificate(cert.Bytes) + if err != nil { + data.WarningValidation = fmt.Sprintf("Failed to parse certificate: %s", err) + return errors.New("") + } + parsedCerts = append(parsedCerts, parsed) + } + + if len(parsedCerts) == 0 { + data.WarningValidation = fmt.Sprintf("You have specified an empty certificate") + return errors.New("") + } + + data.ValidCert = true + + // spew.Dump(parsedCerts) + + opts := x509.VerifyOptions{ + DNSName: serverName, + } + + log.Printf("number of certs - %d", len(parsedCerts)) + if len(parsedCerts) > 1 { + // set up an intermediate + pool := x509.NewCertPool() + for _, cert := range parsedCerts[1:] { + log.Printf("got an intermediate cert") + pool.AddCert(cert) + } + opts.Intermediates = pool + } + + // TODO: save it as a warning rather than error it out -- shouldn't be a big problem + mainCert := parsedCerts[0] + _, err := mainCert.Verify(opts) + if err != nil { + // let self-signed certs through + data.WarningValidation = fmt.Sprintf("Your certificate does not verify: %s", err) + } else { + data.ValidChain = true + } + // spew.Dump(chains) + + // update status + if mainCert != nil { + notAfter := mainCert.NotAfter + data.Subject = mainCert.Subject.String() + data.Issuer = mainCert.Issuer.String() + data.NotAfter = notAfter + data.NotBefore = mainCert.NotBefore + data.DNSNames = mainCert.DNSNames + } + + return nil +} + +func validatePkey(data *tlsConfigStatus, pkey string) error { + // now do a more extended validation + var key *pem.Block // PEM-encoded certificates + var skippedBytes []string // skipped bytes + + // go through all pem blocks, but take first valid pem block and drop the rest + pemblock := []byte(pkey) + for { + var decoded *pem.Block + decoded, pemblock = pem.Decode(pemblock) + if decoded == nil { + break + } + if decoded.Type == "PRIVATE KEY" || strings.HasSuffix(decoded.Type, " PRIVATE KEY") { + key = decoded + break + } else { + skippedBytes = append(skippedBytes, decoded.Type) + } + } + + if key == nil { + data.WarningValidation = "No valid keys were found" + return errors.New("") + } + + // parse the decoded key + _, keytype, err := parsePrivateKey(key.Bytes) + if err != nil { + data.WarningValidation = fmt.Sprintf("Failed to parse private key: %s", err) + return errors.New("") + } + + data.ValidKey = true + data.KeyType = keytype + return nil +} + +/* Process certificate data and its private key. +All parameters are optional. +On error, return partially set object + with 'WarningValidation' field containing error description. */ +func validateCertificates(certChain, pkey, serverName string) tlsConfigStatus { + var data tlsConfigStatus + + // check only public certificate separately from the key + if certChain != "" { + if verifyCertChain(&data, certChain, serverName) != nil { + return data + } + } + + // validate private key (right now the only validation possible is just parsing it) + if pkey != "" { + if validatePkey(&data, pkey) != nil { + return data + } + } + + // if both are set, validate both in unison + if pkey != "" && certChain != "" { + _, err := tls.X509KeyPair([]byte(certChain), []byte(pkey)) + if err != nil { + data.WarningValidation = fmt.Sprintf("Invalid certificate or key: %s", err) + return data + } + data.ValidPair = true + } + + return data +} + +// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates +// PKCS#1 private keys by default, while OpenSSL 1.0.0 generates PKCS#8 keys. +// OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three. +func parsePrivateKey(der []byte) (crypto.PrivateKey, string, error) { + if key, err := x509.ParsePKCS1PrivateKey(der); err == nil { + return key, "RSA", nil + } + + if key, err := x509.ParsePKCS8PrivateKey(der); err == nil { + switch key := key.(type) { + case *rsa.PrivateKey: + return key, "RSA", nil + case *ecdsa.PrivateKey: + return key, "ECDSA", nil + default: + return nil, "", errors.New("tls: found unknown private key type in PKCS#8 wrapping") + } + } + + if key, err := x509.ParseECPrivateKey(der); err == nil { + return key, "ECDSA", nil + } + + return nil, "", errors.New("tls: failed to parse private key") +} + +// unmarshalTLS handles base64-encoded certificates transparently +func unmarshalTLS(r *http.Request) (tlsConfig, error) { + data := tlsConfig{} + err := json.NewDecoder(r.Body).Decode(&data) + if err != nil { + return data, errorx.Decorate(err, "Failed to parse new TLS config json") + } + + if data.CertificateChain != "" { + certPEM, err := base64.StdEncoding.DecodeString(data.CertificateChain) + if err != nil { + return data, errorx.Decorate(err, "Failed to base64-decode certificate chain") + } + data.CertificateChain = string(certPEM) + } + + if data.PrivateKey != "" { + keyPEM, err := base64.StdEncoding.DecodeString(data.PrivateKey) + if err != nil { + return data, errorx.Decorate(err, "Failed to base64-decode private key") + } + + data.PrivateKey = string(keyPEM) + } + + return data, nil +} + +func marshalTLS(w http.ResponseWriter, data tlsConfig) { + w.Header().Set("Content-Type", "application/json") + + if data.CertificateChain != "" { + encoded := base64.StdEncoding.EncodeToString([]byte(data.CertificateChain)) + data.CertificateChain = encoded + } + + if data.PrivateKey != "" { + encoded := base64.StdEncoding.EncodeToString([]byte(data.PrivateKey)) + data.PrivateKey = encoded + } + + err := json.NewEncoder(w).Encode(data) + if err != nil { + httpError(w, http.StatusInternalServerError, "Failed to marshal json with TLS status: %s", err) + return + } +} From 6b2baba3c76b756337872bb38fb802e30fbc1d89 Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Thu, 28 Feb 2019 11:10:43 +0300 Subject: [PATCH 27/95] Add set_upstreams_config function --- control.go | 5 +++++ openapi/openapi.yaml | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/control.go b/control.go index d27a7cfc..d57114ce 100644 --- a/control.go +++ b/control.go @@ -306,6 +306,10 @@ func sortByValue(m map[string]int) []string { // upstreams configuration // ----------------------- +func handleSetUpstreamConfig(w http.ResponseWriter, r *http.Request) { + log.Tracef("%s %v", r.Method, r.URL) +} + func handleSetUpstreamDNS(w http.ResponseWriter, r *http.Request) { log.Tracef("%s %v", r.Method, r.URL) body, err := ioutil.ReadAll(r.Body) @@ -1293,6 +1297,7 @@ func registerControlHandlers() { http.HandleFunc("/control/querylog_enable", postInstall(optionalAuth(ensurePOST(handleQueryLogEnable)))) http.HandleFunc("/control/querylog_disable", postInstall(optionalAuth(ensurePOST(handleQueryLogDisable)))) http.HandleFunc("/control/set_upstream_dns", postInstall(optionalAuth(ensurePOST(handleSetUpstreamDNS)))) + http.HandleFunc("/control/set_upstreams_config", postInstall(optionalAuth(ensurePOST(handleSetUpstreamConfig)))) http.HandleFunc("/control/test_upstream_dns", postInstall(optionalAuth(ensurePOST(handleTestUpstreamDNS)))) http.HandleFunc("/control/all_servers/enable", postInstall(optionalAuth(ensurePOST(handleAllServersEnable)))) http.HandleFunc("/control/all_servers/disable", postInstall(optionalAuth(ensurePOST(handleAllServersDisable)))) diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index e83d6360..f0fb68ee 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -87,6 +87,25 @@ paths: 200: description: OK + /set_upstreams_config: + post: + tags: + - global + operationId: setUpstreamsConfig + summary: "Updates the current upstreams configuration" + consumes: + - application/json + parameters: + - in: "body" + name: "body" + description: "Upstreams configuration JSON" + required: true + schema: + $ref: "#/definitions/UpstreamsConfig" + responses: + 200: + description: OK + /set_upstream_dns: post: tags: @@ -831,6 +850,25 @@ definitions: language: type: "string" example: "en" + UpstreamsConfig: + type: "object" + description: "Upstreams configuration" + required: + - "bootstrap_dns" + - "upstream_dns" + properties: + bootstrap_dns: + type: "string" + example: "8.8.8.8:53" + upstream_dns: + type: "array" + items: + type: "string" + example: + - "tls://1.1.1.1" + - "tls://1.0.0.1" + all_servers: + type: "boolean" Filter: type: "object" description: "Filter subscription info" From 224c2a891dbb83332a1d582bab32a94dc3201215 Mon Sep 17 00:00:00 2001 From: Simon Zolin Date: Thu, 28 Feb 2019 11:55:16 +0300 Subject: [PATCH 28/95] * control: TLS: don't return empty error messages --- control_tls.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/control_tls.go b/control_tls.go index d444fe07..25be44d6 100644 --- a/control_tls.go +++ b/control_tls.go @@ -138,14 +138,14 @@ func verifyCertChain(data *tlsConfigStatus, certChain string, serverName string) parsed, err := x509.ParseCertificate(cert.Bytes) if err != nil { data.WarningValidation = fmt.Sprintf("Failed to parse certificate: %s", err) - return errors.New("") + return errors.New(data.WarningValidation) } parsedCerts = append(parsedCerts, parsed) } if len(parsedCerts) == 0 { data.WarningValidation = fmt.Sprintf("You have specified an empty certificate") - return errors.New("") + return errors.New(data.WarningValidation) } data.ValidCert = true @@ -214,14 +214,14 @@ func validatePkey(data *tlsConfigStatus, pkey string) error { if key == nil { data.WarningValidation = "No valid keys were found" - return errors.New("") + return errors.New(data.WarningValidation) } // parse the decoded key _, keytype, err := parsePrivateKey(key.Bytes) if err != nil { data.WarningValidation = fmt.Sprintf("Failed to parse private key: %s", err) - return errors.New("") + return errors.New(data.WarningValidation) } data.ValidKey = true From 3929f0da449ce0a8368416ebd46a1f83617fdcbd Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Thu, 28 Feb 2019 13:01:41 +0300 Subject: [PATCH 29/95] [change] control: Handle upstream config with JSON --- control.go | 89 ++++++++---------------------------- dnsfilter/dnsfilter.go | 2 +- dnsforward/querylog_top.go | 2 +- openapi/openapi.yaml | 93 ++++---------------------------------- 4 files changed, 31 insertions(+), 155 deletions(-) diff --git a/control.go b/control.go index 81befc50..5b1dcf3c 100644 --- a/control.go +++ b/control.go @@ -306,35 +306,35 @@ func sortByValue(m map[string]int) []string { // upstreams configuration // ----------------------- +// TODO this struct will become unnecessary after config file rework +type upstreamConfig struct { + upstreams []string // Upstreams + bootstrapDNS []string // Bootstrap DNS + allServers bool // --all-servers param for dnsproxy +} + func handleSetUpstreamConfig(w http.ResponseWriter, r *http.Request) { log.Tracef("%s %v", r.Method, r.URL) -} + newconfig := upstreamConfig{} + err := json.NewDecoder(r.Body).Decode(&newconfig) + if err != nil { + httpError(w, http.StatusBadRequest, "Failed to parse new upstreams config json: %s", err) + return + } -func handleSetUpstreamDNS(w http.ResponseWriter, r *http.Request) { - log.Tracef("%s %v", r.Method, r.URL) - setDNSServers(w, r, true) -} - -func handleSetBootstrapDNS(w http.ResponseWriter, r *http.Request) { - log.Tracef("%s %v", r.Method, r.URL) - setDNSServers(w, r, false) + setDNSServers(newconfig.upstreams, true) + setDNSServers(newconfig.bootstrapDNS, false) + config.DNS.AllServers = newconfig.allServers + httpUpdateConfigReloadDNSReturnOK(w, r) } // 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 { - httpError(w, http.StatusBadRequest, "Failed to read request body: %s", err) - return - } - // if empty body -- user is asking for default servers - hosts := strings.Fields(string(body)) - +func setDNSServers(hosts []string, upstreams bool) { // 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) + err := checkBootstrapDNS(host) if err != nil { log.Tracef("%s can not be used as bootstrap DNS cause: %s", host, err) continue @@ -360,52 +360,6 @@ func setDNSServers(w http.ResponseWriter, r *http.Request, upstreams bool) { config.DNS.BootstrapDNS = bootstraps } } - - err = writeAllConfigs() - if err != nil { - httpError(w, http.StatusInternalServerError, "Couldn't write config file: %s", err) - return - } - err = reconfigureDNSServer() - if err != nil { - 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 { - httpError(w, http.StatusInternalServerError, "Couldn't write body: %s", err) - } -} - -func handleAllServersEnable(w http.ResponseWriter, r *http.Request) { - log.Tracef("%s %v", r.Method, r.URL) - config.DNS.AllServers = true - httpUpdateConfigReloadDNSReturnOK(w, r) -} - -func handleAllServersDisable(w http.ResponseWriter, r *http.Request) { - log.Tracef("%s %v", r.Method, r.URL) - config.DNS.AllServers = false - httpUpdateConfigReloadDNSReturnOK(w, r) -} - -func handleAllServersStatus(w http.ResponseWriter, r *http.Request) { - log.Tracef("%s %v", r.Method, r.URL) - data := map[string]interface{}{ - "enabled": config.DNS.AllServers, - } - jsonVal, err := json.Marshal(data) - if err != nil { - httpError(w, http.StatusInternalServerError, "Unable to marshal status json: %s", err) - return - } - - w.Header().Set("Content-Type", "application/json") - _, err = w.Write(jsonVal) - if err != nil { - httpError(w, http.StatusInternalServerError, "Unable to write response json: %s", err) - return - } } // checkBootstrapDNS checks if host is plain DNS @@ -1343,13 +1297,8 @@ func registerControlHandlers() { http.HandleFunc("/control/querylog", postInstall(optionalAuth(ensureGET(handleQueryLog)))) http.HandleFunc("/control/querylog_enable", postInstall(optionalAuth(ensurePOST(handleQueryLogEnable)))) http.HandleFunc("/control/querylog_disable", postInstall(optionalAuth(ensurePOST(handleQueryLogDisable)))) - http.HandleFunc("/control/set_upstream_dns", postInstall(optionalAuth(ensurePOST(handleSetUpstreamDNS)))) http.HandleFunc("/control/set_upstreams_config", postInstall(optionalAuth(ensurePOST(handleSetUpstreamConfig)))) http.HandleFunc("/control/test_upstream_dns", postInstall(optionalAuth(ensurePOST(handleTestUpstreamDNS)))) - http.HandleFunc("/control/set_bootstrap_dns", postInstall(optionalAuth(ensurePOST(handleSetBootstrapDNS)))) - http.HandleFunc("/control/all_servers/enable", postInstall(optionalAuth(ensurePOST(handleAllServersEnable)))) - http.HandleFunc("/control/all_servers/disable", postInstall(optionalAuth(ensurePOST(handleAllServersDisable)))) - http.HandleFunc("/control/all_servers/status", postInstall(optionalAuth(ensureGET(handleAllServersStatus)))) 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/dnsfilter/dnsfilter.go b/dnsfilter/dnsfilter.go index 561ccb04..b33465f9 100644 --- a/dnsfilter/dnsfilter.go +++ b/dnsfilter/dnsfilter.go @@ -16,8 +16,8 @@ import ( "sync/atomic" "time" - "github.com/bluele/gcache" "github.com/AdguardTeam/golibs/log" + "github.com/bluele/gcache" "golang.org/x/net/publicsuffix" ) diff --git a/dnsforward/querylog_top.go b/dnsforward/querylog_top.go index a2ffffdc..b381984c 100644 --- a/dnsforward/querylog_top.go +++ b/dnsforward/querylog_top.go @@ -9,8 +9,8 @@ import ( "sync" "time" - "github.com/bluele/gcache" "github.com/AdguardTeam/golibs/log" + "github.com/bluele/gcache" "github.com/miekg/dns" ) diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index ed788794..6d0aafb4 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -106,63 +106,6 @@ paths: 200: description: OK - /set_upstream_dns: - post: - tags: - - global - operationId: setUpstreamDNS - summary: 'Set upstream DNS for coredns, empty value will reset it to default values' - consumes: - - text/plain - parameters: - - in: body - name: upstream - description: 'Upstream 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 - - /all_servers/enable: - post: - tags: - - global - operationId: allServersEnable - summary: 'Enable parallel queries' - responses: - 200: - description: OK - - /all_servers/disable: - post: - tags: - - global - operationId: allServersDisable - summary: 'Disable parallel queries' - responses: - 200: - description: OK - - /all_servers/status: - get: - tags: - - global - operationId: allServersStatus - summary: 'Get parallel queries status' - responses: - 200: - description: OK - examples: - application/json: - enabled: false - /test_upstream_dns: post: tags: @@ -194,30 +137,6 @@ 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: @@ -880,12 +799,19 @@ definitions: required: - "bootstrap_dns" - "upstream_dns" + - "all_servers" properties: bootstrap_dns: - type: "string" - example: "8.8.8.8:53" + type: "array" + description: 'Bootstrap servers, port is optional after colon. Empty value will reset it to default values' + items: + type: "string" + example: + - "8.8.8.8:53" + - "1.1.1.1:53" upstream_dns: type: "array" + description: 'Upstream servers, port is optional after colon. Empty value will reset it to default values' items: type: "string" example: @@ -893,6 +819,7 @@ definitions: - "tls://1.0.0.1" all_servers: type: "boolean" + description: "If true, parallel queries to all configured upstream servers are enabled" Filter: type: "object" description: "Filter subscription info" From acb4a984664b95d280522792be56bec2146da430 Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Thu, 28 Feb 2019 13:40:40 +0300 Subject: [PATCH 30/95] [change] dnsforward: Add comments for public fields --- dnsforward/dnsforward.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dnsforward/dnsforward.go b/dnsforward/dnsforward.go index 4f910bc8..7b8430ed 100644 --- a/dnsforward/dnsforward.go +++ b/dnsforward/dnsforward.go @@ -62,12 +62,12 @@ type FilteringConfig struct { ProtectionEnabled bool `yaml:"protection_enabled"` // whether or not use any of dnsfilter features FilteringEnabled bool `yaml:"filtering_enabled"` // whether or not use filter lists BlockedResponseTTL uint32 `yaml:"blocked_response_ttl"` // if 0, then default is used (3600) - QueryLogEnabled bool `yaml:"querylog_enabled"` - Ratelimit int `yaml:"ratelimit"` - RatelimitWhitelist []string `yaml:"ratelimit_whitelist"` - RefuseAny bool `yaml:"refuse_any"` - BootstrapDNS []string `yaml:"bootstrap_dns"` - AllServers bool `yaml:"all_servers"` + QueryLogEnabled bool `yaml:"querylog_enabled"` // if true, query log is enabled + Ratelimit int `yaml:"ratelimit"` // max number of requests per second from a given IP (0 to disable) + RatelimitWhitelist []string `yaml:"ratelimit_whitelist"` // a list of whitelisted client IP addresses + RefuseAny bool `yaml:"refuse_any"` // if true, refuse ANY requests + BootstrapDNS []string `yaml:"bootstrap_dns"` // a list of bootstrap DNS for DoH and DoT (plain DNS only) + AllServers bool `yaml:"all_servers"` // if true, parallel queries to all configured upstream servers are enabled dnsfilter.Config `yaml:",inline"` } From b8595b87c4c8705eddc8eed711b4760da9e894fa Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Thu, 28 Feb 2019 14:59:25 +0300 Subject: [PATCH 31/95] * disable config saving if invalid pair --- .../components/Settings/Encryption/Form.js | 21 +++++++++++-------- client/src/reducers/encryption.js | 1 + 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/client/src/components/Settings/Encryption/Form.js b/client/src/components/Settings/Encryption/Form.js index f4b01560..fd43f933 100644 --- a/client/src/components/Settings/Encryption/Form.js +++ b/client/src/components/Settings/Encryption/Form.js @@ -57,6 +57,7 @@ let Form = (props) => { valid_chain, valid_key, valid_cert, + valid_pair, dns_names, key_type, issuer, @@ -65,6 +66,15 @@ let Form = (props) => { setTlsConfig, } = props; + const isSavingDisabled = invalid + || submitting + || processingConfig + || processingValidate + || (isEnabled && (!privateKey || !certificateChain)) + || (privateKey && !valid_key) + || (certificateChain && !valid_cert) + || (privateKey && certificateChain && !valid_pair); + return (
@@ -291,15 +301,7 @@ let Form = (props) => { @@ -334,6 +336,7 @@ Form.propTypes = { valid_chain: PropTypes.bool, valid_key: PropTypes.bool, valid_cert: PropTypes.bool, + valid_pair: PropTypes.bool, dns_names: PropTypes.string, key_type: PropTypes.string, issuer: PropTypes.string, diff --git a/client/src/reducers/encryption.js b/client/src/reducers/encryption.js index 3f51b217..f861701b 100644 --- a/client/src/reducers/encryption.js +++ b/client/src/reducers/encryption.js @@ -70,6 +70,7 @@ const encryption = handleActions({ valid_chain: false, valid_key: false, valid_cert: false, + valid_pair: false, status_cert: '', status_key: '', certificate_chain: '', From a8812908c1062e4dcfe6e30e9cf9612e41967aa1 Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Thu, 28 Feb 2019 15:06:30 +0300 Subject: [PATCH 32/95] [change] control: Fix issues from review --- control.go | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/control.go b/control.go index 5b1dcf3c..85775c1d 100644 --- a/control.go +++ b/control.go @@ -322,44 +322,31 @@ func handleSetUpstreamConfig(w http.ResponseWriter, r *http.Request) { return } - setDNSServers(newconfig.upstreams, true) - setDNSServers(newconfig.bootstrapDNS, false) - config.DNS.AllServers = newconfig.allServers - httpUpdateConfigReloadDNSReturnOK(w, r) -} + config.DNS.UpstreamDNS = defaultDNS + if len(newconfig.upstreams) > 0 { + config.DNS.UpstreamDNS = newconfig.upstreams + } -// setDNSServers sets upstream and bootstrap DNS servers -func setDNSServers(hosts []string, upstreams bool) { // 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 { + if len(newconfig.bootstrapDNS) > 0 { + for _, host := range newconfig.bootstrapDNS { 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) + bootstraps = append(bootstraps, host) } } - // count of upstream or bootstrap servers - count := len(hosts) - if !upstreams { - count = len(bootstraps) + config.DNS.BootstrapDNS = defaultBootstrap + if len(bootstraps) > 0 { + config.DNS.BootstrapDNS = bootstraps } - if upstreams { - config.DNS.UpstreamDNS = defaultDNS - if count != 0 { - config.DNS.UpstreamDNS = hosts - } - } else { - config.DNS.BootstrapDNS = defaultBootstrap - if count != 0 { - config.DNS.BootstrapDNS = bootstraps - } - } + config.DNS.AllServers = newconfig.allServers + httpUpdateConfigReloadDNSReturnOK(w, r) } // checkBootstrapDNS checks if host is plain DNS From 91f8ab0549f07815a0d72301d9b60bc903338ba3 Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Thu, 28 Feb 2019 15:18:51 +0300 Subject: [PATCH 33/95] [change] control: Remove unuseful check --- control.go | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/control.go b/control.go index 85775c1d..7b17321b 100644 --- a/control.go +++ b/control.go @@ -329,15 +329,13 @@ func handleSetUpstreamConfig(w http.ResponseWriter, r *http.Request) { // bootstrap servers are plain DNS only. We should remove tls:// https:// and sdns:// hosts from slice bootstraps := []string{} - if len(newconfig.bootstrapDNS) > 0 { - for _, host := range newconfig.bootstrapDNS { - err := checkBootstrapDNS(host) - if err != nil { - log.Tracef("%s can not be used as bootstrap DNS cause: %s", host, err) - continue - } - bootstraps = append(bootstraps, host) + for _, host := range newconfig.bootstrapDNS { + err := checkBootstrapDNS(host) + if err != nil { + log.Tracef("%s can not be used as bootstrap DNS cause: %s", host, err) + continue } + bootstraps = append(bootstraps, host) } config.DNS.BootstrapDNS = defaultBootstrap From 6b7a8078b0155ba81678e71fe53f447f444dce8b Mon Sep 17 00:00:00 2001 From: Simon Zolin Date: Thu, 28 Feb 2019 15:28:38 +0300 Subject: [PATCH 34/95] * control: use single line comment --- control_tls.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/control_tls.go b/control_tls.go index 25be44d6..0546c5f1 100644 --- a/control_tls.go +++ b/control_tls.go @@ -229,10 +229,10 @@ func validatePkey(data *tlsConfigStatus, pkey string) error { return nil } -/* Process certificate data and its private key. -All parameters are optional. -On error, return partially set object - with 'WarningValidation' field containing error description. */ +// Process certificate data and its private key. +// All parameters are optional. +// On error, return partially set object +// with 'WarningValidation' field containing error description. func validateCertificates(certChain, pkey, serverName string) tlsConfigStatus { var data tlsConfigStatus From 53d680a5dfb027831bdbfc91bde5272d4d849a1a Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Thu, 28 Feb 2019 16:19:23 +0300 Subject: [PATCH 35/95] Fix #597 - [bugfix] querylog_top: Empty domain gets to the Top Queried domains --- dnsforward/querylog_top.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dnsforward/querylog_top.go b/dnsforward/querylog_top.go index a2ffffdc..43d16699 100644 --- a/dnsforward/querylog_top.go +++ b/dnsforward/querylog_top.go @@ -9,8 +9,8 @@ import ( "sync" "time" - "github.com/bluele/gcache" "github.com/AdguardTeam/golibs/log" + "github.com/bluele/gcache" "github.com/miekg/dns" ) @@ -158,6 +158,11 @@ func (d *dayTop) addEntry(entry *logEntry, q *dns.Msg, now time.Time) error { hostname := strings.ToLower(strings.TrimSuffix(q.Question[0].Name, ".")) + // if question hostname is empty, do nothing + if hostname == "" { + return nil + } + // get value, if not set, crate one d.hoursReadLock() defer d.hoursReadUnlock() From d3185459138e4fd0cb8ae21869d6c2fe9d73c5f3 Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Thu, 28 Feb 2019 20:41:18 +0300 Subject: [PATCH 36/95] [change] upgrade_test: add test for upgrade --- upgrade_test.go | 183 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 upgrade_test.go diff --git a/upgrade_test.go b/upgrade_test.go new file mode 100644 index 00000000..e474cc1f --- /dev/null +++ b/upgrade_test.go @@ -0,0 +1,183 @@ +package main + +import ( + "fmt" + "testing" +) + +func TestUpgrade1to2(t *testing.T) { + // Let's create test config + diskConfig := createTestDiskConfig(1) + oldDNSConfig := createTestDNSConfig(1) + + err := upgradeSchema1to2(&diskConfig) + if err != nil { + t.Fatalf("Can't upgrade schema version from 1 to 2") + } + + _, ok := diskConfig["coredns"] + if ok { + t.Fatalf("Core DNS config was not removed after upgrade schema version from 1 to 2") + } + + dnsMap, ok := diskConfig["dns"] + if !ok { + t.Fatalf("No DNS config after upgrade schema version from 1 to 2") + } + + // Cast dns configuration to map + newDNSConfig := make(map[string]interface{}) + switch v := dnsMap.(type) { + case map[interface{}]interface{}: + if len(oldDNSConfig) != len(v) { + t.Fatalf("We loose some data") + } + for key, value := range v { + newDNSConfig[fmt.Sprint(key)] = value + } + default: + t.Fatalf("DNS configuration is not a map") + } + + _, v, err := compareConfigs(oldDNSConfig, newDNSConfig) + if err != nil { + t.Fatalf("Wrong data %s, %s", v, err) + } +} + +func TestUpgrade2to3(t *testing.T) { + // Let's create test config + diskConfig := createTestDiskConfig(2) + oldDNSConfig := createTestDNSConfig(2) + + // Upgrade schema from 2 to 3 + err := upgradeSchema2to3(&diskConfig) + if err != nil { + t.Fatalf("Can't update schema version from 2 to 3: %s", err) + } + + // Check new schema version + newSchemaVersion := diskConfig["schema_version"] + switch v := newSchemaVersion.(type) { + case int: + if v != 3 { + t.Fatalf("Wrong schema version in new config file") + } + default: + t.Fatalf("Schema version is not an integer after update") + } + + // Let's get new dns configuration + dnsMap, ok := diskConfig["dns"] + if !ok { + t.Fatalf("No dns config in new configuration") + } + + // Cast dns configuration to map + newDNSConfig := make(map[string]interface{}) + switch v := dnsMap.(type) { + case map[string]interface{}: + for key, value := range v { + newDNSConfig[fmt.Sprint(key)] = value + } + default: + t.Fatalf("DNS configuration is not a map") + } + + // Check if bootstrap DNS becomes an array + bootstrapDNS := newDNSConfig["bootstrap_dns"] + switch v := bootstrapDNS.(type) { + case []string: + if len(v) != 1 { + t.Fatalf("Wrong count of bootsrap DNS servers") + } + + if v[0] != "8.8.8.8:53" { + t.Fatalf("Wrong bootsrap DNS servers") + } + default: + t.Fatalf("Wrong type for bootsrap DNS") + } + + // Set old value for bootstrap_dns and compare old and new configurations + newDNSConfig["bootstrap_dns"] = "8.8.8.8:53" + _, v, err := compareConfigs(oldDNSConfig, newDNSConfig) + if err != nil { + t.Fatalf("%s value is wrong: %s", v, err) + } +} + +// TODO add comparation for all possible types +func compareConfigs(oldConfig map[interface{}]interface{}, newConfig map[string]interface{}) (string, interface{}, error) { + oldConfigCasted := make(map[string]interface{}) + for k, v := range oldConfig { + oldConfigCasted[fmt.Sprint(k)] = v + } + + // Check old data and new data + for k, v := range newConfig { + switch value := v.(type) { + case string: + case int: + if value != oldConfigCasted[k] { + + } + case []string: + for i, s := range value { + if oldConfigCasted[k].([]string)[i] != s { + return k, v, fmt.Errorf("wrong data for %s", k) + } + } + case bool: + if v != oldConfigCasted[k].(bool) { + return k, v, fmt.Errorf("wrong data for %s", k) + } + default: + return k, v, fmt.Errorf("unknown type in DNS configuration for %s", k) + } + } + + return "", nil, nil +} + +func createTestDiskConfig(schemaVersion int) (diskConfig map[string]interface{}) { + diskConfig = make(map[string]interface{}) + diskConfig["language"] = "en" + diskConfig["filters"] = []filter{} + diskConfig["user_rules"] = []string{} + diskConfig["schema_version"] = schemaVersion + diskConfig["bind_host"] = "0.0.0.0" + diskConfig["bind_port"] = 80 + diskConfig["auth_name"] = "name" + diskConfig["auth_pass"] = "pass" + dnsConfig := createTestDNSConfig(schemaVersion) + if schemaVersion > 1 { + diskConfig["dns"] = dnsConfig + } else { + diskConfig["coredns"] = dnsConfig + } + return diskConfig +} + +func createTestDNSConfig(schemaVersion int) map[interface{}]interface{} { + dnsConfig := make(map[interface{}]interface{}) + dnsConfig["port"] = 53 + dnsConfig["blocked_response_ttl"] = 10 + dnsConfig["querylog_enabled"] = true + dnsConfig["ratelimit"] = 20 + dnsConfig["bootstrap_dns"] = "8.8.8.8:53" + if schemaVersion > 2 { + dnsConfig["bootstrap_dns"] = []string{"8.8.8.8:53"} + } + dnsConfig["parental_sensitivity"] = 13 + dnsConfig["ratelimit_whitelist"] = []string{} + dnsConfig["upstream_dns"] = []string{"tls://1.1.1.1", "tls://1.0.0.1", "8.8.8.8"} + dnsConfig["filtering_enabled"] = true + dnsConfig["refuse_any"] = true + dnsConfig["parental_enabled"] = true + dnsConfig["bind_host"] = "0.0.0.0" + dnsConfig["protection_enabled"] = true + dnsConfig["safesearch_enabled"] = true + dnsConfig["safebrowsing_enabled"] = true + return dnsConfig +} From d9d641941cf00035d8bdef9f27cd8288a86b64d9 Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Fri, 1 Mar 2019 11:27:15 +0300 Subject: [PATCH 37/95] [change] upgrade_test: rework tests --- upgrade_test.go | 187 ++++++++++++++++++++++++++++++------------------ 1 file changed, 117 insertions(+), 70 deletions(-) diff --git a/upgrade_test.go b/upgrade_test.go index e474cc1f..8980eda9 100644 --- a/upgrade_test.go +++ b/upgrade_test.go @@ -6,144 +6,191 @@ import ( ) func TestUpgrade1to2(t *testing.T) { - // Let's create test config + // let's create test config for 1 schema version diskConfig := createTestDiskConfig(1) - oldDNSConfig := createTestDNSConfig(1) + // update config err := upgradeSchema1to2(&diskConfig) if err != nil { t.Fatalf("Can't upgrade schema version from 1 to 2") } + // ensure that schema version was bumped + compareSchemaVersion(t, diskConfig["schema_version"], 2) + + // old coredns entry should be removed _, ok := diskConfig["coredns"] if ok { t.Fatalf("Core DNS config was not removed after upgrade schema version from 1 to 2") } + // pull out new dns config dnsMap, ok := diskConfig["dns"] if !ok { t.Fatalf("No DNS config after upgrade schema version from 1 to 2") } - // Cast dns configuration to map - newDNSConfig := make(map[string]interface{}) - switch v := dnsMap.(type) { - case map[interface{}]interface{}: - if len(oldDNSConfig) != len(v) { - t.Fatalf("We loose some data") - } - for key, value := range v { - newDNSConfig[fmt.Sprint(key)] = value - } - default: - t.Fatalf("DNS configuration is not a map") - } + // cast dns configurations to maps and compare them + oldDNSConfig := castInterfaceToMap(t, createTestDNSConfig(1)) + newDNSConfig := castInterfaceToMap(t, dnsMap) + compareConfigs(t, &oldDNSConfig, &newDNSConfig) - _, v, err := compareConfigs(oldDNSConfig, newDNSConfig) - if err != nil { - t.Fatalf("Wrong data %s, %s", v, err) - } + // exclude dns config and schema version from disk config comparison + oldExcludedEntries := []string{"coredns", "schema_version"} + newExcludedEntries := []string{"dns", "schema_version"} + oldDiskConfig := createTestDiskConfig(1) + compareConfigsWithoutEntries(t, &oldDiskConfig, &diskConfig, oldExcludedEntries, newExcludedEntries) } func TestUpgrade2to3(t *testing.T) { - // Let's create test config + // let's create test config diskConfig := createTestDiskConfig(2) - oldDNSConfig := createTestDNSConfig(2) - // Upgrade schema from 2 to 3 + // upgrade schema from 2 to 3 err := upgradeSchema2to3(&diskConfig) if err != nil { t.Fatalf("Can't update schema version from 2 to 3: %s", err) } - // Check new schema version - newSchemaVersion := diskConfig["schema_version"] - switch v := newSchemaVersion.(type) { - case int: - if v != 3 { - t.Fatalf("Wrong schema version in new config file") - } - default: - t.Fatalf("Schema version is not an integer after update") - } + // check new schema version + compareSchemaVersion(t, diskConfig["schema_version"], 3) - // Let's get new dns configuration + // pull out new dns configuration dnsMap, ok := diskConfig["dns"] if !ok { t.Fatalf("No dns config in new configuration") } - // Cast dns configuration to map - newDNSConfig := make(map[string]interface{}) - switch v := dnsMap.(type) { - case map[string]interface{}: - for key, value := range v { - newDNSConfig[fmt.Sprint(key)] = value - } - default: - t.Fatalf("DNS configuration is not a map") - } + // cast dns configuration to map + newDNSConfig := castInterfaceToMap(t, dnsMap) - // Check if bootstrap DNS becomes an array + // check if bootstrap DNS becomes an array bootstrapDNS := newDNSConfig["bootstrap_dns"] switch v := bootstrapDNS.(type) { case []string: if len(v) != 1 { - t.Fatalf("Wrong count of bootsrap DNS servers") + t.Fatalf("Wrong count of bootsrap DNS servers: %d", len(v)) } if v[0] != "8.8.8.8:53" { - t.Fatalf("Wrong bootsrap DNS servers") + t.Fatalf("Bootsrap DNS server is not 8.8.8.8:53 : %s", v[0]) } default: - t.Fatalf("Wrong type for bootsrap DNS") + t.Fatalf("Wrong type for bootsrap DNS: %T", v) } - // Set old value for bootstrap_dns and compare old and new configurations - newDNSConfig["bootstrap_dns"] = "8.8.8.8:53" - _, v, err := compareConfigs(oldDNSConfig, newDNSConfig) - if err != nil { - t.Fatalf("%s value is wrong: %s", v, err) - } + // exclude bootstrap DNS from DNS configs comparison + excludedEntries := []string{"bootstrap_dns"} + oldDNSConfig := castInterfaceToMap(t, createTestDNSConfig(2)) + compareConfigsWithoutEntries(t, &oldDNSConfig, &newDNSConfig, excludedEntries, excludedEntries) + + // excluded dns config and schema version from disk config comparison + excludedEntries = []string{"dns", "schema_version"} + oldDiskConfig := createTestDiskConfig(2) + compareConfigsWithoutEntries(t, &oldDiskConfig, &diskConfig, excludedEntries, excludedEntries) } -// TODO add comparation for all possible types -func compareConfigs(oldConfig map[interface{}]interface{}, newConfig map[string]interface{}) (string, interface{}, error) { - oldConfigCasted := make(map[string]interface{}) - for k, v := range oldConfig { - oldConfigCasted[fmt.Sprint(k)] = v +func castInterfaceToMap(t *testing.T, oldConfig interface{}) (newConfig map[string]interface{}) { + newConfig = make(map[string]interface{}) + switch v := oldConfig.(type) { + case map[interface{}]interface{}: + for key, value := range v { + newConfig[fmt.Sprint(key)] = value + } + case map[string]interface{}: + for key, value := range v { + newConfig[key] = value + } + default: + t.Fatalf("DNS configuration is not a map") + } + return +} + +// compareConfigsWithoutEntry removes entries from configs and returns result of compareConfigs +func compareConfigsWithoutEntries(t *testing.T, oldConfig, newConfig *map[string]interface{}, oldKey, newKey []string) { + for _, k := range oldKey { + delete(*oldConfig, k) + } + for _, k := range newKey { + delete(*newConfig, k) + } + compareConfigs(t, oldConfig, newConfig) +} + +// compares configs before and after schema upgrade +func compareConfigs(t *testing.T, oldConfig, newConfig *map[string]interface{}) { + if len(*oldConfig) != len(*newConfig) { + t.Fatalf("wrong config entries count! Before upgrade: %d; After upgrade: %d", len(*oldConfig), len(*oldConfig)) } - // Check old data and new data - for k, v := range newConfig { + // Check old and new entries + for k, v := range *newConfig { switch value := v.(type) { case string: + if value != (*oldConfig)[k] { + t.Fatalf("wrong value for string %s. Before update: %s; After update: %s", k, (*oldConfig)[k], value) + } case int: - if value != oldConfigCasted[k] { - + if value != (*oldConfig)[k] { + t.Fatalf("wrong value for int %s. Before update: %d; After update: %d", k, (*oldConfig)[k], value) } case []string: - for i, s := range value { - if oldConfigCasted[k].([]string)[i] != s { - return k, v, fmt.Errorf("wrong data for %s", k) + for i, line := range value { + if len((*oldConfig)[k].([]string)) != len(value) { + t.Fatalf("wrong array length for %s. Before update: %d; After update: %d", k, len((*oldConfig)[k].([]string)), len(value)) + } + if (*oldConfig)[k].([]string)[i] != line { + t.Fatalf("wrong data for string array %s. Before update: %s; After update: %s", k, (*oldConfig)[k].([]string)[i], line) } } case bool: - if v != oldConfigCasted[k].(bool) { - return k, v, fmt.Errorf("wrong data for %s", k) + if v != (*oldConfig)[k].(bool) { + t.Fatalf("wrong boolean value for %s", k) + } + case []filter: + if len((*oldConfig)[k].([]filter)) != len(value) { + t.Fatalf("wrong filters count. Before update: %d; After update: %d", len((*oldConfig)[k].([]filter)), len(value)) + } + for i, newFilter := range value { + oldFilter := (*oldConfig)[k].([]filter)[i] + if oldFilter.Enabled != newFilter.Enabled || oldFilter.Name != newFilter.Name || oldFilter.RulesCount != newFilter.RulesCount { + t.Fatalf("old filter %s not equals new filter %s", oldFilter.Name, newFilter.Name) + } } default: - return k, v, fmt.Errorf("unknown type in DNS configuration for %s", k) + t.Fatalf("uknown data type for %s: %T", k, value) } } +} - return "", nil, nil +// compareSchemaVersion check if newSchemaVersion equals schemaVersion +func compareSchemaVersion(t *testing.T, newSchemaVersion interface{}, schemaVersion int) { + switch v := newSchemaVersion.(type) { + case int: + if v != schemaVersion { + t.Fatalf("Wrong schema version in new config file") + } + default: + t.Fatalf("Schema version is not an integer after update") + } } func createTestDiskConfig(schemaVersion int) (diskConfig map[string]interface{}) { diskConfig = make(map[string]interface{}) diskConfig["language"] = "en" - diskConfig["filters"] = []filter{} + diskConfig["filters"] = []filter{ + { + URL: "https://filters.adtidy.org/android/filters/111_optimized.txt", + Name: "Latvian filter", + RulesCount: 100, + }, + { + URL: "https://easylist.to/easylistgermany/easylistgermany.txt", + Name: "Germany filter", + RulesCount: 200, + }, + } diskConfig["user_rules"] = []string{} diskConfig["schema_version"] = schemaVersion diskConfig["bind_host"] = "0.0.0.0" From e973c4b174d9249cb05f01faa9d7662f2f04d55e Mon Sep 17 00:00:00 2001 From: Aleksey Dmitrevskiy Date: Tue, 5 Mar 2019 12:29:52 +0300 Subject: [PATCH 38/95] [change] control, openapi: Handle upstreams test with JSON --- control.go | 4 ++-- openapi/openapi.yaml | 32 ++++++++++++++++++++------------ 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/control.go b/control.go index 7b17321b..0bc6fc66 100644 --- a/control.go +++ b/control.go @@ -361,12 +361,12 @@ func checkBootstrapDNS(host string) error { func handleTestUpstreamDNS(w http.ResponseWriter, r *http.Request) { log.Tracef("%s %v", r.Method, r.URL) - body, err := ioutil.ReadAll(r.Body) + hosts := []string{} + err := json.NewDecoder(r.Body).Decode(&hosts) if err != nil { httpError(w, http.StatusBadRequest, "Failed to read request body: %s", err) return } - hosts := strings.Fields(string(body)) if len(hosts) == 0 { httpError(w, http.StatusBadRequest, "No servers specified") diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index 6d0aafb4..d84e90ec 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -111,21 +111,15 @@ paths: tags: - global operationId: testUpstreamDNS - summary: 'Test upstream DNS' + summary: "Test upstream DNS" consumes: - - text/plain + - application/json parameters: - - in: body - name: upstream - description: 'Upstream servers, separated by newline or space, port is optional after colon' + - in: "body" + name: "body" + description: "Upstream servers to be tested" 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 + $ref: "#/definitions/TestUpstreams" responses: 200: description: 'Status of testing each requested server, with "OK" meaning that server works, any other text means an error.' @@ -820,6 +814,20 @@ definitions: all_servers: type: "boolean" description: "If true, parallel queries to all configured upstream servers are enabled" + TestUpstreams: + type: "object" + description: "Upstream servers to be tested" + required: + - "upstream_dns" + properties: + upstream_dns: + type: "array" + description: 'Upstream servers, port is optional after colon' + items: + type: "string" + example: + - "tls://1.1.1.1" + - "tls://1.0.0.1" Filter: type: "object" description: "Filter subscription info" From 5d6c980ac7a33e5a4b8d3c376d8984e36cba1f83 Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Wed, 6 Mar 2019 14:45:21 +0300 Subject: [PATCH 39/95] * client: upstream form --- client/src/__locales/en.json | 5 +- client/src/actions/index.js | 13 +- client/src/api/Api.js | 6 +- client/src/components/Settings/Upstream.js | 97 -------------- .../components/Settings/Upstream/Examples.js | 32 +++++ .../src/components/Settings/Upstream/Form.js | 120 ++++++++++++++++++ .../src/components/Settings/Upstream/index.js | 67 ++++++++++ client/src/components/Settings/index.js | 29 +---- client/src/components/ui/Checkbox.css | 4 + client/src/helpers/form.js | 2 +- client/src/helpers/helpers.js | 2 + client/src/reducers/index.js | 8 +- 12 files changed, 256 insertions(+), 129 deletions(-) delete mode 100644 client/src/components/Settings/Upstream.js create mode 100644 client/src/components/Settings/Upstream/Examples.js create mode 100644 client/src/components/Settings/Upstream/Form.js create mode 100644 client/src/components/Settings/Upstream/index.js diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index 45c33828..b70cdd37 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -246,5 +246,8 @@ "form_error_equal": "Shouldn't be equal", "form_error_password": "Password mismatched", "reset_settings": "Reset settings", - "update_announcement": "AdGuard Home {{version}} is now available! <0>Click here for more info." + "update_announcement": "AdGuard Home {{version}} is now available! <0>Click here for more info.", + "upstream_parallel": "Use parallel queries to speed up resolving by simultaneously querying all upstream servers", + "bootstrap_dns": "Bootstrap DNS", + "bootstrap_dns_desc": "Bootstrap DNS for DNS-over-HTTPS and DNS-over-TLS servers" } diff --git a/client/src/actions/index.js b/client/src/actions/index.js index 1bb99064..0bb99940 100644 --- a/client/src/actions/index.js +++ b/client/src/actions/index.js @@ -3,7 +3,7 @@ import round from 'lodash/round'; import { t } from 'i18next'; import { showLoading, hideLoading } from 'react-redux-loading-bar'; -import { normalizeHistory, normalizeFilteringStatus, normalizeLogs } from '../helpers/helpers'; +import { normalizeHistory, normalizeFilteringStatus, normalizeLogs, normalizeTextarea } from '../helpers/helpers'; import { SETTINGS_NAMES } from '../helpers/constants'; import Api from '../api/Api'; @@ -452,10 +452,14 @@ export const setUpstreamRequest = createAction('SET_UPSTREAM_REQUEST'); export const setUpstreamFailure = createAction('SET_UPSTREAM_FAILURE'); export const setUpstreamSuccess = createAction('SET_UPSTREAM_SUCCESS'); -export const setUpstream = url => async (dispatch) => { +export const setUpstream = config => async (dispatch) => { dispatch(setUpstreamRequest()); try { - await apiClient.setUpstream(url); + const values = { ...config }; + values.bootstrap_dns = (values.bootstrap_dns && normalizeTextarea(values.bootstrap_dns)) || ''; + values.upstream_dns = (values.upstream_dns && normalizeTextarea(values.upstream_dns)) || ''; + + await apiClient.setUpstream(values); dispatch(addSuccessToast('updated_upstream_dns_toast')); dispatch(setUpstreamSuccess()); } catch (error) { @@ -468,9 +472,10 @@ export const testUpstreamRequest = createAction('TEST_UPSTREAM_REQUEST'); export const testUpstreamFailure = createAction('TEST_UPSTREAM_FAILURE'); export const testUpstreamSuccess = createAction('TEST_UPSTREAM_SUCCESS'); -export const testUpstream = servers => async (dispatch) => { +export const testUpstream = values => async (dispatch) => { dispatch(testUpstreamRequest()); try { + const servers = normalizeTextarea(values); const upstreamResponse = await apiClient.testUpstream(servers); const testMessages = Object.keys(upstreamResponse).map((key) => { diff --git a/client/src/api/Api.js b/client/src/api/Api.js index d20a334a..17df1221 100644 --- a/client/src/api/Api.js +++ b/client/src/api/Api.js @@ -34,7 +34,7 @@ export default class Api { GLOBAL_QUERY_LOG = { path: 'querylog', method: 'GET' }; GLOBAL_QUERY_LOG_ENABLE = { path: 'querylog_enable', method: 'POST' }; GLOBAL_QUERY_LOG_DISABLE = { path: 'querylog_disable', method: 'POST' }; - GLOBAL_SET_UPSTREAM_DNS = { path: 'set_upstream_dns', method: 'POST' }; + GLOBAL_SET_UPSTREAM_DNS = { path: 'set_upstreams_config', method: 'POST' }; GLOBAL_TEST_UPSTREAM_DNS = { path: 'test_upstream_dns', method: 'POST' }; GLOBAL_VERSION = { path: 'version.json', method: 'GET' }; GLOBAL_ENABLE_PROTECTION = { path: 'enable_protection', method: 'POST' }; @@ -110,7 +110,7 @@ export default class Api { const { path, method } = this.GLOBAL_SET_UPSTREAM_DNS; const config = { data: url, - header: { 'Content-Type': 'text/plain' }, + headers: { 'Content-Type': 'application/json' }, }; return this.makeRequest(path, method, config); } @@ -119,7 +119,7 @@ export default class Api { const { path, method } = this.GLOBAL_TEST_UPSTREAM_DNS; const config = { data: servers, - header: { 'Content-Type': 'text/plain' }, + headers: { 'Content-Type': 'application/json' }, }; return this.makeRequest(path, method, config); } diff --git a/client/src/components/Settings/Upstream.js b/client/src/components/Settings/Upstream.js deleted file mode 100644 index fe24c4d7..00000000 --- a/client/src/components/Settings/Upstream.js +++ /dev/null @@ -1,97 +0,0 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import classnames from 'classnames'; -import { Trans, withNamespaces } from 'react-i18next'; -import Card from '../ui/Card'; - -class Upstream extends Component { - handleChange = (e) => { - const { value } = e.currentTarget; - this.props.handleUpstreamChange(value); - }; - - handleSubmit = (e) => { - e.preventDefault(); - this.props.handleUpstreamSubmit(); - }; - - handleTest = () => { - this.props.handleUpstreamTest(); - } - - render() { - const testButtonClass = classnames({ - 'btn btn-primary btn-standard mr-2': true, - 'btn btn-primary btn-standard mr-2 btn-loading': this.props.processingTestUpstream, - }); - const { t } = this.props; - - return ( - -
-
- -