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