Compare commits

...

46 Commits

Author SHA1 Message Date
Ainar Garipov
b1c71a1284 Pull request: all: prepare for v0.104.2
Merge in DNS/adguard-home from prepare-release to master

Squashed commit of the following:

commit cf4cad216fa259b260bc9cfbd99938979b10623c
Merge: 5434ab5c1 4690229d8
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Nov 19 13:08:50 2020 +0300

    Merge branch 'master' into prepare-release

commit 5434ab5c178942e8db9e99758c86d22e977d092f
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Nov 19 13:01:43 2020 +0300

    all: prepare for v0.104.2
2020-11-19 13:14:52 +03:00
Ainar Garipov
4690229d81 Pull request: querylog: use better error signaling
Merge in DNS/adguard-home from 2325-querylog-suffering to master

Closes #2325.

Squashed commit of the following:

commit 90388050ed495286cdfed6574dd438abd4a33baa
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Nov 19 12:37:00 2020 +0300

    all: changelog

commit bbdeabbb550c7e98f579e2a68c71de7a66624203
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Nov 19 12:33:21 2020 +0300

    querylog: improve error reporting

commit 807b23aa74d0e39f5ef51910e5b91c9b95a8c341
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Nov 18 19:39:22 2020 +0300

    querylog: improve docs

commit 65a8f4f3323192c872b3389d2b3420e072a01297
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Nov 18 19:36:28 2020 +0300

    querylog: use better error signaling
2020-11-19 12:53:31 +03:00
Eugene Burkov
de257b73aa Pull request: update golangci-lint and golangci-lint-actions versions
Merge in DNS/adguard-home from linter-version-update to master

Squashed commit of the following:

commit 3ab2cb198dd924d86f5e6b92d101846acc747e9b
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Wed Nov 18 16:42:13 2020 +0300

    all: update golangci-lint and golangci-lint-actions versions
2020-11-18 18:42:26 +03:00
Eugene Burkov
40614d9a7b Pull request: querylog bug fix
Merge in DNS/adguard-home from 2324-querylog-bug-fix to master

Closes #2324.

Squashed commit of the following:

commit fdd584a218e1edc3e45ab5b00ceed0a3be681e32
Merge: 8103f9e42 f2eda6d19
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Wed Nov 18 15:35:42 2020 +0300

    Merge branch 'master' into 2324-querylog-bug-fix

commit 8103f9e42a398f43682ee30d09b3afdab0e9e177
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Wed Nov 18 14:28:29 2020 +0300

    querylog: fix the file ordering bug

commit 2c4e8fcc5b8593be1614480508dfd600fc676e64
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Tue Nov 17 20:57:45 2020 +0300

    querylog: wrap errors to clarify error trace

commit 3733062b494817696e4443f153774bb01cea1b06
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Tue Nov 17 18:55:17 2020 +0300

    querylog: fix logger output bug
2020-11-18 15:43:28 +03:00
Ainar Garipov
f2eda6d192 Pull request: - client: 2326 Fix dhcp bug interfaces bug
Merge in DNS/adguard-home from fix/2326 to master

Closes #2326.

Squashed commit of the following:

commit 31f24d733eda747e161ddd44055591dbbc0752d7
Author: Artem Baskal <a.baskal@adguard.com>
Date:   Tue Nov 17 18:16:19 2020 +0300

    - client: 2326 Fix dhcp bug interfaces bug
2020-11-17 19:56:58 +03:00
Eugene Burkov
8a9c6e8a02 Pull request: cover with tests
Merge in DNS/adguard-home from 2271-cover-with-tests to master

Updates #2271.

Squashed commit of the following:

commit db6440efe05171bc15367a2996521848ca348053
Merge: db7fa726b bf4c256c7
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Mon Nov 16 19:23:09 2020 +0300

    Merge branch 'master' into 2271-cover-with-tests

commit db7fa726bb91b08ec7aaa6c0c818c88b5feb87cd
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Mon Nov 16 18:26:51 2020 +0300

    all: clean dependencies sum

commit b8dc6078c4bcc0de1b7e9073832de122f6fe38a4
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Mon Nov 16 16:46:00 2020 +0300

    testutil: improve code quality

commit 001b7194682b1f00aa54dc5a28236faed5a5b02d
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Mon Nov 16 16:29:49 2020 +0300

    testutil: enhance functionality

commit f6ccd91a4df6c56778eab8ae50e88e3818b20dd3
Merge: 43fa2eefb 6358240e9
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Mon Nov 16 15:57:37 2020 +0300

    Merge branch 'master' into 2271-cover-with-tests

commit 43fa2eefbc10ef361603cacc1ca12092b12a057a
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Mon Nov 16 14:55:15 2020 +0300

    querylog: replace fake log with real in tests

commit b95bee7565a14a02c80c78131b3ced224663dd8a
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Mon Nov 16 12:38:59 2020 +0300

    dnsfilter: replace thoughtless declaration with idiomatic one

commit a210b1586092e7ae91a9e67c972fa2d2f6baded6
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Fri Nov 13 19:00:25 2020 +0300

    all: refresh golibs dependencies

commit 4ff97bd1ade6c80e274ff5716e44df4eba55bdd9
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Fri Nov 13 18:38:47 2020 +0300

    all: remove std log

commit 542dbda10fefce9f46d15489712b163d919b1291
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Fri Nov 13 13:46:39 2020 +0300

    querylog: improve test logic and readability

commit 796d402385925e8e62a1b4c7bf56e4ceec22418c
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Thu Nov 12 19:06:42 2020 +0300

    all: improve code quality

commit e81894c11ef15b0453e8e5297f1349936a32f9dd
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Thu Nov 12 18:32:30 2020 +0300

    all: cover with tests

commit 252d81fc8a50a91b02cf0f6f35cc22178a2a4d90
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Thu Nov 12 17:32:01 2020 +0300

    all: cover with tests
2020-11-16 19:45:31 +03:00
Ainar Garipov
bf4c256c72 Pull request: return 501 when we don't support features
Merge in DNS/adguard-home from 2295-dhcp-windows to master

Updates #2295.

Squashed commit of the following:

commit 3b00a90c3d9bc33e9af478e4062c0f938d4f327d
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Nov 16 16:45:43 2020 +0300

    all: use the 501 handlers instead of the real ones, revert other changes

commit 0a3b37736a21abd6181e0d28c32069e8d7a576d0
Merge: 45feba755 6358240e9
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Nov 16 15:59:15 2020 +0300

    Merge branch 'master' into 2295-dhcp-windows and update

commit 45feba755dde37e43cc8075b896e1576157341e6
Merge: cd987d8bc a19523b25
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Nov 16 15:51:16 2020 +0300

    Merge branch 'master' into 2295-dhcp-windows

commit cd987d8bc2cd524b7454d9037b595069714645f9
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Nov 13 15:55:23 2020 +0300

    all: improve tests and refactor dhcp checking code even more

commit 3aad675443f325b5909523bcc1c987aa04ac61d9
Merge: 70c477e61 09196118e
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Nov 13 14:44:43 2020 +0300

    Merge branch 'master' into 2295-dhcp-windows

commit 70c477e61cdc1237603918f1c44470c1549f1136
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Nov 13 14:34:06 2020 +0300

    home: fix dhcpd test on windows

commit e59597d783fb9304e63f94eee2b5a5d67a5b2169
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Nov 13 13:38:25 2020 +0300

    all: mention the feature in the changelog

commit 5555c8d881b1c20b5b0a0cb096a17cf56e209c06
Merge: c3b6a5a93 e802e6645
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Nov 13 13:35:35 2020 +0300

    Merge branch 'master' into 2295-dhcp-windows

commit c3b6a5a930693090838eb1ef9f75a09b5b223ba6
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Nov 12 20:37:09 2020 +0300

    util: fix comment

commit ed92dfdb5d3a6c4ba5d032cbe781e7fd87882813
Author: ArtemBaskal <asbaskal@miem.hse.ru>
Date:   Thu Nov 12 20:24:14 2020 +0300

    Adapt client

commit e6f0494c20a4ad5388492af9091568eea5c6e2d6
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Nov 12 13:35:25 2020 +0300

    return 501 when we don't support features
2020-11-16 19:01:12 +03:00
Eugene Burkov
6358240e9b Pull request: 2273 clean tests output
Merge in DNS/adguard-home from 2273-clean-tests-output to master

Closes #2273.

Squashed commit of the following:

commit 7571a33fc1f76300bd256578b3afa95338e399c4
Merge: f17df0f9c a19523b25
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Mon Nov 16 15:45:30 2020 +0300

    Merge branch 'master' into 2273-clean-tests-output

commit f17df0f9ce2a3ed25db33fbc6a2e7cabd33f657b
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Mon Nov 16 15:35:42 2020 +0300

    home: move build constraint on top line

commit 3717c8ef5a51f9dcaa7e524bfa7b0f1d90bec93d
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Mon Nov 16 15:24:50 2020 +0300

    all: add improvements to changelog

commit de6d5afe39d74a3c3d3e0bbe6d0e09aea0214d56
Merge: 43d4f7acf 394fc5a9d
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Mon Nov 16 15:04:38 2020 +0300

    Merge branch 'master' into 2273-clean-tests-output

commit 43d4f7acf188e810aa7277cb6479110c9842e8be
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Mon Nov 16 13:38:13 2020 +0300

    dnsfilter: remove redundant test logging

commit 7194c1413006b8f52fc454e89ab052bf52e4e517
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Mon Nov 16 12:19:14 2020 +0300

    testutil: improve comments

commit 9f17ab08e287fa69ce30d9e7eec8ea8880f87716
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Sat Nov 14 01:22:08 2020 +0300

    nclient4: fix wrong function name

commit f355749149b2a4485792ba2bdcbc0bb4b629d726
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Sat Nov 14 01:07:22 2020 +0300

    testutil: fix comments and naming

commit f8c50a260bfae08d594a7f37d603941d3680a45e
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Fri Nov 13 14:09:50 2020 +0300

    testutil: create a package and include it

commit f169cdc4084b719de65aa0cdc65200b48785322e
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Thu Nov 12 20:15:58 2020 +0300

    agherr: discard loggers output

commit 360e736b5a2a30f2c5350448234f14b841e3ea27
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Thu Nov 12 20:09:55 2020 +0300

    all: replace default log writer with ioutil.Discard

    Closes #2273.
2020-11-16 15:52:05 +03:00
Artem Baskal
a19523b258 - client: 2237 Update graph drawing library
Squashed commit of the following:

commit 980e9c2f37640ee204ce0365f6c3bcc74741cc7c
Merge: cb4cae82b 394fc5a9d
Author: Artem Baskal <a.baskal@adguard.com>
Date:   Mon Nov 16 14:52:26 2020 +0300

    Merge branch 'master' into fix/2237

commit cb4cae82b5b605894d123d6442ea23b24cc90c12
Author: ArtemBaskal <asbaskal@miem.hse.ru>
Date:   Thu Nov 12 12:07:49 2020 +0300

    minor

commit 5c07dac48067b4ed201aeb59a44e8592ed2b0b67
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Wed Nov 11 19:47:38 2020 +0300

    minor

