Add the TLS SNI +[no]tls-sni option to dig for DoT and DoH
Description
Currently, when doing DoT or DoH lookups, dig
does not include the Server Name Indication (SNI) extension during its TLS handshake ClientHello
request.
This makes dig unusable as a DoT or DoH client with TLS proxies and HTTPS proxies and DoT/DoH servers that implement:
- SNI based routing of requests to the correct backends as part of name-based virtual hosting, and/or
- SNI filtering based access control.
Currently dig
also has very poor handling of the fatal-level SNI-related TLS handshake Alert
response from server.
Example of such TLS Alert server response:
Transport Layer Security
TLSv1.2 Record Layer: Alert (Level: Fatal, Description: Unrecognized Name)
Content Type: Alert (21)
Version: TLS 1.2 (0x0303)
Length: 2
Alert Message
Level: Fatal (2)
Description: Unrecognized Name (112)
Current dig behaviour is as follows when the server aborts the handshake by sending such a fatal-level unrecognized_name(112)
alert:
~ $ dig +https @dns.example.com example.com A; echo $?
;; Connection to 192.0.2.53#443(192.0.2.53) for example.com failed: TLS error.
;; Connection to 192.0.2.53#443(192.0.2.53) for example.com failed: TLS error.
;; Connection to 192.0.2.53#443(192.0.2.53) for example.com failed: TLS error.
9
~ $ dig +tls @dns.example.com example.com A; echo $?
0
~ $
There is no dependency on implementing SNI support in named
(which also would be nice for ACLs and for multiple views).
While named
can be placed behind a SNI-capable proxy, there's no workarounds for dig
other than replacing it with a SNI-capable client such as kdig
.
Request
Add +[no]tls-sni=STR
option to dig
similar to the option in kdig
.
Expected behaviour is something roughly along the lines of:
if request is DoT or DoH
if +tls-sni option is specified
SNIHostName = option value
else if +notls-sni option is specified
SNIHostName = NULL
else if @server argument is a hostname
SNIHostName = server hostname FQDN
else if +tls-hostname option is specified
SNIHostName = option value
else
SNIHostName = NULL
if SNIHostName
remove trailing FQDN dot from SNIHostName if specified
Do IDN format conversion to ASCII if necessary
validate SNIHostName against SNI HostName format specification
if SNIHostName format is valid
include SNIHostName as a SNI in TLS ClientHello
include SNIHostName in the first line of dig query output?
else
exit with an error
else
Don't include SNI in TLS ClientHello
if ServerHello response includes "server_name" extension
include SNIHostName in SERVER line in dig query output
Better error handling of the fatal-level unrecognized_name(112)
alert TLS responses from server:
- Start returning an error during DoT instead of a silent success.
- Consider a more descriptive error message than the current
TLS error
:
if a <SNI> value was included in ClientHello
Error message something along the lines of: `'<SNI>' SNI is unrecognised by the server`
else
Error message something along the lines of: `SNI is required by the server`
Links / references
For the most recent background and guidance on SNI see Section 3.7 of RFC 9325.
For the latest SNI specification defining SNI HostName
format and client/server behaviour see Section 3 of RFC 6066.
When implementing, consider application of Internationalized Domain Names (IDN) in SNI as per RFC 5890 and TLS Encrypted Client Hello (ECH) as per the latest draft.