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