commit 53f60762e520427a080bdfcd94b08b9ed3a63ca4
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Wed Nov 11 19:06:06 2020 +0300

    Adapt mobile version

commit 7659ac733ce4606f6fadf30e0eaddbeefd6095d6
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Wed Nov 11 18:31:53 2020 +0300

    Fix empty graph offset, return background area below graph

commit 45499adb20a90024dba4b0b4e44ad4f01a1782d5
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Tue Nov 10 17:46:47 2020 +0300

    - client: 2237 Update graph drawing library
2020-11-16 15:22:30 +03:00
Artem Baskal
394fc5a9d8 - client: 2300 Fix block client bug when clients values are empty in config
Close #2300

Squashed commit of the following:

commit 7222a03ebf3bf8aa93fbd819227e1d5caacce92b
Merge: 91b06b10e 09196118e
Author: Artem Baskal <a.baskal@adguard.com>
Date:   Mon Nov 16 12:46:26 2020 +0300

    Merge branch 'master' into fix/2300

commit 91b06b10e5d46472c9474032d0ae11dc8d0e4609
Author: Artem Baskal <a.baskal@adguard.com>
Date:   Fri Nov 13 15:12:31 2020 +0300

    - client: 2300 Fix block client bug when clients values are empty in config
2020-11-16 12:56:55 +03:00
Ainar Garipov
09196118e9 Pull request: dhcpd: fix possible infinite loop, set timeouts better
Merge in DNS/adguard-home from 2301-dhcp-check to master

Closes #2301.

Squashed commit of the following:

commit bf5c31b8592f909a372fcdaebacc491d310cc3e6
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Fri Nov 13 14:28:54 2020 +0300

    dhcpd: fix possible infinite loop, set timeouts better
2020-11-13 14:40:22 +03:00
Ainar Garipov
e802e6645e Pull request: all: add a changelog and a developer guide
Merge in DNS/adguard-home from 2294-changelog to master

Closes #2294.

Squashed commit of the following:

commit 25ffc9786d23d83448b916a81f0b20135b051169
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Nov 12 19:40:48 2020 +0300

    all: add a changelog and a developer guide
2020-11-13 13:01:07 +03:00
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
Andrey Meshkov
d1e55c31af Update locales 2020-10-28 14:19:29 +03:00
165 changed files with 2698 additions and 1661 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

@@ -12,10 +12,10 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: golangci-lint
uses: golangci/golangci-lint-action@v1
uses: golangci/golangci-lint-action@v2.3.0
with:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
version: v1.27
version: v1.32
eslint:
runs-on: ubuntu-latest

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":{

32
CHANGELOG.md Normal file
View File

