feat: configuration to enable/disable external interfaces

This commit is contained in:
Dimitri Herzog 2023-10-13 14:28:55 +00:00
parent 9f49291177
commit 70399fdaa6
6 changed files with 98 additions and 25 deletions

View File

@ -212,6 +212,7 @@ type Config struct {
Filtering FilteringConfig `yaml:"filtering"` Filtering FilteringConfig `yaml:"filtering"`
Ede EdeConfig `yaml:"ede"` Ede EdeConfig `yaml:"ede"`
SUDN SUDNConfig `yaml:"specialUseDomains"` SUDN SUDNConfig `yaml:"specialUseDomains"`
Interfaces InterfacesConfig `yaml:"interfaces"`
// Deprecated options // Deprecated options
Deprecated struct { Deprecated struct {

15
config/interfaces.go Normal file
View File

@ -0,0 +1,15 @@
package config
// InterfacesConfig configuration for blocky's interfaces (REST, DoH, ...)
type InterfacesConfig struct {
Rest RESTConfig `yaml:"rest"`
DoH DoHConfig `yaml:"dns-over-http"`
}
type RESTConfig struct {
Enable bool `yaml:"enable" default:"true"`
}
type DoHConfig struct {
Enable bool `yaml:"enable" default:"true"`
}

View File

@ -331,3 +331,12 @@ specialUseDomains:
# optional: block recomended private TLDs # optional: block recomended private TLDs
# default: true # default: true
rfc6762-appendixG: true rfc6762-appendixG: true
# optional: configuration for external interfaces
interfaces:
rest:
# optional: if true and http port is defined, provides REST API to control blocky. Default: true
enable: false
dns-over-http:
# optional: if true and http port is defined, provides DNS-over-HTTP endpoint. Default: true
enable: true

View File

@ -12,7 +12,7 @@ configuration properties as [JSON](config.yml).
## Basic configuration ## Basic configuration
| Parameter | Type | Mandatory | Default value | Description | | 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 | | 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 | | keyFile | path | no | | Path to cert and key file for SSL encryption (DoH and DoT); if empty, self-signed certificate is generated |
| dohUserAgent | string | no | | HTTP User Agent for DoH upstreams | | dohUserAgent | string | no | | HTTP User Agent for DoH upstreams |
@ -31,8 +31,8 @@ configuration properties as [JSON](config.yml).
All logging port are optional. All logging port are optional.
| Parameter | Type | Default value | Description | | 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.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.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.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` |
@ -47,12 +47,35 @@ All logging port are optional.
https: 443 https: 443
``` ```
## Interfaces
Blocky listens on port 53 (or other user defined port, see `ports.dns`) and accepts plain DNS queries vie UDP and TCP. If `ports.tls` is defined, it will also provide DoT (DNS-over-TLS) endpoint.
If `ports.http` or `ports.https` is defined, blocky will provide a REST API to control blocky and the DNS-over-HTTP interface by default. See [Interfaces](interfaces.md) for more details.
You can disable the REST API and the DNS-over-HTTP interface if needed by configuring:
!!! example
```yaml
interfaces:
rest:
enable: false
dns-over-http:
enable: false
```
!!! note
Both interfaces are enabled by default if HTTP/HTTPS port is configured
## Logging configuration ## Logging configuration
All logging options are optional. All logging options are optional.
| Parameter | Type | Default value | Description | | Parameter | Type | Default value | Description |
|---------------|---------------------------------|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------| | ------------- | ------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| log.level | enum (debug, info, warn, error) | info | Log level | | log.level | enum (debug, info, warn, error) | info | Log level |
| log.format | enum (text, json) | text | Log format (text or json). | | log.format | enum (text, json) | text | Log format (text or json). |
| log.timestamp | bool | true | Log time stamps (true or false). | | log.timestamp | bool | true | Log time stamps (true or false). |
@ -86,7 +109,7 @@ following network protocols (net part of the resolver URL):
Each resolver must be defined as a string in following format: `[net:]host:[port][/path][#commonName]`. Each resolver must be defined as a string in following format: `[net:]host:[port][/path][#commonName]`.
| Parameter | Type | Mandatory | Default value | | Parameter | Type | Mandatory | Default value |
|------------|----------------------------------|-----------|---------------------------------------------------| | ---------- | -------------------------------- | --------- | ------------------------------------------------- |
| net | enum (tcp+udp, tcp-tls or https) | no | tcp+udp | | net | enum (tcp+udp, tcp-tls or https) | no | tcp+udp |
| host | IP or hostname | yes | | | host | IP or hostname | yes | |
| port | int (1 - 65535) | no | 53 for udp/tcp, 853 for tcp-tls and 443 for https | | port | int (1 - 65535) | no | 53 for udp/tcp, 853 for tcp-tls and 443 for https |
@ -178,7 +201,7 @@ These DNS servers are used to resolve upstream DoH and DoT servers that are spec
It is useful if no system DNS resolver is configured, and/or to encrypt the bootstrap queries. It is useful if no system DNS resolver is configured, and/or to encrypt the bootstrap queries.
| Parameter | Type | Mandatory | Default value | Description | | Parameter | Type | Mandatory | Default value | Description |
|-----------|----------------------|-----------------------------|---------------|--------------------------------------| | --------- | -------------------- | --------------------------- | ------------- | ------------------------------------ |
| upstream | Upstream (see above) | no | | | | upstream | Upstream (see above) | no | | |
| ips | List of IPs | yes, if upstream is DoT/DoH | | Only valid if upstream is DoH or DoT | | ips | List of IPs | yes, if upstream is DoT/DoH | | Only valid if upstream is DoH or DoT |
@ -233,7 +256,7 @@ or define a domain name for your local device on order to use the HTTPS certific
domain must be separated by a comma. domain must be separated by a comma.
| Parameter | Type | Mandatory | Default value | | Parameter | Type | Mandatory | Default value |
|---------------------|-----------------------------------------|-----------|---------------| | ------------------- | --------------------------------------- | --------- | ------------- |
| customTTL | duration (no unit is minutes) | no | 1h | | customTTL | duration (no unit is minutes) | no | 1h |
| rewrite | string: string (domain: domain) | no | | | rewrite | string: string (domain: domain) | no | |
| mapping | string: string (hostname: address list) | no | | | mapping | string: string (hostname: address list) | no | |
@ -467,7 +490,7 @@ You can configure, which response should be sent to the client, if a requested q
queries, NXDOMAIN for other types): queries, NXDOMAIN for other types):
| blockType | Example | Description | | blockType | Example | Description |
|------------|---------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | ---------- | ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| zeroIP | zeroIP | This is the default block type. Server returns 0.0.0.0 (or :: for IPv6) as result for A and AAAA queries | | zeroIP | zeroIP | This is the default block type. Server returns 0.0.0.0 (or :: for IPv6) as result for A and AAAA queries |
| nxDomain | nxDomain | return NXDOMAIN as return code | | nxDomain | nxDomain | return NXDOMAIN as return code |
| custom IPs | 192.100.100.15, 2001:0db8:85a3:08d3:1319:8a2e:0370:7344 | comma separated list of destination IP addresses. Should contain ipv4 and ipv6 to cover all query types. Useful with running web server on this address to display the "blocked" page. | | custom IPs | 192.100.100.15, 2001:0db8:85a3:08d3:1319:8a2e:0370:7344 | comma separated list of destination IP addresses. Should contain ipv4 and ipv6 to cover all query types. Useful with running web server on this address to display the "blocked" page. |
@ -512,7 +535,7 @@ With following parameters you can tune the caching behavior:
Wrong values can significantly increase external DNS traffic or memory consumption. Wrong values can significantly increase external DNS traffic or memory consumption.
| Parameter | Type | Mandatory | Default value | Description | | Parameter | Type | Mandatory | Default value | Description |
|-------------------------------|-----------------|-----------|---------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | ----------------------------- | --------------- | --------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| caching.minTime | duration format | no | 0 (use TTL) | How long a response must be cached (min value). If <=0, use response's TTL, if >0 use this value, if TTL is smaller | | caching.minTime | duration format | no | 0 (use TTL) | How long a response must be cached (min value). If <=0, use response's TTL, if >0 use this value, if TTL is smaller |
| caching.maxTime | duration format | no | 0 (use TTL) | How long a response must be cached (max value). If <0, do not cache responses. If 0, use TTL. If > 0, use this value, if TTL is greater | | caching.maxTime | duration format | no | 0 (use TTL) | How long a response must be cached (max value). If <0, do not cache responses. If 0, use TTL. If > 0, use this value, if TTL is greater |
| caching.maxItemsCount | int | no | 0 (unlimited) | Max number of cache entries (responses) to be kept in cache (soft limit). Default (0): unlimited. Useful on systems with limited amount of RAM. | | caching.maxItemsCount | int | no | 0 (unlimited) | Max number of cache entries (responses) to be kept in cache (soft limit). Default (0): unlimited. Useful on systems with limited amount of RAM. |
@ -537,7 +560,7 @@ Blocky can synchronize its cache and blocking state between multiple instances t
Synchronization is disabled if no address is configured. Synchronization is disabled if no address is configured.
| Parameter | Type | Mandatory | Default value | Description | | Parameter | Type | Mandatory | Default value | Description |
|--------------------------|-----------------|-----------|---------------|---------------------------------------------------------------------| | ------------------------ | --------------- | --------- | ------------- | ------------------------------------------------------------------- |
| redis.address | string | no | | Server address and port or master name if sentinel is used | | redis.address | string | no | | Server address and port or master name if sentinel is used |
| redis.username | string | no | | Username if necessary | | redis.username | string | no | | Username if necessary |
| redis.password | string | no | | Password if necessary | | redis.password | string | no | | Password if necessary |
@ -574,7 +597,7 @@ Blocky can expose various metrics for prometheus. To use the prometheus feature,
see [Basic Configuration](#basic-configuration)). see [Basic Configuration](#basic-configuration)).
| Parameter | Mandatory | Default value | Description | | Parameter | Mandatory | Default value | Description |
|-------------------|-----------|---------------|-------------------------------------| | ----------------- | --------- | ------------- | ----------------------------------- |
| prometheus.enable | no | false | If true, enables prometheus metrics | | prometheus.enable | no | false | If true, enables prometheus metrics |
| prometheus.path | no | /metrics | URL path to the metrics endpoint | | prometheus.path | no | /metrics | URL path to the metrics endpoint |
@ -623,7 +646,7 @@ You can choose which information from processed DNS request and response should
Configuration parameters: Configuration parameters:
| Parameter | Type | Mandatory | Default value | Description | | Parameter | Type | Mandatory | Default value | Description |
|---------------------------|--------------------------------------------------------------------------------------|-----------|---------------|------------------------------------------------------------------------------------| | ------------------------- | ------------------------------------------------------------------------------------ | --------- | ------------- | ---------------------------------------------------------------------------------- |
| queryLog.type | enum (mysql, postgresql, csv, csv-client, console, none (see above)) | no | | Type of logging target. Console if empty | | queryLog.type | enum (mysql, postgresql, csv, csv-client, console, none (see above)) | no | | Type of logging target. Console if empty |
| queryLog.target | string | no | | directory for writing the logs (for csv) or database url (for mysql or postgresql) | | queryLog.target | string | no | | directory for writing the logs (for csv) or database url (for mysql or postgresql) |
| queryLog.logRetentionDays | int | no | 0 | if > 0, deletes log files/database entries which are older than ... days | | queryLog.logRetentionDays | int | no | 0 | if > 0, deletes log files/database entries which are older than ... days |
@ -668,7 +691,7 @@ You can enable resolving of entries, located in local hosts file.
Configuration parameters: Configuration parameters:
| Parameter | Type | Mandatory | Default value | Description | | Parameter | Type | Mandatory | Default value | Description |
|--------------------------|--------------------------------|-----------|---------------|-------------------------------------------------| | ------------------------ | ------------------------------ | --------- | ------------- | ----------------------------------------------- |
| hostsFile.filePath | string | no | | Path to hosts file (e.g. /etc/hosts on Linux) | | hostsFile.filePath | string | no | | Path to hosts file (e.g. /etc/hosts on Linux) |
| hostsFile.hostsTTL | duration (no units is minutes) | no | 1h | TTL | | hostsFile.hostsTTL | duration (no units is minutes) | no | 1h | TTL |
| hostsFile.refreshPeriod | duration format | no | 1h | Time between hosts file refresh | | hostsFile.refreshPeriod | duration format | no | 1h | Time between hosts file refresh |
@ -690,7 +713,7 @@ DNS responses can be extended with EDE codes according to [RFC8914](https://data
Configuration parameters: Configuration parameters:
| Parameter | Type | Mandatory | Default value | Description | | Parameter | Type | Mandatory | Default value | Description |
|------------|------|-----------|---------------|----------------------------------------------------| | ---------- | ---- | --------- | ------------- | -------------------------------------------------- |
| ede.enable | bool | no | false | If true, DNS responses are deliverd with EDE codes | | ede.enable | bool | no | false | If true, DNS responses are deliverd with EDE codes |
!!! example !!! example
@ -708,7 +731,7 @@ Some RFCs have optional recommendations, which are configurable as described bel
Configuration parameters: Configuration parameters:
| Parameter | Type | Mandatory | Default value | Description | | 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) | | specialUseDomains.rfc6762-appendixG | bool | no | true | Block TLDs listed in [RFC 6762 Appendix G](https://www.rfc-editor.org/rfc/rfc6762#appendix-G) |
!!! example !!! example
@ -787,7 +810,7 @@ A value of zero or less will disable this feature.
Configures how HTTP(S) sources are downloaded: Configures how HTTP(S) sources are downloaded:
| Parameter | Type | Mandatory | Default value | Description | | Parameter | Type | Mandatory | Default value | Description |
|-----------|----------|-----------|---------------|------------------------------------------------| | --------- | -------- | --------- | ------------- | ---------------------------------------------- |
| timeout | duration | no | 5s | Download attempt timeout | | timeout | duration | no | 5s | Download attempt timeout |
| attempts | int | no | 3 | How many download attempts should be performed | | attempts | int | no | 3 | How many download attempts should be performed |
| cooldown | duration | no | 500ms | Time between the download attempts | | cooldown | duration | no | 500ms | Time between the download attempts |
@ -808,7 +831,7 @@ This configures how Blocky startup works.
The default strategy is blocking. The default strategy is blocking.
| strategy | Description | | strategy | Description |
|-------------|------------------------------------------------------------------------------------------------------------------------------------------| | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| blocking | all sources are loaded before DNS resolution starts | | blocking | all sources are loaded before DNS resolution starts |
| failOnError | like blocking but blocky will shut down if any source fails to load | | failOnError | like blocking but blocky will shut down if any source fails to load |
| fast | blocky starts serving DNS immediately and sources are loaded asynchronously. The features requiring the sources should enable soon after | | fast | blocky starts serving DNS immediately and sources are loaded asynchronously. The features requiring the sources should enable soon after |

View File

@ -65,22 +65,39 @@ func (s *Server) createOpenAPIInterfaceImpl() (impl api.StrictServerInterface, e
} }
func (s *Server) registerAPIEndpoints(router *chi.Mux) error { func (s *Server) registerAPIEndpoints(router *chi.Mux) error {
if s.cfg.Interfaces.Rest.Enable {
err := s.registerOpenAPIEndpoints(router)
if err != nil {
return fmt.Errorf("unable to register OpenAPI endpoints %w", err)
}
}
s.registerDohEndpoints(router)
return nil
}
func (s *Server) registerDohEndpoints(router *chi.Mux) {
const pathDohQuery = "/dns-query" const pathDohQuery = "/dns-query"
if s.cfg.Interfaces.DoH.Enable {
router.Get(pathDohQuery, s.dohGetRequestHandler)
router.Get(pathDohQuery+"/", s.dohGetRequestHandler)
router.Get(pathDohQuery+"/{clientID}", s.dohGetRequestHandler)
router.Post(pathDohQuery, s.dohPostRequestHandler)
router.Post(pathDohQuery+"/", s.dohPostRequestHandler)
router.Post(pathDohQuery+"/{clientID}", s.dohPostRequestHandler)
}
}
func (s *Server) registerOpenAPIEndpoints(router *chi.Mux) error {
openAPIImpl, err := s.createOpenAPIInterfaceImpl() openAPIImpl, err := s.createOpenAPIInterfaceImpl()
if err != nil { if err != nil {
return err return fmt.Errorf("unable to create OpenAPI server implementation %w", err)
} }
api.RegisterOpenAPIEndpoints(router, openAPIImpl) api.RegisterOpenAPIEndpoints(router, openAPIImpl)
router.Get(pathDohQuery, s.dohGetRequestHandler)
router.Get(pathDohQuery+"/", s.dohGetRequestHandler)
router.Get(pathDohQuery+"/{clientID}", s.dohGetRequestHandler)
router.Post(pathDohQuery, s.dohPostRequestHandler)
router.Post(pathDohQuery+"/", s.dohPostRequestHandler)
router.Post(pathDohQuery+"/{clientID}", s.dohPostRequestHandler)
return nil return nil
} }

View File

@ -164,6 +164,14 @@ var _ = BeforeSuite(func() {
Enable: true, Enable: true,
Path: "/metrics", Path: "/metrics",
}, },
Interfaces: config.InterfacesConfig{
Rest: config.RESTConfig{
Enable: true,
},
DoH: config.DoHConfig{
Enable: true,
},
},
}) })
Expect(err).Should(Succeed()) Expect(err).Should(Succeed())