]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/DNSProxySupport.c
mDNSResponder-765.1.2.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / DNSProxySupport.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2011-2013 Apple Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include "mDNSEmbeddedAPI.h"
19 #include "mDNSMacOSX.h"
20
21 #include <sys/types.h>
22 #include <sys/time.h>
23 #include <sys/event.h>
24 #include <netinet/tcp.h>
25
26 #define ValidSocket(s) ((s) >= 0)
27
28 // Global to store the 4 DNS Proxy Listeners (UDPv4/6, TCPv4/6)
29 static int dp_listener[4];
30
31 #define NUM_PROXY_TCP_CONNS 100
32
33 typedef struct
34 {
35 TCPSocket sock;
36 DNSMessage *reply;
37 mDNSu16 replyLen;
38 mDNSu32 nread;
39 } ProxyTCPInfo_t;
40
41 // returns -1 for failures including the other end closing the socket
42 // returns 0 if successful in reading data, but still not read the data fully
43 // returns 1 if successful in reading all the data
44 mDNSlocal int ProxyTCPRead(ProxyTCPInfo_t *tcpInfo)
45 {
46 long n;
47 mDNSBool closed;
48
49 if (tcpInfo->nread < 2) // First read the two-byte length preceeding the DNS message
50 {
51 mDNSu8 *lenptr = (mDNSu8 *)&tcpInfo->replyLen;
52 n = mDNSPlatformReadTCP(&tcpInfo->sock, lenptr + tcpInfo->nread, 2 - tcpInfo->nread, &closed);
53 if (n < 0 || closed)
54 {
55 LogMsg("ProxyTCPRead: attempt to read message length failed");
56 return -1;
57 }
58
59 tcpInfo->nread += n;
60 if (tcpInfo->nread < 2)
61 {
62 LogMsg("ProxyTCPRead: nread %d, n %d", tcpInfo->nread, n);
63 return 0;
64 }
65
66 tcpInfo->replyLen = (mDNSu16)((mDNSu16)lenptr[0] << 8 | lenptr[1]);
67 if (tcpInfo->replyLen < sizeof(DNSMessageHeader))
68 {
69 LogMsg("ProxyTCPRead: Message length too short (%d bytes)", tcpInfo->replyLen);
70 return -1;
71 }
72
73 tcpInfo->reply = mallocL("ProxyTCPInfo", tcpInfo->replyLen);
74 if (!tcpInfo->reply)
75 {
76 LogMsg("ProxyTCPRead: Memory failure");
77 return -1;
78 }
79 }
80
81 n = mDNSPlatformReadTCP(&tcpInfo->sock, ((char *)tcpInfo->reply) + (tcpInfo->nread - 2), tcpInfo->replyLen - (tcpInfo->nread - 2), &closed);
82
83 if (n < 0 || closed)
84 {
85 LogMsg("ProxyTCPRead: read failure n %d, closed %d", n, closed);
86 return -1;
87 }
88 tcpInfo->nread += n;
89 if ((tcpInfo->nread - 2) != tcpInfo->replyLen)
90 return 0;
91 else
92 return 1;
93 }
94
95 mDNSlocal void ProxyTCPSocketCallBack(int s1, short filter, void *context)
96 {
97 int ret;
98 struct sockaddr_storage from;
99 struct sockaddr_storage to;
100 mDNSAddr senderAddr, destAddr;
101 mDNSIPPort senderPort;
102 ProxyTCPInfo_t *ti = (ProxyTCPInfo_t *)context;
103 TCPSocket *sock = &ti->sock;
104 KQSocketSet *kq = &sock->ss;
105 struct tcp_info tcp_if;
106 socklen_t size = sizeof(tcp_if);
107 int32_t intf_id = 0;
108
109 (void) filter;
110
111 ret = ProxyTCPRead(ti);
112 if (ret == -1)
113 {
114 mDNSPlatformDisposeProxyContext(ti);
115 return;
116 }
117 else if (!ret)
118 {
119 debugf("ProxyTCPReceive: Not yet read completely Actual length %d, Read length %d", ti->replyLen, ti->nread);
120 return;
121 }
122 // We read all the data and hence not interested in read events anymore
123 KQueueSet(s1, EV_DELETE, EVFILT_READ, sock->kqEntry);
124
125 mDNSPlatformMemZero(&to, sizeof(to));
126 mDNSPlatformMemZero(&from, sizeof(from));
127 socklen_t len = sizeof(to);
128 ret = getsockname(s1, (struct sockaddr*) &to, &len);
129 if (ret < 0)
130 {
131 LogMsg("ProxyTCPReceive: getsockname(fd=%d) errno %d", s1, errno);
132 mDNSPlatformDisposeProxyContext(ti);
133 return;
134 }
135 ret = getpeername(s1, (struct sockaddr*) &from, &len);
136 if (ret < 0)
137 {
138 LogMsg("ProxyTCPReceive: getpeername(fd=%d) errno %d", s1, errno);
139 mDNSPlatformDisposeProxyContext(ti);
140 return;
141 }
142 if (getsockopt(s1, IPPROTO_TCP, TCP_INFO, &tcp_if, &size) != 0)
143 {
144 LogMsg("ProxyTCPReceive: getsockopt for TCP_INFO failed (fd=%d) errno %d", s1, errno);
145 return;
146 }
147 intf_id = tcp_if.tcpi_last_outif;
148
149 if (from.ss_family == AF_INET)
150 {
151 struct sockaddr_in *s = (struct sockaddr_in*)&from;
152
153 senderAddr.type = mDNSAddrType_IPv4;
154 senderAddr.ip.v4.NotAnInteger = s->sin_addr.s_addr;
155 senderPort.NotAnInteger = s->sin_port;
156
157 s = (struct sockaddr_in *)&to;
158 destAddr.type = mDNSAddrType_IPv4;
159 destAddr.ip.v4.NotAnInteger = s->sin_addr.s_addr;
160
161 LogInfo("ProxyTCPReceive received IPv4 packet(len %d) from %#-15a to %#-15a on skt %d %s ifindex %d",
162 ti->replyLen, &senderAddr, &destAddr, s1, NULL, intf_id);
163 }
164 else if (from.ss_family == AF_INET6)
165 {
166 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&from;
167 senderAddr.type = mDNSAddrType_IPv6;
168 senderAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
169 senderPort.NotAnInteger = sin6->sin6_port;
170
171 sin6 = (struct sockaddr_in6 *)&to;
172 destAddr.type = mDNSAddrType_IPv6;
173 destAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
174
175 LogInfo("ProxyTCPReceive received IPv6 packet(len %d) from %#-15a to %#-15a on skt %d %s ifindex %d",
176 ti->replyLen, &senderAddr, &destAddr, s1, NULL, intf_id);
177 }
178 else
179 {
180 LogMsg("ProxyTCPReceive from is unknown address family %d", from.ss_family);
181 mDNSPlatformDisposeProxyContext(ti);
182 return;
183 }
184
185 // We pass sock for the TCPSocket and the "ti" for context as that's what we want to free at the end.
186 // In the UDP case, there is just a single socket and nothing to free. Hence, the context (last argument)
187 // would be NULL.
188 kq->m->p->TCPProxyCallback(kq->m, sock, ti->reply, (mDNSu8 *)ti->reply + ti->replyLen, &senderAddr, senderPort, &destAddr,
189 UnicastDNSPort, (mDNSInterfaceID)(uintptr_t)intf_id, ti);
190 }
191
192 mDNSlocal void ProxyTCPAccept(int s1, short filter, void *context)
193 {
194 int newfd;
195 struct sockaddr_storage ss;
196 socklen_t sslen = sizeof(ss);
197 const int on = 1;
198 KQSocketSet *listenSet = (KQSocketSet *)context;
199
200 (void) filter;
201
202 while ((newfd = accept(s1, (struct sockaddr *)&ss, &sslen)) != -1)
203 {
204 int err;
205 int *s;
206 KQueueEntry *k;
207 KQSocketSet *kq;
208
209 // Even though we just need a single KQueueEntry, for simplicity we re-use
210 // the KQSocketSet
211 ProxyTCPInfo_t *ti = mallocL("ProxyTCPContext", sizeof(ProxyTCPInfo_t));
212 if (!ti)
213 {
214 LogMsg("ProxyTCPAccept: cannot allocate TCPSocket");
215 close(newfd);
216 return;
217 }
218 mDNSPlatformMemZero(ti, sizeof(ProxyTCPInfo_t));
219
220 TCPSocket *sock = &ti->sock;
221
222 kq = &sock->ss;
223 kq->sktv4 = -1;
224 kq->sktv6 = -1;
225 kq->m = listenSet->m;
226
227 fcntl(newfd, F_SETFL, fcntl(newfd, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
228 if (ss.ss_family == AF_INET)
229 {
230 s = &kq->sktv4;
231 k = &kq->kqsv4;
232 // Receive interface identifiers
233 err = setsockopt(newfd, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
234 if (err)
235 {
236 LogMsg("ProxyTCPAccept: IP_RECVIF %d errno %d (%s)", newfd, errno, strerror(errno));
237 mDNSPlatformDisposeProxyContext(ti);
238 close(newfd);
239 return;
240 }
241 }
242 else
243 {
244 s = &kq->sktv6;
245 k = &kq->kqsv6;
246 // We want to receive destination addresses and receive interface identifiers
247 err = setsockopt(newfd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
248 if (err)
249 {
250 LogMsg("ProxyTCPAccept: IP_RECVPKTINFO %d errno %d (%s)", newfd, errno, strerror(errno));
251 mDNSPlatformDisposeProxyContext(ti);
252 close(newfd);
253 return;
254 }
255 }
256 *s = newfd;
257 // mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address
258 // from which we can infer the destination address family. Hence we need to remember that here.
259 // Instead of remembering the address family, we remember the right fd.
260 sock->fd = newfd;
261 sock->kqEntry = k;
262 k->KQcallback = ProxyTCPSocketCallBack;
263 k->KQcontext = ti;
264 k->KQtask = "TCP Proxy packet reception";
265 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
266 k->readSource = mDNSNULL;
267 k->writeSource = mDNSNULL;
268 k->fdClosed = mDNSfalse;
269 #endif
270 KQueueSet(*s, EV_ADD, EVFILT_READ, k);
271 }
272 }
273
274 mDNSlocal mStatus SetupUDPProxySocket(mDNS *const m, int skt, KQSocketSet *cp, u_short sa_family, mDNSBool useBackgroundTrafficClass)
275 {
276 int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
277 KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
278 const int on = 1;
279 mStatus err = mStatus_NoError;
280
281 cp->m = m;
282 cp->closeFlag = mDNSNULL;
283
284 // set default traffic class
285 // setTrafficClass(skt, mDNSfalse);
286 (void) useBackgroundTrafficClass;
287
288 if (sa_family == AF_INET)
289 {
290 err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
291 if (err < 0)
292 {
293 LogMsg("SetupUDPProxySocket: IP_RECVDSTADDR %d errno %d (%s)", skt, errno, strerror(errno));
294 return err;
295 }
296
297 // We want to receive interface identifiers
298 err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
299 if (err < 0)
300 {
301 LogMsg("SetupUDPProxySocket: IP_RECVIF %d errno %d (%s)", skt, errno, strerror(errno));
302 return err;
303 }
304 }
305 else if (sa_family == AF_INET6)
306 {
307 // We want to receive destination addresses and receive interface identifiers
308 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
309 if (err < 0)
310 {
311 LogMsg("SetupUDPProxySocket: IPV6_RECVPKTINFO %d errno %d (%s)", skt, errno, strerror(errno));
312 return err;
313 }
314
315 // We want to receive packet hop count value so we can check it
316 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on));
317 if (err < 0)
318 {
319 LogMsg("SetupUDPProxySocket: IPV6_RECVHOPLIMIT %d errno %d (%s)", skt, errno, strerror(errno));
320 return err;
321 }
322 }
323 else
324 {
325 LogMsg("SetupUDPProxySocket: wrong family %d", sa_family);
326 return -1;
327 }
328
329 if (fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK) < 0)
330 {
331 LogMsg("SetupUDPProxySocket: fnctl failed %d", errno);
332 return -1;
333 }
334
335 *s = skt;
336 //k->KQcallback = ProxyUDPSocketCallBack;
337 k->KQcallback = myKQSocketCallBack;
338 k->KQcontext = cp;
339 k->KQtask = "UDP Proxy packet reception";
340 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
341 k->readSource = mDNSNULL;
342 k->writeSource = mDNSNULL;
343 k->fdClosed = mDNSfalse;
344 #endif
345
346 KQueueSet(*s, EV_ADD, EVFILT_READ, k);
347
348 return(err);
349 }
350
351 mDNSlocal mStatus SetupTCPProxySocket(mDNS *const m, int skt, KQSocketSet *cp, u_short sa_family, mDNSBool useBackgroundTrafficClass)
352 {
353 int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
354 KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
355 mStatus err;
356
357 cp->m = m;
358 // XXX may not be used by the TCP codepath
359 cp->closeFlag = mDNSNULL;
360
361 // for TCP sockets, the traffic class is set once and not changed
362 // setTrafficClass(skt, useBackgroundTrafficClass);
363 (void) useBackgroundTrafficClass;
364
365 // All the socket setup has already been done
366 err = listen(skt, NUM_PROXY_TCP_CONNS);
367 if (err)
368 {
369 LogMsg("SetupTCPProxySocket: listen %d errno %d (%s)", skt, errno, strerror(errno));
370 return err;
371 }
372 fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
373
374 *s = skt;
375 k->KQcallback = ProxyTCPAccept;
376 k->KQcontext = cp;
377 k->KQtask = "TCP Accept";
378 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
379 k->readSource = mDNSNULL;
380 k->writeSource = mDNSNULL;
381 k->fdClosed = mDNSfalse;
382 #endif
383 KQueueSet(*s, EV_ADD, EVFILT_READ, k);
384 return mStatus_NoError;
385 }
386
387 mDNSlocal void BindDPSocket(int fd, int sa_family)
388 {
389 int err;
390 const int on = 1;
391
392 if (sa_family == AF_INET)
393 {
394 struct sockaddr_in addr;
395
396 err = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
397 if (err < 0)
398 LogMsg("BindDPSocket: setsockopt SO_REUSEPORT failed for IPv4 %d errno %d (%s)", fd, errno, strerror(errno));
399
400 memset(&addr, 0, sizeof(addr));
401 addr.sin_family = AF_INET;
402 addr.sin_port = htons(53);
403
404 err = bind(fd, (struct sockaddr*) &addr, sizeof(addr));
405 if (err)
406 {
407 LogMsg("BindDPSocket: bind %d errno %d (%s)", fd, errno, strerror(errno));
408 return;
409 }
410 }
411 else
412 {
413 struct sockaddr_in6 addr6;
414
415 // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
416 // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
417 err = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
418 if (err < 0)
419 {
420 LogMsg("DPFBindSocket: setsockopt IPV6_V6ONLY %d errno %d (%s)", fd, errno, strerror(errno));
421 return;
422 }
423 err = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
424 if (err < 0)
425 LogMsg("BindDPSocket: setsockopt SO_REUSEPORT failed for V6 %d errno %d (%s)", fd, errno, strerror(errno));
426
427 memset(&addr6, 0, sizeof(addr6));
428 addr6.sin6_family = AF_INET6;
429 addr6.sin6_port = htons(53);
430
431 err = bind(fd, (struct sockaddr*) &addr6, sizeof(addr6));
432 if (err)
433 {
434 LogMsg("BindDPSocket: bind6 %d errno %d (%s)", fd, errno, strerror(errno));
435 return;
436 }
437 }
438 }
439
440 // Setup DNS Proxy Skts in main kevent loop and set the skt options
441 mDNSlocal void SetupDNSProxySkts(mDNS *const m, int fd[4])
442 {
443 int i;
444 mStatus err;
445 KQSocketSet *udpSS;
446 KQSocketSet *tcpSS;
447
448 udpSS = &m->p->UDPProxy.ss;
449 tcpSS = &m->p->TCPProxy.ss;
450 udpSS->port = UnicastDNSPort;
451 tcpSS->port = UnicastDNSPort;
452
453 LogMsg("SetupDNSProxySkts: %d, %d, %d, %d", fd[0], fd[1], fd[2], fd[3]);
454
455 // myKQSocketCallBack checks for proxy and calls the m->p->ProxyCallback instead of mDNSCoreReceive
456 udpSS->proxy = mDNStrue;
457 err = SetupUDPProxySocket(m, fd[0], udpSS, AF_INET, mDNSfalse);
458 if (err)
459 LogMsg("SetupDNSProxySkts: ERROR!! UDPv4 Socket");
460
461 err = SetupUDPProxySocket(m, fd[1], udpSS, AF_INET6, mDNSfalse);
462 if (err)
463 LogMsg("SetupDNSProxySkts: ERROR!! UDPv6 Socket");
464
465 err = SetupTCPProxySocket(m, fd[2], tcpSS, AF_INET, mDNSfalse);
466 if (err)
467 LogMsg("SetupDNSProxySkts: ERROR!! TCPv4 Socket");
468
469 err = SetupTCPProxySocket(m, fd[3], tcpSS, AF_INET6, mDNSfalse);
470 if (err)
471 LogMsg("SetupDNSProxySkts: ERROR!! TCPv6 Socket");
472
473 for (i = 0; i < 4; i++)
474 dp_listener[i] = fd[i];
475 }
476
477 // Create and bind the DNS Proxy Skts for use
478 mDNSexport void mDNSPlatformInitDNSProxySkts(mDNS *const m, ProxyCallback UDPCallback, ProxyCallback TCPCallback)
479 {
480 int dpskt[4];
481
482 dpskt[0] = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
483 dpskt[1] = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
484 dpskt[2] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
485 dpskt[3] = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
486
487 // Close all DNS Proxy skts in case any of them are invalid
488 if (!ValidSocket(dpskt[0]) || !ValidSocket(dpskt[1]) ||
489 !ValidSocket(dpskt[2]) || !ValidSocket(dpskt[3]))
490 {
491 if (ValidSocket(dpskt[0]))
492 close(dpskt[0]);
493 if (ValidSocket(dpskt[1]))
494 close(dpskt[1]);
495 if (ValidSocket(dpskt[2]))
496 close(dpskt[2]);
497 if (ValidSocket(dpskt[3]))
498 close(dpskt[3]);
499 }
500
501 BindDPSocket(dpskt[0], AF_INET);
502 BindDPSocket(dpskt[1], AF_INET6);
503 BindDPSocket(dpskt[2], AF_INET);
504 BindDPSocket(dpskt[3], AF_INET6);
505
506 LogInfo("mDNSPlatformInitDNSProxySkts: Opened Listener Sockets for DNS Proxy : %d, %d, %d, %d",
507 dpskt[0], dpskt[1], dpskt[2], dpskt[3]);
508
509 m->p->UDPProxyCallback = UDPCallback;
510 m->p->TCPProxyCallback = TCPCallback;
511
512 SetupDNSProxySkts(m, dpskt);
513 }
514
515 mDNSexport void mDNSPlatformCloseDNSProxySkts(mDNS *const m)
516 {
517 (void) m;
518 int i;
519 for (i = 0; i < 4; i++)
520 close(dp_listener[i]);
521 LogInfo("mDNSPlatformCloseDNSProxySkts: Closing DNS Proxy Listener Sockets");
522 }
523
524 mDNSexport void mDNSPlatformDisposeProxyContext(void *context)
525 {
526 ProxyTCPInfo_t *ti;
527 TCPSocket *sock;
528 KQSocketSet *kq;
529
530 if (!context)
531 return;
532
533 ti = (ProxyTCPInfo_t *)context;
534 sock = &ti->sock;
535
536 kq = &sock->ss;
537 if (kq->sktv4 != -1)
538 {
539 shutdown(kq->sktv4, 2);
540 mDNSPlatformCloseFD(&kq->kqsv4, kq->sktv4);
541 }
542 if (kq->sktv6 != -1)
543 {
544 shutdown(kq->sktv6, 2);
545 mDNSPlatformCloseFD(&kq->kqsv6, kq->sktv6);
546 }
547 if (kq->closeFlag)
548 *kq->closeFlag = 1;
549
550 if (ti->reply)
551 freeL("ProxyTCPInfoLen", ti->reply);
552 freeL("ProxyTCPContext", ti);
553 }
554