1Private DNS 2 3Summary 4 5Private DNS is an extension to standard Wide Area Bonjour that allows 6for secure, encrypted, and authorized communications. Private data sent 7from a client to a DNS server is encrypted using Transport Layer 8Security (TLS), ensuring that the data is hidden from prying eyes, and 9contains Transaction Signatures (TSIG), so the server can authorize the 10request. TSIGs are typically associated with Dynamic Updates; we are 11using them for standard and long-lived queries as well. Private DNS also 12protects Dynamic Updates from eavesdropping, by wrapping the update in a 13TLS communication channel if the server has been configured appropriately. 14 15Architectural Overview 16 17mDNSResponder has been modified to automatically issue a private query 18when necessary. After receiving an NXDOMAIN error, mDNSResponder checks 19in the system keychain to see if the user has a DNS query key (TSIG key) 20for the name in question, or for a parent of that name. If a suitable 21key is found, mDNSResponder looks up the zone data associated with the 22name of the question. After determining the correct name server, 23mDNSResponder looks up an additional SRV record "_dns-private._tcp". If 24it finds this record, mDNSResponder will re-issue the query privately. 25If either there is no _dns-private._tcp record, or there is no secret 26key, the call fails as it initially did, with an NXDOMAIN error. 27 28Once the secret key is found and the SRV record is looked up, mDNSResponder 29opens a TLS connection to the server on the port specified in the SRV 30record just looked up. After the connection succeeds, mDNSResponder 31can proceed to use that communication channel to make requests of 32the server. Every private packet must also have a TSIG record; 33the DNS server uses this TSIG record to allow access to its data. 34 35When setting up a long-lived query over TCP (with or without TLS) 36TCP's standard three-way handshake makes the full four-packet LLQ setup 37exchange described in <http://files.dns-sd.org/draft-sekar-dns-llq.txt> 38unnecessary. Instead, when connecting over TCP, the client simply sends 39a setup message and expects to receive ACK + Answers. The setup message 40sent is formatted as described in the LLQ document, however there is 41an additional TSIG' resource record added to the end of it. The TSIG 42resource records looks and acts exactly as it does in a secure update. 43So when the server receives an LLQ (or a standard query), it looks to 44see if the zone that is being referenced is public or private. If it's 45private, then it makes sure that the client is authorized to query that 46zone (by using the TSIG signature) and returns the appropriate data. 47When a zone is configured as private, the server will do this type of 48authorization checking for every query except those queries that are 49looking for SOA and NS records. 50 51Implementation Issues 52 53dnsextd 54 55dnsextd has been modified to behave much like a DNS firewall. The "real" 56DNS server is configured to listen on non-standard ports on the loopback 57interface. dnsextd then listens on the standard DNS ports (TCP/UDP port 5853) and intercepts all DNS traffic. It is responsible for determining 59what zone a DNS request is associated with, determining whether the 60client is allowed access to that zone, and returning the appropriate 61information back to the caller. If the packet is allowed access, dnsextd 62forwards the request to the "real" nameserver, and returns the result to 63the caller. 64 65It was tempting to use BIND9's facility for configuring TSIG enabled 66queries while doing this work. However after proceeding down that path, 67enough subtle interaction problems were found that it was not practical 68to pursue this direction, so instead dnsextd does all TSIG processing 69for queries itself. It does continue to use BIND9 for processing TSIG 70enabled dynamic updates, though one minor downside with this is that 71there are two configuration files (named.conf or dnsextd.conf) that have 72the same secret key information. That seems redundant and error-prone, 73and moving all TSIG processing for both queries and updates into dnsextd 74would fix this. 75 76All private LLQ operations are TSIG-enabled and sent over a secure 77encrypted TLS channel. To accommodate service providers who don't want 78to have to keep open a large number of TLS connections to a large number 79of client machines, the server has the option of dropping the TLS 80connection after initial LLQ setup and sending subsequent events and 81refreshes using unencrypted UDP packets. This results in less load on 82the server, at the cost of slightly lower security (LLQs can only be set 83up by an authorized client, but once set up, subsequent change event 84packets sent over unencrypted UDP could be observed by an eavesdropper). 85A potential solution to this deficiency might be in using DTLS, which is 86a protocol based on TLS that is capable of securing datagram traffic. 87More investigation needs to be done to see if DTLS is suitable for 88private DNS. 89 90It was necessary to relax one of the checks that dnsextd performs during 91processing of an LLQ refresh. Prior to these changes, dnsextd would 92verify that the refresh request came from the same entity that setup the 93LLQ by comparing both the IP Address and port number of the request 94packet with the IP Address and port number of the setup packet. Because 95of the preceding issue, a refresh request might be sent over two 96different sockets. While their IP addresses would be the same, their 97port numbers could potentially differ. This check has been modified to 98only check that the IP addresses match. 99 100When setting up a semi-private LLQ (where the request and initial answer 101set is sent over TLS/TCP, but subsequent change events are sent over 102unencrypted UDP), dnsextd uses the port number of the client's TCP 103socket to determine the UDP event port number. While this eliminates the 104need to pass the UDP event port number in the LLQ setup request 105(obviating a potential data mismatch error), I think it does more harm 106than good, for three reasons: 107 1081) We are relying that all the routers out there implement the Port 109 Mapping Protocol spec correctly. 110 1112) Upon setup every LLQ must NAT map two ports. Upon tear down every LLQ 112 must tear down two NAT mappings. 113 1143) Every LLQ opens up two sockets (TCP and UDP), rather than just the 115 one TCP socket. 116 117All of this just to avoid sending two bytes in the LLQ setup packet 118doesn't seem logical. The approach also necessitates creating an 119additional UDP socket for every private LLQ, port mapping both the TCP 120socket as well as the UDP socket, and moderately increasing the 121complexity and efficiency of the code. Because of this we plan to allow 122the LLQ setup packet to specify a different UDP port for change event 123packets. This will allow mDNSResponder to receive all UDP change event 124packets on a single UDP port, instead of a different one for each LLQ. 125 126Currently, dnsextd is buggy on multi-homed hosts. If it receives a 127packet on interface 2, it will reply on interface 1 causing an error in 128the client program. 129 130dnsextd doesn't fully process all of its option parameters. 131Specifically, it doesn't process the keywords: "listen-on", 132"nameserver", "private", and "llq". It defaults to expecting the "real" 133nameserver to be listening on 127.0.0.1:5030. 134 135 136mDNSResponder 137 138Currently, mDNSResponder attempts to issue private queries for all 139queries that initially result in an NXDOMAIN error. This behavior might 140be modified in future versions, however it seems patently incorrect to 141do this for reverse name lookups. The code that attempts to get the zone 142data associated with the name will never find the zone for a reverse 143name lookup, and so will issue a number of wasteful DNS queries. 144 145mDNSResponder doesn't handle SERV_FULL or STATIC return codes after 146setting up an LLQ over TCP. This isn't a terrible problem right now, 147because dnsextd doesn't ever return them, but this should be fixed so 148that mDNSResponder will work when talking to other servers that do 149return these error codes. 150 151 152Configuration: 153 154Sample named.conf: 155 156// 157// Include keys file 158// 159include "/etc/rndc.key"; 160// Declares control channels to be used by the rndc utility. 161// 162// It is recommended that 127.0.0.1 be the only address used. 163// This also allows non-privileged users on the local host to manage 164// your name server. 165 166// 167// Default controls 168// 169controls 170 { 171 inet 127.0.0.1 port 54 allow { any; } keys { "rndc-key"; }; 172 }; 173 174options 175 { 176 directory "/var/named"; 177 /* 178 * If there is a firewall between you and nameservers you want 179 * to talk to, you might need to uncomment the query-source 180 * directive below. Previous versions of BIND always asked 181 * questions using port 53, but BIND 8.1 uses an unprivileged 182 * port by default. 183 */ 184 185 forwarders 186 { 187 65.23.128.2; 188 65.23.128.3; 189 }; 190 191 listen-on port 5030 { 127.0.0.1; }; 192 recursion true; 193 }; 194 195// 196// a caching only nameserver config 197// 198zone "." IN 199 { 200 type hint; 201 file "named.ca"; 202 }; 203 204zone "localhost" IN 205 { 206 type master; 207 file "localhost.zone"; 208 allow-update { none; }; 209 }; 210 211zone "0.0.127.in-addr.arpa" IN 212 { 213 type master; 214 file "named.local"; 215 allow-update { none; }; 216 }; 217 218zone "hungrywolf.org." in 219 { 220 type master; 221 file "db.hungrywolf.org"; 222 allow-update { key hungrywolf.org.; }; 223 }; 224 225zone "157.23.65.in-addr.arpa" IN 226 { 227 file "db.65.23.157"; 228 type master; 229 }; 230 231zone "100.255.17.in-addr.arpa" IN 232 { 233 file "db.17.255.100"; 234 type master; 235 }; 236 237zone "66.6.24.in-addr.arpa" IN 238 { 239 file "db.24.6.66"; 240 type master; 241 }; 242 243key hungrywolf.org. 244 { 245 algorithm hmac-md5; 246 secret "c8LWr16K6ju6KMO5zT6Tyg=="; 247 }; 248 249logging 250 { 251 category default { _default_log; }; 252 253 channel _default_log 254 { 255 file "/Library/Logs/named.log"; 256 severity info; 257 print-time yes; 258 }; 259 }; 260 261 262Sample dnsextd.conf: 263 264options { }; 265 266key "hungrywolf.org." 267 { 268 secret "c8LWr16K6ju6KMO5zT6Tyg=="; 269 }; 270 271zone "hungrywolf.org." 272 { 273 type private; 274 allow-query { key hungrywolf.org.; }; 275 }; 276