PowerDNS / pdns

PowerDNS Authoritative, PowerDNS Recursor, dnsdist
https://www.powerdns.com/
GNU General Public License v2.0
3.72k stars 912 forks source link

Add dnsdist rules for DoT and DoH connections to detect the DNS server name #7210

Closed M4t7e closed 5 years ago

M4t7e commented 6 years ago

Short description

For DoT and DoH it would be very useful to differenciate between different services based on the DNS servers domain name. With TLS based connections a DNS client can add the Server Name Indication (SNI) in the Client Hello message. The idea is to store the SNI for the whole session context and make it available via a dnsdist rule. For DoH the server name can be extracted from the request URI.

Other information

For DoH it can be extracted from the request URI: https://**service1.example.com**/dns-query

For DoT and DoH it can be extracted from the SNI in the Client Hello: Extension: server_name (len=25) Type: server_name (0) Length: 25 Server Name Indication extension Server Name list length: 23 Server Name Type: host_name (0) Server Name length: 20 Server Name: service1.example.com

Usecase

Example rules in dnsdist:

If there would be a possibility to detect the DNS server name with dnsdist rules, there are countless possibilities. Here two examples:

Enable or disable options based on the DNS server name:

addAction(TLSServerNameRule("no-ecs.example.com"), DisableECSAction())
addAction(HTTPServerNameRule("no-ecs.example.com"), DisableECSAction())
addAction(AllRule(), PoolAction("DEFAULT"))

Send query to special downstream servers that offer different services (e.g. adblock, family-shield, safesearch for popular search engines, DNSSEC, etc.)

addAction(TLSServerNameRule("adblock.example.com"), PoolAction("BLOCK-ADS"))
addAction(HTTPServerNameRule("adblock.example.com"), PoolAction("BLOCK-ADS"))
addAction(AllRule(), PoolAction("DEFAULT"))

Description

It seems that DoT and DoH are becoming more and more popular and the number of (native) client implemenations is increasing. For those two DNS transports it is normally possible to set a domain name or a URL (just DoH) in the DNS resolver setting. Also https://dnscrypt.info/stamps-specifications is saying the hostname will "be used as a SNI name" for DoT and DoH.

Here some interesting DoT/DoH implementations:

In the past the only possibility to differenciate between different services was to have multiple different IPs on the same DNS Resolver or different ports (might be very hard to configure for most DNS clients). Another options is to make use of the source IP address. But this is sometimes very hard because you need to know the current IP address in realtime and especially for mobile devices the IP changes all the time because of different networks (RAN, WiFi, etc.). The DNS server domain name will not change and is independent of IP addresses, NAT scenarios and transport networks. Making use it to offer different services for DoT and DoH connections can be very useful for a lot of applications.

M4t7e commented 6 years ago

I have just tested DoT ("Private DNS") with an Android 9 Pie emulator. It is always sending the SNI in Client Hello messages. And btw, it looks like it creates three connections to the DoT server in parallel.

Habbie commented 5 years ago

An experiment, just for testing SNI extraction with OpenSSL (Debian Buster, version 1.1.1b-2) and (Debian Buster, libgnutls30 3.6.6-2): https://gist.github.com/Habbie/31a5a6a6dc15d1ba727fe3f1d23a968c

Observations:

'Now we just have to type it in'.

Habbie commented 5 years ago

Similar 'just get the SNI out' hack for DoH. https://gist.github.com/Habbie/0ab650579120ac01dd3578b9a1a4215f

Note that this one wouldn't even know where to store the name.

After discussion with @pieterlexis and @rgacogne we realise that addXLocal is not the best interface to begin with, and that the list of paths in addDOHLocal really overstretches the concept. Ideally we'd rearchitect some of this. When we do that, we can also support separate certs for separate SNIs.

M4t7e commented 5 years ago

After discussion with @pieterlexis and @rgacogne we realise that addXLocal is not the best interface to begin with, and that the list of paths in addDOHLocal really overstretches the concept.

This would also be difficult especially with wildcard certificates or similar... My idea was to use a multidomain or a wildcard TLS certificate (e.g. *.example.com) and the different SNI names can be dynamically used with the dnsdist rule functions:

And if possible, make the SNI available in the DNSQuestion object (e.g. dq.sniName) for dynamic and custom Lua actions, debugging, etc.