<rdar://problem/7481776> Suppress logs for "A non-blocking socket operation could...
[people/sha0/mDNSResponder.git] / PrivateDNS.txt
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         };