From 81cbd634236f02b95ac0eab899c94526a44fc816 Mon Sep 17 00:00:00 2001 From: mapl Date: Wed, 25 Sep 2024 17:36:53 +0200 Subject: [PATCH 1/5] ability to disable specialUseDomains handling --- config/sudn.go | 5 +++-- resolver/sudn_resolver.go | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/config/sudn.go b/config/sudn.go index 6f65bb060..ce07aea3e 100644 --- a/config/sudn.go +++ b/config/sudn.go @@ -11,12 +11,13 @@ type SUDN struct { // upstream or custom DNS, which come before SUDN in the resolver chain. // Thus defaulting to `true` and returning NXDOMAIN here should not conflict. RFC6762AppendixG bool `yaml:"rfc6762-appendixG" default:"true"` + Enable bool `yaml:"enable" default:"true"` } // IsEnabled implements `config.Configurable`. func (c *SUDN) IsEnabled() bool { - // The Special Use RFCs are always active - return true + + return c.Enable } // LogConfig implements `config.Configurable`. diff --git a/resolver/sudn_resolver.go b/resolver/sudn_resolver.go index 20f3fe527..964c28c17 100644 --- a/resolver/sudn_resolver.go +++ b/resolver/sudn_resolver.go @@ -101,6 +101,10 @@ func NewSpecialUseDomainNamesResolver(cfg config.SUDN) *SpecialUseDomainNamesRes } func (r *SpecialUseDomainNamesResolver) Resolve(ctx context.Context, request *model.Request) (*model.Response, error) { + if !r.cfg.Enable { + return r.next.Resolve(ctx, request) + } + handler := r.handler(request) if handler != nil { resp := handler(request, r.cfg) From 5d7477f968cc2395f448da19dc0a82bd6b1367a8 Mon Sep 17 00:00:00 2001 From: mapl Date: Wed, 2 Oct 2024 16:48:25 +0200 Subject: [PATCH 2/5] Update docs and add simple test case --- config/sudn.go | 1 - config/sudn_test.go | 14 ++++++- docs/config.yml | 1 + docs/configuration.md | 93 +++++++++++++++++++++++-------------------- 4 files changed, 64 insertions(+), 45 deletions(-) diff --git a/config/sudn.go b/config/sudn.go index ce07aea3e..b8d4c1f25 100644 --- a/config/sudn.go +++ b/config/sudn.go @@ -16,7 +16,6 @@ type SUDN struct { // IsEnabled implements `config.Configurable`. func (c *SUDN) IsEnabled() bool { - return c.Enable } diff --git a/config/sudn_test.go b/config/sudn_test.go index 705ebdd05..965203bdc 100644 --- a/config/sudn_test.go +++ b/config/sudn_test.go @@ -18,9 +18,21 @@ var _ = Describe("SUDNConfig", func() { }) Describe("IsEnabled", func() { - It("is true", func() { + It("should be true by default", func() { Expect(cfg.IsEnabled()).Should(BeTrue()) }) + + When("enabled", func() { + It("should be true", func() { + Expect(cfg.IsEnabled()).Should(BeTrue()) + }) + }) + + When("disabled", func() { + It("should be false", func() { + Expect(cfg.IsEnabled()).Should(BeFalse()) + }) + }) }) Describe("LogConfig", func() { diff --git a/docs/config.yml b/docs/config.yml index 498e4290e..3e7b4b58e 100644 --- a/docs/config.yml +++ b/docs/config.yml @@ -337,6 +337,7 @@ specialUseDomains: # optional: block recomended private TLDs # default: true rfc6762-appendixG: true + enable: true # optional: configure extended client subnet (ECS) support ecs: diff --git a/docs/configuration.md b/docs/configuration.md index 9f2df93d9..a58d37021 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -11,12 +11,12 @@ configuration properties as [JSON](config.yml). ## Basic configuration -| Parameter | Type | Mandatory | Default value | Description | -| ------------------- | ------------------- | --------- | ------------- | ---------------------------------------------------------------------------------------------------------- | -| certFile | path | no | | Path to cert and key file for SSL encryption (DoH and DoT); if empty, self-signed certificate is generated | -| keyFile | path | no | | Path to cert and key file for SSL encryption (DoH and DoT); if empty, self-signed certificate is generated | -| minTlsServeVersion | string | no | 1.2 | Minimum TLS version that the DoT and DoH server use to serve those encrypted DNS requests | -| connectIPVersion | enum (dual, v4, v6) | no | dual | IP version to use for outgoing connections (dual, v4, v6) | +| Parameter | Type | Mandatory | Default value | Description | +| ------------------ | ------------------- | --------- | ------------- | ---------------------------------------------------------------------------------------------------------- | +| certFile | path | no | | Path to cert and key file for SSL encryption (DoH and DoT); if empty, self-signed certificate is generated | +| keyFile | path | no | | Path to cert and key file for SSL encryption (DoH and DoT); if empty, self-signed certificate is generated | +| minTlsServeVersion | string | no | 1.2 | Minimum TLS version that the DoT and DoH server use to serve those encrypted DNS requests | +| connectIPVersion | enum (dual, v4, v6) | no | dual | IP version to use for outgoing connections (dual, v4, v6) | !!! example @@ -29,12 +29,12 @@ configuration properties as [JSON](config.yml). All logging port are optional. -| Parameter | Type | Default value | Description | -| ----------- | ---------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| ports.dns | [IP]:port[,[IP]:port]* | 53 | Port(s) and optional bind ip address(es) to serve DNS endpoint (TCP and UDP). If you wish to specify a specific IP, you can do so such as `192.168.0.1:53`. Example: `53`, `:53`, `127.0.0.1:53,[::1]:53` | -| ports.tls | [IP]:port[,[IP]:port]* | | Port(s) and optional bind ip address(es) to serve DoT DNS endpoint (DNS-over-TLS). If you wish to specify a specific IP, you can do so such as `192.168.0.1:853`. Example: `83`, `:853`, `127.0.0.1:853,[::1]:853` | -| ports.http | [IP]:port[,[IP]:port]* | | Port(s) and optional bind ip address(es) to serve HTTP used for prometheus metrics, pprof, REST API, DoH... If you wish to specify a specific IP, you can do so such as `192.168.0.1:4000`. Example: `4000`, `:4000`, `127.0.0.1:4000,[::1]:4000` | -| ports.https | [IP]:port[,[IP]:port]* | | Port(s) and optional bind ip address(es) to serve HTTPS used for prometheus metrics, pprof, REST API, DoH... If you wish to specify a specific IP, you can do so such as `192.168.0.1:443`. Example: `443`, `:443`, `127.0.0.1:443,[::1]:443` | +| Parameter | Type | Default value | Description | +| ----------- | ----------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ports.dns | [IP]:port[,[IP]:port]\* | 53 | Port(s) and optional bind ip address(es) to serve DNS endpoint (TCP and UDP). If you wish to specify a specific IP, you can do so such as `192.168.0.1:53`. Example: `53`, `:53`, `127.0.0.1:53,[::1]:53` | +| ports.tls | [IP]:port[,[IP]:port]\* | | Port(s) and optional bind ip address(es) to serve DoT DNS endpoint (DNS-over-TLS). If you wish to specify a specific IP, you can do so such as `192.168.0.1:853`. Example: `83`, `:853`, `127.0.0.1:853,[::1]:853` | +| ports.http | [IP]:port[,[IP]:port]\* | | Port(s) and optional bind ip address(es) to serve HTTP used for prometheus metrics, pprof, REST API, DoH... If you wish to specify a specific IP, you can do so such as `192.168.0.1:4000`. Example: `4000`, `:4000`, `127.0.0.1:4000,[::1]:4000` | +| ports.https | [IP]:port[,[IP]:port]\* | | Port(s) and optional bind ip address(es) to serve HTTPS used for prometheus metrics, pprof, REST API, DoH... If you wish to specify a specific IP, you can do so such as `192.168.0.1:443`. Example: `443`, `:443`, `127.0.0.1:443,[::1]:443` | !!! example @@ -49,12 +49,12 @@ All logging port are optional. All logging options are optional. -| Parameter | Type | Default value | Description | -| ------------- | -------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | -| log.level | enum (trace, debug, info, warn, error) | info | Log level | -| log.format | enum (text, json) | text | Log format (text or json). | -| log.timestamp | bool | true | Log timestamps (true or false). | -| log.privacy | bool | false | Obfuscate log output (replace all alphanumeric characters with *) for user sensitive data like request domains or responses to increase privacy. | +| Parameter | Type | Default value | Description | +| ------------- | -------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | +| log.level | enum (trace, debug, info, warn, error) | info | Log level | +| log.format | enum (text, json) | text | Log format (text or json). | +| log.timestamp | bool | true | Log timestamps (true or false). | +| log.privacy | bool | false | Obfuscate log output (replace all alphanumeric characters with \*) for user sensitive data like request domains or responses to increase privacy. | !!! example @@ -89,7 +89,6 @@ This applies to all of them. The default strategy is blocking. For `init.strategy`, the "init" is testing the given resolvers for each group. The potentially fatal error, depending on the strategy, is if a group has no functional resolvers. - ### Upstream Groups To resolve a DNS query, blocky needs external public or private DNS resolvers. Blocky supports DNS resolvers with @@ -101,9 +100,9 @@ following network protocols (net part of the resolver URL): !!! hint - You can (and should!) configure multiple DNS resolvers. + You can (and should!) configure multiple DNS resolvers. Per default blocky uses the `parallel_best` upstream strategy where blocky picks 2 random resolvers from the list for each query and - returns the answer from the fastest one. + returns the answer from the fastest one. Each resolver must be defined as a string in following format: `[net:]host:[port][/path][#commonName]`. @@ -117,8 +116,8 @@ Each resolver must be defined as a string in following format: `[net:]host:[port The `commonName` parameter overrides the expected certificate common name value used for verification. !!! note - Blocky needs at least the configuration of the **default** group with at least one upstream DNS server. This group will be used as a fallback, if no client - specific resolver configuration is available. +Blocky needs at least the configuration of the **default** group with at least one upstream DNS server. This group will be used as a fallback, if no client +specific resolver configuration is available. See [List of public DNS servers](additional_information.md#list-of-public-dns-servers) if you need some ideas, which public free DNS server you could use. @@ -198,7 +197,6 @@ Currently available strategies: - 9.8.7.6 ``` - ## Bootstrap DNS configuration These DNS servers are used to resolve upstream DoH and DoT servers that are specified as host names, and list domains. @@ -291,10 +289,11 @@ This configuration will also resolve any subdomain of the defined domain, recurs CNAME records are supported by utilizing the `zone` parameter. The zone file is a multiline string containing a [DNS Zone File](https://en.wikipedia.org/wiki/Zone_file#Example_file). For records defined using the `zone` parameter, the `customTTL` parameter is unused. Instead, the TTL is defined in the zone directly. The following directives are supported in the zone file: -* `$ORIGIN` - sets the origin for relative domain names -* `$TTL` - sets the default TTL for records in the zone -* `$INCLUDE` - includes another zone file relative to the blocky executable -* `$GENERATE` - generates a range of records + +- `$ORIGIN` - sets the origin for relative domain names +- `$TTL` - sets the default TTL for records in the zone +- `$INCLUDE` - includes another zone file relative to the blocky executable +- `$GENERATE` - generates a range of records With the optional parameter `rewrite` you can replace domain part of the query with the defined part **before** the resolver lookup is performed. @@ -412,7 +411,7 @@ Each list in a group is a "source" and can be downloaded, read from a file, or i The supported list formats are: -1. the well-known [Hosts format](https://en.wikipedia.org/wiki/Hosts_(file)) +1. the well-known [Hosts format]() 2. one domain per line (plain domain list) 3. one wildcard per line 4. one regex per line @@ -453,7 +452,7 @@ The supported list formats are: If a group has **only allowlist** entries, only domains from this list are allowed, and all others be blocked. !!! warning - You must also define a client group mapping, otherwise the allow/denylist definitions will have no effect. +You must also define a client group mapping, otherwise the allow/denylist definitions will have no effect. #### Wildcard support @@ -470,7 +469,7 @@ Examples: - `/^apple\.(de|com)$/` will only block `apple.de` and `apple.com` !!! warning - Regexes use more a lot more memory and are much slower than wildcards, you should use them as a last resort. +Regexes use more a lot more memory and are much slower than wildcards, you should use them as a last resort. ### Client groups @@ -668,7 +667,7 @@ You can choose which information from processed DNS request and response should - `duration`: request processing time in milliseconds !!! hint - If not defined, blocky will log all available information +If not defined, blocky will log all available information Configuration parameters: @@ -692,20 +691,20 @@ Configuration parameters: To connect to a database, you must provide a URL like value for `target`. The exact format and supported parameters depends on the DB type. Parsing is handled not by Blocky, but third-party libraries, therefore the full documentation is external. -| Database | Full docs | Format | Example | -| ---------- | ----------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | -| MySQL | [Go MySQL driver Data Source Name](https://github.com/go-sql-driver/mysql#dsn-data-source-name) | `[username[:password]@][protocol[(host[:port])]]/dbname[?param1=value1[¶mN=valueN]]`| `username:password@tcp(localhost:3306)/blocky_query_log?timeout=15s`| -| PostgreSQL | [pgx.ParseConfig](https://pkg.go.dev/github.com/jackc/pgx/v5/pgconn#ParseConfig) | `postgres://[username[:password]@][host[:port]]/dbname[?param1=value1[¶mN=valueN]]` | `postgres://username@localhost:5432/blocky_query_log` | -| Timescale | See PostgreSQL above | | | +| Database | Full docs | Format | Example | +| ---------- | ----------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| MySQL | [Go MySQL driver Data Source Name](https://github.com/go-sql-driver/mysql#dsn-data-source-name) | `[username[:password]@][protocol[(host[:port])]]/dbname[?param1=value1[¶mN=valueN]]` | `username:password@tcp(localhost:3306)/blocky_query_log?timeout=15s` | +| PostgreSQL | [pgx.ParseConfig](https://pkg.go.dev/github.com/jackc/pgx/v5/pgconn#ParseConfig) | `postgres://[username[:password]@][host[:port]]/dbname[?param1=value1[¶mN=valueN]]` | `postgres://username@localhost:5432/blocky_query_log` | +| Timescale | See PostgreSQL above | | | !!! note - For increased security, it is recommended to configure the password for a PostgreSQL/Timescale connection via the `PGPASSFILE` environment variable. +For increased security, it is recommended to configure the password for a PostgreSQL/Timescale connection via the `PGPASSFILE` environment variable. ### Examples !!! example - **CSV format with limited logging information** +**CSV format with limited logging information** ```yaml queryLog: @@ -719,7 +718,7 @@ Parsing is handled not by Blocky, but third-party libraries, therefore the full ``` !!! example - **MySQL Database** +**MySQL Database** ```yaml queryLog: @@ -753,7 +752,6 @@ Configuration parameters: strategy: fast ``` - ## Deliver EDE codes as EDNS0 option DNS responses can be extended with EDE codes according to [RFC8914](https://datatracker.ietf.org/doc/rfc8914/). @@ -792,14 +790,16 @@ EDNS Client Subnet (ECS) configuration parameters: ## Special Use Domain Names -SUDN (Special Use Domain Names) are always enabled as they are required by various RFCs. +SUDN (Special Use Domain Names) are always enabled by default as they are required by various RFCs. Some RFCs have optional recommendations, which are configurable as described below. +However, you can completely deactivate the blocking of SUDN by setting enable to false Configuration parameters: | Parameter | Type | Mandatory | Default value | Description | | ----------------------------------- | ---- | --------- | ------------- | --------------------------------------------------------------------------------------------- | | specialUseDomains.rfc6762-appendixG | bool | no | true | Block TLDs listed in [RFC 6762 Appendix G](https://www.rfc-editor.org/rfc/rfc6762#appendix-G) | +| enable | bool | no | true | completely disable or enable SUDN blocking | !!! example @@ -808,6 +808,13 @@ Configuration parameters: rfc6762-appendixG: true ``` +!!! example + + ```yaml + specialUseDomains: + enable: false + ``` + ## SSL certificate configuration (DoH / TLS listener) See [Wiki - Configuration of HTTPS](https://github.com/0xERR0R/blocky/wiki/Configuration-of-HTTPS-for-DoH-and-Rest-API) @@ -932,5 +939,5 @@ Default value is 4. !!! note As with other settings under `loading`, the limit applies to the blocking and hosts file resolvers separately. - The total number of concurrent sources concurrently processed can reach the sum of both values. + The total number of concurrent sources concurrently processed can reach the sum of both values. For example if blocking has a limit set to 8 and hosts file's is 4, there could be up to 12 concurrent jobs. From f11d26982e057015b19a6f7b3aa2785c577b69a7 Mon Sep 17 00:00:00 2001 From: mapl <9784732+mapl@users.noreply.github.com> Date: Wed, 16 Oct 2024 22:22:06 +0200 Subject: [PATCH 3/5] Update configuration.md add warning --- docs/configuration.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index a58d37021..4cbb8d2ec 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -792,7 +792,8 @@ EDNS Client Subnet (ECS) configuration parameters: SUDN (Special Use Domain Names) are always enabled by default as they are required by various RFCs. Some RFCs have optional recommendations, which are configurable as described below. -However, you can completely deactivate the blocking of SUDN by setting enable to false +However, you can completely deactivate the blocking of SUDN by setting enable to false. +Warning! You should only disable this if your upstream DNS server is local, as it shouldn't be disabled for remote upstreams. Configuration parameters: From e6c14f855f50e6f37f988bedd5c097c82844e614 Mon Sep 17 00:00:00 2001 From: mapl Date: Fri, 18 Oct 2024 00:52:11 +0200 Subject: [PATCH 4/5] fix basic enable/disabled test --- config/sudn_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/config/sudn_test.go b/config/sudn_test.go index 965203bdc..c5f5c718e 100644 --- a/config/sudn_test.go +++ b/config/sudn_test.go @@ -24,12 +24,18 @@ var _ = Describe("SUDNConfig", func() { When("enabled", func() { It("should be true", func() { + cfg := SUDN{ + Enable: true, + } Expect(cfg.IsEnabled()).Should(BeTrue()) }) }) When("disabled", func() { It("should be false", func() { + cfg := SUDN{ + Enable: false, + } Expect(cfg.IsEnabled()).Should(BeFalse()) }) }) From 84941128b3132f6b064a4aca2f9862a1a39a2d5a Mon Sep 17 00:00:00 2001 From: mapl Date: Sat, 19 Oct 2024 10:57:40 +0200 Subject: [PATCH 5/5] add enable test --- resolver/sudn_resolver_test.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/resolver/sudn_resolver_test.go b/resolver/sudn_resolver_test.go index bfe3ca4b4..9c0a7a8d3 100644 --- a/resolver/sudn_resolver_test.go +++ b/resolver/sudn_resolver_test.go @@ -95,6 +95,24 @@ var _ = Describe("SudnResolver", Label("sudnResolver"), func() { return Entry(description, args...) } + It("should be true by default", func() { + Expect(sutConfig.IsEnabled()).Should(BeTrue()) + }) + + When("enabled", func() { + It("should be true", func() { + sutConfig.Enable = true + Expect(sutConfig.IsEnabled()).Should(BeTrue()) + }) + }) + + When("disabled", func() { + It("should be false", func() { + sutConfig.Enable = false + Expect(sutConfig.IsEnabled()).Should(BeFalse()) + }) + }) + DescribeTable("handled domains", func(qType dns.Type, qName string, expectedRCode int, extraMatchers ...types.GomegaMatcher) { resp, err := sut.Resolve(ctx, newRequest(qName, qType))