diff --git a/client/src/actions/index.js b/client/src/actions/index.js index 5d96b045..d403a77e 100644 --- a/client/src/actions/index.js +++ b/client/src/actions/index.js @@ -343,7 +343,12 @@ export const testUpstreamFailure = createAction('TEST_UPSTREAM_FAILURE'); export const testUpstreamSuccess = createAction('TEST_UPSTREAM_SUCCESS'); export const testUpstream = ( - { bootstrap_dns, upstream_dns, local_ptr_upstreams }, upstream_dns_file, + { + bootstrap_dns, + upstream_dns, + local_ptr_upstreams, + fallback_dns, + }, upstream_dns_file, ) => async (dispatch) => { dispatch(testUpstreamRequest()); try { @@ -352,6 +357,7 @@ export const testUpstream = ( const config = { bootstrap_dns: splitByNewLine(bootstrap_dns), private_upstream: splitByNewLine(local_ptr_upstreams), + fallback_dns: splitByNewLine(fallback_dns), ...(upstream_dns_file ? null : { upstream_dns: removeComments(upstream_dns), }), @@ -386,12 +392,14 @@ export const testUpstreamWithFormValues = () => async (dispatch, getState) => { bootstrap_dns, upstream_dns, local_ptr_upstreams, + fallback_dns, } = getState().form[FORM_NAME.UPSTREAM].values; return dispatch(testUpstream({ bootstrap_dns, upstream_dns, local_ptr_upstreams, + fallback_dns, }, upstream_dns_file)); }; diff --git a/internal/dnsforward/http.go b/internal/dnsforward/http.go index 95e7f407..3827e101 100644 --- a/internal/dnsforward/http.go +++ b/internal/dnsforward/http.go @@ -392,6 +392,7 @@ func (s *Server) setConfigRestartable(dc *jsonDNSConfig) (shouldRestart bool) { type upstreamJSON struct { Upstreams []string `json:"upstream_dns"` BootstrapDNS []string `json:"bootstrap_dns"` + FallbackDNS []string `json:"fallback_dns"` PrivateUpstreams []string `json:"private_upstream"` } @@ -750,11 +751,10 @@ func (s *Server) handleTestUpstreamDNS(w http.ResponseWriter, r *http.Request) { req.Upstreams = stringutil.FilterOut(req.Upstreams, IsCommentOrEmpty) req.PrivateUpstreams = stringutil.FilterOut(req.PrivateUpstreams, IsCommentOrEmpty) - upsNum := len(req.Upstreams) + len(req.PrivateUpstreams) + upsNum := len(req.Upstreams) + len(req.FallbackDNS) + len(req.PrivateUpstreams) result := make(map[string]string, upsNum) resCh := make(chan upsCheckResult, upsNum) - // TODO(s.chzhen): Check fallback DNS servers. for _, ups := range req.Upstreams { go func(ups string) { resCh <- upsCheckResult{ @@ -763,6 +763,14 @@ func (s *Server) handleTestUpstreamDNS(w http.ResponseWriter, r *http.Request) { } }(ups) } + for _, ups := range req.FallbackDNS { + go func(ups string) { + resCh <- upsCheckResult{ + host: ups, + err: s.checkDNS(ups, opts, checkDNSUpstreamExc), + } + }(ups) + } for _, ups := range req.PrivateUpstreams { go func(ups string) { resCh <- upsCheckResult{ diff --git a/internal/dnsforward/http_test.go b/internal/dnsforward/http_test.go index 8eda01c4..7987d94e 100644 --- a/internal/dnsforward/http_test.go +++ b/internal/dnsforward/http_test.go @@ -560,6 +560,23 @@ func TestServer_HandleTestUpstreamDNS(t *testing.T) { hostsUps: "OK", }, name: "etc_hosts", + }, { + body: map[string]any{ + "fallback_dns": []string{goodUps}, + }, + wantResp: map[string]any{ + goodUps: "OK", + }, + name: "fallback_success", + }, { + body: map[string]any{ + "fallback_dns": []string{badUps}, + }, + wantResp: map[string]any{ + badUps: `couldn't communicate with upstream: exchanging with ` + + badUps + ` over tcp: dns: id mismatch`, + }, + name: "fallback_broken", }} for _, tc := range testCases { diff --git a/openapi/CHANGELOG.md b/openapi/CHANGELOG.md index 9ae20255..3ea61c33 100644 --- a/openapi/CHANGELOG.md +++ b/openapi/CHANGELOG.md @@ -6,6 +6,11 @@ ## v0.107.37: API changes +### The new field `"fallback_dns"` in `UpstreamsConfig` object + +* The new field `"fallback_dns"` in `POST /control/test_upstream_dns` is the + list of fallback DNS servers to test. + ### The new field `"fallback_dns"` in `DNSConfig` object * The new field `"fallback_dns"` in `GET /control/dns_info` and `POST diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index 497cb210..52331c7f 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -1503,7 +1503,7 @@ - 'tls://1.0.0.1' 'UpstreamsConfig': 'type': 'object' - 'description': 'Upstreams configuration' + 'description': 'Upstream configuration to be tested' 'required': - 'bootstrap_dns' - 'upstream_dns' @@ -1511,8 +1511,7 @@ 'bootstrap_dns': 'type': 'array' 'description': > - Bootstrap servers, port is optional after colon. Empty value will - reset it to default values. + Bootstrap DNS servers, port is optional after colon. 'items': 'type': 'string' 'example': @@ -1521,18 +1520,25 @@ 'upstream_dns': 'type': 'array' 'description': > - Upstream servers, port is optional after colon. Empty value will - reset it to default values. + Upstream DNS servers, port is optional after colon. 'items': 'type': 'string' 'example': - 'tls://1.1.1.1' - 'tls://1.0.0.1' + 'fallback_dns': + 'type': 'array' + 'description': > + Fallback DNS servers, port is optional after colon. + 'items': + 'type': 'string' + 'example': + - '8.8.8.8' + - '1.1.1.1:53' 'private_upstream': 'type': 'array' 'description': > - Local PTR resolvers, port is optional after colon. Empty value will - reset it to default values. + Local PTR resolvers, port is optional after colon. 'items': 'type': 'string' 'example':