Pull request 2100: v0.107.42-rc

Squashed commit of the following:

commit 284190f748345c7556e60b67f051ec5f6f080948
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Dec 6 19:36:00 2023 +0300

    all: sync with master; upd chlog
This commit is contained in:
Ainar Garipov
2023-12-07 17:23:00 +03:00
parent df91f016f2
commit 25918e56fa
148 changed files with 7204 additions and 1705 deletions

View File

@@ -14,12 +14,13 @@ import (
// Client contains information about persistent clients.
type Client struct {
// upstreamConfig is the custom upstream config for this client. If
// it's nil, it has not been initialized yet. If it's non-nil and
// empty, there are no valid upstreams. If it's non-nil and non-empty,
// these upstream must be used.
upstreamConfig *proxy.UpstreamConfig
// upstreamConfig is the custom upstream configuration for this client. If
// it's nil, it has not been initialized yet. If it's non-nil and empty,
// there are no valid upstreams. If it's non-nil and non-empty, these
// upstream must be used.
upstreamConfig *proxy.CustomUpstreamConfig
// TODO(d.kolyshev): Make safeSearchConf a pointer.
safeSearchConf filtering.SafeSearchConfig
SafeSearch filtering.SafeSearch
@@ -32,6 +33,9 @@ type Client struct {
Tags []string
Upstreams []string
UpstreamsCacheSize uint32
UpstreamsCacheEnabled bool
UseOwnSettings bool
FilteringEnabled bool
SafeBrowsingEnabled bool
@@ -57,8 +61,7 @@ func (c *Client) ShallowClone() (sh *Client) {
// closeUpstreams closes the client-specific upstream config of c if any.
func (c *Client) closeUpstreams() (err error) {
if c.upstreamConfig != nil {
err = c.upstreamConfig.Close()
if err != nil {
if err = c.upstreamConfig.Close(); err != nil {
return fmt.Errorf("closing upstreams of client %q: %w", c.Name, err)
}
}

View File

@@ -126,7 +126,13 @@ func (clients *clientsContainer) Init(
return nil
}
if clients.etcHosts != nil {
// The clients.etcHosts may be nil even if config.Clients.Sources.HostsFile
// is true, because of the deprecated option --no-etc-hosts.
//
// TODO(e.burkov): The option should probably be returned, since hosts file
// currently used not only for clients' information enrichment, but also in
// the filtering module and upstream addresses resolution.
if config.Clients.Sources.HostsFile && clients.etcHosts != nil {
go clients.handleHostsUpdates()
}
@@ -179,6 +185,14 @@ type clientObject struct {
Tags []string `yaml:"tags"`
Upstreams []string `yaml:"upstreams"`
// UpstreamsCacheSize is the DNS cache size (in bytes).
//
// TODO(d.kolyshev): Use [datasize.Bytesize].
UpstreamsCacheSize uint32 `yaml:"upstreams_cache_size"`
// UpstreamsCacheEnabled indicates if the DNS cache is enabled.
UpstreamsCacheEnabled bool `yaml:"upstreams_cache_enabled"`
UseGlobalSettings bool `yaml:"use_global_settings"`
FilteringEnabled bool `yaml:"filtering_enabled"`
ParentalEnabled bool `yaml:"parental_enabled"`
@@ -210,6 +224,8 @@ func (clients *clientsContainer) addFromConfig(
UseOwnBlockedServices: !o.UseGlobalBlockedServices,
IgnoreQueryLog: o.IgnoreQueryLog,
IgnoreStatistics: o.IgnoreStatistics,
UpstreamsCacheEnabled: o.UpstreamsCacheEnabled,
UpstreamsCacheSize: o.UpstreamsCacheSize,
}
if o.SafeSearchConf.Enabled {
@@ -278,6 +294,8 @@ func (clients *clientsContainer) forConfig() (objs []*clientObject) {
UseGlobalBlockedServices: !cli.UseOwnBlockedServices,
IgnoreQueryLog: cli.IgnoreQueryLog,
IgnoreStatistics: cli.IgnoreStatistics,
UpstreamsCacheEnabled: cli.UpstreamsCacheEnabled,
UpstreamsCacheSize: cli.UpstreamsCacheSize,
}
objs = append(objs, o)
@@ -419,18 +437,24 @@ func (clients *clientsContainer) shouldCountClient(ids []string) (y bool) {
return true
}
// findUpstreams returns upstreams configured for the client, identified either
// by its IP address or its ClientID. upsConf is nil if the client isn't found
// or if the client has no custom upstreams.
func (clients *clientsContainer) findUpstreams(
// type check
var _ dnsforward.ClientsContainer = (*clientsContainer)(nil)
// UpstreamConfigByID implements the [dnsforward.ClientsContainer] interface for
// *clientsContainer. upsConf is nil if the client isn't found or if the client
// has no custom upstreams.
func (clients *clientsContainer) UpstreamConfigByID(
id string,
) (upsConf *proxy.UpstreamConfig, err error) {
bootstrap upstream.Resolver,
) (conf *proxy.CustomUpstreamConfig, err error) {
clients.lock.Lock()
defer clients.lock.Unlock()
c, ok := clients.findLocked(id)
if !ok {
return nil, nil
} else if c.upstreamConfig != nil {
return c.upstreamConfig, nil
}
upstreams := stringutil.FilterOut(c.Upstreams, dnsforward.IsCommentOrEmpty)
@@ -438,24 +462,27 @@ func (clients *clientsContainer) findUpstreams(
return nil, nil
}
if c.upstreamConfig != nil {
return c.upstreamConfig, nil
}
var conf *proxy.UpstreamConfig
conf, err = proxy.ParseUpstreamsConfig(
var upsConf *proxy.UpstreamConfig
upsConf, err = proxy.ParseUpstreamsConfig(
upstreams,
&upstream.Options{
Bootstrap: config.DNS.BootstrapDNS,
Bootstrap: bootstrap,
Timeout: config.DNS.UpstreamTimeout.Duration,
HTTPVersions: dnsforward.UpstreamHTTPVersions(config.DNS.UseHTTP3Upstreams),
PreferIPv6: config.DNS.BootstrapPreferIPv6,
},
)
if err != nil {
// Don't wrap the error since it's informative enough as is.
return nil, err
}
conf = proxy.NewCustomUpstreamConfig(
upsConf,
c.UpstreamsCacheEnabled,
int(c.UpstreamsCacheSize),
config.DNS.EDNSClientSubnet.Enabled,
)
c.upstreamConfig = conf
return conf, nil
@@ -672,10 +699,6 @@ func (clients *clientsContainer) Del(name string) (ok bool) {
return false
}
if err := c.closeUpstreams(); err != nil {
log.Error("client container: removing client %s: %s", name, err)
}
clients.del(c)
return true
@@ -683,10 +706,14 @@ func (clients *clientsContainer) Del(name string) (ok bool) {
// del removes c from the indexes. clients.lock is expected to be locked.
func (clients *clientsContainer) del(c *Client) {
// update Name index
if err := c.closeUpstreams(); err != nil {
log.Error("client container: removing client %s: %s", c.Name, err)
}
// Update the name index.
delete(clients.list, c.Name)
// update ID index
// Update the ID index.
for _, id := range c.IDs {
delete(clients.idIndex, id)
}

View File

@@ -314,7 +314,7 @@ func TestClientsAddExisting(t *testing.T) {
clients.dhcp = dhcpServer
err = dhcpServer.AddStaticLease(&dhcpd.Lease{
err = dhcpServer.AddStaticLease(&dhcpsvc.Lease{
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
IP: ip,
Hostname: "testhost",
@@ -355,13 +355,11 @@ func TestClientsCustomUpstream(t *testing.T) {
require.NoError(t, err)
assert.True(t, ok)
config, err := clients.findUpstreams("1.2.3.4")
assert.Nil(t, config)
upsConf, err := clients.UpstreamConfigByID("1.2.3.4", net.DefaultResolver)
assert.Nil(t, upsConf)
assert.NoError(t, err)
config, err = clients.findUpstreams("1.1.1.1")
require.NotNil(t, config)
upsConf, err = clients.UpstreamConfigByID("1.1.1.1", net.DefaultResolver)
require.NotNil(t, upsConf)
assert.NoError(t, err)
assert.Len(t, config.Upstreams, 1)
assert.Len(t, config.DomainReservedUpstreams, 1)
}

View File

@@ -56,34 +56,9 @@ type clientJSON struct {
IgnoreQueryLog aghalg.NullBool `json:"ignore_querylog"`
IgnoreStatistics aghalg.NullBool `json:"ignore_statistics"`
}
// copySettings returns a copy of specific settings from JSON or a previous
// client.
func (j *clientJSON) copySettings(
prev *Client,
) (weekly *schedule.Weekly, ignoreQueryLog, ignoreStatistics bool) {
if j.Schedule != nil {
weekly = j.Schedule.Clone()
} else if prev != nil && prev.BlockedServices != nil {
weekly = prev.BlockedServices.Schedule.Clone()
} else {
weekly = schedule.EmptyWeekly()
}
if j.IgnoreQueryLog != aghalg.NBNull {
ignoreQueryLog = j.IgnoreQueryLog == aghalg.NBTrue
} else if prev != nil {
ignoreQueryLog = prev.IgnoreQueryLog
}
if j.IgnoreStatistics != aghalg.NBNull {
ignoreStatistics = j.IgnoreStatistics == aghalg.NBTrue
} else if prev != nil {
ignoreStatistics = prev.IgnoreStatistics
}
return weekly, ignoreQueryLog, ignoreStatistics
UpstreamsCacheSize uint32 `json:"upstreams_cache_size"`
UpstreamsCacheEnabled aghalg.NullBool `json:"upstreams_cache_enabled"`
}
type runtimeClientJSON struct {
@@ -142,36 +117,35 @@ func (clients *clientsContainer) handleGetClients(w http.ResponseWriter, r *http
// jsonToClient converts JSON object to Client object.
func (clients *clientsContainer) jsonToClient(cj clientJSON, prev *Client) (c *Client, err error) {
var safeSearchConf filtering.SafeSearchConfig
if cj.SafeSearchConf != nil {
safeSearchConf = *cj.SafeSearchConf
} else {
// TODO(d.kolyshev): Remove after cleaning the deprecated
// [clientJSON.SafeSearchEnabled] field.
safeSearchConf = filtering.SafeSearchConfig{
Enabled: cj.SafeSearchEnabled,
}
safeSearchConf := copySafeSearch(cj.SafeSearchConf, cj.SafeSearchEnabled)
// Set default service flags for enabled safesearch.
if safeSearchConf.Enabled {
safeSearchConf.Bing = true
safeSearchConf.DuckDuckGo = true
safeSearchConf.Google = true
safeSearchConf.Pixabay = true
safeSearchConf.Yandex = true
safeSearchConf.YouTube = true
}
var ignoreQueryLog bool
if cj.IgnoreQueryLog != aghalg.NBNull {
ignoreQueryLog = cj.IgnoreQueryLog == aghalg.NBTrue
} else if prev != nil {
ignoreQueryLog = prev.IgnoreQueryLog
}
weekly, ignoreQueryLog, ignoreStatistics := cj.copySettings(prev)
bs := &filtering.BlockedServices{
Schedule: weekly,
IDs: cj.BlockedServices,
var ignoreStatistics bool
if cj.IgnoreStatistics != aghalg.NBNull {
ignoreStatistics = cj.IgnoreStatistics == aghalg.NBTrue
} else if prev != nil {
ignoreStatistics = prev.IgnoreStatistics
}
err = bs.Validate()
var upsCacheEnabled bool
var upsCacheSize uint32
if cj.UpstreamsCacheEnabled != aghalg.NBNull {
upsCacheEnabled = cj.UpstreamsCacheEnabled == aghalg.NBTrue
upsCacheSize = cj.UpstreamsCacheSize
} else if prev != nil {
upsCacheEnabled = prev.UpstreamsCacheEnabled
upsCacheSize = prev.UpstreamsCacheSize
}
svcs, err := copyBlockedServices(cj.Schedule, cj.BlockedServices, prev)
if err != nil {
return nil, fmt.Errorf("validating blocked services: %w", err)
return nil, fmt.Errorf("invalid blocked services: %w", err)
}
c = &Client{
@@ -179,7 +153,7 @@ func (clients *clientsContainer) jsonToClient(cj clientJSON, prev *Client) (c *C
Name: cj.Name,
BlockedServices: bs,
BlockedServices: svcs,
IDs: cj.IDs,
Tags: cj.Tags,
@@ -192,6 +166,8 @@ func (clients *clientsContainer) jsonToClient(cj clientJSON, prev *Client) (c *C
UseOwnBlockedServices: !cj.UseGlobalBlockedServices,
IgnoreQueryLog: ignoreQueryLog,
IgnoreStatistics: ignoreStatistics,
UpstreamsCacheEnabled: upsCacheEnabled,
UpstreamsCacheSize: upsCacheSize,
}
if safeSearchConf.Enabled {
@@ -208,6 +184,63 @@ func (clients *clientsContainer) jsonToClient(cj clientJSON, prev *Client) (c *C
return c, nil
}
// copySafeSearch returns safe search config created from provided parameters.
func copySafeSearch(
jsonConf *filtering.SafeSearchConfig,
enabled bool,
) (conf filtering.SafeSearchConfig) {
if jsonConf != nil {
return *jsonConf
}
// TODO(d.kolyshev): Remove after cleaning the deprecated
// [clientJSON.SafeSearchEnabled] field.
conf = filtering.SafeSearchConfig{
Enabled: enabled,
}
// Set default service flags for enabled safesearch.
if conf.Enabled {
conf.Bing = true
conf.DuckDuckGo = true
conf.Google = true
conf.Pixabay = true
conf.Yandex = true
conf.YouTube = true
}
return conf
}
// copyBlockedServices converts a json blocked services to an internal blocked
// services.
func copyBlockedServices(
sch *schedule.Weekly,
svcStrs []string,
prev *Client,
) (svcs *filtering.BlockedServices, err error) {
var weekly *schedule.Weekly
if sch != nil {
weekly = sch.Clone()
} else if prev != nil && prev.BlockedServices != nil {
weekly = prev.BlockedServices.Schedule.Clone()
} else {
weekly = schedule.EmptyWeekly()
}
svcs = &filtering.BlockedServices{
Schedule: weekly,
IDs: svcStrs,
}
err = svcs.Validate()
if err != nil {
return nil, fmt.Errorf("validating blocked services: %w", err)
}
return svcs, nil
}
// clientToJSON converts Client object to JSON.
func clientToJSON(c *Client) (cj *clientJSON) {
// TODO(d.kolyshev): Remove after cleaning the deprecated
@@ -235,6 +268,9 @@ func clientToJSON(c *Client) (cj *clientJSON) {
IgnoreQueryLog: aghalg.BoolToNullBool(c.IgnoreQueryLog),
IgnoreStatistics: aghalg.BoolToNullBool(c.IgnoreStatistics),
UpstreamsCacheSize: c.UpstreamsCacheSize,
UpstreamsCacheEnabled: aghalg.BoolToNullBool(c.UpstreamsCacheEnabled),
}
}

View File

@@ -115,6 +115,8 @@ type configuration struct {
// Theme is a UI theme for current user.
Theme Theme `yaml:"theme"`
// TODO(a.garipov): Make DNS and the fields below pointers and validate
// and/or reset on explicit nulling.
DNS dnsConfig `yaml:"dns"`
TLS tlsConfigSettings `yaml:"tls"`
QueryLog queryLogConfig `yaml:"querylog"`
@@ -214,18 +216,21 @@ type dnsConfig struct {
// DNS64Prefixes is the list of NAT64 prefixes to be used for DNS64.
DNS64Prefixes []netip.Prefix `yaml:"dns64_prefixes"`
// ServeHTTP3 defines if HTTP/3 is be allowed for incoming requests.
// ServeHTTP3 defines if HTTP/3 is allowed for incoming requests.
//
// TODO(a.garipov): Add to the UI when HTTP/3 support is no longer
// experimental.
ServeHTTP3 bool `yaml:"serve_http3"`
// UseHTTP3Upstreams defines if HTTP/3 is be allowed for DNS-over-HTTPS
// UseHTTP3Upstreams defines if HTTP/3 is allowed for DNS-over-HTTPS
// upstreams.
//
// TODO(a.garipov): Add to the UI when HTTP/3 support is no longer
// experimental.
UseHTTP3Upstreams bool `yaml:"use_http3_upstreams"`
// ServePlainDNS defines if plain DNS is allowed for incoming requests.
ServePlainDNS bool `yaml:"serve_plain_dns"`
}
type tlsConfigSettings struct {
@@ -333,6 +338,7 @@ var config = &configuration{
},
UpstreamTimeout: timeutil.Duration{Duration: dnsforward.DefaultTimeout},
UsePrivateRDNS: true,
ServePlainDNS: true,
},
TLS: tlsConfigSettings{
PortHTTPS: defaultPortHTTPS,

View File

@@ -138,28 +138,28 @@ func initDNSServer(
QueryLog: qlog,
PrivateNets: privateNets,
Anonymizer: anonymizer,
LocalDomain: config.DHCP.LocalDomainName,
DHCPServer: dhcpSrv,
EtcHosts: Context.etcHosts,
LocalDomain: config.DHCP.LocalDomainName,
})
defer func() {
if err != nil {
closeDNSServer()
}
}()
if err != nil {
closeDNSServer()
return fmt.Errorf("dnsforward.NewServer: %w", err)
}
Context.clients.dnsServer = Context.dnsServer
dnsConf, err := newServerConfig(tlsConf, httpReg)
dnsConf, err := newServerConfig(&config.DNS, config.Clients.Sources, tlsConf, httpReg)
if err != nil {
closeDNSServer()
return fmt.Errorf("newServerConfig: %w", err)
}
err = Context.dnsServer.Prepare(dnsConf)
if err != nil {
closeDNSServer()
return fmt.Errorf("dnsServer.Prepare: %w", err)
}
@@ -222,21 +222,37 @@ func ipsToUDPAddrs(ips []netip.Addr, port uint16) (udpAddrs []*net.UDPAddr) {
return udpAddrs
}
// newServerConfig converts values from the configuration file into the internal
// DNS server configuration. All arguments must not be nil.
func newServerConfig(
dnsConf *dnsConfig,
clientSrcConf *clientSourcesConfig,
tlsConf *tlsConfigSettings,
httpReg aghhttp.RegisterFunc,
) (newConf *dnsforward.ServerConfig, err error) {
dnsConf := config.DNS
hosts := aghalg.CoalesceSlice(dnsConf.BindHosts, []netip.Addr{netutil.IPv4Localhost()})
fwdConf := dnsConf.Config
fwdConf.FilterHandler = applyAdditionalFiltering
fwdConf.ClientsContainer = &Context.clients
newConf = &dnsforward.ServerConfig{
UDPListenAddrs: ipsToUDPAddrs(hosts, dnsConf.Port),
TCPListenAddrs: ipsToTCPAddrs(hosts, dnsConf.Port),
Config: dnsConf.Config,
ConfigModified: onConfigModified,
HTTPRegister: httpReg,
UseDNS64: config.DNS.UseDNS64,
DNS64Prefixes: config.DNS.DNS64Prefixes,
UDPListenAddrs: ipsToUDPAddrs(hosts, dnsConf.Port),
TCPListenAddrs: ipsToTCPAddrs(hosts, dnsConf.Port),
Config: fwdConf,
TLSConfig: newDNSTLSConfig(tlsConf, hosts),
TLSAllowUnencryptedDoH: tlsConf.AllowUnencryptedDoH,
UpstreamTimeout: dnsConf.UpstreamTimeout.Duration,
TLSv12Roots: Context.tlsRoots,
ConfigModified: onConfigModified,
HTTPRegister: httpReg,
LocalPTRResolvers: dnsConf.LocalPTRResolvers,
UseDNS64: dnsConf.UseDNS64,
DNS64Prefixes: dnsConf.DNS64Prefixes,
UsePrivateRDNS: dnsConf.UsePrivateRDNS,
ServeHTTP3: dnsConf.ServeHTTP3,
UseHTTP3Upstreams: dnsConf.UseHTTP3Upstreams,
ServePlainDNS: dnsConf.ServePlainDNS,
}
var initialAddresses []netip.Addr
@@ -254,79 +270,81 @@ func newServerConfig(
AddressUpdater: &Context.clients,
InitialAddresses: initialAddresses,
CatchPanics: true,
UseRDNS: config.Clients.Sources.RDNS,
UseWHOIS: config.Clients.Sources.WHOIS,
UseRDNS: clientSrcConf.RDNS,
UseWHOIS: clientSrcConf.WHOIS,
}
if tlsConf.Enabled {
newConf.TLSConfig = tlsConf.TLSConfig
newConf.TLSConfig.ServerName = tlsConf.ServerName
if tlsConf.PortHTTPS != 0 {
newConf.HTTPSListenAddrs = ipsToTCPAddrs(hosts, tlsConf.PortHTTPS)
}
if tlsConf.PortDNSOverTLS != 0 {
newConf.TLSListenAddrs = ipsToTCPAddrs(hosts, tlsConf.PortDNSOverTLS)
}
if tlsConf.PortDNSOverQUIC != 0 {
newConf.QUICListenAddrs = ipsToUDPAddrs(hosts, tlsConf.PortDNSOverQUIC)
}
if tlsConf.PortDNSCrypt != 0 {
newConf.DNSCryptConfig, err = newDNSCrypt(hosts, *tlsConf)
if err != nil {
// Don't wrap the error, because it's already wrapped by
// newDNSCrypt.
return nil, err
}
}
newConf.DNSCryptConfig, err = newDNSCryptConfig(tlsConf, hosts)
if err != nil {
// Don't wrap the error, because it's already wrapped by
// newDNSCryptConfig.
return nil, err
}
newConf.TLSv12Roots = Context.tlsRoots
newConf.TLSAllowUnencryptedDoH = tlsConf.AllowUnencryptedDoH
newConf.FilterHandler = applyAdditionalFiltering
newConf.GetCustomUpstreamByClient = Context.clients.findUpstreams
newConf.LocalPTRResolvers = dnsConf.LocalPTRResolvers
newConf.UpstreamTimeout = dnsConf.UpstreamTimeout.Duration
newConf.UsePrivateRDNS = dnsConf.UsePrivateRDNS
newConf.ServeHTTP3 = dnsConf.ServeHTTP3
newConf.UseHTTP3Upstreams = dnsConf.UseHTTP3Upstreams
return newConf, nil
}
func newDNSCrypt(hosts []netip.Addr, tlsConf tlsConfigSettings) (dnscc dnsforward.DNSCryptConfig, err error) {
if tlsConf.DNSCryptConfigFile == "" {
return dnscc, errors.Error("no dnscrypt_config_file")
// newDNSTLSConfig converts values from the configuration file into the internal
// TLS settings for the DNS server. tlsConf must not be nil.
func newDNSTLSConfig(conf *tlsConfigSettings, addrs []netip.Addr) (dnsConf dnsforward.TLSConfig) {
if !conf.Enabled {
return dnsforward.TLSConfig{}
}
f, err := os.Open(tlsConf.DNSCryptConfigFile)
dnsConf = conf.TLSConfig
dnsConf.ServerName = conf.ServerName
if conf.PortHTTPS != 0 {
dnsConf.HTTPSListenAddrs = ipsToTCPAddrs(addrs, conf.PortHTTPS)
}
if conf.PortDNSOverTLS != 0 {
dnsConf.TLSListenAddrs = ipsToTCPAddrs(addrs, conf.PortDNSOverTLS)
}
if conf.PortDNSOverQUIC != 0 {
dnsConf.QUICListenAddrs = ipsToUDPAddrs(addrs, conf.PortDNSOverQUIC)
}
return dnsConf
}
// newDNSCryptConfig converts values from the configuration file into the
// internal DNSCrypt settings for the DNS server. conf must not be nil.
func newDNSCryptConfig(
conf *tlsConfigSettings,
addrs []netip.Addr,
) (dnsCryptConf dnsforward.DNSCryptConfig, err error) {
if !conf.Enabled || conf.PortDNSCrypt == 0 {
return dnsforward.DNSCryptConfig{}, nil
}
if conf.DNSCryptConfigFile == "" {
return dnsforward.DNSCryptConfig{}, errors.Error("no dnscrypt_config_file")
}
f, err := os.Open(conf.DNSCryptConfigFile)
if err != nil {
return dnscc, fmt.Errorf("opening dnscrypt config: %w", err)
return dnsforward.DNSCryptConfig{}, fmt.Errorf("opening dnscrypt config: %w", err)
}
defer func() { err = errors.WithDeferred(err, f.Close()) }()
rc := &dnscrypt.ResolverConfig{}
err = yaml.NewDecoder(f).Decode(rc)
if err != nil {
return dnscc, fmt.Errorf("decoding dnscrypt config: %w", err)
return dnsforward.DNSCryptConfig{}, fmt.Errorf("decoding dnscrypt config: %w", err)
}
cert, err := rc.CreateCert()
if err != nil {
return dnscc, fmt.Errorf("creating dnscrypt cert: %w", err)
return dnsforward.DNSCryptConfig{}, fmt.Errorf("creating dnscrypt cert: %w", err)
}
return dnsforward.DNSCryptConfig{
ResolverCert: cert,
ProviderName: rc.ProviderName,
UDPListenAddrs: ipsToUDPAddrs(hosts, tlsConf.PortDNSCrypt),
TCPListenAddrs: ipsToTCPAddrs(hosts, tlsConf.PortDNSCrypt),
UDPListenAddrs: ipsToUDPAddrs(addrs, conf.PortDNSCrypt),
TCPListenAddrs: ipsToTCPAddrs(addrs, conf.PortDNSCrypt),
Enabled: true,
}, nil
}
@@ -342,34 +360,36 @@ func getDNSEncryption() (de dnsEncryption) {
Context.tls.WriteDiskConfig(&tlsConf)
if tlsConf.Enabled && len(tlsConf.ServerName) != 0 {
hostname := tlsConf.ServerName
if tlsConf.PortHTTPS != 0 {
addr := hostname
if p := tlsConf.PortHTTPS; p != defaultPortHTTPS {
addr = netutil.JoinHostPort(addr, p)
}
if !tlsConf.Enabled || len(tlsConf.ServerName) == 0 {
return dnsEncryption{}
}
de.https = (&url.URL{
Scheme: "https",
Host: addr,
Path: "/dns-query",
}).String()
hostname := tlsConf.ServerName
if tlsConf.PortHTTPS != 0 {
addr := hostname
if p := tlsConf.PortHTTPS; p != defaultPortHTTPS {
addr = netutil.JoinHostPort(addr, p)
}
if p := tlsConf.PortDNSOverTLS; p != 0 {
de.tls = (&url.URL{
Scheme: "tls",
Host: netutil.JoinHostPort(hostname, p),
}).String()
}
de.https = (&url.URL{
Scheme: "https",
Host: addr,
Path: "/dns-query",
}).String()
}
if p := tlsConf.PortDNSOverQUIC; p != 0 {
de.quic = (&url.URL{
Scheme: "quic",
Host: netutil.JoinHostPort(hostname, p),
}).String()
}
if p := tlsConf.PortDNSOverTLS; p != 0 {
de.tls = (&url.URL{
Scheme: "tls",
Host: netutil.JoinHostPort(hostname, p),
}).String()
}
if p := tlsConf.PortDNSOverQUIC; p != 0 {
de.quic = (&url.URL{
Scheme: "quic",
Host: netutil.JoinHostPort(hostname, p),
}).String()
}
return de
@@ -454,7 +474,7 @@ func reconfigureDNSServer() (err error) {
tlsConf := &tlsConfigSettings{}
Context.tls.WriteDiskConfig(tlsConf)
newConf, err := newServerConfig(tlsConf, httpRegister)
newConf, err := newServerConfig(&config.DNS, config.Clients.Sources, tlsConf, httpRegister)
if err != nil {
return fmt.Errorf("generating forwarding dns server config: %w", err)
}
@@ -520,11 +540,13 @@ type safeSearchResolver struct{}
var _ filtering.Resolver = safeSearchResolver{}
// LookupIP implements [filtering.Resolver] interface for safeSearchResolver.
// It returns the slice of net.IP with IPv4 and IPv6 instances.
//
// TODO(a.garipov): Support network.
func (r safeSearchResolver) LookupIP(_ context.Context, _, host string) (ips []net.IP, err error) {
addrs, err := Context.dnsServer.Resolve(host)
// It returns the slice of net.Addr with IPv4 and IPv6 instances.
func (r safeSearchResolver) LookupIP(
ctx context.Context,
network string,
host string,
) (ips []net.IP, err error) {
addrs, err := Context.dnsServer.Resolve(ctx, network, host)
if err != nil {
return nil, err
}
@@ -534,7 +556,7 @@ func (r safeSearchResolver) LookupIP(_ context.Context, _, host string) (ips []n
}
for _, a := range addrs {
ips = append(ips, a.IP)
ips = append(ips, a.AsSlice())
}
return ips, nil

View File

@@ -6,7 +6,6 @@ import (
"crypto/x509"
"fmt"
"io/fs"
"net"
"net/http"
"net/netip"
"net/url"
@@ -160,7 +159,7 @@ func setupContext(opts options) (err error) {
os.Exit(0)
}
if !opts.noEtcHosts && config.Clients.Sources.HostsFile {
if !opts.noEtcHosts {
err = setupHostsContainer()
if err != nil {
// Don't wrap the error, because it's informative enough as is.
@@ -239,13 +238,13 @@ func setupHostsContainer() (err error) {
)
if err != nil {
closeErr := hostsWatcher.Close()
if errors.Is(err, aghnet.ErrNoHostsPaths) && closeErr == nil {
if errors.Is(err, aghnet.ErrNoHostsPaths) {
log.Info("warning: initing hosts container: %s", err)
return nil
return closeErr
}
return errors.WithDeferred(fmt.Errorf("initing hosts container: %w", err), closeErr)
return errors.Join(fmt.Errorf("initializing hosts container: %w", err), closeErr)
}
return nil
@@ -294,19 +293,13 @@ func initContextClients() (err error) {
arpDB = arpdb.New()
}
err = Context.clients.Init(
return Context.clients.Init(
config.Clients.Persistent,
Context.dhcpServer,
Context.etcHosts,
arpDB,
config.Filtering,
)
if err != nil {
// Don't wrap the error, because it's informative enough as is.
return err
}
return nil
}
// setupBindOpts overrides bind host/port from the opts.
@@ -376,11 +369,15 @@ func setupDNSFilteringConf(conf *filtering.Config) (err error) {
upsOpts := &upstream.Options{
Timeout: dnsTimeout,
ServerIPAddrs: []net.IP{
{94, 140, 14, 15},
{94, 140, 15, 16},
net.ParseIP("2a10:50c0::bad1:ff"),
net.ParseIP("2a10:50c0::bad2:ff"),
Bootstrap: upstream.StaticResolver{
// 94.140.14.15.
netip.AddrFrom4([4]byte{94, 140, 14, 15}),
// 94.140.14.16.
netip.AddrFrom4([4]byte{94, 140, 14, 16}),
// 2a10:50c0::bad1:ff.
netip.AddrFrom16([16]byte{42, 16, 80, 192, 12: 186, 209, 0, 255}),
// 2a10:50c0::bad2:ff.
netip.AddrFrom16([16]byte{42, 16, 80, 192, 12: 186, 210, 0, 255}),
},
}