@@ -0,0 +1,32 @@
# AdGuard Home Changelog
All notable changes to this project will be documented in this file.
The format is based on
[*Keep a Changelog*](https://keepachangelog.com/en/1.0.0/),
and this project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [v0.104.2] - 2020-11-19
### Added
- This changelog :-) (#2294).
- `HACKING.md`, a guide for developers.
### Changed
- Improved tests output (#2273).
### Fixed
- Query logs from file not loading after the ones buffered in memory (#2325).
- Unnecessary errors in query logs when switching between log files (#2324).
- `404 Not Found` errors on the DHCP settings page on *Windows*. The page now
correctly shows that DHCP is not currently available on that OS (#2295).
- Infinite loop in `/dhcp/find_active_dhcp` (#2301).
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.104.2...HEAD
[v0.104.2]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.104.1...v0.104.2

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

153
HACKING.md Normal file
View File

@@ -0,0 +1,153 @@
# AdGuardHome Developer Guidelines
As of **2020-11-12**, this document is still a work-in-progress. Some of the
rules aren't enforced, and others might change. Still, this is a good place to
find out about how we **want** our code to look like.
## Git
* Follow the commit message header format:
```none
pkg: fix the network error logging issue
```
Where `pkg` is the package where most changes took place. If there are
several such packages, just write `all`.
* Keep your commit messages to be no wider than eighty (**80**) columns.
* Only use lowercase letters in your commit message headers.
## Go
* <https://github.com/golang/go/wiki/CodeReviewComments>.
* <https://github.com/golang/go/wiki/TestComments>.
* <https://go-proverbs.github.io/>
* Avoid `init` and use explicit initialization functions instead.
* Avoid `new`, especially with structs.
* Document everything, including unexported top-level identifiers, to build
a habit of writing documentation.
* Don't put variable names into any kind of quotes.
* Don't use naked `return`s.
* Don't use underscores in file and package names, unless they're build tags
or for tests. This is to prevent accidental build errors with weird tags.
* Don't write code with more than four (**4**) levels of indentation. Just
like [Linus said], plus an additional level for an occasional error check or
struct initialization.
* Eschew external dependencies, including transitive, unless
absolutely necessary.
* No `goto`.
* No shadowing, since it can often lead to subtle bugs, especially with
errors.
* Prefer constants to variables where possible. Reduce global variables. Use
[constant errors] instead of `errors.New`.
* Put comments above the documented entity, **not** to the side, to improve
readability.
* Use `gofumpt --extra -s`.
**TODO(a.garipov):** Add to the linters.
* Use linters.
* Use named returns to improve readability of function signatures.
* When a method implements an interface, start the doc comment with the
standard template:
```go
// Foo implements the Fooer interface for *foo.
func (f *foo) Foo() {
// …
}
```
* Write logs and error messages in lowercase only to make it easier to `grep`
logs and error messages without using the `-i` flag.
* Write slices of struct like this:
```go
ts := []T{{
Field: Value0,
// …
}, {
Field: Value1,
// …
}, {
Field: Value2,
// …
}}
```
[constant errors]: https://dave.cheney.net/2016/04/07/constant-errors
[Linus said]: https://www.kernel.org/doc/html/v4.17/process/coding-style.html#indentation
## Text, Including Comments
* Text should wrap at eighty (**80**) columns to be more readable, to use
a common standard, and to allow editing or diffing side-by-side without
wrapping.
The only exception are long hyperlinks.
* Use U.S. English, as it is the most widely used variety of English in the
code right now as well as generally.
* Use double spacing between sentences to make sentence borders more clear.
* Use the serial comma (a.k.a. Oxford comma) to improve comprehension,
decrease ambiguity, and use a common standard.
* Write todos like this:
```go
// TODO(usr1): Fix the frobulation issue.
```
Or, if several people need to look at the code:
```go
// TODO(usr1, usr2): Fix the frobulation issue.
```
## Markdown
* **TODO(a.garipov):** Define our Markdown conventions.
## YAML
* **TODO(a.garipov):** Find a YAML formatter or write our own.
* All strings, including keys, must be quoted. Reason: the [NO-rway Law].
* Indent with two (**2**) spaces.
* No extra indentation in multiline arrays:
```yaml
'values':
- 'value-1'
- 'value-2'
- 'value-3'
```
* Prefer single quotes for string to prevent accidental escaping, unless
escaping is required.
[NO-rway Law]: https://news.ycombinator.com/item?id=17359376

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).

337
client/package-lock.json generated vendored
View File

@@ -2014,72 +2014,168 @@
}
}
},
"@nivo/axes": {
"version": "0.49.1",
"resolved": "https://registry.npmjs.org/@nivo/axes/-/axes-0.49.1.tgz",
"integrity": "sha512-2ZqpKtnZ9HE30H+r565VCrypKRQzAoMbAg1hsht88dlNQRtghBSxbAS0Y4IUW/wgN/AzvOIBJHvxH7bgaB8Oow==",
"@nivo/annotations": {
"version": "0.64.0",
"resolved": "https://registry.npmjs.org/@nivo/annotations/-/annotations-0.64.0.tgz",
"integrity": "sha512-b9VAVuAn2HztOZckU2GcBwptjCobYV5VgX/jwZTSFeZFLtjZza+QinNL2AbQ2cnmeU3nVCw1dTbJMMZ9fTCCNQ==",
"requires": {
"@nivo/core": "0.49.0",
"d3-format": "^1.3.2",
"@nivo/colors": "0.64.0",
"lodash": "^4.17.11",
"react-spring": "^8.0.27"
}
},
"@nivo/axes": {
"version": "0.64.0",
"resolved": "https://registry.npmjs.org/@nivo/axes/-/axes-0.64.0.tgz",
"integrity": "sha512-Pm+Y3C67OuBb3JqHpyFKWAoPAnNojb1s5/LFQYVYN1QpKyjeqilGAoLCjHK6ckgfzreiGf7NG+oBgpH8Ncz2fQ==",
"requires": {
"@nivo/scales": "0.64.0",
"d3-format": "^1.4.4",
"d3-time": "^1.0.11",
"d3-time-format": "^2.1.3",
"lodash": "^4.17.4",
"react-motion": "^0.5.2",
"recompose": "^0.26.0"
"react-spring": "^8.0.27"
},
"dependencies": {
"d3-format": {
"version": "1.4.5",
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz",
"integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ=="
},
"d3-time": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz",
"integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA=="
},
"d3-time-format": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz",
"integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==",
"requires": {
"d3-time": "1"
}
}
}
},
"@nivo/colors": {
"version": "0.64.0",
"resolved": "https://registry.npmjs.org/@nivo/colors/-/colors-0.64.0.tgz",
"integrity": "sha512-3CKIkSjKgwSgBsiJoTlZpFUUpaGTl60pF6rFsIiFT30os9jMxP/J4ikQGQ/vMLPTXskZYoxByaMHGKJy5wypqg==",
"requires": {
"d3-color": "^1.2.3",
"d3-scale": "^3.0.0",
"d3-scale-chromatic": "^1.3.3",
"lodash.get": "^4.4.2",
"lodash.isplainobject": "^4.0.6",
"react-motion": "^0.5.2"
}
},
"@nivo/core": {
"version": "0.49.0",
"resolved": "https://registry.npmjs.org/@nivo/core/-/core-0.49.0.tgz",
"integrity": "sha512-TCPMUO2aJ7fI+ZB6t3d3EBQtNxJnTzaxLJsrVyn/3AQIjUwccAeo2aIy81wLBGWGtlGNUDNdAbnFzXiJosH0yg==",
"version": "0.64.0",
"resolved": "https://registry.npmjs.org/@nivo/core/-/core-0.64.0.tgz",
"integrity": "sha512-tupETbvxgv4B9y3pcXy/lErMwY2aZht+FKSyah1dPFd88LnMD/DOL+to6ociBHmpLQNUMA7wid6R7BlXRY/bmg==",
"requires": {
"d3-color": "^1.0.3",
"d3-format": "^1.3.2",
"d3-color": "^1.2.3",
"d3-format": "^1.4.4",
"d3-hierarchy": "^1.1.8",
"d3-interpolate": "^1.3.2",
"d3-scale": "^2.1.2",
"d3-interpolate": "^2.0.1",
"d3-scale": "^3.0.0",
"d3-scale-chromatic": "^1.3.3",
"d3-shape": "^1.2.2",
"d3-shape": "^1.3.5",
"d3-time-format": "^2.1.3",
"lodash": "^4.17.4",
"react-measure": "^2.0.2",
"react-motion": "^0.5.2",
"recompose": "^0.26.0"
"lodash": "^4.17.11",
"react-spring": "^8.0.27",
"recompose": "^0.30.0",
"resize-observer-polyfill": "^1.5.1"
},
"dependencies": {
"d3-format": {
"version": "1.4.5",
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz",
"integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ=="
},
"d3-time": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz",
"integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA=="
},
"d3-time-format": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz",
"integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==",
"requires": {
"d3-time": "1"
}
}
}
},
"@nivo/legends": {
"version": "0.49.0",
"resolved": "https://registry.npmjs.org/@nivo/legends/-/legends-0.49.0.tgz",
"integrity": "sha512-8KbUFYozqwD+/rj4in0mnF9b9CuyNFjVgXqm2KW3ODVlWIgYgjTVlEhlg9VZIArFPlIyyAjEYC88YSRcALHugg==",
"version": "0.64.0",
"resolved": "https://registry.npmjs.org/@nivo/legends/-/legends-0.64.0.tgz",
"integrity": "sha512-L7Mp/of/jY4qE7ef6PXJ8/e3aASBTfsf5BTOh3imSXZT6I4hXa5ppmGAgZ0gOSpcPXuMEjBc0aSIEJoeoytQ/g==",
"requires": {
"lodash": "^4.17.4",
"recompose": "^0.26.0"
"@nivo/core": "0.64.0",
"lodash": "^4.17.11",
"recompose": "^0.30.0"
}
},
"@nivo/line": {
"version": "0.49.1",
"resolved": "https://registry.npmjs.org/@nivo/line/-/line-0.49.1.tgz",
"integrity": "sha512-wKkOmpnwK2psmZbJReDq+Eh/WV9r1JA8V4Vl4eIRuf971CW0KUT9nCAoc/FcKio0qsiq5wyFt3J5LuAhfzlV/w==",
"version": "0.64.0",
"resolved": "https://registry.npmjs.org/@nivo/line/-/line-0.64.0.tgz",
"integrity": "sha512-WkQU28ZL9Mxq42AdmybWe+2qFh/TiUXu+7e6nj41e/8DO95Guxg1XQ+i5zQKuw/UZlqXZs6WOsMW8EMNE4GzXw==",
"requires": {
"@nivo/axes": "0.49.1",
"@nivo/core": "0.49.0",
"@nivo/legends": "0.49.0",
"@nivo/scales": "0.49.0",
"d3-format": "^1.3.2",
"d3-scale": "^2.1.2",
"d3-shape": "^1.2.2",
"lodash": "^4.17.4",
"react-motion": "^0.5.2",
"recompose": "^0.26.0"
"@nivo/annotations": "0.64.0",
"@nivo/axes": "0.64.0",
"@nivo/colors": "0.64.0",
"@nivo/legends": "0.64.0",
"@nivo/scales": "0.64.0",
"@nivo/tooltip": "0.64.0",
"@nivo/voronoi": "0.64.0",
"d3-shape": "^1.3.5",
"react-spring": "^8.0.27"
}
},
"@nivo/scales": {
"version": "0.49.0",
"resolved": "https://registry.npmjs.org/@nivo/scales/-/scales-0.49.0.tgz",
"integrity": "sha512-+5Leu4zX6mDSAunf4ZJHeqVlT+ZsqiKXLB6hT/u7r3GjxZP9A+n3rHePhIzikBiBRMlLjyiBlylLzhKBAYbGWQ==",
"version": "0.64.0",
"resolved": "https://registry.npmjs.org/@nivo/scales/-/scales-0.64.0.tgz",
"integrity": "sha512-Jbr1rlfe/gLCippndPaCM7doJzzx1K9oXPxS4JiyvrIUkQoMWiozymZQdEp8kgigI6uwWu5xvPwCOFXalCIhKg==",
"requires": {
"d3-scale": "^2.1.2",
"d3-scale": "^3.0.0",
"d3-time-format": "^2.1.3",
"lodash": "^4.17.4"
"lodash": "^4.17.11"
},
"dependencies": {
"d3-time": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz",
"integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA=="
},
"d3-time-format": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz",
"integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==",
"requires": {
"d3-time": "1"
}
}
}
},
"@nivo/tooltip": {
"version": "0.64.0",
"resolved": "https://registry.npmjs.org/@nivo/tooltip/-/tooltip-0.64.0.tgz",
"integrity": "sha512-iGsuCi42uw/8F7OVvPyWdQgxJXVOPTEdtl2WK2FlSJIH7bfnEsZ+R/lTdElY2JAvGHuNW6hQwpNUZdC/2rOatg==",
"requires": {
"react-spring": "^8.0.27"
}
},
"@nivo/voronoi": {
"version": "0.64.0",
"resolved": "https://registry.npmjs.org/@nivo/voronoi/-/voronoi-0.64.0.tgz",
"integrity": "sha512-YdNRzD2rFc1NcAZe9D8gxos+IT2CRPOV/7fUfBCG9SoNw1TtSwSKtEs4xsxmUFmLT1FadWcyKeKuhgJUQnof/A==",
"requires": {
"@nivo/core": "0.64.0",
"d3-delaunay": "^5.1.1",
"d3-scale": "^3.0.0",
"recompose": "^0.30.0"
}
},
"@nodelib/fs.scandir": {
@@ -4681,24 +4777,27 @@
"dev": true
},
"d3-array": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz",
"integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw=="
},
"d3-collection": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz",
"integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A=="
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.8.0.tgz",
"integrity": "sha512-6V272gsOeg7+9pTW1jSYOR1QE37g95I3my1hBmY+vOUNHRrk9yt4OTz/gK7PMkVAVDrYYq4mq3grTiZ8iJdNIw=="
},
"d3-color": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz",
"integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q=="
},
"d3-delaunay": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-5.3.0.tgz",
"integrity": "sha512-amALSrOllWVLaHTnDLHwMIiz0d1bBu9gZXd1FiLfXf8sHcX9jrcj81TVZOqD4UX7MgBZZ07c8GxzEgBpJqc74w==",
"requires": {
"delaunator": "4"
}
},
"d3-format": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.4.tgz",
"integrity": "sha512-TWks25e7t8/cqctxCmxpUuzZN11QxIA7YrMbram94zMQ0PXjE4LVIMe/f6a4+xxL8HQ3OsAFULOINQi1pE62Aw=="
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz",
"integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA=="
},
"d3-hierarchy": {
"version": "1.1.9",
@@ -4706,11 +4805,11 @@
"integrity": "sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ=="
},
"d3-interpolate": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz",
"integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz",
"integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==",
"requires": {
"d3-color": "1"
"d3-color": "1 - 2"
}
},
"d3-path": {
@@ -4719,16 +4818,15 @@
"integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="
},
"d3-scale": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.2.2.tgz",
"integrity": "sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==",
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.2.3.tgz",
"integrity": "sha512-8E37oWEmEzj57bHcnjPVOBS3n4jqakOeuv1EDdQSiSrYnMCBdMd3nc4HtKk7uia8DUHcY/CGuJ42xxgtEYrX0g==",
"requires": {
"d3-array": "^1.2.0",
"d3-collection": "1",
"d3-format": "1",
"d3-interpolate": "1",
"d3-time": "1",
"d3-time-format": "2"
"d3-array": "^2.3.0",
"d3-format": "1 - 2",
"d3-interpolate": "1.2.0 - 2",
"d3-time": "1 - 2",
"d3-time-format": "2 - 3"
}
},
"d3-scale-chromatic": {
@@ -4738,6 +4836,16 @@
"requires": {
"d3-color": "1",
"d3-interpolate": "1"
},
"dependencies": {
"d3-interpolate": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz",
"integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==",
"requires": {
"d3-color": "1"
}
}
}
},
"d3-shape": {
@@ -4749,16 +4857,16 @@
}
},
"d3-time": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz",
"integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA=="
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.0.0.tgz",
"integrity": "sha512-2mvhstTFcMvwStWd9Tj3e6CEqtOivtD8AUiHT8ido/xmzrI9ijrUUihZ6nHuf/vsScRBonagOdj0Vv+SEL5G3Q=="
},
"d3-time-format": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.2.3.tgz",
"integrity": "sha512-RAHNnD8+XvC4Zc4d2A56Uw0yJoM7bsvOlJR33bclxq399Rak/b9bhvu/InjxdWhPtkgU53JJcleJTGkNRnN6IA==",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz",
"integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==",
"requires": {
"d3-time": "1"
"d3-time": "1 - 2"
}
},
"damerau-levenshtein": {
@@ -4963,6 +5071,11 @@
}
}
},
"delaunator": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/delaunator/-/delaunator-4.0.1.tgz",
"integrity": "sha512-WNPWi1IRKZfCt/qIDMfERkDp93+iZEmOxN2yy4Jg+Xhv8SLk2UTqqbe1sfiipn0and9QrE914/ihdx82Y/Giag=="
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -5253,11 +5366,21 @@
"dev": true
},
"encoding": {
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
"integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
"integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
"requires": {
"iconv-lite": "~0.4.13"
"iconv-lite": "^0.6.2"
},
"dependencies": {
"iconv-lite": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz",
"integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==",
"requires": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
}
}
}
},
"end-of-stream": {
@@ -6766,11 +6889,6 @@
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true
},
"get-node-dimensions": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/get-node-dimensions/-/get-node-dimensions-1.2.1.tgz",
"integrity": "sha512-2MSPMu7S1iOTL+BOa6K1S62hB2zUAYNF/lV0gSVlOaacd087lc6nR1H1r0e3B1CerTo+RceOmi1iJW+vp21xcQ=="
},
"get-package-type": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
@@ -7430,6 +7548,7 @@
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"dev": true,
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
}
@@ -10194,6 +10313,16 @@
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.15.tgz",
"integrity": "sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ=="
},
"lodash.get": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
},
"lodash.isplainobject": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
"integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
},
"lodash.sortby": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
@@ -12403,17 +12532,6 @@
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
},
"react-measure": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/react-measure/-/react-measure-2.3.0.tgz",
"integrity": "sha512-dwAvmiOeblj5Dvpnk8Jm7Q8B4THF/f1l1HtKVi0XDecsG6LXwGvzV5R1H32kq3TW6RW64OAf5aoQxpIgLa4z8A==",
"requires": {
"@babel/runtime": "^7.2.0",
"get-node-dimensions": "^1.2.1",
"prop-types": "^15.6.2",
"resize-observer-polyfill": "^1.5.0"
}
},
"react-modal": {
"version": "3.11.2",
"resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.11.2.tgz",
@@ -12576,6 +12694,15 @@
}
}
},
"react-spring": {
"version": "8.0.27",
"resolved": "https://registry.npmjs.org/react-spring/-/react-spring-8.0.27.tgz",
"integrity": "sha512-nDpWBe3ZVezukNRandTeLSPcwwTMjNVu1IDq9qA/AMiUqHuRN4BeSWvKr3eIxxg1vtiYiOLy4FqdfCP5IoP77g==",
"requires": {
"@babel/runtime": "^7.3.1",
"prop-types": "^15.5.8"
}
},
"react-table": {
"version": "6.11.4",
"resolved": "https://registry.npmjs.org/react-table/-/react-table-6.11.4.tgz",
@@ -12663,13 +12790,15 @@
}
},
"recompose": {
"version": "0.26.0",
"resolved": "https://registry.npmjs.org/recompose/-/recompose-0.26.0.tgz",
"integrity": "sha512-KwOu6ztO0mN5vy3+zDcc45lgnaUoaQse/a5yLVqtzTK13czSWnFGmXbQVmnoMgDkI5POd1EwIKSbjU1V7xdZog==",
"version": "0.30.0",
"resolved": "https://registry.npmjs.org/recompose/-/recompose-0.30.0.tgz",
"integrity": "sha512-ZTrzzUDa9AqUIhRk4KmVFihH0rapdCSMFXjhHbNrjAWxBuUD/guYlyysMnuHjlZC/KRiOKRtB4jf96yYSkKE8w==",
"requires": {
"@babel/runtime": "^7.0.0",
"change-emitter": "^0.1.2",
"fbjs": "^0.8.1",
"hoist-non-react-statics": "^2.3.1",
"react-lifecycles-compat": "^3.0.2",
"symbol-observable": "^1.0.4"
}
},
@@ -15067,9 +15196,9 @@
}
},
"ua-parser-js": {
"version": "0.7.21",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.21.tgz",
"integrity": "sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ=="
"version": "0.7.22",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.22.tgz",
"integrity": "sha512-YUxzMjJ5T71w6a8WWVcMGM6YWOTX27rCoIQgLXiWaxqXSx9D7DNjiGWn1aJIRSQ5qr0xuhra77bSIh6voR/46Q=="
},
"unherit": {
"version": "1.1.3",
@@ -16086,9 +16215,9 @@
}
},
"whatwg-fetch": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz",
"integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q=="
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.5.0.tgz",
"integrity": "sha512-jXkLtsR42xhXg7akoDKvKWE40eJeI+2KZqcp2h3NsOrRnDvtWX36KcKl30dy+hxECivdk2BVUHVNrPtoMBUx6A=="
},
"whatwg-mimetype": {
"version": "2.3.0",

2
client/package.json vendored
View File

@@ -13,7 +13,7 @@
"test:watch": "jest --watch"
},
"dependencies": {
"@nivo/line": "^0.49.1",
"@nivo/line": "^0.64.0",
"axios": "^0.19.2",
"classnames": "^2.2.6",
"date-fns": "^1.29.0",

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

@@ -9,7 +9,7 @@
"bootstrap_dns": "Servidores DNS de inicialização",
"bootstrap_dns_desc": "Servidores DNS de inicialização são usados para resolver endereços IP dos resolvedores DoH/DoT que especifica como upstreams.",
"check_dhcp_servers": "Verificar por servidores DHCP",
"save_config": "Guardar configuração",
"save_config": "Guardar definição",
"enabled_dhcp": "Servidor DHCP activado",
"disabled_dhcp": "Servidor DHCP desactivado",
"unavailable_dhcp": "DHCP não está disponível",
@@ -57,7 +57,7 @@
"dhcp_new_static_lease": "Nova concessão estática",
"dhcp_static_leases_not_found": "Nenhuma concessão DHCP estática foi encontrada",
"dhcp_add_static_lease": "Adicionar nova concessão estática",
"dhcp_reset": "Tem a certeza de que deseja redefinir a configuração DHCP?",
"dhcp_reset": "Tem a certeza de que deseja repor a definição de DHCP?",
"country": "País",
"city": "Cidade",
"delete_confirm": "Tem a certeza de que deseja excluir \"{{key}}\"?",
@@ -133,7 +133,7 @@
"encryption_settings": "Configurações de criptografia",
"dhcp_settings": "Configurações de DHCP",
"upstream_dns": "Servidores DNS upstream",
"upstream_dns_help": "Insira os endereços dos servidores, um por linha. <a>Saber mais</a> sobre a configuração de servidores DNS primários.",
"upstream_dns_help": "Insira os endereços dos servidores, um por linha. <a>Saber mais</a> sobre a definição de servidores DNS primários.",
"upstream_dns_configured_in_file": "Configurado em {{path}}",
"test_upstream_btn": "Testar upstreams",
"upstreams": "Upstreams",
@@ -236,8 +236,8 @@
"query_log_retention_confirm": "Tem a certeza de que deseja alterar a retenção do registo de consulta? Se diminuir o valor do intervalo, alguns dados serão perdidos",
"anonymize_client_ip": "Tornar anônimo o IP do cliente",
"anonymize_client_ip_desc": "Não salva o endereço de IP completo do cliente em registros e estatísticas",
"dns_config": "Configuração do servidor DNS",
"dns_cache_config": "Configuração de cache DNS",
"dns_config": "Definição do servidor DNS",
"dns_cache_config": "Definição de cache DNS",
"dns_cache_config_desc": "Aqui você pode configurar o cache do DNS",
"blocking_mode": "Modo de bloqueio",
"default": "Padrão",
@@ -294,11 +294,11 @@
"install_devices_title": "Configure os seus dispositivos",
"install_devices_desc": "Para que o AdGuard Home comece a funcionar, precisa de configurar os seus dispositivos para o poder usar.",
"install_submit_title": "Parabéns!",
"install_submit_desc": "O procedimento de configuração está concluído e está pronto para começar a usar o AdGuard Home.",
"install_submit_desc": "O procedimento de definição está concluído e está pronto para começar a usar o AdGuard Home.",
"install_devices_router": "Router",
"install_devices_router_desc": "Esta configuração cobrirá automaticamente todos os dispositivos ligados ao seu router doméstico e não irá precisar de configurar cada um deles manualmente.",
"install_devices_router_desc": "Esta definição cobrirá automaticamente todos os dispositivos ligados ao seu router doméstico e não irá precisar de configurar cada um deles manualmente.",
"install_devices_address": "O servidor de DNS do AdGuard Home está a capturar os seguintes endereços",
"install_devices_router_list_1": "Abra as configurações do seu router. No navegador insira o IP do router, o padrão é (http://192.168.0.1/ ou http://192.168.1.1/), e o login e a palavra-passe é admin/admin; Se não se lembra da palavra-passe, pode redefinir a palavra-passe rapidamente pressionando um botão no próprio router. Alguns routers têm um aplicação específica que já deve estar instalada no seu computador/telefone.",
"install_devices_router_list_1": "Abra as configurações do seu router. No navegador insira o IP do router, o padrão é (http://192.168.0.1/ ou http://192.168.1.1/), e o login e a palavra-passe é admin/admin; Se não se lembra da palavra-passe, pode repor a palavra-passe rapidamente pressionando um botão no próprio router. Alguns routers têm um aplicação específica que já deve estar instalada no seu computador/telefone.",
"install_devices_router_list_2": "Encontre as configurações de DNS. Procure as letras DNS ao lado de um campo que permite dois ou três conjuntos de números, cada um dividido em quatro grupos de um a três números.",
"install_devices_router_list_3": "Insira aqui seu servidor do AdGuard Home.",
"install_devices_router_list_4": "Você não pode definir um servidor DNS personalizado em alguns tipos de roteadores. Nesse caso, pode ajudar se você configurar o AdGuard Home como um <0>servidor DHCP</0>. Caso contrário, você deve procurar o manual sobre como personalizar os servidores DNS para o seu modelo de roteador específico.",
@@ -327,7 +327,7 @@
"install_saved": "Guardado com sucesso",
"encryption_title": "Encriptação",
"encryption_desc": "Suporta a criptografia (HTTPS/TLS) para DNS e interface de administração web",
"encryption_config_saved": "Configuração de criptografia guardada",
"encryption_config_saved": "Definição de criptografia guardada",
"encryption_server": "Nome do servidor",
"encryption_server_enter": "Insira o seu nome de domínio",
"encryption_server_desc": "Para usar o protocolo HTTPS, precisa de inserir o nome do servidor que corresponde ao seu certificado SSL.",
@@ -355,14 +355,14 @@
"encryption_subject": "Assunto",
"encryption_issuer": "Emissor",
"encryption_hostnames": "Nomes dos servidores",
"encryption_reset": "Tem a certeza de que deseja redefinir a configuração de criptografia?",
"encryption_reset": "Tem a certeza de que deseja repor a definição de criptografia?",
"topline_expiring_certificate": "O seu certificado SSL está prestes a expirar. Actualize as suas <0>definições de criptografia</0>.",
"topline_expired_certificate": "O seu certificado SSL está expirado. Actualize as suas <0>definições de criptografia</0>.",
"form_error_port_range": "Digite um porta entre 80 e 65535",
"form_error_port_unsafe": "Esta porta não é segura",
"form_error_equal": "Não deve ser igual",
"form_error_password": "As palavras-passe não coincidem",
"reset_settings": "Redefinir configurações",
"reset_settings": "Repor configurações",
"update_announcement": "AdGuard Home {{version}} está disponível!<0>Clique aqui</0> para mais informações.",
"setup_guide": "Guia de instalação",
"dns_addresses": "Endereços DNS",
@@ -401,7 +401,7 @@
"client_confirm_delete": "Tem a certeza de que deseja excluir o cliente \"{{key}}\"?",
"list_confirm_delete": "Você tem certeza de que deseja excluir essa lista?",
"auto_clients_title": "Clientes (tempo de execução)",
"auto_clients_desc": "Dados dos clientes que usam o AdGuard Home, que não são armazenados na configuração",
"auto_clients_desc": "Dados dos clientes que usam o AdGuard Home, que não são armazenados na definição",
"access_title": "Configurações de acesso",
"access_desc": "Aqui pode configurar as regras de acesso para o servidores de DNS do AdGuard Home.",
"access_allowed_title": "Clientes permitidos",
@@ -423,7 +423,7 @@
"setup_dns_privacy_android_2": "O <0>AdGuard para Android</0> suporta <1>DNS-sobre-HTTPS</1> e <1>DNS-sobre-TLS</1>.",
"setup_dns_privacy_android_3": "<0>Intra</0> adiciona o suporte <1>DNS-sobre-HTTPS</1> para o Android.",
"setup_dns_privacy_ios_1": "<0>DNSCloak</0> suporta <1>DNS-sobre-HTTPS</1>, mas para o configurar para usar o seu próprio servidor, precisará de gerar um <2>DNS Stamp</2>.",
"setup_dns_privacy_ios_2": "O <0>AdGuard para iOS</0> suporta a configuração do <1>DNS-sobre-HTTPS</1> e <1>DNS-sobre-TLS</1>.",
"setup_dns_privacy_ios_2": "O <0>AdGuard para iOS</0> suporta a definição do <1>DNS-sobre-HTTPS</1> e <1>DNS-sobre-TLS</1>.",
"setup_dns_privacy_other_title": "Outras implementações",
"setup_dns_privacy_other_1": "O próprio AdGuard Home pode ser usado como um cliente DNS seguro em qualquer plataforma.",
"setup_dns_privacy_other_2": "<0>dnsproxy</0> suporta todos os protocolos de DNS seguros conhecidos.",
@@ -460,8 +460,8 @@
"encryption_certificates_source_content": "Colar o conteúdo dos certificados",
"encryption_key_source_path": "Definir um arquivo de chave privada",
"encryption_key_source_content": "Colar o conteúdo da chave privada",
"stats_params": "Configuração de estatísticas",
"config_successfully_saved": "Configuração guardada com sucesso",
"stats_params": "Definição de estatísticas",
"config_successfully_saved": "Definição guardada com sucesso",
"interval_24_hour": "24 horas",
"interval_days": "{{count}} dias",
"interval_days_plural": "{{count}} dias",
@@ -470,7 +470,7 @@
"filter_added_successfully": "O filtro foi adicionado com sucesso",
"filter_removed_successfully": "A lista foi removida com sucesso",
"filter_updated": "O filtro atualizado com sucesso",
"statistics_configuration": "Configuração das estatísticas",
"statistics_configuration": "Definição das estatísticas",
"statistics_retention": "Retenção de estatísticas",
"statistics_retention_desc": "Se diminuir o valor do intervalo, alguns dados serão perdidos",
"statistics_clear": " Limpar estatísticas",
@@ -479,7 +479,7 @@
"statistics_cleared": "As estatísticas foram apagadas com sucesso",
"interval_hours": "{{count}} hora",
"interval_hours_plural": "{{count}} horas",
"filters_configuration": "Configuração dos filtros",
"filters_configuration": "Definição dos filtros",
"filters_enable": "Activar filtros",
"filters_interval": "Intervalo de actualização de filtros",
"disabled": "Desactivado",
@@ -576,11 +576,11 @@
"filter_category_security": "Segurança",
"filter_category_regional": "Regional",
"filter_category_other": "Outro",
"filter_category_general_desc": "Listas que bloqueiam o rastreamento e a publicidade na maioria dos dispositivos",
"filter_category_general_desc": "Listas que bloqueiam o monitorização e a publicidade na maioria dos dispositivos",
"filter_category_security_desc": "Listas especializadas em bloquear domínios de malware, phishing ou fraude",
"filter_category_regional_desc": "Listas focadas em anúncios regionais e servidores de rastreamento",
"filter_category_regional_desc": "Listas focadas em anúncios regionais e servidores de monitorização",
"filter_category_other_desc": "Outras listas negras",
"setup_config_to_enable_dhcp_server": "Configure a configuração para habilitar o servidor DHCP",
"setup_config_to_enable_dhcp_server": "Defina a definição para habilitar o servidor DHCP",
"original_response": "Resposta original",
"click_to_view_queries": "Clique para ver as consultas",
"port_53_faq_link": "A porta 53 é frequentemente ocupada por serviços \"DNSStubListener\" ou \"systemd-resolved\". Por favor leia <0>essa instrução</0> para resolver isso.",

View File

@@ -87,7 +87,7 @@
"refresh_statics": "İstatistikleri yenile",
"dns_query": "DNS Sorguları",
"blocked_by": "<0>Filtreler tarafından engellendi</0>",
"stats_malware_phishing": "Zararlı yazılım/kimlik hırsızlığı engellendi",
"stats_malware_phishing": "Kötü amaçlı yazılım/kimlik avı engellendi",
"stats_adult": "Yetişkin içerikli site engellendi",
"stats_query_domain": "En fazla sorgulanan alan adları",
"for_last_24_hours": "son 24 saat içindekiler",

View File

@@ -264,7 +264,7 @@
"blocking_mode_nxdomain": "不存在的網域NXDOMAIN以 NXDOMAIN 碼回覆",
"blocking_mode_null_ip": "無效的 IP以零值 IP 位址0.0.0.0 供 A:: 供 AAAA回覆",
"blocking_mode_custom_ip": "自訂的 IP以一組手動地被設定的 IP 位址回覆",
"upstream_dns_client_desc": "如果您將此欄位留空AdGuard Home 將在 <0>DNS 設定</0>中使用被配置的伺服器。",
"upstream_dns_client_desc": "如果您將此欄位留空AdGuard Home 將使用在 <0>DNS 設定</0>中被配置的伺服器。",
"tracker_source": "追蹤器來源",
"source_label": "來源",
"found_in_known_domain_db": "在已知的域名資料庫中被發現。",

View File

@@ -51,9 +51,10 @@ export const toggleClientBlockSuccess = createAction('TOGGLE_CLIENT_BLOCK_SUCCES
export const toggleClientBlock = (ip, disallowed, disallowed_rule) => async (dispatch) => {
dispatch(toggleClientBlockRequest());
try {
const {
allowed_clients, blocked_hosts, disallowed_clients = [],
} = await apiClient.getAccessList();
const accessList = await apiClient.getAccessList();
const allowed_clients = accessList.allowed_clients ?? [];
const blocked_hosts = accessList.blocked_hosts ?? [];
const disallowed_clients = accessList.disallowed_clients ?? [];
const updatedDisallowedClients = disallowed
? disallowed_clients.filter((client) => client !== disallowed_rule)

View File

@@ -373,10 +373,14 @@ export const getDhcpStatusFailure = createAction('GET_DHCP_STATUS_FAILURE');
export const getDhcpStatus = () => async (dispatch) => {
dispatch(getDhcpStatusRequest());
try {
const status = await apiClient.getDhcpStatus();
const globalStatus = await apiClient.getGlobalStatus();
status.dhcp_available = globalStatus.dhcp_available;
dispatch(getDhcpStatusSuccess(status));
if (globalStatus.dhcp_available) {
const status = await apiClient.getDhcpStatus();
status.dhcp_available = globalStatus.dhcp_available;
dispatch(getDhcpStatusSuccess(status));
} else {
dispatch(getDhcpStatusFailure());
}
} catch (error) {
dispatch(addErrorToast({ error }));
dispatch(getDhcpStatusFailure());

View File

@@ -22,11 +22,6 @@
border-bottom: 6px solid #585965;
}
.card-chart-bg {
left: -20px;
width: calc(100% + 20px);
}
@media (max-width: 1279.98px) {
.table__action {
position: absolute;

View File

@@ -12,6 +12,7 @@
--gray-4d: #4D4D4D;
--gray-f3: #F3F3F3;
--gray-8: #888;
--gray-3: #333;
--danger: #DF3812;
--white80: rgba(255, 255, 255, 0.8);

View File

@@ -72,30 +72,30 @@ const Interfaces = () => {
(store) => store.form[FORM_NAME.DHCP_INTERFACES]?.values?.interface_name,
);
if (processingInterfaces || !interfaces) {
return null;
}
const interfaceValue = interface_name && interfaces[interface_name];
return !processingInterfaces
&& interfaces
&& <>
<div className="row dhcp__interfaces">
<div className="col col__dhcp">
<Field
name="interface_name"
component={renderSelectField}
className="form-control custom-select pl-4 col-md"
validate={[validateRequiredValue]}
label='dhcp_interface_select'
>
<option value='' disabled={enabled}>
{t('dhcp_interface_select')}
</option>
{renderInterfaces(interfaces)}
</Field>
</div>
{interfaceValue
&& renderInterfaceValues(interfaceValue)}
</div>
</>;
return <div className="row dhcp__interfaces">
<div className="col col__dhcp">
<Field
name="interface_name"
component={renderSelectField}
className="form-control custom-select pl-4 col-md"
validate={[validateRequiredValue]}
label='dhcp_interface_select'
>
<option value='' disabled={enabled}>
{t('dhcp_interface_select')}
</option>
{renderInterfaces(interfaces)}
</Field>
</div>
{interfaceValue
&& renderInterfaceValues(interfaceValue)}
</div>;
};
renderInterfaceValues.propTypes = {

View File

@@ -65,9 +65,14 @@ const Dhcp = () => {
useEffect(() => {
dispatch(getDhcpStatus());
dispatch(getDhcpInterfaces());
}, []);
useEffect(() => {
if (dhcp_available) {
dispatch(getDhcpInterfaces());
}
}, [dhcp_available]);
useEffect(() => {
const [ipv4] = interfaces?.[interface_name]?.ipv4_addresses ?? [];
const [ipv6] = interfaces?.[interface_name]?.ipv6_addresses ?? [];

View File

@@ -80,7 +80,6 @@
.card-body-stats {
position: relative;
flex: 1 1 auto;
height: calc(100% - 3rem);
margin: 0;
padding: 1rem 1.5rem;
}

View File

@@ -1,9 +1,16 @@
.line__tooltip {
padding: 2px 10px 7px;
line-height: 1.1;
color: #fff;
color: var(--white);
background-color: var(--gray-3);
border-radius: 4px;
opacity: 90%;
}
.line__tooltip-text {
font-size: 0.7rem;
}
.card-chart-bg path[d^="M0,32"] {
transform: translateY(32px);
}

View File

@@ -1,56 +1,75 @@
import React from 'react';
import PropTypes from 'prop-types';
import { ResponsiveLine } from '@nivo/line';
import addDays from 'date-fns/add_days';
import addHours from 'date-fns/add_hours';
import subDays from 'date-fns/sub_days';
import subHours from 'date-fns/sub_hours';
import dateFormat from 'date-fns/format';
import round from 'lodash/round';
import { useSelector } from 'react-redux';
import PropTypes from 'prop-types';
import './Line.css';
const Line = ({ data, color }) => data
&& <ResponsiveLine
const Line = ({
data, color = 'black',
}) => {
const interval = useSelector((state) => state.stats.interval);
return <ResponsiveLine
enableArea
animate
enableSlices="x"
curve="linear"
colors={[color]}
data={data}
margin={{
top: data[0].data.every(({ y }) => y === 0) ? 62 : 15,
right: 0,
bottom: 1,
left: 20,
}}
minY="auto"
stacked={false}
curve='linear'
axisBottom={null}
axisLeft={null}
enableGridX={false}
enableGridY={false}
enableDots={false}
enableArea={true}
animate={false}
colorBy={() => (color)}
tooltip={(slice) => (
<div>
{slice.data.map((d) => (
<div key={d.serie.id} className="line__tooltip">
<span className="line__tooltip-text">
<strong>{d.data.y}</strong>
<br />
<small>{d.data.x}</small>
</span>
</div>
))}
</div>
)}
theme={{
tooltip: {
container: {
padding: '0',
background: '#333',
borderRadius: '4px',
crosshair: {
line: {
stroke: 'black',
strokeWidth: 1,
strokeOpacity: 0.35,
},
},
}}
xScale={{
type: 'linear',
min: 0,
max: 'auto',
}}
crosshairType="x"
axisLeft={false}
axisBottom={false}
enableGridX={false}
enableGridY={false}
enablePoints={false}
xFormat={(x) => {
if (interval === 1 || interval === 7) {
const hoursAgo = subHours(Date.now(), 24 * interval);
return dateFormat(addHours(hoursAgo, x), 'D MMM HH:00');
}
const daysAgo = subDays(Date.now(), interval - 1);
return dateFormat(addDays(daysAgo, x), 'D MMM YYYY');
}}
yFormat={(y) => round(y, 2)}
sliceTooltip={(slice) => {
const { xFormatted, yFormatted } = slice.slice.points[0].data;
return <div className="line__tooltip">
<span className="line__tooltip-text">
<strong>{yFormatted}</strong>
<br />
<small>{xFormatted}</small>
</span>
</div>;
}}
/>;
};
Line.propTypes = {
data: PropTypes.array.isRequired,
color: PropTypes.string.isRequired,
color: PropTypes.string,
width: PropTypes.number,
height: PropTypes.number,
};
export default Line;

View File

@@ -13452,10 +13452,8 @@ a.icon:hover {
.card-chart-bg {
height: 4rem;
margin-top: -1rem;
position: relative;
z-index: 1;
overflow: hidden;
}
.card-options {

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

@@ -1,10 +1,6 @@
import 'url-polyfill';
import dateParse from 'date-fns/parse';
import dateFormat from 'date-fns/format';
import subHours from 'date-fns/sub_hours';
import addHours from 'date-fns/add_hours';
import addDays from 'date-fns/add_days';
import subDays from 'date-fns/sub_days';
import round from 'lodash/round';
import axios from 'axios';
import i18n from 'i18next';
@@ -105,21 +101,10 @@ export const normalizeLogs = (logs) => logs.map((log) => {
};
});
export const normalizeHistory = (history, interval) => {
if (interval === 1 || interval === 7) {
const hoursAgo = subHours(Date.now(), 24 * interval);
return history.map((item, index) => ({
x: dateFormat(addHours(hoursAgo, index), 'D MMM HH:00'),
y: round(item, 2),
}));
}
const daysAgo = subDays(Date.now(), interval - 1);
return history.map((item, index) => ({
x: dateFormat(addDays(daysAgo, index), 'D MMM YYYY'),
y: round(item, 2),
}));
};
export const normalizeHistory = (history) => history.map((item, idx) => ({
x: idx,
y: item,
}));
export const normalizeTopStats = (stats) => (
stats.map((item) => ({

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) => {

View File

@@ -44,7 +44,6 @@ const getDevServerConfig = (proxyUrl = BASE_URL) => {
proxy: {
[proxyUrl]: `http://${devServerHost}:${port}`,
},
open: true,
};
};

View File

@@ -1,215 +0,0 @@
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package dhcpd
import (
"bytes"
"fmt"
"net"
"os"
"runtime"
"time"
"github.com/AdguardTeam/AdGuardHome/dhcpd/nclient4"
"github.com/AdguardTeam/golibs/log"
"github.com/insomniacslk/dhcp/dhcpv4"
"github.com/insomniacslk/dhcp/dhcpv6"
"github.com/insomniacslk/dhcp/dhcpv6/nclient6"
"github.com/insomniacslk/dhcp/iana"
)
// CheckIfOtherDHCPServersPresentV4 sends a DHCP request to the specified network interface,
// and waits for a response for a period defined by defaultDiscoverTime
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)
}
// get ipv4 address of an interface
ifaceIPNet := getIfaceIPv4(*iface)
if len(ifaceIPNet) == 0 {
return false, fmt.Errorf("couldn't find IPv4 address of interface %s %+v", ifaceName, iface)
}
if runtime.GOOS == "darwin" {
return false, fmt.Errorf("can't find DHCP server: not supported on macOS")
}
srcIP := ifaceIPNet[0]
src := net.JoinHostPort(srcIP.String(), "68")
dst := "255.255.255.255:67"
hostname, _ := os.Hostname()
req, err := dhcpv4.NewDiscovery(iface.HardwareAddr)
if err != nil {
return false, fmt.Errorf("dhcpv4.NewDiscovery: %s", err)
}
req.Options.Update(dhcpv4.OptClientIdentifier(iface.HardwareAddr))
req.Options.Update(dhcpv4.OptHostName(hostname))
// 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)
}
if !udpAddr.IP.To4().Equal(srcIP) {
return false, wrapErrPrint(err, "Resolved UDP address is not %s", src)
}
// 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)
}
// 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")
}
if c != nil {
defer c.Close()
}
// 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)
}
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)
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
}
log.Tracef("The packet is from an active DHCP server")
// that's a DHCP server there
return true, 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)
}
ifaceIPNet := getIfaceIPv6(*iface)
if len(ifaceIPNet) == 0 {
return false, fmt.Errorf("DHCPv6: couldn't find IPv6 address of interface %s %+v", ifaceName, iface)
}
srcIP := ifaceIPNet[0]
src := net.JoinHostPort(srcIP.String(), "546")
dst := "[ff02::1:2]:547"
req, err := dhcpv6.NewSolicit(iface.HardwareAddr)
if err != nil {
return false, fmt.Errorf("DHCPv6: dhcpv6.NewSolicit: %s", err)
}
udpAddr, err := net.ResolveUDPAddr("udp6", src)
if err != nil {
return false, wrapErrPrint(err, "DHCPv6: Couldn't resolve UDP address %s", src)
}
if !udpAddr.IP.To16().Equal(srcIP) {
return false, wrapErrPrint(err, "DHCPv6: Resolved UDP address is not %s", src)
}
dstAddr, err := net.ResolveUDPAddr("udp6", dst)
if err != nil {
return false, fmt.Errorf("DHCPv6: Couldn't resolve UDP address %s: %s", 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)
}
if c != nil {
defer c.Close()
}
_, err = c.WriteTo(req.ToBytes(), dstAddr)
if err != nil {
return false, fmt.Errorf("DHCPv6: Couldn't send a packet to %s: %s", dst, err)
}
for {
log.Debug("DHCPv6: Waiting %v for an answer", defaultDiscoverTime)
b := make([]byte, 4096)
_ = c.SetReadDeadline(time.Now().Add(defaultDiscoverTime))
n, _, err := c.ReadFrom(b)
if isTimeout(err) {
log.Debug("DHCPv6: didn't receive DHCP response")
return false, nil
}
if err != nil {
return false, wrapErrPrint(err, "Couldn't receive packet")
}
log.Debug("DHCPv6: Received packet (%v bytes)", n)
resp, err := dhcpv6.FromBytes(b[:n])
if err != nil {
log.Debug("DHCPv6: dhcpv6.FromBytes: %s", err)
continue
}
log.Debug("DHCPv6: received message from server: %s", resp.Summary())
cid := req.Options.ClientID()
msg, err := resp.GetInnerMessage()
if err != nil {
log.Debug("DHCPv6: resp.GetInnerMessage: %s", err)
continue
}
rcid := msg.Options.ClientID()
if resp.Type() == dhcpv6.MessageTypeAdvertise &&
msg.TransactionID == req.TransactionID &&
rcid != nil &&
cid.Equal(*rcid) {
log.Debug("DHCPv6: The packet is from an active DHCP server")
return true, nil
}
log.Debug("DHCPv6: received message from server doesn't match our request")
}
}

25
go.mod
View File

@@ -3,8 +3,8 @@ module github.com/AdguardTeam/AdGuardHome
go 1.14
require (
github.com/AdguardTeam/dnsproxy v0.32.6
github.com/AdguardTeam/golibs v0.4.2
github.com/AdguardTeam/dnsproxy v0.33.2
github.com/AdguardTeam/golibs v0.4.3
github.com/AdguardTeam/urlfilter v0.12.3
github.com/NYTimes/gziphandler v1.1.1
github.com/beefsack/go-rate v0.0.0-20200827232406-6cde80facd47 // indirect
@@ -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
)

54
go.sum
View File

@@ -7,11 +7,13 @@ 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.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=
github.com/AdguardTeam/golibs v0.4.3 h1:nXTLLLlIyU4BSRF0An5azS0uimSK/YpIMOBAO0/v1RY=
github.com/AdguardTeam/golibs v0.4.3/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
github.com/AdguardTeam/gomitmproxy v0.2.0/go.mod h1:Qdv0Mktnzer5zpdpi5rAwixNJzW2FN91LjKJCkVbYGU=
github.com/AdguardTeam/urlfilter v0.12.3 h1:FMjQG0eTgrr8xA3z2zaLVcCgGdpzoECPGWwgPjtwPNs=
github.com/AdguardTeam/urlfilter v0.12.3/go.mod h1:1fcCQx5TGJANrQN6sHNNM9KPBl7qx7BJml45ko6vru0=
@@ -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,9 @@ 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-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 +340,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 +366,10 @@ 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-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 +377,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 +395,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 +448,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,78 @@
package agherr
import (
"errors"
"fmt"
"testing"
"github.com/AdguardTeam/AdGuardHome/internal/testutil"
"github.com/stretchr/testify/assert"
)
func TestMain(m *testing.M) {
testutil.DiscardLogOutput(m)
}
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("err: %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

@@ -0,0 +1,284 @@
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package dhcpd
import (
"bytes"
"fmt"
"net"
"os"
"runtime"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd/nclient4"
"github.com/AdguardTeam/golibs/log"
"github.com/insomniacslk/dhcp/dhcpv4"
"github.com/insomniacslk/dhcp/dhcpv6"
"github.com/insomniacslk/dhcp/dhcpv6/nclient6"
"github.com/insomniacslk/dhcp/iana"
)
// CheckIfOtherDHCPServersPresentV4 sends a DHCP request to the specified network interface,
// and waits for a response for a period defined by defaultDiscoverTime
func CheckIfOtherDHCPServersPresentV4(ifaceName string) (bool, error) {
iface, err := net.InterfaceByName(ifaceName)
if err != nil {
return false, fmt.Errorf("couldn't find interface by name %s: %w", ifaceName, err)
}
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("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")
}
srcIP := ifaceIPNet[0]
src := net.JoinHostPort(srcIP.String(), "68")
dst := "255.255.255.255:67"
hostname, _ := os.Hostname()
req, err := dhcpv4.NewDiscovery(iface.HardwareAddr)
if err != nil {
return false, fmt.Errorf("dhcpv4.NewDiscovery: %w", err)
}
req.Options.Update(dhcpv4.OptClientIdentifier(iface.HardwareAddr))
req.Options.Update(dhcpv4.OptHostName(hostname))
// resolve 0.0.0.0:68
udpAddr, err := net.ResolveUDPAddr("udp4", src)
if err != nil {
return false, fmt.Errorf("couldn't resolve UDP address %s: %w", src, err)
}
if !udpAddr.IP.To4().Equal(srcIP) {
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, 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, fmt.Errorf("couldn't listen on :68: %w", err)
}
if c != nil {
defer c.Close()
}
// send to 255.255.255.255:67
_, err = c.WriteTo(req.ToBytes(), dstAddr)
if err != nil {
return false, fmt.Errorf("couldn't send a packet to %s: %w", dst, err)
}
for {
ok, next, err := tryConn4(req, c, iface)
if next {
if err != nil {
log.Debug("dhcpv4: trying a connection: %s", err)
}
continue
}
if ok {
return true, nil
}
if err != nil {
return false, err
}
}
}
// TODO(a.garipov): Refactor further. Inspect error handling, remove parameter
// next, address the TODO, merge with tryConn6, etc.
func tryConn4(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("dhcpv4: waiting %v for an answer", defaultDiscoverTime)
b := make([]byte, 1500)
err = c.SetDeadline(time.Now().Add(defaultDiscoverTime))
if err != nil {
return false, false, fmt.Errorf("setting deadline: %w", err)
}
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("dhcpv4: 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("dhcpv4: 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: %w", ifaceName, err)
}
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("interface %s has no ipv6 addresses", ifaceName)
}
srcIP := ifaceIPNet[0]
src := net.JoinHostPort(srcIP.String(), "546")
dst := "[ff02::1:2]:547"
req, err := dhcpv6.NewSolicit(iface.HardwareAddr)
if err != nil {
return false, fmt.Errorf("dhcpv6: dhcpv6.NewSolicit: %w", err)
}
udpAddr, err := net.ResolveUDPAddr("udp6", src)
if err != nil {
return false, fmt.Errorf("dhcpv6: Couldn't resolve UDP address %s: %w", src, err)
}
if !udpAddr.IP.To16().Equal(srcIP) {
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: %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: %w", err)
}
if c != nil {
defer c.Close()
}
_, err = c.WriteTo(req.ToBytes(), dstAddr)
if err != nil {
return false, fmt.Errorf("dhcpv6: Couldn't send a packet to %s: %w", dst, err)
}
for {
ok, next, err := tryConn6(req, c)
if next {
if err != nil {
log.Debug("dhcpv6: trying a connection: %s", err)
}
continue
}
if ok {
return true, nil
}
if err != nil {
return false, err
}
}
}
// TODO(a.garipov): See the comment on tryConn4. Sigh…
func tryConn6(req *dhcpv6.Message, c net.PacketConn) (ok, next bool, err error) {
// TODO: replicate dhclient's behavior of retrying several times with
// progressively longer timeouts.
log.Tracef("dhcpv6: waiting %v for an answer", defaultDiscoverTime)
b := make([]byte, 4096)
err = c.SetDeadline(time.Now().Add(defaultDiscoverTime))
if err != nil {
return false, false, fmt.Errorf("setting deadline: %w", err)
}
n, _, err := c.ReadFrom(b)
if err != nil {
if isTimeout(err) {
log.Debug("dhcpv6: didn't receive dhcp response")
return false, false, nil
}
return false, false, fmt.Errorf("receiving packet: %w", err)
}
log.Tracef("dhcpv6: received packet, %d bytes", n)
response, err := dhcpv6.FromBytes(b[:n])
if err != nil {
log.Debug("dhcpv6: encoding: %s", err)
return false, true, err
}
log.Debug("dhcpv6: received message from server: %s", response.Summary())
cid := req.Options.ClientID()
msg, err := response.GetInnerMessage()
if err != nil {
log.Debug("dhcpv6: resp.GetInnerMessage(): %s", err)
return false, true, err
}
rcid := msg.Options.ClientID()
if !(response.Type() == dhcpv6.MessageTypeAdvertise &&
msg.TransactionID == req.TransactionID &&
rcid != nil &&
cid.Equal(*rcid)) {
log.Debug("dhcpv6: received message from server doesn't match our request")
return false, true, nil
}
log.Tracef("dhcpv6: the packet is from an active dhcp server")
return true, false, nil
}

View File

@@ -1,3 +1,4 @@
// Package dhcpd provides a DHCP server.
package dhcpd
import (
@@ -5,16 +6,19 @@ import (
"net"
"net/http"
"path/filepath"
"runtime"
"strconv"
"strings"
"time"
"github.com/AdguardTeam/AdGuardHome/util"
"github.com/AdguardTeam/AdGuardHome/internal/util"
"github.com/AdguardTeam/golibs/log"
)
const defaultDiscoverTime = time.Second * 3
const leaseExpireStatic = 1
const (
defaultDiscoverTime = time.Second * 3
leaseExpireStatic = 1
)
var webHandlersRegistered = false
@@ -82,7 +86,8 @@ func (s *Server) CheckConfig(config ServerConfig) error {
// Create - create object
func Create(config ServerConfig) *Server {
s := Server{}
s := &Server{}
s.conf.Enabled = config.Enabled
s.conf.InterfaceName = config.InterfaceName
s.conf.HTTPRegister = config.HTTPRegister
@@ -90,8 +95,21 @@ func Create(config ServerConfig) *Server {
s.conf.DBFilePath = filepath.Join(config.WorkDir, dbFilename)
if !webHandlersRegistered && s.conf.HTTPRegister != nil {
if runtime.GOOS == "windows" {
// Our DHCP server doesn't work on Windows yet, so
// signal that to the front with an HTTP 501.
//
// TODO(a.garipov): This needs refactoring. We
// shouldn't even try and initialize a DHCP server on
// Windows, but there are currently too many
// interconnected parts--such as HTTP handlers and
// frontend--to make that work properly.
s.registerNotImplementedHandlers()
} else {
s.registerHandlers()
}
webHandlersRegistered = true
s.registerHandlers()
}
var err4, err6 error
@@ -130,7 +148,7 @@ func Create(config ServerConfig) *Server {
// we can't delay database loading until DHCP server is started,
// because we need static leases functionality available beforehand
s.dbLoad()
return &s
return s
}
// server calls this function after DB is updated

View File

@@ -9,13 +9,12 @@ import (
"testing"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/testutil"
"github.com/stretchr/testify/assert"
)
func check(t *testing.T, result bool, msg string) {
if !result {
t.Fatal(msg)
}
func TestMain(m *testing.M) {
testutil.DiscardLogOutput(m)
}
func testNotify(flags uint32) {
@@ -83,7 +82,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 +98,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

@@ -10,8 +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 +174,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 +301,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 +334,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 +369,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 +422,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 {
@@ -501,11 +498,48 @@ func (s *Server) handleReset(w http.ResponseWriter, r *http.Request) {
}
func (s *Server) registerHandlers() {
s.conf.HTTPRegister("GET", "/control/dhcp/status", s.handleDHCPStatus)
s.conf.HTTPRegister("GET", "/control/dhcp/interfaces", s.handleDHCPInterfaces)
s.conf.HTTPRegister("POST", "/control/dhcp/set_config", s.handleDHCPSetConfig)
s.conf.HTTPRegister("POST", "/control/dhcp/find_active_dhcp", s.handleDHCPFindActiveServer)
s.conf.HTTPRegister("POST", "/control/dhcp/add_static_lease", s.handleDHCPAddStaticLease)
s.conf.HTTPRegister("POST", "/control/dhcp/remove_static_lease", s.handleDHCPRemoveStaticLease)
s.conf.HTTPRegister("POST", "/control/dhcp/reset", s.handleReset)
s.conf.HTTPRegister(http.MethodGet, "/control/dhcp/status", s.handleDHCPStatus)
s.conf.HTTPRegister(http.MethodGet, "/control/dhcp/interfaces", s.handleDHCPInterfaces)
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/set_config", s.handleDHCPSetConfig)
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/find_active_dhcp", s.handleDHCPFindActiveServer)
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/add_static_lease", s.handleDHCPAddStaticLease)
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/remove_static_lease", s.handleDHCPRemoveStaticLease)
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/reset", s.handleReset)
}
// jsonError is a generic JSON error response.
type jsonError struct {
// Message is the error message, an opaque string.
Message string `json:"message"`
}
// notImplemented returns a handler that replies to any request with an HTTP 501
// Not Implemented status and a JSON error with the provided message msg.
//
// TODO(a.garipov): Either take the logger from the server after we've
// refactored logging or make this not a method of *Server.
func (s *Server) notImplemented(msg string) (f func(http.ResponseWriter, *http.Request)) {
return func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusNotImplemented)
err := json.NewEncoder(w).Encode(&jsonError{
Message: msg,
})
if err != nil {
log.Debug("writing 501 json response: %s", err)
}
}
}
func (s *Server) registerNotImplementedHandlers() {
h := s.notImplemented("dhcp is not supported on windows")
s.conf.HTTPRegister(http.MethodGet, "/control/dhcp/status", h)
s.conf.HTTPRegister(http.MethodGet, "/control/dhcp/interfaces", h)
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/set_config", h)
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/find_active_dhcp", h)
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/add_static_lease", h)
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/remove_static_lease", h)
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/reset", h)
}

View File

@@ -0,0 +1,22 @@
package dhcpd
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
)
func TestServer_notImplemented(t *testing.T) {
s := &Server{}
h := s.notImplemented("never!")
w := httptest.NewRecorder()
r, err := http.NewRequest(http.MethodGet, "/unsupported", nil)
assert.Nil(t, err)
h(w, r)
assert.Equal(t, http.StatusNotImplemented, w.Code)
assert.Equal(t, `{"message":"never!"}`+"\n", w.Body.String())
}

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

@@ -17,11 +17,16 @@ import (
"testing"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/testutil"
"github.com/hugelgupf/socketpair"
"github.com/insomniacslk/dhcp/dhcpv4"
"github.com/insomniacslk/dhcp/dhcpv4/server4"
)
func TestMain(m *testing.M) {
testutil.DiscardLogOutput(m)
}
type handler struct {
mu sync.Mutex
received []*dhcpv4.DHCPv4
@@ -122,6 +127,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,14 +10,15 @@ import (
"runtime"
"strings"
"github.com/AdguardTeam/AdGuardHome/util"
"github.com/AdguardTeam/AdGuardHome/internal/util"
"github.com/AdguardTeam/golibs/file"
"github.com/AdguardTeam/golibs/log"
)
// Check if network interface has a static IP configured
// HasStaticIP check if the network interface has a static IP configured
//
// Supports: Raspbian.
func HasStaticIP(ifaceName string) (bool, error) {
if runtime.GOOS == "linux" {
@@ -36,7 +37,7 @@ func HasStaticIP(ifaceName string) (bool, error) {
return false, fmt.Errorf("cannot check if IP is static: not supported on %s", runtime.GOOS)
}
// Set a static IP for the specified network interface
// SetStaticIP sets a static IP for the network interface.
func SetStaticIP(ifaceName string) error {
if runtime.GOOS == "linux" {
return setStaticIPDhcpdConf(ifaceName)
@@ -73,7 +74,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 +240,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

@@ -1,18 +1,23 @@
package dnsfilter
import (
"bytes"
"fmt"
"net"
"os"
"path"
"runtime"
"strings"
"testing"
"github.com/AdguardTeam/AdGuardHome/internal/testutil"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/urlfilter/rules"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
)
func TestMain(m *testing.M) {
testutil.DiscardLogOutput(m)
}
var setts RequestFilteringSettings
// HELPERS
@@ -36,13 +41,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 +69,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 +105,7 @@ func TestEtcHostsMatching(t *testing.T) {
::1 host2
`,
addr, addr6)
filters := []Filter{Filter{
filters := []Filter{{
ID: 0, Data: []byte(text),
}}
d := NewForTest(nil, filters)
@@ -147,10 +145,17 @@ func TestEtcHostsMatching(t *testing.T) {
// SAFE BROWSING
func TestSafeBrowsing(t *testing.T) {
logOutput := &bytes.Buffer{}
testutil.ReplaceLogWriter(t, logOutput)
testutil.ReplaceLogLevel(t, log.DEBUG)
d := NewForTest(&Config{SafeBrowsingEnabled: true}, nil)
defer d.Close()
gctx.stats.Safebrowsing.Requests = 0
d.checkMatch(t, "wmconvirus.narod.ru")
assert.True(t, strings.Contains(logOutput.String(), "SafeBrowsing lookup for wmconvirus.narod.ru"))
d.checkMatch(t, "test.wmconvirus.narod.ru")
d.checkMatchEmpty(t, "yandex.ru")
d.checkMatchEmpty(t, "pornhub.com")
@@ -300,7 +305,6 @@ func TestSafeSearchCacheGoogle(t *testing.T) {
t.Fatalf("Failed to lookup for %s", safeDomain)
}
t.Logf("IP addresses: %v", ips)
ip := ips[0]
for _, i := range ips {
if i.To4() != nil {
@@ -334,9 +338,14 @@ func TestSafeSearchCacheGoogle(t *testing.T) {
// PARENTAL
func TestParentalControl(t *testing.T) {
logOutput := &bytes.Buffer{}
testutil.ReplaceLogWriter(t, logOutput)
testutil.ReplaceLogLevel(t, log.DEBUG)
d := NewForTest(&Config{ParentalEnabled: true}, nil)
defer d.Close()
d.checkMatch(t, "pornhub.com")
assert.True(t, strings.Contains(logOutput.String(), "Parental lookup for pornhub.com"))
d.checkMatch(t, "www.pornhub.com")
d.checkMatchEmpty(t, "www.yandex.ru")
d.checkMatchEmpty(t, "yandex.ru")
@@ -351,11 +360,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 +419,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 +443,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 +468,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 +488,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 +544,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

@@ -5,7 +5,9 @@ import (
"strings"
"testing"
"github.com/AdguardTeam/AdGuardHome/internal/agherr"
"github.com/AdguardTeam/golibs/cache"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
)
@@ -23,16 +25,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) {
@@ -88,4 +90,47 @@ func TestSafeBrowsingCache(t *testing.T) {
hash = sha256.Sum256([]byte("nonexisting.com"))
_, ok = c.hashToHost[hash]
assert.True(t, ok)
c = &sbCtx{
svc: "SafeBrowsing",
cacheTime: 100,
}
conf = cache.Config{}
c.cache = cache.New(conf)
hash = sha256.Sum256([]byte("sub.host.com"))
c.hashToHost = make(map[[32]byte]string)
c.hashToHost[hash] = "sub.host.com"
c.cache.Set(hash[0:2], make([]byte, 32))
assert.Equal(t, 0, c.getCached())
}
// testErrUpstream implements upstream.Upstream interface for replacing real
// upstream in tests.
type testErrUpstream struct{}
// Exchange always returns nil Msg and non-nil error.
func (teu *testErrUpstream) Exchange(*dns.Msg) (*dns.Msg, error) {
return nil, agherr.Error("bad")
}
func (teu *testErrUpstream) Address() string {
return ""
}
func TestSBPC_checkErrorUpstream(t *testing.T) {
d := NewForTest(&Config{SafeBrowsingEnabled: true}, nil)
defer d.Close()
ups := &testErrUpstream{}
d.safeBrowsingUpstream = ups
d.parentalUpstream = ups
_, err := d.checkSafeBrowsing("smthng.com")
assert.NotNil(t, err)
_, err = d.checkParental("smthng.com")
assert.NotNil(t, err)
}

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

@@ -0,0 +1,170 @@
package dnsforward
import (
"io/ioutil"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestDNSForwardHTTTP_handleGetConfig(t *testing.T) {
s := createTestServer(t)
err := s.Start()
assert.Nil(t, err)
defer assert.Nil(t, s.Stop())
defaultConf := s.conf
w := httptest.NewRecorder()
testCases := []struct {
name string
conf func() ServerConfig
want string
}{{
name: "all_right",
conf: func() ServerConfig {
return defaultConf
},
want: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}",
}, {
name: "fastest_addr",
conf: func() ServerConfig {
conf := defaultConf
conf.FastestAddr = true
return conf
},
want: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"fastest_addr\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}",
}, {
name: "parallel",
conf: func() ServerConfig {
conf := defaultConf
conf.AllServers = true
return conf
},
want: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"parallel\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}",
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
s.conf = tc.conf()
s.handleGetConfig(w, nil)
assert.Equal(t, tc.want, w.Body.String())
assert.Equal(t, "application/json", w.Header().Get("Content-Type"))
})
w.Body.Reset()
}
}
func TestDNSForwardHTTTP_handleSetConfig(t *testing.T) {
s := createTestServer(t)
defaultConf := s.conf
err := s.Start()
assert.Nil(t, err)
defer func() {
assert.Nil(t, s.Stop())
}()
w := httptest.NewRecorder()
const defaultConfJSON = "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}"
testCases := []struct {
name string
req string
wantSet string
wantGet string
}{{
name: "upstream_dns",
req: "{\"upstream_dns\":[\"8.8.8.8:77\",\"8.8.4.4:77\"]}",
wantSet: "",
wantGet: "{\"upstream_dns\":[\"8.8.8.8:77\",\"8.8.4.4:77\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}",
}, {
name: "bootstraps",
req: "{\"bootstrap_dns\":[\"9.9.9.10\"]}",
wantSet: "",
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}",
}, {
name: "blocking_mode_good",
req: "{\"blocking_mode\":\"refused\"}",
wantSet: "",
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"refused\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}",
}, {
name: "blocking_mode_bad",
req: "{\"blocking_mode\":\"custom_ip\"}",
wantSet: "blocking_mode: incorrect value\n",
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}",
}, {
name: "ratelimit",
req: "{\"ratelimit\":6}",
wantSet: "",
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":6,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}",
}, {
name: "edns_cs_enabled",
req: "{\"edns_cs_enabled\":true}",
wantSet: "",
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":true,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}",
}, {
name: "dnssec_enabled",
req: "{\"dnssec_enabled\":true}",
wantSet: "",
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":true,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}",
}, {
name: "cache_size",
req: "{\"cache_size\":1024}",
wantSet: "",
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":1024,\"cache_ttl_min\":0,\"cache_ttl_max\":0}",
}, {
name: "upstream_mode_parallel",
req: "{\"upstream_mode\":\"parallel\"}",
wantSet: "",
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"parallel\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}",
}, {
name: "upstream_mode_fastest_addr",
req: "{\"upstream_mode\":\"fastest_addr\"}",
wantSet: "",
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"fastest_addr\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}",
}, {
name: "upstream_dns_bad",
req: "{\"upstream_dns\":[\"\"]}",
wantSet: "wrong upstreams specification: missing port in address\n",
wantGet: defaultConfJSON,
}, {
name: "bootstraps_bad",
req: "{\"bootstrap_dns\":[\"a\"]}",
wantSet: "a can not be used as bootstrap dns cause: invalid bootstrap server address: Resolver a is not eligible to be a bootstrap DNS server\n",
wantGet: defaultConfJSON,
}, {
name: "cache_bad_ttl",
req: "{\"cache_ttl_min\":1024,\"cache_ttl_max\":512}",
wantSet: "cache_ttl_min must be less or equal than cache_ttl_max\n",
wantGet: defaultConfJSON,
}, {
name: "upstream_mode_bad",
req: "{\"upstream_mode\":\"somethingelse\"}",
wantSet: "upstream_mode: incorrect value\n",
wantGet: defaultConfJSON,
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
rBody := ioutil.NopCloser(strings.NewReader(tc.req))
r, err := http.NewRequest(http.MethodPost, "http://example.com", rBody)
assert.Nil(t, err)
s.handleSetConfig(w, r)
assert.Equal(t, tc.wantSet, w.Body.String())
w.Body.Reset()
s.handleGetConfig(w, nil)
assert.Equal(t, tc.wantGet, w.Body.String())
w.Body.Reset()
})
s.conf = defaultConf
}
}

View File

@@ -18,16 +18,21 @@ import (
"testing"
"time"
"github.com/AdguardTeam/AdGuardHome/util"
"github.com/AdguardTeam/AdGuardHome/internal/testutil"
"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"
"github.com/stretchr/testify/assert"
)
func TestMain(m *testing.M) {
testutil.DiscardLogOutput(m)
}
const (
tlsServerName = "testdns.adguard.com"
testMessagesCount = 10
@@ -751,11 +756,14 @@ func createTestServer(t *testing.T) *Server {
c.CacheTime = 30
f := dnsfilter.New(&c, filters)
s := NewServer(DNSCreateParams{DNSFilter: f})
s.conf.UDPListenAddr = &net.UDPAddr{Port: 0}
s.conf.TCPListenAddr = &net.TCPAddr{Port: 0}
s.conf.UpstreamDNS = []string{"8.8.8.8:53", "8.8.4.4:53"}
s.conf.FilteringConfig.ProtectionEnabled = true
s.conf.ConfigModified = func() {}
err := s.Prepare(nil)
assert.True(t, err == nil)
return s
@@ -815,12 +823,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 +924,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 +986,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 +1041,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

@@ -9,9 +9,14 @@ import (
"testing"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/testutil"
"github.com/stretchr/testify/assert"
)
func TestMain(m *testing.M) {
testutil.DiscardLogOutput(m)
}
func prepareTestDir() string {
const dir = "./agh-test"
_ = os.RemoveAll(dir)
@@ -85,9 +90,11 @@ type testResponseWriter struct {
func (w *testResponseWriter) Header() http.Header {
return w.hdr
}
func (w *testResponseWriter) Write([]byte) (int, error) {
return 0, nil
}
func (w *testResponseWriter) WriteHeader(statusCode int) {
w.statusCode = statusCode
}

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

@@ -6,10 +6,11 @@ import (
"net"
"net/http"
"net/url"
"runtime"
"strconv"
"strings"
"github.com/AdguardTeam/AdGuardHome/dnsforward"
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
"github.com/AdguardTeam/golibs/log"
"github.com/NYTimes/gziphandler"
)
@@ -46,6 +47,7 @@ func handleStatus(w http.ResponseWriter, r *http.Request) {
if Context.dnsServer != nil {
Context.dnsServer.WriteDiskConfig(&c)
}
data := map[string]interface{}{
"dns_addresses": getDNSAddresses(),
"http_port": config.BindPort,
@@ -56,7 +58,17 @@ func handleStatus(w http.ResponseWriter, r *http.Request) {
"protection_enabled": c.ProtectionEnabled,
}
data["dhcp_available"] = (Context.dhcpServer != nil)
if runtime.GOOS == "windows" {
// Set the DHCP to false explicitly, because Context.dhcpServer
// is probably not nil, despite the fact that there is no
// support for DHCP on Windows in AdGuardHome.
//
// See also the TODO in dhcpd.Create.
data["dhcp_available"] = false
} else {
data["dhcp_available"] = (Context.dhcpServer != nil)
}
jsonVal, err := json.Marshal(data)
if err != nil {

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")
}

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