Compare commits

...

1271 Commits

Author SHA1 Message Date
Frank Denis 8dadd61730
Merge pull request #2630 from DNSCrypt/dependabot/github_actions/softprops/action-gh-release-2.0.5
Bump softprops/action-gh-release from 2.0.2 to 2.0.5
2024-05-08 10:31:44 +02:00
dependabot[bot] f7da81cf29
Bump softprops/action-gh-release from 2.0.2 to 2.0.5
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.0.2 to 2.0.5.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](d99959edae...69320dbe05)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-08 03:55:52 +00:00
Frank Denis 0efce55895 Try another ODoH relay 2024-05-07 22:44:33 +02:00
Frank Denis 5a1d94d506 Update the test ODoH relay 2024-05-07 22:35:09 +02:00
Frank Denis 271943c158 Update quic-go 2024-05-07 17:39:56 +02:00
Frank Denis 34a1f2ebf5 Update quic-go 2024-04-27 22:33:56 +02:00
Frank Denis f8ce22d9b9 Update deps 2024-04-25 12:45:52 +02:00
Frank Denis 249dba391d Support gzip compression to fetch source files 2024-04-25 12:43:29 +02:00
Frank Denis 987ae216e3 Add fritz.box to the set of undelegated zones 2024-04-21 20:14:15 +02:00
Frank Denis 7fba32651b Make it more visible that DNS64 has been enabled 2024-04-19 18:27:39 +02:00
Frank Denis 6ae388e646 DNS64 plugin: don't return SYNTH data, alter the response directly
Fixes #2619

However, cached responses now appear with the "PASS" status rather
than "CLOAK".
2024-04-19 18:19:16 +02:00
Frank Denis 0af88bc875 Merge branch 'master' of github.com:DNSCrypt/dnscrypt-proxy
* 'master' of github.com:DNSCrypt/dnscrypt-proxy:
  chore: fix some typos in comments
2024-04-15 12:36:30 +02:00
Frank Denis d36edeb612 Update deps 2024-04-15 12:36:21 +02:00
Frank Denis 041a6c7d7f
Merge pull request #2615 from cuibuwei/master
chore: fix some typos in comments
2024-04-13 20:02:49 +02:00
cuibuwei 2c6416d5ae chore: fix some typos in comments
Signed-off-by: cuibuwei <cuibuwei@gmail.com>
2024-04-13 19:56:31 +08:00
Frank Denis 4d1cd67d4d Nits 2024-04-03 16:49:37 +02:00
Frank Denis 363d44919f Properly check for the sticky bit 2024-04-03 16:47:13 +02:00
Frank Denis a88076d06f
Merge pull request #2605 from edmonds/forward-root-subdomain-matches
Forwarding plugin: Support forwarding subdomains of the root domain
2024-03-26 21:32:06 +01:00
Frank Denis 119bc0b660 Update deps 2024-03-26 19:56:06 +01:00
Robert Edmonds 49000cd4f4 Forwarding plugin: Support forwarding subdomains of the root domain
This commit updates the forwarding plugin to support matching subdomains
of the root domain ("."). It looks like the forwarding plugin already
performs subdomain matches against the domains specified in the
forwarding rules files, but matches against the root domain weren't
working because of the way matches are performed by comparing the
normalized presentation format QNAME (which omits the trailing dot for
all QNAMEs except the root domain name).

Without this commit, only queries where the QNAME is exactly "."
would match a forwarding rule for the "." domain, like this (with
`offline_mode = true` and a single forwarding rule for the "." domain):

```
[2024-03-25 21:13:31]	100.100.100.100	.	NS	FORWARD	0ms	127.0.0.1:53
[2024-03-25 21:13:36]	100.100.100.100	com	NS	NOT_READY	0ms	-
```

With this commit I get the expected result:

```
[2024-03-25 21:40:07]	100.100.100.100	.	NS	FORWARD	0ms	127.0.0.1:53
[2024-03-25 21:40:09]	100.100.100.100	com	NS	FORWARD	0ms	127.0.0.1:53
```
2024-03-25 21:30:09 -04:00
Frank Denis ec46e09360
Merge pull request #2597 from DNSCrypt/dependabot/github_actions/softprops/action-gh-release-d99959edae48b5ffffd7b00da66dcdb0a33a52ee
Bump softprops/action-gh-release from 975c1b265e11dd76618af1c374e7981f9a6ff44a to d99959edae48b5ffffd7b00da66dcdb0a33a52ee
2024-03-11 09:23:02 +01:00
dependabot[bot] ea5808e024
Bump softprops/action-gh-release
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 975c1b265e11dd76618af1c374e7981f9a6ff44a to d99959edae48b5ffffd7b00da66dcdb0a33a52ee.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](975c1b265e...d99959edae)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-11 03:24:39 +00:00
Frank Denis 79a1aa8325
Merge pull request #2591 from alisonatwork/fix-build 2024-02-28 10:11:48 +01:00
Alison Winters 4c442f5dbb use go mod version for codeql 2024-02-28 10:07:03 +08:00
Alison Winters f7e13502c0 fix go version format 2024-02-28 09:47:34 +08:00
YX Hao 8d43ce9b56 make expression be more self-explanatory 2024-02-27 22:05:40 +08:00
YX Hao ac5087315c Listen `0.0.0.0` only on IPv4 2024-02-27 19:04:09 +08:00
Frank Denis ad80d81d43
Merge pull request #2587 from DNSCrypt/dependabot/github_actions/softprops/action-gh-release-975c1b265e11dd76618af1c374e7981f9a6ff44a
Bump softprops/action-gh-release from 4634c16e79c963813287e889244c50009e7f0981 to 975c1b265e11dd76618af1c374e7981f9a6ff44a
2024-02-26 08:47:39 +01:00
dependabot[bot] a7fb13ba4e
Bump softprops/action-gh-release
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 4634c16e79c963813287e889244c50009e7f0981 to 975c1b265e11dd76618af1c374e7981f9a6ff44a.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](4634c16e79...975c1b265e)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-26 03:37:41 +00:00
Frank Denis 006619837f Update deps 2024-02-20 08:01:38 +01:00
Frank Denis 093936f7ab Check for dumb file permissions on startup
There's nothing special about "-service install".

On any system, executables shouldn't be modifiable by other system
users, no matter what the executable is and how it's run.
2024-02-20 02:39:39 +01:00
Frank Denis 7462961980 Warn if the executable of the service being installed could be overwritten by other system users
Fixes #2579

Until this is handled by `kardianos/service`
2024-02-20 02:23:49 +01:00
Frank Denis 0b559bb54f Warn if the main config file could be written by other system users 2024-02-20 02:11:03 +01:00
Frank Denis 658835b4ff
Merge pull request #2573 from DNSCrypt/dependabot/github_actions/softprops/action-gh-release-4634c16e79c963813287e889244c50009e7f0981
Bump softprops/action-gh-release from c9b46fe7aad9f02afd89b12450b780f52dacfb2d to 4634c16e79c963813287e889244c50009e7f0981
2024-02-06 13:23:03 +01:00
Frank Denis 90c3017793
Merge pull request #2544 from DNSCrypt/dependabot/github_actions/actions/setup-go-5
Bump actions/setup-go from 4 to 5
2024-02-06 13:22:24 +01:00
dependabot[bot] e371138b86
Bump softprops/action-gh-release
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from c9b46fe7aad9f02afd89b12450b780f52dacfb2d to 4634c16e79c963813287e889244c50009e7f0981.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](c9b46fe7aa...4634c16e79)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-06 03:22:12 +00:00
Frank Denis bcbf2db4ff
Merge pull request #2568 from lifenjoiner/ci 2024-01-19 14:30:34 +01:00
YX Hao 64fa90839c CI tests the unregistered domain for solid NS answer
And formats.
2024-01-19 19:11:03 +08:00
Frank Denis f2484f5bd5 Cache plugin: replace ARC cache with SIEVE 2024-01-19 00:05:33 +01:00
Frank Denis 63f8d9b30d Update deps 2024-01-18 23:47:00 +01:00
Xiaotong Liu 49e3570c2c
Support server refresh concurrency (#2537)
* simultaneously refresh all servers

* Add `cert_refresh_concurrency`

---------

Co-authored-by: YX Hao <lifenjoiner@163.com>
2023-12-18 19:25:54 +08:00
lifenjoiner 3be53642fe
Merge pull request #2549 from lifenjoiner/wg
Optimize CaptivePortalHandler for clean code
2023-12-17 18:59:05 +08:00
YX Hao 13e7077200 Optimize CaptivePortalHandler for clean code 2023-12-14 19:23:42 +08:00
Frank Denis f5912d7ca9
Merge pull request #2548 from DNSCrypt/dependabot/github_actions/github/codeql-action-3
Bump github/codeql-action from 2 to 3
2023-12-14 07:47:05 +01:00
dependabot[bot] 0196d7d2ab
Bump github/codeql-action from 2 to 3
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2 to 3.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-14 03:22:09 +00:00
Frank Denis 898ded9c52 Merge branch 'master' of github.com:DNSCrypt/dnscrypt-proxy
* 'master' of github.com:DNSCrypt/dnscrypt-proxy:
  add timeout for udp and tcp dialer
  Use blocking channel instead of looping sleep for less CPU usage
2023-12-13 08:35:55 +01:00
Frank Denis e782207911 Update deps 2023-12-13 08:35:41 +01:00
Frank Denis 0f1f635ec1
Merge pull request #2545 from keatonLiu/dial-timeout
add timeout for udp and tcp dialer
2023-12-11 14:45:20 +01:00
keatonLiu 956a14ee21 add timeout for udp and tcp dialer 2023-12-10 23:56:13 +08:00
dependabot[bot] 22731786a2
Bump actions/setup-go from 4 to 5
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 4 to 5.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-07 03:49:26 +00:00
Frank Denis 42b6ae9052
Merge pull request #2541 from lifenjoiner/chan
Use blocking channel instead of looping sleep for less CPU usage
2023-12-03 17:24:10 +01:00
YX Hao 0d5e52bb16 Use blocking channel instead of looping sleep for less CPU usage 2023-12-03 23:00:10 +08:00
Frank Denis 0ba728b6ce Update deps 2023-11-15 15:51:48 -08:00
Frank Denis cb80bf33e8 shellcheck 2023-11-09 22:47:41 +01:00
Frank Denis 88207560a7 shellcheck fixes 2023-11-09 22:45:11 +01:00
Jeffrey Damick 4a361dbb05 Added support to package dnscrypt for windows into an msi 2023-11-09 13:14:29 -08:00
Frank Denis b37a5c991a Update deps 2023-10-12 15:53:53 +02:00
Frank Denis 0232870870 -list: only copy nofilter flag for ODoH relays 2023-09-23 22:52:43 +02:00
Frank Denis 1a9bf8a286 Omit DNSSEC flag for relays 2023-09-23 18:46:11 +02:00
Frank Denis 7fb58720fb Add -include-relays option to include relays in -list and -list-all 2023-09-23 18:37:52 +02:00
Frank Denis f85b3e81ec Update deps 2023-09-19 20:59:57 +02:00
Frank Denis 79779cf744 Merge branch 'master' of github.com:DNSCrypt/dnscrypt-proxy
* 'master' of github.com:DNSCrypt/dnscrypt-proxy:
  Bump actions/checkout from 3 to 4
2023-09-05 22:37:54 +02:00
Frank Denis 8bea679e7b Unofficially support DoH/ODoH over HTTP 2023-09-05 22:37:11 +02:00
Frank Denis 96f21f1bff
Merge pull request #2479 from DNSCrypt/dependabot/github_actions/actions/checkout-4
Bump actions/checkout from 3 to 4
2023-09-05 08:13:08 +02:00
dependabot[bot] 21097686c1
Bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-05 03:29:06 +00:00
Frank Denis 87571d4a7f Add an IPv6 forwarding example
Fixes #2474
2023-08-30 21:32:22 +02:00
Frank Denis f531c8fffb plugin_forward: parse more conventions for IPv6 addresses 2023-08-30 21:29:09 +02:00
Frank Denis 5ae83c1592 Remove minor go version for codeql 2023-08-26 18:28:55 +02:00
Frank Denis c86e9a90cc Update quic-go 2023-08-25 16:15:45 +02:00
Frank Denis d48c811ea9 Don't use absolute paths in the example file 2023-08-17 14:44:47 +02:00
Frank Denis f2b1edcec2 Add dnscry.pt servers 2023-08-17 14:43:33 +02:00
Frank Denis 1b65fe62b0 Bump 2023-08-11 18:56:31 +02:00
Frank Denis 194752e829 Update ChangeLog 2023-08-11 18:47:44 +02:00
Frank Denis 808f2dfa0e Update deps 2023-08-11 17:06:18 +02:00
Frank Denis 7dd79d5f96 Add a little bit more delay when spinning
But we really shouldn't do it that way, if only because there's a race
between the last write to the channel and the close() call
2023-08-11 15:24:14 +02:00
Frank Denis 5088d8fae1 Use the latest version of Go in CI 2023-08-11 14:59:34 +02:00
Frank Denis aff09648bb Add support for extended error codes 2023-08-11 14:59:10 +02:00
Frank Denis 7bca9a6c0a
Merge pull request #2457 from Neo2308/feature/master/check-latest-go
Configured Github CI to always use latest go version
2023-08-11 14:07:59 +02:00
Frank Denis 98d0938815 Make RefreshDelay match the documentation 2023-08-11 14:06:03 +02:00
Frank Denis 50780421a8 Remove ipv6.download.dnscrypt.info
IPv6 address has been added to download.dnscrypt.info
2023-08-11 14:04:20 +02:00
RadhaKrishna be7d5d1277 Configured Github CI to always use latest go
version

* Check if there is a newer version of go before using the cached version.
2023-08-11 17:15:09 +05:30
Frank Denis c3dd761b81 Make error more explicit 2023-08-11 12:07:13 +02:00
Frank Denis d8aec47a72 Revert "Make RefreshDelay match the documentation"
This reverts commit cfd6ced134.
2023-08-11 11:48:30 +02:00
Frank Denis cfd6ced134 Make RefreshDelay match the documentation 2023-08-11 11:42:12 +02:00
Frank Denis bdf27330c9 Make fetchWithCache() more readable 2023-08-11 11:24:54 +02:00
Frank Denis a108d048d8 A useless Chtimes() call is still required for the tests :/ 2023-08-11 11:16:44 +02:00
Frank Denis afcfd566c9 Make updateCache() more readable 2023-08-11 11:11:16 +02:00
Frank Denis ce55d1c5bb Get rid of named return parameters 2023-08-11 11:01:55 +02:00
Frank Denis 2481fbebd7 Revert b898e07066 2023-08-11 01:39:15 +02:00
Frank Denis 32aad7bb34 Format fix 2023-08-11 01:15:34 +02:00
Frank Denis 7033f242c0 Restore the cache update code from version 2.1.4 for now 2023-08-11 00:51:34 +02:00
Frank Denis 2675d73b13 Port changes from #2334
I'm not sure I follow, but I trust @lifenjoiner

Fixes #2334
2023-08-11 00:17:46 +02:00
Frank Denis 5085a22903 Update quic-go again 2023-08-10 23:50:43 +02:00
Frank Denis 7cc5a051c7 Update golang-lru 2023-08-08 14:21:12 +02:00
Frank Denis 894d20191f Update deps 2023-08-07 17:32:25 +02:00
Frank Denis 0a98be94a7 Update quic-go to fix two regressions 2023-08-01 00:06:22 +02:00
Frank Denis 1792c06bc7
Merge pull request #2442 from Expertcoderz/patch-1
Add note regarding block_unqualified setting
2023-07-25 14:55:42 +02:00
Expertcoderz 63e414021b
Add note regarding block_unqualified 2023-07-25 12:36:07 +00:00
Frank Denis d659a801c2 Big update to Update quic-go 2023-07-22 00:41:27 +02:00
Frank Denis a4eda39563
Merge pull request #2438 from Expertcoderz/patch-1
Add .mail & .home.arpa undelegated names
2023-07-15 20:07:05 +02:00
Expertcoderz 4114f032c3
Add .mail & .home.arpa undelegated names
Both names have been recognized for internal use in private networks.
2023-07-15 13:12:40 +00:00
Frank Denis a352a3035c Update deps 2023-07-08 14:56:13 +02:00
Frank Denis 60684f8ee4
Merge pull request #2429 from lifenjoiner/quic-go
Upgrade quic-go to v0.36.1
2023-07-08 14:54:39 +02:00
YX Hao be369a1f7a Shorten a line 2023-07-06 21:01:41 +08:00
YX Hao 89ccc59f0e Upgrade quic-go to v0.36.1
quic-go has made breaking changes since v0.35.0, includes implementing
`CloseIdleConnections`.
Now, the local listener UDPConn are reused, and don't pile up. But,
1 instance (IPv4/IPv6) persists for each connected server.
2023-07-05 21:19:54 +08:00
Frank Denis 16b2c84147 Tone down some errors 2023-06-24 22:38:59 +02:00
Carlo Teubner b46775ae0c
Add some missing error checks (#2420)
I found these with the 'errcheck' tool (via 'golangci-lint').

I aimed to apply reasonable judgement when deciding which errors
actually need handling, and how to handle them.
2023-06-24 22:23:12 +02:00
Frank Denis cef4b041d7 Don't call "bin" what is actually text 2023-06-24 22:11:47 +02:00
Carlo Teubner d8b1f4e7cd
Fix miscellaneous style issues (#2421)
Found by running: golangci-lint run --enable-all

I have only addressed the reported issues that seemed relevant to me.
2023-06-24 21:56:03 +02:00
Frank Denis 23a6cd7504 Revert "Update quic-go"
This reverts commit f9f68cf0a3.

quic-go >= 1.0.35 panics

We may not be using the new API correctly.
2023-06-22 11:06:37 +02:00
Frank Denis f42b7dad17 Update deps 2023-06-22 10:36:33 +02:00
Frank Denis 4f3ce0cbae Update deps 2023-06-18 04:19:52 +02:00
Frank Denis 0f1e3b4ba8 error check all the rand.Read() calls 2023-06-06 09:16:44 +02:00
Frank Denis 62ef5c9d02 Update quic-go to fix a regression 2023-06-01 11:32:10 +02:00
Frank Denis f9f68cf0a3 Update quic-go 2023-05-30 18:17:27 +02:00
Frank Denis 0c26d1637a Add suport for TLS key logging 2023-05-24 09:21:49 +02:00
Frank Denis 9f86ffdd1e Update deps 2023-05-13 11:39:11 +02:00
lifenjoiner 9b2c674744
Base on clientProto value explicitly to dereference clientAddr (#2393)
There are variants local_doh and trampoline for internal flow.
2023-05-13 11:22:52 +02:00
Frank Denis d381af5510 Update deps 2023-05-01 16:05:02 +02:00
Frank Denis c66023c7d7 Clarify that TLS cipher suites are for TLS 1.2
Fixes #2377
2023-04-18 13:15:59 -06:00
Frank Denis 5b8e7d4114 Use the same command as on the wiki to create a local DoH cert 2023-04-14 23:08:10 +02:00
KOLANICH f4007f709d
Add DOH certificate generation commands into the example config. (#2367) 2023-04-14 21:34:29 +02:00
lifenjoiner dd1c066724
CI: Don't downloading already vendored dependencies (#2370) 2023-04-14 21:21:22 +02:00
lifenjoiner 5d551e54ce
CI: Fix actions/setup-go@v4 warning (#2371)
Warning: Restore cache failed: Dependencies file is not found ...
https://github.com/actions/setup-go#caching-dependency-files-and-build-outputs
2023-04-14 21:20:37 +02:00
Thad Guidry fbc7817366
fix grammar in example file (#2372) 2023-04-14 21:19:55 +02:00
Frank Denis 9b61b73852 Update deps 2023-04-07 16:42:57 +02:00
Frank Denis af6340df09 Comment 2023-04-07 16:20:26 +02:00
Frank Denis 9c73ab3070 Simplify updateCache() 2023-04-07 16:18:50 +02:00
Frank Denis ea3625bcfd Try to simplify updateCache() to understand what it does 2023-04-07 16:09:51 +02:00
Frank Denis f567f57150 up 2023-04-07 15:58:34 +02:00
Frank Denis c03f1a31eb Go named return parameters are utterly confusing 2023-04-07 15:37:09 +02:00
Frank Denis c3c51bb435 Partially re-merge 92ed5b95e0 2023-04-07 15:21:00 +02:00
Frank Denis 0f30b3b028 Revert "Try to understand how cache files are updated"
This reverts commit 92ed5b95e0.
2023-04-07 15:16:15 +02:00
lifenjoiner 6d826afac5
Reduce a local variable (#2363) 2023-04-06 14:22:21 +02:00
Frank Denis b341c21dbd Merge branch 'master' of github.com:DNSCrypt/dnscrypt-proxy
* 'master' of github.com:DNSCrypt/dnscrypt-proxy:
  Bump softprops/action-gh-release (#2357)
  Bump actions/setup-go from 3 to 4 (#2354)
  Update deps
  Format
  Better description for ignore_system_dns
  Move booleans together for alignment, avoid unneeded format string
  Try dnscrypt-proxy to resolve configured hosts when ignore_system_dns (#2204)
  Downgrade to TLS 1.2 if an 1.3-incompatible cipher suite is set
2023-04-06 14:21:15 +02:00
Frank Denis 92ed5b95e0 Try to understand how cache files are updated
Having to keep a copy of all the files in memory is weird.

We shouldn't have to do that.
2023-04-06 14:19:25 +02:00
Frank Denis b898e07066 A source URL may have an IP address that doesn't exist any more 2023-04-06 14:18:38 +02:00
dependabot[bot] 92063aa76d
Bump softprops/action-gh-release (#2357)
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from d4e8205d7e959a9107da6396278b2f1f07af0f9b to c9b46fe7aad9f02afd89b12450b780f52dacfb2d.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](d4e8205d7e...c9b46fe7aa)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-05 21:43:53 +02:00
dependabot[bot] 4be5264529
Bump actions/setup-go from 3 to 4 (#2354)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 3 to 4.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-05 21:43:43 +02:00
Frank Denis 13d78c042b Update deps 2023-04-05 21:36:29 +02:00
Frank Denis 36c17eb59a Format 2023-04-05 21:33:21 +02:00
Frank Denis b9f8f78c6e Better description for ignore_system_dns 2023-04-05 21:31:07 +02:00
Frank Denis fc16e3c31c Move booleans together for alignment, avoid unneeded format string 2023-04-05 21:20:42 +02:00
lifenjoiner b3318a94b7
Try dnscrypt-proxy to resolve configured hosts when ignore_system_dns (#2204) 2023-04-05 21:17:51 +02:00
Frank Denis ca0f353087 Downgrade to TLS 1.2 if an 1.3-incompatible cipher suite is set
Fixes #2359
2023-04-05 20:53:27 +02:00
Frank Denis cf7d60a704 Update miekg/dns 2023-03-29 22:00:24 +09:00
Frank Denis a47f7fe750 Update deps 2023-03-23 12:54:45 +01:00
Frank Denis beb002335f Add an example forwarding rule with Tor 2023-03-23 12:53:08 +01:00
Frank Denis 15c87a68a1 Update quic-go 2023-02-25 23:45:38 +01:00
Frank Denis 47e6a56b16 Logger: pre-create log files before lumberjack does
Clunky workaround for https://github.com/natefinch/lumberjack/issues/164
2023-02-25 23:42:38 +01:00
Frank Denis 03c6f92a5f Use crypto_rand() everywhere 2023-02-24 16:20:39 +01:00
lifenjoiner 24a301b1af
Fix DoH3 connections piling up (#2337)
DoH3 creates a new connection for each request without closing.

* `Conn` should be self maintained if it's created by customized `Dial` of `http3.RoundTripper`.
https://pkg.go.dev/github.com/quic-go/quic-go#DialAddrEarlyContext

* http3 doesn't have a `CloseIdleConnections`.
https://pkg.go.dev/net/http#Client.CloseIdleConnections
2023-02-24 16:14:43 +01:00
lifenjoiner a8d1c2fd24
`dlog.SetLogLevel(dlog.SeverityDebug)` if `go test -v` (#2331) 2023-02-21 16:24:11 +01:00
Frank Denis 96ffb21228 Update deps 2023-02-15 18:42:36 +01:00
Frank Denis acc25fcefb Format with gofumpt 2023-02-11 14:27:12 +01:00
Frank Denis 07b4ec33c5 Minor update of x/net and x/crypto 2023-02-09 17:23:48 +01:00
Frank Denis 9f3ef735f2 Bump 2023-02-07 11:03:09 +01:00
Frank Denis d568e43937 Update deps 2023-02-07 11:03:09 +01:00
Frank Denis 68f3ab249c Unbreak cloaking plugin
In version 2.1.3, when the cloaking pluging was enabled, a blocked
response was returned for records that were not A/AAAA/PTR, even
with names that were not in the cloaked list.
2023-02-07 11:03:05 +01:00
dependabot[bot] 2edfdc48b8
Bump roots/issue-closer from 1.1 to 1.2 (#2307)
Bumps [roots/issue-closer](https://github.com/roots/issue-closer) from 1.1 to 1.2.
- [Release notes](https://github.com/roots/issue-closer/releases)
- [Commits](https://github.com/roots/issue-closer/compare/v1.1...v1.2)

---
updated-dependencies:
- dependency-name: roots/issue-closer
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-06 10:46:14 +01:00
Frank Denis 3f31c4d3e2 Update issue-close-message 2023-02-04 22:15:18 +01:00
Frank Denis 84184bbad8 Merge branch 'master' of github.com:DNSCrypt/dnscrypt-proxy
* 'master' of github.com:DNSCrypt/dnscrypt-proxy:
  GitHub Actions: Deprecating save-state and set-output commands (#2295)
  Nits (#2293)
  Make CodeQL happy (#2294)
2023-02-04 22:11:14 +01:00
Frank Denis f630094e8d Add autocloser 2023-02-04 22:11:05 +01:00
lifenjoiner 3517dec376
GitHub Actions: Deprecating save-state and set-output commands (#2295) 2023-02-03 16:24:32 +01:00
lifenjoiner 683aad75da
Nits (#2293) 2023-02-03 16:23:57 +01:00
lifenjoiner e1c7ea1770
Make CodeQL happy (#2294) 2023-02-03 16:22:32 +01:00
Frank Denis 470460f069 GO386=387 -> GO386=softfloat
Fixes #2296
2023-02-03 16:21:51 +01:00
Frank Denis 8694753866 Bump action-gh-release up 2023-02-02 20:28:37 +01:00
Frank Denis b4b58366cc Update ChangeLog 2023-02-02 20:27:16 +01:00
Frank Denis f7df72eafa Bump to 2.1.3 2023-02-02 20:10:54 +01:00
Frank Denis fb15535282 Format 2023-02-02 20:10:49 +01:00
Frank Denis c32aad3dfd Update GitHub status badge 2023-02-02 20:09:09 +01:00
Frank Denis 9e208e6090 Cloak plugin: reject uncloaked records, except NS & SOA
Fixes #2220
2023-02-02 19:59:47 +01:00
Frank Denis 5f88a9146c Get rid of the latest ioutil bits 2023-02-02 19:44:51 +01:00
Frank Denis 3f23ff5c08 Mostly get rid of ioutil 2023-02-02 19:38:24 +01:00
Frank Denis 33c8027e0a Use a custom dialer for HTTP/3 2023-02-02 19:32:17 +01:00
Frank Denis 11e824bd13 Update go-acl 2023-02-02 12:44:12 +01:00
Deltadroid c3fd855831
Update quic-go dependency to support go 1.20 (#2292) 2023-02-02 12:42:11 +01:00
Frank Denis 5438eed2f4 Update go/x/crypto 2023-01-08 21:37:50 +01:00
Frank Denis a868e2b306 2023 2023-01-05 14:06:00 +01:00
Frank Denis f21eca0764 Add time.google.com IP addresses to the captive portals example 2022-12-30 13:50:31 +01:00
Frank Denis c883949a97 Document cert_ignore_timestamp 2022-12-29 22:39:12 +01:00
Frank Denis e13b4842e8 Updater deps 2022-12-17 14:50:10 +01:00
dependabot[bot] 5705b60936
Bump softprops/action-gh-release (#2247)
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from cd28b0f5ee8571b76cfdaa62a30d51d752317477 to 1. This release includes the previously tagged commit.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](cd28b0f5ee...de2c0eb89a)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-22 11:42:01 +01:00
Frank Denis 5f4dfc5d6e Update quic-go 2022-11-19 23:01:21 +01:00
Frank Denis a89d96144f Update deps 2022-11-16 21:38:52 +01:00
Frank Denis 4aa415de6e Update deps 2022-10-24 10:20:25 +02:00
Frank Denis f4389559ef Pin softprops/action-gh-release 2022-10-24 10:10:58 +02:00
Frank Denis 361455cd58 ServiceManagerReadyNotify is not just for systemd 2022-10-20 15:33:43 +02:00
cobratbq 77059ce450
systemd: report Ready earlier as dnscrypt-proxy can itself manage retries for updates/refreshes (#2225) 2022-10-20 15:32:26 +02:00
Frank Denis 09a6918226 Use os.Geteuid()
Fixes #2224
2022-10-18 14:56:39 +02:00
Frank Denis c748630691 Update deps 2022-10-15 10:37:07 +02:00
Frank Denis 94cba8cf78 Update quic-go 2022-09-26 15:12:20 +02:00
Maurizio Pasquinelli ca253923eb
Rename macOS binary (#2191) 2022-08-31 12:05:35 +02:00
Frank Denis 08d44241b9 Update deps 2022-08-30 20:45:06 +02:00
lifenjoiner 4881186dcf
Optimize adopted relay name to show (#2188)
* Optimize adopted relay name to show

DNSCrypt relay requires ServerAddrStr;
ODoH relay requires ProviderName, port 443 can be either present or not;
raw stamp can be both.

Displaying specified stamp makes it easier to debug.

* Fix pasto
2022-08-25 19:28:04 +02:00
Frank Denis 41f192a907 Mention HTTP/3 2022-08-24 17:35:34 +02:00
Frank Denis 937c1e63e2 Revert "xtransport layer to netip and immediate dependencies (#2159)"
This reverts commit baee50f1dc.
2022-08-10 22:24:36 +02:00
Frank Denis e124623ffc Mention HTTP/3 support 2022-08-03 15:31:57 +02:00
lifenjoiner 55fc4c207b
Log to console when in command mode (#2167)
Quick results.
Avoid overwriting the log file in use, by the same config most of the time.
2022-08-03 14:52:08 +02:00
Ian Bashford baee50f1dc
xtransport layer to netip and immediate dependencies (#2159) 2022-08-01 22:31:12 +02:00
Frank Denis 6e1bc06477 Update quic-go 2022-08-01 17:59:01 +02:00
Frank Denis 8523a92437 Update example to include http3 configuration 2022-07-24 16:16:21 +02:00
Frank Denis 442f2e15cb Make HTTP/3 support configurable 2022-07-24 16:13:14 +02:00
Frank Denis 0c88e2a1a0 ChangeLog update 2022-07-24 15:43:03 +02:00
Frank Denis 35063a1eec Quit dep update before the release 2022-07-24 15:06:14 +02:00
Frank Denis 07266e4d4f Update toml dep 2022-07-21 19:02:28 +02:00
Frank Denis 5977de660b Add suport for DoH over HTTP/3 2022-07-21 18:50:10 +02:00
lifenjoiner 91388b148c
Optimize stopping CaptivePortalHandler - 2 (#2155)
1. Fix early return that triggers port rebinding error by 8e46f447.
2. Reduce waiting time while there are multiple listen_addresses.
2022-07-19 12:35:52 +02:00
lifenjoiner 8e46f44799
Optimize stopping CaptivePortalHandler (#2151)
* Optimize stopping CaptivePortalHandler

* Still use unbuffered channel as we close it instead of sending a signal
2022-07-14 21:53:13 +02:00
Frank Denis 3d641b758a Bump 2022-07-13 18:49:50 +02:00
Frank Denis 49ea894ce8 Update dependencies 2022-07-13 18:48:17 +02:00
lifenjoiner 568f54fabb
Reduce comparisons (#2148) 2022-07-08 14:11:51 +02:00
pc-v2 dc2fff05be
Adding flush dns to clean up previous dns cache (#2141) 2022-07-03 14:13:12 +02:00
Frank Denis 38e87f9a7b Add a constant for the maximum number of attempts 2022-06-28 18:30:15 +02:00
lifenjoiner 0e2bb13254
Fix goroutines memory leak by unbuffered channel blocking (#2136)
* Use buffered channel to avoid goroutine hanging on

A send on an unbuffered channel can proceed if a receiver is ready.

* Balance captivePortalHandler.cancelChannels for Stop
2022-06-28 18:28:57 +02:00
Frank Denis 59ce17e0ab No need to warn if this is then going to be an error 2022-06-24 15:41:05 +02:00
Frank Denis ee5c9d67a4 Update miekg/dns 2022-06-24 15:18:33 +02:00
Frank Denis 8c43118b03 Stop mentioning "SERVFAIL" in info messages 2022-06-19 20:38:49 +02:00
ignoramous 7177a0ec74
dns64: preserve cnames in translated response (#2129)
* dns64: preserve cnames in translated response

* dns64: rename synthAAAAs to synth64
2022-06-16 00:53:50 +02:00
lifenjoiner 72a602577a
Raise error for invalid relay (#2128)
* Raise error for invalid relay

* Keep error messages the same

* Distinguish this from validation failed
2022-06-15 13:16:06 +02:00
lifenjoiner 0a0b69d93d
RUnlock for early exit (#2127) 2022-06-14 14:25:52 +02:00
lifenjoiner 6916c047e1
Use registeredServers slice copy during ServerInfo refreshing period (#2125)
goroutines:
proxy.updateRegisteredServers() versus proxy.serversInfo.refresh(proxy)
2022-06-13 17:51:33 +02:00
ignoramous 8d737a69f5
PluginDNS64: Use read and write mutexes as approp (#2124) 2022-06-12 11:27:55 +02:00
Frank Denis 866954fbad PreferServerCipherSuites has been deprecated 2022-06-11 19:26:26 +02:00
Frank Denis e477d0e126 We may not have a configured IP address 2022-06-11 19:23:58 +02:00
Frank Denis e24fdd2235 Nits 2022-06-07 21:33:50 +02:00
livingentity 74fb5dabb9
fix negative rtt / shorten lines (#2118)
* fix negative rtt / shorten lines

* Update serversInfo.go
2022-05-18 17:57:57 +02:00
Frank Denis 1afd573b0d Add builds for linux/riscv64 2022-05-18 13:31:46 +02:00
Frank Denis c367a82ac0 Bump miekg/dns 2022-05-11 19:38:45 +02:00
dependabot[bot] 9c8c327703
Bump github/codeql-action from 1 to 2 (#2102)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 1 to 2.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-26 08:20:41 -07:00
livingentity 207d44323d
Update serversInfo.go (#2092) 2022-04-16 21:26:38 +02:00
Frank Denis 3eac156789 Update burntSushi/toml 2022-04-05 14:05:53 +02:00
Frank Denis 5fca7ea49e Back to VividCortex/ewma 2022-04-05 14:04:26 +02:00
Frank Denis 77dc3b1e85 Update miekg/dns 2022-04-03 23:08:29 +02:00
Frank Denis 66f019d886 Revert "regression: fix ewma warmup again (#2079)"
This reverts commit f67e9cab32.
2022-04-03 23:01:03 +02:00
livingentity f67e9cab32
regression: fix ewma warmup again (#2079)
* Update estimators.go

* Update go.mod

* Update modules.txt

* Update go.sum

* Update serversInfo.go

* Update estimators.go

* Update serversInfo.go
2022-04-02 17:41:36 +02:00
Frank Denis 5d023d2a7c Revert "New feature: sleep mode"
This reverts commit e931b234b7.
2022-04-02 09:33:49 +02:00
Frank Denis e931b234b7 New feature: sleep mode 2022-03-31 20:51:34 +02:00
quindecim ed2c880648
Add sources in [domains-blocklist.conf] (#2039)
* Remove duplicate in [domains-blocklist.conf]

__NextDNS CNAME cloaking list__ is already contained in [your big source](https://github.com/notracking/hosts-blocklists/blob/master/SOURCES.md?plain=1#L47). No reasons to merge it two times.

* Remove more duplicates in [domains-blocklist.conf]

* Revert previous commit

* Add anudeepND and lightswitch05 blocklists
2022-03-29 14:46:46 +02:00
Frank Denis c467e20311 Update deps 2022-03-28 12:35:01 +02:00
Frank Denis df3fb0c9f8 Keep lines short
$ golines -w -m 120 --shorten-comments .
2022-03-23 17:48:48 +01:00
Frank Denis c0435772d4 -resolve: report ECS support
Note that we can't randomize the source network, as Google and
possible others refuse networks that don't get BGP announcements.
2022-03-14 17:04:54 +01:00
Frank Denis 49c17f8e98 -resolve: use TXT records to get resolver information 2022-03-14 16:11:10 +01:00
Frank Denis 0465cd35ef miekg/dns update 2022-03-14 16:02:51 +01:00
dependabot[bot] 08420917a5
Bump actions/setup-go from 2.2.0 to 3 (#2054)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 2.2.0 to 3.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v2.2.0...v3)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-07 17:01:40 +01:00
livingentity 87d9653ec2
Remove unused functions (#2057)
They aren't used anywhere.
2022-03-07 17:01:18 +01:00
BigDargon d30c44a6a8
Change bootstrap resolver Quad9 (with ECS) (#2056) 2022-03-02 13:18:20 +01:00
dependabot[bot] 911108149b
Bump actions/checkout from 2 to 3 (#2055)
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-02 10:15:29 +01:00
dependabot[bot] a8aa4cb8e6
Bump actions/setup-go from 2.1.5 to 2.2.0 (#2035)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 2.1.5 to 2.2.0.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v2.1.5...v2.2.0)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-21 14:17:33 +01:00
Frank Denis ca076ce133 Size estimator: provide the slide size 2022-02-21 14:16:13 +01:00
Frank Denis 034d3bd424 Switch to lifenjoiner's ewma variant 2022-02-21 09:14:24 +01:00
Frank Denis c08852feb1 Update deps; sync vendor 2022-02-21 09:00:21 +01:00
Frank Denis 9373cc7162 Use SimpleEWMA for the question size estimator 2022-02-20 23:40:32 +01:00
Frank Denis cb140673fa Set the number of warmup samples to 1 for the RTT estimator 2022-02-20 23:38:42 +01:00
Frank Denis 7956ba5b10 Switch to an ewma fork that allows setting the warmup samples # 2022-02-20 23:38:06 +01:00
livingentity 9ec8a35468
restore old logic/constants (#2045)
* fix indices

* Update serversInfo.go

For safety go back to former logic, just generalized for lbStrategy, until someone comes up with an actual improvement.

* restore old logic/constants
2022-02-19 17:55:36 +01:00
livingentity ac6abfb985
LBStrategy-aware estimator (#2043)
* fix estimator

* LBStrategy-aware estimator

* typo

* cosmetics
2022-02-15 20:17:48 +01:00
quindecim a20d1685b2
Another minor cosmetic fix to [example-dnscrypt-proxy.toml] (#2036) 2022-02-10 15:27:53 +01:00
livingentity 62092726ec
Minor cosmetic toml changes (#2034)
* Minor cosmetic toml changes

* Minor cosmetic toml changes
2022-02-10 08:49:04 +01:00
Frank Denis f38a5463b0 Indent comments 2022-02-09 12:57:02 +01:00
quindecim 7a54406415
Use the same format logic throughout the document (#2029)
* Use the same spacing logic throughout the document

* Fix previous commit

* Fix previous commit, again

* Use the same logic in comments too
2022-02-09 12:49:22 +01:00
quindecim bce0405c0a
Add more sources in [domains-blocklist.conf] file (#2031)
[OISD nsfw] in [Block pornography] section

[Developer Dan's Hosts: Dating Services] in [Block dating websites] section
[Developer Dan's Hosts: Facebook] in [Block social media sites] section
2022-02-09 12:47:39 +01:00
quindecim 29a3442306
[FIX] Start to use wildcards urls for OISD lists (#2027) 2022-02-08 13:31:32 +01:00
Frank Denis 8ed98cacae Bump miekg/dns up 2022-02-08 09:26:55 +01:00
Peter Dave Hello ef1c70e87d
Remove README.md "Contribute" link as the target doesn't exist (#2015) 2022-02-03 01:30:10 +01:00
Frank Denis 4c67e790f6 -list command: print ODoH targets addresses 2022-02-01 08:19:46 +01:00
Frank Denis 4eeed5816f Fix funky indentation for CloakedPTR 2022-02-01 08:18:45 +01:00
Frank Denis c10e6e0635 Local DoH: add support for request using the GET method
Fixes #2012
2022-01-31 14:56:46 +01:00
Frank Denis e6089449b6 Update domains-blocklist.conf examples:
- Change KADhosts file to the base one
- Remove CHEF-KOCH and GameIndustry lists that don't exist any more

Reported by @remyabel2 - Thanks!
2022-01-30 21:20:19 +01:00
mibere 706c1ab286
Download mirror dnscrypt.net removed (#2003) 2022-01-24 01:36:30 +01:00
Frank Denis f7e3381650 generate-domains-blocklist: parse names prefixed with `*.` 2022-01-23 00:55:26 +01:00
cobratbq 7a8bd35009
systemd: use constants and update status on ready (#1993)
Systemd-notify signaling indicates the status of dnscrypt-proxy when
starting as 'Type=notify' systemd service. However, the status is not
updated when initialization completes, instead it always shows
"Starting". Now fixed.
2022-01-19 20:30:15 +01:00
Frank Denis 06733f57ed If a relay has multiple names, print the one matching the protocol
Fixes #1992
2022-01-17 19:43:12 +01:00
Frank Denis 4fd26029c7 Update BurntSushi/toml 2022-01-13 09:22:22 +01:00
Frank Denis 351bced7c5 New kardianos/service with support for OpenRC 2022-01-11 16:05:08 +01:00
Frank Denis 916e84e798 2022 2021-12-31 23:56:13 +01:00
ValdikSS 53f3a0e63d
Fix broken odoh link in readme (#1976)
* Fix broken odoh link in readme
2021-12-27 12:30:41 +01:00
Frank Denis 4e9f0382ee miekg/dns update 2021-12-24 09:16:59 +01:00
dependabot[bot] 9121f4f359
Bump actions/setup-go from 2.1.4 to 2.1.5 (#1968)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 2.1.4 to 2.1.5.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v2.1.4...v2.1.5)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-12-22 17:59:04 +01:00
Frank Denis e73459f558 Update deps 2021-12-22 14:00:37 +01:00
Frank Denis fbfc2d57a7 omit comparison to bool constant, can be simplified to !cloakedName.isIP
Reported by GitHub's code scanning
2021-12-16 10:43:40 +01:00
Frank Denis b9d6b22ce1 Align 2021-12-13 14:01:13 +01:00
Ian Bashford 1b6caba307
allow ptr queries for cloaked domains (#1958)
* allow ptr queries for cloaked domains

* multi ips per PTR returned + cleanup

* some string tidy up

* enable config file switch

* add cloaked ptr test

* enable cloak ptrs in test scenario

* fix reverse ipv6 ptr lookup

* added ipv6 cloaked ptr test
2021-12-13 14:00:13 +01:00
CNMan 27e93a53cf
minor typo fix (#1951) 2021-11-30 18:26:34 +01:00
Frank Denis 9e7221c31c Update deps 2021-11-05 13:29:16 +01:00
Frank Denis f6f63743ce Update go-minisign 2021-10-28 19:54:01 +02:00
Frank Denis 561e849889 Add a forwarding example for local reverse entries 2021-10-17 15:53:54 +02:00
a1346054 766e149699
Fix typo and alignment in example-dnscrypt-proxy.toml (#1915) 2021-10-10 19:19:45 +02:00
Frank Denis e2ada45598 Update deps 2021-10-09 13:35:18 +02:00
Frank Denis fc0ff3b26a Update ChangeLog 2021-09-27 17:59:16 +02:00
Frank Denis 88b174e5eb Sync deps 2021-09-27 17:49:02 +02:00
Frank Denis e1f3f58eed Bump 2021-09-27 15:51:48 +02:00
Frank Denis efcd392279 StaleResponseTtl -> StaleResponseTTL 2021-09-27 15:47:19 +02:00
Frank Denis 8da1b698ad Revert "Pasto, thanks to @lifenjoiner"
This reverts commit 14ef11447e.
2021-09-27 15:42:54 +02:00
Frank Denis 180e75bfdb Update deps 2021-09-27 12:35:04 +02:00
Frank Denis 77b27d9293 Merge branch 'master' of github.com:DNSCrypt/dnscrypt-proxy
* 'master' of github.com:DNSCrypt/dnscrypt-proxy:
  Make return value explicit
  Repair stale respones for DoH
  Define a constant for the TTL of stale responses
  Update plugin_cache.go (#1900)
2021-09-27 12:31:43 +02:00
Frank Denis 4c29840040 Revert "Print an error if a block/allow rule contains more than a pattern"
This reverts commit 6e8628f796.
2021-09-27 12:29:41 +02:00
Frank Denis b7704a05c5 Make return value explicit 2021-09-25 20:09:29 +02:00
Frank Denis d82021b545 Repair stale respones for DoH 2021-09-25 19:53:43 +02:00
Frank Denis e5608e08cf Define a constant for the TTL of stale responses 2021-09-25 19:53:25 +02:00
livingentity 2a3e59c4bf
Update plugin_cache.go (#1900) 2021-09-25 19:04:17 +02:00
Frank Denis 69019b7a80 generate-domains-blocklist: fix the rx_timed regex
Fixes #1896
2021-09-25 03:10:00 +02:00
Frank Denis 8e913d8bf9 Udate deps 2021-09-24 09:30:49 +02:00
Frank Denis 3bae61dbe1 Properly round the TTL 2021-09-24 09:26:31 +02:00
Frank Denis 5fedbe4c6e // +build -> //go:build 2021-09-23 19:16:26 +02:00
Frank Denis b2f26192e1 gofmt 2021-09-23 19:16:12 +02:00
Frank Denis a4684d3bf5 Round TTLs 2021-09-23 19:10:40 +02:00
Frank Denis 34f0caaa34 Merge branch 'master' of github.com:jedisct1/dnscrypt-proxy
* 'master' of github.com:jedisct1/dnscrypt-proxy:
  Enable HTTP/2 pings
  Remove leftovers from the daemonize option
  DoH/ODoH: strip optional port number when caching a hostname
  Bump actions/setup-go from 2.1.3 to 2.1.4 (#1843)
  fix minor typo in example config (#1847)
2021-09-23 18:38:50 +02:00
Frank Denis 75e917ae49 plugin_cache: update the response TTL, not the cached data
Fixes #1895
2021-09-23 18:37:40 +02:00
Frank Denis 8fc0ffc35f Enable HTTP/2 pings 2021-09-21 12:57:42 +02:00
Frank Denis 97a983c6b3 Remove leftovers from the daemonize option 2021-09-09 11:26:17 +02:00
Frank Denis 0f00cd27f9 DoH/ODoH: strip optional port number when caching a hostname
Fixes #1861
2021-09-06 12:02:56 +02:00
dependabot[bot] 8178f3419f
Bump actions/setup-go from 2.1.3 to 2.1.4 (#1843)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 2.1.3 to 2.1.4.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v2.1.3...v2.1.4)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-08-30 16:34:03 +02:00
Alison Winters d8358b795f
fix minor typo in example config (#1847) 2021-08-29 11:11:52 +02:00
Aaron b8c5790716
Add captive portal entry for dual stack setups (#1835)
For users with a dual stack set up at home (IPv4+native IPv6), Windows 21H1 will report that there is no Internet connection if this entry is missing from their captive portals file.

Signed-off-by: Aaron <admin@datahoarder.dev>
2021-08-20 17:32:32 +02:00
a1346054 f6a2d2ea44
Minor cleanup (#1822)
Make github recognize the licence properly
2021-08-18 11:08:18 +02:00
Frank Denis 68b0d87522 Remove comment decorators around license text
Apparently, this is confusing some license checking tool
2021-08-18 11:03:06 +02:00
Frank Denis bb5dc3b1fc Remove trailing blanks 2021-08-18 11:01:38 +02:00
Frank Denis 59b6b8359c Format as single lines 2021-08-17 20:46:01 +02:00
Frank Denis 785f86f50f powerman update 2021-08-17 16:56:09 +02:00
Frank Denis d8c4a90501 The party is over :) 2021-08-15 03:07:19 +02:00
Frank Denis 9cb89ae410 odoh.md has been deprecated 2021-08-14 13:01:12 +02:00
Frank Denis e83cb28ef5 Split ODoH servers and relays 2021-08-14 12:33:10 +02:00
Frank Denis 73dc3dd1d8 Update/merge ChangeLog 2021-08-13 19:27:11 +02:00
Frank Denis 35c82e3dcf Next will be 2.1.0 2021-08-13 19:20:27 +02:00
Frank Denis 9f0b409375 Update deps 2021-08-13 19:19:23 +02:00
Frank Denis 49fdb461d8 ECHO -> ECH 2021-08-12 19:44:33 +02:00
Frank Denis c9d5d81e6a Update toml dependency 2021-08-08 10:21:25 +02:00
Frank Denis 1052fa6323 serve-stale on overflow 2021-08-04 14:30:32 +02:00
Frank Denis c8a61abb79 Update comment 2021-08-04 14:27:58 +02:00
Frank Denis e64425b5e7 On overflow, only respond to cached/synthesized queries 2021-08-04 14:27:24 +02:00
Frank Denis da69583bd2 When we run out of connections, handle an extra one synchronously 2021-08-04 13:35:33 +02:00
Frank Denis d996e3424d No need to get the time if the connection is refused 2021-08-04 13:23:21 +02:00
Frank Denis b4a073f54f Typo 2021-08-03 11:24:16 +02:00
Frank Denis 0ca90dd8cc xtransport: set a default error status code 2021-07-31 13:21:45 +02:00
Frank Denis 026c42424f Workaround for ODoH relays not properly forwarding the status code
Some ODoH relays return a 200 status code even when the upstream
server returns something different. This is an issue after a key
update, where a 401 code is expected.

Handle empty responses with a 200 status code as a response with
a 401 code as a workaround until these relays are fixed.
2021-07-31 12:54:23 +02:00
Frank Denis cedd4f3b54 xtransport: properly forward the status code on error 2021-07-31 12:38:10 +02:00
dependabot[bot] d3b1976208
Bump actions/setup-go from 1 to 2.1.3 (#1773)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 1 to 2.1.3.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v1...v2.1.3)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-30 20:39:48 +02:00
Frank Denis bc529f0076 Update deps 2021-07-30 20:39:23 +02:00
Frank Denis 796a7f6d31 Add an example for blocking private relay 2021-07-17 14:22:10 +02:00
Frank Denis 03e1916527 🥂 2021-07-16 18:51:03 +02:00
Frank Denis d35c1c3cb2 Lower reject_ttl even more 2021-07-16 16:46:50 +02:00
Frank Denis 8b3b7d38ac Set ttl to reject_ttl for HINFO refused responses
Also lower the example TTL
2021-07-16 16:40:21 +02:00
Frank Denis 9acf257fe5 Merge branch 'master' of github.com:DNSCrypt/dnscrypt-proxy
* 'master' of github.com:DNSCrypt/dnscrypt-proxy:
  Update dependabot.yml (#1770)
2021-07-03 10:57:19 +02:00
Frank Denis 5a091c6da4 Update deps 2021-07-03 10:56:53 +02:00
Jauder Ho 59690da355
Update dependabot.yml (#1770) 2021-07-03 09:42:19 +02:00
Frank Denis f033bb3034 miekg/dns update 2021-06-23 09:45:43 +02:00
Frank Denis 4caa7b6d64 Verbose 2021-06-12 14:48:02 +02:00
Frank Denis 6117a1111c CI: use odoh-crypto-sx which is the only ODoH server yet 2021-06-12 14:21:22 +02:00
Frank Denis 9bea0e8f20 Nits 2021-06-12 14:16:20 +02:00
Frank Denis da9c95ec5c up 2021-06-12 14:08:22 +02:00
Frank Denis b472fb3b21 Bump 2021-06-12 14:03:26 +02:00
Frank Denis 5fb2901dbc Fuzz the stamps parser 2021-06-11 22:20:54 +02:00
Frank Denis ccddb18424 Time to start fuzzing 2021-06-11 22:13:58 +02:00
Frank Denis 1b03ac817e ODoH: supoprt config version 0x0001 in addition to 0xff06 2021-06-11 21:18:05 +02:00
Frank Denis a34258c3aa Nits 2021-06-08 12:07:35 +02:00
Frank Denis 95c9fa75f8 Bump 2021-06-08 11:00:01 +02:00
Frank Denis d6be6f97ea Update ChangeLog 2021-06-08 10:59:26 +02:00
Frank Denis a85a003d2b Filter relays by compatible type before selecting them
Fixes #1739
2021-06-08 10:52:06 +02:00
Frank Denis 5a9a6467df Correctly check for empty/wrong relays 2021-06-08 10:27:03 +02:00
Frank Denis ec581597a2 Require ODoH relays to be present
ODoH target stamps don't include certificate hashes; they are not
meant to be used directly.
2021-06-08 10:19:02 +02:00
Frank Denis 33ed882efe Warn if fallback_resolvers is still in use 2021-06-08 09:53:53 +02:00
Frank Denis b39232e996 this -> that 2021-06-08 01:14:11 +02:00
Frank Denis 9ebb90b22e fallback -> bootstrap 2021-06-08 00:44:06 +02:00
Frank Denis b1dd11be72 Dash 2021-06-07 19:05:15 +02:00
Frank Denis 6076e2dd03 www.msftncsi.com IPs update 2021-06-07 18:47:31 +02:00
Frank Denis a0ecfd6a77 Thanks Chris! 2021-06-07 18:36:37 +02:00
Frank Denis 6c3cec2753 Accept warning for the direct ODoH test 2021-06-07 18:32:20 +02:00
Frank Denis d0e27a1366 Update ChangeLog 2021-06-07 18:25:52 +02:00
Frank Denis d5e9ed3aa9 Don't hardcode the HPKE cipher 2021-06-07 18:16:15 +02:00
Frank Denis 72a354caf9 Update go-hpke-compact 2021-06-07 18:11:58 +02:00
Frank Denis 45d3afc8f9 Call ObliviousDoHQuery() on the initial test 2021-06-07 17:32:34 +02:00
Frank Denis e7f017c592 ODoH: try POST first, even without a relay 2021-06-07 17:19:56 +02:00
Frank Denis 4eab70b770 Indentation matters 2021-06-07 16:44:55 +02:00
Frank Denis 9263d1a01c CI: odoh relays are not servers 2021-06-07 16:15:29 +02:00
Frank Denis f8144f8db6 CI stamp update 2021-06-07 16:13:27 +02:00
Frank Denis 98ab4aee23 Update deps 2021-06-07 15:54:56 +02:00
Frank Denis a2ebe0c4a4 dnscrypt-proxy/odoh.go -> dnscrypt-proxy/oblivious_doh.go 2021-06-07 15:53:11 +02:00
Frank Denis e11b8b0c04 + ODoH 2021-06-07 15:52:52 +02:00
Frank Denis 527c38ebc4 Update CI 2021-06-07 14:27:22 +02:00
Frank Denis 083fa0ad3c Add an extra retry since ODoH servers are currently unstable 2021-06-07 13:49:37 +02:00
Frank Denis f5a69c3bdc Reduce delay 2021-06-07 13:46:44 +02:00
Frank Denis 9e96bbc20b Continue, don't return 2021-06-07 13:44:08 +02:00
Frank Denis a181a23263 Send a dummy initial query before RTT measurement in ODoH 2021-06-07 13:42:33 +02:00
Frank Denis fad415f05a Update example documentation 2021-06-07 13:37:08 +02:00
Frank Denis 29613096da ODoH servers should not require a static configuration 2021-06-07 13:21:58 +02:00
Frank Denis 7980af6f46 Error propagation 2021-06-07 12:38:36 +02:00
Frank Denis 94151f9f96 Use ODoH relays in probes 2021-06-07 12:23:26 +02:00
Frank Denis a11da2d4fb ODoH: check certificate hashes 2021-06-07 12:09:27 +02:00
Frank Denis e0483bbb27 Pretend not to always use the first ODoH config 2021-06-07 12:06:36 +02:00
Frank Denis b35e27bd51 Shuffle ODoH target configs and use different NX queries 2021-06-07 12:05:42 +02:00
Frank Denis 4a4f69edb7 ODoH: only store working configurations
Actually, we only store the first one right now.

We should at least randomize them.
2021-06-07 12:02:21 +02:00
Frank Denis 96b05e57ca Preliminary propoer ODoH initialization 2021-06-07 11:47:11 +02:00
Frank Denis 56f2e9adcc server_name is ignored for x509 certs 2021-06-07 11:27:33 +02:00
Frank Denis dc99f1bc2c If you need this, implement it 2021-06-07 11:26:37 +02:00
Frank Denis 0d81fa2796 Remove doh_client_x509_auth stuf from fetchServerInfo
It doesn't belong there, and that feature doesn't do what it's
documented to do. It sets client certificates globally instead of
doing it per server.
2021-06-07 11:23:48 +02:00
Frank Denis 402860e2a6 ODoH broke DNSCrypt relays with wildcards - repair 2021-06-07 11:06:41 +02:00
Frank Denis cd45f64c18 ODoH: until relay auto selection is implemented, pick random ones 2021-06-07 11:00:21 +02:00
Frank Denis 27a82c54c8 ODoH: handle relay IP addresses 2021-06-07 10:46:01 +02:00
Frank Denis dce4db4c86 Construct net.URL directly 2021-06-07 10:08:55 +02:00
Frank Denis 525927e797 Don't use net/http 2021-06-07 10:05:20 +02:00
Frank Denis 3159bc3191 CI: use odoh-crypto-sx and odohrelay-fastly for testing ODoH 2021-06-06 22:42:33 +02:00
Frank Denis e57d5173e9 Support GET in ODoH targets 2021-06-06 01:22:48 +02:00
Frank Denis f542edacaa ODoH: until detection is in place, without a relay, prefer GET 2021-06-06 01:15:28 +02:00
Frank Denis 92792f0e8b Prevent remotely triggerable crash in ODoH config parser 2021-06-06 01:05:14 +02:00
Frank Denis 1cdb71cd7c Avoid double slashes in ODoH relay URLs 2021-06-06 01:01:39 +02:00
Frank Denis d2947cad75 Unbreak compilation 2021-06-06 00:14:56 +02:00
Frank Denis 3cf5c1ab8e Limit the number of ODoH target configs 2021-06-05 18:35:45 +02:00
Frank Denis 06135b6141 Reduce MaxHTTPBodyLength 2021-06-05 18:29:13 +02:00
Frank Denis 44f3db31ee Just a safeguard 2021-06-05 17:57:48 +02:00
Frank Denis 0a1d3b725c Rename ODoHTarget to ODoHTargetConfig for clarity 2021-06-05 17:49:19 +02:00
Frank Denis 2cf29f9fab CI: check the tests after running them
The ODoH tests don't seem to pass.
2021-06-05 17:04:35 +02:00
Frank Denis e27419f73d x509.SystemCertPool() may fail 2021-06-03 20:59:05 +02:00
Frank Denis ddcc40c954 Hardcode Let's Encrypt ISRG X1 cert
Some operating systems don't include it yet.

Thanks to @rs for the heads up
2021-06-03 12:48:33 +02:00
Frank Denis 14ef11447e Pasto, thanks to @lifenjoiner 2021-05-13 10:30:57 +02:00
Frank Denis 6e8628f796 Print an error if a block/allow rule contains more than a pattern
... and it is not a time range.
2021-05-12 17:43:13 +02:00
Frank Denis 31f4d7aa03 Do not ignore ODoH encryption errors 2021-05-09 16:16:38 +02:00
Frank Denis f9cecd1215 Update miekg/dns 2021-05-07 20:28:25 +02:00
Frank Denis 30779a40a6 Remove sysctl list, which is now updated any more
Fixes #1694
2021-05-01 01:16:35 +02:00
Frank Denis 367b5062ec Add another IP block list 2021-04-30 20:51:22 +02:00
Frank Denis d751781996 Update deps 2021-04-27 14:28:39 +02:00
Frank Denis 58e1410e66 Nits 2021-04-17 16:42:18 +02:00
Frank Denis e2e32406fb Improve ODoH log messages 2021-04-17 16:41:10 +02:00
Christopher Wood 23588733ae
Synchronously update the target configuration upon failure. (#1671)
* Synchronously update the target configuration upon failure.

* Notice a serverInfo failure when key updates fail.

* Add server name to debug logs.
2021-04-17 16:35:55 +02:00
Frank Denis 9759dd90a2 Limit the number of dependabot pull requests 2021-04-14 18:26:38 +02:00
milgradesec 754c2bdb93
Create dependabot.yml (#1670) 2021-04-14 18:25:51 +02:00
Alison Winters eda8dd5181
replace TrimFunc(s, IsSpace) with TrimSpace for ASCII optimization (#1663) 2021-04-05 11:46:57 +02:00
Christopher Wood 03413eae2f
Add ODoH test files. (#1656) 2021-03-30 15:11:09 +02:00
Frank Denis 81692a3a80 Update xsecretbox again 2021-03-30 13:38:50 +02:00
Frank Denis 8213a96cd5 Revert "Remove the need for two chacha20 implementations"
This reverts commit 8e8a4bd024.
2021-03-30 12:29:07 +02:00
Frank Denis cee31b646e Update Go version in CI 2021-03-30 11:57:10 +02:00
Frank Denis 8e8a4bd024 Remove the need for two chacha20 implementations 2021-03-30 11:54:04 +02:00
Frank Denis 3efbacc0d4 Rename 2021-03-30 11:53:59 +02:00
Christopher Wood c748f93752 Add ODoH support. (#1653) 2021-03-30 11:53:51 +02:00
Frank Denis f7219b2bfa Recommend discussions 2021-03-30 10:56:01 +02:00
Frank Denis 09e5812a23 Send info messages to stdout if an output file has been specified
Fixes #1651
2021-03-27 18:39:24 +01:00
Frank Denis 873522c7f7 Add discussions link 2021-03-27 01:57:20 +01:00
Frank Denis 789e5bf162 ... 2021-03-27 01:51:44 +01:00
Frank Denis 795c56f518 Shorten 2021-03-27 01:31:24 +01:00
Frank Denis 4201e7f373 Rename 2021-03-27 01:28:53 +01:00
Frank Denis 1e3f03ab0c ... 2021-03-27 01:19:01 +01:00
Frank Denis 6430ae942c Nits 2021-03-26 09:49:25 +01:00
Frank Denis 76392285e2 Nits 2021-03-26 00:02:54 +01:00
Frank Denis 1ca67270b8 pluralize 2021-03-26 00:01:34 +01:00
Frank Denis a6ea636117 Rename questions to protocol 2021-03-25 23:50:34 +01:00
Frank Denis 0f7208f7ef up 2021-03-25 23:47:55 +01:00
Frank Denis 7d10a2c84d Update issue template 2021-03-25 23:42:10 +01:00
Frank Denis 10ded3d9f2 Update deps 2021-03-22 22:57:07 +01:00
Frank Denis 54d85d7298 Filters don't apply to static entries 2021-03-12 20:05:58 +01:00
Frank Denis 84ea8dc9b0 Merge branch 'master' of github.com:DNSCrypt/dnscrypt-proxy
* 'master' of github.com:DNSCrypt/dnscrypt-proxy:
  Fix domain blocklist config example (#1632)
2021-03-08 15:36:53 +01:00
Frank Denis b1e96b69fd Save 1.4 MiB of memory 2021-03-08 15:36:42 +01:00
synthtech 6bdeaaa70c
Fix domain blocklist config example (#1632) 2021-03-02 01:04:48 +01:00
Frank Denis 09866acdb5 New miekg/dns to fix a resource leak (not affecting us) 2021-02-26 10:38:52 +01:00
Frank Denis 1ae2281588 Update miekg/dns 2021-02-24 15:38:04 +01:00
Frank Denis 34909babfb Typo 2021-02-20 19:11:06 +01:00
Frank Denis bbf4094508 Deps update 2021-02-20 18:55:58 +01:00
Frank Denis 1a82786e07 Merge branch 'master' of github.com:DNSCrypt/dnscrypt-proxy
* 'master' of github.com:DNSCrypt/dnscrypt-proxy:
  Update codeql-analysis.yml (#1612)
2021-02-20 18:51:20 +01:00
Frank Denis c500287498 Rename fallback_resolvers to bootstrap_resolvers
Clarify what they are used for.

Remove the legacy `fallback_resolver`.
2021-02-20 18:50:42 +01:00
miracle091 1795c7be3a Update codeql-analysis.yml (#1612)
using a custom name for the job and removed a step not more needed

Signed-off-by: Frank Denis <github@pureftpd.org>
2021-02-15 01:17:51 +01:00
miracle091 1b4045a098
Update codeql-analysis.yml (#1612)
using a custom name for the job and removed a step not more needed
2021-02-08 17:17:23 +01:00
Frank Denis b131708cd6 Update miekg/dns 2021-02-02 09:48:11 +01:00
Frank Denis 472ab609e4 Update miekg/dns to v1.1.37 2021-01-30 19:29:12 +01:00
Frank Denis 6517bae0c3 Disable full hosts.oisd.nl, replace with the shorter version 2021-01-29 16:20:32 +01:00
Frank Denis 5d6b35213c Add the file name ;) 2021-01-22 18:39:04 +01:00
Frank Denis 96ba551836 Revert "The source tests are completely brok4n :("
This reverts commit a76ffb0143.
2021-01-22 17:50:01 +01:00
Frank Denis d8ff82cf45 IP addresses of queries over local DoH are now logged 2021-01-22 16:13:56 +01:00
lifenjoiner a9cf16b33e
Fix: Randomize source URLs (#1593) 2021-01-22 15:06:49 +01:00
Frank Denis 0ab9e30fa9 Merge branch 'master' of github.com:DNSCrypt/dnscrypt-proxy
* 'master' of github.com:DNSCrypt/dnscrypt-proxy:
  The source tests are completely brok4n :(
  Explain how to listen to all IP addresses
  In the query log, consider everything that's not UDP as TCP
2021-01-22 09:16:56 +01:00
Frank Denis d0f981156b Add the base inherited fd to the application logging fd
Fixes #1585
2021-01-22 09:15:40 +01:00
Frank Denis a76ffb0143 The source tests are completely brok4n :(
Fix at least the fact that URLs are now randomized
2021-01-21 14:59:34 +01:00
Frank Denis 53c8e25352 Explain how to listen to all IP addresses
Fixes #1588
2021-01-21 14:38:36 +01:00
Frank Denis ac0b9cdfe8 In the query log, consider everything that's not UDP as TCP
Fixes #1589
2021-01-21 14:35:06 +01:00
Frank Denis 213695f651 Update deps 2021-01-19 23:05:16 +01:00
Ian Bashford fcd9225121
Threadsafe update (#1579)
* threadsafe update for relays

* locks around registeredRelays
2021-01-09 22:44:32 +01:00
Frank Denis 85d268f2b9 Randomize source URLs
Fixes #1577
2021-01-04 16:41:39 +01:00
Frank Denis 19dbd13c1b Explain the example allowlist 2021-01-03 18:18:46 +01:00
Frank Denis 3b61f50fa9 Add NOT_READY 2021-01-03 18:12:30 +01:00
Frank Denis daa1f3d3b1 Add a NOT_READY return code 2021-01-03 18:09:03 +01:00
Frank Denis f9ec0a9c09 Deep copy cached responses 2021-01-03 17:37:19 +01:00
Frank Denis 3a5585f8a1 Remove test leftover 2021-01-03 17:16:04 +01:00
Frank Denis 1f7b247138 Lower severity 2021-01-03 17:00:39 +01:00
Frank Denis bc42eda1c8 Shorten 2021-01-03 16:58:21 +01:00
Frank Denis 5c3db0dcf5 Try to rely on proxy.serversInfo rather than proxy.registeredServers
With the introduction of background updates, I'm a little bit worried
about race conditions that can happen when a new server or relay is
registered (or even when a stamp changes).
2021-01-03 16:40:38 +01:00
Frank Denis fbd598f027 Nits 2021-01-03 16:22:23 +01:00
Frank Denis 00abe06676 up 2021-01-03 16:03:29 +01:00
Frank Denis 197f13ea0f Fix typo and update message 2021-01-03 16:00:02 +01:00
Frank Denis 5861a58089 Nits 2021-01-03 14:44:02 +01:00
Frank Denis 7c6f0823ea Doc update 2021-01-03 14:41:23 +01:00
Frank Denis 7b962dff98 Nits 2021-01-03 13:58:08 +01:00
Frank Denis 5a079a3eb9 Resolve: print host info 2021-01-03 13:49:43 +01:00
Frank Denis 1e10251407 Only find the farthest route on wildcards 2021-01-03 13:33:51 +01:00
Frank Denis 0f54b2b34c Automatic relay selection 2021-01-03 13:01:44 +01:00
Frank Denis 79cb9451bd Remove log messages that are not really needed 2021-01-02 22:59:21 +01:00
Frank Denis 662b4c0c62 Make staticcheck happier 2021-01-02 22:55:16 +01:00
Frank Denis 9e4a2fc6e1 Format 2021-01-02 22:38:26 +01:00
Frank Denis af80f57a58 Increase timeouts on retry 2021-01-02 22:31:47 +01:00
Frank Denis 996ea0dd89 Don't print the whole response 2021-01-02 22:28:00 +01:00
mibere 1ceb2b1fbd
New download mirror (#1570) 2021-01-02 22:25:41 +01:00
glitsj16 8a9e61d6cd
Fix typo (#1571) 2021-01-02 22:24:11 +01:00
Frank Denis fc82a6c05e Revamp dnscrypt-proxy -resolve 2021-01-02 22:20:52 +01:00
Frank Denis a584effbe9 Remove HTTPS record creation 2021-01-02 19:05:18 +01:00
Frank Denis 7ec5ed127e Repair server randomization 2021-01-02 19:04:53 +01:00
Frank Denis 5398dab58e Lower log level 2021-01-02 17:04:59 +01:00
Frank Denis 93733971a9 Reformat ChangeLog 2021-01-02 16:36:06 +01:00
Frank Denis 930dcd2f8e Update ChangeLog 2021-01-02 16:33:49 +01:00
Frank Denis 8f0b38f4c0 Double comments 2021-01-02 15:37:41 +01:00
Frank Denis 9f5c034c3d Add staticcheck.conf 2021-01-02 15:36:30 +01:00
Frank Denis d2517bd42e Update .gitignore 2021-01-02 15:23:08 +01:00
Frank Denis ee5711fbd6 Disable captive portals by default 2021-01-02 15:22:58 +01:00
Frank Denis 56acb7b5ab Log when the ECS plugin is enabled 2021-01-02 15:10:30 +01:00
Frank Denis a713e1a517 Move captive portals config to a dedicated section
Add examples
2021-01-02 15:10:04 +01:00
Frank Denis dfee2aa546 Merge branch 'master' of github.com:DNSCrypt/dnscrypt-proxy
* 'master' of github.com:DNSCrypt/dnscrypt-proxy:
  add tests for statics (#1569)
2021-01-02 13:20:54 +01:00
Ian Bashford 7afc43ab35
add tests for statics (#1569) 2021-01-02 13:11:26 +01:00
Frank Denis 45829aaa45 Update deps 2021-01-02 12:53:28 +01:00
Frank Denis 3b18058ae5 Add IPv6 cleanbrowsing servers 2021-01-02 12:53:10 +01:00
Ian Bashford 5b8c9c495f
register servers after loading statics (#1568) 2021-01-02 11:57:18 +01:00
Frank Denis b8d17debfd Remove final stops from errors 2021-01-02 11:16:12 +01:00
Frank Denis 2cdafa4bb3 Remove debug leftover 2021-01-02 10:24:32 +01:00
Frank Denis f245189f02 Handle captive portal names after coldstart 2021-01-01 21:39:17 +01:00
Frank Denis c308727d15 Add unsigned macOS packages 2021-01-01 17:55:29 +01:00
Ian Bashford 87fb44a588
Run from in memory cache updates (#1564)
* ConfigFile change to allowlist and blocklist

* revised names and warnings

* consistent file naming in kebab case, and generic use of blocklist and allowlist in cmoments for clarity

* update ci files

* impose maximum delay and document

* live update of servers

* update for source prefixes

* fixup test

* stop registerServers being called twice at startup

* prevent double registration at startup

* tidy function signature for loadSource

Co-authored-by: Ian Bashford <ianbashford@gmail.com>
2021-01-01 14:04:12 +01:00
Frank Denis f19b14e74c Replace the logo with a version that looks better on a dark background
Contributed by @jacob755, thanks!

Closes #1541
2021-01-01 14:01:14 +01:00
Frank Denis 3087eff6d3 CI: update Go 2021-01-01 13:55:14 +01:00
Frank Denis e40e42edf5 Update deps 2021-01-01 13:31:07 +01:00
Frank Denis e519dd17bc 2021 2021-01-01 00:01:59 +01:00
Frank Denis 06cf3a1311 Remove another defunct blocklist source
Fixes #1566
2020-12-31 23:46:06 +01:00
Frank Denis a3ef181e4f Update deps 2020-12-26 18:06:52 +01:00
Frank Denis 254a4a6532 Use , not | to match multiples items
Fixes #1558
2020-12-26 17:55:31 +01:00
Frank Denis 2baabbca8a Ignore regexes in time-based entries
Fixes #1548
2020-12-20 13:49:08 +01:00
Frank Denis 859710d6f5 RIP malwaredomains and malwaredomainlist
Fixes #1549
2020-12-19 16:39:49 +01:00
Frank Denis c17461ed42 generate-domains-blocklist: use the same name for the directory and the tool 2020-12-18 21:27:33 +01:00
Frank Denis 77f81cc8c2 Add recommendation for fallback resolvers in the example config
This is the same recommendation as c4d9860577/dnscrypt-proxy/serversInfo.go (L429-L432)

that has been here for a while as a comment, but having it in the configuration
file gives it more visibility.
2020-12-17 11:10:35 +01:00
Frank Denis c4d9860577 cloak plugin: return multiple the entire set of IPv4 or IPv6 addresses
Fixes #1547
2020-12-17 09:47:44 +01:00
Frank Denis a8a0677ea9 h1 -> http/1.x 2020-12-17 01:13:11 +01:00
Frank Denis 7d851366bb Do not only warn if the protocol is empty 2020-12-17 01:08:06 +01:00
Frank Denis 85e7dddc9b Move a few DNS things to dnsutils 2020-12-12 23:09:15 +01:00
Frank Denis a24b009667 Filler 2020-12-12 22:35:51 +01:00
Frank Denis d700ab6085 Nits 2020-12-12 22:19:09 +01:00
Frank Denis a384011e71 Support relays in static entries 2020-12-12 21:57:04 +01:00
Frank Denis 7f46f4820c Don't use distinct pointers for UDP and TCP relay addresses 2020-12-12 21:18:32 +01:00
Frank Denis ab8ebead34 Remove support for {ip|host}[:port] syntax for specifying a relay
It's very likely that no one ever used it.
2020-12-12 20:46:40 +01:00
Frank Denis 70bffc73f1 go-dnsstamps update 2020-12-11 14:14:09 +01:00
Frank Denis fc785f9f69 Print details when an unsupported protocol is found 2020-12-11 12:26:05 +01:00
Frank Denis d6d8c37ef6 Format 2020-12-11 12:25:57 +01:00
Frank Denis 54b0a5a18d go-dnsstamps update 2020-12-10 22:57:31 +01:00
Frank Denis 3ae3fe2f18 x/crypto update 2020-12-10 19:00:57 +01:00
Frank Denis 0d260d0e2d pattern_matcher: check exact matches first 2020-12-07 12:58:05 +01:00
Frank Denis 1239e64cd9 Correctly check for HTTPS type 2020-12-01 16:08:33 +01:00
Frank Denis b7dfdb1372 Factorize 2020-12-01 16:08:10 +01:00
Frank Denis 24a9539d08 Filter names on SVCB and HTTPS records in addition to CNAME 2020-12-01 16:00:18 +01:00
Frank Denis 5c1e3f0b15 Update deps 2020-12-01 14:46:14 +01:00
Frank Denis 9c50963f69 Add Captain Miao ad list, whitelist mobiledl.adobe.com 2020-12-01 08:46:15 +01:00
Frank Denis 01e60ab31b Add localhost to the allowlist 2020-12-01 08:37:03 +01:00
Frank Denis df8cfe3f3c dnsdist has been fixed 2020-11-30 14:31:30 +01:00
mibere f5827520d8
download mirror download.dnscrypt.net (#1527)
Files are locally hosted on download.dnscrypt.net. A cronjob updates the files every 3 hours, source is https://download.dnscrypt.info
download.dnscrypt.net has IPv4 and IPv6, DNSSEC, HTTPS
2020-11-27 22:35:27 +01:00
Frank Denis f9c11f0897 Allow arbitrary addresses to be set in listen_addresses
Only works on OpenBSD/FreeBSD/Linux (including Android)

Fixes #1362
2020-11-25 19:23:30 +01:00
Frank Denis 02a6ca1098 Keep .home in forwarding rules 2020-11-25 01:39:11 +01:00
petercooperjr 715c32f0fc
Change example forwarding rule to match recommended .home.arpa TLD (#1523)
The ".home" TLD was proposed at one point, and while it's probably not going to actually ever get delegated it's not best practice to just start using your own TLD. The .home.arpa domain has been specifically set aside for use in home networks (RFC 8375) and is probably the better example to put here.
2020-11-25 01:38:14 +01:00
Frank Denis 9e4131c6f7 Add ipv6.download.dnscrypt.info for testing 2020-11-23 21:10:22 +01:00
Frank Denis cae3719464 CI: verify that queries sent over local DoH are properly logged 2020-11-18 20:22:16 +01:00
Frank Denis 7e3e9aa5d2 New version of kardianos/service 2020-11-18 10:19:58 +01:00
Ian Bashford 90a9a9d992
allowed ips plugin (#1510) 2020-11-15 20:59:58 +01:00
Frank Denis 6b6c6753aa Revert struct packing changes for the configuration
structlop is nice, but strips renames
2020-11-14 15:34:03 +01:00
Frank Denis 4fa643ef4d Repack structures to save some memory 2020-11-14 14:46:59 +01:00
Frank Denis e6fdb08d3d Update deps 2020-11-06 07:43:29 +01:00
lifenjoiner 078f69357e
Update example-dnscrypt-proxy.toml (#1489)
* Update lb_strategy usage

* Update example-dnscrypt-proxy.toml
2020-10-21 14:21:39 +02:00
Frank Denis 6ee164a3c9 Update miekg/dns and other dependencies 2020-10-19 16:46:12 +02:00
Frank Denis 7a03369d01 Debug log certificate TTL 2020-10-12 17:58:08 +02:00
Frank Denis d0674ef4d2 Cleanup go.sum 2020-10-12 10:38:44 +02:00
Frank Denis 2b826bbb64 Update deps 2020-10-12 10:35:37 +02:00
Ian Bashford f2700874fd
user-friendly comments - follow up to #1412 (#1486) 2020-10-04 21:05:24 +02:00
Frank Denis 7b7107902b Update deps 2020-09-21 02:15:51 +02:00
Frank Denis 8b72e58656 Make key exchange behaviors consistent 2020-09-21 02:14:17 +02:00
Frank Denis e54056bc38 Update deps 2020-09-18 18:19:55 +02:00
Frank Denis 687fe27371 Nits 2020-09-18 00:14:50 +02:00
Frank Denis 272984a640 Add support for EDNS-client-subnet
Fixes #1471
2020-09-18 00:11:26 +02:00
Frank Denis 4d7f253e6b Don't spawn new connections if we are full 2020-09-17 00:49:49 +02:00
Frank Denis 8411e5a91b Revert "Error out if the dns64 plugin is enabled without listening sockets"
This reverts commit b02649f774.
2020-09-17 00:45:48 +02:00
Frank Denis 4eab88c017 plugin_dns64: don't send queries to self
Fixes #1477
2020-09-17 00:44:37 +02:00
Frank Denis b460ca9fa8 Simplify hasAAAAQuestion 2020-09-17 00:24:04 +02:00
Frank Denis b02649f774 Error out if the dns64 plugin is enabled without listening sockets 2020-09-17 00:19:00 +02:00
Frank Denis c74b993cbb dns64: check the original question, not the returned one 2020-09-17 00:10:11 +02:00
Frank Denis 26505ab560 Merge declaration and assignment 2020-09-13 20:24:06 +02:00
Frank Denis 018d8412be Format generate-domains-blocklist.py with Black 2020-09-12 23:34:39 +02:00
Frank Denis 5a1b87130d Use single quotes for strings
Fixes #1466
2020-09-03 21:21:05 +02:00
Ian Bashford a510b97d86
Update to generate-domains-blocklist.py (#1412)
* ConfigFile change to allowlist and blocklist

* revised names and warnings

* consistent file naming in kebab case, and generic use of blocklist and allowlist in cmoments for clarity

* update ci files

* message about deprecation of -w

Co-authored-by: Ian Bashford <ianbashford@gmail.com>
2020-09-01 23:05:25 +02:00
Frank Denis d175642df3 Quad9 seems to have upgraded their dnsdist version! 2020-08-31 17:13:14 +02:00
Frank Denis f678f39535 CHEF-KOCH lists have moved to Gitlab 2020-08-31 16:06:30 +02:00
Frank Denis d5c3c6747e Revert "CHEF-KOCH is not on GitHub any more :("
This reverts commit b448324e1a.
2020-08-31 16:05:51 +02:00
Frank Denis b448324e1a CHEF-KOCH is not on GitHub any more :(
Fixes #1462
2020-08-30 17:16:49 +02:00
IceCodeNew fd98ced18d
fix `bblck.me` domain not exist error (#1447) 2020-08-15 08:58:59 +02:00
Frank Denis fa5c55c64a Debug log query names 2020-08-09 13:09:37 +02:00
Frank Denis dadb38c32e Lower severity 2020-08-05 15:50:48 +02:00
Frank Denis 0ac96fec30 Add some logging back to fetchDoHServerInfo() 2020-08-05 15:39:30 +02:00
Frank Denis b583fb5314 Turns out that the "test." zone is directly served by the Tencent CDN
without hitting the actual resolvers.

So, we need to use a different test zone.
2020-08-05 15:03:16 +02:00
Frank Denis f3157b0a42 Check DoH servers with a query to a random name
The issue with benchmarking DoH servers is that some responses can
be directly served by a CDN, while others require a round trip to
the origin that can be significantly more expensive.

Random padding was an attempt at mitigating this. Unfortunately,
some servers (Tencent) ignore the padding. We end up with a query
for the root zone served by the Tencent CDN very quickly, but
anything else is orders of magnitude slower.

So, measure a query within the reserved "test." zone instead.
Caching resolvers should either know that "test." is undelegated,
or have it in their negative cache already, so this is unlikely to
trigger an actual query to authoritative servers.

Take it as an opportunity to check that we don't get anything but
a NXDOMAIN response for nonexistent domains.
2020-08-05 14:54:14 +02:00
Frank Denis 60d4c98f31 Unbreak running without a captive portal configuration file 2020-08-04 00:50:59 +02:00
Frank Denis 5843e49188 Sync vendor 2020-08-03 18:23:57 +02:00
dependabot-preview[bot] 1ed325b5c5
Bump github.com/miekg/dns from 1.1.30 to 1.1.31 (#1432)
Bumps [github.com/miekg/dns](https://github.com/miekg/dns) from 1.1.30 to 1.1.31.
- [Release notes](https://github.com/miekg/dns/releases)
- [Changelog](https://github.com/miekg/dns/blob/master/Makefile.release)
- [Commits](https://github.com/miekg/dns/compare/v1.1.30...v1.1.31)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-03 18:23:09 +02:00
Frank Denis f7f84fd871 Add ipv4only.arpa 2020-08-03 18:20:12 +02:00
Frank Denis 4424602e39 Start experimenting with better support for captive portals
MacOS (and probably Windows and other systems) tries to fetch a URL
before marking a network interface as available.

During this time, applications cannot use the interface at all, not
even bind their address.

When DNS queries are sent to dnscrypt-proxy, this causes the system
to wait for a response that can't come from the network, since we
hit a dead lock here.

The only option is to return hard-coded responses directly until
te interface is available.

The same captive portal configuration file can also serve a different
purpose.

Once the network is available, captive portal detection may not
work as expected if the answer is cached for too long. In fact, it
probably can't work at all since routers can't hijack DNS queries.

Once thing we can do is redirect the list of names used for captive
portal detection to the fallback resolvers. This may allow detection
to work as expected while still using a secure channel for all
other queries.
2020-08-03 18:05:42 +02:00
Frank Denis 210ba8c60f coldstart experiment 2020-08-03 15:40:39 +02:00
Frank Denis 1c52451025 Minor deps update 2020-07-31 16:01:41 +02:00
Frank Denis 162b51c791 Remove confusing "Domain exists: probably not, or blocked by the proxy" 2020-07-30 19:25:17 +02:00
Alison Winters 617629c180
initialize the log file before reporting config errors (#1426)
* initialize the log file before reporting config errors

* consistently return error instead of calling dlog.Fatal when parsing config
2020-07-27 16:01:44 +02:00
Frank Denis d3ff3a6bb1 Remove facebookgo/{atomicfile,pidfile}
Fixes #1411
2020-07-10 14:37:35 +02:00
Frank Denis 1a34c8d5ff Add max-stale cache control directive to requests 2020-07-09 21:42:35 +02:00
Frank Denis 8dd4612ea7 Don't use Lumberjack for non-regular files
Fixes #1407
2020-07-08 13:48:04 +02:00
Frank Denis 04b49fd355 Rename the generate-domains-blacklists folder
This is going to break all the scripts using this in a cron job
after an update :/
2020-07-08 12:07:23 +02:00
Frank Denis 77a27a46a4 Rename the python script name in the example config 2020-07-08 12:05:42 +02:00
Ian Bashford af564522ec
Further block/allow updates (#1406)
* ConfigFile change to allowlist and blocklist

* revised names and warnings

* consistent file naming in kebab case, and generic use of blocklist and allowlist in cmoments for clarity

* update ci files

* further allow/blocklist updates

* improve language in comments

Co-authored-by: Ian Bashford <ianbashford@gmail.com>
2020-07-08 12:01:06 +02:00
Frank Denis 10710def50 Make loggers io.Writer implementations, not directly lumberjack objects 2020-07-08 11:36:58 +02:00
Frank Denis 7bec554709 Remove fritz.box after all 2020-07-08 11:03:45 +02:00
Frank Denis 45b915882a Update deps 2020-07-07 14:12:02 +02:00
dependabot-preview[bot] 29c2b76edd
Bump github.com/miekg/dns from 1.1.29 to 1.1.30 (#1403)
Bumps [github.com/miekg/dns](https://github.com/miekg/dns) from 1.1.29 to 1.1.30.
- [Release notes](https://github.com/miekg/dns/releases)
- [Changelog](https://github.com/miekg/dns/blob/master/Makefile.release)
- [Commits](https://github.com/miekg/dns/compare/v1.1.29...v1.1.30)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-07-07 13:27:53 +02:00
hugepants 038ebea0ed
Update broken_implementations with Quad9 -pri suffix (#1398) 2020-07-03 15:28:09 +02:00
hugepants 63c8f0610f
Update broken_implementations list with updated Quad9 v3 names (#1390) 2020-07-03 14:05:39 +02:00
Frank Denis 9bc5bb0e14 Clarify 2020-07-03 13:03:57 +02:00
Frank Denis 90df0292c8 Remove unneeded brackets 2020-07-03 12:59:51 +02:00
yofiji 7a6f1461f8
Add option to go direct for failed certificate retrieval via relay (#1397)
* Add option to go direct for failed certificate retrieval via relay

* add direct_cert_fallback to example config file

Co-authored-by: yofiji <you@example.com>
2020-07-03 12:58:36 +02:00
Frank Denis 5e2f1c4146 Clarify that skipAnonIncompatbibleResolvers does what it says 2020-07-02 13:45:19 +02:00
Frank Denis ece0c76172 Add fritz.box IP to the cloaking rules example
Fixes #1392
2020-07-01 09:20:44 +02:00
Krish De Souza 7b1ccd1053
Issue #1380: Reenable HTTP/2 for local DoH (#1384)
+Updated ci-test number 25 looking for invalid 404 to reflect changes here
2020-06-28 18:20:20 +02:00
Ian Bashford b089d49d25
ConfigFile change to allowlist and blocklist (#1375)
* ConfigFile change to allowlist and blocklist

* revised names and warnings

* consistent file naming in kebab case, and generic use of blocklist and allowlist in cmoments for clarity

* update ci files

Co-authored-by: Ian Bashford <ianbashford@gmail.com>
2020-06-26 23:18:30 +02:00
hugepants 19c0c3f7db
Add forward slashes to example stamp for consistency (#1388)
Seems to work with or without, but makes it consistent with the toml, the documentation and the stamp calculator.
2020-06-26 17:36:15 +02:00
Frank Denis 8935fa454a v2 -> v3 2020-06-21 22:20:34 +02:00
Frank Denis 239b00b624 Add ShiftLeft scan badge 2020-06-20 19:38:58 +02:00
Frank Denis 80942eb231 Don't forget Linux 2020-06-19 21:43:45 +02:00
Frank Denis 55ce158e37 Do we need to duplicate descriptors twice? 2020-06-19 21:42:20 +02:00
Frank Denis 539924f85f Downgrade x/text to a single version 2020-06-19 20:56:21 +02:00
Frank Denis 1124b8304e Remove dependency 2020-06-19 20:16:37 +02:00
Frank Denis 80dfffc4ee Unbreak CI 2020-06-19 20:16:21 +02:00
Frank Denis 03746b76bf Capitalize 2020-06-19 11:39:44 +02:00
IceCodeNew c8d099735b
Disable Sysctl list and AdAway, introduce GameIndustry.eu; Remove Chinese IT companies' top domain from whitelist. (#1365)
* Disable Sysctl list, Introduce GameIndustry.eu

* The host file from http://sysctl.org/cameleon/ is no longer updated, therefore it should be disabled.

* Introduce a new rule maintained by GameIndustry.eu. I only pick the rule sets that NextDNS provides to its customers of their choice, as these rule sets are generally seen as stable and reliable.
However I don't play game so much, there is no way to perform a fully test on my side. There is no FP detected during the couple of days while I using this rule set. And I've gone through the entire contents of the host file in roughly, the entries all seem reasonable to me.

* Disable rule set from AdAway by default

~~It doesn't take long for jedisct1 add baidu.com, and 163.com into whitelist after I introduced this rule into the configuration file, so I guess that the AdAway rule set must have presented a lot of false positives.~~
~~However, these Chinese IT companies are notorious for their extensive user-tracking tactics. Whitelist their top domain may not a good idea.~~
~~My suggestion is to simply disable the ruleset present FP, and let software like ABP or AdGuard do the most elaborate work. - Blocking on the DNS level has its limitations.~~
2020-06-19 00:32:01 +02:00
Prabhu Subramanian 6ee8a14deb
Add shiftleft scan (#1372)
* Create shiftleft-analysis.yml

* Remove comments

Co-authored-by: Frank Denis <124872+jedisct1@users.noreply.github.com>
2020-06-19 00:30:59 +02:00
Frank Denis 6235c11c77 When forking, relocate descriptors higher up
Channels used by the `services` module may use descriptors, so we don't
want to overwrite them.

Maybe
fixes #1371
2020-06-19 00:04:54 +02:00
Frank Denis 6dc484c177 Update deps 2020-06-18 23:19:28 +02:00
Frank Denis e1d6e27a8a Add CodeQL scan result 2020-06-15 20:25:52 +02:00
Frank Denis 5f3b568de3
Add CodeQL scan 2020-06-15 20:02:22 +02:00
Frank Denis 703059922f Easylist has false positives 2020-06-14 15:25:45 +02:00
Frank Denis 06705a6d14 Merge branch 'master' of github.com:jedisct1/dnscrypt-proxy
* 'master' of github.com:jedisct1/dnscrypt-proxy:
  Bump
2020-06-12 14:24:31 +02:00
Frank Denis 5b24439f99 Why the heck is Energized BLU blocking VK? 2020-06-12 14:24:11 +02:00
Frank Denis 65f42918a1 Bump 2020-06-11 17:10:33 +02:00
Frank Denis c59caf3a63 Try oisd list by default, mainly because it tries to avoid FPs 2020-06-11 13:16:50 +02:00
Frank Denis 576162d9bf Remove CodeQL/ShiftLeft until they are enabled for the org 2020-06-11 11:46:17 +02:00
Frank Denis d55421df96 Don't bind listening sockets with the -list/-list-all options
Fixes https://github.com/Homebrew/homebrew-core/pull/55998
2020-06-11 11:41:17 +02:00
Frank Denis 9cce77cc53 No need to import the dnsstamps package twice 2020-06-11 11:13:41 +02:00
Frank Denis 4f47cd0f4f Avoid implicit memory aliasing in for loop 2020-06-11 11:10:33 +02:00
Frank Denis de6afd5a4c Merge branch 'master' of github.com:jedisct1/dnscrypt-proxy
* 'master' of github.com:jedisct1/dnscrypt-proxy:
  Create shiftleft-analysis.yml
  Create codeql-analysis.yml
  Revert "Fix unit tests on Win10 (attempts 1 and 2)"
  sources_test: set bit 16 of the port instead of adding zeros (#1358)
  Fix unit tests on Win10 (attempt 2)
2020-06-11 11:03:30 +02:00
Frank Denis 9f9a17ed6b doh_client_x509_auth: don't ignore errors 2020-06-11 11:03:17 +02:00
Frank Denis 0fd0a1a939
Create shiftleft-analysis.yml 2020-06-11 10:55:08 +02:00
Frank Denis 8a99b3ed93
Create codeql-analysis.yml 2020-06-11 10:53:45 +02:00
William Elwood 2018945fdf Revert "Fix unit tests on Win10 (attempts 1 and 2)"
This reverts commit 92dda0d55a.
This reverts commit 5a1fdc8cd6.
2020-06-10 19:45:11 +01:00
Frank Denis f4d519092b
sources_test: set bit 16 of the port instead of adding zeros (#1358)
Ok @welwood08
2020-06-10 20:24:41 +02:00
William Elwood 92dda0d55a Fix unit tests on Win10 (attempt 2)
Thanks to @lifenjoiner for testing! Windows 10 behaves even more unexpectedly.
After it parses the "ip:port" string as a hostname, it attempts to upgrade from
http to https by appending `:443` and parsing that new URL again.
This seems to happen concurrently with the doomed DNS lookup and we see the
error from whichever fails first.
2020-06-10 12:10:51 +01:00
Frank Denis 8c42c465b2 Be even more explicit 2020-06-10 11:38:46 +02:00
Frank Denis 5416891056 Temporarily parse [tls_client_auth] for backward compatibility
Document the change.

Fixes #1355
2020-06-10 11:37:03 +02:00
Frank Denis d7f16f6be4 Uncomment sections for consistency 2020-06-10 11:04:50 +02:00
Frank Denis adcdcffdec Skip netprobe & listeners when -show-cert or -check are used
Fixes #1354
2020-06-10 11:01:59 +02:00
Huhni c07ed55b16
update domains-blacklist.conf (#1353)
* remove isc.sans.edu lists

It says "Service Suspended" when opening these links

* change Peter Lowe's list to domains only

There is no need to manually strip away all the 127.0.0.1 at the beginning of each line if there is already a method for domains only provided on the website. Could also be modified to ignore old entries with `&startdate%5Byear%5D=2015`.
Adding `&mimetype=plaintext` doesn't seem to change anything for `hostformat=nohtml`, but could be added as well.

* Remove lists intended for adblockers

The Adblock Warning Removal List currently has 559 lines, only two of which are actually useable for dnscypt-proxy (adscat.ru, shellcat.ru).
Fanboy Social currently has 20162 lines and only 118 lines can be used, which is about 0.6%.
CJX Annoyance List: 512 lines, 19 lines usable, but it's just a lite version of the already included Easylists.
Prebake: 1160 lines, 4 lines usable (also not updated since May 2018)

Most of the remaining domains should be covered by a larger domains blocklist, such as Energized BLU, therefore I think it's safe to remove them.

* remove lists included in Energized Blu

Since Energized Blu is enabled by default, there is no need to also enable lists by default that are already contained in it.

Energized Blu contains the following sources:
1hosts, add.2o7Net, add.Dead, Risk & Spam, Adguard Filters, Ador, Anti-PopAds, Coin Blocker, Disconnectme Ads, Malware & Malvertising, EasyPrivacy Specific, hBlock, Lightswitch Ads & Tracking, Spam404, KADhosts, MoaAB, MobileAdTrackers, No Tracking, NSABlocklist, someonewhocares, StevenBlack, Wally3K_Blacklist & Zeus Tracker
2020-06-09 17:43:15 +02:00
William Elwood 5a1fdc8cd6 Fix unit tests on Win10
Untested attempt to fix unit tests that fail on Windows 10 build 1909.
From the test output mentioned in #1332, it looks like this version of Windows
doesn't report an "invalid port" error when asked to connect to an invalid port,
instead it treats the port as part of the host name and attempts a DNS lookup.
Naturally, this fails because the colon character is not valid in a host name.
This change simply makes this inexplicable error an expected result since the
outcome is the same and we can't fix Windows.
2020-06-09 15:51:23 +01:00
Frank Denis f9268be0c2 Recompute deps 2020-06-09 12:09:51 +02:00
Frank Denis 08e9dfe46e Nits 2020-06-09 09:55:40 +02:00
Frank Denis 506f727f1f Another place worth force GC'ing 2020-06-09 09:52:59 +02:00
Frank Denis b794d47a76 Force GC where it seems to matter most 2020-06-09 09:42:09 +02:00
Frank Denis 8200616655 dlog update 2020-06-08 22:52:07 +02:00
Frank Denis 8945cb1b90 Add log_file_latest 2020-06-08 22:31:03 +02:00
Frank Denis 9f9318701f Update dlog 2020-06-08 20:33:18 +02:00
Frank Denis 87c161ab76 Clarify what log_file is 2020-06-08 20:07:24 +02:00
Frank Denis e9227daf6a Update deps 2020-06-08 19:22:36 +02:00
Frank Denis 9c5cf611a4 Preliminary ChangeLog 2020-06-08 19:20:55 +02:00
Frank Denis b32ffbb807 Discourage from blindly using dns64 2020-06-08 18:59:39 +02:00
s-s f48b13f7b8 Add DNS64 support 2020-06-08 18:42:54 +02:00
Frank Denis d766dc8bf7 doh_client_x509_auth: make it clear that root_ca is optional 2020-06-08 18:09:37 +02:00
Kevin O'Sullivan 5db4365540
Adding support for additional root CAs for DoH TLS Auth (#1281) 2020-06-08 18:01:40 +02:00
Frank Denis 68ccd1410f Support multiple stamps per resolver
For now, a single stamp is randomly chosen in order to spread the load,
but we may eventually want to also use this for failover mechanisms.
2020-06-08 17:54:49 +02:00
Frank Denis b0e883ebc6 Android: use getprop persist.sys.timezone to get and set the time zone
Untested. Maybe
fixes #1351
2020-06-06 15:32:27 +02:00
Frank Denis 9d1eee4b29 Expand default whitelist 2020-06-03 09:47:34 +02:00
IceCodeNew dd1f32ebfd
Add comments for domains-blacklist.conf, with a little sorting on it. (#1350)
* Update domains-blacklist.conf

0. Add more comments so it should be much easier for anyone to get understanding how to choose the rules which is delivered in varies levels.
1. Sort rules from Energized so it is ordered in the sort of size, which would make sense.

* Add rule from AdAway

AdAway seems to be a project last more than 9 years. I tried it for several days and haven't experienced any false positive yet.
2020-06-03 09:42:50 +02:00
Frank Denis 2739db2733 Update deps 2020-06-02 13:56:05 +02:00
Frank Denis 010cedd7b8 whitelist qualtrics.com 2020-06-02 13:51:37 +02:00
Frank Denis 45628702b6 Add SANS lists 2020-06-02 13:03:41 +02:00
Frank Denis 1f6d8cc53c Nits 2020-05-31 13:46:44 +02:00
Frank Denis c5d2459752 Whitelist domains required to check for captive portals 2020-05-31 13:36:15 +02:00
Frank Denis 8ddd5fe36e Merge branch 'master' of github.com:jedisct1/dnscrypt-proxy
* 'master' of github.com:jedisct1/dnscrypt-proxy:
  Fallback to cache_file avoiding termination for not offline_mode (#1332)
  Minor update to GH Actions workflow (#1341)
2020-05-31 13:27:28 +02:00
Frank Denis d59d9427b3 Don't wait for the whole server list before accepting connections
Blocking until all servers have been checked is safe, but significantly
increases startup times.

OTOH, we shouldn't accept connections unless we have at least one live
server.

So, a better approach may be to add the ability for `serversInfo.refresh()`
to write to a channel after a live server has been found, and block on
that channel in the main thread before accepting client connections.
2020-05-31 13:24:35 +02:00
lifenjoiner c4a13d25ce
Fallback to cache_file avoiding termination for not offline_mode (#1332)
Ignore downloading error from `NewSource` when startup (cache loaded).
2020-05-30 07:38:04 +01:00
Will Elwood ee62eb7b23
Minor update to GH Actions workflow (#1341)
* Update releases.yml

Run CI for pull requests and new tags, and only when relevant files change in a push or PR.

* Update releases.yml

"Path filters are not evaluated for pushes to tags."
2020-05-29 15:06:02 +02:00
IceCodeNew 3d5f877058
Added Ads-blocking rules from Disconnect (#1336) 2020-05-28 12:10:59 +02:00
IceCodeNew da8620cdda
Update link to Spam404 rule (#1334)
Though the old link is still available, the rule file has stop updating for a long while.
2020-05-27 21:46:15 +02:00
Stathis Xantinidis 230c171c71
Added Block spying and tracking on Windows (#1327)
Reduces a great amount of telemetry on Microsoft based operating systems, for those who need it :)
2020-05-21 14:05:39 +02:00
Frank Denis 7e2404ffef Use domain lists for energized.pro 2020-05-20 16:01:25 +02:00
Linuxfreak ece0d2e8b9
Update EnergizedProtection URLs (#1325)
* Update Energized Protection URLs

EnergizedProtection url links have changed, it seems they had to delete them from github and moved them to their self hosted domain (block.energized.pro).

* Re enabling EnergizedProtection BLU

I commented it out by mistake oops :)
2020-05-20 15:57:11 +02:00
Frank Denis 82f78ef4fa s/BrokenQueryPadding/FragmentsBlocked/
Maybe
fixes #1323
2020-05-19 15:57:56 +02:00
Frank Denis 5c911ad2aa Merge branch 'master' of github.com:DNSCrypt/dnscrypt-proxy
* 'master' of github.com:DNSCrypt/dnscrypt-proxy:
  move mis-categorized line (#1308)
2020-05-06 19:34:55 +02:00
Frank Denis fa2b693506 Remove parse_time_restricted_list 2020-05-06 19:34:41 +02:00
David Refoua 5c36dcb818
move mis-categorized line (#1308) 2020-05-01 21:33:48 +02:00
Frank Denis 35a6fc858f CI: stop publishing MacOS binaries since they now require notarization
Fixes #1300
2020-04-28 10:00:49 +02:00
Frank Denis 3e264b9da9 Rename tls_client_auth to doh_client_x509_auth
Maybe improves clarity? I can never remember what tls_client_auth does.
2020-04-26 21:21:00 +02:00
Frank Denis 3775d59217 Add some comments for an obscure feature 2020-04-26 21:05:23 +02:00
Frank Denis 8f7015f0bc Avoid UTF-8 in domains-blacklist.conf
Fixes #1299
2020-04-26 20:53:47 +02:00
Frank Denis c6b32e0590 Another example of an IP blocklist 2020-04-26 19:42:42 +02:00
Frank Denis 80b95b1ba6 Use accessors for systemd things, too 2020-04-26 17:08:24 +02:00
Frank Denis 436bce9edf Define functions to register socket handles, to improve clarity 2020-04-26 16:52:50 +02:00
Frank Denis 38cfa437db Repair Local DoH; should fix CI tests 2020-04-26 16:34:26 +02:00
Frank Denis 12219c7490 listener->pc
Spotted by @welwood08
2020-04-26 16:19:49 +02:00
Frank Denis 52f87aee8e Accept data from systemd sockets at the same time as everything else 2020-04-26 15:00:39 +02:00
Frank Denis 4029d3d4f3 proxy.dropPrivilege() doesn't return on success 2020-04-26 14:49:43 +02:00
Frank Denis 3c510b74bb Start listeners as goroutines 2020-04-26 14:26:40 +02:00
Frank Denis c6b2869317 Update Poly1305 dep 2020-04-26 13:03:48 +02:00
Frank Denis 4a50736457 Only start accepting connections after everyting has been initialized
Fixes #1295

And more. The estimator, key and servers list were not initialized either.
2020-04-26 12:52:55 +02:00
Frank Denis 7d0e1440e1 ESNI has been renamed to ECHO 2020-04-24 11:15:40 +02:00
Frank Denis 252b10c996 Remove blacklisted names due to globbing patterns
This is very clumsy, as it doesn't handle time-based rules properly,
and doesn't handle whitelists at all.

Adding globs to the "names" list is also an ugly hack just to have
them included in the final output.
2020-04-22 17:55:24 +02:00
Frank Denis a71b531d2e Re-add -o / --output-file 2020-04-21 23:40:58 +02:00
Frank Denis dcd6f8448d Revert "Improve generate-domains-blacklist.py to remove redundant lines (#1184)"
This reverts commit 58871de725.
2020-04-21 23:08:40 +02:00
Huhni 58871de725
Improve generate-domains-blacklist.py to remove redundant lines (#1184)
* Improve script to remove redundant lines

Let the script remove those lines that are covered by regular expressions already

* add optional "-o OUTPUT_FILE" argument 

This ensures that UTF-8 is used.
The redirect to file functionality from before is maintained, because "default=None" is used for the -o argument

I also fixed the formatting slightly to avoid newlines at the beginning of the file.

* improve glob matching

- rename regexes into globs 
- only check trusted (local) files for globs
- use fnmatch instead of manually converting globs into regular expressions and matching them
- modify is_glob function to check only for the following characters: * [ ] ?
- improve get_lines_with_globs function, by using the native filter and lambda functions
- improve covered_by_glob function, by checking if line is part of glob_list, instead of calling is_glob again
- print "ignored entries due to globs in local-additions" to the output as well to better differentiate from other duplicates
2020-04-21 23:07:32 +02:00
Frank Denis 9519472bbe Don't print the proxy version in the child 2020-04-20 12:34:59 +02:00
Frank Denis 6f2dcb900a Drop privileges early
Fixes #1265
2020-04-20 12:27:53 +02:00
Frank Denis b6b7ed3a67 Dropping privileges doesn't work reliably on MacOS 2020-04-20 11:50:27 +02:00
Frank Denis abfd195e51 Use Kadhosts without controversies
Fixes #1288
2020-04-19 17:55:46 +02:00
Frank Denis 69a7d832c4 Remove lists that are pretty much empty 2020-04-19 17:52:16 +02:00
Frank Denis ccc91e28a3 Try enabling energized blu by default
Quite a lot of domains in that list don't exist any more, though.
2020-04-19 17:46:18 +02:00
Frank Denis 900ed13ff1 Remove banbenek's list 2020-04-19 17:39:53 +02:00
Frank Denis dd522bb726 Merge branch 'master' of github.com:DNSCrypt/dnscrypt-proxy
* 'master' of github.com:DNSCrypt/dnscrypt-proxy:
  use global 'timeout' option for forwarding queries (#1284)
2020-04-18 21:18:53 +02:00
Frank Denis 2779d92f01 Add some blacklists 2020-04-18 21:18:40 +02:00
29f f71244ed74
use global 'timeout' option for forwarding queries (#1284)
* Update plugins.go

* Update plugin_forward.go
2020-04-17 20:57:23 +02:00
Frank Denis 4f41fc3fee Add Geoffrey Frogeye's block list 2020-04-12 23:34:15 +02:00
Frank Denis 527764aba7 Upper case 2020-04-05 20:50:28 +02:00
Kiril Angov d2602fd142
Respect proxy.mainProto in forward plugin (#1259)
* Respect proxy.mainProto in forward plugin

* Make the serverProtocol part of pluginsState instead
2020-04-05 20:49:30 +02:00
Frank Denis f4631b9121 Remove unreachable code
Spotted by @komapa
2020-04-05 20:48:00 +02:00
Linuxfreak 76f6d02e52
Change URL of Block Spotify ads (#1266)
The url of the Spotify-HOSTS.txt is changed. Path of "/filter/" is now "/filters/"
2020-04-04 22:18:21 +02:00
Frank Denis 5930b45116 Farewall host-files.net domain list
Fixes #1262
2020-04-02 14:56:38 +02:00
kimw 4ce28473f4
Update example-ip-blacklist.txt (#1264)
fix https://github.com/DNSCrypt/dnscrypt-proxy/issues/1261. remove `[` & `]`.
2020-04-02 14:55:18 +02:00
Frank Denis f6b9706322 This reverts commit 876e389a0a.
April 1st is almost over :)
2020-04-01 21:55:17 +02:00
Frank Denis 876e389a0a Make doh.nsa.gov the default DNS server 2020-04-01 12:22:52 +02:00
Frank Denis 17fbad3648 Update deps 2020-04-01 12:15:13 +02:00
Frank Denis 1ff31f14f1 Remove the ct parameter from DoH queries
That was a workaround for Google, but Google doesn't seem to need
it any more.
2020-04-01 12:12:57 +02:00
Frank Denis eb372e7ce5 First release using GitHub Actions: success! Farewell, Travis. 2020-03-26 18:53:35 +01:00
Frank Denis 89dd0de6af Update ChangeLog 2020-03-26 18:38:15 +01:00
Frank Denis 8fc2f00ffb Probably older than version 1.4.0 2020-03-26 18:33:39 +01:00
Frank Denis 3ca80afb19 packets -> client queries 2020-03-26 17:25:52 +01:00
Frank Denis 74095d38ed Remove LargerResponsesDropped
dnsdist drops DNSCrypt queries shorter than 256 bytes, interpreting them
as not being encrypted instead. This is surprising when doing ad-hoc
testing, but absolutely fine, and we will never send shorter encrypted
queries on normal circumstances.

So, remove a useless knob.
2020-03-26 17:20:34 +01:00
Frank Denis fb04a62470 ChangeLog 2020-03-26 15:39:48 +01:00
Frank Denis b3fbc2304d All dnsdist servers exhibit the same behavior re: sending truncated responses
A 128 bytes query will not get a 200 bytes response (randomly tested on
3.tlu.dl.delivery.mp.microsoft.com), not even a truncated one.

It may be related to fragments being blocked on the server socket, or a
different issue. We can expect everything to be back to normal in dnsdist
1.5.0 no matter what.
2020-03-26 15:19:17 +01:00
Frank Denis 5049516f53 Add an option to ignore servers incompatible with anonymization 2020-03-26 13:41:57 +01:00
Frank Denis 7621737dde Improve debugging 2020-03-26 13:30:39 +01:00
Frank Denis 9542109d66 Cancel dnsExchange goroutines as soon as we have a best response 2020-03-26 12:53:22 +01:00
Frank Denis ad36321dc8 Add cleanbrowsing until dnsdist 1.5.0 is out 2020-03-26 12:31:12 +01:00
Frank Denis 98e53c4013 Replace Travis status badge with the GitHub Action badge 2020-03-26 11:15:12 +01:00
Frank Denis c54e8a2c60 Goodbye Travis, let's switch to GitHub Actions! 2020-03-26 11:02:19 +01:00
Frank Denis 8896787e66 Add other dnsdist servers until the MTU issue is fixed
https://github.com/PowerDNS/pdns/pull/7410
2020-03-26 10:57:09 +01:00
Frank Denis 9f65457b1c Wait a little bit more between UDP attempts 2020-03-26 10:37:56 +01:00
Frank Denis 1d090eb194 Unfortunately, blocking stats.* has too many implications 2020-03-25 20:33:36 +01:00
Frank Denis 7424f1a8b7 Try harder to work around Cisco and Quad9 bugs 2020-03-25 20:10:11 +01:00
Frank Denis 64935c9b92 Bump 2020-03-25 18:24:25 +01:00
Frank Denis 0860245c73 Nits 2020-03-25 18:24:03 +01:00
Frank Denis 25b89e57ae Add Quad9 back to the list of servers with broken padding 2020-03-25 18:11:16 +01:00
Frank Denis 81c8d68462 Pad queries to 1472 bytes for implementations with broken padding
Quad9 doesn't return TC when responses are larger than the question;
it doesn't return anything instead :(
2020-03-25 18:06:02 +01:00
Frank Denis dd37eaed7c Retry over TCP on UDP timeouts 2020-03-25 17:45:59 +01:00
Frank Denis 4fe5929720 Typo
Fixes #1248
2020-03-25 09:11:10 +01:00
Frank Denis c39d66661b Remove ARMv6 and ARMv7 binaries 2020-03-24 21:56:10 +01:00
Frank Denis 16ac53810f Remove armv6 and armv7 builds, this is confusing 2020-03-24 21:55:09 +01:00
Frank Denis 9c15e90610 Update the Android NDK to r20 2020-03-24 18:00:58 +01:00
Frank Denis 39cc14da5c Update ChangeLog 2020-03-24 17:17:45 +01:00
Frank Denis 5d81e5a6db Build Linux binaries for armv7 while we're here 2020-03-24 16:43:48 +01:00
Frank Denis 77507abb62 Fix Travis build for freebsd/arm 2020-03-24 16:00:25 +01:00
Frank Denis 366413fa2d Travis: put commands on single lines
Just to make them easier to execute manually while Travis is b0rk3d
2020-03-24 15:37:23 +01:00
Frank Denis d905021856 Revert "Go back to Go 1.13"
This reverts commit d91df1a62c.

The issue on Mips was unrelated (due to an antique kernel), and
compiling for armv5 seem to work around issues reported on arm
2020-03-24 14:55:01 +01:00
Frank Denis 61d6cfa992 Use GOMIPS64=softfloat 2020-03-24 14:54:58 +01:00
Frank Denis d91df1a62c Go back to Go 1.13
We got too many reports of binaries built with Go 1.41.1 not working
any more on arm and mips CPUs.

So, downgrade until these issues are sorted out.
2020-03-24 14:39:06 +01:00
Frank Denis c13a69b040 Remove deepsource 2020-03-24 14:38:00 +01:00
Frank Denis a58044fed0 Bump 2020-03-24 14:37:35 +01:00
Frank Denis c4287c799f Quad9 doesn't seem to block fragments on all networks
So, remove them from the static list and trust the runtime checks
for detection.
2020-03-24 14:32:23 +01:00
Frank Denis 315f6f45ff Certificates that can't be loaded are fatal 2020-03-24 14:31:43 +01:00
Frank Denis 2670caa71e Print the anonymization incompatibility message even if detected at runtime 2020-03-24 14:19:41 +01:00
Frank Denis 18a8a207ab up deps 2020-03-24 13:01:57 +01:00
Frank Denis 3f07b6079a No need to explicit ignore this variable 2020-03-24 12:45:17 +01:00
Frank Denis b328a9768f Remove debugging code that prevented detection of fragmented UDP support 2020-03-24 12:38:23 +01:00
Frank Denis a3376db1b6 Create binaries for ARMv5 and ARMv6 2020-03-22 12:25:22 +01:00
Frank Denis 79c8fa30d0 Compile ARM binaries for ARMv5
Not sure what's going on here.

GOARM=6 is supposed to be the default when cross-compiling, but
some people reported that executables had illegal instructions without
GOARM=6.

After executables available for download were updated with GOARM=6,
people kept reporting "it doesn't load", even though we presumably
never shipped binaries for ARMv5.

Anyway, try that as a last move.
2020-03-22 12:15:28 +01:00
Frank Denis 6a608565bf arm builds: explicitly build for armv6
The Go documentation says that this is the default, but apparently not.

Fixes #1240
2020-03-21 18:12:47 +01:00
Frank Denis b644ec981c Update Travis config 2020-03-21 16:49:52 +01:00
Frank Denis 420c9682f9 Deps update for IllumOS 2020-03-21 16:41:20 +01:00
Frank Denis 06ca9b01f0 Nits 2020-03-21 10:24:09 +01:00
Frank Denis 9686e789c7 Bump 2020-03-21 10:18:37 +01:00
Frank Denis d80af74300 Fix unit tests 2020-03-20 22:40:29 +01:00
Frank Denis 0b87cc92b6 Fix data race 2020-03-20 21:45:09 +01:00
Frank Denis 44db53f58b Not dnsdist 2020-03-20 21:19:34 +01:00
Frank Denis d1710a4d2b Use single quotes for consistency 2020-03-20 21:18:30 +01:00
Frank Denis 094ea07dc2 Bump 2020-03-20 21:09:34 +01:00
Frank Denis d876c7b487 Keep the default LB strategy if an invalid p* one is used 2020-03-20 20:53:03 +01:00
Frank Denis 62a20fd97a up deps 2020-03-20 20:40:46 +01:00
Frank Denis d9a68abae9 Merge branch 'lbstrategy-interface'
* lbstrategy-interface:
  Support power-of-<arbitrary number>
  Use an interface for load-balancing strategies
2020-03-20 17:55:41 +01:00
Frank Denis 4c402a6012 Revert "Implement pN load balancing strategy (#1188)"
This reverts commit 014a75c0ec.
2020-03-20 17:55:33 +01:00
Timofey 014a75c0ec
Implement pN load balancing strategy (#1188) 2020-03-20 17:55:03 +01:00
Frank Denis 34d83f027f Support power-of-<arbitrary number> 2020-03-20 17:49:32 +01:00
Frank Denis b57cc19d70 Use an interface for load-balancing strategies 2020-03-20 17:37:34 +01:00
Frank Denis a1f3b34390 Update deps 2020-03-20 17:22:23 +01:00
Frank Denis bad3d0accd Update deps 2020-03-19 10:18:43 +01:00
Frank Denis 16708a0c20 Automatically detect servers blocking fragmented queries 2020-03-14 21:34:40 +01:00
Frank Denis 49910d2f72 Localize some error values 2020-03-13 18:44:30 +01:00
Frank Denis 26ebb55c8c Quite a lot of dependency updates 2020-03-13 17:58:44 +01:00
Frank Denis 19647e03a6 Overwrite the server name only when we need to send an upstream query 2020-03-13 17:52:09 +01:00
Dragonfir3 c17637c026
Don't log a server for blocked names by pattern (#1218)
* Update plugins.go

* reason update moved after reject confirmed

added boolean for direct rejects

* remove server with direct rejects

name pattern blocked cases
2020-03-13 17:50:38 +01:00
Frank Denis a8db53e36f Merge branch 'master' of github.com:jedisct1/dnscrypt-proxy
* 'master' of github.com:jedisct1/dnscrypt-proxy:
  Bump github.com/miekg/dns from 1.1.27 to 1.1.28 (#1223)
2020-03-13 17:38:06 +01:00
Frank Denis 5bb5a26150 Update notracking list URL
Fixes #1174
2020-03-13 17:37:50 +01:00
dependabot-preview[bot] 76106944cc
Bump github.com/miekg/dns from 1.1.27 to 1.1.28 (#1223)
Bumps [github.com/miekg/dns](https://github.com/miekg/dns) from 1.1.27 to 1.1.28.
- [Release notes](https://github.com/miekg/dns/releases)
- [Changelog](https://github.com/miekg/dns/blob/master/Makefile.release)
- [Commits](https://github.com/miekg/dns/compare/v1.1.27...v1.1.28)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-13 17:33:56 +01:00
Frank Denis 810f6043d2 People are used to seeing the [static] section at the end 2020-03-09 22:14:31 +01:00
Kevin O'Sullivan c040b13d59
Adding the ability to do TLS client authentication for DoH (#1203)
* Adding the ability to do TLS client authentication for DoH

* whitespace nit

* Check for server specific creds before wildcard

* small comma ok idiom change
2020-03-09 22:11:53 +01:00
Frank Denis c2271c8079 Remove snapcraft file, that was never used for anything 2020-03-02 11:16:09 +01:00
Frank Denis 647b14cd19 Update go.mod/go.sum 2020-02-26 16:52:37 +01:00
Frank Denis ee070be530 Update deps 2020-02-26 15:38:43 +01:00
Frank Denis 92e842126d Skip the Firefox plugin for connections through the local_doh protocol
Fixes #1205
2020-02-26 15:29:28 +01:00
Will Elwood b2be617e6b Update example-dnscrypt-proxy.toml
Fixes to grammar and other minor issues.
2020-02-26 15:13:49 +01:00
Will Elwood 11b31dea4f Update example-dnscrypt-proxy.toml
Attempt to clarify the behaviour of server_names.
2020-02-26 15:13:49 +01:00
Frank Denis aa0e7f42d3 Make the xTransport functions return the HTTP body directly
This simplifies things, but also make RTT computation way more reliable
2020-02-21 22:33:34 +01:00
Frank Denis a6d946c41f Shorten the default broken_query_padding list 2020-02-21 20:33:13 +01:00
Frank Denis 4608b6d18d Add auad9 to the broken_query_padding list
Fixes #1169
2020-02-21 20:31:45 +01:00
Frank Denis 673eea65af Add random padding to the initial DoH query
Fixes #1199
2020-02-21 20:24:24 +01:00
Alison Winters 0ef2737ffe fix minor typos in comment 2020-02-14 18:48:48 +00:00
Alison Winters 1fa26eec0a gofmt whitespace 2020-02-14 18:48:48 +00:00
Alison Winters 8c42609475 fix minor typoS in config file 2020-02-14 18:48:48 +00:00
Frank Denis 323c4a4758 Don't explain the format of other config files in the main config file
This is confusing if you don't read the documentation.

Fixes #1179
2020-02-05 12:17:14 +01:00
Frank Denis 824fa90f94 Forwarding plugin: force set the response ID to match the query ID
Shouldn't be necessary, but just to be safe in case `dns.Exchange()`
does something unexpected.
2020-02-05 02:52:54 +01:00
Frank Denis 63d28fc9b2 Forwarding plugin: retry over TCP if a truncated response is received
dns.Exchange() doesn't do it automatically.

Fixes #1178
2020-02-05 02:44:43 +01:00
Frank Denis 170c690996 Bump 2020-01-31 11:25:04 +01:00
Frank Denis 2dda74647d Don't add padding unless the query has padding
Or else Firefox craps out
2020-01-31 11:17:36 +01:00
Frank Denis 70311614a0 Improve error message on DNSSEC failure 2020-01-31 10:58:07 +01:00
Frank Denis 0f78684e5f Add a test for the local DoH feature 2020-01-31 10:58:07 +01:00
Frank Denis cf1498c9f4 Properly compute the padding length for local DoH
Fixes #1173
2020-01-31 10:58:03 +01:00
Frank Denis d14d2b613a Bump 2020-01-30 16:19:38 +01:00
Frank Denis a6026ce48a Ignore lines starting with '#'
Fixes #1171
2020-01-30 16:16:05 +01:00
Frank Denis 3a94523d65 Bump the cache size a little bit 2020-01-30 15:08:23 +01:00
Frank Denis 0d0c5afd29 Update ChangeLog 2020-01-30 13:39:54 +01:00
Frank Denis c84a394817 Bump 2020-01-30 13:23:03 +01:00
Frank Denis f34d7b60fa Implement serve-stale 2020-01-30 13:15:29 +01:00
Frank Denis f22461374c Retry UDP queries on timeout 2020-01-29 18:53:39 +01:00
Frank Denis cd35e2e854 Update deps 2020-01-29 17:58:43 +01:00
Frank Denis f17ce1ae0d Use constant, but arbitrary long padding 2020-01-29 17:57:59 +01:00
Frank Denis c323bcde21 Update deps 2020-01-29 01:07:08 +01:00
Frank Denis 4d788aed85 Make UDP and TCP code similar when it comes to SOCKS proxying
Actually use the relay when both a relay and a SOCKS proxy are
configured.

Keep forcing TCP when SOCKS is enabled. I couldn't get UDP proxying
to work with Shadowsocks.
2020-01-27 16:07:08 +01:00
Frank Denis 349320f291 Add support for inline comments in patterns lists
Fixes #1162
2020-01-25 15:45:23 +01:00
dependabot-preview[bot] 6fa865d538 Bump github.com/hashicorp/golang-lru from 0.5.3 to 0.5.4
Bumps [github.com/hashicorp/golang-lru](https://github.com/hashicorp/golang-lru) from 0.5.3 to 0.5.4.
- [Release notes](https://github.com/hashicorp/golang-lru/releases)
- [Commits](https://github.com/hashicorp/golang-lru/compare/v0.5.3...v0.5.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-17 10:04:17 +01:00
Frank Denis b041eba311 Update deps 2020-01-15 19:58:59 +01:00
Frank Denis 7ada3fcfb8 Support multiple fallback resolvers 2020-01-15 19:58:14 +01:00
Frank Denis f1bd4bf420 Update deps 2020-01-14 12:14:49 +01:00
Frank Denis 26971d254d go crypto update 2020-01-11 08:57:16 -07:00
Frank Denis 4f03575943 ransomware tracker is no more 2020-01-11 08:55:22 -07:00
Cristian-J 05593a8bbd Ignore links that start with a hyphen or a dot
If you use filter blacklists you'll end up with many invalid links that start with a hyphen or a dot in the final blacklist.
2020-01-08 12:57:22 -07:00
Frank Denis 7fb62d98ea Use EDNS0 padding for local DoH 2020-01-05 21:12:29 -05:00
Frank Denis 6fb42d0eae Improve error message when local DoH is enabled without a certificate
Fixes #1136
2020-01-05 19:02:57 -05:00
Frank Denis 5c37d3b9de Update deps 2020-01-05 19:00:16 -05:00
Frank Denis 19cebfdb0a Mention that /dev/stdout is not for Windows systems
Fixes #1131
2020-01-03 21:13:04 -05:00
Frank Denis 817d92fce0 Merge branch 'master' of github.com:jedisct1/dnscrypt-proxy
* 'master' of github.com:jedisct1/dnscrypt-proxy:
  sys/unix update
  Blacklist motd.ubuntu.com
2020-01-01 11:37:30 +01:00
Frank Denis 33c968b346 2020 2020-01-01 11:36:07 +01:00
Frank Denis fc1754c45f sys/unix update 2019-12-30 20:25:29 +01:00
Frank Denis 1c45d9e156 Blacklist motd.ubuntu.com 2019-12-27 21:21:05 +01:00
Frank Denis abd221738b Explicit brackets 2019-12-23 23:17:46 +01:00
Frank Denis 5ede397d33 Mention ipsum 2019-12-23 19:52:27 +01:00
Frank Denis 69f00ca977 Don't use the message attribute to get an error message
Fixes #1123
2019-12-23 18:58:39 +01:00
Frank Denis a308c76191 Format 2019-12-23 18:55:37 +01:00
Frank Denis 0e644c4b86 Add -config <config file> to the service configuration arguments
Maybe
fixes #1122
2019-12-23 15:35:52 +01:00
Frank Denis 7e45b50d58 Move things around 2019-12-23 15:33:57 +01:00
Frank Denis c27d41faa0 Avoid unneeded DNS packet unpacking 2019-12-23 11:37:45 +01:00
Frank Denis adb6dac420 Strip EDNS0 options in responses 2019-12-22 18:02:33 +01:00
Frank Denis 5118ed21fd Use dumb padding even for GET queries
Resolvers such as Cloudflare always add padding to DoH responses
Resolvers such as Google only do if the question had dumb padding
Resolvers such as Cisco blindly return a copy of the question's padding
Some resolvers don't return any padding no matter what's in the question
Finally, other resolvers return FORMERR

This is a mess. A bad design inherited from DoT, that didn't fix
anything from Unbound's original experiment.

Also, padding with zeros as recommended is a bad idea. When using
GET, escaping makes the actual padding size 3 times as big as needed.
2019-12-22 17:34:16 +01:00
Frank Denis 1585ede954 Use EDNS0 padding when using DoH over POST
This mechanism is horrible, slow (requires re-unpacking and re-packing
the query), should be done at transport layer and not at content layer, and
of course, it is incompatible with some resolvers.

However, in spite of https://go-review.googlesource.com/c/go/+/114316/2/src/net/http/transfer.go ,
we may still end up sending the header and the content in distinct packets.

So, use that horror for POST queries only. For GET, this is not needed.
2019-12-22 15:31:02 +01:00
Frank Denis 0454463539 Pad GET queries 2019-12-22 14:43:21 +01:00
Frank Denis 48817a4642 Unbeta 2019-12-21 21:29:13 +01:00
Frank Denis 6f62a82496 Update deps 2019-12-21 21:28:07 +01:00
unknown a7922a81fb add some nonexistent zones 2019-12-21 14:34:29 +01:00
Frank Denis ebe3a37ddc Merge branch 'master' of github.com:jedisct1/dnscrypt-proxy
* 'master' of github.com:jedisct1/dnscrypt-proxy:
  CI: don't hardcode the HTTP port
  2.0.36-beta.1
  agl/ed25519 is not required any more
  CI: Change the local DoH port, run go tests, enable -race
2019-12-18 23:22:41 +01:00
Frank Denis ffb1a1b718 People really blacklist cdn.cloudflare.net ¯\_(ツ)_/¯ 2019-12-18 23:21:50 +01:00
Frank Denis 99c86283f6 CI: don't hardcode the HTTP port 2019-12-18 12:54:55 +01:00
Frank Denis 80d45a2343 2.0.36-beta.1 2019-12-18 12:44:24 +01:00
Frank Denis 44735cb97e agl/ed25519 is not required any more 2019-12-18 12:40:52 +01:00
Frank Denis 3ec6a814c2 CI: Change the local DoH port, run go tests, enable -race 2019-12-17 23:48:01 +01:00
Frank Denis 3fce30d7a5 Rename PluginsActionForward to PluginsActionContinue
Set the correct response code when forwarding
2019-12-17 19:19:36 +01:00
Frank Denis 2c295e3702 Add an additional CI test for standard, cached queries 2019-12-17 19:03:02 +01:00
Frank Denis daf6d5881d The default return code must be PASS 2019-12-17 18:54:49 +01:00
Frank Denis 515968e414 Run the CI test in the before_install phase
This is unorthodox, but Travis will stop right after most errors
instead of spending forever installing the Android NDK
2019-12-17 18:38:40 +01:00
Frank Denis 56bd9dcd04 Add some temporary basic CI tests 2019-12-17 18:29:33 +01:00
Frank Denis b1c08f8931 Handle Drop/Synth actions the same way in query and response plugins 2019-12-17 16:28:12 +01:00
Frank Denis a23f07a93d Add an IP blacklist example 2019-12-17 15:25:39 +01:00
William Elwood d88995aac6 Minor comment fix
I noticed while writing the functionality tests that comments about relative paths disagreed with what the code was doing.
While the executable directory is used if the configuration file itself can't be found, `cdFileDir(foundConfigFile)` is always executed after the configuration file is found whether that's the same as the executable's directory or not.
Also a couple of punctuation nits.
2019-12-17 14:28:06 +01:00
William Elwood 7d08ba2536 Fix module name
I'm not sure why an extra "dnscrypt-proxy" was added to the module name when the rest of the URL was updated, but it resulted in the following:
```
$ go test -mod=vendor ./...
ok  	github.com/DNSCrypt/dnscrypt-proxy/dnscrypt-proxy/dnscrypt-proxy	0.173s
ok  	github.com/DNSCrypt/dnscrypt-proxy/dnscrypt-proxy/test	0.006s
$ go list ./...
github.com/DNSCrypt/dnscrypt-proxy/dnscrypt-proxy/dnscrypt-proxy
github.com/DNSCrypt/dnscrypt-proxy/dnscrypt-proxy/test
```
Not critical, but it looks wrong that these packages will not be found at those URLs.
2019-12-17 14:27:05 +01:00
Frank Denis 8e5a5b734f Make the doc link more visible 2019-12-17 14:11:05 +01:00
Frank Denis 3c6f87527f Undelegated zones are not dot suffixed any more 2019-12-17 11:08:22 +01:00
Frank Denis 4fd54a4919 Store the normalized qName in the plugin state
We now enforce the fact that a query always include a question.
It holds true for all practical use cases of dnscrypt-proxy.

This avoids quite a lot of redundant code in plugins, and is faster.
2019-12-17 10:11:41 +01:00
Frank Denis ee24bf0421 Bump 2019-12-16 23:06:56 +01:00
Frank Denis a35d08394a Update ChangeLog 2019-12-16 23:06:41 +01:00
Frank Denis 49e8328dd6 Merge branch 'master' of github.com:jedisct1/dnscrypt-proxy 2019-12-16 20:04:52 +01:00
Frank Denis ed5431d7b9 Update deps 2019-12-16 20:04:38 +01:00
Frank 10f33d39fc Update deps 2019-12-16 20:02:53 +01:00
Frank Denis 07e605e9f4 Add a note about dnsmasq
In the config file, so that it has more visibility than in the doc.

Synthetic responses cannot contain NSEC or RRSIG records, and that
seems to be confusing dnsmasq.
2019-12-16 17:23:22 +01:00
Frank Denis eedabcbd4a Reverse 2019-12-16 17:05:05 +01:00
Frank Denis cba755b4d1 Lowercase the question 2019-12-16 17:03:16 +01:00
Frank Denis 7066e53843 Pre-add the final dot 2019-12-16 16:39:30 +01:00
Frank Denis 1b276be85d Rewrite block_undelegated without the generic pattern matcher 2019-12-16 16:35:08 +01:00
Frank Denis 2d25719a69 Reuse the same variable 2019-12-16 16:32:49 +01:00
Frank Denis 66799c4159 Add the ability to block undelegated DNS zones
Using the generic pattern matcher as a first iteration, but we can
save some memory and CPU cycles by building and using a critbit tree
directly.
2019-12-16 16:18:47 +01:00
Frank Denis aa5350c7fd Missed blockedName->xBlockedName renaming
Fixes #1116
2019-12-16 12:13:23 +01:00
Frank Denis 56f838341b travis-ci.org -> travis-ci.com 2019-12-11 14:19:39 +01:00
Frank Denis 76de8a955a Update deps 2019-12-11 14:10:16 +01:00
Frank Denis c1202457bf Json -> JSON 2019-12-11 14:08:48 +01:00
Frank Denis a7b7bdc11e Compress synthetic responses 2019-12-11 14:02:56 +01:00
Frank Denis 9553d7f8c5 Copy the DO bit from questions to synthetic responses 2019-12-11 13:56:25 +01:00
Frank Denis 1674bb1742 Force clear the AD bit unless the DO bit was also set 2019-12-11 09:41:16 +01:00
Frank Denis ee1c0fed93 Properly set DNS flags when creating empty responses 2019-12-11 09:00:29 +01:00
Frank Denis 3b4d6c532d A URL path must start with a / 2019-12-10 16:04:37 +01:00
Frank Denis 4d5c940616 Remove domains-blacklist-all.conf 2019-12-10 15:51:04 +01:00
Frank Denis 45d506efa1 Add the full path to minisign 2019-12-10 00:33:59 +01:00
Frank Denis 6d1e4a9b5d Travis: create /tmp/bin 2019-12-10 00:18:36 +01:00
Frank Denis 279d5619e3 Don't block '.' 2019-12-10 00:03:41 +01:00
Frank Denis 5d396d5f52 Grammar 2019-12-09 23:57:00 +01:00
Frank Denis 7fe2ac4b39 Pasto 2019-12-09 23:55:22 +01:00
Frank Denis c4673d86f5 Define _GNU_SOURCE 2019-12-09 23:45:41 +01:00
Frank Denis c68c672b47 libsodium -> libsodium-dev and move to before_deploy 2019-12-09 23:20:22 +01:00
Frank Denis 548a439528 Bump 2019-12-09 20:56:59 +01:00
Frank Denis a635e92606 Add a new plugin to block unqualified host names 2019-12-09 20:25:38 +01:00
Frank Denis 56d02597a6 Extend the grace period and log when it's used 2019-12-09 17:08:59 +01:00
Frank Denis 21a5765527 Rename resolveWithCache() and make the comment match what the fn does 2019-12-09 17:03:16 +01:00
Frank Denis 2d8fd40481 Don't use named return values just for one value, especially an error
Be consistent with the rest of the code
2019-12-09 16:59:02 +01:00
Frank Denis 3e32d38f29 Explicit initialization 2019-12-09 16:56:43 +01:00
Frank Denis 49460f1d6f pidfile.Write() can fail if no pid file was configured, it's ok 2019-12-09 13:34:14 +01:00
Frank Denis 7991b91f21 Downgrade error level of pidfile.Write() to Critical 2019-12-09 13:08:03 +01:00
Frank Denis b5bb0fd504 If we can't disconnect from the Service Manager, it's no big deal 2019-12-09 13:07:47 +01:00
Frank Denis bfd74185f5 Don't prevent DNS queries from being answered if the partition is full 2019-12-09 12:55:26 +01:00
milgradesec 8efbf401c8 add error checks 2019-12-09 12:50:30 +01:00
Frank Denis 51a842b838 Reapply miekg/dns updates to the vendor dir 2019-12-09 12:03:03 +01:00
Frank Denis 3d11d1d4e0 Revert "Update deps"
This reverts commit 915c90ae37.

The x/sys update breaks compilation on arm
2019-12-09 12:02:42 +01:00
Frank Denis 915c90ae37 Update deps 2019-12-09 10:09:37 +01:00
dependabot-preview[bot] f5880667c9 Bump github.com/miekg/dns from 1.1.22 to 1.1.24
Bumps [github.com/miekg/dns](https://github.com/miekg/dns) from 1.1.22 to 1.1.24.
- [Release notes](https://github.com/miekg/dns/releases)
- [Changelog](https://github.com/miekg/dns/blob/master/Makefile.release)
- [Commits](https://github.com/miekg/dns/compare/v1.1.22...v1.1.24)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-09 10:07:29 +01:00
Frank Denis ba8565a59e Shorten conditions 2019-12-09 10:07:05 +01:00
milgradesec 96d15771e2 add multiple error checks 2019-12-09 09:56:47 +01:00
Frank Denis 61a1637650 Use the singular 2019-12-09 00:01:43 +01:00
Frank Denis 5d778f998a Add issue templates 2019-12-09 00:00:22 +01:00
Frank Denis 2d28e5808d Add fastly.net 2019-12-08 12:30:52 +01:00
Frank Denis de10601a8e Add edgesuite.net to the example whitelist 2019-12-08 10:59:19 +01:00
Frank Denis 59f2df6318 Recommend more names to be forwarded 2019-12-07 17:38:07 +01:00
Frank Denis 62f0b80c66 Add a comment regarding forwarding and ipv6 blocking 2019-12-06 19:41:33 +01:00
Frank Denis db33c69fe5 Log the original qName when a CNAME pointer is blocked 2019-12-05 17:50:04 +01:00
Frank Denis 4d0c5ad569 Merge branch 'master' of github.com:jedisct1/dnscrypt-proxy
* 'master' of github.com:jedisct1/dnscrypt-proxy:
  Travis: use Ubuntu Bionic so we don't have to compile libsodium
  Downcase wiki
  Handle clientsCount in the local DoH handler, too
  Remove beta
  Bump deps
  Fix typo
  Bump
  whitelist
  Add some extra blacklists
2019-12-05 16:49:48 +01:00
Frank Denis 57a88eda56 Add (indirect) to the logged pattern for indirect blocks 2019-12-05 16:49:08 +01:00
Frank Denis 63e8494b44 Travis: use Ubuntu Bionic so we don't have to compile libsodium 2019-12-03 13:31:44 +01:00
Frank Denis 36cffffb11 Downcase wiki 2019-12-03 13:19:38 +01:00
Frank Denis 3a4bc98073 Handle clientsCount in the local DoH handler, too 2019-12-03 13:04:58 +01:00
Frank Denis 0de2246af2 Remove beta
Fixes #1086
2019-12-03 12:34:42 +01:00
Frank Denis 722089e561 Bump deps 2019-12-03 12:02:08 +01:00
glitsj16 443bdce879 Fix typo 2019-12-01 23:38:05 +01:00
Frank Denis 8da3107809 Bump 2019-12-01 17:57:42 +01:00
Frank Denis 98eb5ccd49 whitelist 2019-12-01 17:56:48 +01:00
Frank Denis ef5bde30a7 Merge branch 'master' of github.com:jedisct1/dnscrypt-proxy 2019-12-01 16:01:38 +01:00
Frank Denis 941cd63508 Add some extra blacklists 2019-12-01 16:01:17 +01:00
Frank Denis 21c63a5608 Local-DoH: pad responses 2019-11-29 21:34:21 +01:00
Frank Denis f9019f46a4 2019 2019-11-29 21:24:06 +01:00
Frank Denis 53dd5cd6c5 Clarify 2019-11-29 14:18:48 +01:00
Frank Denis 53924d4cf7 Unset GODEBUG - WHich means that Go 1.13 is now required for TLS 1.3
We could keep setting GODEBUG for compatibility with older versions, but
people complain that it prints debug warnings.
2019-11-29 14:00:21 +01:00
Frank Denis 4a613aa68d Explain what the path is in a URL 2019-11-29 13:42:35 +01:00
Frank Denis c84e104061 Mention local DoH 2019-11-29 09:30:41 +01:00
Frank Denis 3b50caf4cd Add a default local DoH path, print the URLs 2019-11-29 08:53:13 +01:00
Frank Denis 3b2eeea544 Include localhost.pem 2019-11-29 01:13:11 +01:00
Frank Denis 640b949976 Bump to 2.0.34-beta.1 2019-11-29 00:07:36 +01:00
Frank Denis b4356b9fc8 Update deps 2019-11-29 00:06:14 +01:00
Frank Denis 1f55b798c0 Update ChangeLog 2019-11-29 00:05:11 +01:00
Frank Denis f18dbc71ec Make the local DoH path configurable 2019-11-28 23:49:28 +01:00
Frank Denis 583ca09946 Reuse dataType 2019-11-28 23:33:34 +01:00
Frank Denis aad9c8f19c Limit the query body size 2019-11-28 23:32:56 +01:00
Frank Denis 5d6f9358c9 Print something useful when browsing the local DoH URL 2019-11-28 23:30:54 +01:00
Frank Denis 3ef9ec8732 Local DoH tweaks 2019-11-28 23:08:23 +01:00
Frank Denis 3e5dbee75a We don't need to store local copies of cachedResponses 2019-11-28 22:34:02 +01:00
Frank Denis 068509ef30 Rename http to local_doh 2019-11-28 17:11:14 +01:00
Frank Denis 6a679cc543 Move local DoH configuration to its own section 2019-11-28 17:04:29 +01:00
Frank Denis be996c486f Local DoH support, continued 2019-11-28 16:46:25 +01:00
Frank Denis 1966a8604b up 2019-11-26 01:36:35 +01:00
Frank Denis f249813cc5 First bits towards providing access over DoH in addition to DNS
Mainly to deal with the Firefox+ESNI situation
2019-11-24 22:46:27 +01:00
Frank Denis 30b5507bf4 Make the part that creates or gets sockets more readable 2019-11-24 22:12:23 +01:00
Frank Denis bc22f94eeb Don't listen to IPv6 in the example config file
Some hosts don't support IPv6, and the default (without anything in
the config file) is only the IPv4 address anyway.
2019-11-24 10:31:40 +01:00
Frank Denis 67c7254dc5 block_name plugin: also check names found in CNAME records 2019-11-24 10:18:46 +01:00
Frank Denis 1152491b2d Move PluginCache before PluginCacheResponse 2019-11-24 09:14:36 +01:00
Frank Denis 6e3916556f Downcase the query name in BlockedNames.check() 2019-11-20 19:16:37 +01:00
Frank Denis 4aba44898b Bump 2019-11-18 13:00:34 +01:00
Frank Denis a43889741b Up 2019-11-18 12:55:04 +01:00
Frank Denis 230a66ea73 Add an extra byte to the padded length
Fixes resolution of livegorouter.trafficmanager.net via Cisco
2019-11-18 12:50:19 +01:00
Frank Denis 925c12d334 Set the list of blocked names even if logging was not enabled
Fixes #1050
2019-11-18 01:42:51 +01:00
Frank Denis 0790328424 Revert "Revert "plugin_block_name: make the blocking code reusable""
This reverts commit 2d00c24f85.
2019-11-18 01:32:17 +01:00
Frank Denis 2d00c24f85 Revert "plugin_block_name: make the blocking code reusable"
This reverts commit f76e0fd8cf.
2019-11-18 01:29:06 +01:00
Frank Denis 41e23f4c66 Update ChangeLog 2019-11-18 01:16:50 +01:00
Frank Denis 41e35bd8c5 Compress responses 2019-11-18 01:13:18 +01:00
Frank Denis 2d5dc5960a Typo 2019-11-17 23:07:49 +01:00
Frank Denis 821c26178f Typo 2019-11-17 23:07:02 +01:00
Frank Denis d2c6e3ea00 Typo 2019-11-17 23:06:34 +01:00
Frank Denis 578f359f23 Update kardianos/service 2019-11-17 22:54:56 +01:00
Frank Denis 8728361e89 Replace SERVER_ERROR with SERVFAIL
If only because SERVFAIL can be looked up on Google
2019-11-17 22:20:47 +01:00
Frank Denis 1bcd09ca5a Document NETWORK_ERROR 2019-11-17 22:15:44 +01:00
Frank Denis 0b64c5df66 Improve logging 2019-11-17 22:04:58 +01:00
Frank Denis ad40c6c54b Fallback to the system resolver if the fallback resolver doesn't work
This is useful if fallback_resolver has been set to random junk, or
to an external resolver, but port 53 is blocked.

At least, it may allow the server to start.
2019-11-17 22:00:08 +01:00
Frank Denis b03e7f993f Add a default list of buggy servers 2019-11-17 21:44:46 +01:00
Frank Denis 6dcd872385 This is unlikely to become mandatory 2019-11-17 21:38:09 +01:00
Frank Denis 45cb7b48df Format 2019-11-17 21:28:26 +01:00
Frank Denis 64d804486d Bump, update ChangeLog 2019-11-17 21:25:54 +01:00
Frank Denis e211e18f71 Improve logging 2019-11-17 20:40:59 +01:00
Frank Denis 4e217267d4 Log the server name, not the provider name 2019-11-17 20:37:55 +01:00
Frank Denis c3d93124a7 Bump MinResolverIPTTL up 2019-11-17 20:30:59 +01:00
Frank Denis faac6e2082 Set default ignore_system_dns to true 2019-11-17 20:30:04 +01:00
Frank Denis 0e8d1a941b Typo 2019-11-17 20:30:00 +01:00
Frank Denis 068c8e70f2 Typo 2019-11-17 20:00:34 +01:00
Frank Denis 071dceef31 Update deps 2019-11-17 19:50:40 +01:00
Frank Denis 06c0fbb65b Add NETWORK_ERROR 2019-11-17 19:48:15 +01:00
Frank Denis ca7e5e5bcb Rename a few things 2019-11-17 15:07:40 +01:00
Frank Denis 15b405b552 Support workarounds for ancient/broken implementations
Fixes #984
2019-11-16 18:51:16 +01:00
Frank Denis f76e0fd8cf plugin_block_name: make the blocking code reusable 2019-11-15 19:48:15 -05:00
Frank Denis 60aba17e44 Merge branch 'master' of github.com:jedisct1/dnscrypt-proxy 2019-11-14 22:34:44 -05:00
Frank Denis 568376ea13 Update deps 2019-11-14 22:34:38 -05:00
William Elwood e016300aab Fix tests if filesystem stores less precise times
Not all filesystems store modification times with millisecond precision.
2019-11-14 12:47:55 +00:00
William Elwood 2c49804bd0 Renormalize line-endings
Git has been nagging me about these files that I haven't touched being changed.
The solution was to run `git add --renormalize .`.
Apparently this needs to be done after setting up `.gitattributes`.
According to `git ls-files --eol windows/`, the .bat files were previously stored in the index with CRLF endings and will now be stored with LF endings (with .gitattributes dictating that checked out copies will use CRLF).
2019-11-12 16:10:57 +00:00
Will Elwood d063a7959e
Avoid redirect and extra DNS lookup in example
Also makes the URL consistent with the other lists.
2019-11-10 12:48:21 +00:00
William Elwood a521caf6fc Add test for short refresh delay
Ensures a short refresh delay is ignored and the default minimum used instead.
2019-11-10 13:42:17 +01:00
William Elwood 0d0c634242 Avoid writing cache if it didn't change
Most of the time the only useful difference being written is the new modification time anyway, which is now being done explicitly.
2019-11-10 13:42:17 +01:00
William Elwood d43fcabe69 Fix prefetch sometimes being skipped
Previously when the cache was written to disk, the modification time was unspecified.
At the next prefetch, it was possible for the cache to be expiring very soon (on the order of milliseconds) but still deemed valid.
Now the modification time is explicitly set to when the prefetch run began to make this situation much less likely.
2019-11-10 13:42:17 +01:00
Frank Denis 96ffc778af Merge branch 'master' of github.com:jedisct1/dnscrypt-proxy
* 'master' of github.com:jedisct1/dnscrypt-proxy:
  set go.mod to unix endings
2019-11-08 22:51:36 +01:00
Frank Denis a31e7c0c61 Avoid ridiculously low values for proxy.certRefreshDelay 2019-11-08 22:51:04 +01:00
Alison Winters d9fcd74e42 set go.mod to unix endings 2019-11-08 18:30:23 +01:00
Frank Denis 0f7bd23b8a Simplify 2019-11-08 11:28:41 +01:00
William Elwood 4324a09fc9 Fix failing tests on Windows
To simulate failures opening a cache file, fixtures are written without the read permission bits.
Since Unix permission bits have no meaning on Windows, a slightly more complicated solution is required to achieve the same permissions.
Thankfully, there's a library to abstract that already.
2019-11-08 10:17:12 +01:00
William Elwood 77a4a3da90 Reduce indentation and long lines in test 2019-11-08 10:17:12 +01:00
William Elwood 0aea5f81ef Raise log level of a prefetch failure
This way it matches with the "loading from URL" info message and users with that log level aren't left with the false impression that it loaded fine when it really didn't.
2019-11-08 10:17:12 +01:00
William Elwood 5ed7b7c24f Reduce the chances of corrupting the cache
Write both parts of the cache to their temp files before renaming
Now only the 2nd rename failing can leave the cache in a bad state.
2019-11-08 10:17:12 +01:00
William Elwood b6d11b4351 Parse source URLs sooner
URLs only need to be parsed once, after that they are always available to the download func.
2019-11-08 10:17:12 +01:00
William Elwood bf28325b61 Enable tests for expired cache
If the cache is expired but then all downloads fail, the cache should be used.
2019-11-08 10:17:12 +01:00
William Elwood 38019866ca Move download loop, fix unnecessary cache reads
Previously, an expired cache would be read before trying each URL until a download completed.
By moving the download loop, the cache can be read once outside the loop.
2019-11-08 10:17:12 +01:00
William Elwood f6f1a75884 Improve logging by keeping a Source's configured name on the struct 2019-11-08 10:17:12 +01:00
William Elwood b697283309 Minor cleanup, mostly in tests 2019-11-08 10:17:12 +01:00
William Elwood c0e34d1a9e Verify signature immediately after reading from cache or URL
This allows a large number of tests to be enabled and pass now that the behaviour is expected.
The main fix here is that a download with an invalid signature will always fall back on using a properly signed cache, no matter how old it is.
Additionally, downloads will never be written to the cache unless they are properly signed (both at startup and prefetching).
2019-11-08 10:17:12 +01:00
William Elwood 53d5b0f3cd Remove URLToPrefetch struct 2019-11-08 10:17:12 +01:00
William Elwood a83ecf626b Move `when` from URLToPrefetch struct to `refresh` on Source struct 2019-11-08 10:17:12 +01:00
William Elwood b29c70551e Refactor writing download to cache 2019-11-08 10:17:12 +01:00
William Elwood 082a4a5e01 Clarify how refresh_delay is intended to be used internally
Cache TTL is how old the cache can be at startup before trying to download an update immediately.
Prefetch delay is how long the prefetcher should wait between successful downloads of a source.
Previously, the refresh_delay configuration was used at startup as both cache TTL and prefetch delay, with subsequent prefetches using a hard-coded delay.
As discussed, refresh_delay is now only used for cache TTL, prefetch delay always uses the hard-coded delay.
2019-11-08 10:17:12 +01:00
William Elwood 190700e5ba Move cacheFile from URLToPrefetch to Source struct 2019-11-08 10:17:12 +01:00
William Elwood 0991749b19 Allow source URLs to contain query parameters
Previously when constructing the signature URL, the `.minisig` suffix was blindly appended to the string version of the source URL.
Now we take the parsed source URL, deep copy it (saves us parsing it twice), and append the `.minisig` suffix to the path component of the URL.
2019-11-08 10:17:12 +01:00
William Elwood b2ecc45133 Treat each list and signature pair as a single unit
When a list fails to download, there's no point trying to download the signature.
Code duplication moved to where it's easier to refactor away.
Enabled a few more tests.
2019-11-08 10:17:12 +01:00
William Elwood 1e225dbb67 Alter source tests to cover entire prefetch algorithm and make it pass 2019-11-08 10:17:12 +01:00
William Elwood 7e73a26a2f Move most of the prefetching code into sources.go
The proxy shouldn't need to know how prefetching works, just that it needs to do it occasionally. Now the prefetching algorithm can be refactored without having to touch the proxy code.
2019-11-08 10:17:12 +01:00
William Elwood 78f2dead79 Move prefetch URLs onto Source struct
This is mostly in preparation for further refactoring, but does reduce the number of return values from `NewSource()` too.
2019-11-08 10:17:12 +01:00
William Elwood 4a792026eb Refactor cache reading to reduce number of return values 2019-11-08 10:17:12 +01:00
William Elwood fe34d07b68 Refactor away some unnecessary type shuffling
Signatures in particular were read in from both cache and url as `[]byte`, converted to `string`, then back to `[]byte` to pass through to minisign.
Lists themselves will be converted to `string` by the parsing code anyway.
2019-11-08 10:17:12 +01:00
William Elwood ad92be5b9c Refactor saving downloads to cache
Moved writing to happen immediately after the download to reduce duplicated code and number of return values from the download function.
2019-11-08 10:17:12 +01:00
William Elwood 4c156784c8 Refactor calculation of update delay when reading cache
Set the default delay once at the top instead of before every early return.
2019-11-08 10:17:12 +01:00
William Elwood e818eeb800 Refactor reading a URL's content to own function
No longer shadows `url` package with variable of the same name.
2019-11-08 10:17:12 +01:00
William Elwood d851c9eeb6 Refactor signature verification to own function
The cache is no longer destroyed whenever any signature verification fails.
The public key is stored on the Source struct for future use.
2019-11-08 10:17:12 +01:00
William Elwood da0d7fe841 Fix various timing inconsistencies
When comparing times in tests, it's necessary to control the `now` value to ensure slow test runs don't fail incorrectly.
Both cache and download code had been using refreshDelay to set the next prefetch delay, which by default meant the 1st prefetch was 3 days after startup - this has now been corrected to match the 1 day expectation.
Enabling some of the cache tests revealed some other incorrect failures in the test that were also fixed.
2019-11-08 10:17:12 +01:00
William Elwood 03dea47130 Remove dead code paths
These paths were unreachable because XTransport.Get already checks the same conditions.
2019-11-08 10:17:12 +01:00
William Elwood af0629856c Add unit tests for sources.go
Tests cover most of the cache and download related code paths and specify the expected result of various starting states and external failure modes.
Where the current code's behaviour doesn't match a test's expectations, the test is disabled and annotated with a TODO until it can be fixed.
Added dependency on `github.com/powerman/check` and ran `go mod vendor`.
2019-11-08 10:17:12 +01:00
William Elwood 503bfb877b go mod tidy
```console
$ go mod tidy -v
(snip)
unused github.com/agl/ed25519
```
Also add base .gitattributes file to normalize line endings in the repository across differing developer environments.
2019-11-08 10:17:12 +01:00
Frank Denis e6a4a4ffda Update deps 2019-11-05 01:32:38 +01:00
Frank Denis b76db70a6c Revert "cleanup: estimators: simplify blindAdjust"
This reverts commit c699e7bec4.
2019-11-05 01:16:22 +01:00
Frank Denis 17a675021e No one ever completes // TODO things 2019-11-05 01:10:57 +01:00
Frank Denis da3f30871f Revert "fix: proxy: Trigger query logging plugins using defer"
This reverts commit fc9509a8c8.
2019-11-05 00:54:03 +01:00
Frank Denis 14862c2fc7 defer is slow and not worth it here 2019-11-05 00:37:46 +01:00
Frank Denis 316c5ca6b1 Don't return immediately on non-Windows system if netprobe_timout is -1
Fixes #1016
2019-11-04 17:14:31 +01:00
Frank Denis 9852a289f8 Increase the default cache size and minimum TTL 2019-11-03 17:31:41 +01:00
Frank Denis e0c37f92fc Add a comment about why DoH addresses from stamps don't expire 2019-11-03 00:33:17 +01:00
Frank Denis 0f332c644d Set a minimum TTL when caching resolver IPs
Comcast having a 30 sec TTL is silly
2019-11-02 02:01:03 +01:00
Frank Denis 63ed3b4fef Update comment 2019-11-02 01:52:51 +01:00
Frank Denis a84a789a8a Keep resolving if needed 2019-11-02 01:50:35 +01:00
Frank Denis d932d5fdfc Inverse test 2019-11-02 01:20:28 +01:00
Frank Denis 6032c3b79b Add a grace TTL for expired cached IPs
And some comments to make the code more readable
2019-11-01 23:19:07 +01:00
Frank Denis 0dc69eacd5 resolveHostWithCache -> resolveWithCache 2019-11-01 23:10:36 +01:00
Frank Denis b30904f20b lowercase 2019-11-01 23:06:42 +01:00
Frank Denis 8d191cdcf1 Rename CheckResolver to IsIPAndPort for clarity 2019-11-01 23:05:17 +01:00
Frank Denis 3cef651b07 Rename resolveHost() to resolveHostWithCache() for clarity
(but to be honest, I don't understand anything to that code any more)
2019-11-01 23:00:39 +01:00
Frank Denis e028f4d483 Don't delete cached server IP addresses
If we can't update an entry, keep the previous one.
2019-11-01 22:55:06 +01:00
Frank Denis 3db3de0a91 Use SystemResolverTTL as a minimum timeout for cached resolver IPs 2019-11-01 21:47:13 +01:00
Alison Winters 97e4c44223 remove err return values that are never set 2019-11-01 17:13:14 +01:00
Alison Winters 36808cdec7 remove unused patternType return 2019-11-01 17:13:14 +01:00
Alison Winters a0d9412a25 run goimports 2019-11-01 17:13:14 +01:00
Will Elwood cd675913b2
Fix copy-paste oversight
I think these variables are always both nil or both not nil, but maybe in the future they might not be.
2019-11-01 09:07:57 +00:00
Alison Winters 816acb9d8d move ConfigLoad into AppMain 2019-10-31 18:55:44 +01:00
Alison Winters 2f7e057996 move flags parsing into main() 2019-10-31 18:55:44 +01:00
Frank Denis 116f985b96 Bump 2019-10-31 18:12:13 +01:00
Frank Denis c5bda9e2ae Update deps 2019-10-31 18:00:44 +01:00
Frank Denis 59c3d5121d Add brackets around cached IPv6 IP addresses
Fixes #1005
2019-10-31 17:55:54 +01:00
Eric Lagergren 1c9924e055 check error that was being erroneously shadowed 2019-10-31 17:55:26 +01:00
Frank Denis 971b08bcec No more beta 2019-10-31 17:54:04 +01:00
Frank Denis 06b0976786 Remove the serverInfo rwlock; just use the global serversInfo rwlock 2019-10-31 17:50:56 +01:00
Frank Denis 3a68f90c37 Back to 2.0.29 beta 3 (ceed905196) 2019-10-31 17:50:19 +01:00
Frank Denis fb1fc14317 Revert "refactoring of pull 980"
This reverts commit 6fa420a8e0.
2019-10-31 17:36:59 +01:00
Frank Denis 7636a78d74 Revert "avoid LoadConfig twice"
This reverts commit 8f2c438c70.
2019-10-31 17:36:32 +01:00
Frank Denis 828af28658 Revert "move ConfigLoad and InitPluginsGlobals to appMain"
This reverts commit b67d19ffb3.
2019-10-31 17:36:28 +01:00
Frank Denis 393195066e Up 2019-10-31 16:50:38 +01:00
Frank Denis ac0425835b Update ChangeLog 2019-10-31 16:42:36 +01:00
Frank Denis 71e3cf4aef Add brackets around cached IPv6 IP addresses
Fixes #1005
2019-10-31 16:38:43 +01:00
Vladimir Bauer b67d19ffb3 move ConfigLoad and InitPluginsGlobals to appMain 2019-10-31 15:04:12 +01:00
Vladimir Bauer 8f2c438c70 avoid LoadConfig twice 2019-10-31 15:04:12 +01:00
Vladimir Bauer 65de188423 don't use syscall directly 2019-10-31 15:04:12 +01:00
Vladimir Bauer 6fa420a8e0 refactoring of pull 980
follow up on https://github.com/DNSCrypt/dnscrypt-proxy/pull/980#issuecomment-548153169
2019-10-31 15:04:12 +01:00
Alison Winters 9eae8de902 fix the file not found error message when passing -config 2019-10-31 09:53:44 +01:00
Alison Winters 7307c51d6f move ConfigLoad into Start function when running as a service (take 2) 2019-10-31 09:53:44 +01:00
Alison Winters b80e4957d1 move flags parsing into main() 2019-10-31 09:53:44 +01:00
Eric Lagergren 7f82c2504d check error that was being erroneously shadowed 2019-10-31 09:52:05 +01:00
Frank Denis 899cd07239 Bump 2019-10-30 23:02:07 +01:00
Will Elwood 37c939480d
Potential fix for #998
I haven't tested this change, but it should be as simple as that.
2019-10-30 19:01:37 +00:00
Frank Denis 778b2cccc1 Revert "move ConfigLoad into Start function when running as a service"
This reverts commit 9aeec3478f.
2019-10-30 08:02:31 +01:00
Frank Denis 12eaec9104 Nits 2019-10-29 13:13:56 +01:00
Alison Winters 9aeec3478f move ConfigLoad into Start function when running as a service 2019-10-28 15:29:02 +01:00
Frank Denis 4eea03c9a1 No more beta 2019-10-28 12:18:51 +01:00
Frank Denis fe3b8b6321 Merge branch 'master' of github.com:jedisct1/dnscrypt-proxy
* 'master' of github.com:jedisct1/dnscrypt-proxy:
  Fix travis build
2019-10-27 23:36:42 +01:00
Frank Denis 2add754f23 Don't use real server names, because this is apparently confusing 2019-10-27 23:36:08 +01:00
Will Elwood 0c2fb16214 Fix travis build
Hopefully this is all that's needed to make it go green, I'm not set up to test locally.
2019-10-27 09:54:05 +01:00
Frank Denis 4824e91d46 Remove the serverInfo rwlock; just use the global serversInfo rwlock 2019-10-26 17:28:24 +02:00
Frank Denis d17b572b75 Update deps 2019-10-26 16:51:14 +02:00
Vladimir Bauer 6680faf665 make sure tcp/udp Conn are closed on stop signal 2019-10-25 12:56:34 +02:00
Vladimir Bauer 220d418f2f make sure app main goroutine quits, before stopping 2019-10-25 12:56:34 +02:00
Frank Denis ceed905196 Add a more explicit message when a user is set on Windows 2019-10-25 12:53:59 +02:00
Frank Denis f60395390e Typo 2019-10-23 23:30:39 +02:00
Frank Denis e5f3eff760 Add DNS stamps to JSON output 2019-10-23 23:28:46 +02:00
Frank Denis 560577af00 Correctly honor MaxTimeout on Windows, too 2019-10-22 11:53:59 +02:00
Frank Denis 32b691a5c7 Merge branch 'master' of github.com:jedisct1/dnscrypt-proxy
* 'master' of github.com:jedisct1/dnscrypt-proxy:
  Reduce contention
  Don't name different things "ttl" to avoid confusion
  Reduce lock contention
  Nits
  Rename negTTL to rejectTTL to avoid confusion with cacheNegTTL
  feature: Add neg_ttl for rejected entries and cloak_ttl for cloaking-rules entries
  feature: xtransport: Expire CachedIPs, split resolve function from Fetch
  fix: xtransport: Check 'fallback_resolver'
  fix: xtransport: Ensure we strip [] from host/ip before net.ParseIP
  cleanup: xtransport: group all consts and alike
2019-10-22 11:51:38 +02:00
Frank Denis 94c16c3167 MaxTimeout is the maximum timeout, not the minimum
Fixes #977
2019-10-22 11:51:22 +02:00
Frank Denis 3ddb134190 Reduce contention 2019-10-21 18:50:20 +02:00
Frank Denis a0614510e9 Don't name different things "ttl" to avoid confusion 2019-10-21 18:40:47 +02:00
Frank Denis ffd60d21db Reduce lock contention 2019-10-21 18:36:47 +02:00
Frank Denis 70970d2333 Nits 2019-10-21 18:31:06 +02:00
Frank Denis a26b2b42f0 Rename negTTL to rejectTTL to avoid confusion with cacheNegTTL 2019-10-21 18:26:49 +02:00
Markus Linnala bb01595320 feature: Add neg_ttl for rejected entries and cloak_ttl for cloaking-rules
entries

Previously cache_min_ttl was used. But one can certainly set
cache_min_ttl to 0, but still ensure synthetic values have ttl.
Hence new config file options.
2019-10-21 18:12:49 +02:00
Markus Linnala bc831816f5 feature: xtransport: Expire CachedIPs, split resolve function from Fetch
I selected default ttl when resolving using system to be 86400 / 24h.

As the program can run long time, I think it is relevant to honor TTL
when resolving and caching results.

Change cache internal format from string to net.IP. This should ensure
there is no need to further check validity of value later when using.

Resolve part was too big and had only one purpose. So it is fine
candidate to be own function.
2019-10-21 18:12:49 +02:00
Markus Linnala d14d78e648 fix: xtransport: Check 'fallback_resolver'
And also DefaultFallbackResolver.

As far a I could see, value needs to have port defined
too. dns.Exchange does seem to use address as such.
2019-10-21 18:12:49 +02:00
Markus Linnala 890dcca270 fix: xtransport: Ensure we strip [] from host/ip before net.ParseIP 2019-10-21 18:12:49 +02:00
Markus Linnala ac4843b460 cleanup: xtransport: group all consts and alike
This is mainly for case where more consts are added.

Also I think those vars were not variables but treated as
const.
2019-10-21 18:12:49 +02:00
Frank Denis 92e632daf1 Fail on failure :) 2019-10-20 23:07:36 +02:00
Markus Linnala 1cb9a360de fix: proxy: Add missing logging in a case where flow does not return 2019-10-20 22:27:30 +02:00
Frank Denis 74c1f4a00d Use the relay for cert retrieval over TCP, tooo
But don't use a relay if a proxy has been specified already
2019-10-20 21:45:19 +02:00
Markus Linnala fc9509a8c8 fix: proxy: Trigger query logging plugins using defer
This is more robust and uses lot less lines.
2019-10-20 21:30:24 +02:00
Markus Linnala 1b4f873026 fix: serversInfo: use lb strategy always even with estimator
I don't see why estimator should select which candidate to use.
2019-10-20 21:30:24 +02:00
Markus Linnala bc9a37e550 fix: serversInfo: Fix strategy ph to use half of values
Without this fix 'ph' is essentially the same sa 'p2'.
2019-10-20 21:30:24 +02:00
Markus Linnala 147078d588 cleanup: serversInfo: parse host from ServerAddrStr with ExtractHostAndPort
Use only one method to parse host from port.
2019-10-20 21:30:24 +02:00
Markus Linnala 659ff4b19d cleanup: plugins: rename error variable as err
Follow go naming tradition.
2019-10-20 21:30:24 +02:00
Markus Linnala 6ba2ff4fdc cleanup: config: rename static config as StaticsConfig
Naming similar as SourcesConfig.
2019-10-20 21:30:24 +02:00
Frank Denis 084896c3e1 Update changelog 2019-10-20 19:50:19 +02:00
Frank Denis c11723101a Bump 2019-10-20 19:46:25 +02:00
Frank Denis fccf0ba984 Improve logging 2019-10-20 19:40:03 +02:00
Frank Denis f565d3c7f5 Documentation 2019-10-20 19:30:33 +02:00
Frank Denis 5c28950578 Bump the default timeout up
Because, yes, some networks have a lot of latency
2019-10-20 19:22:02 +02:00
Frank Denis 551ddcf199 Improve logging 2019-10-20 19:11:54 +02:00
Frank Denis 2785cc579e Use bigger cert padding 2019-10-20 18:02:14 +02:00
Frank Denis 340a2ead9c Quick ChangeLog update 2019-10-20 15:12:04 +02:00
Frank Denis 0a4bd845df systemd keeps breaking things 2019-10-20 14:57:28 +02:00
Frank Denis 320197a00e Accept relay names in routes, improve documentation 2019-10-20 14:19:21 +02:00
Frank Denis 535bce308c Retry over a direct connection if we can't get a cert via a relay
This is temporary and only to provide compatibility with servers not
running the latest version of encrypted-dns-server.
2019-10-20 12:26:12 +02:00
Frank Denis f9c244db10 Fix typo
I'm quite surprised that it didn't break Android builds
2019-10-20 12:03:20 +02:00
Frank Denis 7fc7eb6f07 Bump 2019-10-20 02:15:06 +02:00
Frank Denis fbe9f225dd Reencrypt on TCP retries 2019-10-20 02:04:32 +02:00
Frank Denis 661477bf09 Note 2019-10-20 01:35:27 +02:00
Frank Denis ff13c813e4 Support relaying for certificates retrieval 2019-10-19 23:50:05 +02:00
Frank Denis d6b63aaf15 Pad certificate requests and add support for proxies 2019-10-19 22:08:02 +02:00
Alison Winters ac6fd3db39 differentiate between timeout and other error for dnscrypt servers 2019-10-19 10:36:26 +02:00
Markus Linnala 0058bc063e feature: service_linux: Support systemd watchdog 2019-10-19 09:36:39 +02:00
Frank Denis 18ba5fe528 Add a SERVFAIL comment because miekg/dns names are a bit unusual 2019-10-18 20:51:11 +02:00
Frank Denis 94cf37dacf Do the netprobe even in offline mode
This is likely to be required at least on Windows.
2019-10-18 20:34:26 +02:00
Frank Denis bcaf0bca96 proxy.certIgnoreTimestamp should only be downgradable 2019-10-18 20:30:41 +02:00
Markus Linnala e5221167e1 cleanup: serversInfo: refreshServer does not use previousIndex as index, use bool instead 2019-10-18 20:24:11 +02:00
Markus Linnala 2a51dca073 cleanup: serversInfo: fetchServerInfo does not use serversInfo 2019-10-18 20:24:11 +02:00
Markus Linnala 683b111bf9 cleanup: serversInfo: simplify handling onld/new servers 2019-10-18 20:24:11 +02:00
Markus Linnala 63520e494d fix: updateTTL guard against overflow 2019-10-18 20:24:11 +02:00
Markus Linnala 13e9c15212 cleanup: MinDNSPacketSize is checked next 2019-10-18 20:24:11 +02:00
Markus Linnala c699e7bec4 cleanup: estimators: simplify blindAdjust 2019-10-18 20:24:11 +02:00
Markus Linnala 111072dec5 change: systemd_linux: Fail if there is error to setup listeners 2019-10-18 20:24:11 +02:00
Markus Linnala acb4bbd002 fix: plugins: use deferred lock to catch all branches 2019-10-18 20:24:11 +02:00
Markus Linnala 5bf5fe6c1d cleanup: main: simplify proxy handling 2019-10-18 20:24:11 +02:00
Markus Linnala cab67ba5a9 cleanup: drop registerServer proxy as not used 2019-10-18 20:24:11 +02:00
Markus Linnala 21d71ac9be change: serversInfo: Use sort instead of own implementation 2019-10-18 20:24:11 +02:00
Markus Linnala 9b019574a0 cleanup: serversInfo : Simplify liveServers handling 2019-10-18 20:24:11 +02:00
Markus Linnala a941cbd893 cleanup: xtransport: simplify body creation 2019-10-18 20:24:11 +02:00
Markus Linnala 345ec56cab cleanup: xtransport: move onion check earlier to fail fast 2019-10-18 20:24:11 +02:00
Markus Linnala df03065eaf change: xtransport: Return http response status string as error, do name make own string
This gives much better possibilities to diagnose problems than error
message with only "informative" part being 500.
2019-10-18 20:24:11 +02:00
Markus Linnala 72681725b1 clanup: xtransport: use MaxDNSPacketSize more 2019-10-18 20:24:11 +02:00
Markus Linnala 0d553a9fa7 cleanup: Drop ExtractPort ExtractHost, use ExtractHostAndPort instead 2019-10-18 20:24:11 +02:00
Markus Linnala f0fae0c756 cleanup: xtransport: There is no function level foundIP in resolveUsingResolver
Rename foundIPx to foundIP just to make it nicer looking.
2019-10-18 20:24:11 +02:00
Markus Linnala 80fa99877f cleanup: proxy: use symbolic code for SERVFAIL 2019-10-18 20:24:11 +02:00
Markus Linnala e8ad2be9f9 change: android does not have systemd
Android is counted as being linux too.

At least according to wikipedia android does not have systemd:
https://en.wikipedia.org/wiki/Systemd
2019-10-18 20:24:11 +02:00
Markus Linnala 8c6a968e27 change: config: handle NetProbe fatal error and run only if not offline
All errors returned from NetProbe are managed as fatal later.
Decide, connection issues are not fatal but bad configuration is.
Without this configuration errors are silently ignored here.
2019-10-18 20:24:11 +02:00
Markus Linnala 32c387318a cleanup: config: drop duplicate code in showCerts setup 2019-10-18 20:24:11 +02:00
Markus Linnala ab94e7eb8a style: gofmt -w -s -d dnscrypt-proxy 2019-10-18 20:24:11 +02:00
Markus Linnala 5e5d1059d7 change: config: cache_max_expire default value from 8600 to 86400 2019-10-18 20:24:11 +02:00
Frank Denis be86d1df27 Fetch the list of relays 2019-10-18 15:53:56 +02:00
Frank Denis 4a5bf3ed8c Extra records don't necessarily need to raise a warning
Proper TXT records can still be present in the response.
2019-10-17 18:33:24 +02:00
Vladimir Bauer 108b7f8446 fix panic if dns.RR is not a *dns.TXT 2019-10-17 18:27:29 +02:00
Frank Denis 55c6cb6c79 Crude fix for #961 2019-10-15 00:47:05 +02:00
Frank Denis 858957ce91 up 2019-10-14 13:27:20 +02:00
Frank Denis 332ba9a7ed Up 2019-10-14 12:13:04 +02:00
Frank Denis dae384f078 2.0.29-beta.1 2019-10-14 12:11:13 +02:00
Frank Denis 322447aa91 Support multiple routes per destination 2019-10-14 12:08:47 +02:00
Frank Denis e9ec2aa801 Log anonymized DNS routes 2019-10-14 11:02:13 +02:00
Frank Denis e6b9f3c2c0 Update go-dnsstamps 2019-10-14 10:50:09 +02:00
Frank Denis f06967a020 Accept stamps of the new DNSCryptRelay type 2019-10-14 02:26:05 +02:00
Frank Denis 67f46b3c3e Update go-dnsstamps 2019-10-14 02:24:04 +02:00
Frank Denis 0e8ca9009e Implement Anonymized DNS 2019-10-14 01:45:38 +02:00
Frank Denis 63e6dbdac7 Avoid strings.ReplaceAll() that was introduced too recently 2019-10-12 22:22:28 +02:00
Frank Denis ed0dbc2b55 Code completion propagates typos :) 2019-10-12 22:18:10 +02:00
Frank Denis a73b547aa2 Update repos name in Travis 2019-10-12 22:13:16 +02:00
Frank Denis f088dd4b2c Use vendored packages in CI builds 2019-10-12 22:09:59 +02:00
Frank Denis aaf493714b Service fix for Catalina 2019-10-12 22:05:46 +02:00
Frank Denis af022d01b4 Add a cloaking example of multiple IPs for a single entry 2019-10-12 21:48:59 +02:00
Frank Denis e974780026 Bump 2019-10-12 21:30:47 +02:00
Frank Denis d2db6b55a8 Update deps 2019-10-12 21:22:15 +02:00
Frank Denis d627a4bc58 Limit the number of required retries for local queries 2019-10-12 21:15:39 +02:00
Frank Denis 20f48edc25 Truncated response over UDP -> immediately retry over TCP
This reduces latency, because when the client retries, or if the
query padding was large enough, we can reply from the cache or
even immediately.
2019-10-12 20:55:59 +02:00
Alison Winters 99e56a400f when parsing a source, try to process all of the servers to ensure maximum connectivity
- a corrupt source (no names/descriptions) will still abort parsing immediately
- a duplicate, missing or invalid server stamp will not abort parsing
  - these errors are logged as warnings, and returned as a single error at the end
2019-10-06 13:56:53 +02:00
Frank Denis 6513818cb3 Continue if some (but not all) server entries are invalid
Diff by @alisonatwork -- thanks!

Fixes #949
2019-10-06 09:13:37 +02:00
Frank Denis 2b23d7ae24 Add some details to the "certificate not valid" debug messages 2019-10-01 08:02:27 +02:00
Frank Denis 2c16bc4eaf Bump InitialMinQuestionSize up 2019-09-26 00:39:13 +02:00
Frank Denis bd23ddaa02 Merge branch 'master' of github.com:jedisct1/dnscrypt-proxy
* 'master' of github.com:jedisct1/dnscrypt-proxy:
  Add deepsource
2019-09-23 10:34:13 +02:00
Frank Denis ad5b2dc4f9 Mention that /dev/stdout can be used to log to the standard output 2019-09-23 10:33:57 +02:00
Frank Denis 9f3f2e9314 Merge branch 'master' of github.com:jedisct1/dnscrypt-proxy
* 'master' of github.com:jedisct1/dnscrypt-proxy:
  Deprecate systemd sockets
  Don't log a server for cached responses (again)
  Don't log a server name for synthetic responses and cloaking
  When forwaring, log the forwarding server instead of the regular one
  Update URLs
2019-09-19 20:26:28 +02:00
Frank Denis 3da36cf71f Add deepsource 2019-09-19 20:26:15 +02:00
Frank Denis ed79bd7489 Deprecate systemd sockets 2019-09-16 15:46:39 +02:00
Frank Denis 7f42123e06 Don't log a server for cached responses (again) 2019-09-11 14:34:18 +02:00
Frank Denis 3d3b5bbc00 Don't log a server name for synthetic responses and cloaking 2019-09-11 14:28:33 +02:00
Frank Denis 23aa3dd57d When forwaring, log the forwarding server instead of the regular one
Fixes #928
2019-09-11 14:17:11 +02:00
Frank Denis f4c1bb7bbf Update URLs 2019-09-11 14:09:12 +02:00
Frank Denis 24794acb08 Update ChangeLog 2019-09-09 18:46:54 +02:00
Frank Denis 8c147c7efd Manually pin dependency revisions 2019-09-09 18:45:42 +02:00
Frank Denis 4974ce98a3 Update ChangeLog 2019-09-09 18:12:36 +02:00
Frank Denis e49823d328 More deps update 2019-09-09 18:08:44 +02:00
Frank Denis 1a06806477 Revert "Use CIRCL for X25519. That makes ephemeral key computation faster."
This reverts commit 5d130cdf0b.

Revert "Kill nacl/box"

This reverts commit dd9cf5cc9a.
2019-09-09 17:43:30 +02:00
Frank Denis 0e7692524e Remove unused function 2019-09-07 17:06:42 +02:00
Frank Denis 3e10fc917f Of course, things have to be different on Linux 2019-09-07 16:45:11 +02:00
Frank Denis 5c9c20c974 swizzle 2019-09-07 16:26:31 +02:00
Frank Denis 776e0d7ccc New feature: query_meta 2019-09-07 16:19:47 +02:00
Frank Denis 6b1966b38f Strip the port when caching the host part of URLs
Fixes #888
2019-09-07 15:31:34 +02:00
Frank Denis deaad9ce2b Add Solaris packages
Fixes #923
2019-09-07 15:02:09 +02:00
Frank Denis ad8b4ec8fe Update ChangeLog 2019-09-07 14:58:56 +02:00
Frank Denis 6e8b7e64ba Use x/sys instead of syscalls, merge privilege_linux and _others 2019-09-07 12:10:31 +02:00
Frank Denis 208c67b53b Print the version before the netprobe
Fixes #901
2019-09-07 11:30:46 +02:00
Frank Denis 9a9f780620 Add a comment to describe why that plugin is necessary 2019-09-07 11:19:28 +02:00
Frank Denis cef00d5d0b Update deps 2019-09-07 11:04:40 +02:00
Frank Denis 207d3172a7 Add a new "firefox" plugin to work around Firefox evil plan 2019-09-07 11:00:18 +02:00
Frank Denis 77f2eef886 Change the user agent 2019-08-27 18:26:29 +02:00
Frank Denis 5f29677400 Format 2019-08-27 18:25:47 +02:00
Frank Denis b543ccabdb dpeth -> depth 2019-08-09 14:33:03 +02:00
Frank Denis 7abd257959 Indent 2019-08-09 14:31:56 +02:00
Peter Dave Hello bf32a9b8c5 [CI] Leverage `after_success` phase in .travis.yml
There were two `ls -l dnscrypt-proxy-*.tar.gz dnscrypt-proxy-*.zip`
commands in `.travis.yml`, one in the `script`(build) phase, one in the
`after_deploy` phase, they were actually duplicated.

As deployment job won't create any new files, and the command isn't part
of the steps to build artifacts, but to confirm/list the built files,
this action looks more suitable to be placed in the `after_success`, to
be separated with the build commands, and the duplicated one in the
`after_deploy` phase could be removed.
2019-08-07 18:01:11 +02:00
Peter Dave Hello 39821afd11 [CI] Adjust blank lines in .travis.yml to improve readability 2019-08-07 18:01:11 +02:00
Peter Dave Hello 6ee4a3738c [CI] Remove deprecated `sudo` option in .travis.yml
Ref:
- https://blog.travis-ci.com/2018-10-04-combining-linux-infrastructures
2019-08-07 18:01:11 +02:00
Peter Dave Hello 760c0c10de [CI] Use git shallow clone to speed up 2019-08-07 18:01:11 +02:00
Frank Denis faa931585b Use single quotation marks everywhere in the example for consistency
Fixes #904
2019-08-04 09:04:01 +02:00
Cédrik d9b450616a Fix DuckDuckGo subdomains
As seen in #891. Thanks to @tunip for the patch!
2019-07-25 23:19:09 +02:00
Cédrik 9cc3d9e4da Cloaking example: DuckDuckGo safe search
As documented at https://help.duckduckgo.com/features/safe-search/
2019-07-22 19:14:25 +02:00
Frank Denis 383e7c87da Merge branch 'master' of github.com:jedisct1/dnscrypt-proxy
* 'master' of github.com:jedisct1/dnscrypt-proxy:
  blocked_query_response takes the format 'a:<IPv4>,aaaa:<IPv6>' for IP responses
  fold 'refused_code_in_responses' and 'respond_with_ip' options into a new option 'blocked_query_response'
  add new option: 'respond_with_ip'
  Added financial contributors to the README
2019-07-22 15:15:28 +02:00
Frank Denis 9a6cc0e137 Add tracker.debian.org to example-whitelist.txt
Fixes #890
2019-07-22 15:15:02 +02:00
James Newell d3ab899f7b blocked_query_response takes the format 'a:<IPv4>,aaaa:<IPv6>' for IP responses 2019-07-17 12:12:28 +02:00
James Newell 5812cb2fe4 fold 'refused_code_in_responses' and 'respond_with_ip' options into a new option 'blocked_query_response' 2019-07-17 12:12:28 +02:00
James Newell 87bbfbfc10 add new option: 'respond_with_ip' 2019-07-17 12:12:28 +02:00
Jess e43b85d9f9 Added financial contributors to the README 2019-07-15 16:54:48 +02:00
Frank Denis 0569c75596 Propagate mainProto to xTransport
Fixes #880
2019-07-10 13:13:28 +02:00
Frank Denis ad05fd6f21 Directly dlog.Fatalf() if an invalid static stamp is given 2019-07-06 18:04:02 +02:00
Frank Denis 9b33aba757 Update deps 2019-07-06 18:03:41 +02:00
Frank Denis 7ca40df7c1 Save a line 2019-06-26 19:51:57 +02:00
Frank Denis dd9cf5cc9a Kill nacl/box 2019-06-24 19:13:34 +02:00
Frank Denis d80e72365f Update deps 2019-06-24 14:55:34 +02:00
Frank Denis 5d130cdf0b Use CIRCL for X25519. That makes ephemeral key computation faster. 2019-06-24 14:17:00 +02:00
Frank Denis d27171f62b Have fetchFromCache support a TTL parameter
Partially
fixes #854
2019-06-13 11:24:15 +02:00
Frank Denis df24db9b9d Remove refresh_delay from the example configuration file
It is not implemented
2019-06-13 11:14:10 +02:00
Frank Denis 8933980121 netprobe_timeout=0 doesn't make much sense 2019-06-07 01:50:03 +02:00
Frank Denis 8def2d5edc Document TLS 1.3 cipher suite IDs 2019-06-07 01:39:35 +02:00
Frank Denis d2aa521369 Add a command-line option to print the server certificate hashes 2019-06-07 01:23:48 +02:00
Frank Denis 9604b8b3e5 Use an example server instead of a real one in the static section 2019-06-04 12:17:47 +02:00
Frank Denis 14d6345d6b Deps update 2019-06-04 09:51:48 +02:00
Frank Denis 0f264fe38e 2.0.25 2019-06-04 01:42:02 +02:00
Frank Denis a060407db1 Use a different address than 255.255.255.0 for netprobes
Windows doesn't seem to like this address.

Also default to the fallback resolver IP if there is one and
no netprobe_address option in the configuration file.

Fix netprobe_timeout = -1 by the way
2019-06-04 01:37:59 +02:00
1800 changed files with 323110 additions and 160906 deletions

1
.ci/allowed-names.txt Normal file
View File

@ -0,0 +1 @@
tracker.debian.org

1
.ci/blocked-ips.txt Normal file
View File

@ -0,0 +1 @@
8.8.8.8

21
.ci/blocked-names.txt Normal file
View File

@ -0,0 +1,21 @@
##################
# Test blocklist #
##################
ad.*
ads.*
banner.*
banners.*
creatives.*
oas.*
oascentral.* # test inline comment
stats.* # test inline comment with trailing spaces
tag.*
telemetry.*
tracker.*
*.local
eth0.me
*.workgroup
*.youtube.* @time-to-sleep
facebook.com @work

204
.ci/ci-build.sh Executable file
View File

@ -0,0 +1,204 @@
#! /bin/sh
PACKAGE_VERSION="$1"
cd dnscrypt-proxy || exit 1
go clean
env GOOS=windows GOARCH=386 go build -mod vendor -ldflags="-s -w"
mkdir win32
ln dnscrypt-proxy.exe win32/
cp ../LICENSE example-dnscrypt-proxy.toml localhost.pem example-*.txt win32/
for i in win32/LICENSE win32/*.toml win32/*.txt; do ex -bsc '%!awk "{sub(/$/,\"\r\")}1"' -cx "$i"; done
ln ../windows/* win32/
zip -9 -r dnscrypt-proxy-win32-${PACKAGE_VERSION:-dev}.zip win32
go clean
env GOOS=windows GOARCH=amd64 go build -mod vendor -ldflags="-s -w"
mkdir win64
ln dnscrypt-proxy.exe win64/
cp ../LICENSE example-dnscrypt-proxy.toml localhost.pem example-*.txt win64/
for i in win64/LICENSE win64/*.toml win64/*.txt; do ex -bsc '%!awk "{sub(/$/,\"\r\")}1"' -cx "$i"; done
ln ../windows/* win64/
zip -9 -r dnscrypt-proxy-win64-${PACKAGE_VERSION:-dev}.zip win64
go clean
env GO386=softfloat GOOS=openbsd GOARCH=386 go build -mod vendor -ldflags="-s -w"
mkdir openbsd-i386
ln dnscrypt-proxy openbsd-i386/
ln ../LICENSE example-dnscrypt-proxy.toml localhost.pem example-*.txt openbsd-i386/
tar czpvf dnscrypt-proxy-openbsd_i386-${PACKAGE_VERSION:-dev}.tar.gz openbsd-i386
go clean
env GOOS=openbsd GOARCH=amd64 go build -mod vendor -ldflags="-s -w"
mkdir openbsd-amd64
ln dnscrypt-proxy openbsd-amd64/
ln ../LICENSE example-dnscrypt-proxy.toml localhost.pem example-*.txt openbsd-amd64/
tar czpvf dnscrypt-proxy-openbsd_amd64-${PACKAGE_VERSION:-dev}.tar.gz openbsd-amd64
go clean
env GOOS=freebsd GOARCH=386 go build -mod vendor -ldflags="-s -w"
mkdir freebsd-i386
ln dnscrypt-proxy freebsd-i386/
ln ../LICENSE example-dnscrypt-proxy.toml localhost.pem example-*.txt freebsd-i386/
tar czpvf dnscrypt-proxy-freebsd_i386-${PACKAGE_VERSION:-dev}.tar.gz freebsd-i386
go clean
env GOOS=freebsd GOARCH=amd64 go build -mod vendor -ldflags="-s -w"
mkdir freebsd-amd64
ln dnscrypt-proxy freebsd-amd64/
ln ../LICENSE example-dnscrypt-proxy.toml localhost.pem example-*.txt freebsd-amd64/
tar czpvf dnscrypt-proxy-freebsd_amd64-${PACKAGE_VERSION:-dev}.tar.gz freebsd-amd64
go clean
env GOOS=freebsd GOARCH=arm GOARM=5 go build -mod vendor -ldflags="-s -w"
mkdir freebsd-arm
ln dnscrypt-proxy freebsd-arm/
ln ../LICENSE example-dnscrypt-proxy.toml localhost.pem example-*.txt freebsd-arm/
tar czpvf dnscrypt-proxy-freebsd_arm-${PACKAGE_VERSION:-dev}.tar.gz freebsd-arm
go clean
env GOOS=dragonfly GOARCH=amd64 go build -mod vendor -ldflags="-s -w"
mkdir dragonflybsd-amd64
ln dnscrypt-proxy dragonflybsd-amd64/
ln ../LICENSE example-dnscrypt-proxy.toml localhost.pem example-*.txt dragonflybsd-amd64/
tar czpvf dnscrypt-proxy-dragonflybsd_amd64-${PACKAGE_VERSION:-dev}.tar.gz dragonflybsd-amd64
go clean
env GOOS=netbsd GOARCH=386 go build -mod vendor -ldflags="-s -w"
mkdir netbsd-i386
ln dnscrypt-proxy netbsd-i386/
ln ../LICENSE example-dnscrypt-proxy.toml localhost.pem example-*.txt netbsd-i386/
tar czpvf dnscrypt-proxy-netbsd_i386-${PACKAGE_VERSION:-dev}.tar.gz netbsd-i386
go clean
env GOOS=netbsd GOARCH=amd64 go build -mod vendor -ldflags="-s -w"
mkdir netbsd-amd64
ln dnscrypt-proxy netbsd-amd64/
ln ../LICENSE example-dnscrypt-proxy.toml localhost.pem example-*.txt netbsd-amd64/
tar czpvf dnscrypt-proxy-netbsd_amd64-${PACKAGE_VERSION:-dev}.tar.gz netbsd-amd64
go clean
env GOOS=solaris GOARCH=amd64 go build -mod vendor -ldflags="-s -w"
mkdir solaris-amd64
ln dnscrypt-proxy solaris-amd64/
ln ../LICENSE example-dnscrypt-proxy.toml localhost.pem example-*.txt solaris-amd64/
tar czpvf dnscrypt-proxy-solaris_amd64-${PACKAGE_VERSION:-dev}.tar.gz solaris-amd64
go clean
env CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -mod vendor -ldflags="-s -w"
mkdir linux-i386
ln dnscrypt-proxy linux-i386/
ln ../LICENSE example-dnscrypt-proxy.toml localhost.pem example-*.txt linux-i386/
tar czpvf dnscrypt-proxy-linux_i386-${PACKAGE_VERSION:-dev}.tar.gz linux-i386
go clean
env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -mod vendor -ldflags="-s -w"
mkdir linux-x86_64
ln dnscrypt-proxy linux-x86_64/
ln ../LICENSE example-dnscrypt-proxy.toml localhost.pem example-*.txt linux-x86_64/
tar czpvf dnscrypt-proxy-linux_x86_64-${PACKAGE_VERSION:-dev}.tar.gz linux-x86_64
go clean
env CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=5 go build -mod vendor -ldflags="-s -w"
mkdir linux-arm
ln dnscrypt-proxy linux-arm/
ln ../LICENSE example-dnscrypt-proxy.toml localhost.pem example-*.txt linux-arm/
tar czpvf dnscrypt-proxy-linux_arm-${PACKAGE_VERSION:-dev}.tar.gz linux-arm
go clean
env CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -mod vendor -ldflags="-s -w"
mkdir linux-arm64
ln dnscrypt-proxy linux-arm64/
ln ../LICENSE example-dnscrypt-proxy.toml localhost.pem example-*.txt linux-arm64/
tar czpvf dnscrypt-proxy-linux_arm64-${PACKAGE_VERSION:-dev}.tar.gz linux-arm64
go clean
env CGO_ENABLED=0 GOOS=linux GOARCH=mips GOMIPS=softfloat go build -mod vendor -ldflags="-s -w"
mkdir linux-mips
ln dnscrypt-proxy linux-mips/
ln ../LICENSE example-dnscrypt-proxy.toml localhost.pem example-*.txt linux-mips/
tar czpvf dnscrypt-proxy-linux_mips-${PACKAGE_VERSION:-dev}.tar.gz linux-mips
go clean
env CGO_ENABLED=0 GOOS=linux GOARCH=mipsle GOMIPS=softfloat go build -mod vendor -ldflags="-s -w"
mkdir linux-mipsle
ln dnscrypt-proxy linux-mipsle/
ln ../LICENSE example-dnscrypt-proxy.toml localhost.pem example-*.txt linux-mipsle/
tar czpvf dnscrypt-proxy-linux_mipsle-${PACKAGE_VERSION:-dev}.tar.gz linux-mipsle
go clean
env CGO_ENABLED=0 GOOS=linux GOARCH=mips64 GOMIPS64=softfloat go build -mod vendor -ldflags="-s -w"
mkdir linux-mips64
ln dnscrypt-proxy linux-mips64/
ln ../LICENSE example-dnscrypt-proxy.toml localhost.pem example-*.txt linux-mips64/
tar czpvf dnscrypt-proxy-linux_mips64-${PACKAGE_VERSION:-dev}.tar.gz linux-mips64
go clean
env CGO_ENABLED=0 GOOS=linux GOARCH=mips64le GOMIPS64=softfloat go build -mod vendor -ldflags="-s -w"
mkdir linux-mips64le
ln dnscrypt-proxy linux-mips64le/
ln ../LICENSE example-dnscrypt-proxy.toml localhost.pem example-*.txt linux-mips64le/
tar czpvf dnscrypt-proxy-linux_mips64le-${PACKAGE_VERSION:-dev}.tar.gz linux-mips64le
go clean
env CGO_ENABLED=0 GOOS=linux GOARCH=riscv64 go build -mod vendor -ldflags="-s -w"
mkdir linux-riscv64
ln dnscrypt-proxy linux-riscv64/
ln ../LICENSE example-dnscrypt-proxy.toml localhost.pem example-*.txt linux-riscv64/
tar czpvf dnscrypt-proxy-linux_riscv64-${PACKAGE_VERSION:-dev}.tar.gz linux-riscv64
go clean
env GOOS=darwin GOARCH=amd64 go build -mod vendor -ldflags="-s -w"
mkdir macos-x86_64
ln dnscrypt-proxy macos-x86_64/
ln ../LICENSE example-dnscrypt-proxy.toml localhost.pem example-*.txt macos-x86_64/
tar czpvf dnscrypt-proxy-macos_x86_64-${PACKAGE_VERSION:-dev}.tar.gz macos-x86_64
go clean
env GOOS=darwin GOARCH=arm64 go build -mod vendor -ldflags="-s -w"
mkdir macos-arm64
ln dnscrypt-proxy macos-arm64/
ln ../LICENSE example-dnscrypt-proxy.toml localhost.pem example-*.txt macos-arm64/
tar czpvf dnscrypt-proxy-macos_arm64-${PACKAGE_VERSION:-dev}.tar.gz macos-arm64
# Android
NDK_VER=r20
curl -LOs https://dl.google.com/android/repository/android-ndk-${NDK_VER}-linux-x86_64.zip
unzip -q android-ndk-${NDK_VER}-linux-x86_64.zip -d ${HOME}
rm android-ndk-${NDK_VER}-linux-x86_64.zip
NDK_TOOLS=${HOME}/android-ndk-${NDK_VER}
export PATH=${PATH}:${NDK_TOOLS}/toolchains/llvm/prebuilt/linux-x86_64/bin
go clean
env CC=armv7a-linux-androideabi19-clang CXX=armv7a-linux-androideabi19-clang++ CGO_ENABLED=1 GOOS=android GOARCH=arm GOARM=7 go build -mod vendor -ldflags="-s -w"
mkdir android-arm
ln dnscrypt-proxy android-arm/
cp ../LICENSE example-dnscrypt-proxy.toml localhost.pem example-*.txt android-arm/
zip -9 -r dnscrypt-proxy-android_arm-${PACKAGE_VERSION:-dev}.zip android-arm
go clean
env CC=aarch64-linux-android21-clang CXX=aarch64-linux-android21-clang++ CGO_ENABLED=1 GOOS=android GOARCH=arm64 go build -mod vendor -ldflags="-s -w"
mkdir android-arm64
ln dnscrypt-proxy android-arm64/
cp ../LICENSE example-dnscrypt-proxy.toml localhost.pem example-*.txt android-arm64/
zip -9 -r dnscrypt-proxy-android_arm64-${PACKAGE_VERSION:-dev}.zip android-arm64
go clean
env CC=i686-linux-android19-clang CXX=i686-linux-android19-clang++ CGO_ENABLED=1 GOOS=android GOARCH=386 go build -mod vendor -ldflags="-s -w"
mkdir android-i386
ln dnscrypt-proxy android-i386/
cp ../LICENSE example-dnscrypt-proxy.toml localhost.pem example-*.txt android-i386/
zip -9 -r dnscrypt-proxy-android_i386-${PACKAGE_VERSION:-dev}.zip android-i386
go clean
env CC=x86_64-linux-android21-clang CXX=x86_64-linux-android21-clang++ CGO_ENABLED=1 GOOS=android GOARCH=amd64 go build -mod vendor -ldflags="-s -w"
mkdir android-x86_64
ln dnscrypt-proxy android-x86_64/
cp ../LICENSE example-dnscrypt-proxy.toml localhost.pem example-*.txt android-x86_64/
zip -9 -r dnscrypt-proxy-android_x86_64-${PACKAGE_VERSION:-dev}.zip android-x86_64
# Done
ls -l dnscrypt-proxy-*.tar.gz dnscrypt-proxy-*.zip

58
.ci/ci-package.sh Executable file
View File

@ -0,0 +1,58 @@
#! /bin/sh
PACKAGE_VERSION="$1"
cd dnscrypt-proxy || exit 1
# setup the environment
sudo apt-get update -y
sudo apt-get install -y wget wine dotnet-sdk-6.0
sudo dpkg --add-architecture i386 && sudo apt-get update && sudo apt-get install -y wine32
sudo apt-get install -y unzip
export WINEPREFIX="$HOME"/.wine32
export WINEARCH=win32
export WINEDEBUG=-all
wget https://dl.winehq.org/wine/wine-mono/8.1.0/wine-mono-8.1.0-x86.msi
WINEPREFIX="$HOME/.wine32" WINEARCH=win32 wineboot --init
WINEPREFIX="$HOME/.wine32" WINEARCH=win32 wine msiexec /i wine-mono-8.1.0-x86.msi
mkdir "$HOME"/.wine32/drive_c/temp
mkdir -p "$HOME"/.wine/drive_c/temp
wget https://github.com/wixtoolset/wix3/releases/download/wix3112rtm/wix311-binaries.zip -nv -O wix.zip
unzip wix.zip -d "$HOME"/wix
rm -f wix.zip
builddir=$(pwd)
srcdir=$(
cd ..
pwd
)
version=$PACKAGE_VERSION
cd "$HOME"/wix || exit
ln -s "$builddir" "$HOME"/wix/build
ln -s "$srcdir"/contrib/msi "$HOME"/wix/wixproj
echo "builddir: $builddir"
# build the msi's
#################
for arch in x64 x86; do
binpath="win32"
if [ "$arch" = "x64" ]; then
binpath="win64"
fi
echo $arch
wine candle.exe -dVersion="$version" -dPlatform=$arch -dPath=build\\$binpath -arch $arch wixproj\\dnscrypt.wxs -out build\\dnscrypt-$arch.wixobj
wine light.exe -out build\\dnscrypt-proxy-$arch-"$version".msi build\\dnscrypt-$arch.wixobj -sval
done
cd "$builddir" || exit

164
.ci/ci-test.sh Executable file
View File

@ -0,0 +1,164 @@
#! /bin/sh
DNS_PORT=5300
HTTP_PORT=3053
TEST_COUNT=0
exec 2>error.log
t() {
TEST_COUNT=$((TEST_COUNT + 1))
echo "Test #${TEST_COUNT}..."
false
}
fail() (
echo "*** Test #${TEST_COUNT} FAILED ***" >&2
)
section() {
true
}
rm -f blocked-names.log blocked-ips.log query.log nx.log allowed-names.log
t || (
cd ../dnscrypt-proxy
go test -mod vendor
go build -mod vendor -race
) || fail
section
sed -e "s/127.0.0.1:53/127.0.0.1:${DNS_PORT}/g" -e "s/# server_names =.*/server_names = ['scaleway-fr']/" ../dnscrypt-proxy/example-dnscrypt-proxy.toml >test-dnscrypt-proxy.toml
../dnscrypt-proxy/dnscrypt-proxy -loglevel 3 -config test-dnscrypt-proxy.toml -pidfile /tmp/dnscrypt-proxy.pidfile &
sleep 5
t ||
dig -p${DNS_PORT} . @127.0.0.1 | grep -Fq 'root-servers.net.' || fail
t || dig -p${DNS_PORT} +dnssec . @127.0.0.1 | grep -Fq 'root-servers.net.' || fail
t || dig -p${DNS_PORT} +dnssec . @127.0.0.1 | grep -Fq 'flags: do;' || fail
t || dig -p${DNS_PORT} +short one.one.one.one @127.0.0.1 | grep -Fq '1.1.1.1' || fail
t || dig -p${DNS_PORT} +dnssec dnscrypt.info @127.0.0.1 | grep -Fq 'flags: qr rd ra ad' || fail
t || dig -p${DNS_PORT} +dnssec dnscrypt.info @127.0.0.1 | grep -Fq 'flags: do;' || fail
kill $(cat /tmp/dnscrypt-proxy.pidfile)
sleep 5
section
../dnscrypt-proxy/dnscrypt-proxy -loglevel 3 -config test2-dnscrypt-proxy.toml -pidfile /tmp/dnscrypt-proxy.pidfile &
sleep 5
section
t || dig -p${DNS_PORT} A microsoft.com @127.0.0.1 | grep -Fq "NOERROR" || fail
t || dig -p${DNS_PORT} A MICROSOFT.COM @127.0.0.1 | grep -Fq "NOERROR" || fail
section
t || dig -p${DNS_PORT} AAAA ipv6.google.com @127.0.0.1 | grep -Fq 'locally blocked' || fail
section
t || dig -p${DNS_PORT} invalid. @127.0.0.1 | grep -Fq NXDOMAIN || fail
t || dig -p${DNS_PORT} +dnssec invalid. @127.0.0.1 | grep -Fq 'flags: do;' || fail
t || dig -p${DNS_PORT} PTR 168.192.in-addr.arpa @127.0.0.1 | grep -Fq 'NXDOMAIN' || fail
t || dig -p${DNS_PORT} +dnssec PTR 168.192.in-addr.arpa @127.0.0.1 | grep -Fq 'flags: do;' || fail
section
t || dig -p${DNS_PORT} +dnssec darpa.mil @127.0.0.1 2>&1 | grep -Fvq 'RRSIG' || fail
t || dig -p${DNS_PORT} +dnssec www.darpa.mil @127.0.0.1 2>&1 | grep -Fvq 'RRSIG' || fail
section
t || dig -p${DNS_PORT} +short cloakedunregistered.com @127.0.0.1 | grep -Eq '1.1.1.1|1.0.0.1' || fail
t || dig -p${DNS_PORT} +short MX cloakedunregistered.com @127.0.0.1 | grep -Fq 'locally blocked' || fail
t || dig -p${DNS_PORT} +short MX example.com @127.0.0.1 | grep -Fvq 'locally blocked' || fail
t || dig -p${DNS_PORT} NS cloakedunregistered.com @127.0.0.1 | grep -Fiq 'gtld-servers.net' || fail
t || dig -p${DNS_PORT} +short www.cloakedunregistered2.com @127.0.0.1 | grep -Eq '1.1.1.1|1.0.0.1' || fail
t || dig -p${DNS_PORT} +short www.dnscrypt-test @127.0.0.1 | grep -Fq '192.168.100.100' || fail
t || dig -p${DNS_PORT} a.www.dnscrypt-test @127.0.0.1 | grep -Fq 'NXDOMAIN' || fail
t || dig -p${DNS_PORT} +short ptr 101.100.168.192.in-addr.arpa. @127.0.0.1 | grep -Eq 'www.dnscrypt-test.com' || fail
t || dig -p${DNS_PORT} +short ptr 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.d.f.ip6.arpa. @127.0.0.1 | grep -Eq 'ipv6.dnscrypt-test.com' || fail
section
t || dig -p${DNS_PORT} telemetry.example @127.0.0.1 | grep -Fq 'locally blocked' || fail
section
t || dig -p${DNS_PORT} dns.google @127.0.0.1 | grep -Fq 'locally blocked' || fail
section
t || dig -p${DNS_PORT} tracker.xdebian.org @127.0.0.1 | grep -Fq 'locally blocked' || fail
t || dig -p${DNS_PORT} tracker.debian.org @127.0.0.1 | grep -Fqv 'locally blocked' || fail
section
t || curl --insecure -siL https://127.0.0.1:${HTTP_PORT}/ | grep -Fq 'HTTP/2 404' || fail
t || curl --insecure -sL https://127.0.0.1:${HTTP_PORT}/dns-query | grep -Fq 'dnscrypt-proxy local DoH server' || fail
t ||
echo yv4BAAABAAAAAAABAAACAAEAACkQAAAAgAAAAA== | base64 -d |
curl -H'Content-Type: application/dns-message' -H'Accept: application/dns-message' --data-binary @- -D - --insecure https://127.0.0.1:${HTTP_PORT}/dns-query 2>/dev/null |
grep -Fq application/dns-message || fail
kill $(cat /tmp/dnscrypt-proxy.pidfile)
sleep 5
section
t || grep -Fq 'telemetry.example' blocked-names.log || fail
t || grep -Fq 'telemetry.*' blocked-names.log || fail
t || grep -Fq 'tracker.xdebian.org' blocked-names.log || fail
t || grep -Fq 'tracker.*' blocked-names.log || fail
section
t || grep -Fq 'dns.google' blocked-ips.log || fail
t || grep -Fq '8.8.8.8' blocked-ips.log || fail
section
t || grep -Fq 'a.www.dnscrypt-test' nx.log || fail
section
t || grep -Fq 'a.www.dnscrypt-test' nx.log || fail
section
t || grep -Eq 'microsoft.com.*PASS.*[^-]$' query.log || fail
t || grep -Eq 'microsoft.com.*PASS.*-$' query.log || fail
t || grep -Eq 'ipv6.google.com.*SYNTH' query.log || fail
t || grep -Eq 'invalid.*SYNTH' query.log || fail
t || grep -Eq '168.192.in-addr.arpa.*SYNTH' query.log || fail
t || grep -Eq 'darpa.mil.*FORWARD' query.log || fail
t || grep -Eq 'www.darpa.mil.*FORWARD' query.log || fail
t || grep -Eq 'cloakedunregistered.com.*CLOAK' query.log || fail
t || grep -Eq 'www.cloakedunregistered2.com.*CLOAK' query.log || fail
t || grep -Eq 'www.dnscrypt-test.*CLOAK' query.log || fail
t || grep -Eq 'a.www.dnscrypt-test.*NXDOMAIN' query.log || fail
t || grep -Eq 'telemetry.example.*REJECT' query.log || fail
t || grep -Eq 'dns.google.*REJECT' query.log || fail
t || grep -Eq 'tracker.xdebian.org.*REJECT' query.log || fail
t || grep -Eq 'tracker.debian.org.*PASS' query.log || fail
t || grep -Eq '[.].*NS.*PASS' query.log || fail
section
t || grep -Fq 'tracker.debian.org' allowed-names.log || fail
t || grep -Fq '*.tracker.debian' allowed-names.log || fail
section
../dnscrypt-proxy/dnscrypt-proxy -loglevel 3 -config test3-dnscrypt-proxy.toml -pidfile /tmp/dnscrypt-proxy.pidfile &
sleep 5
section
t || dig -p${DNS_PORT} A microsoft.com @127.0.0.1 | grep -Fq "NOERROR" || fail
t || dig -p${DNS_PORT} A MICROSOFT.COM @127.0.0.1 | grep -Fq "NOERROR" || fail
kill $(cat /tmp/dnscrypt-proxy.pidfile)
sleep 5
section
../dnscrypt-proxy/dnscrypt-proxy -loglevel 3 -config test-odoh-proxied.toml -pidfile /tmp/odoh-proxied.pidfile &
sleep 5
section
t || dig -p${DNS_PORT} A microsoft.com @127.0.0.1 | grep -Fq "NOERROR" || fail
t || dig -p${DNS_PORT} A cloudflare.com @127.0.0.1 | grep -Fq "NOERROR" || fail
kill $(cat /tmp/odoh-proxied.pidfile)
sleep 5
if [ -s error.log ]; then
cat *.log
exit 1
fi

5
.ci/cloaking-rules.txt Normal file
View File

@ -0,0 +1,5 @@
cloakedunregistered.* one.one.one.one
*.cloakedunregistered2.* one.one.one.one # inline comment
=www.dnscrypt-test 192.168.100.100
=www.dnscrypt-test.com 192.168.100.101
=ipv6.dnscrypt-test.com fd02::1

2
.ci/forwarding-rules.txt Normal file
View File

@ -0,0 +1,2 @@
darpa.mil 208.67.222.222

View File

@ -0,0 +1,17 @@
server_names = ['odohtarget']
listen_addresses = ['127.0.0.1:5300']
[query_log]
file = 'query.log'
[static]
[static.'odohtarget']
stamp = 'sdns://BQcAAAAAAAAADm9kb2guY3J5cHRvLnN4Ci9kbnMtcXVlcnk'
[static.'odohrelay']
stamp = 'sdns://hQcAAAAAAAAADDg5LjM4LjEzMS4zOAAYb2RvaC1ubC5hbGVrYmVyZy5uZXQ6NDQzBi9wcm94eQ'
[anonymized_dns]
routes = [
{ server_name='odohtarget', via=['odohrelay'] }
]

View File

@ -0,0 +1,69 @@
server_names = ['public-scaleway-fr']
listen_addresses = ['127.0.0.1:5300']
require_dnssec = true
dnscrypt_ephemeral_keys = true
tls_disable_session_tickets = false
ignore_system_dns = false
lb_strategy = 'p12'
block_ipv6 = true
block_unqualified = true
block_undelegated = true
forwarding_rules = 'forwarding-rules.txt'
cloaking_rules = 'cloaking-rules.txt'
cloak_ptr = true
cache = true
[local_doh]
listen_addresses = ['127.0.0.1:3053']
cert_file = "../dnscrypt-proxy/localhost.pem"
cert_key_file = "../dnscrypt-proxy/localhost.pem"
[query_log]
file = 'query.log'
[nx_log]
file = 'nx.log'
[blocked_names]
blocked_names_file = 'blocked-names.txt'
log_file = 'blocked-names.log'
[blocked_ips]
blocked_ips_file = 'blocked-ips.txt'
log_file = 'blocked-ips.log'
[allowed_names]
allowed_names_file = 'allowed-names.txt'
log_file = 'allowed-names.log'
[schedules]
[schedules.'time-to-sleep']
mon = [{after='21:00', before='7:00'}]
tue = [{after='21:00', before='7:00'}]
wed = [{after='21:00', before='7:00'}]
thu = [{after='21:00', before='7:00'}]
fri = [{after='23:00', before='7:00'}]
sat = [{after='23:00', before='7:00'}]
sun = [{after='21:00', before='7:00'}]
[schedules.'work']
mon = [{after='9:00', before='18:00'}]
tue = [{after='9:00', before='18:00'}]
wed = [{after='9:00', before='18:00'}]
thu = [{after='9:00', before='18:00'}]
fri = [{after='9:00', before='17:00'}]
[sources]
[sources.'public-resolvers']
urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v2/public-resolvers.md', 'https://download.dnscrypt.info/resolvers-list/v2/public-resolvers.md']
cache_file = 'public-resolvers.md'
minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
prefix = 'public-'
[sources.'relays']
urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v2/relays.md', 'https://download.dnscrypt.info/resolvers-list/v2/relays.md']
cache_file = 'relays.md'
minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
refresh_delay = 72
prefix = 'relay-'

View File

@ -0,0 +1,19 @@
server_names = ['myserver']
listen_addresses = ['127.0.0.1:5300']
require_dnssec = true
dnscrypt_ephemeral_keys = true
tls_disable_session_tickets = false
ignore_system_dns = false
lb_strategy = 'p12'
block_ipv6 = true
block_unqualified = true
block_undelegated = true
cache = true
[query_log]
file = 'query.log'
[static]
[static.'myserver']
stamp = 'sdns://AQcAAAAAAAAADjIxMi40Ny4yMjguMTM2IOgBuE6mBr-wusDOQ0RbsV66ZLAvo8SqMa4QY2oHkDJNHzIuZG5zY3J5cHQtY2VydC5mci5kbnNjcnlwdC5vcmc'

7
.gitattributes vendored Normal file
View File

@ -0,0 +1,7 @@
* text=auto
*.go text diff=golang
*.bat text eol=crlf
go.mod text eol=lf
# Ensure test fixtures don't get mangled
**/testdata/** -text

65
.github/ISSUE_TEMPLATE/bugs.md vendored Normal file
View File

@ -0,0 +1,65 @@
---
name: "\U0001F41E Issues"
about: Bug reports
title: ''
labels: ''
assignees: ''
---
THE TRACKER IS DEDICATED TO KEEPING TRACK OF *BUGS*,
preferably after they have been already discussed and confirmed to be reproducible.
FOR ASSISTANCE, PLEASE CLOSE THIS FORM AND USE THE DISCUSSIONS SECTION INSTEAD:
https://github.com/DNSCrypt/dnscrypt-proxy/discussions/categories/q-a
~~~
Reported bugs must reproducible in the context described in the "Context" section.
Installation and configuration issues are not bugs, but individual assistance request.
Context: the LATEST version of `dnscrypt-proxy` (precompiled binaries downloaded from this repository) is correctly installed and configured on your system, but something doesn't seem to produce the expected result.
If the bug is not trivial to reproduce on any platform, please include ALL the steps required to reliably duplicate it, on a vanilla, generic install of macOS, Windows, OpenBSD or Ubuntu Linux system, in their most current version.
If you don't have any clear understanding of the issue or can't enumerate the steps to reproduce it, open a discussion instead:
https://github.com/DNSCrypt/dnscrypt-proxy/discussions
## Output of the following commands:
./dnscrypt-proxy -version
./dnscrypt-proxy -check
./dnscrypt-proxy -resolve example.com
- [ ] Initially raised as discussion #...
## *What* is affected by this bug?
## *When* does this occur?
## *Where* does it happen?
## *How* do we replicate the issue?
<!-- Please list all the steps required to reliably replicate it, starting from a newly installed operating system -->
## Expected behavior (i.e. solution)
## Other Comments

22
.github/ISSUE_TEMPLATE/suggestions.md vendored Normal file
View File

@ -0,0 +1,22 @@
---
name: "🙋🏽 Planned changes"
about: List of planned changes
title: ''
labels: ''
assignees: ''
---
The starting point should be a discussion.
https://github.com/DNSCrypt/dnscrypt-proxy/discussions/
Suggestions may be raised as an "Ideas" discussion.
We can then determine if the discussion needs to be escalated into a "planned change" or not.
This will help us ensure that the issue tracker properly reflects ongoing or needed work on the project.
---
- [ ] Initially raised as discussion #...

15
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,15 @@
version: 2
updates:
# Maintain dependencies for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
# Maintain dependencies for Go
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "daily"
open-pull-requests-limit: 10

12
.github/workflows/autocloser.yml vendored Normal file
View File

@ -0,0 +1,12 @@
name: Autocloser
on: [issues]
jobs:
autoclose:
runs-on: ubuntu-latest
steps:
- name: Autoclose issues that did not follow issue template
uses: roots/issue-closer@v1.2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
issue-close-message: "This issue was automatically closed because it did not follow the issue template. We use the issue tracker exclusively for bug reports and feature additions that have been previously discussed. However, this issue appears to be a support request. Please use the discussion forums for support requests."
issue-pattern: ".*(do we replicate the issue|Expected behavior|raised as discussion|# Impact).*"

32
.github/workflows/codeql-analysis.yml vendored Normal file
View File

@ -0,0 +1,32 @@
name: "CodeQL scan"
on:
push:
pull_request:
schedule:
- cron: '0 14 * * 6'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
- name: Autobuild
uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3

95
.github/workflows/releases.yml vendored Normal file
View File

@ -0,0 +1,95 @@
on:
push:
paths:
- "**.go"
- "go.*"
- "**/testdata/**"
- ".ci/**"
- ".git*"
- ".github/workflows/releases.yml"
pull_request:
paths:
- "**.go"
- "go.*"
- "**/testdata/**"
- ".ci/**"
- ".git*"
- ".github/workflows/releases.yml"
name: GitHub CI
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Get the version
id: get_version
run: echo "VERSION=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_OUTPUT
- name: Check out code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: 1
check-latest: true
id: go
- name: Test suite
run: |
go version
cd .ci
./ci-test.sh
cd -
- name: Build all
if: startsWith(github.ref, 'refs/tags/')
run: |
.ci/ci-build.sh "${{ steps.get_version.outputs.VERSION }}"
- name: Package
if: startsWith(github.ref, 'refs/tags/')
run: |
.ci/ci-package.sh "${{ steps.get_version.outputs.VERSION }}"
- name: Install minisign and sign
if: startsWith(github.ref, 'refs/tags/')
run: |
sudo apt-get -y install libsodium-dev
git clone --depth 1 https://github.com/jedisct1/minisign.git
cd minisign/src
mkdir -p /tmp/bin
cc -O2 -o /tmp/bin/minisign -D_GNU_SOURCE *.c -lsodium
cd -
/tmp/bin/minisign -v
echo '#' > /tmp/minisign.key
echo "${{ secrets.MINISIGN_SK }}" >> /tmp/minisign.key
cd dnscrypt-proxy
echo | /tmp/bin/minisign -s /tmp/minisign.key -Sm *.tar.gz *.zip
ls -l dnscrypt-proxy*
- name: Create release
id: create_release
uses: actions/create-release@v1
if: startsWith(github.ref, 'refs/tags/')
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
draft: false
prerelease: false
- name: Upload release assets
uses: softprops/action-gh-release@69320dbe05506a9a39fc8ae11030b214ec2d1f87
if: startsWith(github.ref, 'refs/tags/')
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
files: |
dnscrypt-proxy/*.zip
dnscrypt-proxy/*.tar.gz
dnscrypt-proxy/*.minisig
dnscrypt-proxy/*.msi

View File

@ -0,0 +1,23 @@
name: ShiftLeft Scan
on: push
jobs:
Scan-Build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Perform ShiftLeft Scan
uses: ShiftLeftSecurity/scan-action@master
env:
WORKSPACE: ""
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SCAN_AUTO_BUILD: true
with:
output: reports
- name: Upload report
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: reports

8
.gitignore vendored
View File

@ -9,3 +9,11 @@
*~
dnscrypt-proxy/dnscrypt-proxy2
dnscrypt-proxy/dnscrypt-proxy
.idea
.ci/*.log
.ci/*.md
.ci/*.md.minisig
.ci/test-dnscrypt-proxy.toml
contrib/msi/*.msi
contrib/msi/*.wixpdb
contrib/msi/*.wixobj

View File

@ -1,218 +0,0 @@
sudo: false
language: go
os:
- linux
go:
- 1.x
script:
- gimme --list
- echo $TRAVIS_GO_VERSION
- cd dnscrypt-proxy
- go clean
- env GOOS=windows GOARCH=386 go build -ldflags="-s -w"
- mkdir win32
- ln dnscrypt-proxy.exe win32/
- cp ../LICENSE example-dnscrypt-proxy.toml example-*.txt win32/
- for i in win32/LICENSE win32/*.toml win32/*.txt; do ex -bsc '%!awk "{sub(/$/,\"\r\")}1"'
-cx "$i"; done
- ln ../windows/* win32/
- zip -9 -r dnscrypt-proxy-win32-${TRAVIS_TAG:-dev}.zip win32
- go clean
- env GOOS=windows GOARCH=amd64 go build -ldflags="-s -w"
- mkdir win64
- ln dnscrypt-proxy.exe win64/
- cp ../LICENSE example-dnscrypt-proxy.toml example-*.txt win64/
- for i in win64/LICENSE win64/*.toml win64/*.txt; do ex -bsc '%!awk "{sub(/$/,\"\r\")}1"'
-cx "$i"; done
- ln ../windows/* win64/
- zip -9 -r dnscrypt-proxy-win64-${TRAVIS_TAG:-dev}.zip win64
- go clean
- env GO386=387 GOOS=openbsd GOARCH=386 go build -ldflags="-s -w"
- mkdir openbsd-i386
- ln dnscrypt-proxy openbsd-i386/
- ln ../LICENSE example-dnscrypt-proxy.toml example-*.txt openbsd-i386/
- tar czpvf dnscrypt-proxy-openbsd_i386-${TRAVIS_TAG:-dev}.tar.gz openbsd-i386
- go clean
- env GOOS=openbsd GOARCH=amd64 go build -ldflags="-s -w"
- mkdir openbsd-amd64
- ln dnscrypt-proxy openbsd-amd64/
- ln ../LICENSE example-dnscrypt-proxy.toml example-*.txt openbsd-amd64/
- tar czpvf dnscrypt-proxy-openbsd_amd64-${TRAVIS_TAG:-dev}.tar.gz openbsd-amd64
- go clean
- env GOOS=freebsd GOARCH=386 go build -ldflags="-s -w"
- mkdir freebsd-i386
- ln dnscrypt-proxy freebsd-i386/
- ln ../LICENSE example-dnscrypt-proxy.toml example-*.txt freebsd-i386/
- tar czpvf dnscrypt-proxy-freebsd_i386-${TRAVIS_TAG:-dev}.tar.gz freebsd-i386
- go clean
- env GOOS=freebsd GOARCH=amd64 go build -ldflags="-s -w"
- mkdir freebsd-amd64
- ln dnscrypt-proxy freebsd-amd64/
- ln ../LICENSE example-dnscrypt-proxy.toml example-*.txt freebsd-amd64/
- tar czpvf dnscrypt-proxy-freebsd_amd64-${TRAVIS_TAG:-dev}.tar.gz freebsd-amd64
- go clean
- env GOOS=freebsd GOARCH=arm go build -ldflags="-s -w"
- mkdir freebsd-arm
- ln dnscrypt-proxy freebsd-arm/
- ln ../LICENSE example-dnscrypt-proxy.toml example-*.txt freebsd-arm/
- tar czpvf dnscrypt-proxy-freebsd_arm-${TRAVIS_TAG:-dev}.tar.gz freebsd-arm
- go clean
- env GOOS=freebsd GOARCH=arm GOARM=7 go build -ldflags="-s -w"
- mkdir freebsd-armv7
- ln dnscrypt-proxy freebsd-armv7/
- ln ../LICENSE example-dnscrypt-proxy.toml example-*.txt freebsd-armv7/
- tar czpvf dnscrypt-proxy-freebsd_armv7-${TRAVIS_TAG:-dev}.tar.gz freebsd-armv7
- go clean
- env GOOS=dragonfly GOARCH=amd64 go build -ldflags="-s -w"
- mkdir dragonflybsd-amd64
- ln dnscrypt-proxy dragonflybsd-amd64/
- ln ../LICENSE example-dnscrypt-proxy.toml example-*.txt dragonflybsd-amd64/
- tar czpvf dnscrypt-proxy-dragonflybsd_amd64-${TRAVIS_TAG:-dev}.tar.gz dragonflybsd-amd64
- go clean
- env GOOS=netbsd GOARCH=386 go build -ldflags="-s -w"
- mkdir netbsd-i386
- ln dnscrypt-proxy netbsd-i386/
- ln ../LICENSE example-dnscrypt-proxy.toml example-*.txt netbsd-i386/
- tar czpvf dnscrypt-proxy-netbsd_i386-${TRAVIS_TAG:-dev}.tar.gz netbsd-i386
- go clean
- env GOOS=netbsd GOARCH=amd64 go build -ldflags="-s -w"
- mkdir netbsd-amd64
- ln dnscrypt-proxy netbsd-amd64/
- ln ../LICENSE example-dnscrypt-proxy.toml example-*.txt netbsd-amd64/
- tar czpvf dnscrypt-proxy-netbsd_amd64-${TRAVIS_TAG:-dev}.tar.gz netbsd-amd64
- go clean
- env CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags="-s -w"
- mkdir linux-i386
- ln dnscrypt-proxy linux-i386/
- ln ../LICENSE example-dnscrypt-proxy.toml example-*.txt linux-i386/
- tar czpvf dnscrypt-proxy-linux_i386-${TRAVIS_TAG:-dev}.tar.gz linux-i386
- go clean
- env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w"
- mkdir linux-x86_64
- ln dnscrypt-proxy linux-x86_64/
- ln ../LICENSE example-dnscrypt-proxy.toml example-*.txt linux-x86_64/
- tar czpvf dnscrypt-proxy-linux_x86_64-${TRAVIS_TAG:-dev}.tar.gz linux-x86_64
- go clean
- env CGO_ENABLED=0 GOOS=linux GOARCH=arm go build -ldflags="-s -w"
- mkdir linux-arm
- ln dnscrypt-proxy linux-arm/
- ln ../LICENSE example-dnscrypt-proxy.toml example-*.txt linux-arm/
- tar czpvf dnscrypt-proxy-linux_arm-${TRAVIS_TAG:-dev}.tar.gz linux-arm
- go clean
- env CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags="-s -w"
- mkdir linux-arm64
- ln dnscrypt-proxy linux-arm64/
- ln ../LICENSE example-dnscrypt-proxy.toml example-*.txt linux-arm64/
- tar czpvf dnscrypt-proxy-linux_arm64-${TRAVIS_TAG:-dev}.tar.gz linux-arm64
- go clean
- env CGO_ENABLED=0 GOOS=linux GOARCH=mips GOMIPS=softfloat go build -ldflags="-s -w"
- mkdir linux-mips
- ln dnscrypt-proxy linux-mips/
- ln ../LICENSE example-dnscrypt-proxy.toml example-*.txt linux-mips/
- tar czpvf dnscrypt-proxy-linux_mips-${TRAVIS_TAG:-dev}.tar.gz linux-mips
- go clean
- env CGO_ENABLED=0 GOOS=linux GOARCH=mipsle GOMIPS=softfloat go build -ldflags="-s -w"
- mkdir linux-mipsle
- ln dnscrypt-proxy linux-mipsle/
- ln ../LICENSE example-dnscrypt-proxy.toml example-*.txt linux-mipsle/
- tar czpvf dnscrypt-proxy-linux_mipsle-${TRAVIS_TAG:-dev}.tar.gz linux-mipsle
- go clean
- env CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build -ldflags="-s -w"
- mkdir linux-mips64
- ln dnscrypt-proxy linux-mips64/
- ln ../LICENSE example-dnscrypt-proxy.toml example-*.txt linux-mips64/
- tar czpvf dnscrypt-proxy-linux_mips64-${TRAVIS_TAG:-dev}.tar.gz linux-mips64
- go clean
- env CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -ldflags="-s -w"
- mkdir linux-mips64le
- ln dnscrypt-proxy linux-mips64le/
- ln ../LICENSE example-dnscrypt-proxy.toml example-*.txt linux-mips64le/
- tar czpvf dnscrypt-proxy-linux_mips64le-${TRAVIS_TAG:-dev}.tar.gz linux-mips64le
- go clean
- env GOOS=darwin GOARCH=amd64 go build -ldflags="-s -w"
- mkdir macos
- ln dnscrypt-proxy macos/
- ln ../LICENSE example-dnscrypt-proxy.toml example-*.txt macos/
- tar czpvf dnscrypt-proxy-macos-${TRAVIS_TAG:-dev}.tar.gz macos
- go clean
- env CC=arm-linux-androideabi-clang CXX=arm-linux-androideabi-clang++
CGO_ENABLED=1
GOOS=android GOARCH=arm GOARM=7 go build -ldflags="-s -w"
- mkdir android-arm
- ln dnscrypt-proxy android-arm/
- cp ../LICENSE example-dnscrypt-proxy.toml example-*.txt android-arm/
- zip -9 -r dnscrypt-proxy-android_arm-${TRAVIS_TAG:-dev}.zip android-arm
- go clean
- env CC=aarch64-linux-android-clang CXX=aarch64-linux-android-clang++
CGO_ENABLED=1
GOOS=android GOARCH=arm64 go build -ldflags="-s -w"
- mkdir android-arm64
- ln dnscrypt-proxy android-arm64/
- cp ../LICENSE example-dnscrypt-proxy.toml example-*.txt android-arm64/
- zip -9 -r dnscrypt-proxy-android_arm64-${TRAVIS_TAG:-dev}.zip android-arm64
- go clean
- env CC=i686-linux-android-clang CXX=i686-linux-android-clang++
CGO_ENABLED=1 GOOS=android
GOARCH=386 go build -ldflags="-s -w"
- mkdir android-i386
- ln dnscrypt-proxy android-i386/
- cp ../LICENSE example-dnscrypt-proxy.toml example-*.txt android-i386/
- zip -9 -r dnscrypt-proxy-android_i386-${TRAVIS_TAG:-dev}.zip android-i386
- go clean
- env CC=x86_64-linux-android-clang CXX=x86_64-linux-android-clang++
CGO_ENABLED=1
GOOS=android GOARCH=amd64 go build -ldflags="-s -w"
- mkdir android-x86_64
- ln dnscrypt-proxy android-x86_64/
- cp ../LICENSE example-dnscrypt-proxy.toml example-*.txt android-x86_64/
- zip -9 -r dnscrypt-proxy-android_x86_64-${TRAVIS_TAG:-dev}.zip android-x86_64
- ls -l dnscrypt-proxy-*.tar.gz dnscrypt-proxy-*.zip
deploy:
provider: releases
api_key:
secure: J3K/wo3oW/ySl6X4Zk5PX+EVy4fa0qa4fbpKNivogch5yjYw2pgrlSvwto9TM12Gxi4tTMKiWYK4YBapNf+tm501s4OyS1G1rJR1fZ+iyaHgGBLD+QppbivZt+P7Do56agSili68Zcgm7MQfZbvOq9z42z3AJ71+UNTJmTp63voaAuyOF/VdLsmJHMd/5nmFJH6mfMrgMs720GCWxFgdq3NRM2AdVldsp1YmNb4qKqIzunmfxqG9TqVlpq35tNOhWA/Ll3rbsiDVeUpBAW5ked/qHyGRkFVk44O6cPSFGe035Txx0JviBshGxsNSP+aJL9T55hIj1dmuk6g5uhPqABU/zcdJvXOv11oqJuV/DGHO31UfVN6u744LJY6Y1lkd+UUNiOJDPGC80+6M2GbP7BFMZiO5qnYkxzktnYg9b6zIPwmj96XZSniDTAn+qemJf2S8rzShvBtWX29Q4odIaCfFUY8i0muowQ4Vep5S5FqVG+r/rQTXOUIUsNv4r/gP/y5hdtOMC2r1VSvWk068upmW6ovCtcmTghSfYcLCG5r+g5OE2mKj9kbx6RQMspewk9+pvOhNZKXsn/AIvvDC4V46MaDjFkdYN0VbsYB5NH11DGCPH7vDwJnAzzMWnofCkiTG07dJYlLUnD9iUgYoNkrxivAgQKnDP8C6Ka0RGdk=
file:
- dnscrypt-proxy-*.tar.gz
- dnscrypt-proxy-*.zip
- dnscrypt-proxy-*.minisig
file_glob: true
skip_cleanup: true
on:
repo: jedisct1/dnscrypt-proxy
tags: true
before_deploy:
- mkdir -p /tmp/bin /tmp/lib /tmp/include
- export LD_LIBRARY_PATH=/tmp/lib:LD_LIBRARY_PATH
- export PATH=/tmp/bin:$PATH
- git clone https://github.com/jedisct1/libsodium.git --branch=stable
- cd libsodium
- env ./configure --disable-dependency-tracking --prefix=/tmp
- make -j$(nproc) install
- cd -
- git clone https://github.com/jedisct1/minisign.git
- cd minisign/src
- gcc -O2 -o /tmp/bin/minisign -I/tmp/include -L/tmp/lib *.c -lsodium
- cd -
- minisign -v
- echo '#' > /tmp/minisign.key
- echo "$MINISIGN_SK" >> /tmp/minisign.key
- echo | minisign -s /tmp/minisign.key -Sm dnscrypt-proxy-*.tar.gz dnscrypt-proxy-*.zip
after_deploy:
- ls -l dnscrypt-proxy-*.tar.gz dnscrypt-proxy-*.zip
before_install:
- NDK_VER=r18
- curl -LO http://dl.google.com/android/repository/android-ndk-${NDK_VER}-linux-x86_64.zip
- unzip -q android-ndk-${NDK_VER}-linux-x86_64.zip -d $HOME
- rm android-ndk-${NDK_VER}-linux-x86_64.zip
- NDK_TOOLS=$HOME/android-ndk-${NDK_VER}
- NDK_STANDALONE=$HOME/ndk-standalone-${NDK_VER}
- MAKE_TOOLCHAIN=$NDK_TOOLS/build/tools/make_standalone_toolchain.py
- for arch in x86 arm; do python $MAKE_TOOLCHAIN --arch $arch --api 19
--install-dir $NDK_STANDALONE/$arch; PATH=$PATH:$NDK_STANDALONE/$arch/bin; done
- for arch in x86_64 arm64; do python $MAKE_TOOLCHAIN --arch $arch --api 21
--install-dir $NDK_STANDALONE/$arch; PATH=$PATH:$NDK_STANDALONE/$arch/bin; done
- rm -rf $NDK_TOOLS
env:
global:
- secure: cuTXb4v5NwTr1XmkiHGkFir8fMiiBMnraCrls3thdDRlSTix0CiQc/H5Vh8SHauuG6VwVyrCT/Xsf0UQUmnULkPHjvuiNehb+bG4J3fz7hF94glBdQ8vxTuMmnHfJEYTQRLwCsWMBEC1wekw13O8J/0opFNG5neduns3Z1/rD5VSlBwgc8/4lomEp0fadIvzLeS7f5mxeXAD5Z9KBmc09uCjxVoF9Qsk1r901B0c0RMxIbJWyW9ZhDIVr/aEUN/tU0EXMKOA85sizg2moAigb8RZ1WCTh7utLGKpAyQegNk/unkksKMzZFkUCwHkrxlujwoe93wUS4rvZ+3nHMtLQdR+OfMeVs4/zvvQVq2f3bOXgkxgvhq6Bop0RK0xyEJffa5hUFbGNKhIFkLFLn1Ok28t2q7NOFPr0H2egHlkwgPztyhYMYb9C5PW4zd9buI0LS5452C4jXH5raBMfx844wTzaBbN689AKiYb84Qesqczss/o7eC7V48kh823dlZ/s2//gtp1ceqdAtNvp4dy7X/ECA/vNlpYisrtkR/CsFpJjGoTvS37leVMpmc5bn39dkoa5ZLliu7CaFRefbavcWWEImVStll9FBQ6+Ck9+41gczl9Rr7eGIV9ZZ/fmdkLNgxIpoAhZRee/dZD+/0gUExHxXXn10MqPuNVytVPiuU=

424
ChangeLog
View File

@ -1,4 +1,380 @@
* Version 2.0.24
# Version 2.1.5
- dnscrypt-proxy can be compiled with Go 1.21.0+
- Responses to blocked queries now include extended error codes
- Reliability of connections using HTTP/3 has been improved
- New configuration directive: `tls_key_log_file`. When defined, this
is the path to a file where TLS secret keys will be written to, so
that DoH traffic can be locally inspected.
# Version 2.1.4
- Fixes a regression from version 2.1.3: when cloaking was enabled,
blocked responses were returned for records that were not A/AAAA/PTR
even for names that were not in the cloaked list.
# Version 2.1.3
- DNS-over-HTTP/3 (QUIC) should be more reliable. In particular,
version 2.1.2 required another (non-QUIC) resolver to be present for
bootstrapping, or the resolver's IP address to be present in the
stamp. This is not the case any more.
- dnscrypt-proxy is now compatible with Go 1.20+
- Commands (-check, -show-certs, -list, -list-all) now ignore log
files and directly output the result to the standard output.
- The `cert_ignore_timestamp` configuration switch is now documented.
It allows ignoring timestamps for DNSCrypt certificate verification,
until a first server is available. This should only be used on devices
that don't have any ways to set the clock before DNS service is up.
However, a safer alternative remains to use an NTP server with a fixed
IP address (such as time.google.com), configured in the captive portals
file.
- Cloaking: when a name is cloaked, unsupported record types now
return a blocked response rather than the actual records.
- systemd: report Ready earlier as dnscrypt-proxy can itself manage
retries for updates/refreshes.
# Version 2.1.2
- Support for DoH over HTTP/3 (DoH3, HTTP over QUIC) has been added.
Compatible servers will automatically use it. Note that QUIC uses UDP
(usually over port 443, like DNSCrypt) instead of TCP.
- In previous versions, memory usage kept growing due to channels not
being properly closed, causing goroutines to pile up. This was fixed,
resulting in an important reduction of memory usage. Thanks to
@lifenjoiner for investigating and fixing this!
- DNS64: `CNAME` records are now translated like other responses.
Thanks to @ignoramous for this!
- A relay whose name has been configured, but doesn't exist in the
list of available relays is now a hard error. Thanks to @lifenjoiner!
- Mutexes/locking: bug fixes and improvements, by @ignoramous
- Official packages now include linux/riscv64 builds.
- `dnscrypt-proxy -resolve` now reports if ECS (EDNS-clientsubnet) is
supported by the server.
- `dnscrypt-proxy -list` now includes ODoH (Oblivious DoH) servers.
- Local DoH: queries made using the `GET` method are now handled.
- The service can now be installed on OpenRC-based systems.
- `PTR` queries are now supported for cloaked domains. Contributed by
Ian Bashford, thanks!
# Version 2.1.1
This is a bugfix only release, addressing regressions introduced in
version 2.1.0:
- When using DoH, cached responses were not served any more when
experiencing connectivity issues. This has been fixed.
- Time attributes in allow/block lists were ignored. This has been
fixed.
- The TTL as served to clients is now rounded and starts decreasing
before the first query is received.
- Time-based rules are properly handled again in
generate-domains-blocklist.
- DoH/ODoH: entries with an IP address and using a non-standard port
used to require help from a bootstrap resolver. This is not the case
any more.
# Version 2.1.0
- `dnscrypt-proxy` now includes support for Oblivious DoH.
- If the proxy is overloaded, cached and synthetic queries now keep being
served, while non-cached queries are delayed.
- A deprecation warning was added for `fallback_resolvers`.
- Source URLs are now randomized.
- On some platforms, redirecting the application log to a file was not
compatible with user switching; this has been fixed.
- `fallback_resolvers` was renamed to `bootstrap_resolvers` for
clarity. Please update your configuration file accordingly.
# Version 2.0.45
- Configuration changes (to be required in versions 2.1.x):
* `[blacklist]` has been renamed to `[blocked_names]`
* `[ip_blacklist]` has been renamed to `[blocked_ips]`
* `[whitelist]` has been renamed to `[allowed_names]`
* `generate-domains-blacklist.py` has been renamed to
`generate-domains-blocklist.py`, and the configuration files have been
renamed as well.
- `dnscrypt-proxy -resolve` has been completely revamped, and now requires
the configuration file to be accessible. It will send a query to an IP address
of the `dnscrypt-proxy` server by default. Sending queries to arbitrary
servers is also supported with the new `-resolve name,address` syntax.
- Relay lists can be set to `*` for automatic relay selection. When a wildcard
is used, either for the list of servers or relays, the proxy ensures that
relays and servers are on distinct networks.
- Lying resolvers are detected and reported.
- New return code: `NOT_READY` for queries received before the proxy has
been initialized.
- Server lists can't be older than a week any more, even if directory
permissions are incorrect and cache files cannot be written.
- macOS/arm64 is now officially supported.
- New feature: `allowed_ips`, to configure a set of IP addresses to
never block no matter what DNS name resolves to them.
- Hard-coded IP addresses can be immediately returned for test queries
sent by operating systems in order to check for connectivity and captive
portals. Such responses can be sent even before an interface is considered
as enabled by the operating system. This can be configured in a new section
called `[captive_portals]`.
- On Linux, OpenBSD and FreeBSD, `listen_addresses` can now include IP
addresses that haven't been assigned to an interface yet.
- The logo has been tweaked to look fine on a dark background.
- `generate-domains-blocklist.py`: regular expressions are now ignored in
time-based entries.
- Minor bug fixes and logging improvements.
- Cloaking plugin: if an entry has multiple IP addresses for a type,
all the IP addresses are now returned instead of a random one.
- Static entries can now include DNSCrypt relays.
- Name blocking: aliases relying on `SVCB` and `HTTPS` records can now
be blocked in addition to aliases via regular `CNAME` records.
- EDNS-Client-Subnet information can be added to outgoing queries.
Instead of sending the actual client IP, ECS information is user
configurable, and IP addresses will be randomly chosen for every query.
- Initial DoH queries are now checked using random names in order to
properly measure CDNs such as Tencent that ignore the padding.
- DoH: the `max-stale` cache control directive is now present in queries.
- Logs can now be sent to `/dev/stdout` instead of actual files.
- User switching is now supported on macOS.
- New download mirror (https://download.dnscrypt.net) for resolvers,
relays and parental-control.
Thanks to the nice people who contributed to this release:
- Ian Bashford
- Will Elwood
- Alison Winters
- Krish De Souza
- @hugepants
- @IceCodeNew
- @lifenjoiner
- @mibere
- @jacob755
- @petercooperjr
- @yofiji
# Version 2.0.44
- More updates to the set of block lists, thanks again to IceCodeNew.
- Netprobes and listening sockets are now ignored when the `-list`,
`-list-all`, `-show-certs` or `-check` command-line switches are used.
- `tls_client_auth` was renamed to `doh_client_x509_auth`. A section
with the previous name is temporarily ignored if empty, but will error
out if not.
- Unit tests are now working on 32-bit systems. Thanks to Will Elwood
and @lifenjoiner.
# Version 2.0.43
- Built-in support for DNS64 translation has been implemented.
(Contributed by Sergey Smirnov, thanks!)
- Connections to DoH servers can be authenticated using TLS client
certificates (Contributed by Kevin O'Sullivan, thanks!)
- Multiple stamps are now allowed for a single server in resolvers
and relays lists.
- Android: the time zone for log files is now set to the system
time zone.
- Quite a lot of updates and additions have been made to the
example domain block lists. Thanks to `IceCodeNew`!
- Cached configuration files can now be temporarily used if
they are out of date, but bootstraping is impossible. Contributed by
`lifenjoiner`, thanks!
- Precompiled macOS binaries are now notarized.
- `generate-domains-blacklists` now tries to deduplicate entries
clobbered by wildcard rules. Thanks to `Huhni`!
- `generate-domains-blacklists` can now directly write lists to a
file with the `-o` command-line option.
- cache files are now downloaded as the user the daemon will be running
as. This fixes permission issues at startup time.
- Forwarded queries are now subject to global timeouts, and can be
forced to use TCP.
- The `ct` parameter has been removed from DoH queries, as Google doesn't
require it any more.
- Service installation is now supported on FreeBSD.
- When stored into a file, service logs now only contain data from the most
recent launch. This can be changed with the new `log_file_latest` option.
- Breaking change: the `tls_client_auth` section was renamed to
`doh_client_x509_auth`. If you had a tls_client_auth section in the
configuration file, it needs to be updated.
# Version 2.0.42
- The current versions of the `dnsdist` load balancer (presumably used
by quad9, cleanbrowsing, qualityology, freetsa.org, ffmuc.net,
opennic-bongobow, sth-dnscrypt-se, ams-dnscrypt-nl and more)
is preventing queries over 1500 bytes from being received over UDP.
Temporary workarounds have been introduced to improve reliability
with these resolvers for regular DNSCrypt. Unfortunately, anonymized
DNS cannot be reliable until the issue is fixed server-side. `dnsdist`
authors are aware of it and are working on a fix.
- New option in the `[anonymized_dns]` section: `skip_incompatible`,
to ignore resolvers incompatible with Anonymized DNS instead of
using them without a relay.
- The server latency benchmark is faster while being able to perform
more retries if necessary.
- Continuous integration has been moved to GitHub Actions.
# Version 2.0.41
- Precompiled ARM binaries are compatible with ARMv5 CPUs. The
default arm builds were not compatible with older CPUs when compiled
with Go 1.14. mips64 binaries are explicitly compiled with `softfloat`
to improve compatibility.
- Quad9 seems to be only blocking fragmented queries over UDP for
some networks. They have been removed from the default list of broken
resolvers; runtime detection of support for fragments should now do
the job.
- Runtime detection of support for fragments was actually enabled.
# Version 2.0.40
- Servers blocking fragmented queries are now automatically detected.
- The server name is now only present in query logs when an actual
upstream servers was required to resolve a query.
- TLS client authentication has been added for DoH.
- The Firefox plugin is now skipped for connections coming from the
local DoH server.
- DoH RTT computation is now more accurate, especially when CDNs are
in the middle.
- The forwarding plugin is now more reliable, and handles retries over
TCP.
# Version 2.0.39
- The Firefox Local DoH service didn't properly work in version 2.0.38;
this has been fixed. Thanks to Simon Brand for the report!
# Version 2.0.38
- Entries from lists (forwarding, blacklists, whitelists) now support
inline comments.
- Reliability improvement: queries over UDP are retried after a timeout
instead of solely relying on the client.
- Reliability improvement: during temporary network outages, cached records
are now served even if they are stale.
- Bug fix: SOCKS proxies and DNS relays can be combined.
- New feature: multiple fallback resolvers are now supported (see the
new `fallback_resolvers` option. Note that `fallback_resolver` is
still supported for backward compatibility).
- Windows: the service can be installed with a configuration file
stored separately from the application.
- Security (affecting DoH): precompiled binaries of dnscrypt-proxy 2.0.37 are
built using Go 1.13.7 that fixes a TLS certificate parsing issue present in
previous versions of the compiler.
# Version 2.0.36
- New option: `block_undelegated`. When enabled, `dnscrypt-proxy` will
directly respond to queries for locally-served zones (https://sk.tl/2QqB971U)
and nonexistent zones that should have been kept local, but are frequently
leaked. This reduces latency and improves privacy.
- Conformance: the `DO` bit is now set in synthetic responses if it was
set in a question, and the `AD` bit is cleared.
- The `miegkg/dns` module was updated to version 1.1.26, that fixes a
security issue affecting non-encrypted/non-authenticated DNS traffic. In
`dnscrypt-proxy`, this only affects the forwarding feature.
# Version 2.0.35
- New option: `block_unqualified` to block `A`/`AAAA` queries with
unqualified host names. These will very rarely get an answer from upstream
resolvers, but can leak private information to these, as well as to root
servers.
- When a `CNAME` pointer is blocked, the original query name is now logged
along with the pointer. This makes it easier to know what the original
query name, so it can be whitelisted, or what the pointer was, so it
can be removed from the blacklist.
# Version 2.0.34
- Blacklisted names are now also blocked if they appear in `CNAME`
pointers.
- `dnscrypt-proxy` can now act as a local DoH *server*. Firefox can
be configured to use it, so that ESNI can be enabled without bypassing
your DNS proxy.
# Version 2.0.33
- Fixes an issue that caused some valid queries to return `PARSE_ERROR`.
# Version 2.0.32
- On certificate errors, the server name is now logged instead of the
provider name, which is generally more useful.
- IP addresses for DoH servers that require DNS lookups are now cached
for at least 12 hours.
- `ignore_system_dns` is now set to `true` by default.
- A workaround for a bug in Cisco servers has been implemented.
- A corrupted or incomplete resolvers list is now ignored, keeping the
last good known cached list until the next update. In addition, logging was
improved and unit tests were also added. Awesome contribution from William
Elwood, thanks!
- On Windows, the network probe immediately returned instead of blocking
if `netprobe_timeout` was set to `-1`. This has been fixed.
- Expired cached IP addresses now have a grace period, to avoid breaking the
service if they temporarily can't be refreshed.
- On Windows, the service now returns immediately, solving a long-standing
issue when initialization took more than 30 seconds ("The service did not
respond to the start or control request in a timely fashion"). Fantastic
work by Alison Winters, thanks!
- The `SERVER_ERROR` error code has been split into two new error codes:
`NETWORK_ERROR` (self-explanatory) and `SERVFAIL` (a response was returned,
but it includes a `SERVFAIL` error code).
- Responses are now always compressed.
# Version 2.0.31
- This version fixes two regressions introduced in version 2.0.29:
DoH server couldn't be reached over IPv6 any more, and the proxy
couldn't be interrupted while servers were being benchmarked.
# Version 2.0.30
- This version fixes a startup issue introduced in version 2.0.29,
on systems for which the service cannot be automatically installed
(such as OpenBSD and FreeBSD). Reported by @5ch17 and Vinícius Zavam,
and fixed by Will Elwood, thanks!
# Version 2.0.29
- Support for Anonymized DNS has been added!
- Wait before stopping, fixing an issue with Unbound (thanks to
Vladimir Bauer)
- DNS stamps are now included in the -list-all -json ouptut
- The netprobe_timeout setting from the configuration file or
command-line was ignored. This has been fixed.
- The TTL or cloaked entries can now be adjusted (thanks to Markus
Linnala)
- Cached IP address from DoH servers now expire (thanks to Markus
Linnala)
- DNSCrypt certificates can be fetched over Tor and SOCKS proxies
- Retries over TCP are faster
- Improved logging (thanks to Alison Winters)
- Ignore non-TXT records in certificate responses (thanks to Vladimir
Bauer)
- A lot of internal cleanups, thanks to Markus Linnala.
# Version 2.0.28
- Invalid server entries are now skipped instead of preventing a
source from being used. Thanks to Alison Winters for the contribution!
- Truncated responses are immediately retried over TCP instead of
waiting for the client to retry. This reduces the latency for large
responses.
- Responses sent to the local network are assumed to support at least
1252 bytes packets, and use optional information from EDNS up to 4096
bytes. This also reduces latency.
- Logging improvements: servers are not logged for cached, synthetic
and cloaked responses. And the forwarder is logged instead of the
regular server for forwarded responses.
# Version 2.0.27
- The X25519 implementation was changed from using the Go standard
implementation to using Cloudflare's CIRCL library. Unfortunately,
CIRCL appears to be broken on big-endian systems. That change has been
reverted.
- All the dependencies have been updated.
# Version 2.0.26
- A new plugin was added to prevent Firefox from bypassing the system
DNS settings.
- New configuration parameter to set how to respond to blocked
queries: `blocked_query_response`. Responses can now be empty record
sets, REFUSED response codes, or predefined IPv4 and/or IPv6 addresses.
- The `refused_code_in_responses` and `blocked_query_response` options
have been folded into a new `blocked_query_response` option.
- The fallback resolver is now accessed using TCP if `force_tcp` has
been set to `true`.
- CPU usage when enabling DNSCrypt ephemeral keys has been reduced.
- New command-line option: `-show-certs` to print DoH certificate
hashes.
- Solaris packages are now provided.
- DoH servers on a non-standard port, with stamps that don't include
IP addresses, and without working system resolvers can now be properly
bootstrapped.
- A new option, `query_meta`, is now available to add optional records
to client queries.
# Version 2.0.25
- The example IP address for network probes didn't work on Windows.
The example configuration file has been updated and the fallback
resolver IP is now used when no netprobe address has been configured.
# Version 2.0.24
- The query log now includes the time it took to complete the
transaction, the name of the resolver that sent the response and if
the response was served from the cache. Thanks to Ferdinand Holzer for
@ -20,7 +396,7 @@ Thanks to @inkblotadmirer for the report.
- Resolvers are now tried in random order to avoid favoring the first
ones at startup.
* Version 2.0.23
# Version 2.0.23
- Binaries for FreeBSD/armv7 are now available.
- .onion servers are now automatically ignored if Tor routing is not
enabled.
@ -29,15 +405,15 @@ using proxies.
- DNSCrypt communications are now automatically forced to using TCP
when a SOCKS proxy has been set up.
* Version 2.0.22
# Version 2.0.22
- The previous version had issues with the .org TLD when used in
conjunction with dnsmasq. This has been fixed.
* Version 2.0.21
# Version 2.0.21
- The change to run the Windows service as `NT AUTHORITY\NetworkService`
has been reverted, as it was reported to break logging (Windows only).
* Version 2.0.20
# Version 2.0.20
- Startup is now *way* faster, especially when using DoH servers.
- A new action: `CLOAK` is logged when queries are being cloaked.
- A cloaking rule can now map to multiple IPv4 and IPv6 addresses,
@ -51,7 +427,7 @@ generate-domains-blacklist.py script.
script.
- The Windows service is now installed as `NT AUTHORITY\NetworkService`.
* Version 2.0.19
# Version 2.0.19
- The value for `netprobe_timeout` was read from the command-line, but
not from the configuration file any more. This is a regression introduced
in the previous version, that has been fixed.
@ -60,7 +436,7 @@ in the previous version, that has been fixed.
queries with the POST method in order to work around badly configured
proxies.
* Version 2.0.18
# Version 2.0.18
- Official builds now support TLS 1.3.
- The timeout for the initial connectivity check can now be set from
the command line.
@ -69,7 +445,7 @@ the command line.
- In addition to SOCKS, HTTP and HTTPS proxies are now supported for
DoH servers.
* Version 2.0.17
# Version 2.0.17
- Go >= 1.11 is now supported
- The flipside is that Windows XP is not supported any more :(
- When dropping privileges, there is no supervisor process any more.
@ -78,7 +454,7 @@ of flags and payload sizes. This is not the case any more.
- DoH queries are smaller, since workarounds are not required any more
after Google updated their implementation.
* Version 2.0.16
# Version 2.0.16
- On Unix-like systems, the server can run as an unprivileged user,
and the main process will automatically restart if an error occurs.
- pledge() on OpenBSD.
@ -90,7 +466,7 @@ cloaking module for local development.
- The proxy doesn't quit any more if new TCP connections cannot be
created.
* Version 2.0.15
# Version 2.0.15
- Support for proxies (HTTP/SOCKS) was added. All it takes to route
all TCP queries to Tor is add `proxy = "socks5://127.0.0.1:9050"` to
the configuration file.
@ -99,16 +475,16 @@ transaction.
- Pre-built binaries for Linux are statically linked on all
architectures.
* Version 2.0.14
# Version 2.0.14
- Supports DNS-over-HTTPS draft 08.
- Netprobes don't use port 0 by default, as this causes issues with
Little Snitch and FreeBSD.
* Version 2.0.13
# Version 2.0.13
- This version fixes a crash when using DoH for queries whose size
were a multiple of the block size. Reported by @char101, thanks!
* Version 2.0.12
# Version 2.0.12
- Further compatibility fixes for Alpine Linux/i386 and Android/i386
have been made. Thanks to @aead for his help!
- The proxy will now wait for network connectivity before starting.
@ -117,7 +493,7 @@ before the network is fully configured.
- The IPv6 blocking module now returns synthetic SOA records to
improve compatibility with downstream resolvers and stub resolvers.
* Version 2.0.11
# Version 2.0.11
- This release fixes a long-standing bug that caused the proxy to
block or crash when Position-Independent Executables were produced.
This bug only showed up when compiled on (not for) Alpine Linux and
@ -125,13 +501,13 @@ Android, for some CPU architectures.
- New configuration settings: cache_neg_min_ttl and
cache_neg_max_ttl, to clamp the negative caching TTL.
* Version 2.0.10
# Version 2.0.10
- This version fixes a crash when an incomplete size is sent by a
local client for a query over TCP.
- Slight performance improvement of DNSCrypt on non-Intel CPUs such
as Raspberry Pi.
* Version 2.0.9
# Version 2.0.9
- Whitelists have been implemented: one a name matches a pattern in
the whitelist, rules from the name-based and IP-based blacklists will
be bypassed. Whitelists support the same patterns as blacklists, as
@ -157,7 +533,7 @@ especially on Mips and ARM systems.
- The ephemeral keys mode of dnscrypt-proxy v1.x was reimplemented: this
creates a new unique key for every single query.
* Version 2.0.8
# Version 2.0.8
- Multiple URLs can be defined for a source in order to improve
resiliency when servers are temporarily unreachable.
- Connections over IPv6 will be preferred over IPv4 for DoH servers
@ -171,41 +547,41 @@ Android/x86.
- `dnscrypt-proxy -list -json` and `-list-all -json` now include the
remove servers names and IP addresses.
* Version 2.0.7
# Version 2.0.7
- Bug fix: optional ports were not properly parsed with IPv6
addresses -- thanks to @bleeee for the report and fix.
- Bug fix: truncate TCP queries to the prefixed length.
- Certificates are force-refreshed after a time jump (e.g. when a
system resumes from hibernation).
* Version 2.0.6
# Version 2.0.6
- Automatic log files rotation was finally implemented.
- A new -pidfile command-line option to write the PID file was added.
* Version 2.0.5
# Version 2.0.5
- Fixes a crash occasionally happening when using DoH servers, with
stamps not containing any IP addresses, a DNSSEC-signed name, a
non-working system DNS configuration, and a fallback server supporting
DNSSEC.
* Version 2.0.4
# Version 2.0.4
- Fixes a regression with truncated packets. Thanks to @mazesy and
@the-w1nd for spotting a case triggering this!
* Version 2.0.3
# Version 2.0.3
- Load balancing: resolvers that respond promptly, but with bogus
responses are now gradually removed from the preferred pool.
- Due to popular request, Android binaries are now available! Thanks
to @sporif for his help on getting these built.
- Binaries are built using Go 1.10-final.
* Version 2.0.2
# Version 2.0.2
- Properly error out on FreeBSD and other platforms where built-in
service installation is not supported yet.
- Improved load-balancing algorithm, which should result in lower
latency.
* Version 2.0.1
# Version 2.0.1
- Cached source data were not redownloaded if the proxy was used
without interruption. This has been fixed.
- If the network is down at startup time, fall back to cached source

33
LICENSE
View File

@ -1,18 +1,15 @@
/*
* ISC License
*
* Copyright (c) 2018
* Frank Denis <j at pureftpd dot org>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
ISC License
Copyright (c) 2018-2023, Frank Denis <j at pureftpd dot org>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.

View File

@ -1,26 +1,32 @@
# ![dnscrypt-proxy 2](https://raw.github.com/jedisct1/dnscrypt-proxy/master/logo.png?3)
# ![dnscrypt-proxy 2](https://raw.github.com/dnscrypt/dnscrypt-proxy/master/logo.png?3)
[![DNSCrypt-Proxy Release](https://img.shields.io/github/release/jedisct1/dnscrypt-proxy.svg?label=Latest%20Release&style=popout)](https://github.com/jedisct1/dnscrypt-proxy/releases/latest) [![Build Status](https://travis-ci.org/jedisct1/dnscrypt-proxy.svg?branch=master)](https://travis-ci.org/jedisct1/dnscrypt-proxy?branch=master) [![#dnscrypt-proxy:matrix.org](https://img.shields.io/matrix/dnscrypt-proxy:matrix.org.svg?label=DNSCrypt-Proxy%20Matrix%20Chat&server_fqdn=matrix.org&style=popout)](https://matrix.to/#/#dnscrypt-proxy:matrix.org)
[![Financial Contributors on Open Collective](https://opencollective.com/dnscrypt/all/badge.svg?label=financial+contributors)](https://opencollective.com/dnscrypt)
[![DNSCrypt-Proxy Release](https://img.shields.io/github/release/dnscrypt/dnscrypt-proxy.svg?label=Latest%20Release&style=popout)](https://github.com/dnscrypt/dnscrypt-proxy/releases/latest)
[![Build Status](https://github.com/DNSCrypt/dnscrypt-proxy/actions/workflows/releases.yml/badge.svg)](https://github.com/DNSCrypt/dnscrypt-proxy/actions/workflows/releases.yml)
![CodeQL scan](https://github.com/DNSCrypt/dnscrypt-proxy/workflows/CodeQL%20scan/badge.svg)
![ShiftLeft Scan](https://github.com/DNSCrypt/dnscrypt-proxy/workflows/ShiftLeft%20Scan/badge.svg)
[![#dnscrypt-proxy:matrix.org](https://img.shields.io/matrix/dnscrypt-proxy:matrix.org.svg?label=DNSCrypt-Proxy%20Matrix%20Chat&server_fqdn=matrix.org&style=popout)](https://matrix.to/#/#dnscrypt-proxy:matrix.org)
## Overview
A flexible DNS proxy, with support for modern encrypted DNS protocols such as [DNSCrypt v2](https://dnscrypt.info/protocol) and [DNS-over-HTTPS](https://www.rfc-editor.org/rfc/rfc8484.txt).
A flexible DNS proxy, with support for modern encrypted DNS protocols such as [DNSCrypt v2](https://dnscrypt.info/protocol), [DNS-over-HTTPS](https://www.rfc-editor.org/rfc/rfc8484.txt), [Anonymized DNSCrypt](https://github.com/DNSCrypt/dnscrypt-protocol/blob/master/ANONYMIZED-DNSCRYPT.txt) and [ODoH (Oblivious DoH)](https://github.com/DNSCrypt/dnscrypt-resolvers/blob/master/v3/odoh-servers.md).
* [dnscrypt-proxy documentation](https://dnscrypt.info/doc) This project's documentation (Wiki)
* **[dnscrypt-proxy documentation](https://dnscrypt.info/doc) ← Start here**
* [DNSCrypt project home page](https://dnscrypt.info/)
* [Discussions](https://github.com/DNSCrypt/dnscrypt-proxy/discussions)
* [DNS-over-HTTPS and DNSCrypt resolvers](https://dnscrypt.info/public-servers)
* [Server and client implementations](https://dnscrypt.info/implementations)
* [DNS stamps](https://dnscrypt.info/stamps)
* [FAQ](https://dnscrypt.info/faq)
## [Download the latest release](https://github.com/jedisct1/dnscrypt-proxy/releases/latest)
## [Download the latest release](https://github.com/dnscrypt/dnscrypt-proxy/releases/latest)
Available as source code and pre-built binaries for most operating
systems and architectures (see below).
Available as source code and pre-built binaries for most operating systems and architectures (see below).
## Features
* DNS traffic encryption and authentication. Supports DNS-over-HTTPS (DoH) using TLS 1.3, and DNSCrypt.
* DNS traffic encryption and authentication. Supports DNS-over-HTTPS (DoH) using TLS 1.3 and QUIC, DNSCrypt, Anonymized DNS and ODoH
* Client IP addresses can be hidden using Tor, SOCKS proxies or Anonymized DNS relays
* DNS query monitoring, with separate log files for regular and suspicious queries
* Filtering: block ads, malware, and other unwanted content. Compatible with all DNS services
* Time-based filtering, with a flexible weekly schedule
@ -28,11 +34,11 @@ systems and architectures (see below).
* DNS caching, to reduce latency and improve privacy
* Local IPv6 blocking to reduce latency on IPv4-only networks
* Load balancing: pick a set of resolvers, dnscrypt-proxy will automatically measure and keep track of their speed, and balance the traffic across the fastest available ones.
* Cloaking: like a `HOSTS` file on steroids, that can return preconfigured addresses for specific names, or resolve and return the IP address of other names. This can be used for local development as well as to enforce safe search results on Google, Yahoo and Bing.
* Cloaking: like a `HOSTS` file on steroids, that can return preconfigured addresses for specific names, or resolve and return the IP address of other names. This can be used for local development as well as to enforce safe search results on Google, Yahoo, DuckDuckGo and Bing
* Automatic background updates of resolvers lists
* Can force outgoing connections to use TCP
* Supports SOCKS proxies
* Compatible with DNSSEC
* Includes a local DoH server in order to support ECH (ESNI)
## Pre-built binaries
@ -54,7 +60,8 @@ Up-to-date, pre-built binaries are available for:
* Linux/mips64le
* Linux/x86
* Linux/x86_64
* MacOS X
* macOS/arm64
* macOS/x86_64
* NetBSD/x86
* NetBSD/x86_64
* OpenBSD/x86
@ -62,4 +69,34 @@ Up-to-date, pre-built binaries are available for:
* Windows
* Windows 64 bit
How to use these files, as well as how to verify their signatures, are documented in the [installation instructions](https://github.com/jedisct1/dnscrypt-proxy/wiki/installation).
How to use these files, as well as how to verify their signatures, are documented in the [installation instructions](https://github.com/dnscrypt/dnscrypt-proxy/wiki/installation).
## Contributors
### Code Contributors
This project exists thanks to all the people who contribute.
<a href="https://github.com/dnscrypt/dnscrypt-proxy/graphs/contributors"><img src="https://opencollective.com/dnscrypt/contributors.svg?width=890&button=false" /></a>
### Financial Contributors
Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/dnscrypt/contribute)]
#### Individuals
<a href="https://opencollective.com/dnscrypt"><img src="https://opencollective.com/dnscrypt/individuals.svg?width=890"></a>
#### Organizations
Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/dnscrypt/contribute)]
<a href="https://opencollective.com/dnscrypt/organization/0/website"><img src="https://opencollective.com/dnscrypt/organization/0/avatar.svg"></a>
<a href="https://opencollective.com/dnscrypt/organization/1/website"><img src="https://opencollective.com/dnscrypt/organization/1/avatar.svg"></a>
<a href="https://opencollective.com/dnscrypt/organization/2/website"><img src="https://opencollective.com/dnscrypt/organization/2/avatar.svg"></a>
<a href="https://opencollective.com/dnscrypt/organization/3/website"><img src="https://opencollective.com/dnscrypt/organization/3/avatar.svg"></a>
<a href="https://opencollective.com/dnscrypt/organization/4/website"><img src="https://opencollective.com/dnscrypt/organization/4/avatar.svg"></a>
<a href="https://opencollective.com/dnscrypt/organization/5/website"><img src="https://opencollective.com/dnscrypt/organization/5/avatar.svg"></a>
<a href="https://opencollective.com/dnscrypt/organization/6/website"><img src="https://opencollective.com/dnscrypt/organization/6/avatar.svg"></a>
<a href="https://opencollective.com/dnscrypt/organization/7/website"><img src="https://opencollective.com/dnscrypt/organization/7/avatar.svg"></a>
<a href="https://opencollective.com/dnscrypt/organization/8/website"><img src="https://opencollective.com/dnscrypt/organization/8/avatar.svg"></a>
<a href="https://opencollective.com/dnscrypt/organization/9/website"><img src="https://opencollective.com/dnscrypt/organization/9/avatar.svg"></a>

21
contrib/msi/Dockerfile Normal file
View File

@ -0,0 +1,21 @@
FROM ubuntu:latest
MAINTAINER dnscrypt-authors
RUN apt-get update && \
apt-get install -y wget wine dotnet-sdk-6.0 && \
dpkg --add-architecture i386 && apt-get update && apt-get install -y wine32
ENV WINEPREFIX=/root/.wine32 WINEARCH=win32 WINEDEBUG=-all
RUN wget https://dl.winehq.org/wine/wine-mono/8.1.0/wine-mono-8.1.0-x86.msi && \
WINEPREFIX="$HOME/.wine32" WINEARCH=win32 wineboot --init && \
WINEPREFIX="$HOME/.wine32" WINEARCH=win32 wine msiexec /i wine-mono-8.1.0-x86.msi && \
mkdir $WINEPREFIX/drive_c/temp && \
apt-get install -y unzip && \
wget https://github.com/wixtoolset/wix3/releases/download/wix3112rtm/wix311-binaries.zip -nv -O wix.zip && \
unzip wix.zip -d /wix && \
rm -f wix.zip
WORKDIR /wix

13
contrib/msi/README.md Normal file
View File

@ -0,0 +1,13 @@
# Scripts and utilities related to building an .msi (Microsoft Standard Installer) file.
## Docker test image for building an MSI locally
```sh
docker build . -f Dockerfile -t ubuntu:dnscrypt-msi
```
## Test building msi files for intel win32 & win64
```sh
./build.sh
```

30
contrib/msi/build.sh Executable file
View File

@ -0,0 +1,30 @@
#! /bin/sh
version=0.0.0
gitver=$(git describe --tags --always --match="[0-9]*.[0-9]*.[0-9]*" --exclude='*[^0-9.]*')
if [ "$gitver" != "" ]; then
version=$gitver
fi
# build the image by running: docker build . -f Dockerfile -t ubuntu:dnscrypt-msi
if [ "$(docker image list -q ubuntu:dnscrypt-msi)" = "" ]; then
docker build . -f Dockerfile -t ubuntu:dnscrypt-msi
fi
image=ubuntu:dnscrypt-msi
for arch in x64 x86; do
binpath="win32"
if [ "$arch" = "x64" ]; then
binpath="win64"
fi
src=$(
cd ../../dnscrypt-proxy/$binpath || exit
pwd
)
echo "$src"
docker run --rm -v "$(pwd)":/wixproj -v "$src":/src $image wine candle.exe -dVersion="$version" -dPlatform=$arch -dPath=\\src -arch $arch \\wixproj\\dnscrypt.wxs -out \\wixproj\\dnscrypt-$arch.wixobj
docker run --rm -v "$(pwd)":/wixproj -v "$src":/src $image wine light.exe -out \\wixproj\\dnscrypt-proxy-$arch-"$version".msi \\wixproj\\dnscrypt-$arch.wixobj -sval
done

60
contrib/msi/dnscrypt.wxs Normal file
View File

@ -0,0 +1,60 @@
<?xml version="1.0"?>
<?if $(var.Platform)="x64" ?>
<?define Program_Files="ProgramFiles64Folder"?>
<?else ?>
<?define Program_Files="ProgramFilesFolder"?>
<?endif ?>
<?ifndef var.Version?>
<?error Undefined Version variable?>
<?endif ?>
<?ifndef var.Path?>
<?error Undefined Path variable?>
<?endif ?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*"
UpgradeCode="fbf99dd8-c21e-4f9b-a632-de53bb64c45e"
Name="dnscrypt-proxy"
Version="$(var.Version)"
Manufacturer="DNSCrypt"
Language="1033">
<Package InstallerVersion="200" Compressed="yes" Comments="Windows Installer Package" InstallScope="perMachine" />
<Media Id="1" Cabinet="product.cab" EmbedCab="yes" />
<MajorUpgrade DowngradeErrorMessage="A later version of [ProductName] is already installed. Setup will now exit." />
<Upgrade Id="fbf99dd8-c21e-4f9b-a632-de53bb64c45e">
<UpgradeVersion Minimum="$(var.Version)" OnlyDetect="yes" Property="NEWERVERSIONDETECTED" />
<UpgradeVersion Minimum="2.1.0" Maximum="$(var.Version)" IncludeMinimum="yes" IncludeMaximum="no" Property="OLDERVERSIONBEINGUPGRADED" />
</Upgrade>
<Condition Message="A newer version of this software is already installed.">NOT NEWERVERSIONDETECTED</Condition>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="$(var.Program_Files)">
<Directory Id="INSTALLDIR" Name="DNSCrypt">
<Component Id="ApplicationFiles" Guid="7d693c0b-71d8-436a-9c84-60a11dc74092">
<File Id="dnscryptproxy.exe" KeyPath="yes" Source="$(var.Path)\dnscrypt-proxy.exe" DiskId="1"/>
<File Source="$(var.Path)\LICENSE"></File>
<File Source="$(var.Path)\service-install.bat"></File>
<File Source="$(var.Path)\service-restart.bat"></File>
<File Source="$(var.Path)\service-uninstall.bat"></File>
<File Source="$(var.Path)\example-dnscrypt-proxy.toml"></File>
</Component>
<Component Id="ConfigInstall" Guid="db7b691e-f7c7-4c9a-92e1-c6f21ce6430f" KeyPath="yes">
<Condition><![CDATA[CONFIGFILE]]></Condition>
<CopyFile Id="dnscryptproxytoml" DestinationDirectory="INSTALLDIR" DestinationName="dnscrypt-proxy.toml" SourceProperty="CONFIGFILE">
</CopyFile>
<RemoveFile Id="RemoveConfig" Directory="INSTALLDIR" Name="dnscrypt-proxy.toml" On="uninstall" />
</Component>
</Directory>
</Directory>
</Directory>
<Feature Id="Complete" Level="1">
<ComponentRef Id="ApplicationFiles" />
<ComponentRef Id="ConfigInstall" />
</Feature>
</Product>
</Wix>

203
dnscrypt-proxy/coldstart.go Normal file
View File

@ -0,0 +1,203 @@
package main
import (
"fmt"
"net"
"strings"
"sync"
"time"
"github.com/jedisct1/dlog"
"github.com/miekg/dns"
)
type CaptivePortalEntryIPs []net.IP
type CaptivePortalMap map[string]CaptivePortalEntryIPs
type CaptivePortalHandler struct {
wg sync.WaitGroup
cancelChannel chan struct{}
}
func (captivePortalHandler *CaptivePortalHandler) Stop() {
close(captivePortalHandler.cancelChannel)
captivePortalHandler.wg.Wait()
}
func (ipsMap *CaptivePortalMap) GetEntry(msg *dns.Msg) (*dns.Question, *CaptivePortalEntryIPs) {
if len(msg.Question) != 1 {
return nil, nil
}
question := &msg.Question[0]
name, err := NormalizeQName(question.Name)
if err != nil {
return nil, nil
}
ips, ok := (*ipsMap)[name]
if !ok {
return nil, nil
}
if question.Qclass != dns.ClassINET {
return nil, nil
}
return question, &ips
}
func HandleCaptivePortalQuery(msg *dns.Msg, question *dns.Question, ips *CaptivePortalEntryIPs) *dns.Msg {
respMsg := EmptyResponseFromMessage(msg)
ttl := uint32(1)
if question.Qtype == dns.TypeA {
for _, xip := range *ips {
if ip := xip.To4(); ip != nil {
rr := new(dns.A)
rr.Hdr = dns.RR_Header{Name: question.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: ttl}
rr.A = ip
respMsg.Answer = append(respMsg.Answer, rr)
}
}
} else if question.Qtype == dns.TypeAAAA {
for _, xip := range *ips {
if xip.To4() == nil {
if ip := xip.To16(); ip != nil {
rr := new(dns.AAAA)
rr.Hdr = dns.RR_Header{Name: question.Name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: ttl}
rr.AAAA = ip
respMsg.Answer = append(respMsg.Answer, rr)
}
}
}
}
qType, ok := dns.TypeToString[question.Qtype]
if !ok {
qType = fmt.Sprint(question.Qtype)
}
dlog.Infof("Query for captive portal detection: [%v] (%v)", question.Name, qType)
return respMsg
}
func handleColdStartClient(clientPc *net.UDPConn, cancelChannel chan struct{}, ipsMap *CaptivePortalMap) bool {
buffer := make([]byte, MaxDNSPacketSize-1)
clientPc.SetDeadline(time.Now().Add(time.Duration(1) * time.Second))
length, clientAddr, err := clientPc.ReadFrom(buffer)
exit := false
select {
case <-cancelChannel:
exit = true
default:
}
if exit {
return true
}
if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
return false
}
if err != nil {
dlog.Warn(err)
return true
}
packet := buffer[:length]
msg := &dns.Msg{}
if err := msg.Unpack(packet); err != nil {
return false
}
question, ips := ipsMap.GetEntry(msg)
if ips == nil {
return false
}
respMsg := HandleCaptivePortalQuery(msg, question, ips)
if respMsg == nil {
return false
}
if response, err := respMsg.Pack(); err == nil {
clientPc.WriteTo(response, clientAddr)
}
return false
}
func addColdStartListener(
ipsMap *CaptivePortalMap,
listenAddrStr string,
captivePortalHandler *CaptivePortalHandler,
) error {
network := "udp"
isIPv4 := isDigit(listenAddrStr[0])
if isIPv4 {
network = "udp4"
}
listenUDPAddr, err := net.ResolveUDPAddr(network, listenAddrStr)
if err != nil {
return err
}
clientPc, err := net.ListenUDP(network, listenUDPAddr)
if err != nil {
return err
}
captivePortalHandler.wg.Add(1)
go func() {
for !handleColdStartClient(clientPc, captivePortalHandler.cancelChannel, ipsMap) {
}
clientPc.Close()
captivePortalHandler.wg.Done()
}()
return nil
}
func ColdStart(proxy *Proxy) (*CaptivePortalHandler, error) {
if len(proxy.captivePortalMapFile) == 0 {
return nil, nil
}
lines, err := ReadTextFile(proxy.captivePortalMapFile)
if err != nil {
dlog.Warn(err)
return nil, err
}
ipsMap := make(CaptivePortalMap)
for lineNo, line := range strings.Split(lines, "\n") {
line = TrimAndStripInlineComments(line)
if len(line) == 0 {
continue
}
name, ipsStr, ok := StringTwoFields(line)
if !ok {
return nil, fmt.Errorf(
"Syntax error for a captive portal rule at line %d",
1+lineNo,
)
}
name, err = NormalizeQName(name)
if err != nil {
continue
}
var ips []net.IP
for _, ip := range strings.Split(ipsStr, ",") {
ipStr := strings.TrimSpace(ip)
if ip := net.ParseIP(ipStr); ip != nil {
ips = append(ips, ip)
} else {
return nil, fmt.Errorf(
"Syntax error for a captive portal rule at line %d",
1+lineNo,
)
}
}
ipsMap[name] = ips
}
listenAddrStrs := proxy.listenAddresses
captivePortalHandler := CaptivePortalHandler{
cancelChannel: make(chan struct{}),
}
ok := false
for _, listenAddrStr := range listenAddrStrs {
err = addColdStartListener(&ipsMap, listenAddrStr, &captivePortalHandler)
if err == nil {
ok = true
}
}
if ok {
err = nil
}
proxy.captivePortalMap = &ipsMap
return &captivePortalHandler, err
}

View File

@ -4,14 +4,14 @@ import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io/ioutil"
"net"
"os"
"runtime"
"path"
"strconv"
"strings"
"unicode"
"github.com/jedisct1/dlog"
)
type CryptoConstruction uint16
@ -27,21 +27,26 @@ const (
)
const (
MaxHTTPBodyLength = 4000000
MaxHTTPBodyLength = 1000000
)
var (
CertMagic = [4]byte{0x44, 0x4e, 0x53, 0x43}
ServerMagic = [8]byte{0x72, 0x36, 0x66, 0x6e, 0x76, 0x57, 0x6a, 0x38}
MinDNSPacketSize = 12 + 5
MaxDNSPacketSize = 4096
MaxDNSUDPPacketSize = 1252
InitialMinQuestionSize = 256
CertMagic = [4]byte{0x44, 0x4e, 0x53, 0x43}
ServerMagic = [8]byte{0x72, 0x36, 0x66, 0x6e, 0x76, 0x57, 0x6a, 0x38}
MinDNSPacketSize = 12 + 5
MaxDNSPacketSize = 4096
MaxDNSUDPPacketSize = 4096
MaxDNSUDPSafePacketSize = 1252
InitialMinQuestionSize = 512
)
var (
FileDescriptors = make([]*os.File, 0)
FileDescriptorNum = 0
FileDescriptorNum = uintptr(0)
)
const (
InheritedDescriptorsBase = uintptr(50)
)
func PrefixWithSize(packet []byte) ([]byte, error) {
@ -93,20 +98,6 @@ func Max(a, b int) int {
return b
}
func MinF(a, b float64) float64 {
if a < b {
return a
}
return b
}
func MaxF(a, b float64) float64 {
if a > b {
return a
}
return b
}
func StringReverse(s string) string {
r := []rune(s)
for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
@ -123,7 +114,7 @@ func StringTwoFields(str string) (string, string, bool) {
if pos == -1 {
return "", "", false
}
a, b := strings.TrimFunc(str[:pos], unicode.IsSpace), strings.TrimFunc(str[pos+1:], unicode.IsSpace)
a, b := strings.TrimSpace(str[:pos]), strings.TrimSpace(str[pos+1:])
if len(a) == 0 || len(b) == 0 {
return a, b, false
}
@ -135,23 +126,25 @@ func StringQuote(str string) string {
return str[1 : len(str)-1]
}
func ExtractPort(str string, defaultPort int) int {
port := defaultPort
if idx := strings.LastIndex(str, ":"); idx >= 0 && idx < len(str)-1 {
if portX, err := strconv.Atoi(str[idx+1:]); err == nil {
port = portX
func StringStripSpaces(str string) string {
return strings.Map(func(r rune) rune {
if unicode.IsSpace(r) {
return -1
}
}
return port
return r
}, str)
}
func ExtractHost(str string) string {
if idx := strings.LastIndex(str, ":"); idx >= 0 && idx < len(str)-1 {
if _, err := strconv.Atoi(str[idx+1:]); err == nil {
str = str[:idx]
func TrimAndStripInlineComments(str string) string {
if idx := strings.LastIndexByte(str, '#'); idx >= 0 {
if idx == 0 || str[0] == '#' {
return ""
}
if prev := str[idx-1]; prev == ' ' || prev == '\t' {
str = str[:idx-1]
}
}
return str
return strings.TrimSpace(str)
}
func ExtractHostAndPort(str string, defaultPort int) (host string, port int) {
@ -164,20 +157,41 @@ func ExtractHostAndPort(str string, defaultPort int) (host string, port int) {
return
}
func MemUsage() {
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Printf("Alloc = %v MiB", m.Alloc/1024/1024)
fmt.Printf("\tTotalAlloc = %v MiB", m.TotalAlloc/1024/1024)
fmt.Printf("\tSys = %v MiB", m.Sys/1024/1024)
fmt.Printf("\tNumGC = %v\n", m.NumGC)
}
func ReadTextFile(filename string) (string, error) {
bin, err := ioutil.ReadFile(filename)
bin, err := os.ReadFile(filename)
if err != nil {
return "", err
}
bin = bytes.TrimPrefix(bin, []byte{0xef, 0xbb, 0xbf})
return string(bin), nil
}
func isDigit(b byte) bool { return b >= '0' && b <= '9' }
func maybeWritableByOtherUsers(p string) (bool, string, error) {
p = path.Clean(p)
for p != "/" && p != "." {
st, err := os.Stat(p)
if err != nil {
return false, p, err
}
mode := st.Mode()
if mode.Perm()&2 != 0 && !(st.IsDir() && mode&os.ModeSticky == os.ModeSticky) {
return true, p, nil
}
p = path.Dir(p)
}
return false, "", nil
}
func WarnIfMaybeWritableByOtherUsers(p string) {
if ok, px, err := maybeWritableByOtherUsers(p); ok {
if px == p {
dlog.Criticalf("[%s] is writable by other system users - If this is not intentional, it is recommended to fix the access permissions", p)
} else {
dlog.Warnf("[%s] can be modified by other system users because [%s] is writable by other users - If this is not intentional, it is recommended to fix the access permissions", p, px)
}
} else if err != nil {
dlog.Warnf("Error while checking if [%s] is accessible: [%s] : [%s]", p, px, err)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,6 @@ import (
crypto_rand "crypto/rand"
"crypto/sha512"
"errors"
"math/rand"
"github.com/jedisct1/dlog"
"github.com/jedisct1/xsecretbox"
@ -45,22 +44,43 @@ func unpad(packet []byte) ([]byte, error) {
}
}
func ComputeSharedKey(cryptoConstruction CryptoConstruction, secretKey *[32]byte, serverPk *[32]byte, providerName *string) (sharedKey [32]byte) {
func ComputeSharedKey(
cryptoConstruction CryptoConstruction,
secretKey *[32]byte,
serverPk *[32]byte,
providerName *string,
) (sharedKey [32]byte) {
if cryptoConstruction == XChacha20Poly1305 {
var err error
sharedKey, err = xsecretbox.SharedKey(*secretKey, *serverPk)
if err != nil {
dlog.Criticalf("[%v] Weak public key", providerName)
dlog.Criticalf("[%v] Weak XChaCha20 public key", providerName)
}
} else {
box.Precompute(&sharedKey, serverPk, secretKey)
c := byte(0)
for i := 0; i < 32; i++ {
c |= sharedKey[i]
}
if c == 0 {
dlog.Criticalf("[%v] Weak XSalsa20 public key", providerName)
if _, err := crypto_rand.Read(sharedKey[:]); err != nil {
dlog.Fatal(err)
}
}
}
return
}
func (proxy *Proxy) Encrypt(serverInfo *ServerInfo, packet []byte, proto string) (sharedKey *[32]byte, encrypted []byte, clientNonce []byte, err error) {
func (proxy *Proxy) Encrypt(
serverInfo *ServerInfo,
packet []byte,
proto string,
) (sharedKey *[32]byte, encrypted []byte, clientNonce []byte, err error) {
nonce, clientNonce := make([]byte, NonceSize), make([]byte, HalfNonceSize)
crypto_rand.Read(clientNonce)
if _, err := crypto_rand.Read(clientNonce); err != nil {
return nil, nil, nil, err
}
copy(nonce, clientNonce)
var publicKey *[PublicKeySize]byte
if proxy.ephemeralKeys {
@ -83,10 +103,17 @@ func (proxy *Proxy) Encrypt(serverInfo *ServerInfo, packet []byte, proto string)
minQuestionSize = Max(proxy.questionSizeEstimator.MinQuestionSize(), minQuestionSize)
} else {
var xpad [1]byte
rand.Read(xpad[:])
if _, err := crypto_rand.Read(xpad[:]); err != nil {
return nil, nil, nil, err
}
minQuestionSize += int(xpad[0])
}
paddedLength := Min(MaxDNSUDPPacketSize, (Max(minQuestionSize, QueryOverhead)+63) & ^63)
paddedLength := Min(MaxDNSUDPPacketSize, (Max(minQuestionSize, QueryOverhead)+1+63) & ^63)
if serverInfo.knownBugs.fragmentsBlocked && proto == "udp" {
paddedLength = MaxDNSUDPSafePacketSize
} else if serverInfo.Relay != nil && proto == "tcp" {
paddedLength = MaxDNSPacketSize
}
if QueryOverhead+len(packet)+1 > paddedLength {
err = errors.New("Question too large; cannot be padded")
return
@ -104,7 +131,12 @@ func (proxy *Proxy) Encrypt(serverInfo *ServerInfo, packet []byte, proto string)
return
}
func (proxy *Proxy) Decrypt(serverInfo *ServerInfo, sharedKey *[32]byte, encrypted []byte, nonce []byte) ([]byte, error) {
func (proxy *Proxy) Decrypt(
serverInfo *ServerInfo,
sharedKey *[32]byte,
encrypted []byte,
nonce []byte,
) ([]byte, error) {
serverMagicLen := len(ServerMagic)
responseHeaderLen := serverMagicLen + NonceSize
if len(encrypted) < responseHeaderLen+TagSize+int(MinDNSPacketSize) ||

View File

@ -20,40 +20,76 @@ type CertInfo struct {
ForwardSecurity bool
}
func FetchCurrentDNSCryptCert(proxy *Proxy, serverName *string, proto string, pk ed25519.PublicKey, serverAddress string, providerName string, isNew bool) (CertInfo, int, error) {
func FetchCurrentDNSCryptCert(
proxy *Proxy,
serverName *string,
proto string,
pk ed25519.PublicKey,
serverAddress string,
providerName string,
isNew bool,
relay *DNSCryptRelay,
knownBugs ServerBugs,
) (CertInfo, int, bool, error) {
if len(pk) != ed25519.PublicKeySize {
return CertInfo{}, 0, errors.New("Invalid public key length")
return CertInfo{}, 0, false, errors.New("Invalid public key length")
}
if !strings.HasSuffix(providerName, ".") {
providerName = providerName + "."
providerName += "."
}
if serverName == nil {
serverName = &providerName
}
query := new(dns.Msg)
query := dns.Msg{}
query.SetQuestion(providerName, dns.TypeTXT)
client := dns.Client{Net: proto, UDPSize: uint16(MaxDNSUDPPacketSize)}
in, rtt, err := client.Exchange(query, serverAddress)
if !strings.HasPrefix(providerName, "2.dnscrypt-cert.") {
if relay != nil && !proxy.anonDirectCertFallback {
dlog.Warnf(
"[%v] uses a non-standard provider name, enable direct cert fallback to use with a relay ('%v' doesn't start with '2.dnscrypt-cert.')",
*serverName,
providerName,
)
} else {
dlog.Warnf("[%v] uses a non-standard provider name ('%v' doesn't start with '2.dnscrypt-cert.')", *serverName, providerName)
relay = nil
}
}
tryFragmentsSupport := true
if knownBugs.fragmentsBlocked {
tryFragmentsSupport = false
}
in, rtt, fragmentsBlocked, err := DNSExchange(
proxy,
proto,
&query,
serverAddress,
relay,
serverName,
tryFragmentsSupport,
)
if err != nil {
dlog.Noticef("[%s] TIMEOUT", *serverName)
return CertInfo{}, 0, err
return CertInfo{}, 0, fragmentsBlocked, err
}
now := uint32(time.Now().Unix())
certInfo := CertInfo{CryptoConstruction: UndefinedConstruction}
highestSerial := uint32(0)
var certCountStr string
for _, answerRr := range in.Answer {
binCert, err := packTxtString(strings.Join(answerRr.(*dns.TXT).Txt, ""))
if err != nil {
dlog.Warnf("[%v] Unable to unpack the certificate", providerName)
var txt string
if t, ok := answerRr.(*dns.TXT); !ok {
dlog.Noticef("[%v] Extra record of type [%v] found in certificate", *serverName, answerRr.Header().Rrtype)
continue
} else {
txt = strings.Join(t.Txt, "")
}
binCert := PackTXTRR(txt)
if len(binCert) < 124 {
dlog.Warnf("[%v] Certificate too short", providerName)
dlog.Warnf("[%v] Certificate too short", *serverName)
continue
}
if !bytes.Equal(binCert[:4], CertMagic[:4]) {
dlog.Warnf("[%v] Invalid cert magic", providerName)
dlog.Warnf("[%v] Invalid cert magic", *serverName)
continue
}
cryptoConstruction := CryptoConstruction(0)
@ -63,32 +99,41 @@ func FetchCurrentDNSCryptCert(proxy *Proxy, serverName *string, proto string, pk
case 0x0002:
cryptoConstruction = XChacha20Poly1305
default:
dlog.Noticef("[%v] Unsupported crypto construction", providerName)
dlog.Noticef("[%v] Unsupported crypto construction", *serverName)
continue
}
signature := binCert[8:72]
signed := binCert[72:]
if !ed25519.Verify(pk, signed, signature) {
dlog.Warnf("[%v] Incorrect signature", providerName)
dlog.Warnf("[%v] Incorrect signature for provider name: [%v]", *serverName, providerName)
continue
}
serial := binary.BigEndian.Uint32(binCert[112:116])
tsBegin := binary.BigEndian.Uint32(binCert[116:120])
tsEnd := binary.BigEndian.Uint32(binCert[120:124])
if tsBegin >= tsEnd {
dlog.Warnf("[%v] certificate ends before it starts (%v >= %v)", providerName, tsBegin, tsEnd)
dlog.Warnf("[%v] certificate ends before it starts (%v >= %v)", *serverName, tsBegin, tsEnd)
continue
}
ttl := tsEnd - tsBegin
if ttl > 86400*7 {
dlog.Infof("[%v] the key validity period for this server is excessively long (%d days), significantly reducing reliability and forward security.", providerName, ttl/86400)
dlog.Infof(
"[%v] the key validity period for this server is excessively long (%d days), significantly reducing reliability and forward security.",
*serverName,
ttl/86400,
)
daysLeft := (tsEnd - now) / 86400
if daysLeft < 1 {
dlog.Criticalf("[%v] certificate will expire today -- Switch to a different resolver as soon as possible", providerName)
dlog.Criticalf(
"[%v] certificate will expire today -- Switch to a different resolver as soon as possible",
*serverName,
)
} else if daysLeft <= 7 {
dlog.Warnf("[%v] certificate is about to expire -- if you don't manage this server, tell the server operator about it", providerName)
dlog.Warnf("[%v] certificate is about to expire -- if you don't manage this server, tell the server operator about it", *serverName)
} else if daysLeft <= 30 {
dlog.Infof("[%v] certificate will expire in %d days", providerName, daysLeft)
dlog.Infof("[%v] certificate will expire in %d days", *serverName, daysLeft)
} else {
dlog.Debugf("[%v] certificate still valid for %d days", *serverName, daysLeft)
}
certInfo.ForwardSecurity = false
} else {
@ -96,24 +141,30 @@ func FetchCurrentDNSCryptCert(proxy *Proxy, serverName *string, proto string, pk
}
if !proxy.certIgnoreTimestamp {
if now > tsEnd || now < tsBegin {
dlog.Debugf("[%v] Certificate not valid at the current date", providerName)
dlog.Debugf(
"[%v] Certificate not valid at the current date (now: %v is not in [%v..%v])",
*serverName,
now,
tsBegin,
tsEnd,
)
continue
}
}
if serial < highestSerial {
dlog.Debugf("[%v] Superseded by a previous certificate", providerName)
dlog.Debugf("[%v] Superseded by a previous certificate", *serverName)
continue
}
if serial == highestSerial {
if cryptoConstruction < certInfo.CryptoConstruction {
dlog.Debugf("[%v] Keeping the previous, preferred crypto construction", providerName)
dlog.Debugf("[%v] Keeping the previous, preferred crypto construction", *serverName)
continue
} else {
dlog.Debugf("[%v] Upgrading the construction from %v to %v", providerName, certInfo.CryptoConstruction, cryptoConstruction)
dlog.Debugf("[%v] Upgrading the construction from %v to %v", *serverName, certInfo.CryptoConstruction, cryptoConstruction)
}
}
if cryptoConstruction != XChacha20Poly1305 && cryptoConstruction != XSalsa20Poly1305 {
dlog.Noticef("[%v] Cryptographic construction %v not supported", providerName, cryptoConstruction)
dlog.Noticef("[%v] Cryptographic construction %v not supported", *serverName, cryptoConstruction)
continue
}
var serverPk [32]byte
@ -132,42 +183,7 @@ func FetchCurrentDNSCryptCert(proxy *Proxy, serverName *string, proto string, pk
certCountStr = " - additional certificate"
}
if certInfo.CryptoConstruction == UndefinedConstruction {
return certInfo, 0, errors.New("No useable certificate found")
return certInfo, 0, fragmentsBlocked, errors.New("No usable certificate found")
}
return certInfo, int(rtt.Nanoseconds() / 1000000), nil
}
func isDigit(b byte) bool { return b >= '0' && b <= '9' }
func dddToByte(s []byte) byte {
return byte((s[0]-'0')*100 + (s[1]-'0')*10 + (s[2] - '0'))
}
func packTxtString(s string) ([]byte, error) {
bs := make([]byte, len(s))
msg := make([]byte, 0)
copy(bs, s)
for i := 0; i < len(bs); i++ {
if bs[i] == '\\' {
i++
if i == len(bs) {
break
}
if i+2 < len(bs) && isDigit(bs[i]) && isDigit(bs[i+1]) && isDigit(bs[i+2]) {
msg = append(msg, dddToByte(bs[i:]))
i += 2
} else if bs[i] == 't' {
msg = append(msg, '\t')
} else if bs[i] == 'r' {
msg = append(msg, '\r')
} else if bs[i] == 'n' {
msg = append(msg, '\n')
} else {
msg = append(msg, bs[i])
}
} else {
msg = append(msg, bs[i])
}
}
return msg, nil
return certInfo, int(rtt.Nanoseconds() / 1000000), fragmentsBlocked, nil
}

View File

@ -2,55 +2,95 @@ package main
import (
"encoding/binary"
"errors"
"net"
"strings"
"time"
"unicode/utf8"
"github.com/jedisct1/dlog"
"github.com/miekg/dns"
)
func EmptyResponseFromMessage(srcMsg *dns.Msg) *dns.Msg {
dstMsg := dns.Msg{MsgHdr: srcMsg.MsgHdr, Compress: true}
dstMsg.Question = srcMsg.Question
dstMsg.Response = true
if srcMsg.RecursionDesired {
dstMsg.RecursionAvailable = true
}
dstMsg.RecursionDesired = false
dstMsg.CheckingDisabled = false
dstMsg.AuthenticatedData = false
if edns0 := srcMsg.IsEdns0(); edns0 != nil {
dstMsg.SetEdns0(edns0.UDPSize(), edns0.Do())
}
return &dstMsg
}
func TruncatedResponse(packet []byte) ([]byte, error) {
srcMsg := new(dns.Msg)
srcMsg := dns.Msg{}
if err := srcMsg.Unpack(packet); err != nil {
return nil, err
}
dstMsg := srcMsg
dstMsg.Response = true
dstMsg.Answer = make([]dns.RR, 0)
dstMsg.Ns = make([]dns.RR, 0)
dstMsg.Extra = make([]dns.RR, 0)
dstMsg := EmptyResponseFromMessage(&srcMsg)
dstMsg.Truncated = true
return dstMsg.Pack()
}
func EmptyResponseFromMessage(srcMsg *dns.Msg) (*dns.Msg, error) {
dstMsg := srcMsg
dstMsg.Response = true
dstMsg.Answer = make([]dns.RR, 0)
dstMsg.Ns = make([]dns.RR, 0)
dstMsg.Extra = make([]dns.RR, 0)
return dstMsg, nil
}
func RefusedResponseFromMessage(srcMsg *dns.Msg, refusedCode bool) (*dns.Msg, error) {
dstMsg, err := EmptyResponseFromMessage(srcMsg)
if err != nil {
return dstMsg, err
func RefusedResponseFromMessage(srcMsg *dns.Msg, refusedCode bool, ipv4 net.IP, ipv6 net.IP, ttl uint32) *dns.Msg {
dstMsg := EmptyResponseFromMessage(srcMsg)
ede := new(dns.EDNS0_EDE)
if edns0 := dstMsg.IsEdns0(); edns0 != nil {
edns0.Option = append(edns0.Option, ede)
}
ede.InfoCode = dns.ExtendedErrorCodeFiltered
if refusedCode {
dstMsg.Rcode = dns.RcodeRefused
} else {
dstMsg.Rcode = dns.RcodeSuccess
questions := srcMsg.Question
if len(questions) > 0 {
if len(questions) == 0 {
return dstMsg
}
question := questions[0]
sendHInfoResponse := true
if ipv4 != nil && question.Qtype == dns.TypeA {
rr := new(dns.A)
rr.Hdr = dns.RR_Header{Name: question.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: ttl}
rr.A = ipv4.To4()
if rr.A != nil {
dstMsg.Answer = []dns.RR{rr}
sendHInfoResponse = false
ede.InfoCode = dns.ExtendedErrorCodeForgedAnswer
}
} else if ipv6 != nil && question.Qtype == dns.TypeAAAA {
rr := new(dns.AAAA)
rr.Hdr = dns.RR_Header{Name: question.Name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: ttl}
rr.AAAA = ipv6.To16()
if rr.AAAA != nil {
dstMsg.Answer = []dns.RR{rr}
sendHInfoResponse = false
ede.InfoCode = dns.ExtendedErrorCodeForgedAnswer
}
}
if sendHInfoResponse {
hinfo := new(dns.HINFO)
hinfo.Hdr = dns.RR_Header{Name: questions[0].Name, Rrtype: dns.TypeHINFO,
Class: dns.ClassINET, Ttl: 1}
hinfo.Hdr = dns.RR_Header{
Name: question.Name, Rrtype: dns.TypeHINFO,
Class: dns.ClassINET, Ttl: ttl,
}
hinfo.Cpu = "This query has been locally blocked"
hinfo.Os = "by dnscrypt-proxy"
dstMsg.Answer = []dns.RR{hinfo}
} else {
ede.ExtraText = "This query has been locally blocked by dnscrypt-proxy"
}
}
return dstMsg, nil
return dstMsg
}
func HasTCFlag(packet []byte) bool {
@ -69,7 +109,7 @@ func Rcode(packet []byte) uint8 {
return packet[3] & 0xf
}
func NormalizeName(name *[]byte) {
func NormalizeRawQName(name *[]byte) {
for i, c := range *name {
if c >= 65 && c <= 90 {
(*name)[i] = c + 32
@ -77,15 +117,38 @@ func NormalizeName(name *[]byte) {
}
}
func StripTrailingDot(str string) string {
if len(str) > 1 && strings.HasSuffix(str, ".") {
str = str[:len(str)-1]
func NormalizeQName(str string) (string, error) {
if len(str) == 0 || str == "." {
return ".", nil
}
return str
hasUpper := false
str = strings.TrimSuffix(str, ".")
strLen := len(str)
for i := 0; i < strLen; i++ {
c := str[i]
if c >= utf8.RuneSelf {
return str, errors.New("Query name is not an ASCII string")
}
hasUpper = hasUpper || ('A' <= c && c <= 'Z')
}
if !hasUpper {
return str, nil
}
var b strings.Builder
b.Grow(len(str))
for i := 0; i < strLen; i++ {
c := str[i]
if 'A' <= c && c <= 'Z' {
c += 'a' - 'A'
}
b.WriteByte(c)
}
return b.String(), nil
}
func getMinTTL(msg *dns.Msg, minTTL uint32, maxTTL uint32, cacheNegMinTTL uint32, cacheNegMaxTTL uint32) time.Duration {
if (msg.Rcode != dns.RcodeSuccess && msg.Rcode != dns.RcodeNameError) || (len(msg.Answer) <= 0 && len(msg.Ns) <= 0) {
if (msg.Rcode != dns.RcodeSuccess && msg.Rcode != dns.RcodeNameError) ||
(len(msg.Answer) <= 0 && len(msg.Ns) <= 0) {
return time.Duration(cacheNegMinTTL) * time.Second
}
var ttl uint32
@ -142,8 +205,14 @@ func setMaxTTL(msg *dns.Msg, ttl uint32) {
}
func updateTTL(msg *dns.Msg, expiration time.Time) {
ttl := uint32(time.Until(expiration) / time.Second)
until := time.Until(expiration)
ttl := uint32(0)
if until > 0 {
ttl = uint32(until / time.Second)
if until-time.Duration(ttl)*time.Second >= time.Second/2 {
ttl += 1
}
}
for _, rr := range msg.Answer {
rr.Header().Ttl = ttl
}
@ -151,10 +220,291 @@ func updateTTL(msg *dns.Msg, expiration time.Time) {
rr.Header().Ttl = ttl
}
for _, rr := range msg.Extra {
header := rr.Header()
if header.Rrtype == dns.TypeOPT {
continue
if rr.Header().Rrtype != dns.TypeOPT {
rr.Header().Ttl = ttl
}
rr.Header().Ttl = ttl
}
}
func hasEDNS0Padding(packet []byte) (bool, error) {
msg := dns.Msg{}
if err := msg.Unpack(packet); err != nil {
return false, err
}
if edns0 := msg.IsEdns0(); edns0 != nil {
for _, option := range edns0.Option {
if option.Option() == dns.EDNS0PADDING {
return true, nil
}
}
}
return false, nil
}
func addEDNS0PaddingIfNoneFound(msg *dns.Msg, unpaddedPacket []byte, paddingLen int) ([]byte, error) {
edns0 := msg.IsEdns0()
if edns0 == nil {
msg.SetEdns0(uint16(MaxDNSPacketSize), false)
edns0 = msg.IsEdns0()
if edns0 == nil {
return unpaddedPacket, nil
}
}
for _, option := range edns0.Option {
if option.Option() == dns.EDNS0PADDING {
return unpaddedPacket, nil
}
}
ext := new(dns.EDNS0_PADDING)
padding := make([]byte, paddingLen)
for i := range padding {
padding[i] = 'X'
}
ext.Padding = padding[:paddingLen]
edns0.Option = append(edns0.Option, ext)
return msg.Pack()
}
func removeEDNS0Options(msg *dns.Msg) bool {
edns0 := msg.IsEdns0()
if edns0 == nil {
return false
}
edns0.Option = []dns.EDNS0{}
return true
}
func dddToByte(s []byte) byte {
return byte((s[0]-'0')*100 + (s[1]-'0')*10 + (s[2] - '0'))
}
func PackTXTRR(s string) []byte {
bs := make([]byte, len(s))
msg := make([]byte, 0)
copy(bs, s)
for i := 0; i < len(bs); i++ {
if bs[i] == '\\' {
i++
if i == len(bs) {
break
}
if i+2 < len(bs) && isDigit(bs[i]) && isDigit(bs[i+1]) && isDigit(bs[i+2]) {
msg = append(msg, dddToByte(bs[i:]))
i += 2
} else if bs[i] == 't' {
msg = append(msg, '\t')
} else if bs[i] == 'r' {
msg = append(msg, '\r')
} else if bs[i] == 'n' {
msg = append(msg, '\n')
} else {
msg = append(msg, bs[i])
}
} else {
msg = append(msg, bs[i])
}
}
return msg
}
type DNSExchangeResponse struct {
response *dns.Msg
rtt time.Duration
priority int
fragmentsBlocked bool
err error
}
func DNSExchange(
proxy *Proxy,
proto string,
query *dns.Msg,
serverAddress string,
relay *DNSCryptRelay,
serverName *string,
tryFragmentsSupport bool,
) (*dns.Msg, time.Duration, bool, error) {
for {
cancelChannel := make(chan struct{})
maxTries := 3
channel := make(chan DNSExchangeResponse, 2*maxTries)
var err error
options := 0
for tries := 0; tries < maxTries; tries++ {
if tryFragmentsSupport {
queryCopy := query.Copy()
queryCopy.Id += uint16(options)
go func(query *dns.Msg, delay time.Duration) {
time.Sleep(delay)
option := DNSExchangeResponse{err: errors.New("Canceled")}
select {
case <-cancelChannel:
default:
option = _dnsExchange(proxy, proto, query, serverAddress, relay, 1500)
}
option.fragmentsBlocked = false
option.priority = 0
channel <- option
}(queryCopy, time.Duration(200*tries)*time.Millisecond)
options++
}
queryCopy := query.Copy()
queryCopy.Id += uint16(options)
go func(query *dns.Msg, delay time.Duration) {
time.Sleep(delay)
option := DNSExchangeResponse{err: errors.New("Canceled")}
select {
case <-cancelChannel:
default:
option = _dnsExchange(proxy, proto, query, serverAddress, relay, 480)
}
option.fragmentsBlocked = true
option.priority = 1
channel <- option
}(queryCopy, time.Duration(250*tries)*time.Millisecond)
options++
}
var bestOption *DNSExchangeResponse
for i := 0; i < options; i++ {
if dnsExchangeResponse := <-channel; dnsExchangeResponse.err == nil {
if bestOption == nil || dnsExchangeResponse.priority < bestOption.priority ||
(dnsExchangeResponse.priority == bestOption.priority && dnsExchangeResponse.rtt < bestOption.rtt) {
bestOption = &dnsExchangeResponse
if bestOption.priority == 0 {
close(cancelChannel)
break
}
}
} else {
err = dnsExchangeResponse.err
}
}
if bestOption != nil {
if bestOption.fragmentsBlocked {
dlog.Debugf("[%v] public key retrieval succeeded but server is blocking fragments", *serverName)
} else {
dlog.Debugf("[%v] public key retrieval succeeded", *serverName)
}
return bestOption.response, bestOption.rtt, bestOption.fragmentsBlocked, nil
}
if relay == nil || !proxy.anonDirectCertFallback {
if err == nil {
err = errors.New("Unable to reach the server")
}
return nil, 0, false, err
}
dlog.Infof(
"Unable to get the public key for [%v] via relay [%v], retrying over a direct connection",
*serverName,
relay.RelayUDPAddr.IP,
)
relay = nil
}
}
func _dnsExchange(
proxy *Proxy,
proto string,
query *dns.Msg,
serverAddress string,
relay *DNSCryptRelay,
paddedLen int,
) DNSExchangeResponse {
var packet []byte
var rtt time.Duration
if proto == "udp" {
qNameLen, padding := len(query.Question[0].Name), 0
if qNameLen < paddedLen {
padding = paddedLen - qNameLen
}
if padding > 0 {
opt := new(dns.OPT)
opt.Hdr.Name = "."
ext := new(dns.EDNS0_PADDING)
ext.Padding = make([]byte, padding)
opt.Option = append(opt.Option, ext)
query.Extra = []dns.RR{opt}
}
binQuery, err := query.Pack()
if err != nil {
return DNSExchangeResponse{err: err}
}
udpAddr, err := net.ResolveUDPAddr("udp", serverAddress)
if err != nil {
return DNSExchangeResponse{err: err}
}
upstreamAddr := udpAddr
if relay != nil {
proxy.prepareForRelay(udpAddr.IP, udpAddr.Port, &binQuery)
upstreamAddr = relay.RelayUDPAddr
}
now := time.Now()
pc, err := net.DialUDP("udp", nil, upstreamAddr)
if err != nil {
return DNSExchangeResponse{err: err}
}
defer pc.Close()
if err := pc.SetDeadline(time.Now().Add(proxy.timeout)); err != nil {
return DNSExchangeResponse{err: err}
}
if _, err := pc.Write(binQuery); err != nil {
return DNSExchangeResponse{err: err}
}
packet = make([]byte, MaxDNSPacketSize)
length, err := pc.Read(packet)
if err != nil {
return DNSExchangeResponse{err: err}
}
rtt = time.Since(now)
packet = packet[:length]
} else {
binQuery, err := query.Pack()
if err != nil {
return DNSExchangeResponse{err: err}
}
tcpAddr, err := net.ResolveTCPAddr("tcp", serverAddress)
if err != nil {
return DNSExchangeResponse{err: err}
}
upstreamAddr := tcpAddr
if relay != nil {
proxy.prepareForRelay(tcpAddr.IP, tcpAddr.Port, &binQuery)
upstreamAddr = relay.RelayTCPAddr
}
now := time.Now()
var pc net.Conn
proxyDialer := proxy.xTransport.proxyDialer
if proxyDialer == nil {
pc, err = net.DialTCP("tcp", nil, upstreamAddr)
} else {
pc, err = (*proxyDialer).Dial("tcp", tcpAddr.String())
}
if err != nil {
return DNSExchangeResponse{err: err}
}
defer pc.Close()
if err := pc.SetDeadline(time.Now().Add(proxy.timeout)); err != nil {
return DNSExchangeResponse{err: err}
}
binQuery, err = PrefixWithSize(binQuery)
if err != nil {
return DNSExchangeResponse{err: err}
}
if _, err := pc.Write(binQuery); err != nil {
return DNSExchangeResponse{err: err}
}
packet, err = ReadPrefixed(&pc)
if err != nil {
return DNSExchangeResponse{err: err}
}
rtt = time.Since(now)
}
msg := dns.Msg{}
if err := msg.Unpack(packet); err != nil {
return DNSExchangeResponse{err: err}
}
return DNSExchangeResponse{response: &msg, rtt: rtt, err: nil}
}

View File

@ -6,10 +6,6 @@ import (
"github.com/VividCortex/ewma"
)
const (
SizeEstimatorEwmaDecay = 100.0
)
type QuestionSizeEstimator struct {
sync.RWMutex
minQuestionSize int
@ -17,7 +13,10 @@ type QuestionSizeEstimator struct {
}
func NewQuestionSizeEstimator() QuestionSizeEstimator {
return QuestionSizeEstimator{minQuestionSize: InitialMinQuestionSize, ewma: ewma.NewMovingAverage(SizeEstimatorEwmaDecay)}
return QuestionSizeEstimator{
minQuestionSize: InitialMinQuestionSize,
ewma: &ewma.SimpleEWMA{},
}
}
func (questionSizeEstimator *QuestionSizeEstimator) MinQuestionSize() int {

View File

@ -0,0 +1,7 @@
##############################
# Allowed IPs List #
##############################
#192.168.0.*
#fe80:53:* # IPv6 prefix example
#81.169.145.105

View File

@ -0,0 +1,31 @@
###########################
# Allowlist #
###########################
## Rules for allowing queries based on name, one per line
##
## Example of valid patterns:
##
## ads.* | matches anything with an "ads." prefix
## *.example.com | matches example.com and all names within that zone such as www.example.com
## example.com | identical to the above
## =example.com | allows example.com but not *.example.com
## *sex* | matches any name containing that substring
## ads[0-9]* | matches "ads" followed by one or more digits
## ads*.example* | *, ? and [] can be used anywhere, but prefixes/suffixes are faster
# That one may be blocked due to 'tracker' being in the name.
tracker.debian.org
# That one may be blocked due to 'ads' being in the name.
# However, blocking it prevents all sponsored links from the Google
# search engine from being opened.
googleadservices.com
## Time-based rules
# *.youtube.* @time-to-play
# facebook.com @play

View File

@ -1,38 +0,0 @@
###########################
# Blacklist #
###########################
## Rules for name-based query blocking, one per line
##
## Example of valid patterns:
##
## ads.* | matches anything with an "ads." prefix
## *.example.com | matches example.com and all names within that zone such as www.example.com
## example.com | identical to the above
## =example.com | block example.com but not *.example.com
## *sex* | matches any name containing that substring
## ads[0-9]* | matches "ads" followed by one or more digits
## ads*.example* | *, ? and [] can be used anywhere, but prefixes/suffixes are faster
ad.*
ads.*
banner.*
banners.*
creatives.*
oas.*
oascentral.*
stats.*
tag.*
telemetry.*
tracker.*
*.local
eth0.me
*.workgroup
## Time-based rules
# *.youtube.* @time-to-sleep
# facebook.com @work

View File

@ -0,0 +1,16 @@
##############################
# IP blocklist #
##############################
## Rules for IP-based response blocking
##
## Sample feeds of suspect IP addresses:
## - https://github.com/stamparm/ipsum
## - https://github.com/tg12/bad_packets_blocklist
## - https://isc.sans.edu/block.txt
## - https://block.energized.pro/extensions/ips/formats/list.txt
## - https://www.iblocklist.com/lists
163.5.1.4
94.46.118.*
fe80:53:* # IPv6 prefix example

View File

@ -0,0 +1,45 @@
###########################
# Blocklist #
###########################
## Rules for name-based query blocking, one per line
##
## Example of valid patterns:
##
## ads.* | matches anything with an "ads." prefix
## *.example.com | matches example.com and all names within that zone such as www.example.com
## example.com | identical to the above
## =example.com | block example.com but not *.example.com
## *sex* | matches any name containing that substring
## ads[0-9]* | matches "ads" followed by one or more digits
## ads*.example* | *, ? and [] can be used anywhere, but prefixes/suffixes are faster
ad.*
ads.*
banner.*
banners.*
creatives.*
oas.*
oascentral.* # inline comments are allowed after a pound sign
stats.*
tag.*
telemetry.*
tracker.*
*.local
eth0.me
*.workgroup
## Prevent usage of Apple private relay, that bypasses DNS
# mask.apple-dns.net
# mask.icloud.com
# mask-api.icloud.com
# doh.dns.apple.com
## Time-based rules
# *.youtube.* @time-to-sleep
# facebook.com @work

View File

@ -0,0 +1,27 @@
###########################################
# Captive portal test names #
###########################################
## Some operating systems send queries to these names after a network change,
## in order to check if connectivity beyond the router is possible without
## going through a captive portal.
##
## This is a list of hard-coded IP addresses that will be returned when queries
## for these names are received, even before the operating system reports an interface
## as usable for reaching the Internet.
##
## Note that IPv6 addresses don't need to be specified within brackets,
## as there are no port numbers.
captive.apple.com 17.253.109.201, 17.253.113.202
connectivitycheck.gstatic.com 64.233.162.94, 64.233.164.94, 64.233.165.94, 64.233.177.94, 64.233.185.94, 74.125.132.94, 74.125.136.94, 74.125.20.94, 74.125.21.94, 74.125.28.94
connectivitycheck.android.com 64.233.162.100, 64.233.162.101, 64.233.162.102, 64.233.162.113, 64.233.162.138, 64.233.162.139
www.msftncsi.com 2.16.106.89, 2.16.106.91, 23.0.175.137, 23.0.175.146, 23.192.47.155, 23.192.47.203, 23.199.63.160, 23.199.63.184, 23.199.63.208, 23.204.146.160, 23.204.146.163, 23.46.238.243, 23.46.239.24, 23.48.39.16, 23.48.39.48, 23.55.38.139, 23.55.38.146, 23.59.190.185, 23.59.190.195
dns.msftncsi.com 131.107.255.255, fd3e:4f5a:5b81::1
www.msftconnecttest.com 13.107.4.52
ipv6.msftconnecttest.com 2a01:111:2003::52
ipv4only.arpa 192.0.0.170, 192.0.0.171
## Adding IP addresses of NTP servers is also a good idea
time.google.com 216.239.35.0, 2001:4860:4806::

View File

@ -13,7 +13,9 @@ www.google.* forcesafesearch.google.com
www.bing.com strict.bing.com
yandex.ru familysearch.yandex.ru
yandex.ru familysearch.yandex.ru # inline comments are allowed after a pound sign
=duckduckgo.com safe.duckduckgo.com
www.youtube.com restrictmoderate.youtube.com
m.youtube.com restrictmoderate.youtube.com
@ -21,5 +23,22 @@ youtubei.googleapis.com restrictmoderate.youtube.com
youtube.googleapis.com restrictmoderate.youtube.com
www.youtube-nocookie.com restrictmoderate.youtube.com
# Multiple IP entries for the same name are supported.
# In the following example, the same name maps both to IPv4 and IPv6 addresses:
localhost 127.0.0.1
localhost ::1
# For load-balancing, multiple IP addresses of the same class can also be
# provided using the same format, one <pattern> <ip> pair per line.
# ads.* 192.168.100.1
# ads.* 192.168.100.2
# ads.* ::1
# PTR records can be created by setting cloak_ptr in the main configuration file
# Entries with wild cards will not have PTR records created, but multiple
# names for the same IP are supported
# example.com 192.168.100.1
# my.example.com 192.168.100.1

View File

@ -21,19 +21,25 @@
## Servers from the "public-resolvers" source (see down below) can
## be viewed here: https://dnscrypt.info/public-servers
##
## If this line is commented, all registered servers matching the require_* filters
## will be used.
## The proxy will automatically pick working servers from this list.
## Note that the require_* filters do NOT apply when using this setting.
##
## By default, this list is empty and all registered servers matching the
## require_* filters will be used instead.
##
## The proxy will automatically pick the fastest, working servers from the list.
## Remove the leading # first to enable this; lines starting with # are ignored.
# server_names = ['scaleway-fr', 'google', 'yandex', 'cloudflare']
## List of local addresses and ports to listen to. Can be IPv4 and/or IPv6.
## Note: When using systemd socket activation, choose an empty set (i.e. [] ).
## Example with both IPv4 and IPv6:
## listen_addresses = ['127.0.0.1:53', '[::1]:53']
##
## To listen to all IPv4 addresses, use `listen_addresses = ['0.0.0.0:53']`
## To listen to all IPv4+IPv6 addresses, use `listen_addresses = ['[::]:53']`
listen_addresses = ['127.0.0.1:53', '[::1]:53']
listen_addresses = ['127.0.0.1:53']
## Maximum number of simultaneous client connections to accept
@ -49,7 +55,7 @@ max_clients = 250
# user_name = 'nobody'
## Require servers (from static + remote sources) to satisfy specific properties
## Require servers (from remote sources) to satisfy specific properties
# Use servers reachable over IPv4
ipv4_servers = true
@ -63,6 +69,9 @@ dnscrypt_servers = true
# Use servers implementing the DNS-over-HTTPS protocol
doh_servers = true
# Use servers implementing the Oblivious DoH protocol
odoh_servers = false
## Require servers defined by remote sources to satisfy specific properties
@ -72,7 +81,7 @@ require_dnssec = false
# Server must not log user queries (declarative)
require_nolog = true
# Server must not enforce its own blacklist (for parental control, ads blocking...)
# Server must not enforce its own blocklist (for parental control, ads blocking...)
require_nofilter = true
# Server names to avoid even if they match all criteria
@ -88,42 +97,64 @@ disabled_server_names = []
force_tcp = false
## Enable *experimental* support for HTTP/3 (DoH3, HTTP over QUIC)
## Note that, like DNSCrypt but unlike other HTTP versions, this uses
## UDP and (usually) port 443 instead of TCP.
http3 = false
## SOCKS proxy
## Uncomment the following line to route all TCP connections to a local Tor node
## Tor doesn't support UDP, so set `force_tcp` to `true` as well.
# proxy = "socks5://127.0.0.1:9050"
# proxy = 'socks5://127.0.0.1:9050'
## HTTP/HTTPS proxy
## Only for DoH servers
# http_proxy = "http://127.0.0.1:8888"
# http_proxy = 'http://127.0.0.1:8888'
## How long a DNS query will wait for a response, in milliseconds
## How long a DNS query will wait for a response, in milliseconds.
## If you have a network with *a lot* of latency, you may need to
## increase this. Startup may be slower if you do so.
## Don't increase it too much. 10000 is the highest reasonable value.
timeout = 2500
timeout = 5000
## Keepalive for HTTP (HTTPS, HTTP/2) queries, in seconds
## Keepalive for HTTP (HTTPS, HTTP/2, HTTP/3) queries, in seconds
keepalive = 30
## Use the REFUSED return code for blocked responses
## Setting this to `false` means that some responses will be lies.
## Unfortunately, `false` appears to be required for Android 8+
## Add EDNS-client-subnet information to outgoing queries
##
## Multiple networks can be listed; they will be randomly chosen.
## These networks don't have to match your actual networks.
refused_code_in_responses = false
# edns_client_subnet = ['0.0.0.0/0', '2001:db8::/32']
## Load-balancing strategy: 'p2' (default), 'ph', 'first' or 'random'
## Response for blocked queries. Options are `refused`, `hinfo` (default) or
## an IP response. To give an IP response, use the format `a:<IPv4>,aaaa:<IPv6>`.
## Using the `hinfo` option means that some responses will be lies.
## Unfortunately, the `hinfo` option appears to be required for Android 8+
# blocked_query_response = 'refused'
## Load-balancing strategy: 'p2' (default), 'ph', 'p<n>', 'first' or 'random'
## Randomly choose 1 of the fastest 2, half, n, 1 or all live servers by latency.
## The response quality still depends on the server itself.
# lb_strategy = 'p2'
## Set to `true` to constantly try to estimate the latency of all the resolvers
## and adjust the load-balancing parameters accordingly, or to `false` to disable.
## Default is `true` that makes 'p2' `lb_strategy` work well.
# lb_estimator = true
@ -133,21 +164,43 @@ refused_code_in_responses = false
# log_level = 2
## log file for the application
## Log file for the application, as an alternative to sending logs to
## the standard system logging service (syslog/Windows event log).
##
## This file is different from other log files, and will not be
## automatically rotated by the application.
# log_file = 'dnscrypt-proxy.log'
## When using a log file, only keep logs from the most recent launch.
# log_file_latest = true
## Use the system logger (syslog on Unix, Event Log on Windows)
# use_syslog = true
## The maximum concurrency to reload certificates from the resolvers.
## Default is 10.
# cert_refresh_concurrency = 10
## Delay, in minutes, after which certificates are reloaded
cert_refresh_delay = 240
## Initially don't check DNSCrypt server certificates for expiration, and
## only start checking them after a first successful connection to a resolver.
## This can be useful on routers with no battery-backed clock.
# cert_ignore_timestamp = false
## DNSCrypt: Create a new, unique key for every single DNS query
## This may improve privacy but can also have a significant impact on CPU usage
## Only enable if you don't have a lot of network load
@ -160,7 +213,7 @@ cert_refresh_delay = 240
# tls_disable_session_tickets = false
## DoH: Use a specific cipher suite instead of the server preference
## DoH: Use TLS 1.2 and specific cipher suite instead of the server preference
## 49199 = TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
## 49195 = TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
## 52392 = TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
@ -171,39 +224,72 @@ cert_refresh_delay = 240
## This may also help on Intel CPUs running 32-bit operating systems.
##
## Keep tls_cipher_suite empty if you have issues fetching sources or
## connecting to some DoH servers. Google and Cloudflare are fine with it.
## connecting to some DoH servers.
# tls_cipher_suite = [52392, 49199]
## Fallback resolver
## This is a normal, non-encrypted DNS resolver, that will be only used
## for one-shot queries when retrieving the initial resolvers list, and
## only if the system DNS configuration doesn't work.
## No user application queries will ever be leaked through this resolver,
## and it will not be used after IP addresses of resolvers URLs have been found.
## It will never be used if lists have already been cached, and if stamps
## don't include host names without IP addresses.
## It will not be used if the configured system DNS works.
## A resolver supporting DNSSEC is recommended. This may become mandatory.
## Log TLS key material to a file, for debugging purposes only.
## This file will contain the TLS master key, which can be used to decrypt
## all TLS traffic to/from DoH servers.
## Never ever enable except for debugging purposes with a tool such as mitmproxy.
# tls_key_log_file = '/tmp/keylog.txt'
## Bootstrap resolvers
##
## People in China may need to use 114.114.114.114:53 here.
## Other popular options include 8.8.8.8 and 1.1.1.1.
## These are normal, non-encrypted DNS resolvers, that will be only used
## for one-shot queries when retrieving the initial resolvers list and if
## the system DNS configuration doesn't work.
##
## No user queries will ever be leaked through these resolvers, and they will
## not be used after IP addresses of DoH resolvers have been found (if you are
## using DoH).
##
## They will never be used if lists have already been cached, and if the stamps
## of the configured servers already include IP addresses (which is the case for
## most of DoH servers, and for all DNSCrypt servers and relays).
##
## They will not be used if the configured system DNS works, or after the
## proxy already has at least one usable secure resolver.
##
## Resolvers supporting DNSSEC are recommended, and, if you are using
## DoH, bootstrap resolvers should ideally be operated by a different entity
## than the DoH servers you will be using, especially if you have IPv6 enabled.
##
## People in China may want to use 114.114.114.114:53 here.
## Other popular options include 8.8.8.8, 9.9.9.9 and 1.1.1.1.
##
## If more than one resolver is specified, they will be tried in sequence.
##
## TL;DR: put valid standard resolver addresses here. Your actual queries will
## not be sent there. If you're using DNSCrypt or Anonymized DNS and your
## lists are up to date, these resolvers will not even be used.
fallback_resolver = '9.9.9.9:53'
bootstrap_resolvers = ['9.9.9.11:53', '8.8.8.8:53']
## Never let dnscrypt-proxy try to use the system DNS settings;
## unconditionally use the fallback resolver.
## When internal DNS resolution is required, for example to retrieve
## the resolvers list:
##
## - queries will be sent to dnscrypt-proxy itself, if it is already
## running with active servers (*)
## - or else, queries will be sent to fallback servers
## - finally, if `ignore_system_dns` is `false`, queries will be sent
## to the system DNS
##
## (*) this is incompatible with systemd sockets.
## `listen_addrs` must not be empty.
ignore_system_dns = false
ignore_system_dns = true
## Maximum time (in seconds) to wait for network connectivity before
## initializing the proxy.
## Useful if the proxy is automatically started at boot, and network
## connectivity is not guaranteed to be immediately available.
## Use 0 to not test for connectivity at all,
## Use 0 to not test for connectivity at all (not recommended),
## and -1 to wait as much as possible.
netprobe_timeout = 60
@ -217,7 +303,7 @@ netprobe_timeout = 60
## On other operating systems, the connection will be initialized
## but nothing will be sent at all.
netprobe_address = "255.255.255.0:53"
netprobe_address = '9.9.9.9:53'
## Offline mode - Do not use any remote encrypted servers.
@ -227,9 +313,19 @@ netprobe_address = "255.255.255.0:53"
# offline_mode = false
## Additional data to attach to outgoing queries.
## These strings will be added as TXT records to queries.
## Do not use, except on servers explicitly asking for extra data
## to be present.
## encrypted-dns-server can be configured to use this for access control
## in the [access_control] section
# query_meta = ['key1:value1', 'key2:value2', 'token:MySecretToken']
## Automatic log files rotation
# Maximum log files size in MB
# Maximum log files size in MB - Set to 0 for unlimited.
log_files_max_size = 10
# How long to keep backup files, in days
@ -244,23 +340,43 @@ log_files_max_backups = 1
# Filters #
#########################
## Note: if you are using dnsmasq, disable the `dnssec` option in dnsmasq if you
## configure dnscrypt-proxy to do any kind of filtering (including the filters
## below and blocklists).
## You can still choose resolvers that do DNSSEC validation.
## Immediately respond to IPv6-related queries with an empty response
## This makes things faster when there is no IPv6 connectivity, but can
## also cause reliability issues with some stub resolvers.
## Do not enable if you added a validating resolver such as dnsmasq in front
## of the proxy.
block_ipv6 = false
## Immediately respond to A and AAAA queries for host names without a domain name
## This also prevents "dotless domain names" from being resolved upstream.
block_unqualified = true
## Immediately respond to queries for local zones instead of leaking them to
## upstream resolvers (always causing errors or timeouts).
block_undelegated = true
## TTL for synthetic responses sent when a request has been blocked (due to
## IPv6 or blocklists).
reject_ttl = 10
##################################################################################
# Route queries for specific domains to a dedicated set of servers #
##################################################################################
## Example map entries (one entry per line):
## example.com 9.9.9.9
## example.net 9.9.9.9,8.8.8.8,1.1.1.1
## See the `example-forwarding-rules.txt` file for an example
# forwarding_rules = 'forwarding-rules.txt'
@ -273,13 +389,18 @@ block_ipv6 = false
## Cloaking returns a predefined address for a specific name.
## In addition to acting as a HOSTS file, it can also return the IP address
## of a different name. It will also do CNAME flattening.
## If 'cloak_ptr' is set, then PTR (reverse lookups) are enabled
## for cloaking rules that do not contain wild cards.
##
## Example map entries (one entry per line)
## example.com 10.1.1.1
## www.google.com forcesafesearch.google.com
## See the `example-cloaking-rules.txt` file for an example
# cloaking_rules = 'cloaking-rules.txt'
## TTL used when serving entries in cloaking-rules.txt
# cloak_ttl = 600
# cloak_ptr = false
###########################
@ -293,12 +414,12 @@ cache = true
## Cache size
cache_size = 512
cache_size = 4096
## Minimum TTL for cached entries
cache_min_ttl = 600
cache_min_ttl = 2400
## Maximum TTL for cached entries
@ -317,6 +438,53 @@ cache_neg_max_ttl = 600
########################################
# Captive portal handling #
########################################
[captive_portals]
## A file that contains a set of names used by operating systems to
## check for connectivity and captive portals, along with hard-coded
## IP addresses to return.
# map_file = 'example-captive-portals.txt'
##################################
# Local DoH server #
##################################
[local_doh]
## dnscrypt-proxy can act as a local DoH server. By doing so, web browsers
## requiring a direct connection to a DoH server in order to enable some
## features will enable these, without bypassing your DNS proxy.
## Addresses that the local DoH server should listen to
# listen_addresses = ['127.0.0.1:3000']
## Path of the DoH URL. This is not a file, but the part after the hostname
## in the URL. By convention, `/dns-query` is frequently chosen.
## For each `listen_address` the complete URL to access the server will be:
## `https://<listen_address><path>` (ex: `https://127.0.0.1/dns-query`)
# path = '/dns-query'
## Certificate file and key - Note that the certificate has to be trusted.
## Can be generated using the following command:
## openssl req -x509 -nodes -newkey rsa:2048 -days 5000 -sha256 -keyout localhost.pem -out localhost.pem
## See the documentation (wiki) for more information.
# cert_file = 'localhost.pem'
# cert_key_file = 'localhost.pem'
###############################
# Query logging #
###############################
@ -325,19 +493,20 @@ cache_neg_max_ttl = 600
[query_log]
## Path to the query log file (absolute, or relative to the same directory as the executable file)
## Path to the query log file (absolute, or relative to the same directory as the config file)
## Can be set to /dev/stdout in order to log to the standard output.
# file = 'query.log'
# file = 'query.log'
## Query log format (currently supported: tsv and ltsv)
## Query log format (currently supported: tsv and ltsv)
format = 'tsv'
format = 'tsv'
## Do not log these query types, to reduce verbosity. Keep empty to log everything.
## Do not log these query types, to reduce verbosity. Keep empty to log everything.
# ignored_qtypes = ['DNSKEY', 'NS']
# ignored_qtypes = ['DNSKEY', 'NS']
@ -351,22 +520,22 @@ cache_neg_max_ttl = 600
[nx_log]
## Path to the query log file (absolute, or relative to the same directory as the executable file)
## Path to the query log file (absolute, or relative to the same directory as the config file)
# file = 'nx.log'
# file = 'nx.log'
## Query log format (currently supported: tsv and ltsv)
## Query log format (currently supported: tsv and ltsv)
format = 'tsv'
format = 'tsv'
######################################################
# Pattern-based blocking (blacklists) #
# Pattern-based blocking (blocklists) #
######################################################
## Blacklists are made of one pattern per line. Example of valid patterns:
## Blocklists are made of one pattern per line. Example of valid patterns:
##
## example.com
## =example.com
@ -375,81 +544,108 @@ cache_neg_max_ttl = 600
## ads*.example.*
## ads*.example[0-9]*.com
##
## Example blacklist files can be found at https://download.dnscrypt.info/blacklists/
## A script to build blacklists from public feeds can be found in the
## `utils/generate-domains-blacklists` directory of the dnscrypt-proxy source code.
## Example blocklist files can be found at https://download.dnscrypt.info/blocklists/
## A script to build blocklists from public feeds can be found in the
## `utils/generate-domains-blocklists` directory of the dnscrypt-proxy source code.
[blacklist]
[blocked_names]
## Path to the file of blocking rules (absolute, or relative to the same directory as the executable file)
## Path to the file of blocking rules (absolute, or relative to the same directory as the config file)
# blacklist_file = 'blacklist.txt'
# blocked_names_file = 'blocked-names.txt'
## Optional path to a file logging blocked queries
## Optional path to a file logging blocked queries
# log_file = 'blocked.log'
# log_file = 'blocked-names.log'
## Optional log format: tsv or ltsv (default: tsv)
## Optional log format: tsv or ltsv (default: tsv)
# log_format = 'tsv'
# log_format = 'tsv'
###########################################################
# Pattern-based IP blocking (IP blacklists) #
# Pattern-based IP blocking (IP blocklists) #
###########################################################
## IP blacklists are made of one pattern per line. Example of valid patterns:
## IP blocklists are made of one pattern per line. Example of valid patterns:
##
## 127.*
## fe80:abcd:*
## 192.168.1.4
[ip_blacklist]
[blocked_ips]
## Path to the file of blocking rules (absolute, or relative to the same directory as the executable file)
## Path to the file of blocking rules (absolute, or relative to the same directory as the config file)
# blacklist_file = 'ip-blacklist.txt'
# blocked_ips_file = 'blocked-ips.txt'
## Optional path to a file logging blocked queries
## Optional path to a file logging blocked queries
# log_file = 'ip-blocked.log'
# log_file = 'blocked-ips.log'
## Optional log format: tsv or ltsv (default: tsv)
## Optional log format: tsv or ltsv (default: tsv)
# log_format = 'tsv'
# log_format = 'tsv'
######################################################
# Pattern-based whitelisting (blacklists bypass) #
# Pattern-based allow lists (blocklists bypass) #
######################################################
## Whitelists support the same patterns as blacklists
## If a name matches a whitelist entry, the corresponding session
## Allowlists support the same patterns as blocklists
## If a name matches an allowlist entry, the corresponding session
## will bypass names and IP filters.
##
## Time-based rules are also supported to make some websites only accessible at specific times of the day.
[whitelist]
[allowed_names]
## Path to the file of whitelisting rules (absolute, or relative to the same directory as the executable file)
## Path to the file of allow list rules (absolute, or relative to the same directory as the config file)
# whitelist_file = 'whitelist.txt'
# allowed_names_file = 'allowed-names.txt'
## Optional path to a file logging whitelisted queries
## Optional path to a file logging allowed queries
# log_file = 'whitelisted.log'
# log_file = 'allowed-names.log'
## Optional log format: tsv or ltsv (default: tsv)
## Optional log format: tsv or ltsv (default: tsv)
# log_format = 'tsv'
# log_format = 'tsv'
#########################################################
# Pattern-based allowed IPs lists (blocklists bypass) #
#########################################################
## Allowed IP lists support the same patterns as IP blocklists
## If an IP response matches an allowed entry, the corresponding session
## will bypass IP filters.
##
## Time-based rules are also supported to make some websites only accessible at specific times of the day.
[allowed_ips]
## Path to the file of allowed ip rules (absolute, or relative to the same directory as the config file)
# allowed_ips_file = 'allowed-ips.txt'
## Optional path to a file logging allowed queries
# log_file = 'allowed-ips.log'
## Optional log format: tsv or ltsv (default: tsv)
# log_format = 'tsv'
@ -458,34 +654,33 @@ cache_neg_max_ttl = 600
##########################################
## One or more weekly schedules can be defined here.
## Patterns in the name-based blocklist can optionally be followed with @schedule_name
## Patterns in the name-based blocked_names file can optionally be followed with @schedule_name
## to apply the pattern 'schedule_name' only when it matches a time range of that schedule.
##
## For example, the following rule in a blacklist file:
## For example, the following rule in a blocklist file:
## *.youtube.* @time-to-sleep
## would block access to YouTube only during the days, and period of the days
## define by the 'time-to-sleep' schedule.
## would block access to YouTube during the times defined by the 'time-to-sleep' schedule.
##
## {after='21:00', before= '7:00'} matches 0:00-7:00 and 21:00-0:00
## {after= '9:00', before='18:00'} matches 9:00-18:00
[schedules]
# [schedules.'time-to-sleep']
# mon = [{after='21:00', before='7:00'}]
# tue = [{after='21:00', before='7:00'}]
# wed = [{after='21:00', before='7:00'}]
# thu = [{after='21:00', before='7:00'}]
# fri = [{after='23:00', before='7:00'}]
# sat = [{after='23:00', before='7:00'}]
# sun = [{after='21:00', before='7:00'}]
# [schedules.time-to-sleep]
# mon = [{after='21:00', before='7:00'}]
# tue = [{after='21:00', before='7:00'}]
# wed = [{after='21:00', before='7:00'}]
# thu = [{after='21:00', before='7:00'}]
# fri = [{after='23:00', before='7:00'}]
# sat = [{after='23:00', before='7:00'}]
# sun = [{after='21:00', before='7:00'}]
# [schedules.'work']
# mon = [{after='9:00', before='18:00'}]
# tue = [{after='9:00', before='18:00'}]
# wed = [{after='9:00', before='18:00'}]
# thu = [{after='9:00', before='18:00'}]
# fri = [{after='9:00', before='17:00'}]
# [schedules.work]
# mon = [{after='9:00', before='18:00'}]
# tue = [{after='9:00', before='18:00'}]
# wed = [{after='9:00', before='18:00'}]
# thu = [{after='9:00', before='18:00'}]
# fri = [{after='9:00', before='17:00'}]
@ -505,43 +700,209 @@ cache_neg_max_ttl = 600
## must include the prefixes.
##
## If the `urls` property is missing, cache files and valid signatures
## must be already present; This doesn't prevent these cache files from
## must already be present. This doesn't prevent these cache files from
## expiring after `refresh_delay` hours.
## `refreshed_delay` must be in the [24..168] interval.
## The minimum delay of 24 hours (1 day) avoids unnecessary requests to servers.
## The maximum delay of 168 hours (1 week) ensures cache freshness.
[sources]
## An example of a remote source from https://github.com/DNSCrypt/dnscrypt-resolvers
### An example of a remote source from https://github.com/DNSCrypt/dnscrypt-resolvers
[sources.'public-resolvers']
urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v2/public-resolvers.md', 'https://download.dnscrypt.info/resolvers-list/v2/public-resolvers.md']
cache_file = 'public-resolvers.md'
minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
refresh_delay = 72
prefix = ''
[sources.public-resolvers]
urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/public-resolvers.md', 'https://download.dnscrypt.info/resolvers-list/v3/public-resolvers.md']
cache_file = 'public-resolvers.md'
minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
refresh_delay = 72
prefix = ''
## Quad9 over DNSCrypt - https://quad9.net/
### Anonymized DNS relays
[sources.relays]
urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/relays.md', 'https://download.dnscrypt.info/resolvers-list/v3/relays.md']
cache_file = 'relays.md'
minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
refresh_delay = 72
prefix = ''
### ODoH (Oblivious DoH) servers and relays
# [sources.odoh-servers]
# urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/odoh-servers.md', 'https://download.dnscrypt.info/resolvers-list/v3/odoh-servers.md']
# cache_file = 'odoh-servers.md'
# minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
# refresh_delay = 24
# prefix = ''
# [sources.odoh-relays]
# urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/odoh-relays.md', 'https://download.dnscrypt.info/resolvers-list/v3/odoh-relays.md']
# cache_file = 'odoh-relays.md'
# minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
# refresh_delay = 24
# prefix = ''
### Quad9
# [sources.quad9-resolvers]
# urls = ["https://www.quad9.net/quad9-resolvers.md"]
# minisign_key = "RWQBphd2+f6eiAqBsvDZEBXBGHQBJfeG6G+wJPPKxCZMoEQYpmoysKUN"
# cache_file = "quad9-resolvers.md"
# refresh_delay = 72
# prefix = "quad9-"
# urls = ['https://www.quad9.net/quad9-resolvers.md']
# minisign_key = 'RWQBphd2+f6eiAqBsvDZEBXBGHQBJfeG6G+wJPPKxCZMoEQYpmoysKUN'
# cache_file = 'quad9-resolvers.md'
# prefix = 'quad9-'
## Another example source, with resolvers censoring some websites not appropriate for children
## This is a subset of the `public-resolvers` list, so enabling both is useless
### Another example source, with resolvers censoring some websites not appropriate for children
### This is a subset of the `public-resolvers` list, so enabling both is useless.
# [sources.'parental-control']
# urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v2/parental-control.md', 'https://download.dnscrypt.info/resolvers-list/v2/parental-control.md']
# cache_file = 'parental-control.md'
# minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
# [sources.parental-control]
# urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/parental-control.md', 'https://download.dnscrypt.info/resolvers-list/v3/parental-control.md']
# cache_file = 'parental-control.md'
# minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
### dnscry.pt servers - See https://www.dnscry.pt
# [sources.dnscry-pt-resolvers]
# urls = ["https://www.dnscry.pt/resolvers.md"]
# minisign_key = "RWQM31Nwkqh01x88SvrBL8djp1NH56Rb4mKLHz16K7qsXgEomnDv6ziQ"
# cache_file = "dnscry.pt-resolvers.md"
# refresh_delay = 72
# prefix = "dnscry.pt-"
#########################################
# Servers with known bugs #
#########################################
[broken_implementations]
## Cisco servers currently cannot handle queries larger than 1472 bytes, and don't
## truncate responses larger than questions as expected by the DNSCrypt protocol.
## This prevents large responses from being received over UDP and over relays.
##
## Older versions of the `dnsdist` server software had a bug with queries larger
## than 1500 bytes. This is fixed since `dnsdist` version 1.5.0, but
## some server may still run an outdated version.
##
## The list below enables workarounds to make non-relayed usage more reliable
## until the servers are fixed.
fragments_blocked = ['cisco', 'cisco-ipv6', 'cisco-familyshield', 'cisco-familyshield-ipv6', 'cleanbrowsing-adult', 'cleanbrowsing-adult-ipv6', 'cleanbrowsing-family', 'cleanbrowsing-family-ipv6', 'cleanbrowsing-security', 'cleanbrowsing-security-ipv6']
#################################################################
# Certificate-based client authentication for DoH #
#################################################################
## Use a X509 certificate to authenticate yourself when connecting to DoH servers.
## This is only useful if you are operating your own, private DoH server(s).
## 'creds' maps servers to certificates, and supports multiple entries.
## If you are not using the standard root CA, an optional "root_ca"
## property set to the path to a root CRT file can be added to a server entry.
[doh_client_x509_auth]
# creds = [
# { server_name='*', client_cert='client.crt', client_key='client.key' }
# ]
################################
# Anonymized DNS #
################################
[anonymized_dns]
## Routes are indirect ways to reach DNSCrypt servers.
##
## A route maps a server name ("server_name") to one or more relays that will be
## used to connect to that server.
##
## A relay can be specified as a DNS Stamp (either a relay stamp, or a
## DNSCrypt stamp) or a server name.
##
## The following example routes "example-server-1" via `anon-example-1` or `anon-example-2`,
## and "example-server-2" via the relay whose relay DNS stamp is
## "sdns://gRIxMzcuNzQuMjIzLjIzNDo0NDM".
##
## !!! THESE ARE JUST EXAMPLES !!!
##
## Review the list of available relays from the "relays.md" file, and, for each
## server you want to use, define the relays you want connections to go through.
##
## Carefully choose relays and servers so that they are run by different entities.
##
## "server_name" can also be set to "*" to define a default route, for all servers:
## { server_name='*', via=['anon-example-1', 'anon-example-2'] }
##
## If a route is ["*"], the proxy automatically picks a relay on a distinct network.
## { server_name='*', via=['*'] } is also an option, but is likely to be suboptimal.
##
## Manual selection is always recommended over automatic selection, so that you can
## select (relay,server) pairs that work well and fit your own criteria (close by or
## in different countries, operated by different entities, on distinct ISPs...)
# routes = [
# { server_name='example-server-1', via=['anon-example-1', 'anon-example-2'] },
# { server_name='example-server-2', via=['sdns://gRIxMzcuNzQuMjIzLjIzNDo0NDM'] }
# ]
## Skip resolvers incompatible with anonymization instead of using them directly
skip_incompatible = false
## If public server certificates for a non-conformant server cannot be
## retrieved via a relay, try getting them directly. Actual queries
## will then always go through relays.
# direct_cert_fallback = false
###############################
# DNS64 #
###############################
## DNS64 is a mechanism for synthesizing AAAA records from A records.
## It is used with an IPv6/IPv4 translator to enable client-server
## communication between an IPv6-only client and an IPv4-only server,
## without requiring any changes to either the IPv6 or the IPv4 node,
## for the class of applications that work through NATs.
##
## There are two options to synthesize such records:
## Option 1: Using a set of static IPv6 prefixes;
## Option 2: By discovering the IPv6 prefix from DNS64-enabled resolver.
##
## If both options are configured - only static prefixes are used.
## (Ref. RFC6147, RFC6052, RFC7050)
##
## Do not enable unless you know what DNS64 is and why you need it, or else
## you won't be able to connect to anything at all.
[dns64]
## Static prefix(es) as Pref64::/n CIDRs
# prefix = ['64:ff9b::/96']
## DNS64-enabled resolver(s) to discover Pref64::/n CIDRs
## These resolvers are used to query for Well-Known IPv4-only Name (WKN) "ipv4only.arpa." to discover only.
## Set with your ISP's resolvers in case of custom prefixes (other than Well-Known Prefix 64:ff9b::/96).
## IMPORTANT: Default resolvers listed below support Well-Known Prefix 64:ff9b::/96 only.
# resolver = ['[2606:4700:4700::64]:53', '[2001:4860:4860::64]:53']
########################################
# Static entries #
########################################
## Optional, local, static list of additional servers
## Mostly useful for testing your own servers.
[static]
# [static.'google']
# stamp = 'sdns://AgUAAAAAAAAAAAAOZG5zLmdvb2dsZS5jb20NL2V4cGVyaW1lbnRhbA'
# [static.myserver]
# stamp = 'sdns://AQcAAAAAAAAAAAAQMi5kbnNjcnlwdC1jZXJ0Lg'

View File

@ -10,5 +10,27 @@
## In order to enable this feature, the "forwarding_rules" property needs to
## be set to this file name inside the main configuration file.
## Blocking IPv6 may prevent local devices from being discovered.
## If this happens, set `block_ipv6` to `false` in the main config file.
## Forward *.lan, *.local, *.home, *.home.arpa, *.internal and *.localdomain to 192.168.1.1
# lan 192.168.1.1
# local 192.168.1.1
# home 192.168.1.1
# home.arpa 192.168.1.1
# internal 192.168.1.1
# localdomain 192.168.1.1
# 192.in-addr.arpa 192.168.1.1
## Forward queries for example.com and *.example.com to 9.9.9.9 and 8.8.8.8
# example.com 9.9.9.9,8.8.8.8
# example.com 9.9.9.9,8.8.8.8
## Forward queries to a resolver using IPv6
# ipv6.example.com [2001:DB8::42]:53
## Forward queries for .onion names to a local Tor client
## Tor must be configured with the following in the torrc file:
## DNSPort 9053
## AutomapHostsOnResolve 1
# onion 127.0.0.1:9053

View File

@ -1,23 +0,0 @@
###########################
# Whitelist #
###########################
## Rules for name-based query whitelisting, one per line
##
## Example of valid patterns:
##
## ads.* | matches anything with an "ads." prefix
## *.example.com | matches example.com and all names within that zone such as www.example.com
## example.com | identical to the above
## =example.com | whitelists example.com but not *.example.com
## *sex* | matches any name containing that substring
## ads[0-9]* | matches "ads" followed by one or more digits
## ads*.example* | *, ? and [] can be used anywhere, but prefixes/suffixes are faster
## Time-based rules
# *.youtube.* @time-to-play
# facebook.com @play

View File

@ -0,0 +1,41 @@
//go:build gofuzzbeta
// +build gofuzzbeta
package main
import (
"encoding/hex"
"testing"
stamps "github.com/jedisct1/go-dnsstamps"
)
func FuzzParseODoHTargetConfigs(f *testing.F) {
configs_hex := "0020000100010020aacc53b3df0c6eb2d7d5ce4ddf399593376c9903ba6a52a52c3a2340f97bb764"
configs, _ := hex.DecodeString(configs_hex)
f.Add(configs)
f.Fuzz(func(t *testing.T, configs []byte) {
if _, err := parseODoHTargetConfigs(configs); err != nil {
t.Skip()
}
})
}
func FuzzParseStampParser(f *testing.F) {
f.Add("sdns://AgcAAAAAAAAACzEwNC4yMS42Ljc4AA1kb2guY3J5cHRvLnN4Ci9kbnMtcXVlcnk")
f.Add("sdns://AgcAAAAAAAAAGlsyNjA2OjQ3MDA6MzAzNzo6NjgxNTo2NGVdABJkb2gtaXB2Ni5jcnlwdG8uc3gKL2Rucy1xdWVyeQ")
f.Add(
"sdns://AQcAAAAAAAAADTUxLjE1LjEyMi4yNTAg6Q3ZfapcbHgiHKLF7QFoli0Ty1Vsz3RXs1RUbxUrwZAcMi5kbnNjcnlwdC1jZXJ0LnNjYWxld2F5LWFtcw",
)
f.Add(
"sdns://AQcAAAAAAAAAFlsyMDAxOmJjODoxODIwOjUwZDo6MV0g6Q3ZfapcbHgiHKLF7QFoli0Ty1Vsz3RXs1RUbxUrwZAcMi5kbnNjcnlwdC1jZXJ0LnNjYWxld2F5LWFtcw",
)
f.Add("sdns://gQ8xNjMuMTcyLjE4MC4xMjU")
f.Add("sdns://BQcAAAAAAAAADm9kb2guY3J5cHRvLnN4Ci9kbnMtcXVlcnk")
f.Add("sdns://hQcAAAAAAAAAACCi3jNJDEdtNW4tvHN8J3lpIklSa2Wrj7qaNCgEgci9_BpvZG9oLXJlbGF5LmVkZ2Vjb21wdXRlLmFwcAEv")
f.Fuzz(func(t *testing.T, stamp string) {
if _, err := stamps.NewServerStampFromString(stamp); err != nil {
t.Skip()
}
})
}

141
dnscrypt-proxy/local-doh.go Normal file
View File

@ -0,0 +1,141 @@
package main
import (
"encoding/base64"
"fmt"
"io"
"net"
"net/http"
"strings"
"time"
"github.com/jedisct1/dlog"
"github.com/miekg/dns"
)
type localDoHHandler struct {
proxy *Proxy
}
func (handler localDoHHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
proxy := handler.proxy
if !proxy.clientsCountInc() {
dlog.Warnf("Too many incoming connections (max=%d)", proxy.maxClients)
return
}
defer proxy.clientsCountDec()
dataType := "application/dns-message"
writer.Header().Set("Server", "dnscrypt-proxy")
if request.URL.Path != proxy.localDoHPath {
writer.WriteHeader(404)
return
}
packet := []byte{}
var err error
start := time.Now()
if request.Method == "POST" &&
request.Header.Get("Content-Type") == dataType {
packet, err = io.ReadAll(io.LimitReader(request.Body, int64(MaxDNSPacketSize)))
if err != nil {
dlog.Warnf("No body in a local DoH query")
return
}
} else if request.Method == "GET" && request.Header.Get("Accept") == dataType {
encodedPacket := request.URL.Query().Get("dns")
if len(encodedPacket) >= MinDNSPacketSize*4/3 && len(encodedPacket) <= MaxDNSPacketSize*4/3 {
packet, err = base64.RawURLEncoding.DecodeString(encodedPacket)
if err != nil {
dlog.Warnf("Invalid base64 in a local DoH query")
return
}
}
}
if len(packet) < MinDNSPacketSize {
writer.Header().Set("Content-Type", "text/plain")
writer.WriteHeader(400)
writer.Write([]byte("dnscrypt-proxy local DoH server\n"))
return
}
clientAddr, err := net.ResolveTCPAddr("tcp", request.RemoteAddr)
if err != nil {
dlog.Errorf("Unable to get the client address: [%v]", err)
return
}
xClientAddr := net.Addr(clientAddr)
hasEDNS0Padding, err := hasEDNS0Padding(packet)
if err != nil {
writer.WriteHeader(400)
return
}
response := proxy.processIncomingQuery("local_doh", proxy.mainProto, packet, &xClientAddr, nil, start, false)
if len(response) == 0 {
writer.WriteHeader(500)
return
}
msg := dns.Msg{}
if err := msg.Unpack(packet); err != nil {
writer.WriteHeader(500)
return
}
responseLen := len(response)
paddedLen := dohPaddedLen(responseLen)
padLen := paddedLen - responseLen
if hasEDNS0Padding {
response, err = addEDNS0PaddingIfNoneFound(&msg, response, padLen)
if err != nil {
dlog.Critical(err)
return
}
} else {
pad := strings.Repeat("X", padLen)
writer.Header().Set("X-Pad", pad)
}
writer.Header().Set("Content-Type", dataType)
writer.Header().Set("Content-Length", fmt.Sprint(len(response)))
writer.WriteHeader(200)
writer.Write(response)
}
func (proxy *Proxy) localDoHListener(acceptPc *net.TCPListener) {
defer acceptPc.Close()
if len(proxy.localDoHCertFile) == 0 || len(proxy.localDoHCertKeyFile) == 0 {
dlog.Fatal("A certificate and a key are required to start a local DoH service")
}
httpServer := &http.Server{
ReadTimeout: proxy.timeout,
WriteTimeout: proxy.timeout,
Handler: localDoHHandler{proxy: proxy},
}
httpServer.SetKeepAlivesEnabled(true)
if err := httpServer.ServeTLS(acceptPc, proxy.localDoHCertFile, proxy.localDoHCertKeyFile); err != nil {
dlog.Fatal(err)
}
}
func dohPaddedLen(unpaddedLen int) int {
boundaries := [...]int{
64,
128,
192,
256,
320,
384,
512,
704,
768,
896,
960,
1024,
1088,
1152,
2688,
4080,
MaxDNSPacketSize,
}
for _, boundary := range boundaries {
if boundary >= unpaddedLen {
return boundary
}
}
return unpaddedLen
}

View File

@ -0,0 +1,47 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDb7g6EQhbfby97
k4oMbZTzdi2TWFBs7qK/QwgOu+L6EhNHPO1ZEU29v0APFBFJO5zyyAk9bZ9k9tPB
bCuVVI9jEUfLH3UCjEQPG6XI2w++uVh0yALvc/uurCvRHVlle/V7cAoikndc2SjE
RQUALbACIqwD5g0F77BYwcsreB4GH253/R6Q2/CJZ4jNHPjkocOJiVr3ejA0kkoN
MXpGUXWcrVVk20M2A1CeO7HAulLRcklEdoHE3v46pjp0iZK0F9LyZX1U1ql+4QL3
iQttoZ4tMg83lFHSt4G9PrpIhzXr9W4NW822faSvrIwwN/JbItUmRa7n/3+MkuJQ
IGGNDayXAgMBAAECggEBANs0fmGSocuXvYL1Pi4+9qxnCOwIpTi97Zam0BwnZwcL
Bw4FCyiwV4UdX1LoFIailT9i49rHLYzre4oZL6OKgdQjQCSTuQOOHLPWQbpdpWba
w/C5/jr+pkemMZIfJ6BAGiArPt7Qj4oKpFhj1qUj5H9sYXkNTcOx8Fm25rLv6TT9
O7wg0oCpyG+iBSbCYBp9mDMz8pfo4P3BhcFiyKCKeiAC6KuHU81dvuKeFB4XQK+X
no2NqDqe6MBkmTqjNNy+wi1COR7lu34LPiWU5Hq5PdIEqBBUMjlMI6oYlhlgNTdx
SvsqFz3Xs6kpAhJTrSiAqscPYosgaMQxo+LI26PJnikCgYEA9n0OERkm0wSBHnHY
Kx8jaxNYg93jEzVnEgI/MBTJZqEyCs9fF6Imv737VawEN/BhesZZX7bGZQfDo8AT
aiSa5upkkSGXEqTu5ytyoKFTb+dJ/qmx3+zP6dPVzDnc8WPYMoUg7vvjZkXXJgZX
+oMlMUW1wWiDNI3wP19W9Is6xssCgYEA5GqkUBEns6eTFJV0JKqbEORJJ7lx5NZe
cIx+jPpLkILG4mOKOg1TBx0wkxa9cELtsNsM+bPtu9OqRMhsfPBmsXDHhJwg0Z6G
eDTfYYPkpRhwZvl6jBZn9sLVR9wfg2hE+n0lfV3mceg336KOkwAehDU84SWZ2e0S
esqkpbHJa+UCgYA7PY0O8POSzcdWkNf6bS5vAqRIdSCpMjGGc4HKRYSuJNnJHVPm
czNK7Bcm3QPaiexzvI4oYd5G09niVjyUSx3rl7P56Y/MjFVau+d90agjAfyXtyMo
BVtnAGGnBtUiMvP4GGT06xcZMnnmCqpEbBaZQ/7N8Bdwnxh5sqlMdtX2hwKBgAhL
hyQRO2vezgyVUN50A6WdZLq4lVZGIq/bqkzcWhopZaebDc4F5doASV9OGBsXkyI1
EkePLTcA/NH6pVX0NQaEnfpG4To7k46R/PrBm3ATbyGONdEYjzX65VvytoJDKx4d
pVrkKhZA5KaOdLcJ7hHHDSrv/qJXZbBn44rQ5guxAoGBAJ6oeUsUUETakxlmIhmK
xuQmWqLf97BKt8r6Z8CqHKWK7vpG2OmgFYCQGaR7angQ8hmAOv6jM56XhoagDBoc
UoaoEyo9/uCk6NRUkUMj7Tk/5UQSiWLceVH27w+icMFhf1b7EmmNfk+APsiathO5
j4edf1AinVCPwRVVu1dtLL5P
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIDAjCCAeoCCQCptj0+TjjIJjANBgkqhkiG9w0BAQsFADBDMREwDwYDVQQKDAhE
TlNDcnlwdDEaMBgGA1UECwwRTG9jYWwgdGVzdCBzZXJ2ZXIxEjAQBgNVBAMMCWxv
Y2FsaG9zdDAeFw0xOTExMTgxNDA2MzBaFw0zMzA3MjcxNDA2MzBaMEMxETAPBgNV
BAoMCEROU0NyeXB0MRowGAYDVQQLDBFMb2NhbCB0ZXN0IHNlcnZlcjESMBAGA1UE
AwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2+4O
hEIW328ve5OKDG2U83Ytk1hQbO6iv0MIDrvi+hITRzztWRFNvb9ADxQRSTuc8sgJ
PW2fZPbTwWwrlVSPYxFHyx91AoxEDxulyNsPvrlYdMgC73P7rqwr0R1ZZXv1e3AK
IpJ3XNkoxEUFAC2wAiKsA+YNBe+wWMHLK3geBh9ud/0ekNvwiWeIzRz45KHDiYla
93owNJJKDTF6RlF1nK1VZNtDNgNQnjuxwLpS0XJJRHaBxN7+OqY6dImStBfS8mV9
VNapfuEC94kLbaGeLTIPN5RR0reBvT66SIc16/VuDVvNtn2kr6yMMDfyWyLVJkWu
5/9/jJLiUCBhjQ2slwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQA6Vz5HnGuy8jZz
5i8ipbcDMCZNdpYYnxgD53hEKOfoSv7LaF0ztD8Kmg3s5LHv9EHlkK3+G6FWRGiP
9f6IbtRITaiVQP3M13T78hpN5Qq5jgsqjR7ZcN7Etr6ZFd7G/0+mzqbyBuW/3szt
RdX/YLy1csvjbZoNNuXGWRohXjg0Mjko2tRLmARvxA/gZV5zWycv3BD2BPzyCdS9
MDMYSF0RPiL8+alfwLNqLcqMA5liHlmZa85uapQyoUI3ksKJkEgU53aD8cYhH9Yn
6mVpsrvrcRLBiHlbi24QBolhFkCSRK8bXes8XDIPuD8iYRwlrVBwOakMFQWMqNfI
IMOKJomU
-----END CERTIFICATE-----

40
dnscrypt-proxy/logger.go Normal file
View File

@ -0,0 +1,40 @@
package main
import (
"io"
"os"
"github.com/jedisct1/dlog"
"gopkg.in/natefinch/lumberjack.v2"
)
func Logger(logMaxSize int, logMaxAge int, logMaxBackups int, fileName string) io.Writer {
if fileName == "/dev/stdout" {
return os.Stdout
}
if st, _ := os.Stat(fileName); st != nil && !st.Mode().IsRegular() {
if st.Mode().IsDir() {
dlog.Fatalf("[%v] is a directory", fileName)
}
fp, err := os.OpenFile(fileName, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0o644)
if err != nil {
dlog.Fatalf("Unable to access [%v]: [%v]", fileName, err)
}
return fp
}
if fp, err := os.OpenFile(fileName, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0o644); err == nil {
fp.Close()
} else {
dlog.Errorf("Unable to create [%v]: [%v]", fileName, err)
}
logger := &lumberjack.Logger{
LocalTime: true,
MaxSize: logMaxSize,
MaxAge: logMaxAge,
MaxBackups: logMaxBackups,
Filename: fileName,
Compress: true,
}
return logger
}

View File

@ -7,56 +7,88 @@ import (
"fmt"
"math/rand"
"os"
"runtime"
"sync"
"github.com/facebookgo/pidfile"
"github.com/jedisct1/dlog"
"github.com/kardianos/service"
)
const (
AppVersion = "2.0.24"
AppVersion = "2.1.5"
DefaultConfigFileName = "dnscrypt-proxy.toml"
)
type App struct {
wg sync.WaitGroup
quit chan struct{}
proxy Proxy
proxy *Proxy
flags *ConfigFlags
}
func main() {
tzErr := TimezoneSetup()
dlog.Init("dnscrypt-proxy", dlog.SeverityNotice, "DAEMON")
os.Setenv("GODEBUG", os.Getenv("GODEBUG")+",tls13=1")
if tzErr != nil {
dlog.Warnf("Timezone setup failed: [%v]", tzErr)
}
runtime.MemProfileRate = 0
seed := make([]byte, 8)
crypto_rand.Read(seed)
rand.Seed(int64(binary.LittleEndian.Uint64(seed[:])))
if _, err := crypto_rand.Read(seed); err != nil {
dlog.Fatal(err)
}
rand.Seed(int64(binary.LittleEndian.Uint64(seed)))
pwd, err := os.Getwd()
if err != nil {
dlog.Fatal("Unable to find the path to the current directory")
}
svcFlag := flag.String("service", "", fmt.Sprintf("Control the system service: %q", service.ControlAction))
version := flag.Bool("version", false, "print current proxy version")
flags := ConfigFlags{}
flags.Resolve = flag.String("resolve", "", "resolve a DNS name (string can be <name> or <name>,<resolver address>)")
flags.List = flag.Bool("list", false, "print the list of available resolvers for the enabled filters")
flags.ListAll = flag.Bool("list-all", false, "print the complete list of available resolvers, ignoring filters")
flags.IncludeRelays = flag.Bool("include-relays", false, "include the list of available relays in the output of -list and -list-all")
flags.JSONOutput = flag.Bool("json", false, "output list as JSON")
flags.Check = flag.Bool("check", false, "check the configuration file and exit")
flags.ConfigFile = flag.String("config", DefaultConfigFileName, "Path to the configuration file")
flags.Child = flag.Bool("child", false, "Invokes program as a child process")
flags.NetprobeTimeoutOverride = flag.Int("netprobe-timeout", 60, "Override the netprobe timeout")
flags.ShowCerts = flag.Bool("show-certs", false, "print DoH certificate chain hashes")
flag.Parse()
if *version {
fmt.Println(AppVersion)
os.Exit(0)
}
if fullexecpath, err := os.Executable(); err == nil {
WarnIfMaybeWritableByOtherUsers(fullexecpath)
}
app := &App{
flags: &flags,
}
svcConfig := &service.Config{
Name: "dnscrypt-proxy",
DisplayName: "DNSCrypt client proxy",
Description: "Encrypted/authenticated DNS proxy",
WorkingDirectory: pwd,
Arguments: []string{"-config", *flags.ConfigFile},
}
svcFlag := flag.String("service", "", fmt.Sprintf("Control the system service: %q", service.ControlAction))
app := &App{}
svc, err := service.New(app, svcConfig)
if err != nil {
svc = nil
dlog.Debug(err)
}
app.proxy = NewProxy()
_ = ServiceManagerStartNotify()
if err := ConfigLoad(&app.proxy, svcFlag); err != nil {
dlog.Fatal(err)
}
dlog.Noticef("dnscrypt-proxy %s", AppVersion)
if len(*svcFlag) != 0 {
if svc == nil {
dlog.Fatal("Built-in service installation is not supported on this platform")
@ -78,7 +110,7 @@ func main() {
return
}
if svc != nil {
if err = svc.Run(); err != nil {
if err := svc.Run(); err != nil {
dlog.Fatal(err)
}
} else {
@ -87,34 +119,38 @@ func main() {
}
func (app *App) Start(service service.Service) error {
proxy := &app.proxy
if err := InitPluginsGlobals(&proxy.pluginsGlobals, proxy); err != nil {
if service != nil {
go func() {
app.AppMain()
}()
} else {
app.AppMain()
}
return nil
}
func (app *App) AppMain() {
if err := ConfigLoad(app.proxy, app.flags); err != nil {
dlog.Fatal(err)
}
if err := PidFileCreate(); err != nil {
dlog.Errorf("Unable to create the PID file: [%v]", err)
}
if err := app.proxy.InitPluginsGlobals(); err != nil {
dlog.Fatal(err)
}
app.quit = make(chan struct{})
app.wg.Add(1)
if service != nil {
go func() {
app.AppMain(proxy)
}()
} else {
app.AppMain(proxy)
}
return nil
}
func (app *App) AppMain(proxy *Proxy) {
pidfile.Write()
proxy.StartProxy()
app.proxy.StartProxy()
runtime.GC()
<-app.quit
dlog.Notice("Quit signal received...")
app.wg.Done()
}
func (app *App) Stop(service service.Service) error {
if pidFilePath := pidfile.GetPidfilePath(); len(pidFilePath) > 1 {
os.Remove(pidFilePath)
if err := PidFileRemove(); err != nil {
dlog.Warnf("Failed to remove the PID file: [%v]", err)
}
dlog.Notice("Stopped.")
return nil

View File

@ -1,19 +1,26 @@
//go:build !windows
// +build !windows
package main
import (
"errors"
"net"
"time"
"github.com/jedisct1/dlog"
)
func NetProbe(address string, timeout int) error {
if len(address) <= 0 || timeout <= 0 {
func NetProbe(proxy *Proxy, address string, timeout int) error {
if len(address) <= 0 || timeout == 0 {
return nil
}
if captivePortalHandler, err := ColdStart(proxy); err == nil {
if captivePortalHandler != nil {
defer captivePortalHandler.Stop()
}
} else {
dlog.Critical(err)
}
remoteUDPAddr, err := net.ResolveUDPAddr("udp", address)
if err != nil {
return err
@ -22,7 +29,7 @@ func NetProbe(address string, timeout int) error {
if timeout < 0 {
timeout = MaxTimeout
} else {
timeout = Max(MaxTimeout, timeout)
timeout = Min(MaxTimeout, timeout)
}
for tries := timeout; tries > 0; tries-- {
pc, err := net.DialUDP("udp", nil, remoteUDPAddr)
@ -39,7 +46,6 @@ func NetProbe(address string, timeout int) error {
dlog.Notice("Network connectivity detected")
return nil
}
es := "Timeout while waiting for network connectivity"
dlog.Error(es)
return errors.New(es)
dlog.Error("Timeout while waiting for network connectivity")
return nil
}

View File

@ -1,17 +1,23 @@
package main
import (
"errors"
"net"
"time"
"time"
"github.com/jedisct1/dlog"
)
func NetProbe(address string, timeout int) error {
if len(address) <= 0 || timeout <= 0 {
func NetProbe(proxy *Proxy, address string, timeout int) error {
if len(address) <= 0 || timeout == 0 {
return nil
}
if captivePortalHandler, err := ColdStart(proxy); err == nil {
if captivePortalHandler != nil {
defer captivePortalHandler.Stop()
}
} else {
dlog.Critical(err)
}
remoteUDPAddr, err := net.ResolveUDPAddr("udp", address)
if err != nil {
return err
@ -20,14 +26,15 @@ func NetProbe(address string, timeout int) error {
if timeout < 0 {
timeout = MaxTimeout
} else {
timeout = Max(MaxTimeout, timeout)
timeout = Min(MaxTimeout, timeout)
}
for tries := timeout; tries > 0; tries-- {
pc, err := net.DialUDP("udp", nil, remoteUDPAddr)
if err == nil {
// Write at least 1 byte. This ensures that sockets are ready to use for writing.
// Windows specific: during the system startup, sockets can be created but the underlying buffers may not be setup yet. If this is the case
// Write fails with WSAENOBUFS: "An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full"
// Windows specific: during the system startup, sockets can be created but the underlying buffers may not be
// setup yet. If this is the case Write fails with WSAENOBUFS: "An operation on a socket could not be
// performed because the system lacked sufficient buffer space or because a queue was full"
_, err = pc.Write([]byte{0})
}
if err != nil {
@ -43,7 +50,6 @@ func NetProbe(address string, timeout int) error {
dlog.Notice("Network connectivity detected")
return nil
}
es := "Timeout while waiting for network connectivity"
dlog.Error(es)
return errors.New(es)
dlog.Error("Timeout while waiting for network connectivity")
return nil
}

View File

@ -0,0 +1,191 @@
package main
import (
"crypto/subtle"
"encoding/binary"
"fmt"
"github.com/jedisct1/dlog"
hpkecompact "github.com/jedisct1/go-hpke-compact"
)
const (
odohVersion = uint16(0x0001)
odohTestVersion = uint16(0xff06)
maxODoHConfigs = 10
)
type ODoHTargetConfig struct {
suite *hpkecompact.Suite
keyID []byte
publicKey []byte
}
func encodeLengthValue(b []byte) []byte {
lengthBuffer := make([]byte, 2)
binary.BigEndian.PutUint16(lengthBuffer, uint16(len(b)))
return append(lengthBuffer, b...)
}
func parseODoHTargetConfig(config []byte) (ODoHTargetConfig, error) {
if len(config) < 8 {
return ODoHTargetConfig{}, fmt.Errorf("Malformed config")
}
kemID := binary.BigEndian.Uint16(config[0:2])
kdfID := binary.BigEndian.Uint16(config[2:4])
aeadID := binary.BigEndian.Uint16(config[4:6])
publicKeyLength := binary.BigEndian.Uint16(config[6:8])
publicKey := config[8:]
if len(publicKey) != int(publicKeyLength) {
return ODoHTargetConfig{}, fmt.Errorf("Malformed config")
}
suite, err := hpkecompact.NewSuite(hpkecompact.KemID(kemID), hpkecompact.KdfID(kdfID), hpkecompact.AeadID(aeadID))
if err != nil {
return ODoHTargetConfig{}, err
}
_, _, err = suite.NewClientContext(publicKey, []byte("odoh query"), nil)
if err != nil {
return ODoHTargetConfig{}, err
}
keyID, err := suite.Expand(suite.Extract(config, nil), []byte("odoh key id"), uint16(suite.Hash().Size()))
if err != nil {
return ODoHTargetConfig{}, err
}
return ODoHTargetConfig{
suite: suite,
publicKey: publicKey,
keyID: encodeLengthValue(keyID),
}, nil
}
func parseODoHTargetConfigs(configs []byte) ([]ODoHTargetConfig, error) {
if len(configs) <= 2 {
return nil, fmt.Errorf("Server didn't return any ODoH configurations")
}
length := binary.BigEndian.Uint16(configs)
if len(configs) != int(length)+2 {
return nil, fmt.Errorf("Malformed configs")
}
targets := make([]ODoHTargetConfig, 0)
offset := 2
for {
if offset+4 > len(configs) || len(targets) >= maxODoHConfigs {
break
}
configVersion := binary.BigEndian.Uint16(configs[offset : offset+2])
configLength := binary.BigEndian.Uint16(configs[offset+2 : offset+4])
if configVersion == odohVersion || configVersion == odohTestVersion {
if configVersion != odohVersion {
dlog.Debugf("Server still uses the legacy 0x%x ODoH version", configVersion)
}
target, err := parseODoHTargetConfig(configs[offset+4 : offset+4+int(configLength)])
if err == nil {
targets = append(targets, target)
}
}
offset = offset + int(configLength) + 4
}
return targets, nil
}
type ODoHQuery struct {
suite *hpkecompact.Suite
ctx hpkecompact.ClientContext
odohPlaintext []byte
odohMessage []byte
}
func (t ODoHTargetConfig) encryptQuery(query []byte) (ODoHQuery, error) {
clientCtx, encryptedSharedSecret, err := t.suite.NewClientContext(t.publicKey, []byte("odoh query"), nil)
if err != nil {
return ODoHQuery{}, err
}
odohPlaintext := make([]byte, 4+len(query))
binary.BigEndian.PutUint16(odohPlaintext[0:2], uint16(len(query)))
copy(odohPlaintext[2:], query)
aad := append([]byte{0x01}, t.keyID...)
ciphertext, err := clientCtx.EncryptToServer(odohPlaintext, aad)
if err != nil {
return ODoHQuery{}, err
}
encryptedMessage := encodeLengthValue(append(encryptedSharedSecret, ciphertext...))
odohMessage := append(append([]byte{0x01}, t.keyID...), encryptedMessage...)
return ODoHQuery{
suite: t.suite,
odohPlaintext: odohPlaintext,
odohMessage: odohMessage,
ctx: clientCtx,
}, nil
}
func (q ODoHQuery) decryptResponse(response []byte) ([]byte, error) {
if len(response) < 3 {
return nil, fmt.Errorf("Malformed response")
}
messageType := response[0]
if messageType != uint8(0x02) {
return nil, fmt.Errorf("Malformed response")
}
responseNonceLength := binary.BigEndian.Uint16(response[1:3])
if len(response) < 5+int(responseNonceLength) {
return nil, fmt.Errorf("Malformed response")
}
responseNonceEnc := response[1 : 3+responseNonceLength]
secret, err := q.ctx.Export([]byte("odoh response"), q.suite.KeyBytes)
if err != nil {
return nil, err
}
salt := append(q.odohPlaintext, responseNonceEnc...)
prk := q.suite.Extract(secret, salt)
key, err := q.suite.Expand(prk, []byte("odoh key"), q.suite.KeyBytes)
if err != nil {
return nil, err
}
nonce, err := q.suite.Expand(prk, []byte("odoh nonce"), q.suite.NonceBytes)
if err != nil {
return nil, err
}
cipher, err := q.suite.NewRawCipher(key)
if err != nil {
return nil, err
}
ctLength := binary.BigEndian.Uint16(response[3+int(responseNonceLength) : 5+int(responseNonceLength)])
if int(ctLength) != len(response[5+int(responseNonceLength):]) {
return nil, fmt.Errorf("Malformed response")
}
ct := response[5+int(responseNonceLength):]
aad := response[0 : 3+int(responseNonceLength)]
responsePlaintext, err := cipher.Open(nil, nonce, ct, aad)
if err != nil {
return nil, err
}
responseLength := binary.BigEndian.Uint16(responsePlaintext[0:2])
valid := 1
for i := 4 + int(responseLength); i < len(responsePlaintext); i++ {
valid &= subtle.ConstantTimeByteEq(response[i], 0x00)
}
if valid != 1 {
return nil, fmt.Errorf("Malformed response")
}
return responsePlaintext[2 : 2+int(responseLength)], nil
}

View File

@ -30,7 +30,7 @@ type PatternMatcher struct {
indirectVals map[string]interface{}
}
func NewPatternPatcher() *PatternMatcher {
func NewPatternMatcher() *PatternMatcher {
patternMatcher := PatternMatcher{
blockedPrefixes: critbitgo.NewTrie(),
blockedSuffixes: critbitgo.NewTrie(),
@ -51,7 +51,7 @@ func isGlobCandidate(str string) bool {
return false
}
func (patternMatcher *PatternMatcher) Add(pattern string, val interface{}, position int) (PatternType, error) {
func (patternMatcher *PatternMatcher) Add(pattern string, val interface{}, position int) error {
leadingStar := strings.HasPrefix(pattern, "*")
trailingStar := strings.HasSuffix(pattern, "*")
exact := strings.HasPrefix(pattern, "=")
@ -60,24 +60,24 @@ func (patternMatcher *PatternMatcher) Add(pattern string, val interface{}, posit
patternType = PatternTypePattern
_, err := filepath.Match(pattern, "example.com")
if len(pattern) < 2 || err != nil {
return patternType, fmt.Errorf("Syntax error in block rules at pattern %d", position)
return fmt.Errorf("Syntax error in block rules at pattern %d", position)
}
} else if leadingStar && trailingStar {
patternType = PatternTypeSubstring
if len(pattern) < 3 {
return patternType, fmt.Errorf("Syntax error in block rules at pattern %d", position)
return fmt.Errorf("Syntax error in block rules at pattern %d", position)
}
pattern = pattern[1 : len(pattern)-1]
} else if trailingStar {
patternType = PatternTypePrefix
if len(pattern) < 2 {
return patternType, fmt.Errorf("Syntax error in block rules at pattern %d", position)
return fmt.Errorf("Syntax error in block rules at pattern %d", position)
}
pattern = pattern[:len(pattern)-1]
} else if exact {
patternType = PatternTypeExact
if len(pattern) < 2 {
return patternType, fmt.Errorf("Syntax error in block rules at pattern %d", position)
return fmt.Errorf("Syntax error in block rules at pattern %d", position)
}
pattern = pattern[1:]
} else {
@ -112,7 +112,7 @@ func (patternMatcher *PatternMatcher) Add(pattern string, val interface{}, posit
default:
dlog.Fatal("Unexpected block type")
}
return patternType, nil
return nil
}
func (patternMatcher *PatternMatcher) Eval(qName string) (reject bool, reason string, val interface{}) {
@ -120,9 +120,13 @@ func (patternMatcher *PatternMatcher) Eval(qName string) (reject bool, reason st
return false, "", nil
}
if xval := patternMatcher.blockedExact[qName]; xval != nil {
return true, qName, xval
}
revQname := StringReverse(qName)
if match, xval, found := patternMatcher.blockedSuffixes.LongestPrefix([]byte(revQname)); found {
if len(match) == len(qName) || revQname[len(match)] == '.' {
if len(match) == len(revQname) || revQname[len(match)] == '.' {
return true, "*." + StringReverse(string(match)), xval
}
if len(match) < len(revQname) && len(revQname) > 0 {
@ -153,9 +157,5 @@ func (patternMatcher *PatternMatcher) Eval(qName string) (reject bool, reason st
}
}
if xval := patternMatcher.blockedExact[qName]; xval != nil {
return true, qName, xval
}
return false, "", nil
}

29
dnscrypt-proxy/pidfile.go Normal file
View File

@ -0,0 +1,29 @@
package main
import (
"flag"
"os"
"path/filepath"
"strconv"
"github.com/dchest/safefile"
)
var pidFile = flag.String("pidfile", "", "Store the PID into a file")
func PidFileCreate() error {
if pidFile == nil || len(*pidFile) == 0 {
return nil
}
if err := os.MkdirAll(filepath.Dir(*pidFile), 0o755); err != nil {
return err
}
return safefile.WriteFile(*pidFile, []byte(strconv.Itoa(os.Getpid())), 0o644)
}
func PidFileRemove() error {
if pidFile == nil || len(*pidFile) == 0 {
return nil
}
return os.Remove(*pidFile)
}

View File

@ -0,0 +1,157 @@
package main
import (
"errors"
"fmt"
"io"
"net"
"strings"
"time"
iradix "github.com/hashicorp/go-immutable-radix"
"github.com/jedisct1/dlog"
"github.com/miekg/dns"
)
type PluginAllowedIP struct {
allowedPrefixes *iradix.Tree
allowedIPs map[string]interface{}
logger io.Writer
format string
}
func (plugin *PluginAllowedIP) Name() string {
return "allow_ip"
}
func (plugin *PluginAllowedIP) Description() string {
return "Allows DNS queries containing specific IP addresses"
}
func (plugin *PluginAllowedIP) Init(proxy *Proxy) error {
dlog.Noticef("Loading the set of allowed IP rules from [%s]", proxy.allowedIPFile)
lines, err := ReadTextFile(proxy.allowedIPFile)
if err != nil {
return err
}
plugin.allowedPrefixes = iradix.New()
plugin.allowedIPs = make(map[string]interface{})
for lineNo, line := range strings.Split(lines, "\n") {
line = TrimAndStripInlineComments(line)
if len(line) == 0 {
continue
}
ip := net.ParseIP(line)
trailingStar := strings.HasSuffix(line, "*")
if len(line) < 2 || (ip != nil && trailingStar) {
dlog.Errorf("Suspicious allowed IP rule [%s] at line %d", line, lineNo)
continue
}
if trailingStar {
line = line[:len(line)-1]
}
if strings.HasSuffix(line, ":") || strings.HasSuffix(line, ".") {
line = line[:len(line)-1]
}
if len(line) == 0 {
dlog.Errorf("Empty allowed IP rule at line %d", lineNo)
continue
}
if strings.Contains(line, "*") {
dlog.Errorf("Invalid rule: [%s] - wildcards can only be used as a suffix at line %d", line, lineNo)
continue
}
line = strings.ToLower(line)
if trailingStar {
plugin.allowedPrefixes, _, _ = plugin.allowedPrefixes.Insert([]byte(line), 0)
} else {
plugin.allowedIPs[line] = true
}
}
if len(proxy.allowedIPLogFile) == 0 {
return nil
}
plugin.logger = Logger(proxy.logMaxSize, proxy.logMaxAge, proxy.logMaxBackups, proxy.allowedIPLogFile)
plugin.format = proxy.allowedIPFormat
return nil
}
func (plugin *PluginAllowedIP) Drop() error {
return nil
}
func (plugin *PluginAllowedIP) Reload() error {
return nil
}
func (plugin *PluginAllowedIP) Eval(pluginsState *PluginsState, msg *dns.Msg) error {
answers := msg.Answer
if len(answers) == 0 {
return nil
}
allowed, reason, ipStr := false, "", ""
for _, answer := range answers {
header := answer.Header()
Rrtype := header.Rrtype
if header.Class != dns.ClassINET || (Rrtype != dns.TypeA && Rrtype != dns.TypeAAAA) {
continue
}
if Rrtype == dns.TypeA {
ipStr = answer.(*dns.A).A.String()
} else if Rrtype == dns.TypeAAAA {
ipStr = answer.(*dns.AAAA).AAAA.String() // IPv4-mapped IPv6 addresses are converted to IPv4
}
if _, found := plugin.allowedIPs[ipStr]; found {
allowed, reason = true, ipStr
break
}
match, _, found := plugin.allowedPrefixes.Root().LongestPrefix([]byte(ipStr))
if found {
if len(match) == len(ipStr) || (ipStr[len(match)] == '.' || ipStr[len(match)] == ':') {
allowed, reason = true, string(match)+"*"
break
}
}
}
if allowed {
pluginsState.sessionData["whitelisted"] = true
if plugin.logger != nil {
qName := pluginsState.qName
var clientIPStr string
switch pluginsState.clientProto {
case "udp":
clientIPStr = (*pluginsState.clientAddr).(*net.UDPAddr).IP.String()
case "tcp", "local_doh":
clientIPStr = (*pluginsState.clientAddr).(*net.TCPAddr).IP.String()
default:
// Ignore internal flow.
return nil
}
var line string
if plugin.format == "tsv" {
now := time.Now()
year, month, day := now.Date()
hour, minute, second := now.Clock()
tsStr := fmt.Sprintf("[%d-%02d-%02d %02d:%02d:%02d]", year, int(month), day, hour, minute, second)
line = fmt.Sprintf(
"%s\t%s\t%s\t%s\t%s\n",
tsStr,
clientIPStr,
StringQuote(qName),
StringQuote(ipStr),
StringQuote(reason),
)
} else if plugin.format == "ltsv" {
line = fmt.Sprintf("time:%d\thost:%s\tqname:%s\tip:%s\tmessage:%s\n", time.Now().Unix(), clientIPStr, StringQuote(qName), StringQuote(ipStr), StringQuote(reason))
} else {
dlog.Fatalf("Unexpected log format: [%s]", plugin.format)
}
if plugin.logger == nil {
return errors.New("Log file not initialized")
}
_, _ = plugin.logger.Write([]byte(line))
}
}
return nil
}

View File

@ -0,0 +1,127 @@
package main
import (
"errors"
"fmt"
"io"
"net"
"strings"
"time"
"github.com/jedisct1/dlog"
"github.com/miekg/dns"
)
type PluginAllowName struct {
allWeeklyRanges *map[string]WeeklyRanges
patternMatcher *PatternMatcher
logger io.Writer
format string
}
func (plugin *PluginAllowName) Name() string {
return "allow_name"
}
func (plugin *PluginAllowName) Description() string {
return "Allow names matching patterns"
}
func (plugin *PluginAllowName) Init(proxy *Proxy) error {
dlog.Noticef("Loading the set of allowed names from [%s]", proxy.allowNameFile)
lines, err := ReadTextFile(proxy.allowNameFile)
if err != nil {
return err
}
plugin.allWeeklyRanges = proxy.allWeeklyRanges
plugin.patternMatcher = NewPatternMatcher()
for lineNo, line := range strings.Split(lines, "\n") {
line = TrimAndStripInlineComments(line)
if len(line) == 0 {
continue
}
parts := strings.Split(line, "@")
timeRangeName := ""
if len(parts) == 2 {
line = strings.TrimSpace(parts[0])
timeRangeName = strings.TrimSpace(parts[1])
} else if len(parts) > 2 {
dlog.Errorf("Syntax error in allowed names at line %d -- Unexpected @ character", 1+lineNo)
continue
}
var weeklyRanges *WeeklyRanges
if len(timeRangeName) > 0 {
weeklyRangesX, ok := (*plugin.allWeeklyRanges)[timeRangeName]
if !ok {
dlog.Errorf("Time range [%s] not found at line %d", timeRangeName, 1+lineNo)
} else {
weeklyRanges = &weeklyRangesX
}
}
if err := plugin.patternMatcher.Add(line, weeklyRanges, lineNo+1); err != nil {
dlog.Error(err)
continue
}
}
if len(proxy.allowNameLogFile) == 0 {
return nil
}
plugin.logger = Logger(proxy.logMaxSize, proxy.logMaxAge, proxy.logMaxBackups, proxy.allowNameLogFile)
plugin.format = proxy.allowNameFormat
return nil
}
func (plugin *PluginAllowName) Drop() error {
return nil
}
func (plugin *PluginAllowName) Reload() error {
return nil
}
func (plugin *PluginAllowName) Eval(pluginsState *PluginsState, msg *dns.Msg) error {
qName := pluginsState.qName
allowList, reason, xweeklyRanges := plugin.patternMatcher.Eval(qName)
var weeklyRanges *WeeklyRanges
if xweeklyRanges != nil {
weeklyRanges = xweeklyRanges.(*WeeklyRanges)
}
if allowList {
if weeklyRanges != nil && !weeklyRanges.Match() {
allowList = false
}
}
if allowList {
pluginsState.sessionData["whitelisted"] = true
if plugin.logger != nil {
var clientIPStr string
switch pluginsState.clientProto {
case "udp":
clientIPStr = (*pluginsState.clientAddr).(*net.UDPAddr).IP.String()
case "tcp", "local_doh":
clientIPStr = (*pluginsState.clientAddr).(*net.TCPAddr).IP.String()
default:
// Ignore internal flow.
return nil
}
var line string
if plugin.format == "tsv" {
now := time.Now()
year, month, day := now.Date()
hour, minute, second := now.Clock()
tsStr := fmt.Sprintf("[%d-%02d-%02d %02d:%02d:%02d]", year, int(month), day, hour, minute, second)
line = fmt.Sprintf("%s\t%s\t%s\t%s\n", tsStr, clientIPStr, StringQuote(qName), StringQuote(reason))
} else if plugin.format == "ltsv" {
line = fmt.Sprintf("time:%d\thost:%s\tqname:%s\tmessage:%s\n", time.Now().Unix(), clientIPStr, StringQuote(qName), StringQuote(reason))
} else {
dlog.Fatalf("Unexpected log format: [%s]", plugin.format)
}
if plugin.logger == nil {
return errors.New("Log file not initialized")
}
_, _ = plugin.logger.Write([]byte(line))
}
}
return nil
}

View File

@ -3,21 +3,20 @@ package main
import (
"errors"
"fmt"
"io"
"net"
"strings"
"time"
"unicode"
"github.com/hashicorp/go-immutable-radix"
iradix "github.com/hashicorp/go-immutable-radix"
"github.com/jedisct1/dlog"
"github.com/miekg/dns"
"gopkg.in/natefinch/lumberjack.v2"
)
type PluginBlockIP struct {
blockedPrefixes *iradix.Tree
blockedIPs map[string]interface{}
logger *lumberjack.Logger
logger io.Writer
format string
}
@ -31,15 +30,15 @@ func (plugin *PluginBlockIP) Description() string {
func (plugin *PluginBlockIP) Init(proxy *Proxy) error {
dlog.Noticef("Loading the set of IP blocking rules from [%s]", proxy.blockIPFile)
bin, err := ReadTextFile(proxy.blockIPFile)
lines, err := ReadTextFile(proxy.blockIPFile)
if err != nil {
return err
}
plugin.blockedPrefixes = iradix.New()
plugin.blockedIPs = make(map[string]interface{})
for lineNo, line := range strings.Split(string(bin), "\n") {
line = strings.TrimFunc(line, unicode.IsSpace)
if len(line) == 0 || strings.HasPrefix(line, "#") {
for lineNo, line := range strings.Split(lines, "\n") {
line = TrimAndStripInlineComments(line)
if len(line) == 0 {
continue
}
ip := net.ParseIP(line)
@ -72,7 +71,7 @@ func (plugin *PluginBlockIP) Init(proxy *Proxy) error {
if len(proxy.blockIPLogFile) == 0 {
return nil
}
plugin.logger = &lumberjack.Logger{LocalTime: true, MaxSize: proxy.logMaxSize, MaxAge: proxy.logMaxAge, MaxBackups: proxy.logMaxBackups, Filename: proxy.blockIPLogFile, Compress: true}
plugin.logger = Logger(proxy.logMaxSize, proxy.logMaxAge, proxy.logMaxBackups, proxy.blockIPLogFile)
plugin.format = proxy.blockIPFormat
return nil
@ -122,19 +121,16 @@ func (plugin *PluginBlockIP) Eval(pluginsState *PluginsState, msg *dns.Msg) erro
pluginsState.action = PluginsActionReject
pluginsState.returnCode = PluginsReturnCodeReject
if plugin.logger != nil {
questions := msg.Question
if len(questions) != 1 {
return nil
}
qName := strings.ToLower(StripTrailingDot(questions[0].Name))
if len(qName) < 2 {
return nil
}
qName := pluginsState.qName
var clientIPStr string
if pluginsState.clientProto == "udp" {
switch pluginsState.clientProto {
case "udp":
clientIPStr = (*pluginsState.clientAddr).(*net.UDPAddr).IP.String()
} else {
case "tcp", "local_doh":
clientIPStr = (*pluginsState.clientAddr).(*net.TCPAddr).IP.String()
default:
// Ignore internal flow.
return nil
}
var line string
if plugin.format == "tsv" {
@ -142,7 +138,14 @@ func (plugin *PluginBlockIP) Eval(pluginsState *PluginsState, msg *dns.Msg) erro
year, month, day := now.Date()
hour, minute, second := now.Clock()
tsStr := fmt.Sprintf("[%d-%02d-%02d %02d:%02d:%02d]", year, int(month), day, hour, minute, second)
line = fmt.Sprintf("%s\t%s\t%s\t%s\t%s\n", tsStr, clientIPStr, StringQuote(qName), StringQuote(ipStr), StringQuote(reason))
line = fmt.Sprintf(
"%s\t%s\t%s\t%s\t%s\n",
tsStr,
clientIPStr,
StringQuote(qName),
StringQuote(ipStr),
StringQuote(reason),
)
} else if plugin.format == "ltsv" {
line = fmt.Sprintf("time:%d\thost:%s\tqname:%s\tip:%s\tmessage:%s\n", time.Now().Unix(), clientIPStr, StringQuote(qName), StringQuote(ipStr), StringQuote(reason))
} else {
@ -151,7 +154,7 @@ func (plugin *PluginBlockIP) Eval(pluginsState *PluginsState, msg *dns.Msg) erro
if plugin.logger == nil {
return errors.New("Log file not initialized")
}
plugin.logger.Write([]byte(line))
_, _ = plugin.logger.Write([]byte(line))
}
}
return nil

View File

@ -29,23 +29,18 @@ func (plugin *PluginBlockIPv6) Reload() error {
}
func (plugin *PluginBlockIPv6) Eval(pluginsState *PluginsState, msg *dns.Msg) error {
questions := msg.Question
if len(questions) != 1 {
return nil
}
question := questions[0]
question := msg.Question[0]
if question.Qclass != dns.ClassINET || question.Qtype != dns.TypeAAAA {
return nil
}
synth, err := EmptyResponseFromMessage(msg)
if err != nil {
return err
}
synth := EmptyResponseFromMessage(msg)
hinfo := new(dns.HINFO)
hinfo.Hdr = dns.RR_Header{Name: question.Name, Rrtype: dns.TypeHINFO,
Class: dns.ClassINET, Ttl: 86400}
hinfo.Hdr = dns.RR_Header{
Name: question.Name, Rrtype: dns.TypeHINFO,
Class: dns.ClassINET, Ttl: 86400,
}
hinfo.Cpu = "AAAA queries have been locally blocked by dnscrypt-proxy"
hinfo.Os = "Set block_ipv6 to false to disable this feature"
hinfo.Os = "Set block_ipv6 to false to disable that feature"
synth.Answer = []dns.RR{hinfo}
qName := question.Name
i := strings.Index(qName, ".")
@ -61,8 +56,10 @@ func (plugin *PluginBlockIPv6) Eval(pluginsState *PluginsState, msg *dns.Msg) er
soa.Minttl = 2400
soa.Expire = 604800
soa.Retry = 300
soa.Hdr = dns.RR_Header{Name: parentZone, Rrtype: dns.TypeSOA,
Class: dns.ClassINET, Ttl: 60}
soa.Hdr = dns.RR_Header{
Name: parentZone, Rrtype: dns.TypeSOA,
Class: dns.ClassINET, Ttl: 60,
}
synth.Ns = []dns.RR{soa}
pluginsState.synthResponse = synth
pluginsState.action = PluginsActionSynth

View File

@ -3,23 +3,80 @@ package main
import (
"errors"
"fmt"
"io"
"net"
"strings"
"time"
"unicode"
"github.com/jedisct1/dlog"
"github.com/miekg/dns"
lumberjack "gopkg.in/natefinch/lumberjack.v2"
)
type PluginBlockName struct {
type BlockedNames struct {
allWeeklyRanges *map[string]WeeklyRanges
patternMatcher *PatternMatcher
logger *lumberjack.Logger
logger io.Writer
format string
}
const aliasesLimit = 8
var blockedNames *BlockedNames
func (blockedNames *BlockedNames) check(pluginsState *PluginsState, qName string, aliasFor *string) (bool, error) {
reject, reason, xweeklyRanges := blockedNames.patternMatcher.Eval(qName)
if aliasFor != nil {
reason = reason + " (alias for [" + *aliasFor + "])"
}
var weeklyRanges *WeeklyRanges
if xweeklyRanges != nil {
weeklyRanges = xweeklyRanges.(*WeeklyRanges)
}
if reject {
if weeklyRanges != nil && !weeklyRanges.Match() {
reject = false
}
}
if !reject {
return false, nil
}
pluginsState.action = PluginsActionReject
pluginsState.returnCode = PluginsReturnCodeReject
if blockedNames.logger != nil {
var clientIPStr string
switch pluginsState.clientProto {
case "udp":
clientIPStr = (*pluginsState.clientAddr).(*net.UDPAddr).IP.String()
case "tcp", "local_doh":
clientIPStr = (*pluginsState.clientAddr).(*net.TCPAddr).IP.String()
default:
// Ignore internal flow.
return false, nil
}
var line string
if blockedNames.format == "tsv" {
now := time.Now()
year, month, day := now.Date()
hour, minute, second := now.Clock()
tsStr := fmt.Sprintf("[%d-%02d-%02d %02d:%02d:%02d]", year, int(month), day, hour, minute, second)
line = fmt.Sprintf("%s\t%s\t%s\t%s\n", tsStr, clientIPStr, StringQuote(qName), StringQuote(reason))
} else if blockedNames.format == "ltsv" {
line = fmt.Sprintf("time:%d\thost:%s\tqname:%s\tmessage:%s\n", time.Now().Unix(), clientIPStr, StringQuote(qName), StringQuote(reason))
} else {
dlog.Fatalf("Unexpected log format: [%s]", blockedNames.format)
}
if blockedNames.logger == nil {
return false, errors.New("Log file not initialized")
}
_, _ = blockedNames.logger.Write([]byte(line))
}
return true, nil
}
// ---
type PluginBlockName struct{}
func (plugin *PluginBlockName) Name() string {
return "block_name"
}
@ -30,45 +87,48 @@ func (plugin *PluginBlockName) Description() string {
func (plugin *PluginBlockName) Init(proxy *Proxy) error {
dlog.Noticef("Loading the set of blocking rules from [%s]", proxy.blockNameFile)
bin, err := ReadTextFile(proxy.blockNameFile)
lines, err := ReadTextFile(proxy.blockNameFile)
if err != nil {
return err
}
plugin.allWeeklyRanges = proxy.allWeeklyRanges
plugin.patternMatcher = NewPatternPatcher()
for lineNo, line := range strings.Split(string(bin), "\n") {
line = strings.TrimFunc(line, unicode.IsSpace)
if len(line) == 0 || strings.HasPrefix(line, "#") {
xBlockedNames := BlockedNames{
allWeeklyRanges: proxy.allWeeklyRanges,
patternMatcher: NewPatternMatcher(),
}
for lineNo, line := range strings.Split(lines, "\n") {
line = TrimAndStripInlineComments(line)
if len(line) == 0 {
continue
}
parts := strings.Split(line, "@")
timeRangeName := ""
if len(parts) == 2 {
line = strings.TrimFunc(parts[0], unicode.IsSpace)
timeRangeName = strings.TrimFunc(parts[1], unicode.IsSpace)
line = strings.TrimSpace(parts[0])
timeRangeName = strings.TrimSpace(parts[1])
} else if len(parts) > 2 {
dlog.Errorf("Syntax error in block rules at line %d -- Unexpected @ character", 1+lineNo)
continue
}
var weeklyRanges *WeeklyRanges
if len(timeRangeName) > 0 {
weeklyRangesX, ok := (*plugin.allWeeklyRanges)[timeRangeName]
weeklyRangesX, ok := (*xBlockedNames.allWeeklyRanges)[timeRangeName]
if !ok {
dlog.Errorf("Time range [%s] not found at line %d", timeRangeName, 1+lineNo)
} else {
weeklyRanges = &weeklyRangesX
}
}
if _, err := plugin.patternMatcher.Add(line, weeklyRanges, lineNo+1); err != nil {
if err := xBlockedNames.patternMatcher.Add(line, weeklyRanges, lineNo+1); err != nil {
dlog.Error(err)
continue
}
}
blockedNames = &xBlockedNames
if len(proxy.blockNameLogFile) == 0 {
return nil
}
plugin.logger = &lumberjack.Logger{LocalTime: true, MaxSize: proxy.logMaxSize, MaxAge: proxy.logMaxAge, MaxBackups: proxy.logMaxBackups, Filename: proxy.blockNameLogFile, Compress: true}
plugin.format = proxy.blockNameFormat
blockedNames.logger = Logger(proxy.logMaxSize, proxy.logMaxAge, proxy.logMaxBackups, proxy.blockNameLogFile)
blockedNames.format = proxy.blockNameFormat
return nil
}
@ -82,50 +142,69 @@ func (plugin *PluginBlockName) Reload() error {
}
func (plugin *PluginBlockName) Eval(pluginsState *PluginsState, msg *dns.Msg) error {
if pluginsState.sessionData["whitelisted"] != nil {
if blockedNames == nil || pluginsState.sessionData["whitelisted"] != nil {
return nil
}
questions := msg.Question
if len(questions) != 1 {
_, err := blockedNames.check(pluginsState, pluginsState.qName, nil)
return err
}
// ---
type PluginBlockNameResponse struct{}
func (plugin *PluginBlockNameResponse) Name() string {
return "block_name"
}
func (plugin *PluginBlockNameResponse) Description() string {
return "Block DNS responses matching name patterns"
}
func (plugin *PluginBlockNameResponse) Init(proxy *Proxy) error {
return nil
}
func (plugin *PluginBlockNameResponse) Drop() error {
return nil
}
func (plugin *PluginBlockNameResponse) Reload() error {
return nil
}
func (plugin *PluginBlockNameResponse) Eval(pluginsState *PluginsState, msg *dns.Msg) error {
if blockedNames == nil || pluginsState.sessionData["whitelisted"] != nil {
return nil
}
qName := strings.ToLower(StripTrailingDot(questions[0].Name))
reject, reason, xweeklyRanges := plugin.patternMatcher.Eval(qName)
var weeklyRanges *WeeklyRanges
if xweeklyRanges != nil {
weeklyRanges = xweeklyRanges.(*WeeklyRanges)
}
if reject {
if weeklyRanges != nil && !weeklyRanges.Match() {
reject = false
aliasFor := pluginsState.qName
aliasesLeft := aliasesLimit
answers := msg.Answer
for _, answer := range answers {
header := answer.Header()
if header.Class != dns.ClassINET {
continue
}
}
if reject {
pluginsState.action = PluginsActionReject
pluginsState.returnCode = PluginsReturnCodeReject
if plugin.logger != nil {
var clientIPStr string
if pluginsState.clientProto == "udp" {
clientIPStr = (*pluginsState.clientAddr).(*net.UDPAddr).IP.String()
} else {
clientIPStr = (*pluginsState.clientAddr).(*net.TCPAddr).IP.String()
}
var line string
if plugin.format == "tsv" {
now := time.Now()
year, month, day := now.Date()
hour, minute, second := now.Clock()
tsStr := fmt.Sprintf("[%d-%02d-%02d %02d:%02d:%02d]", year, int(month), day, hour, minute, second)
line = fmt.Sprintf("%s\t%s\t%s\t%s\n", tsStr, clientIPStr, StringQuote(qName), StringQuote(reason))
} else if plugin.format == "ltsv" {
line = fmt.Sprintf("time:%d\thost:%s\tqname:%s\tmessage:%s\n", time.Now().Unix(), clientIPStr, StringQuote(qName), StringQuote(reason))
} else {
dlog.Fatalf("Unexpected log format: [%s]", plugin.format)
}
if plugin.logger == nil {
return errors.New("Log file not initialized")
}
plugin.logger.Write([]byte(line))
var target string
if header.Rrtype == dns.TypeCNAME {
target = answer.(*dns.CNAME).Target
} else if header.Rrtype == dns.TypeSVCB && answer.(*dns.SVCB).Priority == 0 {
target = answer.(*dns.SVCB).Target
} else if header.Rrtype == dns.TypeHTTPS && answer.(*dns.HTTPS).Priority == 0 {
target = answer.(*dns.HTTPS).Target
} else {
continue
}
target, err := NormalizeQName(target)
if err != nil {
return err
}
if blocked, err := blockedNames.check(pluginsState, target, &aliasFor); blocked || err != nil {
return err
}
aliasesLeft--
if aliasesLeft == 0 {
break
}
}
return nil

View File

@ -0,0 +1,202 @@
package main
import (
"github.com/k-sone/critbitgo"
"github.com/miekg/dns"
)
var undelegatedSet = []string{
"0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa",
"0.in-addr.arpa",
"1",
"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa",
"10.in-addr.arpa",
"100.100.in-addr.arpa",
"100.51.198.in-addr.arpa",
"101.100.in-addr.arpa",
"102.100.in-addr.arpa",
"103.100.in-addr.arpa",
"104.100.in-addr.arpa",
"105.100.in-addr.arpa",
"106.100.in-addr.arpa",
"107.100.in-addr.arpa",
"108.100.in-addr.arpa",
"109.100.in-addr.arpa",
"110.100.in-addr.arpa",
"111.100.in-addr.arpa",
"112.100.in-addr.arpa",
"113.0.203.in-addr.arpa",
"113.100.in-addr.arpa",
"114.100.in-addr.arpa",
"115.100.in-addr.arpa",
"116.100.in-addr.arpa",
"117.100.in-addr.arpa",
"118.100.in-addr.arpa",
"119.100.in-addr.arpa",
"120.100.in-addr.arpa",
"121.100.in-addr.arpa",
"122.100.in-addr.arpa",
"123.100.in-addr.arpa",
"124.100.in-addr.arpa",
"125.100.in-addr.arpa",
"126.100.in-addr.arpa",
"127.100.in-addr.arpa",
"127.in-addr.arpa",
"16.172.in-addr.arpa",
"168.192.in-addr.arpa",
"17.172.in-addr.arpa",
"18.172.in-addr.arpa",
"19.172.in-addr.arpa",
"2.0.192.in-addr.arpa",
"20.172.in-addr.arpa",
"21.172.in-addr.arpa",
"22.172.in-addr.arpa",
"23.172.in-addr.arpa",
"24.172.in-addr.arpa",
"25.172.in-addr.arpa",
"254.169.in-addr.arpa",
"255.255.255.255.in-addr.arpa",
"26.172.in-addr.arpa",
"27.172.in-addr.arpa",
"28.172.in-addr.arpa",
"29.172.in-addr.arpa",
"30.172.in-addr.arpa",
"31.172.in-addr.arpa",
"64.100.in-addr.arpa",
"65.100.in-addr.arpa",
"66.100.in-addr.arpa",
"67.100.in-addr.arpa",
"68.100.in-addr.arpa",
"69.100.in-addr.arpa",
"70.100.in-addr.arpa",
"71.100.in-addr.arpa",
"72.100.in-addr.arpa",
"73.100.in-addr.arpa",
"74.100.in-addr.arpa",
"75.100.in-addr.arpa",
"76.100.in-addr.arpa",
"77.100.in-addr.arpa",
"78.100.in-addr.arpa",
"79.100.in-addr.arpa",
"8.b.d.0.1.0.0.2.ip6.arpa",
"8.e.f.ip6.arpa",
"80.100.in-addr.arpa",
"81.100.in-addr.arpa",
"82.100.in-addr.arpa",
"83.100.in-addr.arpa",
"84.100.in-addr.arpa",
"85.100.in-addr.arpa",
"86.100.in-addr.arpa",
"87.100.in-addr.arpa",
"88.100.in-addr.arpa",
"89.100.in-addr.arpa",
"9.e.f.ip6.arpa",
"90.100.in-addr.arpa",
"91.100.in-addr.arpa",
"92.100.in-addr.arpa",
"93.100.in-addr.arpa",
"94.100.in-addr.arpa",
"95.100.in-addr.arpa",
"96.100.in-addr.arpa",
"97.100.in-addr.arpa",
"98.100.in-addr.arpa",
"99.100.in-addr.arpa",
"a.e.f.ip6.arpa",
"airdream",
"api",
"b.e.f.ip6.arpa",
"bbrouter",
"belkin",
"bind",
"blinkap",
"corp",
"d.f.ip6.arpa",
"davolink",
"dearmyrouter",
"dhcp",
"dlink",
"domain",
"envoy",
"example",
"f.f.ip6.arpa",
"fritz.box",
"grp",
"gw==",
"home",
"home.arpa",
"hub",
"internal",
"intra",
"intranet",
"invalid",
"ksyun",
"lan",
"loc",
"local",
"localdomain",
"localhost",
"localnet",
"mail",
"modem",
"mynet",
"myrouter",
"novalocal",
"onion",
"openstacklocal",
"priv",
"private",
"prv",
"router",
"telus",
"test",
"totolink",
"wlan_ap",
"workgroup",
"zghjccbob3n0",
}
type PluginBlockUndelegated struct {
suffixes *critbitgo.Trie
}
func (plugin *PluginBlockUndelegated) Name() string {
return "block_undelegated"
}
func (plugin *PluginBlockUndelegated) Description() string {
return "Block undelegated DNS names"
}
func (plugin *PluginBlockUndelegated) Init(proxy *Proxy) error {
suffixes := critbitgo.NewTrie()
for _, line := range undelegatedSet {
pattern := StringReverse(line)
suffixes.Insert([]byte(pattern), true)
}
plugin.suffixes = suffixes
return nil
}
func (plugin *PluginBlockUndelegated) Drop() error {
return nil
}
func (plugin *PluginBlockUndelegated) Reload() error {
return nil
}
func (plugin *PluginBlockUndelegated) Eval(pluginsState *PluginsState, msg *dns.Msg) error {
revQname := StringReverse(pluginsState.qName)
match, _, found := plugin.suffixes.LongestPrefix([]byte(revQname))
if !found {
return nil
}
if len(match) == len(revQname) || revQname[len(match)] == '.' {
synth := EmptyResponseFromMessage(msg)
synth.Rcode = dns.RcodeNameError
pluginsState.synthResponse = synth
pluginsState.action = PluginsActionSynth
pluginsState.returnCode = PluginsReturnCodeSynth
}
return nil
}

View File

@ -0,0 +1,46 @@
package main
import (
"strings"
"github.com/miekg/dns"
)
type PluginBlockUnqualified struct{}
func (plugin *PluginBlockUnqualified) Name() string {
return "block_unqualified"
}
func (plugin *PluginBlockUnqualified) Description() string {
return "Block unqualified DNS names"
}
func (plugin *PluginBlockUnqualified) Init(proxy *Proxy) error {
return nil
}
func (plugin *PluginBlockUnqualified) Drop() error {
return nil
}
func (plugin *PluginBlockUnqualified) Reload() error {
return nil
}
func (plugin *PluginBlockUnqualified) Eval(pluginsState *PluginsState, msg *dns.Msg) error {
question := msg.Question[0]
if question.Qclass != dns.ClassINET || (question.Qtype != dns.TypeA && question.Qtype != dns.TypeAAAA) {
return nil
}
if strings.IndexByte(pluginsState.qName, '.') >= 0 {
return nil
}
synth := EmptyResponseFromMessage(msg)
synth.Rcode = dns.RcodeNameError
pluginsState.synthResponse = synth
pluginsState.action = PluginsActionSynth
pluginsState.returnCode = PluginsReturnCodeSynth
return nil
}

View File

@ -3,14 +3,15 @@ package main
import (
"crypto/sha512"
"encoding/binary"
"errors"
"sync"
"time"
lru "github.com/hashicorp/golang-lru"
"github.com/miekg/dns"
sieve "github.com/opencoff/go-sieve"
)
const StaleResponseTTL = 30 * time.Second
type CachedResponse struct {
expiration time.Time
msg dns.Msg
@ -18,69 +19,33 @@ type CachedResponse struct {
type CachedResponses struct {
sync.RWMutex
cache *lru.ARCCache
cache *sieve.Sieve[[32]byte, CachedResponse]
}
var cachedResponses CachedResponses
type PluginCacheResponse struct {
cachedResponses *CachedResponses
}
func (plugin *PluginCacheResponse) Name() string {
return "cache_response"
}
func (plugin *PluginCacheResponse) Description() string {
return "DNS cache (writer)."
}
func (plugin *PluginCacheResponse) Init(proxy *Proxy) error {
return nil
}
func (plugin *PluginCacheResponse) Drop() error {
return nil
}
func (plugin *PluginCacheResponse) Reload() error {
return nil
}
func (plugin *PluginCacheResponse) Eval(pluginsState *PluginsState, msg *dns.Msg) error {
plugin.cachedResponses = &cachedResponses
if msg.Rcode != dns.RcodeSuccess && msg.Rcode != dns.RcodeNameError && msg.Rcode != dns.RcodeNotAuth {
return nil
func computeCacheKey(pluginsState *PluginsState, msg *dns.Msg) [32]byte {
question := msg.Question[0]
h := sha512.New512_256()
var tmp [5]byte
binary.LittleEndian.PutUint16(tmp[0:2], question.Qtype)
binary.LittleEndian.PutUint16(tmp[2:4], question.Qclass)
if pluginsState.dnssec {
tmp[4] = 1
}
if msg.Truncated {
return nil
}
cacheKey, err := computeCacheKey(pluginsState, msg)
if err != nil {
return err
}
ttl := getMinTTL(msg, pluginsState.cacheMinTTL, pluginsState.cacheMaxTTL, pluginsState.cacheNegMinTTL, pluginsState.cacheNegMaxTTL)
cachedResponse := CachedResponse{
expiration: time.Now().Add(ttl),
msg: *msg,
}
plugin.cachedResponses.Lock()
defer plugin.cachedResponses.Unlock()
if plugin.cachedResponses.cache == nil {
plugin.cachedResponses.cache, err = lru.NewARC(pluginsState.cacheSize)
if err != nil {
return err
}
}
plugin.cachedResponses.cache.Add(cacheKey, cachedResponse)
updateTTL(msg, cachedResponse.expiration)
h.Write(tmp[:])
normalizedRawQName := []byte(question.Name)
NormalizeRawQName(&normalizedRawQName)
h.Write(normalizedRawQName)
var sum [32]byte
h.Sum(sum[:0])
return nil
return sum
}
type PluginCache struct {
cachedResponses *CachedResponses
}
// ---
type PluginCache struct{}
func (plugin *PluginCache) Name() string {
return "cache"
@ -103,57 +68,97 @@ func (plugin *PluginCache) Reload() error {
}
func (plugin *PluginCache) Eval(pluginsState *PluginsState, msg *dns.Msg) error {
plugin.cachedResponses = &cachedResponses
cacheKey := computeCacheKey(pluginsState, msg)
cacheKey, err := computeCacheKey(pluginsState, msg)
if err != nil {
cachedResponses.RLock()
if cachedResponses.cache == nil {
cachedResponses.RUnlock()
return nil
}
plugin.cachedResponses.RLock()
defer plugin.cachedResponses.RUnlock()
if plugin.cachedResponses.cache == nil {
return nil
}
cachedAny, ok := plugin.cachedResponses.cache.Get(cacheKey)
cached, ok := cachedResponses.cache.Get(cacheKey)
if !ok {
cachedResponses.RUnlock()
return nil
}
cached := cachedAny.(CachedResponse)
if time.Now().After(cached.expiration) {
return nil
}
expiration := cached.expiration
synth := cached.msg.Copy()
cachedResponses.RUnlock()
updateTTL(&cached.msg, cached.expiration)
synth := cached.msg
synth.Id = msg.Id
synth.Response = true
synth.Compress = true
synth.Question = msg.Question
pluginsState.synthResponse = &synth
if time.Now().After(expiration) {
expiration2 := time.Now().Add(StaleResponseTTL)
updateTTL(synth, expiration2)
pluginsState.sessionData["stale"] = synth
return nil
}
updateTTL(synth, expiration)
pluginsState.synthResponse = synth
pluginsState.action = PluginsActionSynth
pluginsState.cacheHit = true
return nil
}
func computeCacheKey(pluginsState *PluginsState, msg *dns.Msg) ([32]byte, error) {
questions := msg.Question
if len(questions) != 1 {
return [32]byte{}, errors.New("No question present")
}
question := questions[0]
h := sha512.New512_256()
var tmp [5]byte
binary.LittleEndian.PutUint16(tmp[0:2], question.Qtype)
binary.LittleEndian.PutUint16(tmp[2:4], question.Qclass)
if pluginsState.dnssec {
tmp[4] = 1
}
h.Write(tmp[:])
normalizedName := []byte(question.Name)
NormalizeName(&normalizedName)
h.Write(normalizedName)
var sum [32]byte
h.Sum(sum[:0])
return sum, nil
// ---
type PluginCacheResponse struct{}
func (plugin *PluginCacheResponse) Name() string {
return "cache_response"
}
func (plugin *PluginCacheResponse) Description() string {
return "DNS cache (writer)."
}
func (plugin *PluginCacheResponse) Init(proxy *Proxy) error {
return nil
}
func (plugin *PluginCacheResponse) Drop() error {
return nil
}
func (plugin *PluginCacheResponse) Reload() error {
return nil
}
func (plugin *PluginCacheResponse) Eval(pluginsState *PluginsState, msg *dns.Msg) error {
if msg.Rcode != dns.RcodeSuccess && msg.Rcode != dns.RcodeNameError && msg.Rcode != dns.RcodeNotAuth {
return nil
}
if msg.Truncated {
return nil
}
cacheKey := computeCacheKey(pluginsState, msg)
ttl := getMinTTL(
msg,
pluginsState.cacheMinTTL,
pluginsState.cacheMaxTTL,
pluginsState.cacheNegMinTTL,
pluginsState.cacheNegMaxTTL,
)
cachedResponse := CachedResponse{
expiration: time.Now().Add(ttl),
msg: *msg,
}
cachedResponses.Lock()
if cachedResponses.cache == nil {
var err error
cachedResponses.cache = sieve.New[[32]byte, CachedResponse](pluginsState.cacheSize)
if cachedResponses.cache == nil {
cachedResponses.Unlock()
return err
}
}
cachedResponses.cache.Add(cacheKey, cachedResponse)
cachedResponses.Unlock()
updateTTL(msg, cachedResponse.expiration)
return nil
}

View File

@ -0,0 +1,44 @@
package main
import (
"github.com/jedisct1/dlog"
"github.com/miekg/dns"
)
type PluginCaptivePortal struct {
captivePortalMap *CaptivePortalMap
}
func (plugin *PluginCaptivePortal) Name() string {
return "captive portal handlers"
}
func (plugin *PluginCaptivePortal) Description() string {
return "Handle test queries operating systems make to detect Wi-Fi captive portal"
}
func (plugin *PluginCaptivePortal) Init(proxy *Proxy) error {
plugin.captivePortalMap = proxy.captivePortalMap
dlog.Notice("Captive portals handler enabled")
return nil
}
func (plugin *PluginCaptivePortal) Drop() error {
return nil
}
func (plugin *PluginCaptivePortal) Reload() error {
return nil
}
func (plugin *PluginCaptivePortal) Eval(pluginsState *PluginsState, msg *dns.Msg) error {
question, ips := plugin.captivePortalMap.GetEntry(msg)
if ips == nil {
return nil
}
if synth := HandleCaptivePortalQuery(msg, question, ips); synth != nil {
pluginsState.synthResponse = synth
pluginsState.action = PluginsActionSynth
}
return nil
}

View File

@ -19,12 +19,14 @@ type CloakedName struct {
lastUpdate *time.Time
lineNo int
isIP bool
PTR []string
}
type PluginCloak struct {
sync.RWMutex
patternMatcher *PatternMatcher
ttl uint32
createPTR bool
}
func (plugin *PluginCloak) Name() string {
@ -37,23 +39,24 @@ func (plugin *PluginCloak) Description() string {
func (plugin *PluginCloak) Init(proxy *Proxy) error {
dlog.Noticef("Loading the set of cloaking rules from [%s]", proxy.cloakFile)
bin, err := ReadTextFile(proxy.cloakFile)
lines, err := ReadTextFile(proxy.cloakFile)
if err != nil {
return err
}
plugin.ttl = proxy.cacheMinTTL
plugin.patternMatcher = NewPatternPatcher()
plugin.ttl = proxy.cloakTTL
plugin.createPTR = proxy.cloakedPTR
plugin.patternMatcher = NewPatternMatcher()
cloakedNames := make(map[string]*CloakedName)
for lineNo, line := range strings.Split(string(bin), "\n") {
line = strings.TrimFunc(line, unicode.IsSpace)
if len(line) == 0 || strings.HasPrefix(line, "#") {
for lineNo, line := range strings.Split(lines, "\n") {
line = TrimAndStripInlineComments(line)
if len(line) == 0 {
continue
}
var target string
parts := strings.FieldsFunc(line, unicode.IsSpace)
if len(parts) == 2 {
line = strings.TrimFunc(parts[0], unicode.IsSpace)
target = strings.TrimFunc(parts[1], unicode.IsSpace)
line = strings.TrimSpace(parts[0])
target = strings.TrimSpace(parts[1])
} else if len(parts) > 2 {
dlog.Errorf("Syntax error in cloaking rules at line %d -- Unexpected space character", 1+lineNo)
continue
@ -67,11 +70,12 @@ func (plugin *PluginCloak) Init(proxy *Proxy) error {
if !found {
cloakedName = &CloakedName{}
}
if ip := net.ParseIP(target); ip != nil {
ip := net.ParseIP(target)
if ip != nil {
if ipv4 := ip.To4(); ipv4 != nil {
cloakedName.ipv4 = append((*cloakedName).ipv4, ipv4)
cloakedName.ipv4 = append(cloakedName.ipv4, ipv4)
} else if ipv6 := ip.To16(); ipv6 != nil {
cloakedName.ipv6 = append((*cloakedName).ipv6, ipv6)
cloakedName.ipv6 = append(cloakedName.ipv6, ipv6)
} else {
dlog.Errorf("Invalid IP address in cloaking rule at line %d", 1+lineNo)
continue
@ -82,13 +86,46 @@ func (plugin *PluginCloak) Init(proxy *Proxy) error {
}
cloakedName.lineNo = lineNo + 1
cloakedNames[line] = cloakedName
if !plugin.createPTR || strings.Contains(line, "*") || !cloakedName.isIP {
continue
}
var ptrLine string
if ipv4 := ip.To4(); ipv4 != nil {
reversed, _ := dns.ReverseAddr(ip.To4().String())
ptrLine = strings.TrimSuffix(reversed, ".")
} else {
reversed, _ := dns.ReverseAddr(cloakedName.ipv6[0].To16().String())
ptrLine = strings.TrimSuffix(reversed, ".")
}
ptrQueryLine := ptrEntryToQuery(ptrLine)
ptrCloakedName, found := cloakedNames[ptrQueryLine]
if !found {
ptrCloakedName = &CloakedName{}
}
ptrCloakedName.isIP = true
ptrCloakedName.PTR = append((*ptrCloakedName).PTR, ptrNameToFQDN(line))
ptrCloakedName.lineNo = lineNo + 1
cloakedNames[ptrQueryLine] = ptrCloakedName
}
for line, cloakedName := range cloakedNames {
plugin.patternMatcher.Add(line, cloakedName, cloakedName.lineNo)
if err := plugin.patternMatcher.Add(line, cloakedName, cloakedName.lineNo); err != nil {
return err
}
}
return nil
}
func ptrEntryToQuery(ptrEntry string) string {
return "=" + ptrEntry
}
func ptrNameToFQDN(ptrLine string) string {
ptrLine = strings.TrimPrefix(ptrLine, "=")
return ptrLine + "."
}
func (plugin *PluginCloak) Drop() error {
return nil
}
@ -98,25 +135,23 @@ func (plugin *PluginCloak) Reload() error {
}
func (plugin *PluginCloak) Eval(pluginsState *PluginsState, msg *dns.Msg) error {
questions := msg.Question
if len(questions) != 1 {
return nil
}
question := questions[0]
if question.Qclass != dns.ClassINET || (question.Qtype != dns.TypeA && question.Qtype != dns.TypeAAAA) {
return nil
}
qName := strings.ToLower(StripTrailingDot(questions[0].Name))
if len(qName) < 2 {
question := msg.Question[0]
if question.Qclass != dns.ClassINET || question.Qtype == dns.TypeNS || question.Qtype == dns.TypeSOA {
return nil
}
now := time.Now()
plugin.RLock()
_, _, xcloakedName := plugin.patternMatcher.Eval(qName)
_, _, xcloakedName := plugin.patternMatcher.Eval(pluginsState.qName)
if xcloakedName == nil {
plugin.RUnlock()
return nil
}
if question.Qtype != dns.TypeA && question.Qtype != dns.TypeAAAA && question.Qtype != dns.TypePTR {
plugin.RUnlock()
pluginsState.action = PluginsActionReject
pluginsState.returnCode = PluginsReturnCodeCloak
return nil
}
cloakedName := xcloakedName.(*CloakedName)
ttl, expired := plugin.ttl, false
if cloakedName.lastUpdate != nil {
@ -153,36 +188,35 @@ func (plugin *PluginCloak) Eval(pluginsState *PluginsState, msg *dns.Msg) error
plugin.Unlock()
plugin.RLock()
}
var ip *net.IP
if question.Qtype == dns.TypeA {
ipLen := len(cloakedName.ipv4)
if ipLen > 0 {
ip = &cloakedName.ipv4[rand.Intn(ipLen)]
}
} else {
ipLen := len(cloakedName.ipv6)
if ipLen > 0 {
ip = &cloakedName.ipv6[rand.Intn(ipLen)]
}
}
plugin.RUnlock()
synth, err := EmptyResponseFromMessage(msg)
if err != nil {
return err
}
if ip == nil {
synth.Answer = []dns.RR{}
} else if question.Qtype == dns.TypeA {
rr := new(dns.A)
rr.Hdr = dns.RR_Header{Name: question.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: ttl}
rr.A = *ip
synth.Answer = []dns.RR{rr}
} else {
rr := new(dns.AAAA)
rr.Hdr = dns.RR_Header{Name: question.Name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: ttl}
rr.AAAA = *ip
synth.Answer = []dns.RR{rr}
synth := EmptyResponseFromMessage(msg)
synth.Answer = []dns.RR{}
if question.Qtype == dns.TypeA {
for _, ip := range cloakedName.ipv4 {
rr := new(dns.A)
rr.Hdr = dns.RR_Header{Name: question.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: ttl}
rr.A = ip
synth.Answer = append(synth.Answer, rr)
}
} else if question.Qtype == dns.TypeAAAA {
for _, ip := range cloakedName.ipv6 {
rr := new(dns.AAAA)
rr.Hdr = dns.RR_Header{Name: question.Name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: ttl}
rr.AAAA = ip
synth.Answer = append(synth.Answer, rr)
}
} else if question.Qtype == dns.TypePTR {
for _, ptr := range cloakedName.PTR {
rr := new(dns.PTR)
rr.Hdr = dns.RR_Header{Name: question.Name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: ttl}
rr.Ptr = ptr
synth.Answer = append(synth.Answer, rr)
}
}
rand.Shuffle(
len(synth.Answer),
func(i, j int) { synth.Answer[i], synth.Answer[j] = synth.Answer[j], synth.Answer[i] },
)
pluginsState.synthResponse = synth
pluginsState.action = PluginsActionSynth
pluginsState.returnCode = PluginsReturnCodeCloak

View File

@ -0,0 +1,265 @@
package main
import (
"errors"
"net"
"sync"
"time"
"github.com/jedisct1/dlog"
"github.com/miekg/dns"
)
const rfc7050WKN = "ipv4only.arpa."
var (
rfc7050WKA1 = net.IPv4(192, 0, 0, 170)
rfc7050WKA2 = net.IPv4(192, 0, 0, 171)
)
type PluginDNS64 struct {
pref64Mutex *sync.RWMutex
pref64 []*net.IPNet
dns64Resolvers []string
ipv4Resolver string
proxy *Proxy
}
func (plugin *PluginDNS64) Name() string {
return "dns64"
}
func (plugin *PluginDNS64) Description() string {
return "Synthesize DNS64 AAAA responses"
}
func (plugin *PluginDNS64) Init(proxy *Proxy) error {
if len(proxy.listenAddresses) == 0 {
return errors.New("At least one listening IP address must be configured for the DNS64 plugin to work")
}
plugin.ipv4Resolver = proxy.listenAddresses[0] // query is sent to ourselves
plugin.pref64Mutex = new(sync.RWMutex)
plugin.proxy = proxy
if len(proxy.dns64Prefixes) != 0 {
plugin.pref64Mutex.Lock()
defer plugin.pref64Mutex.Unlock()
for _, prefStr := range proxy.dns64Prefixes {
_, pref, err := net.ParseCIDR(prefStr)
if err != nil {
return err
}
dlog.Noticef("Registered DNS64 prefix [%s]", pref.String())
plugin.pref64 = append(plugin.pref64, pref)
}
} else if len(proxy.dns64Resolvers) != 0 {
plugin.dns64Resolvers = proxy.dns64Resolvers
if err := plugin.refreshPref64(); err != nil {
return err
}
} else {
return nil
}
dlog.Notice("DNS64 map enabled")
return nil
}
func (plugin *PluginDNS64) Drop() error {
return nil
}
func (plugin *PluginDNS64) Reload() error {
return nil
}
func (plugin *PluginDNS64) Eval(pluginsState *PluginsState, msg *dns.Msg) error {
if hasAAAAAnswer(msg) {
return nil
}
question := pluginsState.questionMsg.Question[0]
if question.Qclass != dns.ClassINET || question.Qtype != dns.TypeAAAA {
return nil
}
msgA := pluginsState.questionMsg.Copy()
msgA.SetQuestion(question.Name, dns.TypeA)
msgAPacket, err := msgA.Pack()
if err != nil {
return err
}
if !plugin.proxy.clientsCountInc() {
return errors.New("Too many concurrent connections to handle DNS64 subqueries")
}
respPacket := plugin.proxy.processIncomingQuery(
"trampoline",
plugin.proxy.mainProto,
msgAPacket,
nil,
nil,
time.Now(),
false,
)
plugin.proxy.clientsCountDec()
resp := dns.Msg{}
if err := resp.Unpack(respPacket); err != nil {
return err
}
if resp.Rcode != dns.RcodeSuccess {
return nil
}
if len(resp.Answer) == 0 {
return nil
}
initialTTL := uint32(600)
for _, ns := range resp.Ns {
header := ns.Header()
if header.Rrtype == dns.TypeSOA {
initialTTL = header.Ttl
}
}
synth64 := make([]dns.RR, 0)
for _, answer := range resp.Answer {
header := answer.Header()
if header.Rrtype == dns.TypeCNAME {
synth64 = append(synth64, answer)
} else if header.Rrtype == dns.TypeA {
ttl := initialTTL
if ttl > header.Ttl {
ttl = header.Ttl
}
ipv4 := answer.(*dns.A).A.To4()
if ipv4 != nil {
plugin.pref64Mutex.RLock()
for _, prefix := range plugin.pref64 {
ipv6 := translateToIPv6(ipv4, prefix)
synthAAAA := new(dns.AAAA)
synthAAAA.Hdr = dns.RR_Header{
Name: header.Name,
Rrtype: dns.TypeAAAA,
Class: header.Class,
Ttl: ttl,
}
synthAAAA.AAAA = ipv6
synth64 = append(synth64, synthAAAA)
}
plugin.pref64Mutex.RUnlock()
}
}
}
msg.Answer = synth64
msg.AuthenticatedData = false
msg.SetEdns0(uint16(MaxDNSUDPSafePacketSize), false)
pluginsState.returnCode = PluginsReturnCodeCloak
return nil
}
func hasAAAAAnswer(msg *dns.Msg) bool {
for _, answer := range msg.Answer {
if answer.Header().Rrtype == dns.TypeAAAA {
return true
}
}
return false
}
func translateToIPv6(ipv4 net.IP, prefix *net.IPNet) net.IP {
ipv6 := make(net.IP, net.IPv6len)
copy(ipv6, prefix.IP)
n, _ := prefix.Mask.Size()
ipShift := n / 8
for i := 0; i < net.IPv4len; i++ {
if ipShift+i == 8 {
ipShift++
}
ipv6[ipShift+i] = ipv4[i]
}
return ipv6
}
func (plugin *PluginDNS64) fetchPref64(resolver string) error {
msg := new(dns.Msg)
msg.SetQuestion(rfc7050WKN, dns.TypeAAAA)
client := new(dns.Client)
resp, _, err := client.Exchange(msg, resolver)
if err != nil {
return err
}
if resp == nil || resp.Rcode != dns.RcodeSuccess {
return errors.New("Unable to fetch Pref64")
}
uniqPrefixes := make(map[string]struct{})
prefixes := make([]*net.IPNet, 0)
for _, answer := range resp.Answer {
if answer.Header().Rrtype == dns.TypeAAAA {
ipv6 := answer.(*dns.AAAA).AAAA
if ipv6 != nil && len(ipv6) == net.IPv6len {
prefEnd := 0
if wka := net.IPv4(ipv6[12], ipv6[13], ipv6[14], ipv6[15]); wka.Equal(rfc7050WKA1) ||
wka.Equal(rfc7050WKA2) { // 96
prefEnd = 12
} else if wka := net.IPv4(ipv6[9], ipv6[10], ipv6[11], ipv6[12]); wka.Equal(rfc7050WKA1) || wka.Equal(rfc7050WKA2) { // 64
prefEnd = 8
} else if wka := net.IPv4(ipv6[7], ipv6[9], ipv6[10], ipv6[11]); wka.Equal(rfc7050WKA1) || wka.Equal(rfc7050WKA2) { // 56
prefEnd = 7
} else if wka := net.IPv4(ipv6[6], ipv6[7], ipv6[9], ipv6[10]); wka.Equal(rfc7050WKA1) || wka.Equal(rfc7050WKA2) { // 48
prefEnd = 6
} else if wka := net.IPv4(ipv6[5], ipv6[6], ipv6[7], ipv6[9]); wka.Equal(rfc7050WKA1) || wka.Equal(rfc7050WKA2) { // 40
prefEnd = 5
} else if wka := net.IPv4(ipv6[4], ipv6[5], ipv6[6], ipv6[7]); wka.Equal(rfc7050WKA1) || wka.Equal(rfc7050WKA2) { // 32
prefEnd = 4
}
if prefEnd > 0 {
prefix := new(net.IPNet)
prefix.IP = append(ipv6[:prefEnd], net.IPv6zero[prefEnd:]...)
prefix.Mask = net.CIDRMask(prefEnd*8, 128)
if _, ok := uniqPrefixes[prefix.String()]; !ok {
prefixes = append(prefixes, prefix)
uniqPrefixes[prefix.String()] = struct{}{}
dlog.Infof("Registered DNS64 prefix [%s]", prefix.String())
}
}
}
}
}
if len(prefixes) == 0 {
return errors.New("Empty Pref64 list")
}
plugin.pref64Mutex.Lock()
defer plugin.pref64Mutex.Unlock()
plugin.pref64 = prefixes
return nil
}
func (plugin *PluginDNS64) refreshPref64() error {
for _, resolver := range plugin.dns64Resolvers {
if err := plugin.fetchPref64(resolver); err == nil {
break
}
}
plugin.pref64Mutex.RLock()
defer plugin.pref64Mutex.RUnlock()
if len(plugin.pref64) == 0 {
return errors.New("Empty Pref64 list")
}
return nil
}

View File

@ -0,0 +1,80 @@
package main
import (
"math/rand"
"net"
"github.com/jedisct1/dlog"
"github.com/miekg/dns"
)
type PluginECS struct {
nets []*net.IPNet
}
func (plugin *PluginECS) Name() string {
return "ecs"
}
func (plugin *PluginECS) Description() string {
return "Set EDNS-client-subnet information in outgoing queries."
}
func (plugin *PluginECS) Init(proxy *Proxy) error {
plugin.nets = proxy.ednsClientSubnets
dlog.Notice("ECS plugin enabled")
return nil
}
func (plugin *PluginECS) Drop() error {
return nil
}
func (plugin *PluginECS) Reload() error {
return nil
}
func (plugin *PluginECS) Eval(pluginsState *PluginsState, msg *dns.Msg) error {
var options *[]dns.EDNS0
for _, extra := range msg.Extra {
if extra.Header().Rrtype == dns.TypeOPT {
options = &extra.(*dns.OPT).Option
for _, option := range *options {
if option.Option() == dns.EDNS0SUBNET {
return nil
}
}
break
}
}
if options == nil {
msg.SetEdns0(uint16(pluginsState.maxPayloadSize), false)
for _, extra := range msg.Extra {
if extra.Header().Rrtype == dns.TypeOPT {
options = &extra.(*dns.OPT).Option
break
}
}
}
if options == nil {
return nil
}
prr := dns.EDNS0_SUBNET{}
prr.Code = dns.EDNS0SUBNET
net := plugin.nets[rand.Intn(len(plugin.nets))]
bits, totalSize := net.Mask.Size()
if totalSize == 32 {
prr.Family = 1
} else if totalSize == 128 {
prr.Family = 2
} else {
return nil
}
prr.SourceNetmask = uint8(bits)
prr.SourceScope = 0
prr.Address = net.IP
*options = append(*options, &prr)
return nil
}

View File

@ -0,0 +1,53 @@
// Work around Mozilla's evil plan - https://sk.tl/3Ek6tzhq
package main
import (
"strings"
"github.com/jedisct1/dlog"
"github.com/miekg/dns"
)
type PluginFirefox struct{}
func (plugin *PluginFirefox) Name() string {
return "firefox"
}
func (plugin *PluginFirefox) Description() string {
return "Work around Firefox taking over DNS"
}
func (plugin *PluginFirefox) Init(proxy *Proxy) error {
dlog.Noticef("Firefox workaround initialized")
return nil
}
func (plugin *PluginFirefox) Drop() error {
return nil
}
func (plugin *PluginFirefox) Reload() error {
return nil
}
func (plugin *PluginFirefox) Eval(pluginsState *PluginsState, msg *dns.Msg) error {
if pluginsState.clientProto == "local_doh" {
return nil
}
question := msg.Question[0]
if question.Qclass != dns.ClassINET || (question.Qtype != dns.TypeA && question.Qtype != dns.TypeAAAA) {
return nil
}
qName := pluginsState.qName
if qName != "use-application-dns.net" && !strings.HasSuffix(qName, ".use-application-dns.net") {
return nil
}
synth := EmptyResponseFromMessage(msg)
synth.Rcode = dns.RcodeNameError
pluginsState.synthResponse = synth
pluginsState.action = PluginsActionSynth
pluginsState.returnCode = PluginsReturnCodeSynth
return nil
}

View File

@ -5,7 +5,6 @@ import (
"math/rand"
"net"
"strings"
"unicode"
"github.com/jedisct1/dlog"
"github.com/miekg/dns"
@ -30,33 +29,44 @@ func (plugin *PluginForward) Description() string {
func (plugin *PluginForward) Init(proxy *Proxy) error {
dlog.Noticef("Loading the set of forwarding rules from [%s]", proxy.forwardFile)
bin, err := ReadTextFile(proxy.forwardFile)
lines, err := ReadTextFile(proxy.forwardFile)
if err != nil {
return err
}
for lineNo, line := range strings.Split(string(bin), "\n") {
line = strings.TrimFunc(line, unicode.IsSpace)
if len(line) == 0 || strings.HasPrefix(line, "#") {
for lineNo, line := range strings.Split(lines, "\n") {
line = TrimAndStripInlineComments(line)
if len(line) == 0 {
continue
}
domain, serversStr, ok := StringTwoFields(line)
if !ok {
return fmt.Errorf("Syntax error for a forwarding rule at line %d. Expected syntax: example.com: 9.9.9.9,8.8.8.8", 1+lineNo)
return fmt.Errorf(
"Syntax error for a forwarding rule at line %d. Expected syntax: example.com 9.9.9.9,8.8.8.8",
1+lineNo,
)
}
domain = strings.ToLower(domain)
var servers []string
for _, server := range strings.Split(serversStr, ",") {
server = strings.TrimFunc(server, unicode.IsSpace)
if net.ParseIP(server) != nil {
server = fmt.Sprintf("%s:%d", server, 53)
server = strings.TrimSpace(server)
server = strings.TrimPrefix(server, "[")
server = strings.TrimSuffix(server, "]")
if ip := net.ParseIP(server); ip != nil {
if ip.To4() != nil {
server = fmt.Sprintf("%s:%d", server, 53)
} else {
server = fmt.Sprintf("[%s]:%d", server, 53)
}
}
dlog.Infof("Forwarding [%s] to %s", domain, server)
servers = append(servers, server)
}
if len(servers) == 0 {
continue
}
plugin.forwardMap = append(plugin.forwardMap, PluginForwardEntry{
domain: domain, servers: servers,
domain: domain,
servers: servers,
})
}
return nil
@ -71,19 +81,17 @@ func (plugin *PluginForward) Reload() error {
}
func (plugin *PluginForward) Eval(pluginsState *PluginsState, msg *dns.Msg) error {
questions := msg.Question
if len(questions) != 1 {
return nil
}
question := strings.ToLower(StripTrailingDot(questions[0].Name))
questionLen := len(question)
qName := pluginsState.qName
qNameLen := len(qName)
var servers []string
for _, candidate := range plugin.forwardMap {
candidateLen := len(candidate.domain)
if candidateLen > questionLen {
if candidateLen > qNameLen {
continue
}
if question[questionLen-candidateLen:] == candidate.domain && (candidateLen == questionLen || (question[questionLen-candidateLen-1] == '.')) {
if (qName[qNameLen-candidateLen:] == candidate.domain &&
(candidateLen == qNameLen || (qName[qNameLen-candidateLen-1] == '.'))) ||
(candidate.domain == ".") {
servers = candidate.servers
break
}
@ -92,11 +100,25 @@ func (plugin *PluginForward) Eval(pluginsState *PluginsState, msg *dns.Msg) erro
return nil
}
server := servers[rand.Intn(len(servers))]
respMsg, err := dns.Exchange(msg, server)
pluginsState.serverName = server
client := dns.Client{Net: pluginsState.serverProto, Timeout: pluginsState.timeout}
respMsg, _, err := client.Exchange(msg, server)
if err != nil {
return err
}
if respMsg.Truncated {
client.Net = "tcp"
respMsg, _, err = client.Exchange(msg, server)
if err != nil {
return err
}
}
if edns0 := respMsg.IsEdns0(); edns0 == nil || !edns0.Do() {
respMsg.AuthenticatedData = false
}
respMsg.Id = msg.Id
pluginsState.synthResponse = respMsg
pluginsState.action = PluginsActionSynth
pluginsState.returnCode = PluginsReturnCodeForward
return nil
}

View File

@ -29,12 +29,19 @@ func (plugin *PluginGetSetPayloadSize) Eval(pluginsState *PluginsState, msg *dns
edns0 := msg.IsEdns0()
dnssec := false
if edns0 != nil {
pluginsState.originalMaxPayloadSize = Min(int(edns0.UDPSize())-ResponseOverhead, pluginsState.originalMaxPayloadSize)
pluginsState.maxUnencryptedUDPSafePayloadSize = int(edns0.UDPSize())
pluginsState.originalMaxPayloadSize = Max(
pluginsState.maxUnencryptedUDPSafePayloadSize-ResponseOverhead,
pluginsState.originalMaxPayloadSize,
)
dnssec = edns0.Do()
}
var options *[]dns.EDNS0
pluginsState.dnssec = dnssec
pluginsState.maxPayloadSize = Min(MaxDNSUDPPacketSize-ResponseOverhead, Max(pluginsState.originalMaxPayloadSize, pluginsState.maxPayloadSize))
pluginsState.maxPayloadSize = Min(
MaxDNSUDPPacketSize-ResponseOverhead,
Max(pluginsState.originalMaxPayloadSize, pluginsState.maxPayloadSize),
)
if pluginsState.maxPayloadSize > 512 {
extra2 := []dns.RR{}
for _, extra := range msg.Extra {

View File

@ -3,16 +3,16 @@ package main
import (
"errors"
"fmt"
"io"
"net"
"time"
"github.com/jedisct1/dlog"
"github.com/miekg/dns"
lumberjack "gopkg.in/natefinch/lumberjack.v2"
)
type PluginNxLog struct {
logger *lumberjack.Logger
logger io.Writer
format string
}
@ -25,7 +25,7 @@ func (plugin *PluginNxLog) Description() string {
}
func (plugin *PluginNxLog) Init(proxy *Proxy) error {
plugin.logger = &lumberjack.Logger{LocalTime: true, MaxSize: proxy.logMaxSize, MaxAge: proxy.logMaxAge, MaxBackups: proxy.logMaxBackups, Filename: proxy.nxLogFile, Compress: true}
plugin.logger = Logger(proxy.logMaxSize, proxy.logMaxAge, proxy.logMaxBackups, proxy.nxLogFile)
plugin.format = proxy.nxLogFormat
return nil
@ -43,22 +43,22 @@ func (plugin *PluginNxLog) Eval(pluginsState *PluginsState, msg *dns.Msg) error
if msg.Rcode != dns.RcodeNameError {
return nil
}
questions := msg.Question
if len(questions) == 0 {
var clientIPStr string
switch pluginsState.clientProto {
case "udp":
clientIPStr = (*pluginsState.clientAddr).(*net.UDPAddr).IP.String()
case "tcp", "local_doh":
clientIPStr = (*pluginsState.clientAddr).(*net.TCPAddr).IP.String()
default:
// Ignore internal flow.
return nil
}
question := questions[0]
question := msg.Question[0]
qType, ok := dns.TypeToString[question.Qtype]
if !ok {
qType = string(qType)
}
var clientIPStr string
if pluginsState.clientProto == "udp" {
clientIPStr = (*pluginsState.clientAddr).(*net.UDPAddr).IP.String()
} else {
clientIPStr = (*pluginsState.clientAddr).(*net.TCPAddr).IP.String()
}
qName := StripTrailingDot(question.Name)
qName := pluginsState.qName
var line string
if plugin.format == "tsv" {
@ -76,7 +76,7 @@ func (plugin *PluginNxLog) Eval(pluginsState *PluginsState, msg *dns.Msg) error
if plugin.logger == nil {
return errors.New("Log file not initialized")
}
plugin.logger.Write([]byte(line))
_, _ = plugin.logger.Write([]byte(line))
return nil
}

View File

@ -3,17 +3,17 @@ package main
import (
"errors"
"fmt"
"io"
"net"
"strings"
"time"
"github.com/jedisct1/dlog"
"github.com/miekg/dns"
lumberjack "gopkg.in/natefinch/lumberjack.v2"
)
type PluginQueryLog struct {
logger *lumberjack.Logger
logger io.Writer
format string
ignoredQtypes []string
}
@ -27,7 +27,7 @@ func (plugin *PluginQueryLog) Description() string {
}
func (plugin *PluginQueryLog) Init(proxy *Proxy) error {
plugin.logger = &lumberjack.Logger{LocalTime: true, MaxSize: proxy.logMaxSize, MaxAge: proxy.logMaxAge, MaxBackups: proxy.logMaxBackups, Filename: proxy.queryLogFile, Compress: true}
plugin.logger = Logger(proxy.logMaxSize, proxy.logMaxAge, proxy.logMaxBackups, proxy.queryLogFile)
plugin.format = proxy.queryLogFormat
plugin.ignoredQtypes = proxy.queryLogIgnoredQtypes
@ -43,11 +43,17 @@ func (plugin *PluginQueryLog) Reload() error {
}
func (plugin *PluginQueryLog) Eval(pluginsState *PluginsState, msg *dns.Msg) error {
questions := msg.Question
if len(questions) == 0 {
var clientIPStr string
switch pluginsState.clientProto {
case "udp":
clientIPStr = (*pluginsState.clientAddr).(*net.UDPAddr).IP.String()
case "tcp", "local_doh":
clientIPStr = (*pluginsState.clientAddr).(*net.TCPAddr).IP.String()
default:
// Ignore internal flow.
return nil
}
question := questions[0]
question := msg.Question[0]
qType, ok := dns.TypeToString[question.Qtype]
if !ok {
qType = string(qType)
@ -59,13 +65,16 @@ func (plugin *PluginQueryLog) Eval(pluginsState *PluginsState, msg *dns.Msg) err
}
}
}
var clientIPStr string
if pluginsState.clientProto == "udp" {
clientIPStr = (*pluginsState.clientAddr).(*net.UDPAddr).IP.String()
qName := pluginsState.qName
if pluginsState.cacheHit {
pluginsState.serverName = "-"
} else {
clientIPStr = (*pluginsState.clientAddr).(*net.TCPAddr).IP.String()
switch pluginsState.returnCode {
case PluginsReturnCodeSynth, PluginsReturnCodeCloak, PluginsReturnCodeParseError:
pluginsState.serverName = "-"
}
}
qName := StripTrailingDot(question.Name)
returnCode, ok := PluginsReturnCodeToString[pluginsState.returnCode]
if !ok {
returnCode = string(returnCode)
@ -75,15 +84,22 @@ func (plugin *PluginQueryLog) Eval(pluginsState *PluginsState, msg *dns.Msg) err
if !pluginsState.requestStart.IsZero() && !pluginsState.requestEnd.IsZero() {
requestDuration = pluginsState.requestEnd.Sub(pluginsState.requestStart)
}
var line string
if plugin.format == "tsv" {
now := time.Now()
year, month, day := now.Date()
hour, minute, second := now.Clock()
tsStr := fmt.Sprintf("[%d-%02d-%02d %02d:%02d:%02d]", year, int(month), day, hour, minute, second)
line = fmt.Sprintf("%s\t%s\t%s\t%s\t%s\t%dms\t%s\n", tsStr, clientIPStr, StringQuote(qName), qType, returnCode, requestDuration/time.Millisecond,
StringQuote(pluginsState.serverName))
line = fmt.Sprintf(
"%s\t%s\t%s\t%s\t%s\t%dms\t%s\n",
tsStr,
clientIPStr,
StringQuote(qName),
qType,
returnCode,
requestDuration/time.Millisecond,
StringQuote(pluginsState.serverName),
)
} else if plugin.format == "ltsv" {
cached := 0
if pluginsState.cacheHit {
@ -97,6 +113,7 @@ func (plugin *PluginQueryLog) Eval(pluginsState *PluginsState, msg *dns.Msg) err
if plugin.logger == nil {
return errors.New("Log file not initialized")
}
plugin.logger.Write([]byte(line))
_, _ = plugin.logger.Write([]byte(line))
return nil
}

View File

@ -0,0 +1,41 @@
package main
import (
"github.com/miekg/dns"
)
type PluginQueryMeta struct {
queryMetaRR *dns.TXT
}
func (plugin *PluginQueryMeta) Name() string {
return "query_log"
}
func (plugin *PluginQueryMeta) Description() string {
return "Log DNS queries."
}
func (plugin *PluginQueryMeta) Init(proxy *Proxy) error {
queryMetaRR := new(dns.TXT)
queryMetaRR.Hdr = dns.RR_Header{
Name: ".", Rrtype: dns.TypeTXT,
Class: dns.ClassINET, Ttl: 86400,
}
queryMetaRR.Txt = proxy.queryMeta
plugin.queryMetaRR = queryMetaRR
return nil
}
func (plugin *PluginQueryMeta) Drop() error {
return nil
}
func (plugin *PluginQueryMeta) Reload() error {
return nil
}
func (plugin *PluginQueryMeta) Eval(pluginsState *PluginsState, msg *dns.Msg) error {
msg.Extra = []dns.RR{plugin.queryMetaRR}
return nil
}

View File

@ -1,131 +0,0 @@
package main
import (
"errors"
"fmt"
"net"
"strings"
"time"
"unicode"
"github.com/jedisct1/dlog"
"github.com/miekg/dns"
lumberjack "gopkg.in/natefinch/lumberjack.v2"
)
type PluginWhitelistName struct {
allWeeklyRanges *map[string]WeeklyRanges
patternMatcher *PatternMatcher
logger *lumberjack.Logger
format string
}
func (plugin *PluginWhitelistName) Name() string {
return "whitelist_name"
}
func (plugin *PluginWhitelistName) Description() string {
return "Whitelists DNS queries matching name patterns"
}
func (plugin *PluginWhitelistName) Init(proxy *Proxy) error {
dlog.Noticef("Loading the set of whitelisting rules from [%s]", proxy.whitelistNameFile)
bin, err := ReadTextFile(proxy.whitelistNameFile)
if err != nil {
return err
}
plugin.allWeeklyRanges = proxy.allWeeklyRanges
plugin.patternMatcher = NewPatternPatcher()
for lineNo, line := range strings.Split(string(bin), "\n") {
line = strings.TrimFunc(line, unicode.IsSpace)
if len(line) == 0 || strings.HasPrefix(line, "#") {
continue
}
parts := strings.Split(line, "@")
timeRangeName := ""
if len(parts) == 2 {
line = strings.TrimFunc(parts[0], unicode.IsSpace)
timeRangeName = strings.TrimFunc(parts[1], unicode.IsSpace)
} else if len(parts) > 2 {
dlog.Errorf("Syntax error in whitelist rules at line %d -- Unexpected @ character", 1+lineNo)
continue
}
var weeklyRanges *WeeklyRanges
if len(timeRangeName) > 0 {
weeklyRangesX, ok := (*plugin.allWeeklyRanges)[timeRangeName]
if !ok {
dlog.Errorf("Time range [%s] not found at line %d", timeRangeName, 1+lineNo)
} else {
weeklyRanges = &weeklyRangesX
}
}
if _, err := plugin.patternMatcher.Add(line, weeklyRanges, lineNo+1); err != nil {
dlog.Error(err)
continue
}
}
if len(proxy.whitelistNameLogFile) == 0 {
return nil
}
plugin.logger = &lumberjack.Logger{LocalTime: true, MaxSize: proxy.logMaxSize, MaxAge: proxy.logMaxAge, MaxBackups: proxy.logMaxBackups, Filename: proxy.whitelistNameLogFile, Compress: true}
plugin.format = proxy.whitelistNameFormat
return nil
}
func (plugin *PluginWhitelistName) Drop() error {
return nil
}
func (plugin *PluginWhitelistName) Reload() error {
return nil
}
func (plugin *PluginWhitelistName) Eval(pluginsState *PluginsState, msg *dns.Msg) error {
questions := msg.Question
if len(questions) != 1 {
return nil
}
qName := strings.ToLower(StripTrailingDot(questions[0].Name))
whitelist, reason, xweeklyRanges := plugin.patternMatcher.Eval(qName)
var weeklyRanges *WeeklyRanges
if xweeklyRanges != nil {
weeklyRanges = xweeklyRanges.(*WeeklyRanges)
}
if whitelist {
if weeklyRanges != nil && !weeklyRanges.Match() {
whitelist = false
}
}
if whitelist {
if pluginsState.sessionData == nil {
pluginsState.sessionData = make(map[string]interface{})
}
pluginsState.sessionData["whitelisted"] = true
if plugin.logger != nil {
var clientIPStr string
if pluginsState.clientProto == "udp" {
clientIPStr = (*pluginsState.clientAddr).(*net.UDPAddr).IP.String()
} else {
clientIPStr = (*pluginsState.clientAddr).(*net.TCPAddr).IP.String()
}
var line string
if plugin.format == "tsv" {
now := time.Now()
year, month, day := now.Date()
hour, minute, second := now.Clock()
tsStr := fmt.Sprintf("[%d-%02d-%02d %02d:%02d:%02d]", year, int(month), day, hour, minute, second)
line = fmt.Sprintf("%s\t%s\t%s\t%s\n", tsStr, clientIPStr, StringQuote(qName), StringQuote(reason))
} else if plugin.format == "ltsv" {
line = fmt.Sprintf("time:%d\thost:%s\tqname:%s\tmessage:%s\n", time.Now().Unix(), clientIPStr, StringQuote(qName), StringQuote(reason))
} else {
dlog.Fatalf("Unexpected log format: [%s]", plugin.format)
}
if plugin.logger == nil {
return errors.New("Log file not initialized")
}
plugin.logger.Write([]byte(line))
}
}
return nil
}

View File

@ -3,6 +3,7 @@ package main
import (
"errors"
"net"
"strings"
"sync"
"time"
@ -13,11 +14,11 @@ import (
type PluginsAction int
const (
PluginsActionNone = 0
PluginsActionForward = 1
PluginsActionDrop = 2
PluginsActionReject = 3
PluginsActionSynth = 4
PluginsActionNone = 0
PluginsActionContinue = 1
PluginsActionDrop = 2
PluginsActionReject = 3
PluginsActionSynth = 4
)
type PluginsGlobals struct {
@ -26,6 +27,8 @@ type PluginsGlobals struct {
responsePlugins *[]Plugin
loggingPlugins *[]Plugin
refusedCodeInResponses bool
respondWithIPv4 net.IP
respondWithIPv6 net.IP
}
type PluginsReturnCode int
@ -39,8 +42,11 @@ const (
PluginsReturnCodeParseError
PluginsReturnCodeNXDomain
PluginsReturnCodeResponseError
PluginsReturnCodeServerError
PluginsReturnCodeServFail
PluginsReturnCodeNetworkError
PluginsReturnCodeCloak
PluginsReturnCodeServerTimeout
PluginsReturnCodeNotReady
)
var PluginsReturnCodeToString = map[PluginsReturnCode]string{
@ -52,36 +58,57 @@ var PluginsReturnCodeToString = map[PluginsReturnCode]string{
PluginsReturnCodeParseError: "PARSE_ERROR",
PluginsReturnCodeNXDomain: "NXDOMAIN",
PluginsReturnCodeResponseError: "RESPONSE_ERROR",
PluginsReturnCodeServerError: "SERVER_ERROR",
PluginsReturnCodeServFail: "SERVFAIL",
PluginsReturnCodeNetworkError: "NETWORK_ERROR",
PluginsReturnCodeCloak: "CLOAK",
PluginsReturnCodeServerTimeout: "SERVER_TIMEOUT",
PluginsReturnCodeNotReady: "NOT_READY",
}
type PluginsState struct {
sessionData map[string]interface{}
action PluginsAction
originalMaxPayloadSize int
maxPayloadSize int
clientProto string
clientAddr *net.Addr
synthResponse *dns.Msg
dnssec bool
cacheSize int
cacheNegMinTTL uint32
cacheNegMaxTTL uint32
cacheMinTTL uint32
cacheMaxTTL uint32
questionMsg *dns.Msg
requestStart time.Time
requestEnd time.Time
cacheHit bool
returnCode PluginsReturnCode
serverName string
requestStart time.Time
requestEnd time.Time
clientProto string
serverName string
serverProto string
qName string
clientAddr *net.Addr
synthResponse *dns.Msg
questionMsg *dns.Msg
sessionData map[string]interface{}
action PluginsAction
timeout time.Duration
returnCode PluginsReturnCode
maxPayloadSize int
cacheSize int
originalMaxPayloadSize int
maxUnencryptedUDPSafePayloadSize int
rejectTTL uint32
cacheMaxTTL uint32
cacheNegMaxTTL uint32
cacheNegMinTTL uint32
cacheMinTTL uint32
cacheHit bool
dnssec bool
}
func InitPluginsGlobals(pluginsGlobals *PluginsGlobals, proxy *Proxy) error {
func (proxy *Proxy) InitPluginsGlobals() error {
queryPlugins := &[]Plugin{}
if len(proxy.whitelistNameFile) != 0 {
*queryPlugins = append(*queryPlugins, Plugin(new(PluginWhitelistName)))
if proxy.captivePortalMap != nil {
*queryPlugins = append(*queryPlugins, Plugin(new(PluginCaptivePortal)))
}
if len(proxy.queryMeta) != 0 {
*queryPlugins = append(*queryPlugins, Plugin(new(PluginQueryMeta)))
}
if len(proxy.allowNameFile) != 0 {
*queryPlugins = append(*queryPlugins, Plugin(new(PluginAllowName)))
}
*queryPlugins = append(*queryPlugins, Plugin(new(PluginFirefox)))
if len(proxy.ednsClientSubnets) != 0 {
*queryPlugins = append(*queryPlugins, Plugin(new(PluginECS)))
}
if len(proxy.blockNameFile) != 0 {
*queryPlugins = append(*queryPlugins, Plugin(new(PluginBlockName)))
@ -99,14 +126,29 @@ func InitPluginsGlobals(pluginsGlobals *PluginsGlobals, proxy *Proxy) error {
if len(proxy.forwardFile) != 0 {
*queryPlugins = append(*queryPlugins, Plugin(new(PluginForward)))
}
if proxy.pluginBlockUnqualified {
*queryPlugins = append(*queryPlugins, Plugin(new(PluginBlockUnqualified)))
}
if proxy.pluginBlockUndelegated {
*queryPlugins = append(*queryPlugins, Plugin(new(PluginBlockUndelegated)))
}
responsePlugins := &[]Plugin{}
if len(proxy.nxLogFile) != 0 {
*responsePlugins = append(*responsePlugins, Plugin(new(PluginNxLog)))
}
if len(proxy.allowedIPFile) != 0 {
*responsePlugins = append(*responsePlugins, Plugin(new(PluginAllowedIP)))
}
if len(proxy.blockNameFile) != 0 {
*responsePlugins = append(*responsePlugins, Plugin(new(PluginBlockNameResponse)))
}
if len(proxy.blockIPFile) != 0 {
*responsePlugins = append(*responsePlugins, Plugin(new(PluginBlockIP)))
}
if len(proxy.dns64Resolvers) != 0 || len(proxy.dns64Prefixes) != 0 {
*responsePlugins = append(*responsePlugins, Plugin(new(PluginDNS64)))
}
if proxy.cache {
*responsePlugins = append(*responsePlugins, Plugin(new(PluginCacheResponse)))
}
@ -132,13 +174,63 @@ func InitPluginsGlobals(pluginsGlobals *PluginsGlobals, proxy *Proxy) error {
}
}
(*pluginsGlobals).queryPlugins = queryPlugins
(*pluginsGlobals).responsePlugins = responsePlugins
(*pluginsGlobals).loggingPlugins = loggingPlugins
(*pluginsGlobals).refusedCodeInResponses = proxy.refusedCodeInResponses
proxy.pluginsGlobals.queryPlugins = queryPlugins
proxy.pluginsGlobals.responsePlugins = responsePlugins
proxy.pluginsGlobals.loggingPlugins = loggingPlugins
parseBlockedQueryResponse(proxy.blockedQueryResponse, &proxy.pluginsGlobals)
return nil
}
// blockedQueryResponse can be 'refused', 'hinfo' or IP responses 'a:IPv4,aaaa:IPv6
func parseBlockedQueryResponse(blockedResponse string, pluginsGlobals *PluginsGlobals) {
blockedResponse = StringStripSpaces(strings.ToLower(blockedResponse))
if strings.HasPrefix(blockedResponse, "a:") {
blockedIPStrings := strings.Split(blockedResponse, ",")
pluginsGlobals.respondWithIPv4 = net.ParseIP(strings.TrimPrefix(blockedIPStrings[0], "a:"))
if pluginsGlobals.respondWithIPv4 == nil {
dlog.Notice("Error parsing IPv4 response given in blocked_query_response option, defaulting to `hinfo`")
pluginsGlobals.refusedCodeInResponses = false
return
}
if len(blockedIPStrings) > 1 {
if strings.HasPrefix(blockedIPStrings[1], "aaaa:") {
ipv6Response := strings.TrimPrefix(blockedIPStrings[1], "aaaa:")
if strings.HasPrefix(ipv6Response, "[") {
ipv6Response = strings.Trim(ipv6Response, "[]")
}
pluginsGlobals.respondWithIPv6 = net.ParseIP(ipv6Response)
if pluginsGlobals.respondWithIPv6 == nil {
dlog.Notice(
"Error parsing IPv6 response given in blocked_query_response option, defaulting to IPv4",
)
}
} else {
dlog.Noticef("Invalid IPv6 response given in blocked_query_response option [%s], the option should take the form 'a:<IPv4>,aaaa:<IPv6>'", blockedIPStrings[1])
}
}
if pluginsGlobals.respondWithIPv6 == nil {
pluginsGlobals.respondWithIPv6 = pluginsGlobals.respondWithIPv4
}
} else {
switch blockedResponse {
case "refused":
pluginsGlobals.refusedCodeInResponses = true
case "hinfo":
pluginsGlobals.refusedCodeInResponses = false
default:
dlog.Noticef("Invalid blocked_query_response option [%s], defaulting to `hinfo`", blockedResponse)
pluginsGlobals.refusedCodeInResponses = false
}
}
}
type Plugin interface {
Name() string
Description() string
@ -148,68 +240,99 @@ type Plugin interface {
Eval(pluginsState *PluginsState, msg *dns.Msg) error
}
func NewPluginsState(proxy *Proxy, clientProto string, clientAddr *net.Addr, start time.Time) PluginsState {
func NewPluginsState(
proxy *Proxy,
clientProto string,
clientAddr *net.Addr,
serverProto string,
start time.Time,
) PluginsState {
return PluginsState{
action: PluginsActionForward,
maxPayloadSize: MaxDNSUDPPacketSize - ResponseOverhead,
clientProto: clientProto,
clientAddr: clientAddr,
cacheSize: proxy.cacheSize,
cacheNegMinTTL: proxy.cacheNegMinTTL,
cacheNegMaxTTL: proxy.cacheNegMaxTTL,
cacheMinTTL: proxy.cacheMinTTL,
cacheMaxTTL: proxy.cacheMaxTTL,
questionMsg: nil,
requestStart: start,
action: PluginsActionContinue,
returnCode: PluginsReturnCodePass,
maxPayloadSize: MaxDNSUDPPacketSize - ResponseOverhead,
clientProto: clientProto,
clientAddr: clientAddr,
cacheSize: proxy.cacheSize,
cacheNegMinTTL: proxy.cacheNegMinTTL,
cacheNegMaxTTL: proxy.cacheNegMaxTTL,
cacheMinTTL: proxy.cacheMinTTL,
cacheMaxTTL: proxy.cacheMaxTTL,
rejectTTL: proxy.rejectTTL,
questionMsg: nil,
qName: "",
serverName: "-",
serverProto: serverProto,
timeout: proxy.timeout,
requestStart: start,
maxUnencryptedUDPSafePayloadSize: MaxDNSUDPSafePacketSize,
sessionData: make(map[string]interface{}),
}
}
func (pluginsState *PluginsState) ApplyQueryPlugins(pluginsGlobals *PluginsGlobals, packet []byte, serverName string) ([]byte, error) {
if len(*pluginsGlobals.queryPlugins) == 0 && len(*pluginsGlobals.loggingPlugins) == 0 {
return packet, nil
}
pluginsState.serverName = serverName
pluginsState.action = PluginsActionForward
func (pluginsState *PluginsState) ApplyQueryPlugins(
pluginsGlobals *PluginsGlobals,
packet []byte,
needsEDNS0Padding bool,
) ([]byte, error) {
msg := dns.Msg{}
if err := msg.Unpack(packet); err != nil {
return packet, err
}
if len(msg.Question) > 1 {
if len(msg.Question) != 1 {
return packet, errors.New("Unexpected number of questions")
}
qName, err := NormalizeQName(msg.Question[0].Name)
if err != nil {
return packet, err
}
dlog.Debugf("Handling query for [%v]", qName)
pluginsState.qName = qName
pluginsState.questionMsg = &msg
if len(*pluginsGlobals.queryPlugins) == 0 && len(*pluginsGlobals.loggingPlugins) == 0 {
return packet, nil
}
pluginsGlobals.RLock()
defer pluginsGlobals.RUnlock()
for _, plugin := range *pluginsGlobals.queryPlugins {
if ret := plugin.Eval(pluginsState, &msg); ret != nil {
pluginsGlobals.RUnlock()
if err := plugin.Eval(pluginsState, &msg); err != nil {
pluginsState.action = PluginsActionDrop
return packet, ret
return packet, err
}
if pluginsState.action == PluginsActionReject {
synth, err := RefusedResponseFromMessage(&msg, pluginsGlobals.refusedCodeInResponses)
if err != nil {
return nil, err
}
synth := RefusedResponseFromMessage(
&msg,
pluginsGlobals.refusedCodeInResponses,
pluginsGlobals.respondWithIPv4,
pluginsGlobals.respondWithIPv6,
pluginsState.rejectTTL,
)
pluginsState.synthResponse = synth
}
if pluginsState.action != PluginsActionForward {
if pluginsState.action != PluginsActionContinue {
break
}
}
pluginsGlobals.RUnlock()
packet2, err := msg.PackBuffer(packet)
if err != nil {
return packet, err
}
if needsEDNS0Padding && pluginsState.action == PluginsActionContinue {
padLen := 63 - ((len(packet2) + 63) & 63)
if paddedPacket2, _ := addEDNS0PaddingIfNoneFound(&msg, packet2, padLen); paddedPacket2 != nil {
return paddedPacket2, nil
}
}
return packet2, nil
}
func (pluginsState *PluginsState) ApplyResponsePlugins(pluginsGlobals *PluginsGlobals, packet []byte, ttl *uint32) ([]byte, error) {
if len(*pluginsGlobals.responsePlugins) == 0 && len(*pluginsGlobals.loggingPlugins) == 0 {
return packet, nil
}
pluginsState.action = PluginsActionForward
msg := dns.Msg{}
func (pluginsState *PluginsState) ApplyResponsePlugins(
pluginsGlobals *PluginsGlobals,
packet []byte,
ttl *uint32,
) ([]byte, error) {
msg := dns.Msg{Compress: true}
if err := msg.Unpack(packet); err != nil {
if len(packet) >= MinDNSPacketSize && HasTCFlag(packet) {
err = nil
@ -222,30 +345,32 @@ func (pluginsState *PluginsState) ApplyResponsePlugins(pluginsGlobals *PluginsGl
case dns.RcodeNameError:
pluginsState.returnCode = PluginsReturnCodeNXDomain
case dns.RcodeServerFailure:
pluginsState.returnCode = PluginsReturnCodeServerError
pluginsState.returnCode = PluginsReturnCodeServFail
default:
pluginsState.returnCode = PluginsReturnCodeResponseError
}
removeEDNS0Options(&msg)
pluginsGlobals.RLock()
defer pluginsGlobals.RUnlock()
for _, plugin := range *pluginsGlobals.responsePlugins {
if ret := plugin.Eval(pluginsState, &msg); ret != nil {
pluginsGlobals.RUnlock()
if err := plugin.Eval(pluginsState, &msg); err != nil {
pluginsState.action = PluginsActionDrop
return packet, ret
return packet, err
}
if pluginsState.action == PluginsActionReject {
synth, err := RefusedResponseFromMessage(&msg, pluginsGlobals.refusedCodeInResponses)
if err != nil {
return nil, err
}
dlog.Infof("Blocking [%s]", synth.Question[0].Name)
synth := RefusedResponseFromMessage(
&msg,
pluginsGlobals.refusedCodeInResponses,
pluginsGlobals.respondWithIPv4,
pluginsGlobals.respondWithIPv6,
pluginsState.rejectTTL,
)
pluginsState.synthResponse = synth
}
if pluginsState.action != PluginsActionForward {
if pluginsState.action != PluginsActionContinue {
break
}
}
pluginsGlobals.RUnlock()
if ttl != nil {
setMaxTTL(&msg, *ttl)
}
@ -262,16 +387,15 @@ func (pluginsState *PluginsState) ApplyLoggingPlugins(pluginsGlobals *PluginsGlo
}
pluginsState.requestEnd = time.Now()
questionMsg := pluginsState.questionMsg
if questionMsg == nil || len(questionMsg.Question) > 1 {
return errors.New("Unexpected number of questions")
if questionMsg == nil {
return errors.New("Question not found")
}
pluginsGlobals.RLock()
defer pluginsGlobals.RUnlock()
for _, plugin := range *pluginsGlobals.loggingPlugins {
if ret := plugin.Eval(pluginsState, questionMsg); ret != nil {
pluginsGlobals.RUnlock()
return ret
if err := plugin.Eval(pluginsState, questionMsg); err != nil {
return err
}
}
pluginsGlobals.RUnlock()
return nil
}

View File

@ -9,12 +9,13 @@ import (
"strconv"
"syscall"
"golang.org/x/sys/unix"
"github.com/jedisct1/dlog"
)
func (proxy *Proxy) dropPrivilege(userStr string, fds []*os.File) {
currentUser, err := user.Current()
if err != nil && currentUser.Uid != "0" {
if os.Geteuid() != 0 {
dlog.Fatal("Root privileges are required in order to switch to a different user. Maybe try again with 'sudo'")
}
userInfo, err := user.Lookup(userStr)
@ -23,9 +24,19 @@ func (proxy *Proxy) dropPrivilege(userStr string, fds []*os.File) {
if err != nil {
uid, err2 := strconv.Atoi(userStr)
if err2 != nil || uid <= 0 {
dlog.Fatalf("Unable to retrieve any information about user [%s]: [%s] - Remove the user_name directive from the configuration file in order to avoid identity switch", userStr, err)
dlog.Fatalf(
"Unable to retrieve any information about user [%s]: [%s] - Remove the user_name directive from the configuration file in order to avoid identity switch",
userStr,
err,
)
}
dlog.Warnf("Unable to retrieve any information about user [%s]: [%s] - Switching to user id [%v] with the same group id, as [%v] looks like a user id. But you should remove or fix the user_name directive in the configuration file if possible", userStr, err, uid, uid)
dlog.Warnf(
"Unable to retrieve any information about user [%s]: [%s] - Switching to user id [%v] with the same group id, as [%v] looks like a user id. But you should remove or fix the user_name directive in the configuration file if possible",
userStr,
err,
uid,
uid,
)
userInfo = &user.User{Uid: userStr, Gid: userStr}
}
uid, err := strconv.Atoi(userInfo.Uid)
@ -45,42 +56,36 @@ func (proxy *Proxy) dropPrivilege(userStr string, fds []*os.File) {
dlog.Fatal(err)
}
ServiceManagerReadyNotify()
if err := ServiceManagerReadyNotify(); err != nil {
dlog.Fatal(err)
}
args = append(args, "-child")
dlog.Notice("Dropping privileges")
runtime.LockOSThread()
if _, _, rcode := syscall.RawSyscall(syscall.SYS_SETGROUPS, uintptr(0), uintptr(0), 0); rcode != 0 {
dlog.Fatalf("Unable to drop additional groups: [%s]", rcode.Error())
}
if _, _, rcode := syscall.RawSyscall(syscall.SYS_SETGID, uintptr(gid), 0, 0); rcode != 0 {
dlog.Fatalf("Unable to drop user privileges: [%s]", rcode.Error())
dlog.Fatalf("Unable to drop group privileges: [%s]", rcode.Error())
}
if _, _, rcode := syscall.RawSyscall(syscall.SYS_SETUID, uintptr(uid), 0, 0); rcode != 0 {
dlog.Fatalf("Unable to drop user privileges: [%s]", rcode.Error())
}
maxfd := uintptr(0)
for _, fd := range fds {
if fd.Fd() > maxfd {
maxfd = fd.Fd()
}
}
fdbase := maxfd + 1
for i, fd := range fds {
if _, _, rcode := syscall.RawSyscall(syscall.SYS_DUP3, fd.Fd(), fdbase+uintptr(i), 0); rcode != 0 {
dlog.Fatalf("Unable to clone file descriptor: [%s]", rcode.Error())
if fd.Fd() >= InheritedDescriptorsBase {
dlog.Fatal("Duplicated file descriptors are above base")
}
if _, _, rcode := syscall.RawSyscall(syscall.SYS_FCNTL, fd.Fd(), syscall.F_SETFD, syscall.FD_CLOEXEC); rcode != 0 {
dlog.Fatalf("Unable to set the close on exec flag: [%s]", rcode.Error())
if err := unix.Dup2(int(fd.Fd()), int(InheritedDescriptorsBase+uintptr(i))); err != nil {
dlog.Fatalf("Unable to clone file descriptor: [%s]", err)
}
if _, err := unix.FcntlInt(fd.Fd(), unix.F_SETFD, unix.FD_CLOEXEC); err != nil {
dlog.Fatalf("Unable to set the close on exec flag: [%s]", err)
}
}
for i := range fds {
if _, _, rcode := syscall.RawSyscall(syscall.SYS_DUP3, fdbase+uintptr(i), uintptr(i)+3, 0); rcode != 0 {
dlog.Fatalf("Unable to reassign descriptor: [%s]", rcode.Error())
}
}
err = syscall.Exec(path, args, os.Environ())
err = unix.Exec(path, args, os.Environ())
dlog.Fatalf("Unable to reexecute [%s]: [%s]", path, err)
os.Exit(1)
}

View File

@ -1,3 +1,4 @@
//go:build !windows && !linux
// +build !windows,!linux
package main
@ -9,75 +10,84 @@ import (
"path/filepath"
"runtime"
"strconv"
"syscall"
"golang.org/x/sys/unix"
"github.com/jedisct1/dlog"
)
func (proxy *Proxy) dropPrivilege(userStr string, fds []*os.File) {
currentUser, err := user.Current()
if err != nil && currentUser.Uid != "0" {
if os.Geteuid() != 0 {
dlog.Fatal("Root privileges are required in order to switch to a different user. Maybe try again with 'sudo'")
}
user, err := user.Lookup(userStr)
userInfo, err := user.Lookup(userStr)
args := os.Args
if err != nil {
dlog.Fatal(err)
uid, err2 := strconv.Atoi(userStr)
if err2 != nil || uid <= 0 {
dlog.Fatalf(
"Unable to retrieve any information about user [%s]: [%s] - Remove the user_name directive from the configuration file in order to avoid identity switch",
userStr,
err,
)
}
dlog.Warnf(
"Unable to retrieve any information about user [%s]: [%s] - Switching to user id [%v] with the same group id, as [%v] looks like a user id. But you should remove or fix the user_name directive in the configuration file if possible",
userStr,
err,
uid,
uid,
)
userInfo = &user.User{Uid: userStr, Gid: userStr}
}
uid, err := strconv.Atoi(user.Uid)
uid, err := strconv.Atoi(userInfo.Uid)
if err != nil {
dlog.Fatal(err)
}
gid, err := strconv.Atoi(user.Gid)
gid, err := strconv.Atoi(userInfo.Gid)
if err != nil {
dlog.Fatal(err)
}
execPath, err := exec.LookPath(args[0])
if err != nil {
dlog.Fatal(err)
dlog.Fatalf("Unable to get the path to the dnscrypt-proxy executable file: [%s]", err)
}
path, err := filepath.Abs(execPath)
if err != nil {
dlog.Fatal(err)
}
ServiceManagerReadyNotify()
if err := ServiceManagerReadyNotify(); err != nil {
dlog.Fatal(err)
}
args = append(args, "-child")
dlog.Notice("Dropping privileges")
runtime.LockOSThread()
if _, _, rcode := syscall.RawSyscall(syscall.SYS_SETGROUPS, uintptr(0), uintptr(0), 0); rcode != 0 {
dlog.Fatalf("Unable to drop additional groups: %s", rcode.Error())
if err := unix.Setgroups([]int{}); err != nil {
dlog.Fatalf("Unable to drop additional groups: %s", err)
}
if _, _, rcode := syscall.RawSyscall(syscall.SYS_SETGID, uintptr(gid), 0, 0); rcode != 0 {
dlog.Fatalf("Unable to drop user privileges: %s", rcode.Error())
if err := unix.Setgid(gid); err != nil {
dlog.Fatalf("Unable to drop group privileges: %s", err)
}
if _, _, rcode := syscall.RawSyscall(syscall.SYS_SETUID, uintptr(uid), 0, 0); rcode != 0 {
dlog.Fatalf("Unable to drop user privileges: %s", rcode.Error())
if err := unix.Setuid(uid); err != nil {
dlog.Fatalf("Unable to drop user privileges: %s", err)
}
maxfd := uintptr(0)
for _, fd := range fds {
if fd.Fd() > maxfd {
maxfd = fd.Fd()
}
}
fdbase := maxfd + 1
for i, fd := range fds {
if _, _, rcode := syscall.RawSyscall(syscall.SYS_DUP2, fd.Fd(), fdbase+uintptr(i), 0); rcode != 0 {
dlog.Fatalf("Unable to clone file descriptor: [%s]", rcode.Error())
if fd.Fd() >= InheritedDescriptorsBase {
dlog.Fatal("Duplicated file descriptors are above base")
}
if _, _, rcode := syscall.RawSyscall(syscall.SYS_FCNTL, fd.Fd(), syscall.F_SETFD, syscall.FD_CLOEXEC); rcode != 0 {
dlog.Fatalf("Unable to set the close on exec flag: [%s]", rcode.Error())
if err := unix.Dup2(int(fd.Fd()), int(InheritedDescriptorsBase+uintptr(i))); err != nil {
dlog.Fatalf("Unable to clone file descriptor: [%s]", err)
}
if _, err := unix.FcntlInt(fd.Fd(), unix.F_SETFD, unix.FD_CLOEXEC); err != nil {
dlog.Fatalf("Unable to set the close on exec flag: [%s]", err)
}
}
for i := range fds {
if _, _, rcode := syscall.RawSyscall(syscall.SYS_DUP2, fdbase+uintptr(i), uintptr(i)+3, 0); rcode != 0 {
dlog.Fatalf("Unable to reassign descriptor: [%s]", rcode.Error())
}
}
err = syscall.Exec(path, args, os.Environ())
err = unix.Exec(path, args, os.Environ())
dlog.Fatalf("Unable to reexecute [%s]: [%s]", path, err)
os.Exit(1)
}

File diff suppressed because it is too large Load Diff

View File

@ -1,60 +1,383 @@
package main
import (
"errors"
"fmt"
"net"
"os"
"strings"
"time"
"github.com/miekg/dns"
)
const myResolverHost string = "resolver.dnscrypt.info"
const (
myResolverHost string = "resolver.dnscrypt.info."
nonexistentName string = "nonexistent-zone.dnscrypt-test."
)
func Resolve(name string) {
fmt.Printf("Resolving [%s]\n\n", name)
fmt.Printf("Domain exists: ")
ns, err := net.LookupNS(name)
if err != nil || len(ns) == 0 {
if name == "." {
fmt.Println("'No' would mean that the Internet doesn't exist any more, and that would be very sad. On the bright side, you just found an easter egg.")
} else {
fmt.Println("probably not, or blocked by the proxy")
}
} else {
fmt.Printf("yes, %d name servers found\n", len(ns))
func resolveQuery(server string, qName string, qType uint16, sendClientSubnet bool) (*dns.Msg, error) {
client := new(dns.Client)
client.ReadTimeout = 2 * time.Second
msg := &dns.Msg{
MsgHdr: dns.MsgHdr{
RecursionDesired: true,
Opcode: dns.OpcodeQuery,
},
Question: make([]dns.Question, 1),
}
options := &dns.OPT{
Hdr: dns.RR_Header{
Name: ".",
Rrtype: dns.TypeOPT,
},
}
fmt.Printf("Canonical name: ")
cname, err := net.LookupCNAME(name)
if err != nil {
fmt.Println("-")
} else {
if sendClientSubnet {
subnet := net.IPNet{IP: net.IPv4(93, 184, 216, 0), Mask: net.CIDRMask(24, 32)}
prr := dns.EDNS0_SUBNET{}
prr.Code = dns.EDNS0SUBNET
bits, totalSize := subnet.Mask.Size()
if totalSize == 32 {
prr.Family = 1
} else if totalSize == 128 { // if we want to test with IPv6
prr.Family = 2
}
prr.SourceNetmask = uint8(bits)
prr.SourceScope = 0
prr.Address = subnet.IP
options.Option = append(options.Option, &prr)
}
msg.Extra = append(msg.Extra, options)
options.SetDo()
options.SetUDPSize(uint16(MaxDNSPacketSize))
msg.Question[0] = dns.Question{Name: qName, Qtype: qType, Qclass: dns.ClassINET}
msg.Id = dns.Id()
for i := 0; i < 3; i++ {
response, rtt, err := client.Exchange(msg, server)
if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
client.ReadTimeout *= 2
continue
}
_ = rtt
if err != nil {
return nil, err
}
return response, nil
}
return nil, errors.New("Timeout")
}
func Resolve(server string, name string, singleResolver bool) {
parts := strings.SplitN(name, ",", 2)
if len(parts) == 2 {
name, server = parts[0], parts[1]
singleResolver = true
}
host, port := ExtractHostAndPort(server, 53)
if host == "0.0.0.0" {
host = "127.0.0.1"
} else if host == "[::]" {
host = "[::1]"
}
server = fmt.Sprintf("%s:%d", host, port)
fmt.Printf("Resolving [%s] using %s port %d\n\n", name, host, port)
name = dns.Fqdn(name)
cname := name
var clientSubnet string
for once := true; once; once = false {
response, err := resolveQuery(server, myResolverHost, dns.TypeTXT, true)
if err != nil {
fmt.Printf("Unable to resolve: [%s]\n", err)
os.Exit(1)
}
fmt.Printf("Resolver : ")
res := make([]string, 0)
for _, answer := range response.Answer {
if answer.Header().Class != dns.ClassINET || answer.Header().Rrtype != dns.TypeTXT {
continue
}
var ip string
for _, txt := range answer.(*dns.TXT).Txt {
if strings.HasPrefix(txt, "Resolver IP: ") {
ip = strings.TrimPrefix(txt, "Resolver IP: ")
} else if strings.HasPrefix(txt, "EDNS0 client subnet: ") {
clientSubnet = strings.TrimPrefix(txt, "EDNS0 client subnet: ")
}
}
if ip == "" {
continue
}
if rev, err := dns.ReverseAddr(ip); err == nil {
response, err = resolveQuery(server, rev, dns.TypePTR, false)
if err != nil {
break
}
for _, answer := range response.Answer {
if answer.Header().Rrtype != dns.TypePTR || answer.Header().Class != dns.ClassINET {
continue
}
ip = ip + " (" + answer.(*dns.PTR).Ptr + ")"
break
}
}
res = append(res, ip)
}
if len(res) == 0 {
fmt.Println("-")
} else {
fmt.Println(strings.Join(res, ", "))
}
}
if singleResolver {
for once := true; once; once = false {
fmt.Printf("Lying : ")
response, err := resolveQuery(server, nonexistentName, dns.TypeA, false)
if err != nil {
break
}
if response.Rcode == dns.RcodeSuccess {
fmt.Println("yes. That resolver returns wrong responses")
} else if response.Rcode == dns.RcodeNameError {
fmt.Println("no")
} else {
fmt.Printf("unknown - query returned %s\n", dns.RcodeToString[response.Rcode])
}
if response.Rcode == dns.RcodeNameError {
fmt.Printf("DNSSEC : ")
if response.AuthenticatedData {
fmt.Println("yes, the resolver supports DNSSEC")
} else {
fmt.Println("no, the resolver doesn't support DNSSEC")
}
}
fmt.Printf("ECS : ")
if clientSubnet != "" {
fmt.Println("client network address is sent to authoritative servers")
} else {
fmt.Println("ignored or selective")
}
}
}
fmt.Println("")
cname:
for once := true; once; once = false {
fmt.Printf("Canonical name: ")
for i := 0; i < 100; i++ {
response, err := resolveQuery(server, cname, dns.TypeCNAME, false)
if err != nil {
break cname
}
found := false
for _, answer := range response.Answer {
if answer.Header().Rrtype != dns.TypeCNAME || answer.Header().Class != dns.ClassINET {
continue
}
cname = answer.(*dns.CNAME).Target
found = true
break
}
if !found {
break
}
}
fmt.Println(cname)
}
fmt.Printf("IP addresses: ")
addrs, err := net.LookupHost(name)
if err != nil {
fmt.Println("-")
} else {
fmt.Println(strings.Join(addrs, ", "))
}
fmt.Println("")
fmt.Printf("TXT records: ")
txt, err := net.LookupTXT(name)
if err != nil {
fmt.Println("-")
} else {
fmt.Println(strings.Join(txt, " "))
}
resIP, err := net.LookupHost(myResolverHost)
if err == nil && len(resIP) > 0 {
fmt.Printf("Resolver IP: %s", resIP[0])
rev, err := net.LookupAddr(resIP[0])
if err == nil && len(rev) > 0 {
fmt.Printf(" (%s)", rev[0])
for once := true; once; once = false {
fmt.Printf("IPv4 addresses: ")
response, err := resolveQuery(server, cname, dns.TypeA, false)
if err != nil {
break
}
ipv4 := make([]string, 0)
for _, answer := range response.Answer {
if answer.Header().Rrtype != dns.TypeA || answer.Header().Class != dns.ClassINET {
continue
}
ipv4 = append(ipv4, answer.(*dns.A).A.String())
}
if len(ipv4) == 0 {
fmt.Println("-")
} else {
fmt.Println(strings.Join(ipv4, ", "))
}
fmt.Println("")
}
for once := true; once; once = false {
fmt.Printf("IPv6 addresses: ")
response, err := resolveQuery(server, cname, dns.TypeAAAA, false)
if err != nil {
break
}
ipv6 := make([]string, 0)
for _, answer := range response.Answer {
if answer.Header().Rrtype != dns.TypeAAAA || answer.Header().Class != dns.ClassINET {
continue
}
ipv6 = append(ipv6, answer.(*dns.AAAA).AAAA.String())
}
if len(ipv6) == 0 {
fmt.Println("-")
} else {
fmt.Println(strings.Join(ipv6, ", "))
}
}
fmt.Println("")
for once := true; once; once = false {
fmt.Printf("Name servers : ")
response, err := resolveQuery(server, cname, dns.TypeNS, false)
if err != nil {
break
}
nss := make([]string, 0)
for _, answer := range response.Answer {
if answer.Header().Rrtype != dns.TypeNS || answer.Header().Class != dns.ClassINET {
continue
}
nss = append(nss, answer.(*dns.NS).Ns)
}
if response.Rcode == dns.RcodeNameError {
fmt.Println("name does not exist")
} else if response.Rcode != dns.RcodeSuccess {
fmt.Printf("server returned %s", dns.RcodeToString[response.Rcode])
} else if len(nss) == 0 {
fmt.Println("no name servers found")
} else {
fmt.Println(strings.Join(nss, ", "))
}
fmt.Printf("DNSSEC signed : ")
if response.AuthenticatedData {
fmt.Println("yes")
} else {
fmt.Println("no")
}
}
for once := true; once; once = false {
fmt.Printf("Mail servers : ")
response, err := resolveQuery(server, cname, dns.TypeMX, false)
if err != nil {
break
}
mxs := make([]string, 0)
for _, answer := range response.Answer {
if answer.Header().Rrtype != dns.TypeMX || answer.Header().Class != dns.ClassINET {
continue
}
mxs = append(mxs, answer.(*dns.MX).Mx)
}
if len(mxs) == 0 {
fmt.Println("no mail servers found")
} else if len(mxs) > 1 {
fmt.Printf("%d mail servers found\n", len(mxs))
} else {
fmt.Println("1 mail servers found")
}
}
fmt.Println("")
for once := true; once; once = false {
fmt.Printf("HTTPS alias : ")
response, err := resolveQuery(server, cname, dns.TypeHTTPS, false)
if err != nil {
break
}
aliases := make([]string, 0)
for _, answer := range response.Answer {
if answer.Header().Rrtype != dns.TypeHTTPS || answer.Header().Class != dns.ClassINET {
continue
}
https := answer.(*dns.HTTPS)
if https.Priority != 0 || len(https.Target) < 2 {
continue
}
aliases = append(aliases, https.Target)
}
if len(aliases) == 0 {
fmt.Println("-")
} else {
fmt.Println(strings.Join(aliases, ", "))
}
fmt.Printf("HTTPS info : ")
info := make([]string, 0)
for _, answer := range response.Answer {
if answer.Header().Rrtype != dns.TypeHTTPS || answer.Header().Class != dns.ClassINET {
continue
}
https := answer.(*dns.HTTPS)
if https.Priority == 0 || len(https.Target) > 1 {
continue
}
for _, value := range https.Value {
info = append(info, fmt.Sprintf("[%s]=[%s]", value.Key(), value.String()))
}
}
if len(info) == 0 {
fmt.Println("-")
} else {
fmt.Println(strings.Join(info, ", "))
}
}
fmt.Println("")
for once := true; once; once = false {
fmt.Printf("Host info : ")
response, err := resolveQuery(server, cname, dns.TypeHINFO, false)
if err != nil {
break
}
hinfo := make([]string, 0)
for _, answer := range response.Answer {
if answer.Header().Rrtype != dns.TypeHINFO || answer.Header().Class != dns.ClassINET {
continue
}
hinfo = append(hinfo, fmt.Sprintf("%s %s", answer.(*dns.HINFO).Cpu, answer.(*dns.HINFO).Os))
}
if len(hinfo) == 0 {
fmt.Println("-")
} else {
fmt.Println(strings.Join(hinfo, ", "))
}
}
for once := true; once; once = false {
fmt.Printf("TXT records : ")
response, err := resolveQuery(server, cname, dns.TypeTXT, false)
if err != nil {
break
}
txt := make([]string, 0)
for _, answer := range response.Answer {
if answer.Header().Rrtype != dns.TypeTXT || answer.Header().Class != dns.ClassINET {
continue
}
txt = append(txt, strings.Join(answer.(*dns.TXT).Txt, " "))
}
if len(txt) == 0 {
fmt.Println("-")
} else {
fmt.Println(strings.Join(txt, ", "))
}
}
fmt.Println("")
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,12 @@
//go:build android
// +build android
package main
func ServiceManagerStartNotify() error {
return nil
}
func ServiceManagerReadyNotify() error {
return nil
}

View File

@ -1,12 +1,36 @@
//go:build !android
// +build !android
package main
import "github.com/coreos/go-systemd/daemon"
import (
"github.com/coreos/go-systemd/daemon"
clocksmith "github.com/jedisct1/go-clocksmith"
)
const SdNotifyStatus = "STATUS="
func ServiceManagerStartNotify() error {
daemon.SdNotify(false, "STATUS=Starting")
daemon.SdNotify(false, SdNotifyStatus+"Starting...")
return nil
}
func ServiceManagerReadyNotify() {
daemon.SdNotify(false, "READY=1")
func ServiceManagerReadyNotify() error {
daemon.SdNotify(false, daemon.SdNotifyReady+"\n"+SdNotifyStatus+"Ready")
return systemDWatchdog()
}
func systemDWatchdog() error {
watchdogFailureDelay, err := daemon.SdWatchdogEnabled(false)
if err != nil || watchdogFailureDelay == 0 {
return err
}
refreshInterval := watchdogFailureDelay / 3
go func() {
for {
daemon.SdNotify(false, daemon.SdNotifyWatchdog)
clocksmith.Sleep(refreshInterval)
}
}()
return nil
}

View File

@ -1,3 +1,4 @@
//go:build !linux && !windows
// +build !linux,!windows
package main
@ -6,5 +7,6 @@ func ServiceManagerStartNotify() error {
return nil
}
func ServiceManagerReadyNotify() {
func ServiceManagerReadyNotify() error {
return nil
}

View File

@ -7,8 +7,11 @@ func ServiceManagerStartNotify() error {
if err != nil {
return err
}
mgr.Disconnect()
_ = mgr.Disconnect()
return nil
}
func ServiceManagerReadyNotify() {}
func ServiceManagerReadyNotify() error {
return nil
}

View File

@ -0,0 +1,31 @@
package main
import (
"net"
"syscall"
)
func (proxy *Proxy) udpListenerConfig() (*net.ListenConfig, error) {
return &net.ListenConfig{
Control: func(network, address string, c syscall.RawConn) error {
_ = c.Control(func(fd uintptr) {
_ = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_DF, 0)
_ = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_TOS, 0x70)
_ = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_RCVBUF, 4096)
_ = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_SNDBUF, 4096)
})
return nil
},
}, nil
}
func (proxy *Proxy) tcpListenerConfig() (*net.ListenConfig, error) {
return &net.ListenConfig{
Control: func(network, address string, c syscall.RawConn) error {
_ = c.Control(func(fd uintptr) {
_ = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_TOS, 0x70)
})
return nil
},
}, nil
}

View File

@ -0,0 +1,35 @@
package main
import (
"net"
"syscall"
)
func (proxy *Proxy) udpListenerConfig() (*net.ListenConfig, error) {
return &net.ListenConfig{
Control: func(network, address string, c syscall.RawConn) error {
_ = c.Control(func(fd uintptr) {
_ = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BINDANY, 1)
_ = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IPV6_BINDANY, 1)
_ = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_DF, 0)
_ = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_TOS, 0x70)
_ = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_RCVBUF, 4096)
_ = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_SNDBUF, 4096)
})
return nil
},
}, nil
}
func (proxy *Proxy) tcpListenerConfig() (*net.ListenConfig, error) {
return &net.ListenConfig{
Control: func(network, address string, c syscall.RawConn) error {
_ = c.Control(func(fd uintptr) {
_ = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BINDANY, 1)
_ = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IPV6_BINDANY, 1)
_ = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_TOS, 0x70)
})
return nil
},
}, nil
}

View File

@ -0,0 +1,40 @@
package main
import (
"net"
"syscall"
)
func (proxy *Proxy) udpListenerConfig() (*net.ListenConfig, error) {
return &net.ListenConfig{
Control: func(network, address string, c syscall.RawConn) error {
_ = c.Control(func(fd uintptr) {
_ = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_FREEBIND, 1)
_ = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_DF, 0)
_ = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_TOS, 0x70)
_ = syscall.SetsockoptInt(
int(fd),
syscall.IPPROTO_IP,
syscall.IP_MTU_DISCOVER,
syscall.IP_PMTUDISC_DONT,
)
_ = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_RCVBUFFORCE, 4096)
_ = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_SNDBUFFORCE, 4096)
})
return nil
},
}, nil
}
func (proxy *Proxy) tcpListenerConfig() (*net.ListenConfig, error) {
return &net.ListenConfig{
Control: func(network, address string, c syscall.RawConn) error {
_ = c.Control(func(fd uintptr) {
_ = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_FREEBIND, 1)
_ = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_TOS, 0x70)
_ = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_QUICKACK, 1)
})
return nil
},
}, nil
}

View File

@ -0,0 +1,33 @@
package main
import (
"net"
"syscall"
)
func (proxy *Proxy) udpListenerConfig() (*net.ListenConfig, error) {
return &net.ListenConfig{
Control: func(network, address string, c syscall.RawConn) error {
_ = c.Control(func(fd uintptr) {
_ = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_BINDANY, 1)
_ = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_DF, 0)
_ = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_TOS, 0x70)
_ = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_RCVBUF, 4096)
_ = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_SNDBUF, 4096)
})
return nil
},
}, nil
}
func (proxy *Proxy) tcpListenerConfig() (*net.ListenConfig, error) {
return &net.ListenConfig{
Control: func(network, address string, c syscall.RawConn) error {
_ = c.Control(func(fd uintptr) {
_ = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_BINDANY, 1)
_ = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_TOS, 0x70)
})
return nil
},
}, nil
}

View File

@ -0,0 +1,16 @@
//go:build !freebsd && !openbsd && !windows && !darwin && !linux
// +build !freebsd,!openbsd,!windows,!darwin,!linux
package main
import (
"net"
)
func (proxy *Proxy) udpListenerConfig() (*net.ListenConfig, error) {
return &net.ListenConfig{}, nil
}
func (proxy *Proxy) tcpListenerConfig() (*net.ListenConfig, error) {
return &net.ListenConfig{}, nil
}

View File

@ -0,0 +1,30 @@
package main
import (
"net"
"syscall"
)
func (proxy *Proxy) udpListenerConfig() (*net.ListenConfig, error) {
return &net.ListenConfig{
Control: func(network, address string, c syscall.RawConn) error {
_ = c.Control(func(fd uintptr) {
_ = syscall.SetsockoptInt(syscall.Handle(fd), syscall.IPPROTO_IP, syscall.IP_TOS, 0x70)
_ = syscall.SetsockoptInt(syscall.Handle(fd), syscall.SOL_SOCKET, syscall.SO_RCVBUF, 4096)
_ = syscall.SetsockoptInt(syscall.Handle(fd), syscall.SOL_SOCKET, syscall.SO_SNDBUF, 4096)
})
return nil
},
}, nil
}
func (proxy *Proxy) tcpListenerConfig() (*net.ListenConfig, error) {
return &net.ListenConfig{
Control: func(network, address string, c syscall.RawConn) error {
_ = c.Control(func(fd uintptr) {
_ = syscall.SetsockoptInt(syscall.Handle(fd), syscall.IPPROTO_IP, syscall.IP_TOS, 0x70)
})
return nil
},
}, nil
}

View File

@ -1,22 +1,19 @@
package main
import (
"errors"
"bytes"
"fmt"
"io"
"io/ioutil"
"net/http"
"math/rand"
"net/url"
"os"
"path/filepath"
"strings"
"time"
"unicode"
"github.com/dchest/safefile"
"github.com/jedisct1/dlog"
stamps "github.com/jedisct1/go-dnsstamps"
"github.com/jedisct1/go-dnsstamps"
"github.com/jedisct1/go-minisign"
)
@ -27,220 +24,268 @@ const (
)
const (
SourcesUpdateDelay = time.Duration(24) * time.Hour
DefaultPrefetchDelay time.Duration = 24 * time.Hour
MinimumPrefetchInterval time.Duration = 10 * time.Minute
)
type Source struct {
urls []string
format SourceFormat
in string
name string
urls []*url.URL
format SourceFormat
bin []byte
minisignKey *minisign.PublicKey
cacheFile string
cacheTTL, prefetchDelay time.Duration
refresh time.Time
prefix string
}
func fetchFromCache(cacheFile string) (in string, expired bool, delayTillNextUpdate time.Duration, err error) {
expired = false
fi, err := os.Stat(cacheFile)
if err != nil {
dlog.Debugf("Cache file [%s] not present", cacheFile)
delayTillNextUpdate = time.Duration(0)
return
// timeNow() is replaced by tests to provide a static value
var timeNow = time.Now
func (source *Source) checkSignature(bin, sig []byte) error {
signature, err := minisign.DecodeSignature(string(sig))
if err == nil {
_, err = source.minisignKey.Verify(bin, signature)
}
elapsed := time.Since(fi.ModTime())
if elapsed < SourcesUpdateDelay {
dlog.Debugf("Cache file [%s] is still fresh", cacheFile)
delayTillNextUpdate = SourcesUpdateDelay - elapsed
return err
}
func (source *Source) fetchFromCache(now time.Time) (time.Duration, error) {
var err error
var bin, sig []byte
if bin, err = os.ReadFile(source.cacheFile); err != nil {
return 0, err
}
if sig, err = os.ReadFile(source.cacheFile + ".minisig"); err != nil {
return 0, err
}
if err = source.checkSignature(bin, sig); err != nil {
return 0, err
}
source.bin = bin
var fi os.FileInfo
if fi, err = os.Stat(source.cacheFile); err != nil {
return 0, err
}
var ttl time.Duration = 0
if elapsed := now.Sub(fi.ModTime()); elapsed < source.cacheTTL {
ttl = source.prefetchDelay - elapsed
dlog.Debugf("Source [%s] cache file [%s] is still fresh, next update: %v", source.name, source.cacheFile, ttl)
} else {
dlog.Debugf("Cache file [%s] needs to be refreshed", cacheFile)
delayTillNextUpdate = time.Duration(0)
dlog.Debugf("Source [%s] cache file [%s] needs to be refreshed", source.name, source.cacheFile)
}
var bin []byte
bin, err = ioutil.ReadFile(cacheFile)
if err != nil {
delayTillNextUpdate = time.Duration(0)
return
}
in = string(bin)
if delayTillNextUpdate <= time.Duration(0) {
expired = true
}
return
return ttl, nil
}
func fetchWithCache(xTransport *XTransport, urlStr string, cacheFile string) (in string, cached bool, delayTillNextUpdate time.Duration, err error) {
cached = false
expired := false
in, expired, delayTillNextUpdate, err = fetchFromCache(cacheFile)
if err == nil && !expired {
dlog.Debugf("Delay till next update: %v", delayTillNextUpdate)
cached = true
return
func writeSource(f string, bin, sig []byte) error {
var err error
var fSrc, fSig *safefile.File
if fSrc, err = safefile.Create(f, 0o644); err != nil {
return err
}
if expired {
cached = true
defer fSrc.Close()
if fSig, err = safefile.Create(f+".minisig", 0o644); err != nil {
return err
}
if len(urlStr) == 0 {
if !expired {
err = fmt.Errorf("Cache file [%s] not present and no URL given to retrieve it", cacheFile)
defer fSig.Close()
if _, err = fSrc.Write(bin); err != nil {
return err
}
if _, err = fSig.Write(sig); err != nil {
return err
}
if err = fSrc.Commit(); err != nil {
return err
}
return fSig.Commit()
}
func (source *Source) updateCache(bin, sig []byte, now time.Time) {
file := source.cacheFile
absPath := file
if resolved, err := filepath.Abs(file); err != nil {
absPath = resolved
}
if !bytes.Equal(source.bin, bin) {
if err := writeSource(file, bin, sig); err != nil {
dlog.Warnf("Couldn't write cache file [%s]: %s", absPath, err) // an error writing to the cache isn't fatal
}
return
}
if err := os.Chtimes(file, now, now); err != nil {
dlog.Warnf("Couldn't update cache file [%s]: %s", absPath, err)
}
var resp *http.Response
dlog.Infof("Loading source information from URL [%s]", urlStr)
source.bin = bin
}
url, err := url.Parse(urlStr)
func (source *Source) parseURLs(urls []string) {
for _, urlStr := range urls {
if srcURL, err := url.Parse(urlStr); err != nil {
dlog.Warnf("Source [%s] failed to parse URL [%s]", source.name, urlStr)
} else {
source.urls = append(source.urls, srcURL)
}
}
}
func fetchFromURL(xTransport *XTransport, u *url.URL) ([]byte, error) {
bin, _, _, _, err := xTransport.GetWithCompression(u, "", DefaultTimeout)
return bin, err
}
func (source *Source) fetchWithCache(xTransport *XTransport, now time.Time) (time.Duration, error) {
var err error
var ttl time.Duration
if ttl, err = source.fetchFromCache(now); err != nil {
if len(source.urls) == 0 {
dlog.Errorf("Source [%s] cache file [%s] not present and no valid URL", source.name, source.cacheFile)
return 0, err
}
dlog.Debugf("Source [%s] cache file [%s] not present", source.name, source.cacheFile)
}
if len(source.urls) == 0 {
return 0, err
}
if ttl > 0 {
source.refresh = now.Add(ttl)
return 0, err
}
ttl = MinimumPrefetchInterval
source.refresh = now.Add(ttl)
var bin, sig []byte
for _, srcURL := range source.urls {
dlog.Infof("Source [%s] loading from URL [%s]", source.name, srcURL)
sigURL := &url.URL{}
*sigURL = *srcURL // deep copy to avoid parsing twice
sigURL.Path += ".minisig"
if bin, err = fetchFromURL(xTransport, srcURL); err != nil {
dlog.Debugf("Source [%s] failed to download from URL [%s]", source.name, srcURL)
continue
}
if sig, err = fetchFromURL(xTransport, sigURL); err != nil {
dlog.Debugf("Source [%s] failed to download signature from URL [%s]", source.name, sigURL)
continue
}
if err = source.checkSignature(bin, sig); err != nil {
dlog.Debugf("Source [%s] failed signature check using URL [%s]", source.name, srcURL)
continue
}
break // valid signature
}
if err != nil {
return
return 0, err
}
resp, _, err = xTransport.Get(url, "", 30*time.Second)
if err == nil && resp != nil && (resp.StatusCode < 200 || resp.StatusCode > 299) {
err = fmt.Errorf("Webserver returned code %d", resp.StatusCode)
return
} else if err != nil {
return
} else if resp == nil {
err = errors.New("Webserver returned an error")
return
}
var bin []byte
bin, err = ioutil.ReadAll(io.LimitReader(resp.Body, MaxHTTPBodyLength))
resp.Body.Close()
if err != nil {
return
}
err = nil
cached = false
in = string(bin)
delayTillNextUpdate = SourcesUpdateDelay
return
source.updateCache(bin, sig, now)
ttl = source.prefetchDelay
source.refresh = now.Add(ttl)
return ttl, nil
}
func AtomicFileWrite(file string, data []byte) error {
return safefile.WriteFile(file, data, 0644)
}
type URLToPrefetch struct {
url string
cacheFile string
when time.Time
}
func NewSource(xTransport *XTransport, urls []string, minisignKeyStr string, cacheFile string, formatStr string, refreshDelay time.Duration) (Source, []URLToPrefetch, error) {
_ = refreshDelay
source := Source{urls: urls}
// NewSource loads a new source using the given cacheFile and urls, ensuring it has a valid signature
func NewSource(
name string,
xTransport *XTransport,
urls []string,
minisignKeyStr string,
cacheFile string,
formatStr string,
refreshDelay time.Duration,
prefix string,
) (*Source, error) {
if refreshDelay < DefaultPrefetchDelay {
refreshDelay = DefaultPrefetchDelay
}
source := &Source{
name: name,
urls: []*url.URL{},
cacheFile: cacheFile,
cacheTTL: refreshDelay,
prefetchDelay: DefaultPrefetchDelay,
prefix: prefix,
}
if formatStr == "v2" {
source.format = SourceFormatV2
} else {
return source, []URLToPrefetch{}, fmt.Errorf("Unsupported source format: [%s]", formatStr)
return source, fmt.Errorf("Unsupported source format: [%s]", formatStr)
}
minisignKey, err := minisign.NewPublicKey(minisignKeyStr)
if err != nil {
return source, []URLToPrefetch{}, err
}
now := time.Now()
urlsToPrefetch := []URLToPrefetch{}
sigCacheFile := cacheFile + ".minisig"
var sigStr, in string
var cached, sigCached bool
var delayTillNextUpdate, sigDelayTillNextUpdate time.Duration
var sigErr error
var preloadURL string
if len(urls) <= 0 {
in, cached, delayTillNextUpdate, err = fetchWithCache(xTransport, "", cacheFile)
sigStr, sigCached, sigDelayTillNextUpdate, sigErr = fetchWithCache(xTransport, "", sigCacheFile)
if minisignKey, err := minisign.NewPublicKey(minisignKeyStr); err == nil {
source.minisignKey = &minisignKey
} else {
preloadURL = urls[0]
for _, url := range urls {
sigURL := url + ".minisig"
in, cached, delayTillNextUpdate, err = fetchWithCache(xTransport, url, cacheFile)
sigStr, sigCached, sigDelayTillNextUpdate, sigErr = fetchWithCache(xTransport, sigURL, sigCacheFile)
if err == nil && sigErr == nil {
preloadURL = url
break
}
dlog.Infof("Loading from [%s] failed", url)
}
return source, err
}
if len(preloadURL) > 0 {
url := preloadURL
sigURL := url + ".minisig"
urlsToPrefetch = append(urlsToPrefetch, URLToPrefetch{url: url, cacheFile: cacheFile, when: now.Add(delayTillNextUpdate)})
urlsToPrefetch = append(urlsToPrefetch, URLToPrefetch{url: sigURL, cacheFile: sigCacheFile, when: now.Add(sigDelayTillNextUpdate)})
source.parseURLs(urls)
_, err := source.fetchWithCache(xTransport, timeNow())
if err == nil {
dlog.Noticef("Source [%s] loaded", name)
}
if sigErr != nil && err == nil {
err = sigErr
}
if err != nil {
return source, urlsToPrefetch, err
}
signature, err := minisign.DecodeSignature(sigStr)
if err != nil {
os.Remove(cacheFile)
os.Remove(sigCacheFile)
return source, urlsToPrefetch, err
}
res, err := minisignKey.Verify([]byte(in), signature)
if err != nil || !res {
os.Remove(cacheFile)
os.Remove(sigCacheFile)
return source, urlsToPrefetch, err
}
if !cached {
if err = AtomicFileWrite(cacheFile, []byte(in)); err != nil {
if absPath, err2 := filepath.Abs(cacheFile); err2 == nil {
dlog.Warnf("%s: %s", absPath, err)
}
}
}
if !sigCached {
if err = AtomicFileWrite(sigCacheFile, []byte(sigStr)); err != nil {
if absPath, err2 := filepath.Abs(sigCacheFile); err2 == nil {
dlog.Warnf("%s: %s", absPath, err)
}
}
}
dlog.Noticef("Source [%s] loaded", cacheFile)
source.in = in
return source, urlsToPrefetch, nil
return source, err
}
func (source *Source) Parse(prefix string) ([]RegisteredServer, error) {
// PrefetchSources downloads latest versions of given sources, ensuring they have a valid signature before caching
func PrefetchSources(xTransport *XTransport, sources []*Source) time.Duration {
now := timeNow()
interval := MinimumPrefetchInterval
for _, source := range sources {
if source.refresh.IsZero() || source.refresh.After(now) {
continue
}
dlog.Debugf("Prefetching [%s]", source.name)
if delay, err := source.fetchWithCache(xTransport, now); err != nil {
dlog.Infof("Prefetching [%s] failed: %v, will retry in %v", source.name, err, interval)
} else {
dlog.Debugf("Prefetching [%s] succeeded, next update in %v min", source.name, delay)
if delay >= MinimumPrefetchInterval && (interval == MinimumPrefetchInterval || interval > delay) {
interval = delay
}
}
}
return interval
}
func (source *Source) Parse() ([]RegisteredServer, error) {
if source.format == SourceFormatV2 {
return source.parseV2(prefix)
return source.parseV2()
}
dlog.Fatal("Unexpected source format")
return []RegisteredServer{}, nil
}
func (source *Source) parseV2(prefix string) ([]RegisteredServer, error) {
func (source *Source) parseV2() ([]RegisteredServer, error) {
var registeredServers []RegisteredServer
in := string(source.in)
var stampErrs []string
appendStampErr := func(format string, a ...interface{}) {
stampErr := fmt.Sprintf(format, a...)
stampErrs = append(stampErrs, stampErr)
dlog.Warn(stampErr)
}
in := string(source.bin)
parts := strings.Split(in, "## ")
if len(parts) < 2 {
return registeredServers, fmt.Errorf("Invalid format for source at [%v]", source.urls)
}
parts = parts[1:]
for _, part := range parts {
part = strings.TrimFunc(part, unicode.IsSpace)
part = strings.TrimSpace(part)
subparts := strings.Split(part, "\n")
if len(subparts) < 2 {
return registeredServers, fmt.Errorf("Invalid format for source at [%v]", source.urls)
}
name := strings.TrimFunc(subparts[0], unicode.IsSpace)
name := strings.TrimSpace(subparts[0])
if len(name) == 0 {
return registeredServers, fmt.Errorf("Invalid format for source at [%v]", source.urls)
}
subparts = subparts[1:]
name = prefix + name
name = source.prefix + name
var stampStr, description string
stampStrs := make([]string, 0)
for _, subpart := range subparts {
subpart = strings.TrimFunc(subpart, unicode.IsSpace)
if strings.HasPrefix(subpart, "sdns:") {
if len(stampStr) > 0 {
return registeredServers, fmt.Errorf("Multiple stamps for server [%s] in source from [%v]", name, source.urls)
}
stampStr = subpart
subpart = strings.TrimSpace(subpart)
if strings.HasPrefix(subpart, "sdns:") && len(subpart) >= 6 {
stampStrs = append(stampStrs, subpart)
continue
} else if len(subpart) == 0 || strings.HasPrefix(subpart, "//") {
continue
@ -250,13 +295,24 @@ func (source *Source) parseV2(prefix string) ([]RegisteredServer, error) {
}
description += subpart
}
if len(stampStr) < 6 {
return registeredServers, fmt.Errorf("Missing stamp for server [%s] in source from [%v]", name, source.urls)
stampStrsLen := len(stampStrs)
if stampStrsLen <= 0 {
appendStampErr("Missing stamp for server [%s]", name)
continue
} else if stampStrsLen > 1 {
rand.Shuffle(stampStrsLen, func(i, j int) { stampStrs[i], stampStrs[j] = stampStrs[j], stampStrs[i] })
}
var stamp dnsstamps.ServerStamp
var err error
for _, stampStr = range stampStrs {
stamp, err = dnsstamps.NewServerStampFromString(stampStr)
if err == nil {
break
}
appendStampErr("Invalid or unsupported stamp [%v]: %s", stampStr, err.Error())
}
stamp, err := stamps.NewServerStampFromString(stampStr)
if err != nil {
dlog.Errorf("Invalid or unsupported stamp: [%v]", stampStr)
return registeredServers, err
continue
}
registeredServer := RegisteredServer{
name: name, stamp: stamp, description: description,
@ -264,14 +320,8 @@ func (source *Source) parseV2(prefix string) ([]RegisteredServer, error) {
dlog.Debugf("Registered [%s] with stamp [%s]", name, stamp.String())
registeredServers = append(registeredServers, registeredServer)
}
if len(stampErrs) > 0 {
return registeredServers, fmt.Errorf("%s", strings.Join(stampErrs, ", "))
}
return registeredServers, nil
}
func PrefetchSourceURL(xTransport *XTransport, urlToPrefetch *URLToPrefetch) error {
in, cached, delayTillNextUpdate, err := fetchWithCache(xTransport, urlToPrefetch.url, urlToPrefetch.cacheFile)
if err == nil && !cached {
AtomicFileWrite(urlToPrefetch.cacheFile, []byte(in))
}
urlToPrefetch.when = time.Now().Add(delayTillNextUpdate)
return err
}

View File

@ -0,0 +1,491 @@
package main
import (
"bytes"
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"os"
"path/filepath"
"strconv"
"strings"
"testing"
"time"
"github.com/hectane/go-acl"
"github.com/jedisct1/dlog"
"github.com/jedisct1/go-minisign"
"github.com/powerman/check"
)
type SourceFixture struct {
suffix string
content []byte
length string // HTTP Content-Length header
perms os.FileMode
mtime time.Time
}
type SourceTestState uint8
const (
TestStateCorrect SourceTestState = iota // valid files
TestStateExpired // modification time of files set in distant past (cache only)
TestStatePartial // incomplete files
TestStatePartialSig // incomplete .minisig
TestStateMissing // non-existent files
TestStateMissingSig // non-existent .minisig
TestStateReadErr // I/O error on reading files (download only)
TestStateReadSigErr // I/O error on reading .minisig (download only)
TestStateOpenErr // I/O error on opening files
TestStateOpenSigErr // I/O error on opening .minisig
TestStatePathErr // unparseable path to files (download only)
)
type SourceTestData struct {
n int // subtest counter
xTransport *XTransport
key *minisign.PublicKey
keyStr, tempDir string
sources []string
fixtures map[SourceTestState]map[string]SourceFixture
timeNow, timeOld, timeUpd time.Time
server *httptest.Server
reqActual, reqExpect map[string]uint
cacheTests map[string]SourceTestState
downloadTests map[string][]SourceTestState
}
type SourceTestExpect struct {
success bool
err, cachePath string
cache []SourceFixture
mtime time.Time
urls []string
Source *Source
delay time.Duration
prefix string
}
func readFixture(t *testing.T, name string) []byte {
bin, err := os.ReadFile(filepath.Join("testdata", name))
if err != nil {
t.Fatalf("Unable to read test fixture %s: %v", name, err)
}
return bin
}
func writeSourceCache(t *testing.T, e *SourceTestExpect) {
for _, f := range e.cache {
if f.content == nil {
continue
}
path := e.cachePath + f.suffix
perms := f.perms
if perms == 0 {
perms = 0o644
}
if err := os.WriteFile(path, f.content, perms); err != nil {
t.Fatalf("Unable to write cache file %s: %v", path, err)
}
if err := acl.Chmod(path, perms); err != nil {
t.Fatalf("Unable to set permissions on cache file %s: %v", path, err)
}
if f.suffix != "" {
continue
}
mtime := f.mtime
if f.mtime.IsZero() {
mtime = e.mtime
}
if err := os.Chtimes(path, mtime, mtime); err != nil {
t.Fatalf("Unable to touch cache file %s to %v: %v", path, f.mtime, err)
}
}
}
func checkSourceCache(c *check.C, e *SourceTestExpect) {
for _, f := range e.cache {
path := e.cachePath + f.suffix
_ = acl.Chmod(path, 0o644) // don't worry if this fails, reading it will catch the same problem
got, err := os.ReadFile(path)
c.DeepEqual(got, f.content, "Unexpected content for cache file '%s', err %v", path, err)
if f.suffix != "" {
continue
}
if fi, err := os.Stat(path); err == nil { // again, if this failed it was already caught above
mtime := f.mtime
if f.mtime.IsZero() {
mtime = e.mtime
}
c.EQ(fi.ModTime(), mtime, "Unexpected timestamp for cache file '%s'", path)
}
}
}
func loadSnakeoil(t *testing.T, d *SourceTestData) {
key, err := minisign.NewPublicKeyFromFile(filepath.Join("testdata", "snakeoil.pub"))
if err != nil {
t.Fatalf("Unable to load snakeoil key: %v", err)
}
d.keyStr = string(bytes.SplitN(readFixture(t, "snakeoil.pub"), []byte("\n"), 2)[1])
d.key = &key
}
func loadTestSourceNames(t *testing.T, d *SourceTestData) {
files, err := os.ReadDir(filepath.Join("testdata", "sources"))
if err != nil {
t.Fatalf("Unable to load list of test sources: %v", err)
}
for _, file := range files {
if !file.IsDir() && strings.HasSuffix(file.Name(), ".minisig") {
d.sources = append(d.sources, strings.TrimSuffix(file.Name(), ".minisig"))
}
}
}
func generateFixtureState(_ *testing.T, d *SourceTestData, suffix, file string, state SourceTestState) {
if _, ok := d.fixtures[state]; !ok {
d.fixtures[state] = map[string]SourceFixture{}
}
if suffix != ".minisig" {
switch state {
case TestStatePartialSig, TestStateMissingSig, TestStateReadSigErr, TestStateOpenSigErr:
d.fixtures[state][file] = d.fixtures[TestStateCorrect][file]
return
}
}
f := SourceFixture{suffix: suffix}
switch state {
case TestStateExpired:
f.content, f.mtime = d.fixtures[TestStateCorrect][file].content, d.timeOld
case TestStatePartial, TestStatePartialSig:
f.content = d.fixtures[TestStateCorrect][file].content[:1]
case TestStateReadErr, TestStateReadSigErr:
f.content, f.length = []byte{}, "1"
case TestStateOpenErr, TestStateOpenSigErr:
f.content, f.perms = d.fixtures[TestStateCorrect][file].content[:1], 0o200
}
d.fixtures[state][file] = f
}
func loadFixtures(t *testing.T, d *SourceTestData) {
d.fixtures = map[SourceTestState]map[string]SourceFixture{TestStateCorrect: {}}
for _, source := range d.sources {
for _, suffix := range [...]string{"", ".minisig"} {
file := source + suffix
d.fixtures[TestStateCorrect][file] = SourceFixture{
suffix: suffix,
content: readFixture(t, filepath.Join("sources", file)),
}
for _, state := range [...]SourceTestState{
TestStateExpired,
TestStatePartial,
TestStateReadErr,
TestStateOpenErr,
TestStatePartialSig,
TestStateMissingSig,
TestStateReadSigErr,
TestStateOpenSigErr,
} {
generateFixtureState(t, d, suffix, file, state)
}
}
}
}
func makeTempDir(t *testing.T, d *SourceTestData) {
name, err := os.MkdirTemp("", "sources_test.go."+t.Name())
if err != nil {
t.Fatalf("Unable to create temporary directory: %v", err)
}
d.tempDir = name
}
func makeTestServer(t *testing.T, d *SourceTestData) {
d.reqActual, d.reqExpect = map[string]uint{}, map[string]uint{}
d.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var data []byte = nil
d.reqActual[r.URL.Path]++
pathParts := strings.SplitN(strings.TrimPrefix(r.URL.Path, "/"), "/", 2)
state, _ := strconv.ParseUint(pathParts[0], 10, 8)
if fixture, ok := d.fixtures[SourceTestState(state)][pathParts[1]]; ok {
if len(fixture.length) > 0 {
w.Header().Set("Content-Length", fixture.length) // client will return unexpected EOF
}
data = fixture.content
}
if data != nil {
if _, err := w.Write(data); err != nil {
t.Logf("Error writing HTTP response for request [%s]: %v", r.URL.Path, err)
}
} else {
w.WriteHeader(http.StatusNotFound)
}
}))
}
func checkTestServer(c *check.C, d *SourceTestData) {
c.DeepEqual(d.reqActual, d.reqExpect, "Unexpected HTTP request log")
d.reqActual, d.reqExpect = map[string]uint{}, map[string]uint{}
}
func setupSourceTest(t *testing.T) (func(), *SourceTestData) {
d := &SourceTestData{n: -1, xTransport: NewXTransport()}
d.cacheTests = map[string]SourceTestState{ // determines cache files written to disk before each call
"correct": TestStateCorrect,
"expired": TestStateExpired,
"partial": TestStatePartial,
"partial-sig": TestStatePartialSig,
"missing": TestStateMissing,
"missing-sig": TestStateMissingSig,
"open-err": TestStateOpenErr,
"open-sig-err": TestStateOpenSigErr,
}
d.downloadTests = map[string][]SourceTestState{ // determines the list of URLs passed in each call and how they will respond
"correct": {TestStateCorrect},
"partial": {TestStatePartial},
"partial-sig": {TestStatePartialSig},
"missing": {TestStateMissing},
"missing-sig": {TestStateMissingSig},
"read-err": {TestStateReadErr},
"read-sig-err": {TestStateReadSigErr},
"open-err": {TestStateOpenErr},
"open-sig-err": {TestStateOpenSigErr},
"path-err": {TestStatePathErr},
"partial,correct": {TestStatePartial, TestStateCorrect},
"partial-sig,correct": {TestStatePartialSig, TestStateCorrect},
"missing,correct": {TestStateMissing, TestStateCorrect},
"missing-sig,correct": {TestStateMissingSig, TestStateCorrect},
"read-err,correct": {TestStateReadErr, TestStateCorrect},
"read-sig-err,correct": {TestStateReadSigErr, TestStateCorrect},
"open-err,correct": {TestStateOpenErr, TestStateCorrect},
"open-sig-err,correct": {TestStateOpenSigErr, TestStateCorrect},
"path-err,correct": {TestStatePathErr, TestStateCorrect},
"no-urls": {},
}
d.xTransport.rebuildTransport()
d.timeNow = time.Now().AddDate(0, 0, 0).Truncate(time.Second)
d.timeOld = d.timeNow.Add(DefaultPrefetchDelay * -4)
d.timeUpd = d.timeNow.Add(DefaultPrefetchDelay)
timeNow = func() time.Time { return d.timeNow } // originally defined in sources.go, replaced during testing to ensure consistent results
makeTempDir(t, d)
makeTestServer(t, d)
loadSnakeoil(t, d)
loadTestSourceNames(t, d)
loadFixtures(t, d)
return func() {
os.RemoveAll(d.tempDir)
d.server.Close()
}, d
}
func prepSourceTestCache(t *testing.T, d *SourceTestData, e *SourceTestExpect, source string, state SourceTestState) {
e.cache = []SourceFixture{d.fixtures[state][source], d.fixtures[state][source+".minisig"]}
switch state {
case TestStateCorrect:
e.Source.bin, e.success = e.cache[0].content, true
case TestStateExpired:
e.Source.bin = e.cache[0].content
case TestStatePartial, TestStatePartialSig:
e.err = "signature"
case TestStateMissing, TestStateMissingSig, TestStateOpenErr, TestStateOpenSigErr:
e.err = "open"
}
writeSourceCache(t, e)
}
func prepSourceTestDownload(
_ *testing.T,
d *SourceTestData,
e *SourceTestExpect,
source string,
downloadTest []SourceTestState,
) {
if len(downloadTest) == 0 {
return
}
for _, state := range downloadTest {
path := "/" + strconv.FormatUint(uint64(state), 10) + "/" + source
serverURL := d.server.URL
switch state {
case TestStateMissing, TestStateMissingSig:
e.err = "404 Not Found"
case TestStatePartial, TestStatePartialSig:
e.err = "signature"
case TestStateReadErr, TestStateReadSigErr:
e.err = "unexpected EOF"
case TestStateOpenErr, TestStateOpenSigErr:
if u, err := url.Parse(serverURL + path); err == nil {
host, port := ExtractHostAndPort(u.Host, -1)
u.Host = fmt.Sprintf(
"%s:%d",
host,
port|0x10000,
) // high numeric port is parsed but then fails to connect
serverURL = u.String()
}
e.err = "invalid port"
case TestStatePathErr:
path = "..." + path // non-numeric port fails URL parsing
}
if u, err := url.Parse(serverURL + path); err == nil {
e.Source.urls = append(e.Source.urls, u)
}
e.urls = append(e.urls, serverURL+path)
if e.success {
continue
}
switch state {
case TestStateCorrect:
e.cache = []SourceFixture{d.fixtures[state][source], d.fixtures[state][source+".minisig"]}
e.Source.bin, e.success = e.cache[0].content, true
fallthrough
case TestStateMissingSig, TestStatePartial, TestStatePartialSig, TestStateReadSigErr:
d.reqExpect[path+".minisig"]++
fallthrough
case TestStateMissing, TestStateReadErr:
d.reqExpect[path]++
}
}
if e.success {
e.err = ""
e.delay = DefaultPrefetchDelay
} else {
e.delay = MinimumPrefetchInterval
}
if len(e.Source.urls) > 0 {
e.Source.refresh = d.timeNow.Add(e.delay)
} else {
e.success = false
}
}
func setupSourceTestCase(t *testing.T, d *SourceTestData, i int,
cacheTest *SourceTestState, downloadTest []SourceTestState,
) (id string, e *SourceTestExpect) {
id = strconv.Itoa(d.n) + "-" + strconv.Itoa(i)
e = &SourceTestExpect{
cachePath: filepath.Join(d.tempDir, id),
mtime: d.timeNow,
}
e.Source = &Source{
name: id, urls: []*url.URL{}, format: SourceFormatV2, minisignKey: d.key,
cacheFile: e.cachePath, cacheTTL: DefaultPrefetchDelay * 3, prefetchDelay: DefaultPrefetchDelay,
}
if cacheTest != nil {
prepSourceTestCache(t, d, e, d.sources[i], *cacheTest)
i = (i + 1) % len(d.sources) // make the cached and downloaded fixtures different
}
prepSourceTestDownload(t, d, e, d.sources[i], downloadTest)
return
}
func TestNewSource(t *testing.T) {
if testing.Verbose() {
dlog.SetLogLevel(dlog.SeverityDebug)
dlog.UseSyslog(false)
}
teardown, d := setupSourceTest(t)
defer teardown()
checkResult := func(t *testing.T, e *SourceTestExpect, got *Source, err error) {
c := check.T(t)
if len(e.err) > 0 {
c.Match(err, e.err, "Unexpected error")
} else {
c.Nil(err, "Unexpected error")
}
c.DeepEqual(got, e.Source, "Unexpected return")
checkTestServer(c, d)
checkSourceCache(c, e)
}
d.n++
for _, tt := range []struct {
v, key string
refreshDelay time.Duration
e *SourceTestExpect
}{
{"", "", 0, &SourceTestExpect{err: " ", Source: &Source{name: "short refresh delay", urls: []*url.URL{}, cacheTTL: DefaultPrefetchDelay, prefetchDelay: DefaultPrefetchDelay, prefix: ""}}},
{"v1", d.keyStr, DefaultPrefetchDelay * 2, &SourceTestExpect{err: "Unsupported source format", Source: &Source{name: "old format", urls: []*url.URL{}, cacheTTL: DefaultPrefetchDelay * 2, prefetchDelay: DefaultPrefetchDelay}}},
{"v2", "", DefaultPrefetchDelay * 3, &SourceTestExpect{err: "Invalid encoded public key", Source: &Source{name: "invalid public key", urls: []*url.URL{}, cacheTTL: DefaultPrefetchDelay * 3, prefetchDelay: DefaultPrefetchDelay}}},
} {
t.Run(tt.e.Source.name, func(t *testing.T) {
got, err := NewSource(
tt.e.Source.name,
d.xTransport,
tt.e.urls,
tt.key,
tt.e.cachePath,
tt.v,
tt.refreshDelay,
tt.e.prefix,
)
checkResult(t, tt.e, got, err)
})
}
for cacheTestName, cacheTest := range d.cacheTests {
for downloadTestName, downloadTest := range d.downloadTests {
d.n++
for i := range d.sources {
id, e := setupSourceTestCase(t, d, i, &cacheTest, downloadTest)
t.Run("cache "+cacheTestName+", download "+downloadTestName+"/"+id, func(t *testing.T) {
got, err := NewSource(
id,
d.xTransport,
e.urls,
d.keyStr,
e.cachePath,
"v2",
DefaultPrefetchDelay*3,
"",
)
checkResult(t, e, got, err)
})
}
}
}
}
func TestPrefetchSources(t *testing.T) {
if testing.Verbose() {
dlog.SetLogLevel(dlog.SeverityDebug)
dlog.UseSyslog(false)
}
teardown, d := setupSourceTest(t)
defer teardown()
checkResult := func(t *testing.T, expects []*SourceTestExpect, got time.Duration) {
c := check.T(t)
expectDelay := MinimumPrefetchInterval
for _, e := range expects {
if e.delay >= MinimumPrefetchInterval && (expectDelay == MinimumPrefetchInterval || expectDelay > e.delay) {
expectDelay = e.delay
}
}
c.InDelta(got, expectDelay, time.Second, "Unexpected return")
checkTestServer(c, d)
for _, e := range expects {
checkSourceCache(c, e)
}
}
timeNow = func() time.Time { return d.timeUpd } // since the fixtures are prepared using real now, make the tested code think it's the future
for downloadTestName, downloadTest := range d.downloadTests {
d.n++
sources := []*Source{}
expects := []*SourceTestExpect{}
for i := range d.sources {
_, e := setupSourceTestCase(t, d, i, nil, downloadTest)
e.mtime = d.timeUpd
s := &Source{}
*s = *e.Source
s.bin = nil
sources = append(sources, s)
expects = append(expects, e)
}
t.Run("download "+downloadTestName, func(t *testing.T) {
got := PrefetchSources(d.xTransport, sources)
checkResult(t, expects, got)
})
}
}
func TestMain(m *testing.M) { check.TestMain(m) }

View File

@ -0,0 +1 @@
checks = ["all", "-ST1005"]

View File

@ -0,0 +1,5 @@
package main
func (proxy *Proxy) addSystemDListeners() error {
return nil
}

View File

@ -1,7 +1,8 @@
//go:build !linux
// +build !linux
package main
func (proxy *Proxy) SystemDListeners() error {
func (proxy *Proxy) addSystemDListeners() error {
return nil
}

View File

@ -1,3 +1,6 @@
//go:build !android
// +build !android
package main
import (
@ -7,23 +10,26 @@ import (
"github.com/jedisct1/dlog"
)
func (proxy *Proxy) SystemDListeners() error {
func (proxy *Proxy) addSystemDListeners() error {
files := activation.Files(true)
if len(files) > 0 && (len(proxy.userName) > 0 || proxy.child) {
dlog.Fatal("Systemd activated sockets are incompatible with privilege dropping. Remove activated sockets and fill `listen_addresses` in the dnscrypt-proxy configuration file instead.")
}
for i, file := range files {
if listener, err := net.FileListener(file); err == nil {
dlog.Noticef("Wiring systemd TCP socket #%d, %s, %s", i, file.Name(), listener.Addr())
go proxy.tcpListener(listener.(*net.TCPListener))
} else if pc, err := net.FilePacketConn(file); err == nil {
dlog.Noticef("Wiring systemd UDP socket #%d, %s, %s", i, file.Name(), pc.LocalAddr())
go proxy.udpListener(pc.(*net.UDPConn))
if len(files) > 0 {
if len(proxy.userName) > 0 || proxy.child {
dlog.Fatal(
"Systemd activated sockets are incompatible with privilege dropping. Remove activated sockets and fill `listen_addresses` in the dnscrypt-proxy configuration file instead.",
)
}
dlog.Warn("Systemd sockets are untested and unsupported - use at your own risk")
}
for i, file := range files {
defer file.Close()
if listener, err := net.FileListener(file); err == nil {
proxy.registerTCPListener(listener.(*net.TCPListener))
dlog.Noticef("Wiring systemd TCP socket #%d, %s, %s", i, file.Name(), listener.Addr())
} else if pc, err := net.FilePacketConn(file); err == nil {
proxy.registerUDPListener(pc.(*net.UDPConn))
dlog.Noticef("Wiring systemd UDP socket #%d, %s, %s", i, file.Name(), pc.LocalAddr())
}
file.Close()
}
return nil
}

2
dnscrypt-proxy/testdata/snakeoil.key vendored Normal file
View File

@ -0,0 +1,2 @@
untrusted comment: minisign encrypted secret key
RWRTY0IyhB6jk0BvB9YnhvXfyLkbKj5CSoL4jZtHw7qidhhNW3sAAAACAAAAAAAAAEAAAAAAus/LOCZVIOcL/da0ldQytjgjKmd5D/C84VitiDP0Fe9zWfTxaGs6SXn4tk0ZYmh2CmHydeQstzpA8cTinbFZgb+gxMHu205cqwHr1wUMtBpKhgdwqPh1EWfokCzrGSCj2Vjxq/Fr0bQ=

2
dnscrypt-proxy/testdata/snakeoil.pub vendored Normal file
View File

@ -0,0 +1,2 @@
untrusted comment: minisign public key 956181C0EA8BF961
RWRh+YvqwIFhlRUdNGI/u+EDEmFip5BjgHY/z1yQkmRUcLfeIDWBCxnP

View File

@ -0,0 +1,2 @@
# Minimal example of an empty source list

View File

@ -0,0 +1,4 @@
untrusted comment: signature from minisign secret key
RWRh+YvqwIFhlQu0PHH9BqqxLYYwmhA4TFMNmfj11kkEYZvu8atPqYVEEyEnLIZLUhx+MYHYoiYrRI88LSpoKxMVSr9jIcaGaAI=
trusted comment: timestamp:1571786369 file:empty.md
LTu6UMxo0VXIESDN3/vpM/A04L2RfJkorJNPhXMcYUFl4lRH2x7DSyqCK0k6L3fS7u5iz0+SPLxVx17oqw4aBg==

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