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 #define ValidSocket(s) ((s) >= 0)
28 // Global to store the 4 DNS Proxy Listeners (UDPv4/6, TCPv4/6)
29 static int dp_listener
[4];
31 #define NUM_PROXY_TCP_CONNS 100
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
)
49 if (tcpInfo
->nread
< 2) // First read the two-byte length preceeding the DNS message
51 mDNSu8
*lenptr
= (mDNSu8
*)&tcpInfo
->replyLen
;
52 n
= mDNSPlatformReadTCP(&tcpInfo
->sock
, lenptr
+ tcpInfo
->nread
, 2 - tcpInfo
->nread
, &closed
);
55 LogMsg("ProxyTCPRead: attempt to read message length failed");
60 if (tcpInfo
->nread
< 2)
62 LogMsg("ProxyTCPRead: nread %d, n %d", tcpInfo
->nread
, n
);
66 tcpInfo
->replyLen
= (mDNSu16
)((mDNSu16
)lenptr
[0] << 8 | lenptr
[1]);
67 if (tcpInfo
->replyLen
< sizeof(DNSMessageHeader
))
69 LogMsg("ProxyTCPRead: Message length too short (%d bytes)", tcpInfo
->replyLen
);
73 tcpInfo
->reply
= mallocL("ProxyTCPInfo", tcpInfo
->replyLen
);
76 LogMsg("ProxyTCPRead: Memory failure");
81 n
= mDNSPlatformReadTCP(&tcpInfo
->sock
, ((char *)tcpInfo
->reply
) + (tcpInfo
->nread
- 2), tcpInfo
->replyLen
- (tcpInfo
->nread
- 2), &closed
);
85 LogMsg("ProxyTCPRead: read failure n %d, closed %d", n
, closed
);
89 if ((tcpInfo
->nread
- 2) != tcpInfo
->replyLen
)
95 mDNSlocal
void ProxyTCPSocketCallBack(int s1
, short filter
, void *context
)
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
);
111 ret
= ProxyTCPRead(ti
);
114 mDNSPlatformDisposeProxyContext(ti
);
119 debugf("ProxyTCPReceive: Not yet read completely Actual length %d, Read length %d", ti
->replyLen
, ti
->nread
);
122 // We read all the data and hence not interested in read events anymore
123 KQueueSet(s1
, EV_DELETE
, EVFILT_READ
, sock
->kqEntry
);
125 mDNSPlatformMemZero(&to
, sizeof(to
));
126 mDNSPlatformMemZero(&from
, sizeof(from
));
127 socklen_t len
= sizeof(to
);
128 ret
= getsockname(s1
, (struct sockaddr
*) &to
, &len
);
131 LogMsg("ProxyTCPReceive: getsockname(fd=%d) errno %d", s1
, errno
);
132 mDNSPlatformDisposeProxyContext(ti
);
135 ret
= getpeername(s1
, (struct sockaddr
*) &from
, &len
);
138 LogMsg("ProxyTCPReceive: getpeername(fd=%d) errno %d", s1
, errno
);
139 mDNSPlatformDisposeProxyContext(ti
);
142 if (getsockopt(s1
, IPPROTO_TCP
, TCP_INFO
, &tcp_if
, &size
) != 0)
144 LogMsg("ProxyTCPReceive: getsockopt for TCP_INFO failed (fd=%d) errno %d", s1
, errno
);
147 intf_id
= tcp_if
.tcpi_last_outif
;
149 if (from
.ss_family
== AF_INET
)
151 struct sockaddr_in
*s
= (struct sockaddr_in
*)&from
;
153 senderAddr
.type
= mDNSAddrType_IPv4
;
154 senderAddr
.ip
.v4
.NotAnInteger
= s
->sin_addr
.s_addr
;
155 senderPort
.NotAnInteger
= s
->sin_port
;
157 s
= (struct sockaddr_in
*)&to
;
158 destAddr
.type
= mDNSAddrType_IPv4
;
159 destAddr
.ip
.v4
.NotAnInteger
= s
->sin_addr
.s_addr
;
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
);
164 else if (from
.ss_family
== AF_INET6
)
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
;
171 sin6
= (struct sockaddr_in6
*)&to
;
172 destAddr
.type
= mDNSAddrType_IPv6
;
173 destAddr
.ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
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
);
180 LogMsg("ProxyTCPReceive from is unknown address family %d", from
.ss_family
);
181 mDNSPlatformDisposeProxyContext(ti
);
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)
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
);
192 mDNSlocal
void ProxyTCPAccept(int s1
, short filter
, void *context
)
195 struct sockaddr_storage ss
;
196 socklen_t sslen
= sizeof(ss
);
198 KQSocketSet
*listenSet
= (KQSocketSet
*)context
;
202 while ((newfd
= accept(s1
, (struct sockaddr
*)&ss
, &sslen
)) != -1)
209 // Even though we just need a single KQueueEntry, for simplicity we re-use
211 ProxyTCPInfo_t
*ti
= mallocL("ProxyTCPContext", sizeof(ProxyTCPInfo_t
));
214 LogMsg("ProxyTCPAccept: cannot allocate TCPSocket");
218 mDNSPlatformMemZero(ti
, sizeof(ProxyTCPInfo_t
));
220 TCPSocket
*sock
= &ti
->sock
;
225 kq
->m
= listenSet
->m
;
227 fcntl(newfd
, F_SETFL
, fcntl(newfd
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
228 if (ss
.ss_family
== AF_INET
)
232 // Receive interface identifiers
233 err
= setsockopt(newfd
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
236 LogMsg("ProxyTCPAccept: IP_RECVIF %d errno %d (%s)", newfd
, errno
, strerror(errno
));
237 mDNSPlatformDisposeProxyContext(ti
);
246 // We want to receive destination addresses and receive interface identifiers
247 err
= setsockopt(newfd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &on
, sizeof(on
));
250 LogMsg("ProxyTCPAccept: IP_RECVPKTINFO %d errno %d (%s)", newfd
, errno
, strerror(errno
));
251 mDNSPlatformDisposeProxyContext(ti
);
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.
262 k
->KQcallback
= ProxyTCPSocketCallBack
;
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
;
270 KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
);
274 mDNSlocal mStatus
SetupUDPProxySocket(mDNS
*const m
, int skt
, KQSocketSet
*cp
, u_short sa_family
, mDNSBool useBackgroundTrafficClass
)
276 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
277 KQueueEntry
*k
= (sa_family
== AF_INET
) ? &cp
->kqsv4
: &cp
->kqsv6
;
279 mStatus err
= mStatus_NoError
;
282 cp
->closeFlag
= mDNSNULL
;
284 // set default traffic class
285 // setTrafficClass(skt, mDNSfalse);
286 (void) useBackgroundTrafficClass
;
288 if (sa_family
== AF_INET
)
290 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVDSTADDR
, &on
, sizeof(on
));
293 LogMsg("SetupUDPProxySocket: IP_RECVDSTADDR %d errno %d (%s)", skt
, errno
, strerror(errno
));
297 // We want to receive interface identifiers
298 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
301 LogMsg("SetupUDPProxySocket: IP_RECVIF %d errno %d (%s)", skt
, errno
, strerror(errno
));
305 else if (sa_family
== AF_INET6
)
307 // We want to receive destination addresses and receive interface identifiers
308 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &on
, sizeof(on
));
311 LogMsg("SetupUDPProxySocket: IPV6_RECVPKTINFO %d errno %d (%s)", skt
, errno
, strerror(errno
));
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
));
319 LogMsg("SetupUDPProxySocket: IPV6_RECVHOPLIMIT %d errno %d (%s)", skt
, errno
, strerror(errno
));
325 LogMsg("SetupUDPProxySocket: wrong family %d", sa_family
);
329 if (fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
) < 0)
331 LogMsg("SetupUDPProxySocket: fnctl failed %d", errno
);
336 //k->KQcallback = ProxyUDPSocketCallBack;
337 k
->KQcallback
= myKQSocketCallBack
;
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
;
346 KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
);
351 mDNSlocal mStatus
SetupTCPProxySocket(mDNS
*const m
, int skt
, KQSocketSet
*cp
, u_short sa_family
, mDNSBool useBackgroundTrafficClass
)
353 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
354 KQueueEntry
*k
= (sa_family
== AF_INET
) ? &cp
->kqsv4
: &cp
->kqsv6
;
358 // XXX may not be used by the TCP codepath
359 cp
->closeFlag
= mDNSNULL
;
361 // for TCP sockets, the traffic class is set once and not changed
362 // setTrafficClass(skt, useBackgroundTrafficClass);
363 (void) useBackgroundTrafficClass
;
365 // All the socket setup has already been done
366 err
= listen(skt
, NUM_PROXY_TCP_CONNS
);
369 LogMsg("SetupTCPProxySocket: listen %d errno %d (%s)", skt
, errno
, strerror(errno
));
372 fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
375 k
->KQcallback
= ProxyTCPAccept
;
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
;
383 KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
);
384 return mStatus_NoError
;
387 mDNSlocal
void BindDPSocket(int fd
, int sa_family
)
392 if (sa_family
== AF_INET
)
394 struct sockaddr_in addr
;
396 err
= setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
398 LogMsg("BindDPSocket: setsockopt SO_REUSEPORT failed for IPv4 %d errno %d (%s)", fd
, errno
, strerror(errno
));
400 memset(&addr
, 0, sizeof(addr
));
401 addr
.sin_family
= AF_INET
;
402 addr
.sin_port
= htons(53);
404 err
= bind(fd
, (struct sockaddr
*) &addr
, sizeof(addr
));
407 LogMsg("BindDPSocket: bind %d errno %d (%s)", fd
, errno
, strerror(errno
));
413 struct sockaddr_in6 addr6
;
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
));
420 LogMsg("DPFBindSocket: setsockopt IPV6_V6ONLY %d errno %d (%s)", fd
, errno
, strerror(errno
));
423 err
= setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
425 LogMsg("BindDPSocket: setsockopt SO_REUSEPORT failed for V6 %d errno %d (%s)", fd
, errno
, strerror(errno
));
427 memset(&addr6
, 0, sizeof(addr6
));
428 addr6
.sin6_family
= AF_INET6
;
429 addr6
.sin6_port
= htons(53);
431 err
= bind(fd
, (struct sockaddr
*) &addr6
, sizeof(addr6
));
434 LogMsg("BindDPSocket: bind6 %d errno %d (%s)", fd
, errno
, strerror(errno
));
440 // Setup DNS Proxy Skts in main kevent loop and set the skt options
441 mDNSlocal
void SetupDNSProxySkts(mDNS
*const m
, int fd
[4])
448 udpSS
= &m
->p
->UDPProxy
.ss
;
449 tcpSS
= &m
->p
->TCPProxy
.ss
;
450 udpSS
->port
= UnicastDNSPort
;
451 tcpSS
->port
= UnicastDNSPort
;
453 LogMsg("SetupDNSProxySkts: %d, %d, %d, %d", fd
[0], fd
[1], fd
[2], fd
[3]);
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
);
459 LogMsg("SetupDNSProxySkts: ERROR!! UDPv4 Socket");
461 err
= SetupUDPProxySocket(m
, fd
[1], udpSS
, AF_INET6
, mDNSfalse
);
463 LogMsg("SetupDNSProxySkts: ERROR!! UDPv6 Socket");
465 err
= SetupTCPProxySocket(m
, fd
[2], tcpSS
, AF_INET
, mDNSfalse
);
467 LogMsg("SetupDNSProxySkts: ERROR!! TCPv4 Socket");
469 err
= SetupTCPProxySocket(m
, fd
[3], tcpSS
, AF_INET6
, mDNSfalse
);
471 LogMsg("SetupDNSProxySkts: ERROR!! TCPv6 Socket");
473 for (i
= 0; i
< 4; i
++)
474 dp_listener
[i
] = fd
[i
];
477 // Create and bind the DNS Proxy Skts for use
478 mDNSexport
void mDNSPlatformInitDNSProxySkts(mDNS
*const m
, ProxyCallback UDPCallback
, ProxyCallback TCPCallback
)
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
);
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]))
491 if (ValidSocket(dpskt
[0]))
493 if (ValidSocket(dpskt
[1]))
495 if (ValidSocket(dpskt
[2]))
497 if (ValidSocket(dpskt
[3]))
501 BindDPSocket(dpskt
[0], AF_INET
);
502 BindDPSocket(dpskt
[1], AF_INET6
);
503 BindDPSocket(dpskt
[2], AF_INET
);
504 BindDPSocket(dpskt
[3], AF_INET6
);
506 LogInfo("mDNSPlatformInitDNSProxySkts: Opened Listener Sockets for DNS Proxy : %d, %d, %d, %d",
507 dpskt
[0], dpskt
[1], dpskt
[2], dpskt
[3]);
509 m
->p
->UDPProxyCallback
= UDPCallback
;
510 m
->p
->TCPProxyCallback
= TCPCallback
;
512 SetupDNSProxySkts(m
, dpskt
);
515 mDNSexport
void mDNSPlatformCloseDNSProxySkts(mDNS
*const m
)
519 for (i
= 0; i
< 4; i
++)
520 close(dp_listener
[i
]);
521 LogInfo("mDNSPlatformCloseDNSProxySkts: Closing DNS Proxy Listener Sockets");
524 mDNSexport
void mDNSPlatformDisposeProxyContext(void *context
)
533 ti
= (ProxyTCPInfo_t
*)context
;
539 shutdown(kq
->sktv4
, 2);
540 mDNSPlatformCloseFD(&kq
->kqsv4
, kq
->sktv4
);
544 shutdown(kq
->sktv6
, 2);
545 mDNSPlatformCloseFD(&kq
->kqsv6
, kq
->sktv6
);
551 freeL("ProxyTCPInfoLen", ti
->reply
);
552 freeL("ProxyTCPContext", ti
);