Skip to content

Commit

Permalink
Pull request 2338: AGDNS-2665-upstream-timeout
Browse files Browse the repository at this point in the history
Merge in DNS/adguard-home from AGDNS-2665-upstream-timeout to master

Squashed commit of the following:

commit b4041c9
Merge: d939b3b b92a3cf
Author: Ainar Garipov <[email protected]>
Date:   Fri Feb 7 16:15:19 2025 +0300

    Merge branch 'master' into AGDNS-2665-upstream-timeout

commit d939b3b
Author: Ainar Garipov <[email protected]>
Date:   Fri Feb 7 16:10:06 2025 +0300

    client: imp i18n

commit 52089ad
Author: Stanislav Chzhen <[email protected]>
Date:   Thu Feb 6 18:39:53 2025 +0300

    all: fix typo

commit aca08b1
Author: Ildar Kamalov <[email protected]>
Date:   Thu Feb 6 15:19:30 2025 +0300

    client: rearrange upstream timeout settings

commit 48e75fa
Author: Stanislav Chzhen <[email protected]>
Date:   Tue Feb 4 20:48:53 2025 +0300

    github: upd actions cache

commit 64bac19
Author: Stanislav Chzhen <[email protected]>
Date:   Tue Feb 4 20:28:54 2025 +0300

    all: imp code

commit 95c7369
Author: Stanislav Chzhen <[email protected]>
Date:   Mon Feb 3 16:25:35 2025 +0300

    all: upstream timeout
  • Loading branch information
schzhn committed Feb 10, 2025
1 parent b92a3cf commit 2fe2d25
Show file tree
Hide file tree
Showing 13 changed files with 176 additions and 5 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ NOTE: Add new changes BELOW THIS COMMENT.

- Go version has been updated to prevent the possibility of exploiting the Go vulnerabilities fixed in [1.23.6][go-1.23.6].

### Added

- The ability to specify the upstream timeout in the Web UI.

### Changed

- The *Fastest IP adddress* upstream mode now collects statistics for the all upstream DNS servers.
Expand Down
7 changes: 5 additions & 2 deletions client/src/__locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"upstream_parallel": "Use parallel queries to speed up resolving by querying all upstream servers simultaneously.",
"parallel_requests": "Parallel requests",
"load_balancing": "Load-balancing",
"load_balancing_desc": "Query one upstream server at a time. AdGuard Home uses a weighted random algorithm to select servers with the lowest number of failed lookups and the lowest average lookup time.",
"load_balancing_desc": "Query one upstream server at a time.<br/>AdGuard Home uses a weighted random algorithm to select servers with the lowest number of failed lookups and the lowest average lookup time.",
"bootstrap_dns": "Bootstrap DNS servers",
"bootstrap_dns_desc": "IP addresses of DNS servers used to resolve IP addresses of the DoH/DoT resolvers you specify as upstreams. Comments are not permitted.",
"fallback_dns_title": "Fallback DNS servers",
Expand Down Expand Up @@ -294,6 +294,9 @@
"blocked_response_ttl": "Blocked response TTL",
"blocked_response_ttl_desc": "Specifies for how many seconds the clients should cache a filtered response",
"form_enter_blocked_response_ttl": "Enter blocked response TTL (seconds)",
"upstream_timeout": "Upstream timeout",
"upstream_timeout_desc": "Specifies the number of seconds to wait for a response from the upstream server",
"form_enter_upstream_timeout": "Enter the upstream server timeout duration in seconds",
"dnscrypt": "DNSCrypt",
"dns_over_https": "DNS-over-HTTPS",
"dns_over_tls": "DNS-over-TLS",
Expand Down Expand Up @@ -598,7 +601,7 @@
"disable_ipv6": "Disable resolving of IPv6 addresses",
"disable_ipv6_desc": "Drop all DNS queries for IPv6 addresses (type AAAA) and remove IPv6 hints from HTTPS responses.",
"fastest_addr": "Fastest IP address",
"fastest_addr_desc": "Query all DNS servers and return the fastest IP address among all responses. This slows down DNS queries as AdGuard Home has to wait for responses from all DNS servers, but improves the overall connectivity.",
"fastest_addr_desc": "Wait for responses from <b>all</b> DNS servers, measure the TCP connection speed for each server, and return the IP address of the server with the fastest connection speed.<br/>This mode can significantly slow down DNS queries, if one or more upstream servers are not responding. Make sure that your upstream servers are stable and your upstream timeout is low.",
"autofix_warning_text": "If you click \"Fix\", AdGuard Home will configure your system to use AdGuard Home DNS server.",
"autofix_warning_list": "It will perform these tasks: <0>Deactivate system DNSStubListener</0> <0>Set DNS server address to 127.0.0.1</0> <0>Replace symbolic link target of /etc/resolv.conf with /run/systemd/resolve/resolv.conf</0> <0>Stop DNSStubListener (reload systemd-resolved service)</0>",
"autofix_warning_result": "As a result all DNS requests from your system will be processed by AdGuard Home by default.",
Expand Down
46 changes: 43 additions & 3 deletions client/src/components/Settings/Dns/Upstream/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,19 @@ import classnames from 'classnames';

