Skip to content

Commit

Permalink
Pull request 377: ADG-8932 Hosts
Browse files Browse the repository at this point in the history
Squashed commit of the following:

commit 3f18744
Author: Eugene Burkov <[email protected]>
Date:   Mon Aug 19 19:38:20 2024 +0300

    cmd: parse better

commit a44ba8c
Author: Eugene Burkov <[email protected]>
Date:   Mon Aug 19 19:35:36 2024 +0300

    handler: fix doc

commit 59750f9
Author: Eugene Burkov <[email protected]>
Date:   Mon Aug 19 19:32:48 2024 +0300

    all: fix go-flags

commit 8fec401
Author: Eugene Burkov <[email protected]>
Date:   Mon Aug 19 17:20:09 2024 +0300

    all: imp code, skel

commit 76d3cd6
Author: Eugene Burkov <[email protected]>
Date:   Mon Aug 19 16:40:26 2024 +0300

    all: imp code

commit 50f32a3
Author: Eugene Burkov <[email protected]>
Date:   Mon Aug 19 16:29:38 2024 +0300

    all: imp code, ifaces

commit cce416f
Author: Eugene Burkov <[email protected]>
Date:   Mon Aug 19 14:51:31 2024 +0300

    all: upd go, golibs

commit 5f56f30
Author: Eugene Burkov <[email protected]>
Date:   Mon Aug 19 14:38:37 2024 +0300

    all: hosts handler
  • Loading branch information
EugeneOne1 committed Aug 20, 2024
1 parent ae6b69c commit 25e110a
Show file tree
Hide file tree
Showing 20 changed files with 718 additions and 145 deletions.
29 changes: 19 additions & 10 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# Makefile. Bump this number every time a significant change is made to
# this Makefile.
#
# AdGuard-Project-Version: 5
# AdGuard-Project-Version: 6

# Don't name these macros "GO" etc., because GNU Make apparently makes
# them exported environment variables with the literal value of
Expand All @@ -24,19 +24,20 @@ BRANCH = $$( git rev-parse --abbrev-ref HEAD )
DIST_DIR = build
GOAMD64 = v1
GOPROXY = https://proxy.golang.org|direct
GOTOOLCHAIN = go1.22.5
GOTOOLCHAIN = go1.22.6
GOTELEMETRY = off
OUT = dnsproxy
RACE = 0
REVISION = $$( git rev-parse --short HEAD )
VERSION = 0

ENV = env\
BRANCH="$(BRANCH)"\
COMMIT='$(COMMIT)'\
DIST_DIR='$(DIST_DIR)'\
GO="$(GO.MACRO)"\
GOAMD64='$(GOAMD64)'\
GOPROXY='$(GOPROXY)'\
GOTELEMETRY='$(GOTELEMETRY)'\
GOTOOLCHAIN='$(GOTOOLCHAIN)'\
OUT='$(OUT)'\
PATH="$${PWD}/bin:$$( "$(GO.MACRO)" env GOPATH )/bin:$${PATH}"\
Expand All @@ -47,6 +48,11 @@ ENV = env\

# Keep the line above blank.

ENV_MISC = env\
VERBOSE="$(VERBOSE.MACRO)"\

# Keep the line above blank.

# Keep this target first, so that a naked make invocation triggers a
# full build.
build: go-deps go-build
Expand All @@ -55,13 +61,13 @@ init: ; git config core.hooksPath ./scripts/hooks

test: go-test

go-build: ; $(ENV) "$(SHELL)" ./scripts/make/go-build.sh
go-deps: ; $(ENV) "$(SHELL)" ./scripts/make/go-deps.sh
go-lint: ; $(ENV) "$(SHELL)" ./scripts/make/go-lint.sh
go-test: ; $(ENV) RACE='1' "$(SHELL)" ./scripts/make/go-test.sh
go-tools: ; $(ENV) "$(SHELL)" ./scripts/make/go-tools.sh

go-upd-tools: ; $(ENV) "$(SHELL)" ./scripts/make/go-upd-tools.sh
go-build: ; $(ENV) "$(SHELL)" ./scripts/make/go-build.sh
go-deps: ; $(ENV) "$(SHELL)" ./scripts/make/go-deps.sh
go-env: ; $(ENV) "$(GO.MACRO)" env
go-lint: ; $(ENV) "$(SHELL)" ./scripts/make/go-lint.sh
go-test: ; $(ENV) RACE='1' "$(SHELL)" ./scripts/make/go-test.sh
go-tools: ; $(ENV) "$(SHELL)" ./scripts/make/go-tools.sh
go-upd-tools: ; $(ENV) "$(SHELL)" ./scripts/make/go-upd-tools.sh

go-check: go-tools go-lint go-test

Expand All @@ -76,6 +82,9 @@ go-os-check:

txt-lint: ; $(ENV) "$(SHELL)" ./scripts/make/txt-lint.sh

