1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2011 Apple Computer, 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.
17 #include "mDNSEmbeddedAPI.h"
18 #include "mDNSMacOSX.h"
20 #include <sys/types.h>
22 #include <sys/event.h>
24 #define ValidSocket(s) ((s) >= 0)
26 // Global to store the 4 DNS Proxy Listeners (UDPv4/6, TCPv4/6)
27 static int dp_listener
[4];
29 #define NUM_PROXY_TCP_CONNS 100
39 // returns -1 for failures including the other end closing the socket
40 // returns 0 if successful in reading data, but still not read the data fully
41 // returns 1 if successful in reading all the data
42 mDNSlocal
int ProxyTCPRead(ProxyTCPInfo_t
*tcpInfo
)
47 if (tcpInfo
->nread
< 2) // First read the two-byte length preceeding the DNS message
49 mDNSu8
*lenptr
= (mDNSu8
*)&tcpInfo
->replyLen
;
50 n
= mDNSPlatformReadTCP(&tcpInfo
->sock
, lenptr
+ tcpInfo
->nread
, 2 - tcpInfo
->nread
, &closed
);
53 LogMsg("ProxyTCPRead: attempt to read message length failed");
58 if (tcpInfo
->nread
< 2)
60 LogMsg("ProxyTCPRead: nread %d, n %d", tcpInfo
->nread
, n
);
64 tcpInfo
->replyLen
= (mDNSu16
)((mDNSu16
)lenptr
[0] << 8 | lenptr
[1]);
65 if (tcpInfo
->replyLen
< sizeof(DNSMessageHeader
))
67 LogMsg("ProxyTCPRead: Message length too short (%d bytes)", tcpInfo
->replyLen
);
71 tcpInfo
->reply
= mallocL("ProxyTCPInfo", tcpInfo
->replyLen
);
74 LogMsg("ProxyTCPRead: Memory failure");
79 n
= mDNSPlatformReadTCP(&tcpInfo
->sock
, ((char *)tcpInfo
->reply
) + (tcpInfo
->nread
- 2), tcpInfo
->replyLen
- (tcpInfo
->nread
- 2), &closed
);
83 LogMsg("ProxyTCPRead: read failure n %d, closed %d", n
, closed
);
87 if ((tcpInfo
->nread
- 2) != tcpInfo
->replyLen
)
93 mDNSlocal
void ProxyTCPSocketCallBack(int s1
, short filter
, void *context
)
96 struct sockaddr_storage from
;
97 struct sockaddr_storage to
;
98 mDNSAddr senderAddr
, destAddr
;
99 mDNSIPPort senderPort
;
100 ProxyTCPInfo_t
*ti
= (ProxyTCPInfo_t
*)context
;
101 TCPSocket
*sock
= &ti
->sock
;
102 KQSocketSet
*kq
= &sock
->ss
;
106 ret
= ProxyTCPRead(ti
);
109 mDNSPlatformDisposeProxyContext(ti
);
114 debugf("ProxyTCPReceive: Not yet read completely Actual length %d, Read length %d", ti
->replyLen
, ti
->nread
);
117 // We read all the data and hence not interested in read events anymore
118 KQueueSet(s1
, EV_DELETE
, EVFILT_READ
, sock
->kqEntry
);
120 mDNSPlatformMemZero(&to
, sizeof(to
));
121 mDNSPlatformMemZero(&from
, sizeof(from
));
122 socklen_t len
= sizeof(to
);
123 ret
= getsockname(s1
, (struct sockaddr
*) &to
, &len
);
126 LogMsg("ProxyTCPReceive: getsockname(fd=%d) errno %d", s1
, errno
);
127 mDNSPlatformDisposeProxyContext(ti
);
130 ret
= getpeername(s1
, (struct sockaddr
*) &from
, &len
);
133 LogMsg("ProxyTCPReceive: getpeername(fd=%d) errno %d", s1
, errno
);
134 mDNSPlatformDisposeProxyContext(ti
);
138 if (from
.ss_family
== AF_INET
)
140 struct sockaddr_in
*s
= (struct sockaddr_in
*)&from
;
142 senderAddr
.type
= mDNSAddrType_IPv4
;
143 senderAddr
.ip
.v4
.NotAnInteger
= s
->sin_addr
.s_addr
;
144 senderPort
.NotAnInteger
= s
->sin_port
;
146 s
= (struct sockaddr_in
*)&to
;
147 destAddr
.type
= mDNSAddrType_IPv4
;
148 destAddr
.ip
.v4
.NotAnInteger
= s
->sin_addr
.s_addr
;
150 LogInfo("ProxyTCPReceive received IPv4 packet(len %d) from %#-15a to %#-15a on skt %d %s", ti
->replyLen
, &senderAddr
, &destAddr
, s1
, NULL
);
152 else if (from
.ss_family
== AF_INET6
)
154 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&from
;
155 senderAddr
.type
= mDNSAddrType_IPv6
;
156 senderAddr
.ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
157 senderPort
.NotAnInteger
= sin6
->sin6_port
;
159 sin6
= (struct sockaddr_in6
*)&to
;
160 destAddr
.type
= mDNSAddrType_IPv6
;
161 destAddr
.ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
163 LogInfo("ProxyTCPReceive received IPv6 packet(len %d) from %#-15a to %#-15a on skt %d %s", ti
->replyLen
, &senderAddr
, &destAddr
, s1
, NULL
);
167 LogMsg("ProxyTCPReceive from is unknown address family %d", from
.ss_family
);
168 mDNSPlatformDisposeProxyContext(ti
);
172 // We pass sock for the TCPSocket and the "ti" for context as that's what we want to free at the end.
173 // In the UDP case, there is just a single socket and nothing to free. Hence, the context (last argument)
175 kq
->m
->p
->TCPProxyCallback(kq
->m
, sock
, ti
->reply
, (mDNSu8
*)ti
->reply
+ ti
->replyLen
, &senderAddr
, senderPort
, &destAddr
,
176 UnicastDNSPort
, 0, ti
);
179 mDNSlocal
void ProxyTCPAccept(int s1
, short filter
, void *context
)
182 struct sockaddr_storage ss
;
183 socklen_t sslen
= sizeof(ss
);
185 KQSocketSet
*listenSet
= (KQSocketSet
*)context
;
189 while ((newfd
= accept(s1
, (struct sockaddr
*)&ss
, &sslen
)) != -1)
196 // Even though we just need a single KQueueEntry, for simplicity we re-use
198 ProxyTCPInfo_t
*ti
= mallocL("ProxyTCPContext", sizeof(ProxyTCPInfo_t
));
201 LogMsg("ProxyTCPAccept: cannot allocate TCPSocket");
205 mDNSPlatformMemZero(ti
, sizeof(ProxyTCPInfo_t
));
206 TCPSocket
*sock
= &ti
->sock
;
211 kq
->m
= listenSet
->m
;
213 fcntl(newfd
, F_SETFL
, fcntl(newfd
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
214 if (ss
.ss_family
== AF_INET
)
218 // Receive interface identifiers
219 err
= setsockopt(newfd
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
222 LogMsg("ProxyTCPAccept: IP_RECVIF %d errno %d (%s)", newfd
, errno
, strerror(errno
));
223 mDNSPlatformDisposeProxyContext(ti
);
231 // We want to receive destination addresses and receive interface identifiers
232 err
= setsockopt(newfd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &on
, sizeof(on
));
235 LogMsg("ProxyTCPAccept: IP_RECVPKTINFO %d errno %d (%s)", newfd
, errno
, strerror(errno
));
236 mDNSPlatformDisposeProxyContext(ti
);
241 // mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address
242 // from which we can infer the destination address family. Hence we need to remember that here.
243 // Instead of remembering the address family, we remember the right fd.
247 k
->KQcallback
= ProxyTCPSocketCallBack
;
249 k
->KQtask
= "TCP Proxy packet reception";
250 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
251 k
->readSource
= mDNSNULL
;
252 k
->writeSource
= mDNSNULL
;
253 k
->fdClosed
= mDNSfalse
;
255 KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
);
259 mDNSlocal mStatus
SetupUDPProxySocket(mDNS
*const m
, int skt
, KQSocketSet
*cp
, u_short sa_family
, mDNSBool useBackgroundTrafficClass
)
261 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
262 KQueueEntry
*k
= (sa_family
== AF_INET
) ? &cp
->kqsv4
: &cp
->kqsv6
;
265 mStatus err
= mStatus_NoError
;
269 cp
->closeFlag
= mDNSNULL
;
271 // set default traffic class
272 // setTrafficClass(skt, mDNSfalse);
273 (void) useBackgroundTrafficClass
;
275 if (sa_family
== AF_INET
)
277 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVDSTADDR
, &on
, sizeof(on
));
280 LogMsg("SetupUDPProxySocket: IP_RECVDSTADDR %d errno %d (%s)", skt
, errno
, strerror(errno
));
284 // We want to receive interface identifiers
285 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
288 LogMsg("SetupUDPProxySocket: IP_RECVIF %d errno %d (%s)", skt
, errno
, strerror(errno
));
292 else if (sa_family
== AF_INET6
)
294 // We want to receive destination addresses and receive interface identifiers
295 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &on
, sizeof(on
));
298 LogMsg("SetupUDPProxySocket: IPV6_RECVPKTINFO %d errno %d (%s)", skt
, errno
, strerror(errno
));
302 // We want to receive packet hop count value so we can check it
303 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &on
, sizeof(on
));
306 LogMsg("SetupUDPProxySocket: IPV6_RECVHOPLIMIT %d errno %d (%s)", skt
, errno
, strerror(errno
));
312 LogMsg("SetupUDPProxySocket: wrong family %d", sa_family
);
316 if (fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
) < 0)
318 LogMsg("SetupUDPProxySocket: fnctl failed %d", errno
);
323 //k->KQcallback = ProxyUDPSocketCallBack;
324 k
->KQcallback
= myKQSocketCallBack
;
326 k
->KQtask
= "UDP Proxy packet reception";
327 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
328 k
->readSource
= mDNSNULL
;
329 k
->writeSource
= mDNSNULL
;
330 k
->fdClosed
= mDNSfalse
;
333 KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
);
338 mDNSlocal mStatus
SetupTCPProxySocket(mDNS
*const m
, int skt
, KQSocketSet
*cp
, u_short sa_family
, mDNSBool useBackgroundTrafficClass
)
340 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
341 KQueueEntry
*k
= (sa_family
== AF_INET
) ? &cp
->kqsv4
: &cp
->kqsv6
;
347 // XXX may not be used by the TCP codepath
348 cp
->closeFlag
= mDNSNULL
;
350 // for TCP sockets, the traffic class is set once and not changed
351 // setTrafficClass(skt, useBackgroundTrafficClass);
352 (void) useBackgroundTrafficClass
;
354 // All the socket setup has already been done
355 err
= listen(skt
, NUM_PROXY_TCP_CONNS
);
358 LogMsg("SetupTCPProxySocket: listen %d errno %d (%s)", skt
, errno
, strerror(errno
));
361 fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
364 k
->KQcallback
= ProxyTCPAccept
;
366 k
->KQtask
= "TCP Accept";
367 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
368 k
->readSource
= mDNSNULL
;
369 k
->writeSource
= mDNSNULL
;
370 k
->fdClosed
= mDNSfalse
;
372 KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
);
373 return mStatus_NoError
;
376 mDNSlocal
void BindDPSocket(int fd
, int sa_family
)
381 if (sa_family
== AF_INET
)
383 struct sockaddr_in addr
;
385 err
= setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
387 LogMsg("BindDPSocket: setsockopt SO_REUSEPORT failed for V4 %d errno %d (%s)", fd
, errno
, strerror(errno
));
389 memset(&addr
, 0, sizeof(addr
));
390 addr
.sin_family
= AF_INET
;
391 addr
.sin_port
= htons(53);
393 err
= bind(fd
, (struct sockaddr
*) &addr
, sizeof(addr
));
396 LogMsg("BindDPSocket: bind %d errno %d (%s)", fd
, errno
, strerror(errno
));
402 struct sockaddr_in6 addr6
;
404 // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
405 // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
406 err
= setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
));
409 LogMsg("DPFBindSocket: setsockopt IPV6_V6ONLY %d errno %d (%s)", fd
, errno
, strerror(errno
));
412 err
= setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
414 LogMsg("BindDPSocket: setsockopt SO_REUSEPORT failed for V6 %d errno %d (%s)", fd
, errno
, strerror(errno
));
416 memset(&addr6
, 0, sizeof(addr6
));
417 addr6
.sin6_family
= AF_INET6
;
418 addr6
.sin6_port
= htons(53);
420 err
= bind(fd
, (struct sockaddr
*) &addr6
, sizeof(addr6
));
423 LogMsg("BindDPSocket: bind6 %d errno %d (%s)", fd
, errno
, strerror(errno
));
429 // Setup DNS Proxy Skts in main kevent loop and set the skt options
430 mDNSlocal
void SetupDNSProxySkts(mDNS
*const m
, int fd
[4])
437 udpSS
= &m
->p
->UDPProxy
.ss
;
438 tcpSS
= &m
->p
->TCPProxy
.ss
;
439 udpSS
->port
= UnicastDNSPort
;
440 tcpSS
->port
= UnicastDNSPort
;
442 LogMsg("SetupDNSProxySkts: %d, %d, %d, %d", fd
[0], fd
[1], fd
[2], fd
[3]);
444 // myKQSocketCallBack checks for proxy and calls the m->p->ProxyCallback instead of mDNSCoreReceive
445 udpSS
->proxy
= mDNStrue
;
446 err
= SetupUDPProxySocket(m
, fd
[0], udpSS
, AF_INET
, mDNSfalse
);
448 LogMsg("SetupDNSProxySkts: ERROR!! UDPv4 Socket");
450 err
= SetupUDPProxySocket(m
, fd
[1], udpSS
, AF_INET6
, mDNSfalse
);
452 LogMsg("SetupDNSProxySkts: ERROR!! UDPv6 Socket");
454 err
= SetupTCPProxySocket(m
, fd
[2], tcpSS
, AF_INET
, mDNSfalse
);
456 LogMsg("SetupDNSProxySkts: ERROR!! TCPv4 Socket");
458 err
= SetupTCPProxySocket(m
, fd
[3], tcpSS
, AF_INET6
, mDNSfalse
);
460 LogMsg("SetupDNSProxySkts: ERROR!! TCPv6 Socket");
462 for (i
= 0; i
< 4; i
++)
463 dp_listener
[i
] = fd
[i
];
466 // Create and bind the DNS Proxy Skts for use
467 mDNSexport
void mDNSPlatformInitDNSProxySkts(mDNS
*const m
, ProxyCallback UDPCallback
, ProxyCallback TCPCallback
)
471 dpskt
[0] = socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
472 dpskt
[1] = socket(AF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
);
473 dpskt
[2] = socket(AF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
474 dpskt
[3] = socket(AF_INET6
, SOCK_STREAM
, IPPROTO_TCP
);
476 // Close all DNS Proxy skts in case any of them are invalid
477 if (!ValidSocket(dpskt
[0]) || !ValidSocket(dpskt
[1]) ||
478 !ValidSocket(dpskt
[2]) || !ValidSocket(dpskt
[3]))
480 if (ValidSocket(dpskt
[0]))
482 if (ValidSocket(dpskt
[1]))
484 if (ValidSocket(dpskt
[2]))
486 if (ValidSocket(dpskt
[3]))
490 BindDPSocket(dpskt
[0], AF_INET
);
491 BindDPSocket(dpskt
[1], AF_INET6
);
492 BindDPSocket(dpskt
[2], AF_INET
);
493 BindDPSocket(dpskt
[3], AF_INET6
);
495 LogInfo("mDNSPlatformInitDNSProxySkts: Opened Listener Sockets for DNS Proxy : %d, %d, %d, %d",
496 dpskt
[0], dpskt
[1], dpskt
[2], dpskt
[3]);
498 m
->p
->UDPProxyCallback
= UDPCallback
;
499 m
->p
->TCPProxyCallback
= TCPCallback
;
501 SetupDNSProxySkts(m
, dpskt
);
504 mDNSexport
void mDNSPlatformCloseDNSProxySkts(mDNS
*const m
)
508 for (i
= 0; i
< 4; i
++)
509 close(dp_listener
[i
]);
510 LogInfo("mDNSPlatformCloseDNSProxySkts: Closing DNS Proxy Listener Sockets");
513 mDNSexport
void mDNSPlatformDisposeProxyContext(void *context
)
522 ti
= (ProxyTCPInfo_t
*)context
;
528 shutdown(kq
->sktv4
, 2);
529 mDNSPlatformCloseFD(&kq
->kqsv4
, kq
->sktv4
);
533 shutdown(kq
->sktv6
, 2);
534 mDNSPlatformCloseFD(&kq
->kqsv6
, kq
->sktv6
);
540 freeL("ProxyTCPInfoLen", ti
->reply
);
541 freeL("ProxyTCPContext", ti
);