import Examples from './Examples';

import { renderRadioField, renderTextareaField, CheckboxField } from '../../../../helpers/form';
import { DNS_REQUEST_OPTIONS, FORM_NAME, UPSTREAM_CONFIGURATION_WIKI_LINK } from '../../../../helpers/constants';
import {
renderRadioField,
renderTextareaField,
CheckboxField,
renderInputField,
toNumber,
} from '../../../../helpers/form';
import {
DNS_REQUEST_OPTIONS,
FORM_NAME,
UINT32_RANGE,
UPSTREAM_CONFIGURATION_WIKI_LINK,
} from '../../../../helpers/constants';

import { testUpstreamWithFormValues } from '../../../../actions';

Expand All @@ -17,6 +28,7 @@ import { removeEmptyLines, trimLinesAndRemoveEmpty } from '../../../../helpers/h
import { getTextareaCommentsHighlight, syncScroll } from '../../../../helpers/highlightTextareaComments';
import '../../../ui/texareaCommentsHighlight.css';
import { RootState } from '../../../../initialState';
import { validateRequiredValue } from '../../../../helpers/validators';

const UPSTREAM_DNS_NAME = 'upstream_dns';
const UPSTREAM_MODE_NAME = 'upstream_mode';
Expand Down Expand Up @@ -301,7 +313,7 @@ const Form = ({ submitting, invalid, handleSubmit }: FormProps) => {
<hr />
</div>

<div className="col-12 mb-4">
<div className="col-12">
<Field
name="resolve_clients"
type="checkbox"
Expand All @@ -311,6 +323,34 @@ const Form = ({ submitting, invalid, handleSubmit }: FormProps) => {
disabled={processingSetConfig}
/>
</div>

<div className="col-12">
<hr />
</div>

<div className="col-12 col-md-7">
<div className="form__group">
<label htmlFor="upstream_timeout" className="form__label form__label--with-desc">
<Trans>upstream_timeout</Trans>
</label>

<div className="form__desc form__desc--top">
<Trans>upstream_timeout_desc</Trans>
</div>

<Field
name="upstream_timeout"
type="number"
component={renderInputField}
className="form-control"
placeholder={t('form_enter_upstream_timeout')}
normalize={toNumber}
validate={validateRequiredValue}
min={1}
max={UINT32_RANGE.MAX}
/>
</div>
</div>
</div>

<div className="card-actions">
Expand Down
4 changes: 4 additions & 0 deletions client/src/components/Settings/Dns/Upstream/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const Upstream = () => {
resolve_clients,
local_ptr_upstreams,
use_private_ptr_resolvers,
upstream_timeout,
} = useSelector((state: RootState) => state.dnsConfig, shallowEqual);

const upstream_dns_file = useSelector((state: RootState) => state.dnsConfig.upstream_dns_file);
Expand All @@ -32,6 +33,7 @@ const Upstream = () => {
resolve_clients,
local_ptr_upstreams,
use_private_ptr_resolvers,
upstream_timeout,
} = values;

const dnsConfig = {
Expand All @@ -41,6 +43,7 @@ const Upstream = () => {
resolve_clients,
local_ptr_upstreams,
use_private_ptr_resolvers,
upstream_timeout,
...(upstream_dns_file ? null : { upstream_dns }),
};

Expand All @@ -64,6 +67,7 @@ const Upstream = () => {
resolve_clients,
local_ptr_upstreams,
use_private_ptr_resolvers,
upstream_timeout,
}}
onSubmit={handleSubmit}
/>
Expand Down
2 changes: 2 additions & 0 deletions client/src/initialState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ export type DnsConfigData = {
blocking_ipv4: string;
blocking_ipv6: string;
blocked_response_ttl: number;
upstream_timeout: number;
edns_cs_enabled: boolean;
disable_ipv6: boolean;
dnssec_enabled: boolean;
Expand Down Expand Up @@ -489,6 +490,7 @@ export const initialState: RootState = {
blocking_ipv4: DEFAULT_BLOCKING_IPV4,
blocking_ipv6: DEFAULT_BLOCKING_IPV6,
blocked_response_ttl: 10,
upstream_timeout: 10,
edns_cs_enabled: false,
disable_ipv6: false,
dnssec_enabled: false,
Expand Down
1 change: 1 addition & 0 deletions client/src/reducers/dnsConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ const dnsConfig = handleActions(
blocking_ipv4: DEFAULT_BLOCKING_IPV4,
blocking_ipv6: DEFAULT_BLOCKING_IPV6,
blocked_response_ttl: 10,
upstream_timeout: 10,
edns_cs_enabled: false,
disable_ipv6: false,
dnssec_enabled: false,
Expand Down
8 changes: 8 additions & 0 deletions internal/dnsforward/dnsforward.go
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,14 @@ func (s *Server) AddrProcConfig() (c *client.DefaultAddrProcConfig) {
}
}

// UpstreamTimeout returns the current upstream timeout configuration.
func (s *Server) UpstreamTimeout() (t time.Duration) {
s.serverLock.RLock()
defer s.serverLock.RUnlock()

return s.conf.UpstreamTimeout
}

// Resolve gets IP addresses by host name from an upstream server. No
// request/response filtering is performed. Query log and Stats are not
// updated. This method may be called before [Server.Start].
Expand Down
30 changes: 30 additions & 0 deletions internal/dnsforward/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/stringutil"
"github.com/AdguardTeam/golibs/validate"
)

// jsonDNSConfig is the JSON representation of the DNS server configuration.
Expand Down Expand Up @@ -53,6 +54,9 @@ type jsonDNSConfig struct {
// rate limiting requests.
RatelimitSubnetLenIPv6 *int `json:"ratelimit_subnet_len_ipv6"`

// UpstreamTimeout is an upstream timeout in seconds.
UpstreamTimeout *int `json:"upstream_timeout"`

// RatelimitWhitelist is a list of IP addresses excluded from rate limiting.
RatelimitWhitelist *[]netip.Addr `json:"ratelimit_whitelist"`

Expand Down Expand Up @@ -147,6 +151,7 @@ func (s *Server) getDNSConfig() (c *jsonDNSConfig) {
ratelimitSubnetLenIPv4 := s.conf.RatelimitSubnetLenIPv4
ratelimitSubnetLenIPv6 := s.conf.RatelimitSubnetLenIPv6
ratelimitWhitelist := append([]netip.Addr{}, s.conf.RatelimitWhitelist...)
upstreamTimeout := int(s.conf.UpstreamTimeout.Seconds())

customIP := s.conf.EDNSClientSubnet.CustomIP
enableEDNSClientSubnet := s.conf.EDNSClientSubnet.Enabled
Expand Down Expand Up @@ -192,6 +197,7 @@ func (s *Server) getDNSConfig() (c *jsonDNSConfig) {
RatelimitSubnetLenIPv4: &ratelimitSubnetLenIPv4,
RatelimitSubnetLenIPv6: &ratelimitSubnetLenIPv6,
RatelimitWhitelist: &ratelimitWhitelist,
UpstreamTimeout: &upstreamTimeout,
EDNSCSCustomIP: customIP,
EDNSCSEnabled: &enableEDNSClientSubnet,
EDNSCSUseCustom: &useCustom,
Expand Down Expand Up @@ -302,6 +308,12 @@ func (req *jsonDNSConfig) validate(
return err
}

err = req.checkUpstreamTimeout()
if err != nil {
// Don't wrap the error since it's informative enough as is.
return err
}

return nil
}

Expand Down Expand Up @@ -437,6 +449,16 @@ func (req *jsonDNSConfig) checkRatelimitSubnetMaskLen() (err error) {
return nil
}

// checkUpstreamTimeout returns an error if the configuration of the upstream
// timeout is invalid.
func (req *jsonDNSConfig) checkUpstreamTimeout() (err error) {
if req.UpstreamTimeout == nil {
return nil
}

return validate.NoLessThan("upstream_timeout", *req.UpstreamTimeout, 1)
}

// checkInclusion returns an error if a ptr is not nil and points to value,
// that not in the inclusive range between minN and maxN.
func checkInclusion(ptr *int, minN, maxN int) (err error) {
Expand Down Expand Up @@ -588,6 +610,14 @@ func (s *Server) setConfigRestartable(dc *jsonDNSConfig) (shouldRestart bool) {
shouldRestart = true
}

if dc.UpstreamTimeout != nil {
ut := time.Duration(*dc.UpstreamTimeout) * time.Second
if s.conf.UpstreamTimeout != ut {
s.conf.UpstreamTimeout = ut
shouldRestart = true
}
}

return shouldRestart
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"blocking_ipv4": "",
"blocking_ipv6": "",
"blocked_response_ttl": 10,
"upstream_timeout": 10,
"edns_cs_enabled": false,
"dnssec_enabled": false,
"disable_ipv6": false,
Expand Down Expand Up @@ -63,6 +64,7 @@
"blocking_ipv4": "",
"blocking_ipv6": "",
"blocked_response_ttl": 10,
"upstream_timeout": 10,
"edns_cs_enabled": false,
"dnssec_enabled": false,
"disable_ipv6": false,
Expand Down Expand Up @@ -102,6 +104,7 @@
"blocking_ipv4": "",
"blocking_ipv6": "",
"blocked_response_ttl": 10,
"upstream_timeout": 10,
"edns_cs_enabled": false,
"dnssec_enabled": false,
"disable_ipv6": false,
Expand Down
Loading

0 comments on commit 2fe2d25

Please sign in to comment.