Compare commits

...

33 Commits

Author SHA1 Message Date
Ainar Garipov
13f708b483 Pull request: * querylog: fix end of log handling
Merge in DNS/adguard-home from 2229-query-log to master

Closes #2229.

Squashed commit of the following:

commit 32508a3f3b1e098869e1649a2774f1f17d14d41f
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Nov 10 16:51:25 2020 +0300

    * querylog: add test

commit 774159cc313a0284a8bb8327489671e5d7a3e4eb
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Nov 10 15:26:26 2020 +0300

    * querylog: better errors

commit 27b13a4dcaff9e8f9b08aec81c0c03f62ebd3fa5
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Nov 10 15:18:51 2020 +0300

    * querylog: fix end of log handling
2020-11-10 19:00:55 +03:00
Ainar Garipov
979874c92b Pull request: * all: update dnsproxy
Merge in DNS/adguard-home from update-dnsproxy to master

Closes #2252.

Squashed commit of the following:

commit e66b2a0a2555d8ae75b42fd64b83b654810a65c2
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Nov 10 11:56:22 2020 +0300

    * all: update dnsproxy
2020-11-10 15:19:25 +03:00
Ainar Garipov
3cc5bf210d Pull request: * dhcpd: send secondary dns as well
Merge in DNS/adguard-home from 1708-secondary-dns to master

Updates #1708.

Squashed commit of the following:

commit 4529452e31131763f00c9c834cc95638f1a3d142
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Nov 9 18:12:57 2020 +0300

    * dhcpd: send secondary dns as well
2020-11-09 19:27:04 +03:00
Ainar Garipov
1e583315a8 Pull request: * all: update dnsproxy
Merge in DNS/adguard-home from update-dnsproxy to master

Squashed commit of the following:

commit 6ed03c2131b93e3882e8f820e110696a41223267
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Nov 9 13:13:36 2020 +0300

    * all: update dnsproxy
2020-11-09 14:44:21 +03:00
Andrey Meshkov
ee8a033472 Merge branch 'master' of git://github.com/gontazaka/AdGuardHome into gontazaka-master 2020-11-09 11:55:45 +03:00
Andrey Meshkov
b85c0b3bf7 Merge branch 'docker-workflow' of git://github.com/crazy-max/AdGuardHome into crazy-max-docker-workflow 2020-11-09 11:28:27 +03:00
CrazyMax
859ed209a0 Update docker workflow 2020-11-08 23:06:52 +01:00
CrazyMax
c6a6f05b1b Use zoneinfo from Go 2020-11-08 22:57:47 +01:00
gontazaka
5bf330bf14 Fix link address 2020-11-07 13:28:19 +09:00
Ainar Garipov
eefa553100 Pull request: - isdelve: remove unused package
Merge in DNS/adguard-home from remove-isdelve to master

Squashed commit of the following:

commit aa305fa46713b39a8299754e8fd557cbadcb7cc3
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Nov 6 18:06:07 2020 +0300

    - isdelve: remove unused package
2020-11-06 20:20:15 +03:00
Ainar Garipov
298f74ba81 Pull request: * all: allow multiple hosts in reverse lookups
Merge in DNS/adguard-home from 2269-multiple-hosts to master

For #2269.

Squashed commit of the following:

commit f8ae452540b106f2d5b130b8edb08c4e76b003f4
Merge: 8dd06f7cc 3e1f92225
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Nov 6 17:28:12 2020 +0300

    Merge branch 'master' into 2269-multiple-hosts

commit 8dd06f7cca27ec32a4690e2673603b166f82af0a
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Nov 5 20:28:33 2020 +0300

    * all: allow multiple hosts in reverse lookups
2020-11-06 17:34:40 +03:00
Eugene Burkov
3e1f922252 Pull request:* all: fix all staticcheck simplification and unused warnings
Merge in DNS/adguard-home from 2270-fix-s-u-warnings to master

Squashed commit of the following:

commit 03e0f78bd471057007c2d4042ee26eda2bbc9b29
Merge: 50dc3ef5c 7e16fda57
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Fri Nov 6 11:54:09 2020 +0300

    Merge branch 'master' into 2270-fix-s-u-warnings

commit 50dc3ef5c44a5fdc941794c26784b0c44d7b5aa0
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Thu Nov 5 19:48:54 2020 +0300

    * all: improve code quality

commit d6d804f759ce3e47154a389b427550e72c4b9090
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Thu Nov 5 18:03:35 2020 +0300

    * all: fix all staticcheck simplification and unused warnings

    Closes #2270.
2020-11-06 12:15:08 +03:00
Andrey Meshkov
7e16fda57b Change the default for max_goroutines #2257
Closes #2257

* commit '84ca2f58a8b4379a3ee6d0bd9f754be20a3ecaea':
  Added a more detailed comment
  Change the default for max_goroutines #2257
2020-11-05 21:14:05 +03:00
Ainar Garipov
11e794f554 Pull request: * .goreleaser: use a different snap plug for cap_net_raw
Merge in DNS/adguard-home from 2228-new-plug to master

For #2228.

Squashed commit of the following:

commit a073c8e033b1dfbdbd3fff8d773c6a2406b6211b
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Nov 5 17:02:56 2020 +0300

    * .goreleaser: use a different snap plug for cap_net_raw
2020-11-05 17:52:03 +03:00
Eugene Burkov
2baa33fb1f Pull request:* all: remove github.com/joomcode/errorx dependency
Merge in DNS/adguard-home from 2240-removing-errorx-dependency to master

Squashed commit of the following:

commit 5bbe0567356f06e3b9ee5b3dc38d357b472cacb1
Merge: a6040850d 02d16a0b4
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Thu Nov 5 14:32:22 2020 +0300

    Merge branch 'master' into 2240-removing-errorx-dependency

commit a6040850da3cefb131208097477b0956e80063fb
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Thu Nov 5 14:23:36 2020 +0300

    * dhcpd: convert some abbreviations to lowercase.

commit d05bd51b994906b0ff52c5a8e779bd1f512f4bb7
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Thu Nov 5 12:47:20 2020 +0300

    * agherr: last final fixes

commit 164bca55035ff44e50b0abb33e129a0d24ffe87c
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Nov 3 19:11:10 2020 +0300

    * all: final fixes again

commit a0ac26f409c0b28a176cf2861d52c2f471b59484
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Nov 3 18:51:39 2020 +0300

    * all: final fixes

commit 6147b02d402b513323b07e85856b348884f3a088
Merge: 9fd3af1a3 62cc334f4
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Tue Nov 3 18:26:03 2020 +0300

    Merge branch 'master' into 2240-removing-errorx-dependency

commit 9fd3af1a39a3189b5c41315a8ad1568ae5cb4fc9
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Tue Nov 3 18:23:08 2020 +0300

    * all: remove useless helper

commit 7cd9aeae639762b28b25f354d69c5cf74f670211
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Tue Nov 3 17:19:26 2020 +0300

    * agherr: improved code tidiness

commit a74a49236e9aaace070646dac710de9201105262
Merge: dc9dedbf2 df34ee5c0
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Tue Nov 3 16:54:29 2020 +0300

    Merge branch 'master' into 2240-removing-errorx-dependency

commit dc9dedbf205756e3adaa3bc776d349bf3d8c69a5
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Tue Nov 3 16:40:08 2020 +0300

    * agherr: improve and cover by tests

commit fd6bfe9e282156cc60e006cb7cd46cce4d3a07a8
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Tue Nov 3 14:06:27 2020 +0300

    * all: improve code quality

commit ea00c2f8c5060e9611f9a80cfd0e4a039526d0c4
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Tue Nov 3 13:03:57 2020 +0300

    * all: fix linter style warnings

commit 8e75e1a681a7218c2b4c69adfa2b7e1e2966f9ac
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Tue Nov 3 12:29:26 2020 +0300

    * all: remove github.com/joomcode/errorx dependency

    Closes #2240.
2020-11-05 15:20:57 +03:00
Ainar Garipov
02d16a0b40 Pull request: * home, openapi: improve docs and responses
Merge in DNS/adguard-home from 2243-better-docs to master

Closes #2243.

Squashed commit of the following:

commit 26c655a0e4339528870633c2cdf39c3b5c486b1d
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Nov 5 12:51:43 2020 +0300

    * openapi: improve more

commit dc0ab9857787d14eb0686814a4f3c8f917698bee
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Nov 3 20:40:32 2020 +0300

    * home, openapi: improve docs and responses
2020-11-05 13:59:57 +03:00
Andrey Meshkov
84ca2f58a8 Added a more detailed comment 2020-11-05 13:26:13 +03:00
Andrey Meshkov
bc20917840 Change the default for max_goroutines #2257 2020-11-04 13:41:40 +03:00
Artem Baskal
62cc334f46 + client: 2241 Add DNS-over-QUIC string
Close #2241

* commit '3d19f91bede4aee8ee44a4b0a31c4c7b91405785':
  + client: 2241 Add DNS-over-QUIC string
2020-11-03 18:05:14 +03:00
Ainar Garipov
d398e4b01c Pull request: 2250 config reload fix
Merge in DNS/adguard-home from 2250-config-reload-fix to master

Closes #2250.

Squashed commit of the following:

commit 928f28a0732c14f24576de02d0a9fcd34f484c63
Author: Vladislav Alekseev <vldrus@gmail.com>
Date:   Mon Nov 2 02:53:51 2020 +0300

    TLS: use correct config on reload after receiving SIGHUP

commit 9e10d84cf9fbf3298d7f426903dfa4f20f39024b
Author: Vladislav Alekseev <vldrus@gmail.com>
Date:   Mon Nov 2 02:52:32 2020 +0300

    Service: reload config (-s reload): fix for parsing application pid if 'ps' return space padded value
2020-11-03 17:44:03 +03:00
ArtemBaskal
3d19f91bed + client: 2241 Add DNS-over-QUIC string 2020-11-03 17:32:56 +03:00
Ainar Garipov
df34ee5c09 Pull request: * dnsforward, querylog: set client_proto for logs correctly
Merge in DNS/adguard-home from 2241-doq-logs to master

Squashed commit of the following:

commit a15cab05358e3c0b97f8257f8b9628fa590e7e7d
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Nov 3 14:22:25 2020 +0300

    * all: update dnsproxy

commit 5fb0919a7528dc6ee7a433a8096b550f3691771c
Merge: b22b1dff4 64c1a68fb
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Nov 3 14:22:15 2020 +0300

    Merge branch 'master' into 2241-doq-logs

commit b22b1dff43e541d77160fd5c234483bbf0f6d8de
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Nov 3 12:37:23 2020 +0300

    * dnsforward, querylog: set client_proto for logs correctly
2020-11-03 15:39:55 +03:00
Artem Baskal
64c1a68fb9 - client: 2254 Fix textarea with comments fonts
Close #2254

* commit 'd747185b45e9300b771c69dd27a2757fc40b52f6':
  - client: 2254 Fix textarea with comments fonts
2020-11-03 12:36:57 +03:00
ArtemBaskal
d747185b45 - client: 2254 Fix textarea with comments fonts 2020-11-03 12:07:01 +03:00
Eugene Burkov
8afdc049ef Pull request:* all: replace our pprof fork with net/http/pprof
Merge in DNS/adguard-home from 2239-remove-pprof-fork to master

Squashed commit of the following:

commit eefcaae015292768b26a70a27d352d3e2aa3f9ef
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Fri Oct 30 20:00:05 2020 +0300

    * all: replace our pprof fork with net/http/pprof

    Closes #2239.
2020-11-02 16:32:33 +03:00
Eugene Burkov
812b43a4b3 Pull request:* all: fix all staticcheck SA warnings
Merge in DNS/adguard-home from 2238-fix-static-analisys-warnings to master

Squashed commit of the following:

commit 721ca6fa1cbfdfe9d414e6ed52fec4a64653fb52
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Fri Oct 30 15:48:10 2020 +0300

    * all: fix all staticcheck SA warnings

    Closes #2238.
2020-10-30 19:18:51 +03:00
Ainar Garipov
ae8de95d89 Pull request: * all: move internal Go packages to internal/
Merge in DNS/adguard-home from 2234-move-to-internal to master

Squashed commit of the following:

commit d26a288cabeac86f9483fab307677b1027c78524
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Fri Oct 30 12:44:18 2020 +0300

    * all: move internal Go packages to internal/

    Closes #2234.
2020-10-30 13:32:02 +03:00
Ainar Garipov
df3fa595a2 Pull request: * home: improve naming in mobileconfig handlers
Merge in DNS/adguard-home from 2235-mobileconfig-server-name to master

* commit '98f6843aab8ff69606f44f6a5721d5f2a5707a0f':
  * home: improve naming in mobileconfig handlers
2020-10-30 12:41:34 +03:00
Ainar Garipov
98f6843aab * home: improve naming in mobileconfig handlers
Updates #2235.
2020-10-29 19:42:25 +03:00
Ainar Garipov
9761f13399 Pull request: .goreleaser: add a new snap plug to bind to devices
Merge in DNS/adguard-home from 2228-linux-caps to master

* commit 'a376bf915a397e71763bed9e86ab2767d5467e85':
  .goreleaser: add a new snap plug to bind to devices
2020-10-29 18:57:38 +03:00
Ainar Garipov
a376bf915a .goreleaser: add a new snap plug to bind to devices
Closes #2228.
2020-10-29 17:27:14 +03:00
Ainar Garipov
da5c1ebbbf Pull request: * querylog: use the vanilla errors package
Merge in DNS/adguard-home from remove-pkg-errors to master

* commit '40ebccaab415f957c8234ad2c3a9615225ddae68':
  * querylog: use the vanilla errors package
2020-10-29 12:22:33 +03:00
Ainar Garipov
40ebccaab4 * querylog: use the vanilla errors package 2020-10-28 19:34:29 +03:00
140 changed files with 1205 additions and 1200 deletions

View File

@@ -134,23 +134,21 @@ jobs:
runs-on: ubuntu-latest
needs: test
steps:
-
name: Set up Docker Buildx
uses: crazy-max/ghaction-docker-buildx@v1
-
name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
-
name: Set up QEMU
uses: docker/setup-qemu-action@v1
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
-
name: Docker Buildx (build)
run: |
make docker-multi-arch
-
name: Clear
if: always() && startsWith(github.ref, 'refs/tags/v')
run: |
rm -f ${HOME}/.docker/config.json
notify:
needs: [app, docker]

View File

@@ -90,7 +90,13 @@ snapcrafts:
apps:
adguard-home:
command: AdGuardHome -w $SNAP_DATA --no-check-update
plugs: [ network-bind ]
plugs:
# Add the "netrwork-bind" plug to bind to interfaces.
- network-bind
# Add the "netrwork-control" plug to be able to bind to ports below
# 1024 (cap_net_bind_service) and also to bind to a particular
# interface using SO_BINDTODEVICE (cap_net_raw).
- network-control
daemon: simple
adguard-home-web:
command: adguard-home-web.sh

View File

