2 * Copyright (c) 2011-2019 Apple Inc. All rights reserved.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "mDNSEmbeddedAPI.h"
18 #include "mDNSMacOSX.h"
20 #include <sys/types.h>
22 #include <sys/event.h>
23 #include <netinet/tcp.h>
25 extern mDNS mDNSStorage
;
27 #define ValidSocket(s) ((s) >= 0)
29 // Global to store the 4 DNS Proxy Listeners (UDPv4/6, TCPv4/6)
30 static int dp_listener
[4];
32 #define NUM_PROXY_TCP_CONNS 100
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
)
50 if (tcpInfo
->nread
< 2) // First read the two-byte length preceeding the DNS message
52 mDNSu8
*lenptr
= (mDNSu8
*)&tcpInfo
->replyLen
;
53 n
= mDNSPlatformReadTCP(&tcpInfo
->sock
, lenptr
+ tcpInfo
->nread
, 2 - tcpInfo
->nread
, &closed
);
56 LogMsg("ProxyTCPRead: attempt to read message length failed");
61 if (tcpInfo
->nread
< 2)
63 LogMsg("ProxyTCPRead: nread %d, n %d", tcpInfo
->nread
, n
);
67 tcpInfo
->replyLen
= (mDNSu16
)((mDNSu16
)lenptr
[0] << 8 | lenptr
[1]);
68 if (tcpInfo
->replyLen
< sizeof(DNSMessageHeader
))
70 LogMsg("ProxyTCPRead: Message length too short (%d bytes)", tcpInfo
->replyLen
);
74 tcpInfo
->reply
= (DNSMessage
*) mallocL("ProxyTCPInfo", tcpInfo
->replyLen
);
77 LogMsg("ProxyTCPRead: Memory failure");
82 n
= mDNSPlatformReadTCP(&tcpInfo
->sock
, ((char *)tcpInfo
->reply
) + (tcpInfo
->nread
- 2), tcpInfo
->replyLen
- (tcpInfo
->nread
- 2), &closed
);
86 LogMsg("ProxyTCPRead: read failure n %d, closed %d", n
, closed
);
90 if ((tcpInfo
->nread
- 2) != tcpInfo
->replyLen
)
96 mDNSlocal
void ProxyTCPSocketCallBack(int s1
, short filter
, void *context
, __unused mDNSBool encounteredEOF
)
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
);
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 ti
->sock
.m
->p
->TCPProxyCallback(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
, __unused mDNSBool encounteredEOF
)
195 struct sockaddr_storage ss
;
196 socklen_t sslen
= sizeof(ss
);
198 TCPSocket
*listenSock
= (TCPSocket
*)context
;
202 while ((newfd
= accept(s1
, (struct sockaddr
*)&ss
, &sslen
)) != -1)
206 // Even though we just need a single KQueueEntry, for simplicity we re-use
208 ProxyTCPInfo_t
* const ti
= (ProxyTCPInfo_t
*)callocL("ProxyTCPContext", sizeof(*ti
));
211 LogMsg("ProxyTCPAccept: cannot allocate TCPSocket");
215 TCPSocket
* const sock
= &ti
->sock
;
217 sock
->m
= listenSock
->m
;
219 fcntl(newfd
, F_SETFL
, fcntl(newfd
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
220 if (ss
.ss_family
== AF_INET
)
222 // Receive interface identifiers
223 err
= setsockopt(newfd
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
226 LogMsg("ProxyTCPAccept: IP_RECVIF %d errno %d (%s)", newfd
, errno
, strerror(errno
));
227 mDNSPlatformDisposeProxyContext(ti
);
234 // We want to receive destination addresses and receive interface identifiers
235 err
= setsockopt(newfd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &on
, sizeof(on
));
238 LogMsg("ProxyTCPAccept: IP_RECVPKTINFO %d errno %d (%s)", newfd
, errno
, strerror(errno
));
239 mDNSPlatformDisposeProxyContext(ti
);
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.
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
;
256 sock
->connected
= mDNStrue
;
257 sock
->m
= listenSock
->m
;
258 KQueueSet(newfd
, EV_ADD
, EVFILT_READ
, &sock
->kqEntry
);
262 mDNSlocal mStatus
SetupUDPProxySocket(int skt
, KQSocketSet
*cp
, u_short sa_family
, mDNSBool useBackgroundTrafficClass
)
264 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
265 KQueueEntry
*k
= (sa_family
== AF_INET
) ? &cp
->kqsv4
: &cp
->kqsv6
;
267 mStatus err
= mStatus_NoError
;
269 cp
->m
= &mDNSStorage
;
270 cp
->closeFlag
= mDNSNULL
;
272 // set default traffic class
273 // setTrafficClass(skt, mDNSfalse);
274 (void) useBackgroundTrafficClass
;
276 if (sa_family
== AF_INET
)
278 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVDSTADDR
, &on
, sizeof(on
));
281 LogMsg("SetupUDPProxySocket: IP_RECVDSTADDR %d errno %d (%s)", skt
, errno
, strerror(errno
));
285 // We want to receive interface identifiers
286 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
289 LogMsg("SetupUDPProxySocket: IP_RECVIF %d errno %d (%s)", skt
, errno
, strerror(errno
));
293 else if (sa_family
== AF_INET6
)
295 // We want to receive destination addresses and receive interface identifiers
296 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &on
, sizeof(on
));
299 LogMsg("SetupUDPProxySocket: IPV6_RECVPKTINFO %d errno %d (%s)", skt
, errno
, strerror(errno
));
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
));
307 LogMsg("SetupUDPProxySocket: IPV6_RECVHOPLIMIT %d errno %d (%s)", skt
, errno
, strerror(errno
));
313 LogMsg("SetupUDPProxySocket: wrong family %d", sa_family
);
317 if (fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
) < 0)
319 LogMsg("SetupUDPProxySocket: fnctl failed %d", errno
);
324 //k->KQcallback = ProxyUDPSocketCallBack;
325 k
->KQcallback
= myKQSocketCallBack
;
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
;
334 KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
);
339 mDNSlocal mStatus
SetupTCPProxySocket(int skt
, TCPSocket
*sock
, u_short sa_family
, mDNSBool useBackgroundTrafficClass
)
342 mDNS
*m
= &mDNSStorage
;
344 // for TCP sockets, the traffic class is set once and not changed
345 // setTrafficClass(skt, useBackgroundTrafficClass);
346 (void) useBackgroundTrafficClass
;
349 // All the socket setup has already been done
350 err
= listen(skt
, NUM_PROXY_TCP_CONNS
);
353 LogMsg("SetupTCPProxySocket: listen %d errno %d (%s)", skt
, errno
, strerror(errno
));
356 fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
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
;
368 KQueueSet(skt
, EV_ADD
, EVFILT_READ
, &sock
->kqEntry
);
369 return mStatus_NoError
;
372 mDNSlocal
void BindDPSocket(int fd
, int sa_family
)
377 if (sa_family
== AF_INET
)
379 struct sockaddr_in addr
;
381 err
= setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
383 LogMsg("BindDPSocket: setsockopt SO_REUSEPORT failed for IPv4 %d errno %d (%s)", fd
, errno
, strerror(errno
));
385 memset(&addr
, 0, sizeof(addr
));
386 addr
.sin_family
= AF_INET
;
387 addr
.sin_port
= htons(53);
389 err
= bind(fd
, (struct sockaddr
*) &addr
, sizeof(addr
));
392 LogMsg("BindDPSocket: bind %d errno %d (%s)", fd
, errno
, strerror(errno
));
398 struct sockaddr_in6 addr6
;
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
));
405 LogMsg("DPFBindSocket: setsockopt IPV6_V6ONLY %d errno %d (%s)", fd
, errno
, strerror(errno
));
408 err
= setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
410 LogMsg("BindDPSocket: setsockopt SO_REUSEPORT failed for V6 %d errno %d (%s)", fd
, errno
, strerror(errno
));
412 memset(&addr6
, 0, sizeof(addr6
));
413 addr6
.sin6_family
= AF_INET6
;
414 addr6
.sin6_port
= htons(53);
416 err
= bind(fd
, (struct sockaddr
*) &addr6
, sizeof(addr6
));
419 LogMsg("BindDPSocket: bind6 %d errno %d (%s)", fd
, errno
, strerror(errno
));
425 // Setup DNS Proxy Skts in main kevent loop and set the skt options
426 mDNSlocal
void SetupDNSProxySkts(int fd
[4])
428 mDNS
*const m
= &mDNSStorage
;
434 udpSS
= &m
->p
->UDPProxy
.ss
;
435 udpSS
->port
= UnicastDNSPort
;
436 v4
= &m
->p
->TCPProxyV4
;
437 v6
= &m
->p
->TCPProxyV6
;
439 v4
->port
= UnicastDNSPort
;
441 v6
->port
= UnicastDNSPort
;
443 LogMsg("SetupDNSProxySkts: %d, %d, %d, %d", fd
[0], fd
[1], fd
[2], fd
[3]);
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
);
449 LogMsg("SetupDNSProxySkts: ERROR!! UDPv4 Socket");
451 err
= SetupUDPProxySocket(fd
[1], udpSS
, AF_INET6
, mDNSfalse
);
453 LogMsg("SetupDNSProxySkts: ERROR!! UDPv6 Socket");
455 err
= SetupTCPProxySocket(fd
[2], v4
, AF_INET
, mDNSfalse
);
457 LogMsg("SetupDNSProxySkts: ERROR!! TCPv4 Socket");
459 err
= SetupTCPProxySocket(fd
[3], v6
, AF_INET6
, mDNSfalse
);
461 LogMsg("SetupDNSProxySkts: ERROR!! TCPv6 Socket");
463 for (i
= 0; i
< 4; i
++)
464 dp_listener
[i
] = fd
[i
];
467 // Create and bind the DNS Proxy Skts for use
468 mDNSexport
void mDNSPlatformInitDNSProxySkts(ProxyCallback UDPCallback
, ProxyCallback TCPCallback
)
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
);
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]))
481 if (ValidSocket(dpskt
[0]))
483 if (ValidSocket(dpskt
[1]))
485 if (ValidSocket(dpskt
[2]))
487 if (ValidSocket(dpskt
[3]))
491 BindDPSocket(dpskt
[0], AF_INET
);
492 BindDPSocket(dpskt
[1], AF_INET6
);
493 BindDPSocket(dpskt
[2], AF_INET
);
494 BindDPSocket(dpskt
[3], AF_INET6
);
496 LogInfo("mDNSPlatformInitDNSProxySkts: Opened Listener Sockets for DNS Proxy : %d, %d, %d, %d",
497 dpskt
[0], dpskt
[1], dpskt
[2], dpskt
[3]);
499 mDNSStorage
.p
->UDPProxyCallback
= UDPCallback
;
500 mDNSStorage
.p
->TCPProxyCallback
= TCPCallback
;
502 SetupDNSProxySkts(dpskt
);
505 mDNSexport
void mDNSPlatformCloseDNSProxySkts(mDNS
*const m
)
509 for (i
= 0; i
< 4; i
++)
510 close(dp_listener
[i
]);
511 LogInfo("mDNSPlatformCloseDNSProxySkts: Closing DNS Proxy Listener Sockets");
514 mDNSexport
void mDNSPlatformDisposeProxyContext(void *context
)
522 ti
= (ProxyTCPInfo_t
*)context
;
527 mDNSPlatformCloseFD(&sock
->kqEntry
, sock
->fd
);
532 freeL("ProxyTCPInfoLen", ti
->reply
);
533 freeL("ProxyTCPContext", ti
);
539 // c-file-style: "bsd"
542 // indent-tabs-mode: nil