Skip to content

Commit

Permalink
all: upstream timeout
Browse files Browse the repository at this point in the history
  • Loading branch information
schzhn committed Feb 3, 2025
1 parent d3dea0f commit 95c7369
Show file tree
Hide file tree
Showing 13 changed files with 160 additions and 1 deletion.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ See also the [v0.107.57 GitHub milestone][ms-v0.107.57].
NOTE: Add new changes BELOW THIS COMMENT.
-->

### Added

- An option 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
5 changes: 4 additions & 1 deletion client/src/__locales/en.json
Original file line number Diff line number Diff line change
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 all DNS servers, measure TCP connection speed for each IP address, and return the IP address with the fastest connection speed. This can significantly slow down DNS queries if any of the upstream servers is not responding, so 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
24 changes: 24 additions & 0 deletions client/src/components/Settings/Dns/Config/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,30 @@ const Form = ({ handleSubmit, submitting, invalid, processing }: ConfigFormProps
/>
</div>
</div>

<div className="col-12 col-md-7">
<div className="form__group form__group--settings">
<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={100}
/>
</div>
</div>
</div>

<button
Expand Down
2 changes: 2 additions & 0 deletions client/src/components/Settings/Dns/Config/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const Config = () => {
blocking_ipv4,
blocking_ipv6,
blocked_response_ttl,
upstream_timeout,
edns_cs_enabled,
edns_cs_use_custom,
edns_cs_custom_ip,
Expand All @@ -45,6 +46,7 @@ const Config = () => {
blocking_ipv4,
blocking_ipv6,
blocked_response_ttl,
upstream_timeout,
edns_cs_enabled,
disable_ipv6,
dnssec_enabled,
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
9 changes: 9 additions & 0 deletions internal/dnsforward/dnsforward.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/netutil/sysresolv"
"github.com/AdguardTeam/golibs/stringutil"
"github.com/AdguardTeam/golibs/timeutil"
"github.com/miekg/dns"
)

Expand Down Expand Up @@ -329,6 +330,14 @@ func (s *Server) AddrProcConfig() (c *client.DefaultAddrProcConfig) {
}
}

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

return timeutil.Duration(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
34 changes: 34 additions & 0 deletions internal/dnsforward/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,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 +150,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 +196,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 +307,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 +448,21 @@ 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
}

t := *req.UpstreamTimeout
if t <= 1 || t >= 100 {
return fmt.Errorf("upstream_timeout: %w", errors.ErrOutOfRange)
}

return nil
}

// 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 +614,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 95c7369

Please sign in to comment.