@@ -1587,7 +1587,7 @@ Response:
"upstream":"...", // Upstream URL starting with tcp://, tls://, https://, or with an IP address
"answer_dnssec": true,
"client":"127.0.0.1",
"client_proto": "" (plain) | "doh" | "dot",
"client_proto": "" (plain) | "doh" | "dot" | "doq",
"elapsedMs":"0.098403",
"filterId":1,
"question":{

View File

@@ -59,7 +59,6 @@ RUN apk --update --no-cache add \
ca-certificates \
libcap \
libressl \
tzdata \
&& rm -rf /tmp/* /var/cache/apk/*
COPY --from=builder --chown=nobody:nogroup /app/AdGuardHome /opt/adguardhome/AdGuardHome

View File

@@ -109,7 +109,7 @@ $(error DOCKER_IMAGE_NAME value is not set)
endif
# OS-specific flags
TEST_FLAGS := -race
TEST_FLAGS := --race -v
ifeq ($(OS),Windows_NT)
TEST_FLAGS :=
endif
@@ -160,11 +160,13 @@ lint-go:
@echo Running go linter
golangci-lint run
test:
@echo Running JS unit-tests
test: test-js test-go
test-js:
npm run test --prefix client
@echo Running Go unit-tests
go test $(TEST_FLAGS) -v -coverprofile=coverage.txt -covermode=atomic ./...
test-go:
go test $(TEST_FLAGS) --coverprofile coverage.txt ./...
ci: client_with_deps
go mod download

View File

@@ -293,7 +293,7 @@ Here is a link to AdGuard Home project: https://crowdin.com/project/adguard-appl
Here's what you can also do to contribute:
1. [Look for issues](https://github.com/AdguardTeam/AdGuardHome/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22+) marked as "help wanted".
2. Actualize the list of *Blocked services*. It it can be found in [dnsfilter/blocked_services.go](https://github.com/AdguardTeam/AdGuardHome/blob/master/dnsfilter/blocked_services.go).
2. Actualize the list of *Blocked services*. It it can be found in [dnsfilter/blocked_services.go](https://github.com/AdguardTeam/AdGuardHome/blob/master/internal/dnsfilter/blocked_services.go).
3. Actualize the list of known *trackers*. It it can be found in [client/src/helpers/trackers/adguard.json](https://github.com/AdguardTeam/AdGuardHome/blob/master/client/src/helpers/trackers/adguard.json).
4. Actualize the list of vetted *blocklists*. It it can be found in [client/src/helpers/filters/filters.json](https://github.com/AdguardTeam/AdGuardHome/blob/master/client/src/helpers/filters/filters.json).

View File

@@ -249,6 +249,7 @@
"blocking_ipv6": "Blocking IPv6",
"dns_over_https": "DNS-over-HTTPS",
"dns_over_tls": "DNS-over-TLS",
"dns_over_quic": "DNS-over-QUIC",
"download_mobileconfig_doh": "Download .mobileconfig for DNS-over-HTTPS",
"download_mobileconfig_dot": "Download .mobileconfig for DNS-over-TLS",
"plain_dns": "Plain DNS",
@@ -587,4 +588,4 @@
"adg_will_drop_dns_queries": "AdGuard Home will be dropping all DNS queries from this client.",
"client_not_in_allowed_clients": "The client is not allowed because it is not in the \"Allowed clients\" list.",
"experimental": "Experimental"
}
}

View File

@@ -475,6 +475,7 @@ export const BLOCK_ACTIONS = {
export const SCHEME_TO_PROTOCOL_MAP = {
doh: 'dns_over_https',
dot: 'dns_over_tls',
doq: 'dns_over_quic',
'': 'plain_dns',
};

View File

@@ -17,7 +17,7 @@ export const getTextareaCommentsHighlight = (
) => {
const renderLine = (line, idx) => renderHighlightedLine(line, idx, commentLineTokens);
return <code className={classnames('text-output', className)} ref={ref}>{lines?.split('\n').map(renderLine)}</code>;
return <code className={classnames('text-output font-monospace', className)} ref={ref}>{lines?.split('\n').map(renderLine)}</code>;
};
export const syncScroll = (e, ref) => {

23
go.mod
View File

@@ -3,7 +3,7 @@ module github.com/AdguardTeam/AdGuardHome
go 1.14
require (
github.com/AdguardTeam/dnsproxy v0.32.6
github.com/AdguardTeam/dnsproxy v0.33.2
github.com/AdguardTeam/golibs v0.4.2
github.com/AdguardTeam/urlfilter v0.12.3
github.com/NYTimes/gziphandler v1.1.1
@@ -12,25 +12,26 @@ require (
github.com/gobuffalo/packr v1.30.1
github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714
github.com/insomniacslk/dhcp v0.0.0-20200621044212-d74cd86ad5b8
github.com/joomcode/errorx v1.0.3
github.com/joomcode/errorx v1.0.3 // indirect
github.com/kardianos/service v1.1.0
github.com/marten-seemann/qtls-go1-15 v0.1.1 // indirect
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7
github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065
github.com/miekg/dns v1.1.31
github.com/pkg/errors v0.9.1
github.com/miekg/dns v1.1.35
github.com/rogpeppe/go-internal v1.5.2 // indirect
github.com/satori/go.uuid v1.2.0
github.com/sirupsen/logrus v1.6.0 // indirect
github.com/sparrc/go-ping v0.0.0-20190613174326-4e5b6552494c
github.com/stretchr/testify v1.5.1
github.com/stretchr/testify v1.6.1
github.com/u-root/u-root v6.0.0+incompatible
go.etcd.io/bbolt v1.3.4
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
golang.org/x/net v0.0.0-20200904194848-62affa334b73
golang.org/x/sys v0.0.0-20200917073148-efd3b9a0ff20
golang.org/x/text v0.3.3 // indirect
google.golang.org/protobuf v1.25.0 // indirect
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 // indirect
golang.org/x/sys v0.0.0-20201109165425-215b40eba54c
golang.org/x/text v0.3.4 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0
gopkg.in/yaml.v2 v2.3.0
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
howett.net/plist v0.0.0-20200419221736-3b63eb3a43b5
)

58
go.sum
View File

@@ -7,8 +7,10 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/AdguardTeam/dnsproxy v0.32.6 h1:HCKQFUvyvIP3lrJxP8t8+mE/DJwLk2HDmzI/af5PUu4=
github.com/AdguardTeam/dnsproxy v0.32.6/go.mod h1:ZLDrKIypYxBDz2N9FQHgeehuHrwTbuhZXdGwNySshbw=
github.com/AdguardTeam/dnsproxy v0.33.1 h1:rEAS1fBEQ3JslzsfkcyMRV96OeBWFnKzXvksduI0ous=
github.com/AdguardTeam/dnsproxy v0.33.1/go.mod h1:kLi6lMpErnZThy5haiRSis4q0KTB8uPWO4JQsU1EDJA=
github.com/AdguardTeam/dnsproxy v0.33.2 h1:k5aMcsw3TA/G2DR8EjIkwutDPuuRkKh8xij4cFWC6Fk=
github.com/AdguardTeam/dnsproxy v0.33.2/go.mod h1:kLi6lMpErnZThy5haiRSis4q0KTB8uPWO4JQsU1EDJA=
github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
github.com/AdguardTeam/golibs v0.4.2 h1:7M28oTZFoFwNmp8eGPb3ImmYbxGaJLyQXeIFVHjME0o=
github.com/AdguardTeam/golibs v0.4.2/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
@@ -25,10 +27,12 @@ github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmH
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=
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635/go.mod h1:lmLxL+FV291OopO93Bwf9fQLQeLyt33VJRUg5VJ30us=
github.com/ameshkov/dnscrypt v1.1.0 h1:2vAt5dD6ZmqlAxEAfzRcLBnkvdf8NI46Kn9InSwQbSI=
github.com/ameshkov/dnscrypt v1.1.0/go.mod h1:ikduAxNLCTEfd1AaCgpIA5TgroIVQ8JY3Vb095fiFJg=
github.com/ameshkov/dnscrypt/v2 v2.0.0 h1:i83G8MeGLrAFgUL8GSu98TVhtFDEifF7SIS7Qi/RZ3U=
github.com/ameshkov/dnscrypt/v2 v2.0.0/go.mod h1:nbZnxJt4edIPx2Haa8n2XtC2g5AWcsdQiSuXkNH8eDI=
github.com/ameshkov/dnsstamps v1.0.1 h1:LhGvgWDzhNJh+kBQd/AfUlq1vfVe109huiXw4JhnPug=
github.com/ameshkov/dnsstamps v1.0.1/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A=
github.com/ameshkov/dnsstamps v1.0.3 h1:Srzik+J9mivH1alRACTbys2xOxs0lRH9qnTA7Y1OYVo=
github.com/ameshkov/dnsstamps v1.0.3/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/beefsack/go-rate v0.0.0-20180408011153-efa7637bb9b6 h1:KXlsf+qt/X5ttPGEjR0tPH1xaWWoKBEg9Q1THAj2h3I=
@@ -98,6 +102,8 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
@@ -152,8 +158,8 @@ github.com/kr/pty v1.1.3/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=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lucas-clemente/quic-go v0.18.0 h1:JhQDdqxdwdmGdKsKgXi1+coHRoGhvU6z0rNzOJqZ/4o=
github.com/lucas-clemente/quic-go v0.18.0/go.mod h1:yXttHsSNxQi8AWijC/vLP+OJczXqzHSOcJrM5ITUlCg=
github.com/lucas-clemente/quic-go v0.18.1 h1:DMR7guC0NtVS8zNZR3IO7NARZvZygkSC56GGtC6cyys=
github.com/lucas-clemente/quic-go v0.18.1/go.mod h1:yXttHsSNxQi8AWijC/vLP+OJczXqzHSOcJrM5ITUlCg=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@@ -173,8 +179,9 @@ github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZ
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/miekg/dns v1.1.29 h1:xHBEhR+t5RzcFJjBLJlax2daXOrTYtr9z4WdKEfWFzg=
github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/miekg/dns v1.1.31 h1:sJFOl9BgwbYAWOGEwr61FU28pqsBNdpRBnhGXtO06Oo=
github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/miekg/dns v1.1.34/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/miekg/dns v1.1.35 h1:oTfOaDH+mZkdcgdIjH6yBajRGtIwcwcaR+rt23ZSrJs=
github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -209,6 +216,8 @@ github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.5.2 h1:qLvObTrvO/XRCqmkKxUlOBc48bI3efyDuAZe25QiF0w=
github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
@@ -261,6 +270,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/u-root/u-root v6.0.0+incompatible h1:YqPGmRoRyYmeg17KIWFRSyVq6LX5T6GSzawyA6wG6EE=
github.com/u-root/u-root v6.0.0+incompatible/go.mod h1:RYkpo8pTHrNjW08opNd/U6p/RJE7K0D8fXO0d47+3YY=
@@ -284,12 +295,13 @@ golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3 h1:XQyxROzUlZH+WIQwySDgnISgOivlhjIEwaQaJEJrrN0=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -312,8 +324,11 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA=
golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102 h1:42cLlJJdEh+ySyeUUbEQ5bsTiq8voBeTuweGVkY6Puw=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -327,6 +342,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -351,8 +368,12 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d h1:nc5K6ox/4lTFbMVSL9WRR81ix
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200917073148-efd3b9a0ff20 h1:4X356008q5SA3YXu8PiRap39KFmy4Lf6sGlceJKZQsU=
golang.org/x/sys v0.0.0-20200917073148-efd3b9a0ff20/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201107080550-4d91cf3a1aaf h1:kt3wY1Lu5MJAnKTfoMR52Cu4gwvna4VTzNOiT8tY73s=
golang.org/x/sys v0.0.0-20201107080550-4d91cf3a1aaf/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201109165425-215b40eba54c h1:+B+zPA6081G5cEb2triOIJpcvSW4AYzmIyWAqMn2JAc=
golang.org/x/sys v0.0.0-20201109165425-215b40eba54c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -360,6 +381,8 @@ golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -376,6 +399,8 @@ golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapK
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
@@ -427,6 +452,11 @@ gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo=
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

67
internal/agherr/agherr.go Normal file
View File

@@ -0,0 +1,67 @@
// Package agherr contains the extended error type, and the function for
// wrapping several errors.
package agherr
import (
"fmt"
"strings"
)
// Error is the constant error type.
type Error string
// Error implements the error interface for Error.
func (err Error) Error() (msg string) {
return string(err)
}
// manyError is an error containing several wrapped errors. It is created to be
// a simpler version of the API provided by github.com/joomcode/errorx.
type manyError struct {
message string
underlying []error
}
// Many wraps several errors and returns a single error.
func Many(message string, underlying ...error) error {
err := &manyError{
message: message,
underlying: underlying,
}
return err
}
// Error implements the error interface for *manyError.
func (e *manyError) Error() string {
switch len(e.underlying) {
case 0:
return e.message
case 1:
return fmt.Sprintf("%s: %s", e.message, e.underlying[0])
default:
b := &strings.Builder{}
// Ignore errors, since strings.(*Buffer).Write never returns
// errors.
_, _ = fmt.Fprintf(b, "%s: %s (hidden: %s", e.message, e.underlying[0], e.underlying[1])
for _, u := range e.underlying[2:] {
// See comment above.
_, _ = fmt.Fprintf(b, ", %s", u)
}
// See comment above.
_, _ = b.WriteString(")")
return b.String()
}
}
// Unwrap implements the hidden errors.wrapper interface for *manyError.
func (e *manyError) Unwrap() error {
if len(e.underlying) == 0 {
return nil
}
return e.underlying[0]
}

View File

@@ -0,0 +1,73 @@
package agherr
import (
"errors"
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
func TestError_Error(t *testing.T) {
testCases := []struct {
name string
want string
err error
}{{
name: "simple",
want: "a",
err: Many("a"),
}, {
name: "wrapping",
want: "a: b",
err: Many("a", errors.New("b")),
}, {
name: "wrapping several",
want: "a: b (hidden: c, d)",
err: Many("a", errors.New("b"), errors.New("c"), errors.New("d")),
}, {
name: "wrapping wrapper",
want: "a: b: c (hidden: d)",
err: Many("a", Many("b", errors.New("c"), errors.New("d"))),
}}
for _, tc := range testCases {
assert.Equal(t, tc.want, tc.err.Error(), tc.name)
}
}
func TestError_Unwrap(t *testing.T) {
const (
errSimple = iota
errWrapped
errNil
)
errs := []error{
errSimple: errors.New("a"),
errWrapped: fmt.Errorf("%w", errors.New("nested")),
errNil: nil,
}
testCases := []struct {
name string
want error
wrapped error
}{{
name: "simple",
want: errs[errSimple],
wrapped: Many("a", errs[errSimple]),
}, {
name: "nested",
want: errs[errWrapped],
wrapped: Many("b", errs[errWrapped]),
}, {
name: "nil passed",
want: errs[errNil],
wrapped: Many("c", errs[errNil]),
}, {
name: "nil not passed",
want: nil,
wrapped: Many("d"),
}}
for _, tc := range testCases {
assert.Equal(t, tc.want, errors.Unwrap(tc.wrapped), tc.name)
}
}

View File

@@ -10,7 +10,7 @@ import (
"runtime"
"time"
"github.com/AdguardTeam/AdGuardHome/dhcpd/nclient4"
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd/nclient4"
"github.com/AdguardTeam/golibs/log"
"github.com/insomniacslk/dhcp/dhcpv4"
"github.com/insomniacslk/dhcp/dhcpv6"
@@ -23,15 +23,19 @@ import (
func CheckIfOtherDHCPServersPresentV4(ifaceName string) (bool, error) {
iface, err := net.InterfaceByName(ifaceName)
if err != nil {
return false, wrapErrPrint(err, "Couldn't find interface by name %s", ifaceName)
return false, fmt.Errorf("couldn't find interface by name %s: %w", ifaceName, err)
}
// get ipv4 address of an interface
ifaceIPNet := getIfaceIPv4(*iface)
ifaceIPNet, err := ifaceIPv4Addrs(iface)
if err != nil {
return false, fmt.Errorf("getting ipv4 addrs for iface %s: %w", ifaceName, err)
}
if len(ifaceIPNet) == 0 {
return false, fmt.Errorf("couldn't find IPv4 address of interface %s %+v", ifaceName, iface)
return false, fmt.Errorf("interface %s has no ipv4 addresses", ifaceName)
}
// TODO(a.garipov): Find out what this is about. Perhaps this
// information is outdated or at least incomplete.
if runtime.GOOS == "darwin" {
return false, fmt.Errorf("can't find DHCP server: not supported on macOS")
}
@@ -44,7 +48,7 @@ func CheckIfOtherDHCPServersPresentV4(ifaceName string) (bool, error) {
req, err := dhcpv4.NewDiscovery(iface.HardwareAddr)
if err != nil {
return false, fmt.Errorf("dhcpv4.NewDiscovery: %s", err)
return false, fmt.Errorf("dhcpv4.NewDiscovery: %w", err)
}
req.Options.Update(dhcpv4.OptClientIdentifier(iface.HardwareAddr))
req.Options.Update(dhcpv4.OptHostName(hostname))
@@ -52,24 +56,24 @@ func CheckIfOtherDHCPServersPresentV4(ifaceName string) (bool, error) {
// resolve 0.0.0.0:68
udpAddr, err := net.ResolveUDPAddr("udp4", src)
if err != nil {
return false, wrapErrPrint(err, "Couldn't resolve UDP address %s", src)
return false, fmt.Errorf("couldn't resolve UDP address %s: %w", src, err)
}
if !udpAddr.IP.To4().Equal(srcIP) {
return false, wrapErrPrint(err, "Resolved UDP address is not %s", src)
return false, fmt.Errorf("resolved UDP address is not %s: %w", src, err)
}
// resolve 255.255.255.255:67
dstAddr, err := net.ResolveUDPAddr("udp4", dst)
if err != nil {
return false, wrapErrPrint(err, "Couldn't resolve UDP address %s", dst)
return false, fmt.Errorf("couldn't resolve UDP address %s: %w", dst, err)
}
// bind to 0.0.0.0:68
log.Tracef("Listening to udp4 %+v", udpAddr)
c, err := nclient4.NewRawUDPConn(ifaceName, 68)
if err != nil {
return false, wrapErrPrint(err, "Couldn't listen on :68")
return false, fmt.Errorf("couldn't listen on :68: %w", err)
}
if c != nil {
defer c.Close()
@@ -78,61 +82,84 @@ func CheckIfOtherDHCPServersPresentV4(ifaceName string) (bool, error) {
// send to 255.255.255.255:67
_, err = c.WriteTo(req.ToBytes(), dstAddr)
if err != nil {
return false, wrapErrPrint(err, "Couldn't send a packet to %s", dst)
return false, fmt.Errorf("couldn't send a packet to %s: %w", dst, err)
}
for {
// wait for answer
log.Tracef("Waiting %v for an answer", defaultDiscoverTime)
// TODO: replicate dhclient's behaviour of retrying several times with progressively bigger timeouts
b := make([]byte, 1500)
_ = c.SetReadDeadline(time.Now().Add(defaultDiscoverTime))
n, _, err := c.ReadFrom(b)
if isTimeout(err) {
// timed out -- no DHCP servers
log.Debug("DHCPv4: didn't receive DHCP response")
return false, nil
}
if err != nil {
return false, wrapErrPrint(err, "Couldn't receive packet")
}
log.Tracef("Received packet (%v bytes)", n)
response, err := dhcpv4.FromBytes(b[:n])
if err != nil {
log.Debug("DHCPv4: dhcpv4.FromBytes: %s", err)
ok, next, err := tryConn(req, c, iface)
if next {
continue
}
log.Debug("DHCPv4: received message from server: %s", response.Summary())
if !(response.OpCode == dhcpv4.OpcodeBootReply &&
response.HWType == iana.HWTypeEthernet &&
bytes.Equal(response.ClientHWAddr, iface.HardwareAddr) &&
bytes.Equal(response.TransactionID[:], req.TransactionID[:]) &&
response.Options.Has(dhcpv4.OptionDHCPMessageType)) {
log.Debug("DHCPv4: received message from server doesn't match our request")
continue
if ok {
return true, nil
}
if err != nil {
log.Debug("%s", err)
}
log.Tracef("The packet is from an active DHCP server")
// that's a DHCP server there
return true, nil
}
}
// TODO(a.garipov): Refactor further. Inspect error handling, remove the next
// parameter, address the TODO, etc.
func tryConn(req *dhcpv4.DHCPv4, c net.PacketConn, iface *net.Interface) (ok, next bool, err error) {
// TODO: replicate dhclient's behavior of retrying several times with
// progressively longer timeouts.
log.Tracef("waiting %v for an answer", defaultDiscoverTime)
b := make([]byte, 1500)
_ = c.SetReadDeadline(time.Now().Add(defaultDiscoverTime))
n, _, err := c.ReadFrom(b)
if err != nil {
if isTimeout(err) {
log.Debug("dhcpv4: didn't receive dhcp response")
return false, false, nil
}
return false, false, fmt.Errorf("receiving packet: %w", err)
}
log.Tracef("received packet, %d bytes", n)
response, err := dhcpv4.FromBytes(b[:n])
if err != nil {
log.Debug("dhcpv4: encoding: %s", err)
return false, true, err
}
log.Debug("dhcpv4: received message from server: %s", response.Summary())
if !(response.OpCode == dhcpv4.OpcodeBootReply &&
response.HWType == iana.HWTypeEthernet &&
bytes.Equal(response.ClientHWAddr, iface.HardwareAddr) &&
bytes.Equal(response.TransactionID[:], req.TransactionID[:]) &&
response.Options.Has(dhcpv4.OptionDHCPMessageType)) {
log.Debug("dhcpv4: received message from server doesn't match our request")
return false, true, nil
}
log.Tracef("the packet is from an active dhcp server")
return true, false, nil
}
// CheckIfOtherDHCPServersPresentV6 sends a DHCP request to the specified network interface,
// and waits for a response for a period defined by defaultDiscoverTime
func CheckIfOtherDHCPServersPresentV6(ifaceName string) (bool, error) {
iface, err := net.InterfaceByName(ifaceName)
if err != nil {
return false, fmt.Errorf("DHCPv6: net.InterfaceByName: %s: %s", ifaceName, err)
return false, fmt.Errorf("dhcpv6: net.InterfaceByName: %s: %w", ifaceName, err)
}
ifaceIPNet := getIfaceIPv6(*iface)
ifaceIPNet, err := ifaceIPv6Addrs(iface)
if err != nil {
return false, fmt.Errorf("getting ipv6 addrs for iface %s: %w", ifaceName, err)
}
if len(ifaceIPNet) == 0 {
return false, fmt.Errorf("DHCPv6: couldn't find IPv6 address of interface %s %+v", ifaceName, iface)
return false, fmt.Errorf("interface %s has no ipv6 addresses", ifaceName)
}
srcIP := ifaceIPNet[0]
@@ -141,27 +168,27 @@ func CheckIfOtherDHCPServersPresentV6(ifaceName string) (bool, error) {
req, err := dhcpv6.NewSolicit(iface.HardwareAddr)
if err != nil {
return false, fmt.Errorf("DHCPv6: dhcpv6.NewSolicit: %s", err)
return false, fmt.Errorf("dhcpv6: dhcpv6.NewSolicit: %w", err)
}
udpAddr, err := net.ResolveUDPAddr("udp6", src)
if err != nil {
return false, wrapErrPrint(err, "DHCPv6: Couldn't resolve UDP address %s", src)
return false, fmt.Errorf("dhcpv6: Couldn't resolve UDP address %s: %w", src, err)
}
if !udpAddr.IP.To16().Equal(srcIP) {
return false, wrapErrPrint(err, "DHCPv6: Resolved UDP address is not %s", src)
return false, fmt.Errorf("dhcpv6: Resolved UDP address is not %s: %w", src, err)
}
dstAddr, err := net.ResolveUDPAddr("udp6", dst)
if err != nil {
return false, fmt.Errorf("DHCPv6: Couldn't resolve UDP address %s: %s", dst, err)
return false, fmt.Errorf("dhcpv6: Couldn't resolve UDP address %s: %w", dst, err)
}
log.Debug("DHCPv6: Listening to udp6 %+v", udpAddr)
c, err := nclient6.NewIPv6UDPConn(ifaceName, dhcpv6.DefaultClientPort)
if err != nil {
return false, fmt.Errorf("DHCPv6: Couldn't listen on :546: %s", err)
return false, fmt.Errorf("dhcpv6: Couldn't listen on :546: %w", err)
}
if c != nil {
defer c.Close()
@@ -169,7 +196,7 @@ func CheckIfOtherDHCPServersPresentV6(ifaceName string) (bool, error) {
_, err = c.WriteTo(req.ToBytes(), dstAddr)
if err != nil {
return false, fmt.Errorf("DHCPv6: Couldn't send a packet to %s: %s", dst, err)
return false, fmt.Errorf("dhcpv6: Couldn't send a packet to %s: %w", dst, err)
}
for {
@@ -182,7 +209,7 @@ func CheckIfOtherDHCPServersPresentV6(ifaceName string) (bool, error) {
return false, nil
}
if err != nil {
return false, wrapErrPrint(err, "Couldn't receive packet")
return false, fmt.Errorf("couldn't receive packet: %w", err)
}
log.Debug("DHCPv6: Received packet (%v bytes)", n)

View File

@@ -10,7 +10,7 @@ import (
"strings"
"time"
"github.com/AdguardTeam/AdGuardHome/util"
"github.com/AdguardTeam/AdGuardHome/internal/util"
"github.com/AdguardTeam/golibs/jsonutil"
"github.com/AdguardTeam/golibs/log"
@@ -175,7 +175,7 @@ func (s *Server) handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) {
v6conf.InterfaceName = newconfig.InterfaceName
v6conf.notify = s.onNotify
s6, err = v6Create(v6conf)
if s6 == nil {
if err != nil {
httpError(r, w, http.StatusBadRequest, "Invalid DHCPv6 configuration: %s", err)
return
}
@@ -302,17 +302,17 @@ func (s *Server) handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) {
func (s *Server) handleDHCPFindActiveServer(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
errorText := fmt.Sprintf("failed to read request body: %s", err)
log.Error(errorText)
http.Error(w, errorText, http.StatusBadRequest)
msg := fmt.Sprintf("failed to read request body: %s", err)
log.Error(msg)
http.Error(w, msg, http.StatusBadRequest)
return
}
interfaceName := strings.TrimSpace(string(body))
if interfaceName == "" {
errorText := fmt.Sprintf("empty interface name specified")
log.Error(errorText)
http.Error(w, errorText, http.StatusBadRequest)
msg := "empty interface name specified"
log.Error(msg)
http.Error(w, msg, http.StatusBadRequest)
return
}
@@ -335,7 +335,7 @@ func (s *Server) handleDHCPFindActiveServer(w http.ResponseWriter, r *http.Reque
foundVal := "no"
if found4 {
foundVal = "yes"
} else if err != nil {
} else if err4 != nil {
foundVal = "error"
othSrv["error"] = err4.Error()
}
@@ -370,7 +370,6 @@ func (s *Server) handleDHCPFindActiveServer(w http.ResponseWriter, r *http.Reque
}
func (s *Server) handleDHCPAddStaticLease(w http.ResponseWriter, r *http.Request) {
lj := staticLeaseJSON{}
err := json.NewDecoder(r.Body).Decode(&lj)
if err != nil {
@@ -424,7 +423,6 @@ func (s *Server) handleDHCPAddStaticLease(w http.ResponseWriter, r *http.Request
}
func (s *Server) handleDHCPRemoveStaticLease(w http.ResponseWriter, r *http.Request) {
lj := staticLeaseJSON{}
err := json.NewDecoder(r.Body).Decode(&lj)
if err != nil {

View File

@@ -9,7 +9,7 @@ import (
"strings"
"time"
"github.com/AdguardTeam/AdGuardHome/util"
"github.com/AdguardTeam/AdGuardHome/internal/util"
"github.com/AdguardTeam/golibs/log"
)

View File

@@ -12,12 +12,6 @@ import (
"github.com/stretchr/testify/assert"
)
func check(t *testing.T, result bool, msg string) {
if !result {
t.Fatal(msg)
}
}
func testNotify(flags uint32) {
}
@@ -83,7 +77,6 @@ func TestIsValidSubnetMask(t *testing.T) {
func TestNormalizeLeases(t *testing.T) {
dynLeases := []*Lease{}
staticLeases := []*Lease{}
leases := []*Lease{}
lease := &Lease{}
lease.HWAddr = []byte{1, 2, 3, 4}
@@ -100,7 +93,7 @@ func TestNormalizeLeases(t *testing.T) {
lease.HWAddr = []byte{2, 2, 3, 4}
staticLeases = append(staticLeases, lease)
leases = normalizeLeases(staticLeases, dynLeases)
leases := normalizeLeases(staticLeases, dynLeases)
assert.True(t, len(leases) == 3)
assert.True(t, bytes.Equal(leases[0].HWAddr, []byte{1, 2, 3, 4}))

View File

@@ -4,9 +4,6 @@ import (
"encoding/binary"
"fmt"
"net"
"github.com/AdguardTeam/golibs/log"
"github.com/joomcode/errorx"
)
func isTimeout(err error) bool {
@@ -17,37 +14,6 @@ func isTimeout(err error) bool {
return operr.Timeout()
}
// Get IPv4 address list
func getIfaceIPv4(iface net.Interface) []net.IP {
addrs, err := iface.Addrs()
if err != nil {
return nil
}
var res []net.IP
for _, a := range addrs {
ipnet, ok := a.(*net.IPNet)
if !ok {
continue
}
if ipnet.IP.To4() != nil {
res = append(res, ipnet.IP.To4())
}
}
return res
}
func wrapErrPrint(err error, message string, args ...interface{}) error {
var errx error
if err == nil {
errx = fmt.Errorf(message, args...)
} else {
errx = errorx.Decorate(err, message, args...)
}
log.Println(errx.Error())
return errx
}
func parseIPv4(text string) (net.IP, error) {
result := net.ParseIP(text)
if result == nil {

View File

@@ -48,14 +48,12 @@ const (
ServerPort = 67
)
var (
// DefaultServers is the address of all link-local DHCP servers and
// relay agents.
DefaultServers = &net.UDPAddr{
IP: net.IPv4bcast,
Port: ServerPort,
}
)
// DefaultServers is the address of all link-local DHCP servers and
// relay agents.
var DefaultServers = &net.UDPAddr{
IP: net.IPv4bcast,
Port: ServerPort,
}
var (
// ErrNoResponse is returned when no response packet is received.
@@ -375,14 +373,6 @@ func WithHWAddr(hwAddr net.HardwareAddr) ClientOpt {
}
}
// nolint
func withBufferCap(n int) ClientOpt {
return func(c *Client) (err error) {
c.bufferCap = n
return
}
}
// WithRetry configures the number of retransmissions to attempt.
//
// Default is 3.

View File

@@ -122,6 +122,13 @@ func newPacket(op dhcpv4.OpcodeType, xid dhcpv4.TransactionID) *dhcpv4.DHCPv4 {
return p
}
func withBufferCap(n int) ClientOpt {
return func(c *Client) (err error) {
c.bufferCap = n
return
}
}
func TestSendAndRead(t *testing.T) {
for _, tt := range []struct {
desc string

View File

@@ -10,7 +10,7 @@ import (
"runtime"
"strings"
"github.com/AdguardTeam/AdGuardHome/util"
"github.com/AdguardTeam/AdGuardHome/internal/util"
"github.com/AdguardTeam/golibs/file"
@@ -73,7 +73,6 @@ func hasStaticIPDhcpcdConf(dhcpConf, ifaceName string) bool {
// we found our interface
withinInterfaceCtx = true
}
} else {
if strings.HasPrefix(line, "interface ") {
// we found another interface - reset our state
@@ -240,7 +239,7 @@ func getNetworkSetupHardwareReports() map[string]string {
return nil
}
m := make(map[string]string, 0)
m := make(map[string]string)
matches := re.FindAllStringSubmatch(out, -1)
for i := range matches {

View File

@@ -163,7 +163,7 @@ func (ra *raCtx) Init() error {
return nil
}
log.Debug("DHCPv6 RA: source IP address: %s DNS IP address: %s",
log.Debug("dhcpv6 ra: source IP address: %s DNS IP address: %s",
ra.ipAddr, ra.dnsIPAddr)
params := icmpv6RA{
@@ -183,7 +183,7 @@ func (ra *raCtx) Init() error {
ipAndScope := ra.ipAddr.String() + "%" + ra.ifaceName
ra.conn, err = icmp.ListenPacket("ip6:ipv6-icmp", ipAndScope)
if err != nil {
return fmt.Errorf("DHCPv6 RA: icmp.ListenPacket: %s", err)
return fmt.Errorf("dhcpv6 ra: icmp.ListenPacket: %w", err)
}
success := false
defer func() {
@@ -195,11 +195,11 @@ func (ra *raCtx) Init() error {
con6 := ra.conn.IPv6PacketConn()
if err := con6.SetHopLimit(255); err != nil {
return fmt.Errorf("DHCPv6 RA: SetHopLimit: %s", err)
return fmt.Errorf("dhcpv6 ra: SetHopLimit: %w", err)
}
if err := con6.SetMulticastHopLimit(255); err != nil {
return fmt.Errorf("DHCPv6 RA: SetMulticastHopLimit: %s", err)
return fmt.Errorf("dhcpv6 ra: SetMulticastHopLimit: %w", err)
}
msg := &ipv6.ControlMessage{
@@ -212,15 +212,15 @@ func (ra *raCtx) Init() error {
}
go func() {
log.Debug("DHCPv6 RA: starting to send periodic RouterAdvertisement packets")
log.Debug("dhcpv6 ra: starting to send periodic RouterAdvertisement packets")
for ra.stop.Load() == 0 {
_, err = con6.WriteTo(data, msg, addr)
if err != nil {
log.Error("DHCPv6 RA: WriteTo: %s", err)
log.Error("dhcpv6 ra: WriteTo: %s", err)
}
time.Sleep(ra.packetSendPeriod)
}
log.Debug("DHCPv6 RA: loop exit")
log.Debug("dhcpv6 ra: loop exit")
}()
success = true
@@ -229,7 +229,7 @@ func (ra *raCtx) Init() error {
// Close - close module
func (ra *raCtx) Close() {
log.Debug("DHCPv6 RA: closing")
log.Debug("dhcpv6 ra: closing")
ra.stop.Store(1)

View File

@@ -36,7 +36,7 @@ func (s *v4Server) WriteDiskConfig6(c *V6ServerConf) {
}
// Return TRUE if IP address is within range [start..stop]
func ip4InRange(start net.IP, stop net.IP, ip net.IP) bool {
func ip4InRange(start, stop, ip net.IP) bool {
if len(start) != 4 || len(stop) != 4 {
return false
}
@@ -55,7 +55,7 @@ func (s *v4Server) ResetLeases(leases []*Lease) {
if l.Expiry.Unix() != leaseExpireStatic &&
!ip4InRange(s.conf.ipStart, s.conf.ipEnd, l.IP) {
log.Debug("DHCPv4: skipping a lease with IP %v: not within current IP range", l.IP)
log.Debug("dhcpv4: skipping a lease with IP %v: not within current IP range", l.IP)
continue
}
@@ -124,7 +124,7 @@ func (s *v4Server) blacklistLease(lease *Lease) {
// Remove (swap) lease by index
func (s *v4Server) leaseRemoveSwapByIndex(i int) {
s.ipAddrs[s.leases[i].IP[3]] = 0
log.Debug("DHCPv4: removed lease %s", s.leases[i].HWAddr)
log.Debug("dhcpv4: removed lease %s", s.leases[i].HWAddr)
n := len(s.leases)
if i != n-1 {
@@ -168,7 +168,7 @@ func (s *v4Server) rmDynamicLease(lease Lease) error {
func (s *v4Server) addLease(l *Lease) {
s.leases = append(s.leases, l)
s.ipAddrs[l.IP[3]] = 1
log.Debug("DHCPv4: added lease %s <-> %s", l.IP, l.HWAddr)
log.Debug("dhcpv4: added lease %s <-> %s", l.IP, l.HWAddr)
}
// Remove a lease with the same properties
@@ -178,8 +178,7 @@ func (s *v4Server) rmLease(lease Lease) error {
if !bytes.Equal(l.HWAddr, lease.HWAddr) ||
l.Hostname != lease.Hostname {
return fmt.Errorf("Lease not found")
return fmt.Errorf("lease not found")
}
s.leaseRemoveSwapByIndex(i)
@@ -238,7 +237,6 @@ func (s *v4Server) RemoveStaticLease(l Lease) error {
// Send ICMP to the specified machine
// Return TRUE if it doesn't reply, which probably means that the IP is available
func (s *v4Server) addrAvailable(target net.IP) bool {
if s.conf.ICMPTimeout == 0 {
return true
}
@@ -256,15 +254,15 @@ func (s *v4Server) addrAvailable(target net.IP) bool {
pinger.OnRecv = func(pkt *ping.Packet) {
reply = true
}
log.Debug("DHCPv4: Sending ICMP Echo to %v", target)
log.Debug("dhcpv4: Sending ICMP Echo to %v", target)
pinger.Run()
if reply {
log.Info("DHCPv4: IP conflict: %v is already used by another device", target)
log.Info("dhcpv4: IP conflict: %v is already used by another device", target)
return false
}
log.Debug("DHCPv4: ICMP procedure is complete: %v", target)
log.Debug("dhcpv4: ICMP procedure is complete: %v", target)
return true
}
@@ -337,7 +335,7 @@ func (s *v4Server) commitLease(l *Lease) {
}
// Process Discover request and return lease
func (s *v4Server) processDiscover(req *dhcpv4.DHCPv4, resp *dhcpv4.DHCPv4) *Lease {
func (s *v4Server) processDiscover(req, resp *dhcpv4.DHCPv4) *Lease {
mac := req.ClientHWAddr
s.leasesLock.Lock()
@@ -349,7 +347,7 @@ func (s *v4Server) processDiscover(req *dhcpv4.DHCPv4, resp *dhcpv4.DHCPv4) *Lea
for lease == nil {
lease = s.reserveLease(mac)
if lease == nil {
log.Debug("DHCPv4: No more IP addresses")
log.Debug("dhcpv4: No more IP addresses")
if toStore {
s.conf.notify(LeaseChangedDBStore)
}
@@ -372,7 +370,7 @@ func (s *v4Server) processDiscover(req *dhcpv4.DHCPv4, resp *dhcpv4.DHCPv4) *Lea
reqIP := req.Options.Get(dhcpv4.OptionRequestedIPAddress)
if len(reqIP) != 0 &&
!bytes.Equal(reqIP, lease.IP) {
log.Debug("DHCPv4: different RequestedIP: %v != %v", reqIP, lease.IP)
log.Debug("dhcpv4: different RequestedIP: %v != %v", reqIP, lease.IP)
}
}
@@ -407,12 +405,11 @@ func (o *optFQDN) ToBytes() []byte {
copy(b[i:], []byte(o.name))
return b
}
// Process Request request and return lease
// Return false if we don't need to reply
func (s *v4Server) processRequest(req *dhcpv4.DHCPv4, resp *dhcpv4.DHCPv4) (*Lease, bool) {
func (s *v4Server) processRequest(req, resp *dhcpv4.DHCPv4) (*Lease, bool) {
var lease *Lease
mac := req.ClientHWAddr
hostname := req.Options.Get(dhcpv4.OptionHostName)
@@ -424,12 +421,12 @@ func (s *v4Server) processRequest(req *dhcpv4.DHCPv4, resp *dhcpv4.DHCPv4) (*Lea
sid := req.Options.Get(dhcpv4.OptionServerIdentifier)
if len(sid) != 0 &&
!bytes.Equal(sid, s.conf.dnsIPAddrs[0]) {
log.Debug("DHCPv4: Bad OptionServerIdentifier in Request message for %s", mac)
log.Debug("dhcpv4: Bad OptionServerIdentifier in Request message for %s", mac)
return nil, false
}
if len(reqIP) != 4 {
log.Debug("DHCPv4: Bad OptionRequestedIPAddress in Request message for %s", mac)
log.Debug("dhcpv4: Bad OptionRequestedIPAddress in Request message for %s", mac)
return nil, false
}
@@ -438,7 +435,7 @@ func (s *v4Server) processRequest(req *dhcpv4.DHCPv4, resp *dhcpv4.DHCPv4) (*Lea
if bytes.Equal(l.HWAddr, mac) {
if !bytes.Equal(l.IP, reqIP) {
s.leasesLock.Unlock()
log.Debug("DHCPv4: Mismatched OptionRequestedIPAddress in Request message for %s", mac)
log.Debug("dhcpv4: Mismatched OptionRequestedIPAddress in Request message for %s", mac)
return nil, true
}
@@ -449,7 +446,7 @@ func (s *v4Server) processRequest(req *dhcpv4.DHCPv4, resp *dhcpv4.DHCPv4) (*Lea
s.leasesLock.Unlock()
if lease == nil {
log.Debug("DHCPv4: No lease for %s", mac)
log.Debug("dhcpv4: No lease for %s", mac)
return nil, true
}
@@ -475,8 +472,7 @@ func (s *v4Server) processRequest(req *dhcpv4.DHCPv4, resp *dhcpv4.DHCPv4) (*Lea
// Return 1: OK
// Return 0: error; reply with Nak
// Return -1: error; don't reply
func (s *v4Server) process(req *dhcpv4.DHCPv4, resp *dhcpv4.DHCPv4) int {
func (s *v4Server) process(req, resp *dhcpv4.DHCPv4) int {
var lease *Lease
resp.UpdateOption(dhcpv4.OptServerIdentifier(s.conf.dnsIPAddrs[0]))
@@ -519,7 +515,7 @@ func (s *v4Server) process(req *dhcpv4.DHCPv4, resp *dhcpv4.DHCPv4) int {
// client(0.0.0.0:68) -> (Request:ClientMAC,Type=Request,ClientID,ReqIP||ClientIP,HostName,ServerID,ParamReqList) -> server(255.255.255.255:67)
// client(255.255.255.255:68) <- (Reply:YourIP,ClientMAC,Type=ACK,ServerID,SubnetMask,LeaseTime) <- server(<IP>:67)
func (s *v4Server) packetHandler(conn net.PacketConn, peer net.Addr, req *dhcpv4.DHCPv4) {
log.Debug("DHCPv4: received message: %s", req.Summary())
log.Debug("dhcpv4: received message: %s", req.Summary())
switch req.MessageType() {
case dhcpv4.MessageTypeDiscover,
@@ -527,18 +523,18 @@ func (s *v4Server) packetHandler(conn net.PacketConn, peer net.Addr, req *dhcpv4
//
default:
log.Debug("DHCPv4: unsupported message type %d", req.MessageType())
log.Debug("dhcpv4: unsupported message type %d", req.MessageType())
return
}
resp, err := dhcpv4.NewReplyFromRequest(req)
if err != nil {
log.Debug("DHCPv4: dhcpv4.New: %s", err)
log.Debug("dhcpv4: dhcpv4.New: %s", err)
return
}
if len(req.ClientHWAddr) != 6 {
log.Debug("DHCPv4: Invalid ClientHWAddr")
log.Debug("dhcpv4: Invalid ClientHWAddr")
return
}
@@ -549,33 +545,74 @@ func (s *v4Server) packetHandler(conn net.PacketConn, peer net.Addr, req *dhcpv4
resp.Options.Update(dhcpv4.OptMessageType(dhcpv4.MessageTypeNak))
}
log.Debug("DHCPv4: sending: %s", resp.Summary())
log.Debug("dhcpv4: sending: %s", resp.Summary())
_, err = conn.WriteTo(resp.ToBytes(), peer)
if err != nil {
log.Error("DHCPv4: conn.Write to %s failed: %s", peer, err)
log.Error("dhcpv4: conn.Write to %s failed: %s", peer, err)
return
}
}
// Start - start server
// ifaceIPv4Addrs returns the interface's IPv4 addresses.
func ifaceIPv4Addrs(iface *net.Interface) (ips []net.IP, err error) {
addrs, err := iface.Addrs()
if err != nil {
return nil, err
}
for _, a := range addrs {
ipnet, ok := a.(*net.IPNet)
if !ok {
continue
}
if ip := ipnet.IP.To4(); ip != nil {
ips = append(ips, ip)
}
}
return ips, nil
}
// Start starts the IPv4 DHCP server.
func (s *v4Server) Start() error {
if !s.conf.Enabled {
return nil
}
iface, err := net.InterfaceByName(s.conf.InterfaceName)
ifaceName := s.conf.InterfaceName
iface, err := net.InterfaceByName(ifaceName)
if err != nil {
return fmt.Errorf("DHCPv4: Couldn't find interface by name %s: %s", s.conf.InterfaceName, err)
return fmt.Errorf("dhcpv4: finding interface %s by name: %w", ifaceName, err)
}
log.Debug("DHCPv4: starting...")
s.conf.dnsIPAddrs = getIfaceIPv4(*iface)
if len(s.conf.dnsIPAddrs) == 0 {
log.Debug("DHCPv4: no IPv6 address for interface %s", iface.Name)
return nil
log.Debug("dhcpv4: starting...")
dnsIPAddrs, err := ifaceIPv4Addrs(iface)
if err != nil {
return fmt.Errorf("dhcpv4: getting ipv4 addrs for iface %s: %w", ifaceName, err)
}
switch len(dnsIPAddrs) {
case 0:
log.Debug("dhcpv4: no ipv4 address for interface %s", iface.Name)
return nil
case 1:
// Some Android devices use 8.8.8.8 if there is no secondary DNS
// server. Fix that by setting the secondary DNS address to our
// address as well.
//
// See https://github.com/AdguardTeam/AdGuardHome/issues/1708.
log.Debug("dhcpv4: setting secondary dns ip to iself for interface %s", iface.Name)
dnsIPAddrs = append(dnsIPAddrs, dnsIPAddrs[0])
default:
// Go on.
}
s.conf.dnsIPAddrs = dnsIPAddrs
laddr := &net.UDPAddr{
IP: net.ParseIP("0.0.0.0"),
Port: dhcpv4.ServerPort,
@@ -585,12 +622,13 @@ func (s *v4Server) Start() error {
return err
}
log.Info("DHCPv4: listening")
log.Info("dhcpv4: listening")
go func() {
err = s.srv.Serve()
log.Debug("DHCPv4: srv.Serve: %s", err)
log.Debug("dhcpv4: srv.Serve: %s", err)
}()
return nil
}
@@ -600,10 +638,10 @@ func (s *v4Server) Stop() {
return
}
log.Debug("DHCPv4: stopping")
log.Debug("dhcpv4: stopping")
err := s.srv.Close()
if err != nil {
log.Error("DHCPv4: srv.Close: %s", err)
log.Error("dhcpv4: srv.Close: %s", err)
}
// now s.srv.Serve() will return
s.srv = nil
@@ -621,31 +659,31 @@ func v4Create(conf V4ServerConf) (DHCPServer, error) {
var err error
s.conf.routerIP, err = parseIPv4(s.conf.GatewayIP)
if err != nil {
return s, fmt.Errorf("DHCPv4: %s", err)
return s, fmt.Errorf("dhcpv4: %w", err)
}
subnet, err := parseIPv4(s.conf.SubnetMask)
if err != nil || !isValidSubnetMask(subnet) {
return s, fmt.Errorf("DHCPv4: invalid subnet mask: %s", s.conf.SubnetMask)
return s, fmt.Errorf("dhcpv4: invalid subnet mask: %s", s.conf.SubnetMask)
}
s.conf.subnetMask = make([]byte, 4)
copy(s.conf.subnetMask, subnet)
s.conf.ipStart, err = parseIPv4(conf.RangeStart)
if s.conf.ipStart == nil {
return s, fmt.Errorf("DHCPv4: %s", err)
return s, fmt.Errorf("dhcpv4: %w", err)
}
if s.conf.ipStart[0] == 0 {
return s, fmt.Errorf("DHCPv4: invalid range start IP")
return s, fmt.Errorf("dhcpv4: invalid range start IP")
}
s.conf.ipEnd, err = parseIPv4(conf.RangeEnd)
if s.conf.ipEnd == nil {
return s, fmt.Errorf("DHCPv4: %s", err)
return s, fmt.Errorf("dhcpv4: %w", err)
}
if !net.IP.Equal(s.conf.ipStart[:3], s.conf.ipEnd[:3]) ||
s.conf.ipStart[3] > s.conf.ipEnd[3] {
return s, fmt.Errorf("DHCPv4: range end IP should match range start IP")
return s, fmt.Errorf("dhcpv4: range end IP should match range start IP")
}
if conf.LeaseDuration == 0 {
@@ -658,7 +696,7 @@ func v4Create(conf V4ServerConf) (DHCPServer, error) {
for _, o := range conf.Options {
code, val := parseOptionString(o)
if code == 0 {
log.Debug("DHCPv4: bad option string: %s", o)
log.Debug("dhcpv4: bad option string: %s", o)
continue
}

View File

@@ -41,10 +41,11 @@ func (s *v6Server) WriteDiskConfig6(c *V6ServerConf) {
// Return TRUE if IP address is within range [start..0xff]
// nolint(staticcheck)
func ip6InRange(start net.IP, ip net.IP) bool {
func ip6InRange(start, ip net.IP) bool {
if len(start) != 16 {
return false
}
//lint:ignore SA1021 TODO(e.burkov): Ignore this for now, think about using masks.
if !bytes.Equal(start[:15], ip[:15]) {
return false
}
@@ -72,12 +73,10 @@ func (s *v6Server) GetLeases(flags int) []Lease {
var result []Lease
s.leasesLock.Lock()
for _, lease := range s.leases {
if lease.Expiry.Unix() == leaseExpireStatic {
if (flags & LeasesStatic) != 0 {
result = append(result, *lease)
}
} else {
if (flags & LeasesDynamic) != 0 {
result = append(result, *lease)
@@ -214,8 +213,7 @@ func (s *v6Server) rmLease(lease Lease) error {
if !bytes.Equal(l.HWAddr, lease.HWAddr) ||
l.Hostname != lease.Hostname {
return fmt.Errorf("Lease not found")
return fmt.Errorf("lease not found")
}
s.leaseRemoveSwapByIndex(i)
@@ -302,7 +300,7 @@ func (s *v6Server) commitDynamicLease(l *Lease) {
// Check Client ID
func (s *v6Server) checkCID(msg *dhcpv6.Message) error {
if msg.Options.ClientID() == nil {
return fmt.Errorf("DHCPv6: no ClientID option in request")
return fmt.Errorf("dhcpv6: no ClientID option in request")
}
return nil
}
@@ -317,7 +315,7 @@ func (s *v6Server) checkSID(msg *dhcpv6.Message) error {
dhcpv6.MessageTypeRebind:
if sid != nil {
return fmt.Errorf("DHCPv6: drop packet: ServerID option in message %s", msg.Type().String())
return fmt.Errorf("dhcpv6: drop packet: ServerID option in message %s", msg.Type().String())
}
case dhcpv6.MessageTypeRequest,
@@ -326,10 +324,10 @@ func (s *v6Server) checkSID(msg *dhcpv6.Message) error {
dhcpv6.MessageTypeDecline:
if sid == nil {
return fmt.Errorf("DHCPv6: drop packet: no ServerID option in message %s", msg.Type().String())
return fmt.Errorf("dhcpv6: drop packet: no ServerID option in message %s", msg.Type().String())
}
if !sid.Equal(s.sid) {
return fmt.Errorf("DHCPv6: drop packet: mismatched ServerID option in message %s: %s",
return fmt.Errorf("dhcpv6: drop packet: mismatched ServerID option in message %s: %s",
msg.Type().String(), sid.String())
}
}
@@ -371,7 +369,7 @@ func (s *v6Server) commitLease(msg *dhcpv6.Message, lease *Lease) time.Duration
//
case dhcpv6.MessageTypeConfirm:
lifetime = lease.Expiry.Sub(time.Now())
lifetime = time.Until(lease.Expiry)
case dhcpv6.MessageTypeRequest,
dhcpv6.MessageTypeRenew,
@@ -385,7 +383,7 @@ func (s *v6Server) commitLease(msg *dhcpv6.Message, lease *Lease) time.Duration
}
// Find a lease associated with MAC and prepare response
func (s *v6Server) process(msg *dhcpv6.Message, req dhcpv6.DHCPv6, resp dhcpv6.DHCPv6) bool {
func (s *v6Server) process(msg *dhcpv6.Message, req, resp dhcpv6.DHCPv6) bool {
switch msg.Type() {
case dhcpv6.MessageTypeSolicit,
dhcpv6.MessageTypeRequest,
@@ -539,24 +537,25 @@ func (s *v6Server) packetHandler(conn net.PacketConn, peer net.Addr, req dhcpv6.
}
}
// Get IPv6 address list
func getIfaceIPv6(iface net.Interface) []net.IP {
// ifaceIPv6Addrs returns the interface's IPv6 addresses.
func ifaceIPv6Addrs(iface *net.Interface) (ips []net.IP, err error) {
addrs, err := iface.Addrs()
if err != nil {
return nil
return nil, err
}
var res []net.IP
for _, a := range addrs {
ipnet, ok := a.(*net.IPNet)
if !ok {
continue
}
if ipnet.IP.To4() == nil {
res = append(res, ipnet.IP)
if ip := ipnet.IP.To16(); ip != nil {
ips = append(ips, ip)
}
}
return res
return ips, nil
}
// initialize RA module
@@ -580,23 +579,40 @@ func (s *v6Server) initRA(iface *net.Interface) error {
return s.ra.Init()
}
// Start - start server
// Start starts the IPv6 DHCP server.
func (s *v6Server) Start() error {
if !s.conf.Enabled {
return nil
}
iface, err := net.InterfaceByName(s.conf.InterfaceName)
ifaceName := s.conf.InterfaceName
iface, err := net.InterfaceByName(ifaceName)
if err != nil {
return wrapErrPrint(err, "Couldn't find interface by name %s", s.conf.InterfaceName)
return fmt.Errorf("dhcpv6: finding interface %s by name: %w", ifaceName, err)
}
s.conf.dnsIPAddrs = getIfaceIPv6(*iface)
if len(s.conf.dnsIPAddrs) == 0 {
log.Debug("DHCPv6: no IPv6 address for interface %s", iface.Name)
return nil
log.Debug("dhcpv4: starting...")
dnsIPAddrs, err := ifaceIPv6Addrs(iface)
if err != nil {
return fmt.Errorf("dhcpv6: getting ipv6 addrs for iface %s: %w", ifaceName, err)
}
switch len(dnsIPAddrs) {
case 0:
log.Debug("dhcpv6: no ipv6 address for interface %s", iface.Name)
return nil
case 1:
// See the comment in (*v4Server).Start.
log.Debug("dhcpv6: setting secondary dns ip to iself for interface %s", iface.Name)
dnsIPAddrs = append(dnsIPAddrs, dnsIPAddrs[0])
default:
// Go on.
}
s.conf.dnsIPAddrs = dnsIPAddrs
err = s.initRA(iface)
if err != nil {
return err
@@ -611,7 +627,7 @@ func (s *v6Server) Start() error {
log.Debug("DHCPv6: starting...")
if len(iface.HardwareAddr) != 6 {
return fmt.Errorf("DHCPv6: invalid MAC %s", iface.HardwareAddr)
return fmt.Errorf("dhcpv6: invalid MAC %s", iface.HardwareAddr)
}
s.sid = dhcpv6.Duid{
Type: dhcpv6.DUID_LLT,
@@ -666,7 +682,7 @@ func v6Create(conf V6ServerConf) (DHCPServer, error) {
s.conf.ipStart = net.ParseIP(conf.RangeStart)
if s.conf.ipStart == nil || s.conf.ipStart.To16() == nil {
return s, fmt.Errorf("DHCPv6: invalid range-start IP: %s", conf.RangeStart)
return s, fmt.Errorf("dhcpv6: invalid range-start IP: %s", conf.RangeStart)
}
if conf.LeaseDuration == 0 {

View File

@@ -22,12 +22,12 @@ func main() {
res, err := filter.CheckHost(host)
if err != nil {
// temporary failure
log.Fatalf("Failed to check host '%s': %s", host, err)
log.Fatalf("Failed to check host %q: %s", host, err)
}
if res.IsFiltered {
log.Printf("Host %s is filtered, reason - '%s', matched rule: '%s'", host, res.Reason, res.Rule)
log.Printf("Host %s is filtered, reason - %q, matched rule: %q", host, res.Reason, res.Rule)
} else {
log.Printf("Host %s is not filtered, reason - '%s'", host, res.Reason)
log.Printf("Host %s is not filtered, reason - %q", host, res.Reason)
}
}
```
@@ -59,12 +59,12 @@ func main() {
res, err := filter.CheckHost(host)
if err != nil {
// temporary failure
log.Fatalf("Failed to check host '%s': %s", host, err)
log.Fatalf("Failed to check host %q: %s", host, err)
}
if res.IsFiltered {
log.Printf("Host %s is filtered, reason - '%s', matched rule: '%s'", host, res.Reason, res.Rule)
log.Printf("Host %s is filtered, reason - %q, matched rule: %q", host, res.Reason, res.Rule)
} else {
log.Printf("Host %s is not filtered, reason - '%s'", host, res.Reason)
log.Printf("Host %s is not filtered, reason - %q", host, res.Reason)
}
}
```

View File

@@ -1,3 +1,4 @@
// Package dnsfilter implements a DNS filter.
package dnsfilter
import (
@@ -11,7 +12,7 @@ import (
"strings"
"sync"
"github.com/AdguardTeam/AdGuardHome/util"
"github.com/AdguardTeam/AdGuardHome/internal/util"
"github.com/AdguardTeam/dnsproxy/upstream"
"github.com/AdguardTeam/golibs/cache"
"github.com/AdguardTeam/golibs/log"
@@ -199,7 +200,7 @@ func (d *Dnsfilter) WriteDiskConfig(c *Config) {
// SetFilters - set new filters (synchronously or asynchronously)
// When filters are set asynchronously, the old filters continue working until the new filters are ready.
// In this case the caller must ensure that the old filter files are intact.
func (d *Dnsfilter) SetFilters(blockFilters []Filter, allowFilters []Filter, async bool) error {
func (d *Dnsfilter) SetFilters(blockFilters, allowFilters []Filter, async bool) error {
if async {
params := filtersInitializerParams{
allowFilters: allowFilters,
@@ -281,7 +282,7 @@ type Result struct {
CanonName string `json:",omitempty"` // CNAME value
// for RewriteEtcHosts:
ReverseHost string `json:",omitempty"`
ReverseHosts []string `json:",omitempty"`
// for ReasonRewrite & RewriteEtcHosts:
IPList []net.IP `json:",omitempty"` // list of IP addresses
@@ -325,18 +326,9 @@ func (d *Dnsfilter) CheckHost(host string, qtype uint16, setts *RequestFiltering
// Now check the hosts file -- do we have any rules for it?
// just like DNS rewrites, it has higher priority than filtering rules.
if d.Config.AutoHosts != nil {
ips := d.Config.AutoHosts.Process(host, qtype)
if ips != nil {
result.Reason = RewriteEtcHosts
result.IPList = ips
return result, nil
}
revHost := d.Config.AutoHosts.ProcessReverse(host, qtype)
if len(revHost) != 0 {
result.Reason = RewriteEtcHosts
result.ReverseHost = revHost + "."
return result, nil
matched, err := d.checkAutoHosts(host, qtype, &result)
if matched {
return result, err
}
}
@@ -401,6 +393,31 @@ func (d *Dnsfilter) CheckHost(host string, qtype uint16, setts *RequestFiltering
return Result{}, nil
}
func (d *Dnsfilter) checkAutoHosts(host string, qtype uint16, result *Result) (matched bool, err error) {
ips := d.Config.AutoHosts.Process(host, qtype)
if ips != nil {
result.Reason = RewriteEtcHosts
result.IPList = ips
return true, nil
}
revHosts := d.Config.AutoHosts.ProcessReverse(host, qtype)
if len(revHosts) != 0 {
result.Reason = RewriteEtcHosts
// TODO(a.garipov): Optimize this with a buffer.
result.ReverseHosts = make([]string, len(revHosts))
for i := range revHosts {
result.ReverseHosts[i] = revHosts[i] + "."
}
return true, nil
}
return false, nil
}
// Process rewrites table
// . Find CNAME for a domain name (exact match or by wildcard)
// . if found and CNAME equals to domain name - this is an exception; exit
@@ -481,13 +498,10 @@ func matchBlockedServicesRules(host string, svcs []ServiceEntry) Result {
// Adding rule and matching against the rules
//
// Return TRUE if file exists
// fileExists returns true if file exists.
func fileExists(fn string) bool {
_, err := os.Stat(fn)
if err != nil {
return false
}
return true
return err == nil
}
func createFilteringEngine(filters []Filter) (*filterlist.RuleStorage, *urlfilter.DNSEngine, error) {
@@ -501,19 +515,18 @@ func createFilteringEngine(filters []Filter) (*filterlist.RuleStorage, *urlfilte
RulesText: string(f.Data),
IgnoreCosmetic: true,
}
} else if !fileExists(f.FilePath) {
list = &filterlist.StringRuleList{
ID: int(f.ID),
IgnoreCosmetic: true,
}
} else if runtime.GOOS == "windows" {
// On Windows we don't pass a file to urlfilter because
// it's difficult to update this file while it's being used.
// it's difficult to update this file while it's being
// used.
data, err := ioutil.ReadFile(f.FilePath)
if err != nil {
return nil, nil, fmt.Errorf("ioutil.ReadFile(): %s: %s", f.FilePath, err)
return nil, nil, fmt.Errorf("ioutil.ReadFile(): %s: %w", f.FilePath, err)
}
list = &filterlist.StringRuleList{
ID: int(f.ID),
@@ -525,7 +538,7 @@ func createFilteringEngine(filters []Filter) (*filterlist.RuleStorage, *urlfilte
var err error
list, err = filterlist.NewFileRuleList(int(f.ID), f.FilePath, true)
if err != nil {
return nil, nil, fmt.Errorf("filterlist.NewFileRuleList(): %s: %s", f.FilePath, err)
return nil, nil, fmt.Errorf("filterlist.NewFileRuleList(): %s: %w", f.FilePath, err)
}
}
listArray = append(listArray, list)
@@ -533,13 +546,13 @@ func createFilteringEngine(filters []Filter) (*filterlist.RuleStorage, *urlfilte
rulesStorage, err := filterlist.NewRuleStorage(listArray)
if err != nil {
return nil, nil, fmt.Errorf("filterlist.NewRuleStorage(): %s", err)
return nil, nil, fmt.Errorf("filterlist.NewRuleStorage(): %w", err)
}
filteringEngine := urlfilter.NewDNSEngine(rulesStorage)
return rulesStorage, filteringEngine, nil
}
// Initialize urlfilter objects
// Initialize urlfilter objects.
func (d *Dnsfilter) initFiltering(allowFilters, blockFilters []Filter) error {
rulesStorage, filteringEngine, err := createFilteringEngine(blockFilters)
if err != nil {
@@ -565,7 +578,8 @@ func (d *Dnsfilter) initFiltering(allowFilters, blockFilters []Filter) error {
return nil
}
// matchHost is a low-level way to check only if hostname is filtered by rules, skipping expensive safebrowsing and parental lookups
// matchHost is a low-level way to check only if hostname is filtered by rules,
// skipping expensive safebrowsing and parental lookups.
func (d *Dnsfilter) matchHost(host string, qtype uint16, setts RequestFilteringSettings) (Result, error) {
d.engineLock.RLock()
// Keep in mind that this lock must be held no just when calling Match()
@@ -590,7 +604,7 @@ func (d *Dnsfilter) matchHost(host string, qtype uint16, setts RequestFilteringS
rule = rr.HostRulesV6[0]
}
log.Debug("Filtering: found whitelist rule for host '%s': '%s' list_id: %d",
log.Debug("Filtering: found whitelist rule for host %q: %q list_id: %d",
host, rule.Text(), rule.GetFilterListID())
res := makeResult(rule, NotFilteredWhiteList)
return res, nil
@@ -607,7 +621,7 @@ func (d *Dnsfilter) matchHost(host string, qtype uint16, setts RequestFilteringS
}
if rr.NetworkRule != nil {
log.Debug("Filtering: found rule for host '%s': '%s' list_id: %d",
log.Debug("Filtering: found rule for host %q: %q list_id: %d",
host, rr.NetworkRule.Text(), rr.NetworkRule.GetFilterListID())
reason := FilteredBlackList
if rr.NetworkRule.Whitelist {
@@ -619,7 +633,7 @@ func (d *Dnsfilter) matchHost(host string, qtype uint16, setts RequestFilteringS
if qtype == dns.TypeA && rr.HostRulesV4 != nil {
rule := rr.HostRulesV4[0] // note that we process only 1 matched rule
log.Debug("Filtering: found rule for host '%s': '%s' list_id: %d",
log.Debug("Filtering: found rule for host %q: %q list_id: %d",
host, rule.Text(), rule.GetFilterListID())
res := makeResult(rule, FilteredBlackList)
res.IP = rule.IP.To4()
@@ -628,7 +642,7 @@ func (d *Dnsfilter) matchHost(host string, qtype uint16, setts RequestFilteringS
if qtype == dns.TypeAAAA && rr.HostRulesV6 != nil {
rule := rr.HostRulesV6[0] // note that we process only 1 matched rule
log.Debug("Filtering: found rule for host '%s': '%s' list_id: %d",
log.Debug("Filtering: found rule for host %q: %q list_id: %d",
host, rule.Text(), rule.GetFilterListID())
res := makeResult(rule, FilteredBlackList)
res.IP = rule.IP
@@ -644,7 +658,7 @@ func (d *Dnsfilter) matchHost(host string, qtype uint16, setts RequestFilteringS
} else if rr.HostRulesV6 != nil {
rule = rr.HostRulesV6[0]
}
log.Debug("Filtering: found rule for host '%s': '%s' list_id: %d",
log.Debug("Filtering: found rule for host %q: %q list_id: %d",
host, rule.Text(), rule.GetFilterListID())
res := makeResult(rule, FilteredBlackList)
res.IP = net.IP{}
@@ -666,21 +680,18 @@ func makeResult(rule rules.Rule, reason Reason) Result {
return res
}
// InitModule() - manually initialize blocked services map
// InitModule manually initializes blocked services map.
func InitModule() {
initBlockedServices()
}
// New creates properly initialized DNS Filter that is ready to be used
// New creates properly initialized DNS Filter that is ready to be used.
func New(c *Config, blockFilters []Filter) *Dnsfilter {
if c != nil {
cacheConf := cache.Config{
EnableLRU: true,
}
// initialize objects only once
if gctx.safebrowsingCache == nil {
cacheConf.MaxSize = c.SafeBrowsingCacheSize
gctx.safebrowsingCache = cache.New(cacheConf)
@@ -713,7 +724,7 @@ func New(c *Config, blockFilters []Filter) *Dnsfilter {
bsvcs := []string{}
for _, s := range d.BlockedServices {
if !BlockedSvcKnown(s) {
log.Debug("skipping unknown blocked-service '%s'", s)
log.Debug("skipping unknown blocked-service %q", s)
continue
}
bsvcs = append(bsvcs, s)
@@ -750,7 +761,7 @@ func (d *Dnsfilter) Start() {
// stats
//
// GetStats return dns filtering stats since startup
// GetStats return dns filtering stats since startup.
func (d *Dnsfilter) GetStats() Stats {
return gctx.stats
}

View File

@@ -3,9 +3,6 @@ package dnsfilter
import (
"fmt"
"net"
"os"
"path"
"runtime"
"testing"
"github.com/AdguardTeam/urlfilter/rules"
@@ -36,13 +33,6 @@ func purgeCaches() {
}
}
func _Func() string {
pc := make([]uintptr, 10) // at least 1 entry needed
runtime.Callers(2, pc)
f := runtime.FuncForPC(pc[0])
return path.Base(f.Name())
}
func NewForTest(c *Config, filters []Filter) *Dnsfilter {
setts = RequestFilteringSettings{}
setts.FilteringEnabled = true
@@ -71,7 +61,7 @@ func (d *Dnsfilter) checkMatch(t *testing.T, hostname string) {
}
}
func (d *Dnsfilter) checkMatchIP(t *testing.T, hostname string, ip string, qtype uint16) {
func (d *Dnsfilter) checkMatchIP(t *testing.T, hostname, ip string, qtype uint16) {
t.Helper()
ret, err := d.CheckHost(hostname, qtype, &setts)
if err != nil {
@@ -107,7 +97,7 @@ func TestEtcHostsMatching(t *testing.T) {
::1 host2
`,
addr, addr6)
filters := []Filter{Filter{
filters := []Filter{{
ID: 0, Data: []byte(text),
}}
d := NewForTest(nil, filters)
@@ -351,11 +341,15 @@ func TestParentalControl(t *testing.T) {
// FILTERING
var blockingRules = "||example.org^\n"
var whitelistRules = "||example.org^\n@@||test.example.org\n"
var importantRules = "@@||example.org^\n||test.example.org^$important\n"
var regexRules = "/example\\.org/\n@@||test.example.org^\n"
var maskRules = "test*.example.org^\nexam*.com\n"
const nl = "\n"
const (
blockingRules = `||example.org^` + nl
whitelistRules = `||example.org^` + nl + `@@||test.example.org` + nl
importantRules = `@@||example.org^` + nl + `||test.example.org^$important` + nl
regexRules = `/example\.org/` + nl + `@@||test.example.org^` + nl
maskRules = `test*.example.org^` + nl + `exam*.com` + nl
)
var tests = []struct {
testname string
@@ -406,7 +400,7 @@ var tests = []struct {
func TestMatching(t *testing.T) {
for _, test := range tests {
t.Run(fmt.Sprintf("%s-%s", test.testname, test.hostname), func(t *testing.T) {
filters := []Filter{Filter{
filters := []Filter{{
ID: 0, Data: []byte(test.rules),
}}
d := NewForTest(nil, filters)
@@ -430,14 +424,14 @@ func TestWhitelist(t *testing.T) {
rules := `||host1^
||host2^
`
filters := []Filter{Filter{
filters := []Filter{{
ID: 0, Data: []byte(rules),
}}
whiteRules := `||host1^
||host3^
`
whiteFilters := []Filter{Filter{
whiteFilters := []Filter{{
ID: 0, Data: []byte(whiteRules),
}}
d := NewForTest(nil, filters)
@@ -455,7 +449,6 @@ func TestWhitelist(t *testing.T) {
assert.True(t, err == nil)
assert.True(t, ret.IsFiltered && ret.Reason == FilteredBlackList)
assert.True(t, ret.Rule == "||host2^")
}
// CLIENT SETTINGS
@@ -476,7 +469,7 @@ func applyClientSettings(setts *RequestFilteringSettings) {
// then apply per-client settings and check behaviour once again
func TestClientSettings(t *testing.T) {
var r Result
filters := []Filter{Filter{
filters := []Filter{{
ID: 0, Data: []byte("||example.org^\n"),
}}
d := NewForTest(&Config{ParentalEnabled: true, SafeBrowsingEnabled: false}, filters)
@@ -532,13 +525,6 @@ func TestClientSettings(t *testing.T) {
assert.True(t, r.IsFiltered && r.Reason == FilteredBlockedService)
}
func prepareTestDir() string {
const dir = "./agh-test"
_ = os.RemoveAll(dir)
_ = os.MkdirAll(dir, 0755)
return dir
}
// BENCHMARKS
func BenchmarkSafeBrowsing(b *testing.B) {

View File

@@ -22,8 +22,7 @@ func (d *Dnsfilter) setCacheResult(cache cache.Cache, host string, res Result) i
var buf bytes.Buffer
expire := uint(time.Now().Unix()) + d.Config.CacheTime*60
var exp []byte
exp = make([]byte, 4)
exp := make([]byte, 4)
binary.BigEndian.PutUint32(exp, uint32(expire))
_, _ = buf.Write(exp)

View File

@@ -22,11 +22,13 @@ import (
"golang.org/x/net/publicsuffix"
)
const dnsTimeout = 3 * time.Second
const defaultSafebrowsingServer = "https://dns-family.adguard.com/dns-query"
const defaultParentalServer = "https://dns-family.adguard.com/dns-query"
const sbTXTSuffix = "sb.dns.adguard.com."
const pcTXTSuffix = "pc.dns.adguard.com."
const (
dnsTimeout = 3 * time.Second
defaultSafebrowsingServer = `https://dns-family.adguard.com/dns-query`
defaultParentalServer = `https://dns-family.adguard.com/dns-query`
sbTXTSuffix = `sb.dns.adguard.com.`
pcTXTSuffix = `pc.dns.adguard.com.`
)
func (d *Dnsfilter) initSecurityServices() error {
var err error
@@ -60,7 +62,7 @@ expire byte[4]
hash byte[32]
...
*/
func (c *sbCtx) setCache(prefix []byte, hashes []byte) {
func (c *sbCtx) setCache(prefix, hashes []byte) {
d := make([]byte, 4+len(hashes))
expire := uint(time.Now().Unix()) + c.cacheTime*60
binary.BigEndian.PutUint32(d[:4], uint32(expire))
@@ -158,16 +160,28 @@ func hostnameToHashes(host string) map[[32]byte]string {
// convert hash array to string
func (c *sbCtx) getQuestion() string {
q := ""
b := &strings.Builder{}
encoder := hex.NewEncoder(b)
for hash := range c.hashToHost {
q += fmt.Sprintf("%s.", hex.EncodeToString(hash[0:2]))
// Ignore errors, since strings.(*Buffer).Write never returns
// errors.
//
// TODO(e.burkov, a.garipov): Find out and document why exactly
// this slice.
_, _ = encoder.Write(hash[0:2])
_, _ = b.WriteRune('.')
}
if c.svc == "SafeBrowsing" {
q += sbTXTSuffix
} else {
q += pcTXTSuffix
// See comment above.
_, _ = b.WriteString(sbTXTSuffix)
return b.String()
}
return q
// See comment above.
_, _ = b.WriteString(pcTXTSuffix)
return b.String()
}
// Find the target hash in TXT response

View File

@@ -23,16 +23,16 @@ func TestSafeBrowsingHash(t *testing.T) {
assert.False(t, ok)
c := &sbCtx{
svc: "SafeBrowsing",
svc: "SafeBrowsing",
hashToHost: hashes,
}
// test getQuestion()
c.hashToHost = hashes
q := c.getQuestion()
assert.True(t, strings.Index(q, "7a1b.") >= 0)
assert.True(t, strings.Index(q, "af5a.") >= 0)
assert.True(t, strings.Index(q, "eb11.") >= 0)
assert.True(t, strings.Index(q, "sb.dns.adguard.com.") > 0)
assert.True(t, strings.Contains(q, "7a1b."))
assert.True(t, strings.Contains(q, "af5a."))
assert.True(t, strings.Contains(q, "eb11."))
assert.True(t, strings.HasSuffix(q, "sb.dns.adguard.com."))
}
func TestSafeBrowsingCache(t *testing.T) {

View File

@@ -51,7 +51,7 @@ func (a *accessCtx) Init(allowedClients, disallowedClients, blockedHosts []strin
listArray = append(listArray, list)
rulesStorage, err := filterlist.NewRuleStorage(listArray)
if err != nil {
return fmt.Errorf("filterlist.NewRuleStorage(): %s", err)
return fmt.Errorf("filterlist.NewRuleStorage(): %w", err)
}
a.blockedHostsEngine = urlfilter.NewDNSEngine(rulesStorage)

View File

@@ -10,12 +10,11 @@ import (
"net/http"
"sort"
"github.com/AdguardTeam/AdGuardHome/dnsfilter"
"github.com/AdguardTeam/AdGuardHome/util"
"github.com/AdguardTeam/AdGuardHome/internal/dnsfilter"
"github.com/AdguardTeam/AdGuardHome/internal/util"
"github.com/AdguardTeam/dnsproxy/proxy"
"github.com/AdguardTeam/dnsproxy/upstream"
"github.com/AdguardTeam/golibs/log"
"github.com/joomcode/errorx"
)
// FilteringConfig represents the DNS filtering configuration of AdGuard Home
@@ -252,14 +251,14 @@ func (s *Server) prepareUpstreamSettings() error {
upstreams = filterOutComments(upstreams)
upstreamConfig, err := proxy.ParseUpstreamsConfig(upstreams, s.conf.BootstrapDNS, DefaultTimeout)
if err != nil {
return fmt.Errorf("DNS: proxy.ParseUpstreamsConfig: %s", err)
return fmt.Errorf("dns: proxy.ParseUpstreamsConfig: %w", err)
}
if len(upstreamConfig.Upstreams) == 0 {
log.Info("Warning: no default upstream servers specified, using %v", defaultDNS)
uc, err := proxy.ParseUpstreamsConfig(defaultDNS, s.conf.BootstrapDNS, DefaultTimeout)
if err != nil {
return fmt.Errorf("DNS: failed to parse default upstreams: %v", err)
return fmt.Errorf("dns: failed to parse default upstreams: %v", err)
}
upstreamConfig.Upstreams = uc.Upstreams
}
@@ -300,13 +299,13 @@ func (s *Server) prepareTLS(proxyConfig *proxy.Config) error {
var err error
s.conf.cert, err = tls.X509KeyPair(s.conf.CertificateChainData, s.conf.PrivateKeyData)
if err != nil {
return errorx.Decorate(err, "Failed to parse TLS keypair")
return fmt.Errorf("failed to parse TLS keypair: %w", err)
}
if s.conf.StrictSNICheck {
x, err := x509.ParseCertificate(s.conf.cert.Certificate[0])
if err != nil {
return errorx.Decorate(err, "x509.ParseCertificate(): %s", err)
return fmt.Errorf("x509.ParseCertificate(): %w", err)
}
if len(x.DNSNames) != 0 {
s.conf.dnsNames = x.DNSNames

View File

@@ -1,3 +1,4 @@
// Package dnsforward contains a DNS forwarding server.
package dnsforward
import (
@@ -8,13 +9,12 @@ import (
"sync"
"time"
"github.com/AdguardTeam/AdGuardHome/dhcpd"
"github.com/AdguardTeam/AdGuardHome/dnsfilter"
"github.com/AdguardTeam/AdGuardHome/querylog"
"github.com/AdguardTeam/AdGuardHome/stats"
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
"github.com/AdguardTeam/AdGuardHome/internal/dnsfilter"
"github.com/AdguardTeam/AdGuardHome/internal/querylog"
"github.com/AdguardTeam/AdGuardHome/internal/stats"
"github.com/AdguardTeam/dnsproxy/proxy"
"github.com/AdguardTeam/golibs/log"
"github.com/joomcode/errorx"
"github.com/miekg/dns"
)
@@ -181,12 +181,9 @@ func (s *Server) Prepare(config *ServerConfig) error {
s.conf.BlockingIPAddrv4 = net.ParseIP(s.conf.BlockingIPv4)
s.conf.BlockingIPAddrv6 = net.ParseIP(s.conf.BlockingIPv6)
if s.conf.BlockingIPAddrv4 == nil || s.conf.BlockingIPAddrv6 == nil {
return fmt.Errorf("DNS: invalid custom blocking IP address specified")
return fmt.Errorf("dns: invalid custom blocking IP address specified")
}
}
if s.conf.MaxGoroutines == 0 {
s.conf.MaxGoroutines = 50
}
}
// Set default values in the case if nothing is configured
@@ -249,7 +246,7 @@ func (s *Server) stopInternal() error {
if s.dnsProxy != nil {
err := s.dnsProxy.Stop()
if err != nil {
return errorx.Decorate(err, "could not stop the DNS server properly")
return fmt.Errorf("could not stop the DNS server properly: %w", err)
}
}
@@ -272,7 +269,7 @@ func (s *Server) Reconfigure(config *ServerConfig) error {
log.Print("Start reconfiguring the server")
err := s.stopInternal()
if err != nil {
return errorx.Decorate(err, "could not reconfigure the server")
return fmt.Errorf("could not reconfigure the server: %w", err)
}
// It seems that net.Listener.Close() doesn't close file descriptors right away.
@@ -281,12 +278,12 @@ func (s *Server) Reconfigure(config *ServerConfig) error {
err = s.Prepare(config)
if err != nil {
return errorx.Decorate(err, "could not reconfigure the server")
return fmt.Errorf("could not reconfigure the server: %w", err)
}
err = s.startInternal()
if err != nil {
return errorx.Decorate(err, "could not reconfigure the server")
return fmt.Errorf("could not reconfigure the server: %w", err)
}
return nil

View File

@@ -17,7 +17,7 @@ import (
func httpError(r *http.Request, w http.ResponseWriter, code int, format string, args ...interface{}) {
text := fmt.Sprintf(format, args...)
log.Info("DNS: %s %s: %s", r.Method, r.URL, text)
log.Info("dns: %s %s: %s", r.Method, r.URL, text)
http.Error(w, text, code)
}
@@ -102,7 +102,7 @@ func checkBootstrap(addr string) error {
}
_, err := upstream.NewResolver(addr, 0)
if err != nil {
return fmt.Errorf("invalid bootstrap server address: %s", err)
return fmt.Errorf("invalid bootstrap server address: %w", err)
}
return nil
}
@@ -322,7 +322,7 @@ func separateUpstream(upstream string) (string, bool, error) {
// split domains and upstream string
domainsAndUpstream := strings.Split(strings.TrimPrefix(upstream, "[/"), "/]")
if len(domainsAndUpstream) != 2 {
return "", defaultUpstream, fmt.Errorf("wrong DNS upstream per domain specification: %s", upstream)
return "", defaultUpstream, fmt.Errorf("wrong dns upstream per domain specification: %s", upstream)
}
// split domains list and validate each one
@@ -357,7 +357,7 @@ func checkPlainDNS(upstream string) error {
_, err = strconv.ParseInt(port, 0, 64)
if err != nil {
return fmt.Errorf("%s is not a valid port: %s", port, err)
return fmt.Errorf("%s is not a valid port: %w", port, err)
}
return nil
@@ -405,7 +405,7 @@ func checkDNS(input string, bootstrap []string) error {
// separate upstream from domains list
input, defaultUpstream, err := separateUpstream(input)
if err != nil {
return fmt.Errorf("wrong upstream format: %s", err)
return fmt.Errorf("wrong upstream format: %w", err)
}
// No need to check this DNS server
@@ -414,17 +414,17 @@ func checkDNS(input string, bootstrap []string) error {
}
if _, err := validateUpstream(input); err != nil {
return fmt.Errorf("wrong upstream format: %s", err)
return fmt.Errorf("wrong upstream format: %w", err)
}
if len(bootstrap) == 0 {
bootstrap = defaultBootstrap
}
log.Debug("Checking if DNS %s works...", input)
log.Debug("checking if dns %s works...", input)
u, err := upstream.AddressToUpstream(input, upstream.Options{Bootstrap: bootstrap, Timeout: DefaultTimeout})
if err != nil {
return fmt.Errorf("failed to choose upstream for %s: %s", input, err)
return fmt.Errorf("failed to choose upstream for %s: %w", input, err)
}
req := dns.Msg{}
@@ -435,18 +435,18 @@ func checkDNS(input string, bootstrap []string) error {
}
reply, err := u.Exchange(&req)
if err != nil {
return fmt.Errorf("couldn't communicate with DNS server %s: %s", input, err)
return fmt.Errorf("couldn't communicate with dns server %s: %w", input, err)
}
if len(reply.Answer) != 1 {
return fmt.Errorf("DNS server %s returned wrong answer", input)
return fmt.Errorf("dns server %s returned wrong answer", input)
}
if t, ok := reply.Answer[0].(*dns.A); ok {
if !net.IPv4(8, 8, 8, 8).Equal(t.A) {
return fmt.Errorf("DNS server %s returned wrong answer: %v", input, t.A)
return fmt.Errorf("dns server %s returned wrong answer: %v", input, t.A)
}
}
log.Debug("DNS %s works OK", input)
log.Debug("dns %s works OK", input)
return nil
}
@@ -462,7 +462,7 @@ func (s *Server) handleDOH(w http.ResponseWriter, r *http.Request) {
}
if !s.IsRunning() {
httpError(r, w, http.StatusInternalServerError, "DNS server is not running")
httpError(r, w, http.StatusInternalServerError, "dns server is not running")
return
}

View File

@@ -18,10 +18,10 @@ import (
"testing"
"time"
"github.com/AdguardTeam/AdGuardHome/util"
"github.com/AdguardTeam/AdGuardHome/internal/util"
"github.com/AdguardTeam/AdGuardHome/dhcpd"
"github.com/AdguardTeam/AdGuardHome/dnsfilter"
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
"github.com/AdguardTeam/AdGuardHome/internal/dnsfilter"
"github.com/AdguardTeam/dnsproxy/proxy"
"github.com/AdguardTeam/dnsproxy/upstream"
"github.com/miekg/dns"
@@ -815,12 +815,12 @@ func sendTestMessageAsync(t *testing.T, conn *dns.Conn, g *sync.WaitGroup) {
req := createGoogleATestMessage()
err := conn.WriteMsg(req)
if err != nil {
t.Fatalf("cannot write message: %s", err)
panic(fmt.Sprintf("cannot write message: %s", err))
}
res, err := conn.ReadMsg()
if err != nil {
t.Fatalf("cannot read response to message: %s", err)
panic(fmt.Sprintf("cannot read response to message: %s", err))
}
assertGoogleAResponse(t, res)
}
@@ -916,20 +916,23 @@ func publicKey(priv interface{}) interface{} {
}
func TestValidateUpstream(t *testing.T) {
invalidUpstreams := []string{"1.2.3.4.5",
invalidUpstreams := []string{
"1.2.3.4.5",
"123.3.7m",
"htttps://google.com/dns-query",
"[/host.com]tls://dns.adguard.com",
"[host.ru]#",
}
validDefaultUpstreams := []string{"1.1.1.1",
validDefaultUpstreams := []string{
"1.1.1.1",
"tls://1.1.1.1",
"https://dns.adguard.com/dns-query",
"sdns://AQMAAAAAAAAAFDE3Ni4xMDMuMTMwLjEzMDo1NDQzINErR_JS3PLCu_iZEIbq95zkSV2LFsigxDIuUso_OQhzIjIuZG5zY3J5cHQuZGVmYXVsdC5uczEuYWRndWFyZC5jb20",
}
validUpstreams := []string{"[/host.com/]1.1.1.1",
validUpstreams := []string{
"[/host.com/]1.1.1.1",
"[//]tls://1.1.1.1",
"[/www.host.com/]#",
"[/host.com/google.com/]8.8.8.8",
@@ -975,7 +978,8 @@ func TestValidateUpstreamsSet(t *testing.T) {
assert.Nil(t, err, "comments should not be validated")
// Set of valid upstreams. There is no default upstream specified
upstreamsSet = []string{"[/host.com/]1.1.1.1",
upstreamsSet = []string{
"[/host.com/]1.1.1.1",
"[//]tls://1.1.1.1",
"[/www.host.com/]#",
"[/host.com/google.com/]8.8.8.8",
@@ -1029,9 +1033,7 @@ func (d *testDHCP) Leases(flags int) []dhcpd.Lease {
l.Hostname = "localhost"
return []dhcpd.Lease{l}
}
func (d *testDHCP) SetOnLeaseChanged(onLeaseChanged dhcpd.OnLeaseChangedT) {
return
}
func (d *testDHCP) SetOnLeaseChanged(onLeaseChanged dhcpd.OnLeaseChangedT) {}
func TestPTRResponseFromDHCPLeases(t *testing.T) {
dhcp := &testDHCP{}

View File

@@ -1,12 +1,13 @@
package dnsforward
import (
"fmt"
"strings"
"github.com/AdguardTeam/AdGuardHome/dnsfilter"
"github.com/AdguardTeam/AdGuardHome/internal/dnsfilter"
"github.com/AdguardTeam/dnsproxy/proxy"
"github.com/AdguardTeam/golibs/log"
"github.com/joomcode/errorx"
"github.com/miekg/dns"
)
@@ -49,29 +50,32 @@ func (s *Server) filterDNSRequest(ctx *dnsContext) (*dnsfilter.Result, error) {
res, err := s.dnsFilter.CheckHost(host, d.Req.Question[0].Qtype, ctx.setts)
if err != nil {
// Return immediately if there's an error
return nil, errorx.Decorate(err, "dnsfilter failed to check host '%s'", host)
return nil, fmt.Errorf("dnsfilter failed to check host %q: %w", host, err)
} else if res.IsFiltered {
log.Tracef("Host %s is filtered, reason - '%s', matched rule: '%s'", host, res.Reason, res.Rule)
log.Tracef("Host %s is filtered, reason - %q, matched rule: %q", host, res.Reason, res.Rule)
d.Res = s.genDNSFilterMessage(d, &res)
} else if res.Reason == dnsfilter.ReasonRewrite && len(res.CanonName) != 0 && len(res.IPList) == 0 {
ctx.origQuestion = d.Req.Question[0]
// resolve canonical name, not the original host name
d.Req.Question[0].Name = dns.Fqdn(res.CanonName)
} else if res.Reason == dnsfilter.RewriteEtcHosts && len(res.ReverseHost) != 0 {
} else if res.Reason == dnsfilter.RewriteEtcHosts && len(res.ReverseHosts) != 0 {
resp := s.makeResponse(req)
ptr := &dns.PTR{}
ptr.Hdr = dns.RR_Header{
Name: req.Question[0].Name,
Rrtype: dns.TypePTR,
Ttl: s.conf.BlockedResponseTTL,
Class: dns.ClassINET,
for _, h := range res.ReverseHosts {
hdr := dns.RR_Header{
Name: req.Question[0].Name,
Rrtype: dns.TypePTR,
Ttl: s.conf.BlockedResponseTTL,
Class: dns.ClassINET,
}
ptr := &dns.PTR{
Hdr: hdr,
Ptr: h,
}
resp.Answer = append(resp.Answer, ptr)
}
ptr.Ptr = res.ReverseHost
resp.Answer = append(resp.Answer, ptr)
d.Res = resp
} else if res.Reason == dnsfilter.ReasonRewrite || res.Reason == dnsfilter.RewriteEtcHosts {
resp := s.makeResponse(req)
@@ -136,7 +140,6 @@ func (s *Server) filterDNSResponse(ctx *dnsContext) (*dnsfilter.Result, error) {
if err != nil {
return nil, err
} else if res.IsFiltered {
d.Res = s.genDNSFilterMessage(d, &res)
log.Debug("DNSFwd: Matched %s by response: %s", d.Req.Question[0].Name, host)

View File

@@ -5,9 +5,9 @@ import (
"strings"
"time"
"github.com/AdguardTeam/AdGuardHome/dhcpd"
"github.com/AdguardTeam/AdGuardHome/dnsfilter"
"github.com/AdguardTeam/AdGuardHome/util"
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
"github.com/AdguardTeam/AdGuardHome/internal/dnsfilter"
"github.com/AdguardTeam/AdGuardHome/internal/util"
"github.com/AdguardTeam/dnsproxy/proxy"
"github.com/AdguardTeam/golibs/log"
"github.com/miekg/dns"

View File

@@ -5,7 +5,7 @@ import (
"strings"
"sync"
"github.com/AdguardTeam/AdGuardHome/util"
"github.com/AdguardTeam/AdGuardHome/internal/util"
"github.com/AdguardTeam/golibs/log"
"github.com/miekg/dns"
)
@@ -31,13 +31,13 @@ func (c *ipsetCtx) init(ipsetConfig []string) {
it = strings.TrimSpace(it)
hostsAndNames := strings.Split(it, "/")
if len(hostsAndNames) != 2 {
log.Debug("IPSET: invalid value '%s'", it)
log.Debug("IPSET: invalid value %q", it)
continue
}
ipsetNames := strings.Split(hostsAndNames[1], ",")
if len(ipsetNames) == 0 {
log.Debug("IPSET: invalid value '%s'", it)
log.Debug("IPSET: invalid value %q", it)
continue
}
bad := false
@@ -49,7 +49,7 @@ func (c *ipsetCtx) init(ipsetConfig []string) {
}
}
if bad {
log.Debug("IPSET: invalid value '%s'", it)
log.Debug("IPSET: invalid value %q", it)
continue
}
@@ -58,7 +58,7 @@ func (c *ipsetCtx) init(ipsetConfig []string) {
host = strings.TrimSpace(host)
host = strings.ToLower(host)
if len(host) == 0 {
log.Debug("IPSET: invalid value '%s'", it)
log.Debug("IPSET: invalid value %q", it)
continue
}
c.ipsetList[host] = ipsetNames
@@ -131,7 +131,7 @@ func (c *ipsetCtx) process(ctx *dnsContext) int {
continue
}
if code != 0 {
log.Info("IPSET: ipset add: code:%d output:'%s'", code, out)
log.Info("IPSET: ipset add: code:%d output:%q", code, out)
continue
}
log.Debug("IPSET: added %s(%s) -> %s", host, ipStr, name)

View File

@@ -5,7 +5,7 @@ import (
"net"
"time"
"github.com/AdguardTeam/AdGuardHome/dnsfilter"
"github.com/AdguardTeam/AdGuardHome/internal/dnsfilter"
"github.com/AdguardTeam/dnsproxy/proxy"
"github.com/miekg/dns"
)
@@ -46,7 +46,6 @@ func (s *Server) genDNSFilterMessage(d *proxy.DNSContext, result *dnsfilter.Resu
if s.conf.BlockingMode == "null_ip" {
// it means that we should return 0.0.0.0 or :: for any blocked request
return s.makeResponseNullIP(m)
} else if s.conf.BlockingMode == "custom_ip" {
// means that we should return custom IP for any blocked request
@@ -56,12 +55,10 @@ func (s *Server) genDNSFilterMessage(d *proxy.DNSContext, result *dnsfilter.Resu
case dns.TypeAAAA:
return s.genAAAARecord(m, s.conf.BlockingIPAddrv6)
}
} else if s.conf.BlockingMode == "nxdomain" {
// means that we should return NXDOMAIN for any blocked request
return s.genNXDomain(m)
} else if s.conf.BlockingMode == "refused" {
// means that we should return NXDOMAIN for any blocked request
@@ -148,7 +145,6 @@ func (s *Server) makeResponseNullIP(req *dns.Msg) *dns.Msg {
}
func (s *Server) genBlockedHost(request *dns.Msg, newAddr string, d *proxy.DNSContext) *dns.Msg {
ip := net.ParseIP(newAddr)
if ip != nil {
return s.genResponseWithIP(request, ip)
@@ -168,7 +164,7 @@ func (s *Server) genBlockedHost(request *dns.Msg, newAddr string, d *proxy.DNSCo
err := s.dnsProxy.Resolve(newContext)
if err != nil {
log.Printf("Couldn't look up replacement host '%s': %s", newAddr, err)
log.Printf("Couldn't look up replacement host %q: %s", newAddr, err)
return s.genServerFailure(request)
}

View File

@@ -5,12 +5,11 @@ import (
"strings"
"time"
"github.com/AdguardTeam/AdGuardHome/querylog"
"github.com/miekg/dns"
"github.com/AdguardTeam/AdGuardHome/dnsfilter"
"github.com/AdguardTeam/AdGuardHome/stats"
"github.com/AdguardTeam/AdGuardHome/internal/dnsfilter"
"github.com/AdguardTeam/AdGuardHome/internal/querylog"
"github.com/AdguardTeam/AdGuardHome/internal/stats"
"github.com/AdguardTeam/dnsproxy/proxy"
"github.com/miekg/dns"
)
// Write Stats data and logs
@@ -40,10 +39,16 @@ func processQueryLogsAndStats(ctx *dnsContext) int {
ClientIP: getIP(d.Addr),
}
if d.Proto == "https" {
p.ClientProto = "doh"
} else if d.Proto == "tls" {
p.ClientProto = "dot"
switch d.Proto {
case proxy.ProtoHTTPS:
p.ClientProto = querylog.ClientProtoDOH
case proxy.ProtoQUIC:
p.ClientProto = querylog.ClientProtoDOQ
case proxy.ProtoTLS:
p.ClientProto = querylog.ClientProtoDOT
default:
// Consider this a plain DNS-over-UDP or DNS-over-TCL
// request.
}
if d.Upstream != nil {

View File

@@ -27,7 +27,7 @@ func stringArrayDup(a []string) []string {
// Get IP address from net.Addr object
// Note: we can't use net.SplitHostPort(a.String()) because of IPv6 zone:
// https://github.com/AdguardTeam/AdGuardHome/issues/1261
// https://github.com/AdguardTeam/AdGuardHome/internal/issues/1261
func ipFromAddr(a net.Addr) string {
switch addr := a.(type) {
case *net.UDPAddr:

View File

@@ -17,22 +17,22 @@ import (
"golang.org/x/crypto/bcrypt"
)
const cookieTTL = 365 * 24 // in hours
const sessionCookieName = "agh_session"
const (
cookieTTL = 365 * 24 // in hours
sessionCookieName = "agh_session"
)
type session struct {
userName string
expire uint32 // expiration time (in seconds)
}
/*
expire byte[4]
name_len byte[2]
name byte[]
*/
func (s *session) serialize() []byte {
var data []byte
data = make([]byte, 4+2+len(s.userName))
const (
expireLen = 4
nameLen = 2
)
data := make([]byte, expireLen+nameLen+len(s.userName))
binary.BigEndian.PutUint32(data[0:4], s.expire)
binary.BigEndian.PutUint16(data[4:6], uint16(len(s.userName)))
copy(data[6:], []byte(s.userName))
@@ -78,11 +78,11 @@ func InitAuth(dbFilename string, users []User, sessionTTL uint32) *Auth {
a.sessions = make(map[string]*session)
rand.Seed(time.Now().UTC().Unix())
var err error
a.db, err = bbolt.Open(dbFilename, 0644, nil)
a.db, err = bbolt.Open(dbFilename, 0o644, nil)
if err != nil {
log.Error("Auth: open DB: %s: %s", dbFilename, err)
if err.Error() == "invalid argument" {
log.Error("AdGuard Home cannot be initialized due to an incompatible file system.\nPlease read the explanation here: https://github.com/AdguardTeam/AdGuardHome/wiki/Getting-Started#limitations")
log.Error("AdGuard Home cannot be initialized due to an incompatible file system.\nPlease read the explanation here: https://github.com/AdguardTeam/AdGuardHome/internal/wiki/Getting-Started#limitations")
}
return nil
}
@@ -318,7 +318,7 @@ func handleLogin(w http.ResponseWriter, r *http.Request) {
cookie := Context.auth.httpCookie(req)
if len(cookie) == 0 {
log.Info("Auth: invalid user name or password: name='%s'", req.Name)
log.Info("Auth: invalid user name or password: name=%q", req.Name)
time.Sleep(1 * time.Second)
http.Error(w, "invalid user name or password", http.StatusBadRequest)
return
@@ -372,7 +372,6 @@ func parseCookie(cookie string) string {
// nolint(gocyclo)
func optionalAuth(handler func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/login.html" {
// redirect to dashboard if already authenticated
authRequired := Context.auth != nil && Context.auth.AuthRequired()
@@ -424,7 +423,6 @@ func optionalAuth(handler func(http.ResponseWriter, *http.Request)) func(http.Re
if r.URL.Path == "/" || r.URL.Path == "/index.html" {
if glProcessRedirect(w, r) {
log.Debug("Auth: redirected to login page by GL-Inet submodule")
} else {
w.Header().Set("Location", "/login.html")
w.WriteHeader(http.StatusFound)
@@ -474,7 +472,7 @@ func (a *Auth) UserAdd(u *User, password string) {
}
// UserFind - find a user
func (a *Auth) UserFind(login string, password string) User {
func (a *Auth) UserFind(login, password string) User {
a.lock.Lock()
defer a.lock.Unlock()
for _, u := range a.users {

View File

@@ -13,10 +13,10 @@ import (
"github.com/AdguardTeam/dnsproxy/proxy"
"github.com/AdguardTeam/AdGuardHome/dhcpd"
"github.com/AdguardTeam/AdGuardHome/dnsfilter"
"github.com/AdguardTeam/AdGuardHome/dnsforward"
"github.com/AdguardTeam/AdGuardHome/util"
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
"github.com/AdguardTeam/AdGuardHome/internal/dnsfilter"
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
"github.com/AdguardTeam/AdGuardHome/internal/util"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/utils"
)
@@ -126,7 +126,6 @@ func (clients *clientsContainer) Start() {
}
go clients.periodicUpdate()
}
}
// Reload - reload auto-clients
@@ -173,7 +172,7 @@ func (clients *clientsContainer) addFromConfig(objects []clientObject) {
for _, s := range cy.BlockedServices {
if !dnsfilter.BlockedSvcKnown(s) {
log.Debug("Clients: skipping unknown blocked-service '%s'", s)
log.Debug("Clients: skipping unknown blocked-service %q", s)
continue
}
cli.BlockedServices = append(cli.BlockedServices, s)
@@ -181,7 +180,7 @@ func (clients *clientsContainer) addFromConfig(objects []clientObject) {
for _, t := range cy.Tags {
if !clients.tagKnown(t) {
log.Debug("Clients: skipping unknown tag '%s'", t)
log.Debug("Clients: skipping unknown tag %q", t)
continue
}
cli.Tags = append(cli.Tags, t)
@@ -377,7 +376,7 @@ func (clients *clientsContainer) check(c *Client) error {
}
if len(c.IDs) == 0 {
return fmt.Errorf("ID required")
return fmt.Errorf("id required")
}
for i, id := range c.IDs {
@@ -409,7 +408,7 @@ func (clients *clientsContainer) check(c *Client) error {
err := dnsforward.ValidateUpstreams(c.Upstreams)
if err != nil {
return fmt.Errorf("invalid upstream servers: %s", err)
return fmt.Errorf("invalid upstream servers: %w", err)
}
return nil
@@ -448,7 +447,7 @@ func (clients *clientsContainer) Add(c Client) (bool, error) {
clients.idIndex[id] = &c
}
log.Debug("Clients: added '%s': ID:%v [%d]", c.Name, c.IDs, len(clients.list))
log.Debug("Clients: added %q: ID:%v [%d]", c.Name, c.IDs, len(clients.list))
return true, nil
}
@@ -590,7 +589,7 @@ func (clients *clientsContainer) addHost(ip, host string, source clientSource) (
}
clients.ipHost[ip] = ch
}
log.Debug("Clients: added '%s' -> '%s' [%d]", ip, host, len(clients.ipHost))
log.Debug("Clients: added %q -> %q [%d]", ip, host, len(clients.ipHost))
return true, nil
}
@@ -607,22 +606,25 @@ func (clients *clientsContainer) rmHosts(source clientSource) int {
return n
}
// Fill clients array from system hosts-file
// addFromHostsFile fills the clients hosts list from the system's hosts files.
func (clients *clientsContainer) addFromHostsFile() {
hosts := clients.autoHosts.List()
clients.lock.Lock()
defer clients.lock.Unlock()
_ = clients.rmHosts(ClientSourceHostsFile)
n := 0
for ip, name := range hosts {
ok, err := clients.addHost(ip, name, ClientSourceHostsFile)
if err != nil {
log.Debug("Clients: %s", err)
}
if ok {
n++
for ip, names := range hosts {
for _, name := range names {
ok, err := clients.addHost(ip, name, ClientSourceHostsFile)
if err != nil {
log.Debug("Clients: %s", err)
}
if ok {
n++
}
}
}

View File

@@ -6,7 +6,7 @@ import (
"testing"
"time"
"github.com/AdguardTeam/AdGuardHome/dhcpd"
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
"github.com/stretchr/testify/assert"
)

View File

@@ -6,11 +6,11 @@ import (
"path/filepath"
"sync"
"github.com/AdguardTeam/AdGuardHome/dhcpd"
"github.com/AdguardTeam/AdGuardHome/dnsfilter"
"github.com/AdguardTeam/AdGuardHome/dnsforward"
"github.com/AdguardTeam/AdGuardHome/querylog"
"github.com/AdguardTeam/AdGuardHome/stats"
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
"github.com/AdguardTeam/AdGuardHome/internal/dnsfilter"
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
"github.com/AdguardTeam/AdGuardHome/internal/querylog"
"github.com/AdguardTeam/AdGuardHome/internal/stats"
"github.com/AdguardTeam/golibs/file"
"github.com/AdguardTeam/golibs/log"
yaml "gopkg.in/yaml.v2"
@@ -120,6 +120,12 @@ var config = configuration{
Ratelimit: 20,
RefuseAny: true,
AllServers: false,
// set default maximum concurrent queries to 300
// we introduced a default limit due to this:
// https://github.com/AdguardTeam/AdGuardHome/issues/2015#issuecomment-674041912
// was later increased to 300 due to https://github.com/AdguardTeam/AdGuardHome/issues/2257
MaxGoroutines: 300,
},
FilteringEnabled: true, // whether or not use filter lists
FiltersUpdateIntervalHours: 24,

View File

@@ -9,7 +9,7 @@ import (
"strconv"
"strings"
"github.com/AdguardTeam/AdGuardHome/dnsforward"
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
"github.com/AdguardTeam/golibs/log"
"github.com/NYTimes/gziphandler"
)

View File

@@ -12,7 +12,7 @@ import (
"strings"
"time"
"github.com/AdguardTeam/AdGuardHome/util"
"github.com/AdguardTeam/AdGuardHome/internal/util"
"github.com/AdguardTeam/golibs/log"
"github.com/miekg/dns"
)
@@ -26,10 +26,10 @@ func isValidURL(rawurl string) bool {
url, err := url.ParseRequestURI(rawurl)
if err != nil {
return false //Couldn't even parse the rawurl
return false // Couldn't even parse the rawurl
}
if len(url.Scheme) == 0 {
return false //No Scheme found
return false // No Scheme found
}
return true
}
@@ -95,44 +95,57 @@ func (f *Filtering) handleFilteringAddURL(w http.ResponseWriter, r *http.Request
}
func (f *Filtering) handleFilteringRemoveURL(w http.ResponseWriter, r *http.Request) {
type request struct {
URL string `json:"url"`
Whitelist bool `json:"whitelist"`
}
req := request{}
err := json.NewDecoder(r.Body).Decode(&req)
if err != nil {
httpError(w, http.StatusBadRequest, "Failed to parse request body json: %s", err)
httpError(w, http.StatusBadRequest, "failed to parse request body json: %s", err)
return
}
// go through each element and delete if url matches
config.Lock()
newFilters := []filter{}
filters := &config.Filters
if req.Whitelist {
filters = &config.WhitelistFilters
}
for _, filter := range *filters {
if filter.URL != req.URL {
newFilters = append(newFilters, filter)
} else {
err := os.Rename(filter.Path(), filter.Path()+".old")
if err != nil {
log.Error("os.Rename: %s: %s", filter.Path(), err)
}
var deleted filter
var newFilters []filter
for _, f := range *filters {
if f.URL != req.URL {
newFilters = append(newFilters, f)
continue
}
deleted = f
path := f.Path()
err = os.Rename(path, path+".old")
if err != nil {
log.Error("deleting filter %q: %s", path, err)
}
}
// Update the configuration after removing filter files
*filters = newFilters
config.Unlock()
onConfigModified()
enableFilters(true)
// Note: the old files "filter.txt.old" aren't deleted - it's not really necessary,
// but will require the additional code to run after enableFilters() is finished: i.e. complicated
// NOTE: The old files "filter.txt.old" aren't deleted. It's not really
// necessary, but will require the additional complicated code to run
// after enableFilters is done.
//
// TODO(a.garipov): Make sure the above comment is true.
_, err = fmt.Fprintf(w, "OK %d rules\n", deleted.RulesCount)
if err != nil {
httpError(w, http.StatusInternalServerError, "couldn't write body: %s", err)
}
}
type filterURLJSON struct {

View File

@@ -13,9 +13,9 @@ import (
"runtime"
"strconv"
"github.com/AdguardTeam/AdGuardHome/util"
"github.com/AdguardTeam/AdGuardHome/internal/util"
"github.com/AdguardTeam/AdGuardHome/dhcpd"
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
"github.com/AdguardTeam/golibs/log"
)
@@ -71,6 +71,7 @@ type checkConfigReqEnt struct {
IP string `json:"ip"`
Autofix bool `json:"autofix"`
}
type checkConfigReq struct {
Web checkConfigReqEnt `json:"web"`
DNS checkConfigReqEnt `json:"dns"`
@@ -81,11 +82,13 @@ type checkConfigRespEnt struct {
Status string `json:"status"`
CanAutofix bool `json:"can_autofix"`
}
type staticIPJSON struct {
Static string `json:"static"`
IP string `json:"ip"`
Error string `json:"error"`
}
type checkConfigResp struct {
Web checkConfigRespEnt `json:"web"`
DNS checkConfigRespEnt `json:"dns"`
@@ -214,31 +217,33 @@ func checkDNSStubListener() bool {
return true
}
const resolvedConfPath = "/etc/systemd/resolved.conf.d/adguardhome.conf"
const resolvedConfData = `[Resolve]
const (
resolvedConfPath = "/etc/systemd/resolved.conf.d/adguardhome.conf"
resolvedConfData = `[Resolve]
DNS=127.0.0.1
DNSStubListener=no
`
)
const resolvConfPath = "/etc/resolv.conf"
// Deactivate DNSStubListener
func disableDNSStubListener() error {
dir := filepath.Dir(resolvedConfPath)
err := os.MkdirAll(dir, 0755)
err := os.MkdirAll(dir, 0o755)
if err != nil {
return fmt.Errorf("os.MkdirAll: %s: %s", dir, err)
return fmt.Errorf("os.MkdirAll: %s: %w", dir, err)
}
err = ioutil.WriteFile(resolvedConfPath, []byte(resolvedConfData), 0644)
err = ioutil.WriteFile(resolvedConfPath, []byte(resolvedConfData), 0o644)
if err != nil {
return fmt.Errorf("ioutil.WriteFile: %s: %s", resolvedConfPath, err)
return fmt.Errorf("ioutil.WriteFile: %s: %w", resolvedConfPath, err)
}
_ = os.Rename(resolvConfPath, resolvConfPath+".backup")
err = os.Symlink("/run/systemd/resolve/resolv.conf", resolvConfPath)
if err != nil {
_ = os.Remove(resolvedConfPath) // remove the file we've just created
return fmt.Errorf("os.Symlink: %s: %s", resolvConfPath, err)
return fmt.Errorf("os.Symlink: %s: %w", resolvConfPath, err)
}
cmd := exec.Command("systemctl", "reload-or-restart", "systemd-resolved")
@@ -259,6 +264,7 @@ type applyConfigReqEnt struct {
IP string `json:"ip"`
Port int `json:"port"`
}
type applyConfigReq struct {
Web applyConfigReqEnt `json:"web"`
DNS applyConfigReqEnt `json:"dns"`

View File

@@ -10,8 +10,8 @@ import (
"strings"
"syscall"
"github.com/AdguardTeam/AdGuardHome/update"
"github.com/AdguardTeam/AdGuardHome/util"
"github.com/AdguardTeam/AdGuardHome/internal/update"
"github.com/AdguardTeam/AdGuardHome/internal/util"
"github.com/AdguardTeam/golibs/log"
)
@@ -46,7 +46,7 @@ func handleGetVersionJSON(w http.ResponseWriter, r *http.Request) {
Context.controlLock.Unlock()
if err != nil && strings.HasSuffix(err.Error(), "i/o timeout") {
// This case may happen while we're restarting DNS server
// https://github.com/AdguardTeam/AdGuardHome/issues/934
// https://github.com/AdguardTeam/AdGuardHome/internal/issues/934
continue
}
break

View File

@@ -53,10 +53,10 @@ func TestDoUpdate(t *testing.T) {
updateDir: Context.workDir + "/agh-update-" + newver,
backupDir: Context.workDir + "/agh-backup",
configName: Context.workDir + "/AdGuardHome.yaml",
updateConfigName: Context.workDir + "/agh-update-" + newver + "/AdGuardHome/AdGuardHome.yaml",
updateConfigName: Context.workDir + "/agh-update-" + newver + "/AdGuardHome/internal/AdGuardHome.yaml",
curBinName: Context.workDir + "/AdGuardHome",
bkpBinName: Context.workDir + "/agh-backup/AdGuardHome",
newBinName: Context.workDir + "/agh-update-" + newver + "/AdGuardHome/AdGuardHome",
newBinName: Context.workDir + "/agh-update-" + newver + "/AdGuardHome/internal/AdGuardHome",
}
assert.Equal(t, uu.pkgURL, u.pkgURL)

View File

@@ -5,14 +5,13 @@ import (
"net"
"path/filepath"
"github.com/AdguardTeam/AdGuardHome/dnsfilter"
"github.com/AdguardTeam/AdGuardHome/dnsforward"
"github.com/AdguardTeam/AdGuardHome/querylog"
"github.com/AdguardTeam/AdGuardHome/stats"
"github.com/AdguardTeam/AdGuardHome/util"
"github.com/AdguardTeam/AdGuardHome/internal/dnsfilter"
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
"github.com/AdguardTeam/AdGuardHome/internal/querylog"
"github.com/AdguardTeam/AdGuardHome/internal/stats"
"github.com/AdguardTeam/AdGuardHome/internal/util"
"github.com/AdguardTeam/dnsproxy/proxy"
"github.com/AdguardTeam/golibs/log"
"github.com/joomcode/errorx"
)
// Called by other modules when configuration is changed
@@ -75,7 +74,7 @@ func initDNSServer() error {
err = Context.dnsServer.Prepare(&dnsConfig)
if err != nil {
closeDNSServer()
return fmt.Errorf("dnsServer.Prepare: %s", err)
return fmt.Errorf("dnsServer.Prepare: %w", err)
}
Context.rdns = InitRDNS(Context.dnsServer, &Context.clients)
@@ -96,41 +95,41 @@ func isPublicIP(ip net.IP) bool {
if ip4 != nil {
switch ip4[0] {
case 0:
return false //software
return false // software
case 10:
return false //private network
return false // private network
case 127:
return false //loopback
return false // loopback
case 169:
if ip4[1] == 254 {
return false //link-local
return false // link-local
}
case 172:
if ip4[1] >= 16 && ip4[1] <= 31 {
return false //private network
return false // private network
}
case 192:
if (ip4[1] == 0 && ip4[2] == 0) || //private network
(ip4[1] == 0 && ip4[2] == 2) || //documentation
(ip4[1] == 88 && ip4[2] == 99) || //reserved
(ip4[1] == 168) { //private network
if (ip4[1] == 0 && ip4[2] == 0) || // private network
(ip4[1] == 0 && ip4[2] == 2) || // documentation
(ip4[1] == 88 && ip4[2] == 99) || // reserved
(ip4[1] == 168) { // private network
return false
}
case 198:
if (ip4[1] == 18 || ip4[2] == 19) || //private network
(ip4[1] == 51 || ip4[2] == 100) { //documentation
if (ip4[1] == 18 || ip4[2] == 19) || // private network
(ip4[1] == 51 || ip4[2] == 100) { // documentation
return false
}
case 203:
if ip4[1] == 0 && ip4[2] == 113 { //documentation
if ip4[1] == 0 && ip4[2] == 113 { // documentation
return false
}
case 224:
if ip4[1] == 0 && ip4[2] == 0 { //multicast
if ip4[1] == 0 && ip4[2] == 0 { // multicast
return false
}
case 255:
if ip4[1] == 255 && ip4[2] == 255 && ip4[3] == 255 { //subnet
if ip4[1] == 255 && ip4[2] == 255 && ip4[3] == 255 { // subnet
return false
}
}
@@ -313,7 +312,7 @@ func startDNSServer() error {
err := Context.dnsServer.Start()
if err != nil {
return errorx.Decorate(err, "Couldn't start forwarding DNS server")
return fmt.Errorf("couldn't start forwarding DNS server: %w", err)
}
Context.dnsFilter.Start()
@@ -340,7 +339,7 @@ func reconfigureDNSServer() error {
newconfig := generateServerConfig()
err := Context.dnsServer.Reconfigure(&newconfig)
if err != nil {
return errorx.Decorate(err, "Couldn't start forwarding DNS server")
return fmt.Errorf("couldn't start forwarding DNS server: %w", err)
}
return nil
@@ -353,7 +352,7 @@ func stopDNSServer() error {
err := Context.dnsServer.Stop()
if err != nil {
return errorx.Decorate(err, "Couldn't stop forwarding DNS server")
return fmt.Errorf("couldn't stop forwarding DNS server: %w", err)
}
closeDNSServer()

View File

@@ -15,14 +15,11 @@ import (
"sync/atomic"
"time"
"github.com/AdguardTeam/AdGuardHome/dnsfilter"
"github.com/AdguardTeam/AdGuardHome/util"
"github.com/AdguardTeam/AdGuardHome/internal/dnsfilter"
"github.com/AdguardTeam/golibs/log"
)
var (
nextFilterID = time.Now().Unix() // semi-stable way to generate an unique ID
)
var nextFilterID = time.Now().Unix() // semi-stable way to generate an unique ID
// Filtering - module object
type Filtering struct {
@@ -35,7 +32,7 @@ type Filtering struct {
// Init - initialize the module
func (f *Filtering) Init() {
f.filterTitleRegexp = regexp.MustCompile(`^! Title: +(.*)$`)
_ = os.MkdirAll(filepath.Join(Context.getDataDir(), filterDir), 0755)
_ = os.MkdirAll(filepath.Join(Context.getDataDir(), filterDir), 0o755)
f.loadFilters(config.Filters)
f.loadFilters(config.WhitelistFilters)
deduplicateFilters()
@@ -466,7 +463,6 @@ func (f *Filtering) parseFilterContents(file io.Reader) (int, uint32, string) {
line = strings.TrimSpace(line)
if len(line) == 0 {
//
} else if line[0] == '!' {
m := f.filterTitleRegexp.FindAllStringSubmatch(line, -1)
if len(m) > 0 && len(m[0]) >= 2 && !seenTitle {
@@ -476,7 +472,6 @@ func (f *Filtering) parseFilterContents(file io.Reader) (int, uint32, string) {
} else if line[0] == '#' {
//
} else {
rulesCount++
}
@@ -521,7 +516,7 @@ func (f *Filtering) updateIntl(filter *filter) (bool, error) {
if filepath.IsAbs(filter.URL) {
f, err := os.Open(filter.URL)
if err != nil {
return false, fmt.Errorf("open file: %s", err)
return false, fmt.Errorf("open file: %w", err)
}
defer f.Close()
reader = f
@@ -552,8 +547,10 @@ func (f *Filtering) updateIntl(filter *filter) (bool, error) {
total += n
if htmlTest {
// gather full buffer firstChunk and perform its data tests
num := util.MinInt(n, len(firstChunk)-firstChunkLen)
num := len(firstChunk) - firstChunkLen
if n < num {
num = n
}
copied := copy(firstChunk[firstChunkLen:], buf[:num])
firstChunkLen += copied
@@ -563,8 +560,7 @@ func (f *Filtering) updateIntl(filter *filter) (bool, error) {
}
s := strings.ToLower(string(firstChunk))
if strings.Index(s, "<html") >= 0 ||
strings.Index(s, "<!doctype") >= 0 {
if strings.Contains(s, "<html") || strings.Contains(s, "<!doctype") {
return false, fmt.Errorf("data is HTML, not plain text")
}

View File

@@ -1,3 +1,4 @@
// Package home contains AdGuard Home's HTTP API methods.
package home
import (
@@ -8,6 +9,7 @@ import (
"io/ioutil"
"net"
"net/http"
"net/http/pprof"
"net/url"
"os"
"os/signal"
@@ -20,18 +22,15 @@ import (
"gopkg.in/natefinch/lumberjack.v2"
"github.com/AdguardTeam/AdGuardHome/update"
"github.com/AdguardTeam/AdGuardHome/util"
"github.com/AdguardTeam/AdGuardHome/internal/agherr"
"github.com/AdguardTeam/AdGuardHome/internal/update"
"github.com/AdguardTeam/AdGuardHome/internal/util"
"github.com/joomcode/errorx"
"github.com/AdguardTeam/AdGuardHome/isdelve"
"github.com/AdguardTeam/AdGuardHome/dhcpd"
"github.com/AdguardTeam/AdGuardHome/dnsfilter"
"github.com/AdguardTeam/AdGuardHome/dnsforward"
"github.com/AdguardTeam/AdGuardHome/querylog"
"github.com/AdguardTeam/AdGuardHome/stats"
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
"github.com/AdguardTeam/AdGuardHome/internal/dnsfilter"
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
"github.com/AdguardTeam/AdGuardHome/internal/querylog"
"github.com/AdguardTeam/AdGuardHome/internal/stats"
"github.com/AdguardTeam/golibs/log"
)
@@ -95,7 +94,7 @@ func (c *homeContext) getDataDir() string {
var Context homeContext
// Main is the entry point
func Main(version string, channel string, armVer string) {
func Main(version, channel, armVer string) {
// Init update-related global variables
versionString = version
updateChannel = channel
@@ -111,7 +110,7 @@ func Main(version string, channel string, armVer string) {
go func() {
for {
sig := <-Context.appSignalChannel
log.Info("Received signal '%s'", sig)
log.Info("Received signal %q", sig)
switch sig {
case syscall.SIGHUP:
Context.clients.Reload()
@@ -264,7 +263,11 @@ func run(args options) {
if config.DebugPProf {
mux := http.NewServeMux()
util.PProfRegisterWebHandlers(mux)
mux.HandleFunc("/debug/pprof/", pprof.Index)
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
go func() {
log.Info("pprof: listening on localhost:6060")
err := http.ListenAndServe("localhost:6060", mux)
@@ -273,7 +276,7 @@ func run(args options) {
}
}
err := os.MkdirAll(Context.getDataDir(), 0755)
err := os.MkdirAll(Context.getDataDir(), 0o755)
if err != nil {
log.Fatalf("Cannot create DNS data dir at %s: %s", Context.getDataDir(), err)
}
@@ -352,10 +355,7 @@ func checkPermissions() {
// On Windows we need to have admin rights to run properly
admin, _ := util.HaveAdminRights()
if //noinspection ALL
admin || isdelve.Enabled {
// Don't forget that for this to work you need to add "delve" tag explicitly
// https://stackoverflow.com/questions/47879070/how-can-i-see-if-the-goland-debugger-is-running-in-the-program
if admin {
return
}
@@ -381,7 +381,7 @@ Please note, that this is crucial for a server to be able to use privileged port
You have two options:
1. Run AdGuard Home with root privileges
2. On Linux you can grant the CAP_NET_BIND_SERVICE capability:
https://github.com/AdguardTeam/AdGuardHome/wiki/Getting-Started#running-without-superuser`
https://github.com/AdguardTeam/AdGuardHome/internal/wiki/Getting-Started#running-without-superuser`
log.Fatal(msg)
}
@@ -398,7 +398,7 @@ Please note, that this is crucial for a DNS server to be able to use that port.`
// Write PID to a file
func writePIDFile(fn string) bool {
data := fmt.Sprintf("%d", os.Getpid())
err := ioutil.WriteFile(fn, []byte(data), 0644)
err := ioutil.WriteFile(fn, []byte(data), 0o644)
if err != nil {
log.Error("Couldn't write PID to file %s: %v", fn, err)
return false
@@ -481,7 +481,7 @@ func configureLogger(args options) {
logFilePath = ls.LogFile
}
_, err := os.OpenFile(logFilePath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
_, err := os.OpenFile(logFilePath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0o644)
if err != nil {
log.Fatalf("cannot create a log file: %s", err)
}
@@ -492,7 +492,7 @@ func configureLogger(args options) {
LocalTime: ls.LogLocalTime,
MaxBackups: ls.LogMaxBackups,
MaxSize: ls.LogMaxSize, // megabytes
MaxAge: ls.LogMaxAge, //days
MaxAge: ls.LogMaxAge, // days
})
}
}
@@ -611,11 +611,7 @@ func detectFirstRun() bool {
configfile = filepath.Join(Context.workDir, Context.configFilename)
}
_, err := os.Stat(configfile)
if !os.IsNotExist(err) {
// do nothing, file exists
return false
}
return true
return os.IsNotExist(err)
}
// Connect to a remote server resolving hostname using our own DNS server
@@ -656,7 +652,7 @@ func customDialContext(ctx context.Context, network, addr string) (net.Conn, err
}
return con, err
}
return nil, errorx.DecorateMany(fmt.Sprintf("couldn't dial to %s", addr), dialErrs...)
return nil, agherr.Many(fmt.Sprintf("couldn't dial to %s", addr), dialErrs...)
}
func getHTTPProxy(req *http.Request) (*url.URL, error) {

View File

@@ -58,9 +58,9 @@ func handleI18nCurrentLanguage(w http.ResponseWriter, r *http.Request) {
log.Printf("config.Language is %s", config.Language)
_, err := fmt.Fprintf(w, "%s\n", config.Language)
if err != nil {
errorText := fmt.Sprintf("Unable to write response json: %s", err)
log.Println(errorText)
http.Error(w, errorText, http.StatusInternalServerError)
msg := fmt.Sprintf("Unable to write response json: %s", err)
log.Println(msg)
http.Error(w, msg, http.StatusInternalServerError)
return
}
}
@@ -68,23 +68,23 @@ func handleI18nCurrentLanguage(w http.ResponseWriter, r *http.Request) {
func handleI18nChangeLanguage(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
errorText := fmt.Sprintf("failed to read request body: %s", err)
log.Println(errorText)
http.Error(w, errorText, http.StatusBadRequest)
msg := fmt.Sprintf("failed to read request body: %s", err)
log.Println(msg)
http.Error(w, msg, http.StatusBadRequest)
return
}
language := strings.TrimSpace(string(body))
if language == "" {
errorText := fmt.Sprintf("empty language specified")
log.Println(errorText)
http.Error(w, errorText, http.StatusBadRequest)
msg := "empty language specified"
log.Println(msg)
http.Error(w, msg, http.StatusBadRequest)
return
}
if !isLanguageAllowed(language) {
errorText := fmt.Sprintf("unknown language specified: %s", language)
log.Println(errorText)
http.Error(w, errorText, http.StatusBadRequest)
msg := fmt.Sprintf("unknown language specified: %s", language)
log.Println(msg)
http.Error(w, msg, http.StatusBadRequest)
return
}

View File

@@ -11,7 +11,7 @@ import (
// memoryUsage implements a couple of not really beautiful hacks which purpose is to
// make OS reclaim the memory freed by AdGuard Home as soon as possible.
// See this for the details on the performance hits & gains:
// https://github.com/AdguardTeam/AdGuardHome/issues/2044#issuecomment-687042211
// https://github.com/AdguardTeam/AdGuardHome/internal/issues/2044#issuecomment-687042211
func memoryUsage(args options) {
if args.disableMemoryOptimization {
log.Info("Memory optimization is disabled")
@@ -32,13 +32,9 @@ func memoryUsage(args options) {
// that the OS could reclaim the free memory
go func() {
ticker := time.NewTicker(5 * time.Minute)
for {
select {
case t := <-ticker.C:
t.Second()
log.Debug("Free OS memory")
debug.FreeOSMemory()
}
for range ticker.C {
log.Debug("free os memory")
debug.FreeOSMemory()
}
}()
}

View File

@@ -2,6 +2,7 @@ package home
import (
"fmt"
"net"
"net/http"
uuid "github.com/satori/go.uuid"
@@ -14,7 +15,7 @@ type DNSSettings struct {
ServerName string `plist:",omitempty"`
}
type PayloadContent = struct {
type PayloadContent struct {
Name string
PayloadDescription string
PayloadDisplayName string
@@ -25,7 +26,7 @@ type PayloadContent = struct {
DNSSettings DNSSettings
}
type MobileConfig = struct {
type MobileConfig struct {
PayloadContent []PayloadContent
PayloadDescription string
PayloadDisplayName string
@@ -40,8 +41,21 @@ func genUUIDv4() string {
return uuid.NewV4().String()
}
func getMobileConfig(r *http.Request, d DNSSettings) ([]byte, error) {
name := fmt.Sprintf("%s DNS over %s", r.Host, d.DNSProtocol)
const (
dnsProtoHTTPS = "HTTPS"
dnsProtoTLS = "TLS"
)
func getMobileConfig(d DNSSettings) ([]byte, error) {
var name string
switch d.DNSProtocol {
case dnsProtoHTTPS:
name = fmt.Sprintf("%s DoH", d.ServerName)
case dnsProtoTLS:
name = fmt.Sprintf("%s DoT", d.ServerName)
default:
return nil, fmt.Errorf("bad dns protocol %q", d.DNSProtocol)
}
data := MobileConfig{
PayloadContent: []PayloadContent{{
@@ -66,9 +80,8 @@ func getMobileConfig(r *http.Request, d DNSSettings) ([]byte, error) {
return plist.MarshalIndent(data, plist.XMLFormat, "\t")
}
func handleMobileConfig(w http.ResponseWriter, r *http.Request, d DNSSettings) {
mobileconfig, err := getMobileConfig(r, d)
func handleMobileConfig(w http.ResponseWriter, d DNSSettings) {
mobileconfig, err := getMobileConfig(d)
if err != nil {
httpError(w, http.StatusInternalServerError, "plist.MarshalIndent: %s", err)
}
@@ -78,15 +91,23 @@ func handleMobileConfig(w http.ResponseWriter, r *http.Request, d DNSSettings) {
}
func handleMobileConfigDoh(w http.ResponseWriter, r *http.Request) {
handleMobileConfig(w, r, DNSSettings{
DNSProtocol: "HTTPS",
handleMobileConfig(w, DNSSettings{
DNSProtocol: dnsProtoHTTPS,
ServerURL: fmt.Sprintf("https://%s/dns-query", r.Host),
})
}
func handleMobileConfigDot(w http.ResponseWriter, r *http.Request) {
handleMobileConfig(w, r, DNSSettings{
DNSProtocol: "TLS",
ServerName: r.Host,
var err error
var host string
host, _, err = net.SplitHostPort(r.Host)
if err != nil {
httpError(w, http.StatusBadRequest, "getting host: %s", err)
}
handleMobileConfig(w, DNSSettings{
DNSProtocol: dnsProtoTLS,
ServerName: host,
})
}

View File

@@ -0,0 +1,33 @@
package home
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
"howett.net/plist"
)
func TestHandleMobileConfigDot(t *testing.T) {
var err error
var r *http.Request
r, err = http.NewRequest(http.MethodGet, "https://example.com:12345/apple/dot.mobileconfig", nil)
assert.Nil(t, err)
w := httptest.NewRecorder()
handleMobileConfigDot(w, r)
assert.Equal(t, http.StatusOK, w.Code)
var mc MobileConfig
_, err = plist.Unmarshal(w.Body.Bytes(), &mc)
assert.Nil(t, err)
if assert.Equal(t, 1, len(mc.PayloadContent)) {
assert.Equal(t, "example.com DoT", mc.PayloadContent[0].Name)
assert.Equal(t, "example.com DoT", mc.PayloadContent[0].PayloadDisplayName)
assert.Equal(t, "example.com", mc.PayloadContent[0].DNSSettings.ServerName)
}
}

View File

@@ -106,7 +106,7 @@ var portArg = arg{
var p int
minPort, maxPort := 0, 1<<16-1
if p, err = strconv.Atoi(v); err != nil {
err = fmt.Errorf("port '%s' is not a number", v)
err = fmt.Errorf("port %q is not a number", v)
} else if p < minPort || p > maxPort {
err = fmt.Errorf("port %d not in range %d - %d", p, minPort, maxPort)
} else {

View File

@@ -5,7 +5,7 @@ import (
"strings"
"time"
"github.com/AdguardTeam/AdGuardHome/dnsforward"
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
"github.com/AdguardTeam/golibs/cache"
"github.com/AdguardTeam/golibs/log"
"github.com/miekg/dns"
@@ -116,8 +116,7 @@ func (r *RDNS) resolve(ip string) string {
// Add the hostname:IP pair to "Clients" array
func (r *RDNS) workerLoop() {
for {
var ip string
ip = <-r.ipChannel
ip := <-r.ipChannel
host := r.resolve(ip)
if len(host) == 0 {

View File

@@ -3,7 +3,7 @@ package home
import (
"testing"
"github.com/AdguardTeam/AdGuardHome/dnsforward"
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
"github.com/stretchr/testify/assert"
)

View File

@@ -9,7 +9,7 @@ import (
"strings"
"syscall"
"github.com/AdguardTeam/AdGuardHome/util"
"github.com/AdguardTeam/AdGuardHome/internal/util"
"github.com/AdguardTeam/golibs/log"
"github.com/kardianos/service"
)
@@ -104,7 +104,7 @@ func sendSigReload() {
return
}
pid, err := strconv.Atoi(parts[0])
pid, err := strconv.Atoi(strings.TrimSpace(parts[0]))
if err != nil {
log.Error("Can't read PID file %s: %s", pidfile, err)
return
@@ -203,7 +203,7 @@ func handleServiceInstallCommand(s service.Service) {
log.Fatal(err)
}
if util.IsOpenWrt() {
if util.IsOpenWRT() {
// On OpenWrt it is important to run enable after the service installation
// Otherwise, the service won't start on the system startup
_, err := runInitdCommand("enable")
@@ -230,7 +230,7 @@ Click on the link below and follow the Installation Wizard steps to finish setup
// handleServiceStatusCommand handles service "uninstall" command
func handleServiceUninstallCommand(s service.Service) {
if util.IsOpenWrt() {
if util.IsOpenWRT() {
// On OpenWrt it is important to run disable command first
// as it will remove the symlink
_, err := runInitdCommand("disable")
@@ -272,14 +272,14 @@ func configureService(c *service.Config) {
// Redirect StdErr & StdOut to files.
c.Option["LogOutput"] = true
// Use modified service file templates
// Use modified service file templates.
c.Option["SystemdScript"] = systemdScript
c.Option["SysvScript"] = sysvScript
// On OpenWrt we're using a different type of sysvScript
if util.IsOpenWrt() {
// On OpenWrt we're using a different type of sysvScript.
if util.IsOpenWRT() {
c.Option["SysvScript"] = openWrtScript
} else if util.IsFreeBSD() {
} else if runtime.GOOS == "freebsd" {
c.Option["SysvScript"] = freeBSDScript
}
}
@@ -452,7 +452,7 @@ exit 0
`
// OpenWrt procd init script
// https://github.com/AdguardTeam/AdGuardHome/issues/1386
// https://github.com/AdguardTeam/AdGuardHome/internal/issues/1386
const openWrtScript = `#!/bin/sh /etc/rc.common
USE_PROCD=1
@@ -502,6 +502,7 @@ status() {
fi
}
`
const freeBSDScript = `#!/bin/sh
# PROVIDE: {{.Name}}
# REQUIRE: networking

View File

@@ -20,7 +20,6 @@ import (
"time"
"github.com/AdguardTeam/golibs/log"
"github.com/joomcode/errorx"
)
var tlsWebHandlersRegistered = false
@@ -136,6 +135,10 @@ func (t *TLSMod) Reload() {
t.certLastMod = fi.ModTime().UTC()
_ = reconfigureDNSServer()
t.confLock.Lock()
tlsConf = t.conf
t.confLock.Unlock()
Context.web.TLSConfigChanged(tlsConf)
}
@@ -302,12 +305,11 @@ func (t *TLSMod) handleTLSConfigure(w http.ResponseWriter, r *http.Request) {
}
}
func verifyCertChain(data *tlsConfigStatus, certChain string, serverName string) error {
func verifyCertChain(data *tlsConfigStatus, certChain, serverName string) error {
log.Tracef("TLS: got certificate: %d bytes", len(certChain))
// now do a more extended validation
var certs []*pem.Block // PEM-encoded certificates
var skippedBytes []string // skipped bytes
var certs []*pem.Block // PEM-encoded certificates
pemblock := []byte(certChain)
for {
@@ -318,10 +320,6 @@ func verifyCertChain(data *tlsConfigStatus, certChain string, serverName string)
}
if decoded.Type == "CERTIFICATE" {
certs = append(certs, decoded)
} else {
// ignore "this result of append is never used" warning
// nolint
skippedBytes = append(skippedBytes, decoded.Type)
}
}
@@ -337,7 +335,7 @@ func verifyCertChain(data *tlsConfigStatus, certChain string, serverName string)
}
if len(parsedCerts) == 0 {
data.WarningValidation = fmt.Sprintf("You have specified an empty certificate")
data.WarningValidation = "You have specified an empty certificate"
return errors.New(data.WarningValidation)
}
@@ -387,8 +385,7 @@ func verifyCertChain(data *tlsConfigStatus, certChain string, serverName string)
func validatePkey(data *tlsConfigStatus, pkey string) error {
// now do a more extended validation
var key *pem.Block // PEM-encoded certificates
var skippedBytes []string // skipped bytes
var key *pem.Block // PEM-encoded certificates
// go through all pem blocks, but take first valid pem block and drop the rest
pemblock := []byte(pkey)
@@ -401,10 +398,6 @@ func validatePkey(data *tlsConfigStatus, pkey string) error {
if decoded.Type == "PRIVATE KEY" || strings.HasSuffix(decoded.Type, " PRIVATE KEY") {
key = decoded
break
} else {
// ignore "this result of append is never used"
// nolint
skippedBytes = append(skippedBytes, decoded.Type)
}
}
@@ -490,13 +483,13 @@ func unmarshalTLS(r *http.Request) (tlsConfigSettings, error) {
data := tlsConfigSettings{}
err := json.NewDecoder(r.Body).Decode(&data)
if err != nil {
return data, errorx.Decorate(err, "Failed to parse new TLS config json")
return data, fmt.Errorf("failed to parse new TLS config json: %w", err)
}
if data.CertificateChain != "" {
certPEM, err := base64.StdEncoding.DecodeString(data.CertificateChain)
if err != nil {
return data, errorx.Decorate(err, "Failed to base64-decode certificate chain")
return data, fmt.Errorf("failed to base64-decode certificate chain: %w", err)
}
data.CertificateChain = string(certPEM)
if data.CertificatePath != "" {
@@ -507,7 +500,7 @@ func unmarshalTLS(r *http.Request) (tlsConfigSettings, error) {
if data.PrivateKey != "" {
keyPEM, err := base64.StdEncoding.DecodeString(data.PrivateKey)
if err != nil {
return data, errorx.Decorate(err, "Failed to base64-decode private key")
return data, fmt.Errorf("failed to base64-decode private key: %w", err)
}
data.PrivateKey = string(keyPEM)

View File

@@ -5,7 +5,7 @@ import (
"os"
"path/filepath"
"github.com/AdguardTeam/AdGuardHome/util"
"github.com/AdguardTeam/AdGuardHome/internal/util"
"github.com/AdguardTeam/golibs/file"
"github.com/AdguardTeam/golibs/log"
@@ -184,7 +184,7 @@ func upgradeSchema2to3(diskConfig *map[string]interface{}) error {
newDNSConfig[fmt.Sprint(k)] = v
}
default:
return fmt.Errorf("DNS configuration is not a map")
return fmt.Errorf("dns configuration is not a map")
}
// Replace bootstrap_dns value filed with new array contains old bootstrap_dns inside
@@ -217,7 +217,6 @@ func upgradeSchema3to4(diskConfig *map[string]interface{}) error {
case []interface{}:
for i := range arr {
switch c := arr[i].(type) {
case map[interface{}]interface{}:
@@ -309,7 +308,6 @@ func upgradeSchema5to6(diskConfig *map[string]interface{}) error {
case []interface{}:
for i := range arr {
switch c := arr[i].(type) {
case map[interface{}]interface{}:

View File

@@ -9,7 +9,7 @@ import (
"strconv"
"sync"
"github.com/AdguardTeam/AdGuardHome/util"
"github.com/AdguardTeam/AdGuardHome/internal/util"
"github.com/AdguardTeam/golibs/log"
"github.com/NYTimes/gziphandler"
"github.com/gobuffalo/packr"
@@ -63,7 +63,7 @@ func CreateWeb(conf *WebConfig) *Web {
w.errLogger = golog.New(&lw, "", 0)
// Initialize and run the admin Web interface
box := packr.NewBox("../build/static")
box := packr.NewBox("../../build/static")
// if not configured, redirect / to /install.html, otherwise redirect /install.html to /
http.Handle("/", postInstallHandler(optionalAuthHandler(gziphandler.GzipHandler(http.FileServer(box)))))

View File

@@ -9,7 +9,7 @@ import (
"strings"
"time"
"github.com/AdguardTeam/AdGuardHome/util"
"github.com/AdguardTeam/AdGuardHome/internal/util"
"github.com/AdguardTeam/golibs/cache"
"github.com/AdguardTeam/golibs/log"
@@ -116,7 +116,7 @@ func whoisParse(data string) map[string]string {
}
// Send request to a server and receive the response
func (w *Whois) query(target string, serverAddr string) (string, error) {
func (w *Whois) query(target, serverAddr string) (string, error) {
addr, _, _ := net.SplitHostPort(serverAddr)
if addr == "whois.arin.net" {
target = "n + " + target
@@ -168,7 +168,7 @@ func (w *Whois) queryAll(target string) (string, error) {
log.Debug("Whois: redirected to %s IP:%s", redir, target)
}
return "", fmt.Errorf("Whois: redirect loop")
return "", fmt.Errorf("whois: redirect loop")
}
// Request WHOIS information
@@ -224,8 +224,7 @@ func (w *Whois) Begin(ip string) {
// Get IP address from channel; get WHOIS info; associate info with a client
func (w *Whois) workerLoop() {
for {
var ip string
ip = <-w.ipChan
ip := <-w.ipChan
info := w.process(ip)
if len(info) == 0 {

View File

@@ -3,7 +3,7 @@ package home
import (
"testing"
"github.com/AdguardTeam/AdGuardHome/dnsforward"
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
"github.com/stretchr/testify/assert"
)

View File

@@ -6,7 +6,7 @@ import (
"strings"
"time"
"github.com/AdguardTeam/AdGuardHome/dnsfilter"
"github.com/AdguardTeam/AdGuardHome/internal/dnsfilter"
"github.com/AdguardTeam/golibs/log"
"github.com/miekg/dns"
)
@@ -38,7 +38,7 @@ func decodeLogEntry(ent *logEntry, str string) {
ent.QClass = v
case "CP":
ent.ClientProto = v
ent.ClientProto, err = NewClientProto(v)
case "Answer":
ent.Answer, err = base64.StdEncoding.DecodeString(v)

View File

@@ -15,7 +15,7 @@ func TestJSON(t *testing.T) {
assert.Equal(t, "keystr", k)
assert.Equal(t, "val", v)
k, v, jtype = readJSON(&s)
k, _, jtype = readJSON(&s)
assert.Equal(t, jtype, int32(jsonTObj))
assert.Equal(t, "obj", k)
@@ -29,6 +29,6 @@ func TestJSON(t *testing.T) {
assert.Equal(t, "keyint", k)
assert.Equal(t, "123456", v)
k, v, jtype = readJSON(&s)
_, _, jtype = readJSON(&s)
assert.True(t, jtype == jsonTErr)
}

View File

@@ -1,13 +1,15 @@
// Package querylog provides query log functions and interfaces.
package querylog
import (
"fmt"
"os"
"path/filepath"
"strings"
"sync"
"time"
"github.com/AdguardTeam/AdGuardHome/dnsfilter"
"github.com/AdguardTeam/AdGuardHome/internal/dnsfilter"
"github.com/AdguardTeam/golibs/log"
"github.com/miekg/dns"
)
@@ -29,6 +31,33 @@ type queryLog struct {
fileWriteLock sync.Mutex
}
// ClientProto values are names of the client protocols.
type ClientProto string
// Client protocol names.
const (
ClientProtoDOH ClientProto = "doh"
ClientProtoDOQ ClientProto = "doq"
ClientProtoDOT ClientProto = "dot"
ClientProtoPlain ClientProto = ""
)
// NewClientProto validates that the client protocol name is valid and returns
// the name as a ClientProto.
func NewClientProto(s string) (cp ClientProto, err error) {
switch cp = ClientProto(s); cp {
case
ClientProtoDOH,
ClientProtoDOQ,
ClientProtoDOT,
ClientProtoPlain:
return cp, nil
default:
return "", fmt.Errorf("invalid client proto: %q", s)
}
}
// logEntry - represents a single log entry
type logEntry struct {
IP string `json:"IP"` // Client IP
@@ -38,7 +67,7 @@ type logEntry struct {
QType string `json:"QT"`
QClass string `json:"QC"`
ClientProto string `json:"CP"` // "" or "doh"
ClientProto ClientProto `json:"CP"`
Answer []byte `json:",omitempty"` // sometimes empty answers happen like binerdunt.top or rev2.globalrootservers.net
OrigAnswer []byte `json:",omitempty"`
@@ -158,7 +187,6 @@ func (l *queryLog) Add(params AddParams) {
// writing to file is disabled - just remove the oldest entry from array
l.buffer = l.buffer[1:]
}
} else if !l.flushPending {
needFlush = len(l.buffer) >= int(l.conf.MemSize)
if needFlush {

View File

@@ -6,14 +6,16 @@ import (
"sync"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/agherr"
"github.com/AdguardTeam/golibs/log"
"github.com/pkg/errors"
)
// ErrSeekNotFound is returned from the Seek method
// if we failed to find the desired record
var ErrSeekNotFound = errors.New("Seek not found the record")
// ErrSeekNotFound is returned from Seek if when it fails to find the requested
// record.
const ErrSeekNotFound agherr.Error = "seek: record not found"
// ErrEndOfLog is returned from Seek when the end of the current log is reached.
const ErrEndOfLog agherr.Error = "seek: end of log"
// TODO: Find a way to grow buffer instead of relying on this value when reading strings
const maxEntrySize = 16 * 1024
@@ -40,8 +42,7 @@ type QLogFile struct {
// NewQLogFile initializes a new instance of the QLogFile
func NewQLogFile(path string) (*QLogFile, error) {
f, err := os.OpenFile(path, os.O_RDONLY, 0644)
f, err := os.OpenFile(path, os.O_RDONLY, 0o644)
if err != nil {
return nil, err
}
@@ -107,6 +108,8 @@ func (q *QLogFile) Seek(timestamp int64) (int64, int, error) {
// the scope is too narrow and we won't find anything anymore
log.Error("querylog: didn't find timestamp:%v", timestamp)
return 0, depth, ErrSeekNotFound
} else if lineIdx == end && lineEndIdx == end {
return 0, depth, ErrEndOfLog
}
// Save the last found idx
@@ -228,7 +231,7 @@ func (q *QLogFile) readNextLine(position int64) (string, int64, error) {
// Look for the end of the prev line
// This is where we'll read from
var startLine = int64(0)
startLine := int64(0)
for i := relativePos - 1; i >= 0; i-- {
if q.buffer[i] == '\n' {
startLine = i + 1
@@ -294,7 +297,7 @@ func (q *QLogFile) readProbeLine(position int64) (string, int64, int64, error) {
// Now start looking for the new line character starting
// from the relativePos and going left
var startLine = int64(0)
startLine := int64(0)
for i := relativePos - 1; i >= 0; i-- {
if buffer[i] == '\n' {
startLine = i + 1
@@ -302,7 +305,7 @@ func (q *QLogFile) readProbeLine(position int64) (string, int64, int64, error) {
}
}
// Looking for the end of line now
var endLine = int64(bufferLen)
endLine := int64(bufferLen)
lineEndIdx := endLine + seekPosition
for i := relativePos; i < int64(bufferLen); i++ {
if buffer[i] == '\n' {

Some files were not shown because too many files have changed in this diff Show More