1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2011-2013 Apple Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include "mDNSEmbeddedAPI.h"
19 #include "mDNSMacOSX.h"
21 #include <sys/types.h>
23 #include <sys/event.h>
24 #include <netinet/tcp.h>
26 mDNSexport mDNS mDNSStorage
;
28 #define ValidSocket(s) ((s) >= 0)
30 // Global to store the 4 DNS Proxy Listeners (UDPv4/6, TCPv4/6)
31 static int dp_listener
[4];
33 #define NUM_PROXY_TCP_CONNS 100
43 // returns -1 for failures including the other end closing the socket
44 // returns 0 if successful in reading data, but still not read the data fully
45 // returns 1 if successful in reading all the data
46 mDNSlocal
int ProxyTCPRead(ProxyTCPInfo_t
*tcpInfo
)
51 if (tcpInfo
->nread
< 2) // First read the two-byte length preceeding the DNS message
53 mDNSu8
*lenptr
= (mDNSu8
*)&tcpInfo
->replyLen
;
54 n
= mDNSPlatformReadTCP(&tcpInfo
->sock
, lenptr
+ tcpInfo
->nread
, 2 - tcpInfo
->nread
, &closed
);
57 LogMsg("ProxyTCPRead: attempt to read message length failed");
62 if (tcpInfo
->nread
< 2)
64 LogMsg("ProxyTCPRead: nread %d, n %d", tcpInfo
->nread
, n
);
68 tcpInfo
->replyLen
= (mDNSu16
)((mDNSu16
)lenptr
[0] << 8 | lenptr
[1]);
69 if (tcpInfo
->replyLen
< sizeof(DNSMessageHeader
))
71 LogMsg("ProxyTCPRead: Message length too short (%d bytes)", tcpInfo
->replyLen
);
75 tcpInfo
->reply
= mallocL("ProxyTCPInfo", tcpInfo
->replyLen
);
78 LogMsg("ProxyTCPRead: Memory failure");
83 n
= mDNSPlatformReadTCP(&tcpInfo
->sock
, ((char *)tcpInfo
->reply
) + (tcpInfo
->nread
- 2), tcpInfo
->replyLen
- (tcpInfo
->nread
- 2), &closed
);
87 LogMsg("ProxyTCPRead: read failure n %d, closed %d", n
, closed
);
91 if ((tcpInfo
->nread
- 2) != tcpInfo
->replyLen
)
97 mDNSlocal
void ProxyTCPSocketCallBack(int s1
, short filter
, void *context
, __unused mDNSBool encounteredEOF
)
100 struct sockaddr_storage from
;
101 struct sockaddr_storage to
;
102 mDNSAddr senderAddr
, destAddr
;
103 mDNSIPPort senderPort
;
104 ProxyTCPInfo_t
*ti
= (ProxyTCPInfo_t
*)context
;
105 TCPSocket
*sock
= &ti
->sock
;
106 KQSocketSet
*kq
= &sock
->ss
;
107 struct tcp_info tcp_if
;
108 socklen_t size
= sizeof(tcp_if
);
113 ret
= ProxyTCPRead(ti
);
116 mDNSPlatformDisposeProxyContext(ti
);
121 debugf("ProxyTCPReceive: Not yet read completely Actual length %d, Read length %d", ti
->replyLen
, ti
->nread
);
124 // We read all the data and hence not interested in read events anymore
125 KQueueSet(s1
, EV_DELETE
, EVFILT_READ
, sock
->kqEntry
);
127 mDNSPlatformMemZero(&to
, sizeof(to
));
128 mDNSPlatformMemZero(&from
, sizeof(from
));
129 socklen_t len
= sizeof(to
);
130 ret
= getsockname(s1
, (struct sockaddr
*) &to
, &len
);
133 LogMsg("ProxyTCPReceive: getsockname(fd=%d) errno %d", s1
, errno
);
134 mDNSPlatformDisposeProxyContext(ti
);
137 ret
= getpeername(s1
, (struct sockaddr
*) &from
, &len
);
140 LogMsg("ProxyTCPReceive: getpeername(fd=%d) errno %d", s1
, errno
);
141 mDNSPlatformDisposeProxyContext(ti
);
144 if (getsockopt(s1
, IPPROTO_TCP
, TCP_INFO
, &tcp_if
, &size
) != 0)
146 LogMsg("ProxyTCPReceive: getsockopt for TCP_INFO failed (fd=%d) errno %d", s1
, errno
);
149 intf_id
= tcp_if
.tcpi_last_outif
;
151 if (from
.ss_family
== AF_INET
)
153 struct sockaddr_in
*s
= (struct sockaddr_in
*)&from
;
155 senderAddr
.type
= mDNSAddrType_IPv4
;
156 senderAddr
.ip
.v4
.NotAnInteger
= s
->sin_addr
.s_addr
;
157 senderPort
.NotAnInteger
= s
->sin_port
;
159 s
= (struct sockaddr_in
*)&to
;
160 destAddr
.type
= mDNSAddrType_IPv4
;
161 destAddr
.ip
.v4
.NotAnInteger
= s
->sin_addr
.s_addr
;
163 LogInfo("ProxyTCPReceive received IPv4 packet(len %d) from %#-15a to %#-15a on skt %d %s ifindex %d",
164 ti
->replyLen
, &senderAddr
, &destAddr
, s1
, NULL
, intf_id
);
166 else if (from
.ss_family
== AF_INET6
)
168 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&from
;
169 senderAddr
.type
= mDNSAddrType_IPv6
;
170 senderAddr
.ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
171 senderPort
.NotAnInteger
= sin6
->sin6_port
;
173 sin6
= (struct sockaddr_in6
*)&to
;
174 destAddr
.type
= mDNSAddrType_IPv6
;
175 destAddr
.ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
177 LogInfo("ProxyTCPReceive received IPv6 packet(len %d) from %#-15a to %#-15a on skt %d %s ifindex %d",
178 ti
->replyLen
, &senderAddr
, &destAddr
, s1
, NULL
, intf_id
);
182 LogMsg("ProxyTCPReceive from is unknown address family %d", from
.ss_family
);
183 mDNSPlatformDisposeProxyContext(ti
);
187 // We pass sock for the TCPSocket and the "ti" for context as that's what we want to free at the end.
188 // In the UDP case, there is just a single socket and nothing to free. Hence, the context (last argument)
190 kq
->m
->p
->TCPProxyCallback(sock
, ti
->reply
, (mDNSu8
*)ti
->reply
+ ti
->replyLen
, &senderAddr
, senderPort
, &destAddr
,
191 UnicastDNSPort
, (mDNSInterfaceID
)(uintptr_t)intf_id
, ti
);
194 mDNSlocal
void ProxyTCPAccept(int s1
, short filter
, void *context
, __unused mDNSBool encounteredEOF
)
197 struct sockaddr_storage ss
;
198 socklen_t sslen
= sizeof(ss
);
200 KQSocketSet
*listenSet
= (KQSocketSet
*)context
;
204 while ((newfd
= accept(s1
, (struct sockaddr
*)&ss
, &sslen
)) != -1)
211 // Even though we just need a single KQueueEntry, for simplicity we re-use
213 ProxyTCPInfo_t
*ti
= mallocL("ProxyTCPContext", sizeof(ProxyTCPInfo_t
));
216 LogMsg("ProxyTCPAccept: cannot allocate TCPSocket");
220 mDNSPlatformMemZero(ti
, sizeof(ProxyTCPInfo_t
));
222 TCPSocket
*sock
= &ti
->sock
;
227 kq
->m
= listenSet
->m
;
229 fcntl(newfd
, F_SETFL
, fcntl(newfd
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
230 if (ss
.ss_family
== AF_INET
)
234 // Receive interface identifiers
235 err
= setsockopt(newfd
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
238 LogMsg("ProxyTCPAccept: IP_RECVIF %d errno %d (%s)", newfd
, errno
, strerror(errno
));
239 mDNSPlatformDisposeProxyContext(ti
);
248 // We want to receive destination addresses and receive interface identifiers
249 err
= setsockopt(newfd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &on
, sizeof(on
));
252 LogMsg("ProxyTCPAccept: IP_RECVPKTINFO %d errno %d (%s)", newfd
, errno
, strerror(errno
));
253 mDNSPlatformDisposeProxyContext(ti
);
259 // mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address
260 // from which we can infer the destination address family. Hence we need to remember that here.
261 // Instead of remembering the address family, we remember the right fd.
264 k
->KQcallback
= ProxyTCPSocketCallBack
;
266 k
->KQtask
= "TCP Proxy packet reception";
267 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
268 k
->readSource
= mDNSNULL
;
269 k
->writeSource
= mDNSNULL
;
270 k
->fdClosed
= mDNSfalse
;
272 KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
);
276 mDNSlocal mStatus
SetupUDPProxySocket(int skt
, KQSocketSet
*cp
, u_short sa_family
, mDNSBool useBackgroundTrafficClass
)
278 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
279 KQueueEntry
*k
= (sa_family
== AF_INET
) ? &cp
->kqsv4
: &cp
->kqsv6
;
281 mStatus err
= mStatus_NoError
;
283 cp
->m
= &mDNSStorage
;
284 cp
->closeFlag
= mDNSNULL
;
286 // set default traffic class
287 // setTrafficClass(skt, mDNSfalse);
288 (void) useBackgroundTrafficClass
;
290 if (sa_family
== AF_INET
)
292 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVDSTADDR
, &on
, sizeof(on
));
295 LogMsg("SetupUDPProxySocket: IP_RECVDSTADDR %d errno %d (%s)", skt
, errno
, strerror(errno
));
299 // We want to receive interface identifiers
300 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
303 LogMsg("SetupUDPProxySocket: IP_RECVIF %d errno %d (%s)", skt
, errno
, strerror(errno
));
307 else if (sa_family
== AF_INET6
)
309 // We want to receive destination addresses and receive interface identifiers
310 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &on
, sizeof(on
));
313 LogMsg("SetupUDPProxySocket: IPV6_RECVPKTINFO %d errno %d (%s)", skt
, errno
, strerror(errno
));
317 // We want to receive packet hop count value so we can check it
318 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &on
, sizeof(on
));
321 LogMsg("SetupUDPProxySocket: IPV6_RECVHOPLIMIT %d errno %d (%s)", skt
, errno
, strerror(errno
));
327 LogMsg("SetupUDPProxySocket: wrong family %d", sa_family
);
331 if (fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
) < 0)
333 LogMsg("SetupUDPProxySocket: fnctl failed %d", errno
);
338 //k->KQcallback = ProxyUDPSocketCallBack;
339 k
->KQcallback
= myKQSocketCallBack
;
341 k
->KQtask
= "UDP Proxy packet reception";
342 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
343 k
->readSource
= mDNSNULL
;
344 k
->writeSource
= mDNSNULL
;
345 k
->fdClosed
= mDNSfalse
;
348 KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
);
353 mDNSlocal mStatus
SetupTCPProxySocket(int skt
, KQSocketSet
*cp
, u_short sa_family
, mDNSBool useBackgroundTrafficClass
)
355 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
356 KQueueEntry
*k
= (sa_family
== AF_INET
) ? &cp
->kqsv4
: &cp
->kqsv6
;
359 cp
->m
= &mDNSStorage
;
360 // XXX may not be used by the TCP codepath
361 cp
->closeFlag
= mDNSNULL
;
363 // for TCP sockets, the traffic class is set once and not changed
364 // setTrafficClass(skt, useBackgroundTrafficClass);
365 (void) useBackgroundTrafficClass
;
367 // All the socket setup has already been done
368 err
= listen(skt
, NUM_PROXY_TCP_CONNS
);
371 LogMsg("SetupTCPProxySocket: listen %d errno %d (%s)", skt
, errno
, strerror(errno
));
374 fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
377 k
->KQcallback
= ProxyTCPAccept
;
379 k
->KQtask
= "TCP Accept";
380 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
381 k
->readSource
= mDNSNULL
;
382 k
->writeSource
= mDNSNULL
;
383 k
->fdClosed
= mDNSfalse
;
385 KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
);
386 return mStatus_NoError
;
389 mDNSlocal
void BindDPSocket(int fd
, int sa_family
)
394 if (sa_family
== AF_INET
)
396 struct sockaddr_in addr
;
398 err
= setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
400 LogMsg("BindDPSocket: setsockopt SO_REUSEPORT failed for IPv4 %d errno %d (%s)", fd
, errno
, strerror(errno
));
402 memset(&addr
, 0, sizeof(addr
));
403 addr
.sin_family
= AF_INET
;
404 addr
.sin_port
= htons(53);
406 err
= bind(fd
, (struct sockaddr
*) &addr
, sizeof(addr
));
409 LogMsg("BindDPSocket: bind %d errno %d (%s)", fd
, errno
, strerror(errno
));
415 struct sockaddr_in6 addr6
;
417 // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
418 // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
419 err
= setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
));
422 LogMsg("DPFBindSocket: setsockopt IPV6_V6ONLY %d errno %d (%s)", fd
, errno
, strerror(errno
));
425 err
= setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
427 LogMsg("BindDPSocket: setsockopt SO_REUSEPORT failed for V6 %d errno %d (%s)", fd
, errno
, strerror(errno
));
429 memset(&addr6
, 0, sizeof(addr6
));
430 addr6
.sin6_family
= AF_INET6
;
431 addr6
.sin6_port
= htons(53);
433 err
= bind(fd
, (struct sockaddr
*) &addr6
, sizeof(addr6
));
436 LogMsg("BindDPSocket: bind6 %d errno %d (%s)", fd
, errno
, strerror(errno
));
442 // Setup DNS Proxy Skts in main kevent loop and set the skt options
443 mDNSlocal
void SetupDNSProxySkts(int fd
[4])
445 mDNS
*const m
= &mDNSStorage
;
451 udpSS
= &m
->p
->UDPProxy
.ss
;
452 tcpSS
= &m
->p
->TCPProxy
.ss
;
453 udpSS
->port
= UnicastDNSPort
;
454 tcpSS
->port
= UnicastDNSPort
;
456 LogMsg("SetupDNSProxySkts: %d, %d, %d, %d", fd
[0], fd
[1], fd
[2], fd
[3]);
458 // myKQSocketCallBack checks for proxy and calls the m->p->ProxyCallback instead of mDNSCoreReceive
459 udpSS
->proxy
= mDNStrue
;
460 err
= SetupUDPProxySocket(fd
[0], udpSS
, AF_INET
, mDNSfalse
);
462 LogMsg("SetupDNSProxySkts: ERROR!! UDPv4 Socket");
464 err
= SetupUDPProxySocket(fd
[1], udpSS
, AF_INET6
, mDNSfalse
);
466 LogMsg("SetupDNSProxySkts: ERROR!! UDPv6 Socket");
468 err
= SetupTCPProxySocket(fd
[2], tcpSS
, AF_INET
, mDNSfalse
);
470 LogMsg("SetupDNSProxySkts: ERROR!! TCPv4 Socket");
472 err
= SetupTCPProxySocket(fd
[3], tcpSS
, AF_INET6
, mDNSfalse
);
474 LogMsg("SetupDNSProxySkts: ERROR!! TCPv6 Socket");
476 for (i
= 0; i
< 4; i
++)
477 dp_listener
[i
] = fd
[i
];
480 // Create and bind the DNS Proxy Skts for use
481 mDNSexport
void mDNSPlatformInitDNSProxySkts(ProxyCallback UDPCallback
, ProxyCallback TCPCallback
)
485 dpskt
[0] = socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
486 dpskt
[1] = socket(AF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
);
487 dpskt
[2] = socket(AF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
488 dpskt
[3] = socket(AF_INET6
, SOCK_STREAM
, IPPROTO_TCP
);
490 // Close all DNS Proxy skts in case any of them are invalid
491 if (!ValidSocket(dpskt
[0]) || !ValidSocket(dpskt
[1]) ||
492 !ValidSocket(dpskt
[2]) || !ValidSocket(dpskt
[3]))
494 if (ValidSocket(dpskt
[0]))
496 if (ValidSocket(dpskt
[1]))
498 if (ValidSocket(dpskt
[2]))
500 if (ValidSocket(dpskt
[3]))
504 BindDPSocket(dpskt
[0], AF_INET
);
505 BindDPSocket(dpskt
[1], AF_INET6
);
506 BindDPSocket(dpskt
[2], AF_INET
);
507 BindDPSocket(dpskt
[3], AF_INET6
);
509 LogInfo("mDNSPlatformInitDNSProxySkts: Opened Listener Sockets for DNS Proxy : %d, %d, %d, %d",
510 dpskt
[0], dpskt
[1], dpskt
[2], dpskt
[3]);
512 mDNSStorage
.p
->UDPProxyCallback
= UDPCallback
;
513 mDNSStorage
.p
->TCPProxyCallback
= TCPCallback
;
515 SetupDNSProxySkts(dpskt
);
518 mDNSexport
void mDNSPlatformCloseDNSProxySkts(mDNS
*const m
)
522 for (i
= 0; i
< 4; i
++)
523 close(dp_listener
[i
]);
524 LogInfo("mDNSPlatformCloseDNSProxySkts: Closing DNS Proxy Listener Sockets");
527 mDNSexport
void mDNSPlatformDisposeProxyContext(void *context
)
536 ti
= (ProxyTCPInfo_t
*)context
;
542 shutdown(kq
->sktv4
, 2);
543 mDNSPlatformCloseFD(&kq
->kqsv4
, kq
->sktv4
);
547 shutdown(kq
->sktv6
, 2);
548 mDNSPlatformCloseFD(&kq
->kqsv6
, kq
->sktv6
);
554 freeL("ProxyTCPInfoLen", ti
->reply
);
555 freeL("ProxyTCPContext", ti
);