md-lint: ; $(ENV_MISC) "$(SHELL)" ./scripts/make/md-lint.sh
sh-lint: ; $(ENV_MISC) "$(SHELL)" ./scripts/make/sh-lint.sh

clean: ; $(ENV) $(GO.MACRO) clean && rm -f -r '$(DIST_DIR)'

release: clean
Expand Down
23 changes: 16 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,30 +48,38 @@ Usage:
dnsproxy [OPTIONS]
Application Options:
--config-path= yaml configuration file. Minimal working configuration in config.yaml.dist. Options passed through command line will override the ones from this file.
--config-path= yaml configuration file. Minimal working configuration in config.yaml.dist. Options passed through command
line will override the ones from this file.
-o, --output= Path to the log file. If not set, write to stdout.
-c, --tls-crt= Path to a file with the certificate chain
-k, --tls-key= Path to a file with the private key
--https-server-name= Set the Server header for the responses from the HTTPS server. (default: dnsproxy)
--https-userinfo= If set, all DoH queries are required to have this basic authentication information.
-g, --dnscrypt-config= Path to a file with DNSCrypt configuration. You can generate one using https://github.com/ameshkov/dnscrypt
--edns-addr= Send EDNS Client Address
--upstream-mode= Defines the upstreams logic mode, possible values: load_balance, parallel, fastest_addr (default: load_balance)
--upstream-mode= Defines the upstreams logic mode, possible values: load_balance, parallel, fastest_addr (default:
load_balance)
-l, --listen= Listening addresses
-p, --port= Listening ports. Zero value disables TCP and UDP listeners
-s, --https-port= Listening ports for DNS-over-HTTPS
-t, --tls-port= Listening ports for DNS-over-TLS
-q, --quic-port= Listening ports for DNS-over-QUIC
-y, --dnscrypt-port= Listening ports for DNSCrypt
-u, --upstream= An upstream to be used (can be specified multiple times). You can also specify path to a file with the list of servers
-u, --upstream= An upstream to be used (can be specified multiple times). You can also specify path to a file with the
list of servers
-b, --bootstrap= Bootstrap DNS for DoH and DoT, can be specified multiple times (default: use system-provided)
-f, --fallback= Fallback resolvers to use when regular ones are unavailable, can be specified multiple times. You can also specify path to a file with the list of servers
-f, --fallback= Fallback resolvers to use when regular ones are unavailable, can be specified multiple times. You can also
specify path to a file with the list of servers
--private-rdns-upstream= Private DNS upstreams to use for reverse DNS lookups of private addresses, can be specified multiple times
--dns64-prefix= Prefix used to handle DNS64. If not specified, dnsproxy uses the 'Well-Known Prefix' 64:ff9b::. Can be specified multiple times
--dns64-prefix= Prefix used to handle DNS64. If not specified, dnsproxy uses the 'Well-Known Prefix' 64:ff9b::. Can be
specified multiple times
--private-subnets= Private subnets to use for reverse DNS lookups of private addresses
--bogus-nxdomain= Transform the responses containing at least a single IP that matches specified addresses and CIDRs into NXDOMAIN. Can be specified multiple times.
--bogus-nxdomain= Transform the responses containing at least a single IP that matches specified addresses and CIDRs into
NXDOMAIN. Can be specified multiple times.
--hosts-files= List of paths to the hosts files relative to the root, can be specified multiple times
--timeout= Timeout for outbound DNS queries to remote upstream servers in a human-readable form (default: 10s)
--cache-min-ttl= Minimum TTL value for DNS entries, in seconds. Capped at 3600. Artificially extending TTLs should only be done with careful consideration.
--cache-min-ttl= Minimum TTL value for DNS entries, in seconds. Capped at 3600. Artificially extending TTLs should only be
done with careful consideration.
--cache-max-ttl= Maximum TTL value for DNS entries, in seconds.
--cache-size= Cache size (in bytes). Default: 64k
-r, --ratelimit= Ratelimit (requests per second)
Expand All @@ -93,6 +101,7 @@ Application Options:
--edns Use EDNS Client Subnet extension
--dns64 If specified, dnsproxy will act as a DNS64 server
--use-private-rdns If specified, use private upstreams for reverse DNS lookups of private addresses
--hosts-file-enabled= If specified, use hosts files for resolving (default: true)
Help Options:
-h, --help Show this help message
Expand Down
3 changes: 2 additions & 1 deletion bamboo-specs/bamboo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@
# exact patch version as opposed to a minor one to make sure that this exact
# version is actually used and not whatever the docker daemon on the CI has
# cached a few months ago.
'dockerGo': 'golang:1.22.5'
'dockerGo': 'golang:1.22.6'
'maintainer': 'Adguard Go Team'
'name': 'dnsproxy'

'stages':
# TODO(e.burkov): Add separate lint stage for texts.
- 'Lint':
'manual': false
'final': false
Expand Down
22 changes: 11 additions & 11 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
module github.com/AdguardTeam/dnsproxy

go 1.22.5
go 1.22.6

