From e2ddc82d70ecff9ed2ddedb68bffaf7937a21370 Mon Sep 17 00:00:00 2001 From: Simon Zolin Date: Wed, 22 Apr 2020 19:14:04 +0300 Subject: [PATCH] + DNS: add fastest_addr setting * API: /dns_info, /dns_config: add "parallel_requests" instead of "all_servers" from /set_upstreams_config * API: /status: removed fields #715 Squashed commit of the following: commit 7dd913bd336ecbaa7419b998d0bf913d89702fe6 Merge: 43706970 8170955a Author: Simon Zolin Date: Wed Apr 22 19:09:36 2020 +0300 Merge remote-tracking branch 'origin/master' into 715-fastest-addr commit 437069702a3e91e0b066e4b22b08cdc02ff19eaf Author: Simon Zolin Date: Wed Apr 22 19:08:55 2020 +0300 minor commit 9e713df80c5bf113c98794c0a20915c756a76938 Merge: e3bf4037 9b7c1181 Author: Simon Zolin Date: Tue Apr 21 16:02:03 2020 +0300 Merge remote-tracking branch 'origin/master' into 715-fastest-addr commit e3bf4037f49198e42bde55305d6f9077341b556a Author: Simon Zolin Date: Tue Apr 21 15:40:49 2020 +0300 minor commit d6e6a823c5e51acc061b2850d362772efcb827e1 Author: Simon Zolin Date: Fri Apr 17 17:56:24 2020 +0300 * API changes . removed POST /set_upstreams_config . removed fields from GET /status: bootstrap_dns, upstream_dns, all_servers . added new fields to /dns_config and /dns_info commit 237a452d09cc48ff8f00e81c7fd35e7828bea835 Author: Simon Zolin Date: Fri Apr 17 16:43:13 2020 +0300 * API: /dns_info, /dns_config: add "parallel_requests" instead of "all_servers" from /set_upstreams_config commit 9976723b9725ed19e0cce152d1d1198b13c4acc1 Author: Simon Zolin Date: Mon Mar 23 10:28:25 2020 +0300 openapi commit 6f8ea16c6332606f29095b0094d71e8a91798f82 Merge: 36e4d4e8 c8285c41 Author: Simon Zolin Date: Fri Mar 20 19:18:48 2020 +0300 Merge remote-tracking branch 'origin/master' into 715-fastest-addr commit 36e4d4e82cadeaba5a11313f0d69d66a0924c342 Author: Simon Zolin Date: Fri Mar 20 18:13:43 2020 +0300 + DNS: add fastest_addr setting --- AGHTechDoc.md | 10 ++++ dnsforward/dnsforward.go | 3 ++ dnsforward/dnsforward_http.go | 94 ++++++++++++++++++----------------- home/control.go | 3 -- openapi/CHANGELOG.md | 64 ++++++++++++++++++++++++ openapi/openapi.yaml | 57 +++++++++------------ 6 files changed, 148 insertions(+), 83 deletions(-) diff --git a/AGHTechDoc.md b/AGHTechDoc.md index 4c8e0fda..5a3b001c 100644 --- a/AGHTechDoc.md +++ b/AGHTechDoc.md @@ -882,6 +882,9 @@ Response: 200 OK { + "upstream_dns": ["tls://...", ...], + "bootstrap_dns": ["1.2.3.4", ...], + "protection_enabled": true | false, "ratelimit": 1234, "blocking_mode": "default" | "nxdomain" | "null_ip" | "custom_ip", @@ -890,6 +893,8 @@ Response: "edns_cs_enabled": true | false, "dnssec_enabled": true | false "disable_ipv6": true | false, + "fastest_addr": true | false, // use Fastest Address algorithm + "parallel_requests": true | false, // send DNS requests to all upstream servers at once } @@ -900,6 +905,9 @@ Request: POST /control/dns_config { + "upstream_dns": ["tls://...", ...], + "bootstrap_dns": ["1.2.3.4", ...], + "protection_enabled": true | false, "ratelimit": 1234, "blocking_mode": "default" | "nxdomain" | "null_ip" | "custom_ip", @@ -908,6 +916,8 @@ Request: "edns_cs_enabled": true | false, "dnssec_enabled": true | false "disable_ipv6": true | false, + "fastest_addr": true | false, // use Fastest Address algorithm + "parallel_requests": true | false, // send DNS requests to all upstream servers at once } Response: diff --git a/dnsforward/dnsforward.go b/dnsforward/dnsforward.go index b191a966..4f630afb 100644 --- a/dnsforward/dnsforward.go +++ b/dnsforward/dnsforward.go @@ -141,6 +141,8 @@ type FilteringConfig struct { // Respond with an empty answer to all AAAA requests AAAADisabled bool `yaml:"aaaa_disabled"` + FastestAddrAlgo bool `yaml:"fastest_addr"` // use Fastest Address algorithm + AllowedClients []string `yaml:"allowed_clients"` // IP addresses of whitelist clients DisallowedClients []string `yaml:"disallowed_clients"` // IP addresses of clients that should be blocked BlockedHosts []string `yaml:"blocked_hosts"` // hosts that should be blocked @@ -305,6 +307,7 @@ func (s *Server) Prepare(config *ServerConfig) error { RequestHandler: s.handleDNSRequest, AllServers: s.conf.AllServers, EnableEDNSClientSubnet: s.conf.EnableEDNSClientSubnet, + FindFastestAddr: s.conf.FastestAddrAlgo, } intlProxyConfig := proxy.Config{ diff --git a/dnsforward/dnsforward_http.go b/dnsforward/dnsforward_http.go index 414b728b..4658cbbf 100644 --- a/dnsforward/dnsforward_http.go +++ b/dnsforward/dnsforward_http.go @@ -22,6 +22,9 @@ func httpError(r *http.Request, w http.ResponseWriter, code int, format string, } type dnsConfigJSON struct { + Upstreams []string `json:"upstream_dns"` + Bootstraps []string `json:"bootstrap_dns"` + ProtectionEnabled bool `json:"protection_enabled"` RateLimit uint32 `json:"ratelimit"` BlockingMode string `json:"blocking_mode"` @@ -30,11 +33,16 @@ type dnsConfigJSON struct { EDNSCSEnabled bool `json:"edns_cs_enabled"` DNSSECEnabled bool `json:"dnssec_enabled"` DisableIPv6 bool `json:"disable_ipv6"` + FastestAddr bool `json:"fastest_addr"` + ParallelRequests bool `json:"parallel_requests"` } func (s *Server) handleGetConfig(w http.ResponseWriter, r *http.Request) { resp := dnsConfigJSON{} s.RLock() + resp.Upstreams = stringArrayDup(s.conf.UpstreamDNS) + resp.Bootstraps = stringArrayDup(s.conf.BootstrapDNS) + resp.ProtectionEnabled = s.conf.ProtectionEnabled resp.BlockingMode = s.conf.BlockingMode resp.BlockingIPv4 = s.conf.BlockingIPv4 @@ -43,6 +51,8 @@ func (s *Server) handleGetConfig(w http.ResponseWriter, r *http.Request) { resp.EDNSCSEnabled = s.conf.EnableEDNSClientSubnet resp.DNSSECEnabled = s.conf.EnableDNSSEC resp.DisableIPv6 = s.conf.AAAADisabled + resp.FastestAddr = s.conf.FastestAddrAlgo + resp.ParallelRequests = s.conf.AllServers s.RUnlock() js, err := json.Marshal(resp) @@ -75,6 +85,7 @@ func checkBlockingMode(req dnsConfigJSON) bool { return true } +// nolint(gocyclo) - we need to check each JSON field separately func (s *Server) handleSetConfig(w http.ResponseWriter, r *http.Request) { req := dnsConfigJSON{} js, err := jsonutil.DecodeObject(&req, r.Body) @@ -83,6 +94,25 @@ func (s *Server) handleSetConfig(w http.ResponseWriter, r *http.Request) { return } + if js.Exists("upstream_dns") { + if len(req.Upstreams) != 0 { + err = ValidateUpstreams(req.Upstreams) + if err != nil { + httpError(r, w, http.StatusBadRequest, "wrong upstreams specification: %s", err) + return + } + } + } + + if js.Exists("bootstrap_dns") { + for _, host := range req.Bootstraps { + if err := checkPlainDNS(host); err != nil { + httpError(r, w, http.StatusBadRequest, "%s can not be used as bootstrap dns cause: %s", host, err) + return + } + } + } + if js.Exists("blocking_mode") && !checkBlockingMode(req) { httpError(r, w, http.StatusBadRequest, "blocking_mode: incorrect value") return @@ -91,6 +121,16 @@ func (s *Server) handleSetConfig(w http.ResponseWriter, r *http.Request) { restart := false s.Lock() + if js.Exists("upstream_dns") { + s.conf.UpstreamDNS = req.Upstreams + restart = true + } + + if js.Exists("bootstrap_dns") { + s.conf.BootstrapDNS = req.Bootstraps + restart = true + } + if js.Exists("protection_enabled") { s.conf.ProtectionEnabled = req.ProtectionEnabled } @@ -129,6 +169,14 @@ func (s *Server) handleSetConfig(w http.ResponseWriter, r *http.Request) { s.conf.AAAADisabled = req.DisableIPv6 } + if js.Exists("fastest_addr") { + s.conf.FastestAddrAlgo = req.FastestAddr + } + + if js.Exists("parallel_requests") { + s.conf.AllServers = req.ParallelRequests + } + s.Unlock() s.conf.ConfigModified() @@ -144,51 +192,6 @@ func (s *Server) handleSetConfig(w http.ResponseWriter, r *http.Request) { type upstreamJSON struct { Upstreams []string `json:"upstream_dns"` // Upstreams BootstrapDNS []string `json:"bootstrap_dns"` // Bootstrap DNS - AllServers bool `json:"all_servers"` // --all-servers param for dnsproxy -} - -func (s *Server) handleSetUpstreamConfig(w http.ResponseWriter, r *http.Request) { - req := upstreamJSON{} - err := json.NewDecoder(r.Body).Decode(&req) - if err != nil { - httpError(r, w, http.StatusBadRequest, "Failed to parse new upstreams config json: %s", err) - return - } - - if len(req.Upstreams) != 0 { - err = ValidateUpstreams(req.Upstreams) - if err != nil { - httpError(r, w, http.StatusBadRequest, "wrong upstreams specification: %s", err) - return - } - } - - newconf := FilteringConfig{} - newconf.UpstreamDNS = req.Upstreams - - // bootstrap servers are plain DNS only - for _, host := range req.BootstrapDNS { - if err := checkPlainDNS(host); err != nil { - httpError(r, w, http.StatusBadRequest, "%s can not be used as bootstrap dns cause: %s", host, err) - return - } - } - newconf.BootstrapDNS = req.BootstrapDNS - - newconf.AllServers = req.AllServers - - s.Lock() - s.conf.UpstreamDNS = newconf.UpstreamDNS - s.conf.BootstrapDNS = newconf.BootstrapDNS - s.conf.AllServers = newconf.AllServers - s.Unlock() - s.conf.ConfigModified() - - err = s.Reconfigure(nil) - if err != nil { - httpError(r, w, http.StatusInternalServerError, "%s", err) - return - } } // ValidateUpstreams validates each upstream and returns an error if any upstream is invalid or if there are no default upstreams specified @@ -399,7 +402,6 @@ func (s *Server) handleDOH(w http.ResponseWriter, r *http.Request) { func (s *Server) registerHandlers() { s.conf.HTTPRegister("GET", "/control/dns_info", s.handleGetConfig) s.conf.HTTPRegister("POST", "/control/dns_config", s.handleSetConfig) - s.conf.HTTPRegister("POST", "/control/set_upstreams_config", s.handleSetUpstreamConfig) s.conf.HTTPRegister("POST", "/control/test_upstream_dns", s.handleTestUpstreamDNS) s.conf.HTTPRegister("GET", "/control/access/list", s.handleAccessList) diff --git a/home/control.go b/home/control.go index 4d1dbe0c..310b9f20 100644 --- a/home/control.go +++ b/home/control.go @@ -55,9 +55,6 @@ func handleStatus(w http.ResponseWriter, r *http.Request) { "language": config.Language, "protection_enabled": c.ProtectionEnabled, - "bootstrap_dns": c.BootstrapDNS, - "upstream_dns": c.UpstreamDNS, - "all_servers": c.AllServers, } jsonVal, err := json.Marshal(data) diff --git a/openapi/CHANGELOG.md b/openapi/CHANGELOG.md index 877c1f7c..193b69fc 100644 --- a/openapi/CHANGELOG.md +++ b/openapi/CHANGELOG.md @@ -1,6 +1,70 @@ # AdGuard Home API Change Log +## v0.102: API changes + +### API: Get general status: GET /control/status + +* Removed "upstream_dns", "bootstrap_dns", "all_servers" parameters + +### API: Get DNS general settings: GET /control/dns_info + +* Added "parallel_requests", "upstream_dns", "bootstrap_dns" parameters + +Request: + + GET /control/dns_info + +Response: + + 200 OK + + { + "upstream_dns": ["tls://...", ...], + "bootstrap_dns": ["1.2.3.4", ...], + + "protection_enabled": true | false, + "ratelimit": 1234, + "blocking_mode": "default" | "nxdomain" | "null_ip" | "custom_ip", + "blocking_ipv4": "1.2.3.4", + "blocking_ipv6": "1:2:3::4", + "edns_cs_enabled": true | false, + "dnssec_enabled": true | false + "disable_ipv6": true | false, + "fastest_addr": true | false, // use Fastest Address algorithm + "parallel_requests": true | false, // send DNS requests to all upstream servers at once + } + +### API: Set DNS general settings: POST /control/dns_config + +* Added "parallel_requests", "upstream_dns", "bootstrap_dns" parameters +* removed /control/set_upstreams_config method + +Request: + + POST /control/dns_config + + { + "upstream_dns": ["tls://...", ...], + "bootstrap_dns": ["1.2.3.4", ...], + + "protection_enabled": true | false, + "ratelimit": 1234, + "blocking_mode": "default" | "nxdomain" | "null_ip" | "custom_ip", + "blocking_ipv4": "1.2.3.4", + "blocking_ipv6": "1:2:3::4", + "edns_cs_enabled": true | false, + "dnssec_enabled": true | false + "disable_ipv6": true | false, + "fastest_addr": true | false, // use Fastest Address algorithm + "parallel_requests": true | false, // send DNS requests to all upstream servers at once + } + +Response: + + 200 OK + + ## v0.101: API changes ### API: Refresh filters: POST /control/filtering/refresh diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index 9653af5a..a9791c4d 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -2,7 +2,7 @@ swagger: '2.0' info: title: 'AdGuard Home' description: 'AdGuard Home REST API. Admin web interface is built on top of this REST API.' - version: '0.101' + version: '0.102' schemes: - http basePath: /control @@ -99,25 +99,6 @@ 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 - /test_upstream_dns: post: tags: @@ -1072,16 +1053,6 @@ definitions: type: "boolean" running: type: "boolean" - 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" version: type: "string" example: "0.1" @@ -1093,6 +1064,22 @@ definitions: type: "object" description: "Query log configuration" properties: + bootstrap_dns: + 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: + - "tls://1.1.1.1" + - "tls://1.0.0.1" protection_enabled: type: "boolean" ratelimit: @@ -1112,6 +1099,11 @@ definitions: type: "boolean" dnssec_enabled: type: "boolean" + fastest_addr: + type: "boolean" + parallel_requests: + type: "boolean" + description: "If true, parallel queries to all configured upstream servers are enabled" UpstreamsConfig: type: "object" @@ -1119,7 +1111,6 @@ definitions: required: - "bootstrap_dns" - "upstream_dns" - - "all_servers" properties: bootstrap_dns: type: "array" @@ -1137,9 +1128,7 @@ definitions: example: - "tls://1.1.1.1" - "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"