From cde2c21a3cfadc7004feeaf804cee0b557c10474 Mon Sep 17 00:00:00 2001 From: Ingmar Stein Date: Sat, 12 Oct 2024 21:34:57 +0200 Subject: [PATCH] Add documentation for the Filter AAAA and Split Horizon apps. --- Apps/FilterAaaaApp/README.md | 46 +++++++++++ Apps/SplitHorizonApp/README.md | 136 +++++++++++++++++++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100644 Apps/FilterAaaaApp/README.md create mode 100644 Apps/SplitHorizonApp/README.md diff --git a/Apps/FilterAaaaApp/README.md b/Apps/FilterAaaaApp/README.md new file mode 100644 index 00000000..59f5f1fb --- /dev/null +++ b/Apps/FilterAaaaApp/README.md @@ -0,0 +1,46 @@ +# Filter AAAA + +The `Filter AAAA` app allows filtering `AAAA` records by returning `NODATA` responses when `A` records for the same domain name are available. This allows clients with dual-stack (IPv4 and IPv6) internet connections to prefer using IPv4 to connect to websites and use IPv6 only when a website has no IPv4 support. + +The app is a _post processor_. That means, it modifies a response generated by the DNS server before it is sent to the client. + +## Configuration + +As any post processor, this app is configured globally in the app settings. Its configuration file is a JSON document which looks like the following: + +``` +{ + "enableFilterAaaa": true, + "bypassLocalZones": false, + "bypassNetworks": [ + "192.168.1.0/24" + ], + "bypassDomains": [ + "example.com" + ] +} +``` + +The individual settings are: + +- `enableFilterAaaa`: when set to `false`, this app is disabled and passes through the original response. + +- `bypassLocalZones`: when set to `true`, authoritative answers are passed through unmodified. + +- `bypassNetworks`: a list of networks. If a request originates from a client in any of the specified networks, the original response is passed through unmodified. + +- `bypassDomains` a list of domain names. If a request is for a domain in this list, the original response is passed through unmodified. This includes subdomains of the domains in `bypassDomains`, i.e. `example.com` also matches `subdomain.example.com`. + +## Post-processing + +The app processes any response which matches all of the following criteria: + +- the response has a `NoError` response code +- the query type is `AAAA` +- the response contains at least one `AAAA` record +- the request / response pair is not excluded by any configuration setting +- a lookup for an up `A` record for the same domain is successful and returns an address + +Note that this means that `NXDOMAIN`, `SERVFAIL`, and `NODATA` responses are left unmodified. + +The matching responses are replaced by one which includes all the `CNAME` records from the original response and a `SOA` record, but no `AAAA` record. diff --git a/Apps/SplitHorizonApp/README.md b/Apps/SplitHorizonApp/README.md new file mode 100644 index 00000000..37eff4e6 --- /dev/null +++ b/Apps/SplitHorizonApp/README.md @@ -0,0 +1,136 @@ +# Split Horizon + +The Split Horizon app provides two distinct features which can be used independently: + +1. Create `APP` records in primary and forwarder zones that can return different sets of `A`, `AAAA`, or `CNAME` records for clients querying over public, private, or other specified networks. + +1. Translate IP addresses in a DNS response for `A` and `AAAA` type requests based on the client's network address and the configured 1:1 translation. + +The following sections describe each feature in more detail. + +## A / AAAA / CNAME + +To respond with different `A`, `AAAA`, or `CNAME` records to different clients, create an `APP` record with the respective name in a primary or forwarder zone. Select the `Split Horizon` app and the `SplitHorizon.SimpleAddress` class for `A` and `AAAA` records or `SplitHorizon.SimpleCNAME` for `CNAME` records. + +Each `APP` record is configured with a JSON document which looks like the following: + +``` +{ + "public": [ + "1.1.1.1", + "2.2.2.2" + ], + "private": [ + "192.168.1.1", + "::1" + ], + "custom-networks": [ + "172.16.1.1" + ], + "10.0.0.0/8": [ + "10.1.1.1" + ] +} +``` + +An example for `CNAME` replacements: + +``` +{ + "public": "api.example.com", + "private": "api.example.corp", + "custom-networks": "custom.example.corp", + "10.0.0.0/8": "api.intranet.example.corp" +} +``` + +Keys can be one of the following: + +- a network specification (like `10.0.0.0/8`) +- a named network defined in the global app configuration (see [Address Translation]) +- `private`: private IP ranges defined in RFC 1918 +- `public`: all IPs outside the private IP ranges defined in RFC 1918 + +Values are either lists of IPv4 and IPv6 addresses which get mapped to `A` and `AAAA` records in the response or a single string to be used as the resulting `CNAME` response. + +The lists don't have to be exhaustive: requests from clients which don't match any of the networks are processed as if the `APP` record didn't exist. For example, this could mean that a request is forwarded via a `FWD` record. + +## Address Translation + +Translates IP addresses in a DNS response for `A` and `AAAA` type request based on the client's network address and the configured 1:1 translation. Also supports reverse (`PTR`) queries for translated addresses. + +### Configuration + +This feature is both a _post processor_ as well as a _request handler_. That means, it modifies a response generated by the DNS server before it is sent to the client and also serves authoritative responses for some requests. It is configured globally in the app settings. Its configuration file is a JSON document which looks like the following: + +``` +{ + "networks": { + "custom-networks": [ + "172.16.1.0/24", + "172.16.10.0/24", + "172.16.2.1" + ] + }, + "enableAddressTranslation": false, + "networkGroupMap": { + "10.0.0.0/8": "local1", + "172.16.0.0/12": "local2", + "192.168.0.0/16": "local3" + }, + "groups": [ + { + "name": "local1", + "enabled": true, + "translateReverseLookups": true, + "externalToInternalTranslation": { + "1.2.3.0/24": "10.0.0.0/24", + "5.6.7.8": "10.0.0.5" + } + }, + { + "name": "local2", + "enabled": true, + "translateReverseLookups": true, + "externalToInternalTranslation": { + "1.2.3.4": "172.16.0.4", + "5.6.7.8": "172.16.0.5" + } + }, + { + "name": "local3", + "enabled": true, + "translateReverseLookups": true, + "externalToInternalTranslation": { + "1.2.3.4": "192.168.0.4", + "5.6.7.8": "192.168.0.5" + } + } + ] +} +``` + +The individual settings are: + +- `networks`: a map of network names to lists of network addresses. This can used to name networks for use in `APP` records for this app. By using named networks, it becomes easy to change a network definition which is reused across multiple `APP` records. +- `enableAddressTranslation`: when set to `false`, address translation is disabled and the original response is passed through unmodified. +- `networkGroupMap`: maps given networks to one of the following named groups. The IP of the requesting client is usses the group with the most specific network mask. Example: if you have mappings `"192.168.1.0/24" = "local1"` and `"192.168.0.0/16" = "local2"`, the client with the IP `192.168.1.10` is considered a member of group `local1`. +- `groups`: a list of groups. A group has the following properties: + - `name`: the name of the group. + - `enabled`: flag whether to perform address translation for this group. + - `translateReverseLookups`: flag whether to respond to `PTR` queries for internal IPs (see below) + - `externalToInternalTranslation`: a mapping from external to internal network addresses (see below). The networks must be of the same size (have the same prefix length). + +### Processing + +Forward lookups (`A` and `AAAA`) which fulfill all of the following requirements are processed by this app: + +- the requesting client is a member of a group defined in `networkGroupMap` +- the response code is `NoError` +- the response has at least one answer + +Note that `NXDOMAIN`, `SERVFAIL`, and `NODATA` answers are passed through unmodified. + +For every `A` and `AAAA` record in the response, the app replaces any IP according to the rules defined in `externalToInternalTranslation` of the client's network group. The translation is a 1:1 mapping which just replaces the network part of an IP. For example, given `externalToInternalTranslation": { "1.2.3.0/24": "10.0.0.0/24 }`, the response `1.2.3.4` is replaced with `10.0.0.4`. + +If `translateReverseLookups` is enabled for a given group, the app also modifies `PTR` queries for domains representing the internal IPs of the group by responding with a `CNAME` record for a domain representing the corresponding IP in the external range. For example, given `externalToInternalTranslation": { "1.2.3.0/24": "10.0.0.0/24 }`, a `PTR` query for `4.0.0.10.in-addr.arpa` will receive the response `CNAME 4.3.2.1.in-addr.arpa`.