require (
github.com/AdguardTeam/golibs v0.25.2
github.com/AdguardTeam/golibs v0.26.0
github.com/ameshkov/dnscrypt/v2 v2.2.7
github.com/ameshkov/dnsstamps v1.0.3
github.com/beefsack/go-rate v0.0.0-20220214233405-116f4ca011a0
github.com/bluele/gcache v0.0.2
github.com/jessevdk/go-flags v1.5.0
github.com/jessevdk/go-flags v1.6.1
github.com/miekg/dns v1.1.58
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/quic-go/quic-go v0.44.0
github.com/stretchr/testify v1.9.0
golang.org/x/exp v0.0.0-20240707233637-46b078467d37
golang.org/x/net v0.27.0
golang.org/x/sys v0.22.0
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa
golang.org/x/net v0.28.0
golang.org/x/sys v0.24.0
gopkg.in/yaml.v3 v3.0.1
)

Expand All @@ -31,11 +31,11 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
go.uber.org/mock v0.4.0 // indirect
golang.org/x/crypto v0.25.0 // indirect
golang.org/x/mod v0.19.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/tools v0.23.0 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/mod v0.20.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/text v0.17.0 // indirect
golang.org/x/tools v0.24.0 // indirect
gonum.org/v1/gonum v0.14.0
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
)
41 changes: 20 additions & 21 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
github.com/AdguardTeam/golibs v0.25.2 h1:4+c9LjAIdd9trRk71hXghJ5OL/VRosBm+/0dKH+H39U=
github.com/AdguardTeam/golibs v0.25.2/go.mod h1:HaTyS2wCbxFudjht9N/+/Qf1b5cMad2BAYSwe7DPCXI=
github.com/AdguardTeam/golibs v0.26.0 h1:uLL0XggEjB+87lL1tPpEAQNoKAlHDq5AyBUVWEgf63E=
github.com/AdguardTeam/golibs v0.26.0/go.mod h1:iWdjXPCwmK2g2FKIb/OwEPnovSXeMqRhI8FWLxF5oxE=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 h1:52m0LGchQBBVqJRyYYufQuIbVqRawmubW3OFGqK1ekw=
Expand All @@ -26,8 +26,8 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20240130152714-0ed6a68c8d9e h1:E+3PBMCXn0ma79O7iCrne0iUpKtZ7rIcZvoz+jNtNtw=
github.com/google/pprof v0.0.0-20240130152714-0ed6a68c8d9e/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc=
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4=
github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
Expand All @@ -54,25 +54,24 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/exp v0.0.0-20240707233637-46b078467d37 h1:uLDX+AfeFCct3a2C7uIWBKMJIR3CJMhcgfrUAqjRK6w=
golang.org/x/exp v0.0.0-20240707233637-46b078467d37/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0=
gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
Expand Down
19 changes: 15 additions & 4 deletions internal/cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,23 @@ func createProxyConfig(
l *slog.Logger,
options *Options,
) (conf *proxy.Config, err error) {
reqHdlr := handler.NewDefault(&handler.DefaultConfig{
hostsFiles, err := options.hostsFiles(ctx, l)
if err != nil {
// Don't wrap the error since it's informative enough as is.
return nil, err
}

reqHdlr, err := handler.NewDefault(&handler.DefaultConfig{
Logger: l.With(slogutil.KeyPrefix, "default_handler"),
// TODO(e.burkov): Use the configured message constructor.
MessageConstructor: dnsmsg.DefaultMessageConstructor{},
HaltIPv6: options.IPv6Disabled,
HostsFiles: hostsFiles,
FileSystem: osutil.RootDirFS(),
})
if err != nil {
return nil, fmt.Errorf("creating default handler: %w", err)
}

conf = &proxy.Config{
Logger: l.With(slogutil.KeyPrefix, proxy.LogPrefix),
Expand Down Expand Up @@ -141,7 +152,7 @@ func (opts *Options) initUpstreams(
Logger: l,
HTTPVersions: httpVersions,
InsecureSkipVerify: opts.Insecure,
Timeout: timeout,
Timeout: timeout.Duration,
}
boot, err := initBootstrap(ctx, l, opts.BootstrapDNS, bootOpts)
if err != nil {
Expand All @@ -153,7 +164,7 @@ func (opts *Options) initUpstreams(
HTTPVersions: httpVersions,
InsecureSkipVerify: opts.Insecure,
Bootstrap: boot,
Timeout: timeout,
Timeout: timeout.Duration,
}
upstreams := loadServersList(opts.Upstreams)

Expand All @@ -166,7 +177,7 @@ func (opts *Options) initUpstreams(
Logger: l,
HTTPVersions: httpVersions,
Bootstrap: boot,
Timeout: min(defaultLocalTimeout, timeout),
Timeout: min(defaultLocalTimeout, timeout.Duration),
}
privateUpstreams := loadServersList(opts.PrivateRDNSUpstreams)

Expand Down
Loading

0 comments on commit 25e110a

Please sign in to comment.