1 /* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
2 *
3 * Copyright (c) 2002-2019 Apple Inc. All rights reserved.
4 *
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
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
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.
16 *
17 */
18
19 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
20 #include "DNSCommon.h"
21 #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
22 #include "PlatformCommon.h"
23 #include "dns_sd.h"
24
25 #include <assert.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <syslog.h>
32 #include <stdarg.h>
33 #include <fcntl.h>
34 #include <sys/types.h>
35 #include <sys/time.h>
36 #include <sys/socket.h>
37 #include <sys/uio.h>
38 #include <sys/select.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41 #include <time.h> // platform support for UTC time
42 #include <ifaddrs.h>
43
44 #if USES_NETLINK
45 #include <asm/types.h>
46 #include <linux/netlink.h>
47 #include <linux/rtnetlink.h>
48 #else // USES_NETLINK
49 #include <net/route.h>
50 #include <net/if.h>
51 #endif // USES_NETLINK
52
53 #include "mDNSUNP.h"
54 #include "GenLinkedList.h"
55 #include "dnsproxy.h"
56
57 // ***************************************************************************
58 // Structures
59
60 // Context record for interface change callback
61 struct IfChangeRec
62 {
63 int NotifySD;
64 mDNS *mDNS;
65 };
66 typedef struct IfChangeRec IfChangeRec;
67
68 // Note that static data is initialized to zero in (modern) C.
69 static PosixEventSource *gEventSources; // linked list of PosixEventSource's
70 static sigset_t gEventSignalSet; // Signals which event loop listens for
71 static sigset_t gEventSignals; // Signals which were received while inside loop
72
73 static PosixNetworkInterface *gRecentInterfaces;
74
75 // ***************************************************************************
76 // Globals (for debugging)
77
78 static int num_registered_interfaces = 0;
79 static int num_pkts_accepted = 0;
80 static int num_pkts_rejected = 0;
81
82 // ***************************************************************************
83 // Locals
84 mDNSlocal void requestReadEvents(PosixEventSource *eventSource,
85 const char *taskName, mDNSPosixEventCallback callback, void *context);
86 mDNSlocal mStatus stopReadOrWriteEvents(int fd, mDNSBool freeSource, mDNSBool removeSource, int flags);
87 mDNSlocal void requestWriteEvents(PosixEventSource *eventSource,
88 const char *taskName, mDNSPosixEventCallback callback, void *context);
89 // ***************************************************************************
90 // Functions
91
92 #if MDNS_MALLOC_DEBUGGING
mDNSPlatformValidateLists(void)93 mDNSexport void mDNSPlatformValidateLists(void)
94 {
95 // This should validate gEventSources and any other Posix-specific stuff that gets allocated.
96 }
97 #endif
98
99 int gMDNSPlatformPosixVerboseLevel = 0;
100
101 #define PosixErrorToStatus(errNum) ((errNum) == 0 ? mStatus_NoError : mStatus_UnknownErr)
102
SockAddrTomDNSAddr(const struct sockaddr * const sa,mDNSAddr * ipAddr,mDNSIPPort * ipPort)103 mDNSlocal void SockAddrTomDNSAddr(const struct sockaddr *const sa, mDNSAddr *ipAddr, mDNSIPPort *ipPort)
104 {
105 switch (sa->sa_family)
106 {
107 case AF_INET:
108 {
109 struct sockaddr_in *sin = (struct sockaddr_in*)sa;
110 ipAddr->type = mDNSAddrType_IPv4;
111 ipAddr->ip.v4.NotAnInteger = sin->sin_addr.s_addr;
112 if (ipPort) ipPort->NotAnInteger = sin->sin_port;
113 break;
114 }
115
116 #if HAVE_IPV6
117 case AF_INET6:
118 {
119 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa;
120 #ifndef NOT_HAVE_SA_LEN
121 assert(sin6->sin6_len == sizeof(*sin6));
122 #endif
123 ipAddr->type = mDNSAddrType_IPv6;
124 ipAddr->ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
125 if (ipPort) ipPort->NotAnInteger = sin6->sin6_port;
126 break;
127 }
128 #endif
129
130 default:
131 verbosedebugf("SockAddrTomDNSAddr: Uknown address family %d\n", sa->sa_family);
132 ipAddr->type = mDNSAddrType_None;
133 if (ipPort) ipPort->NotAnInteger = 0;
134 break;
135 }
136 }
137
138 #if COMPILER_LIKES_PRAGMA_MARK
139 #pragma mark ***** Send and Receive
140 #endif
141
142 // mDNS core calls this routine when it needs to send a packet.
mDNSPlatformSendUDP(const mDNS * const m,const void * const msg,const mDNSu8 * const end,mDNSInterfaceID InterfaceID,UDPSocket * src,const mDNSAddr * dst,mDNSIPPort dstPort,mDNSBool useBackgroundTrafficClass)143 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
144 mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,
145 mDNSIPPort dstPort, mDNSBool useBackgroundTrafficClass)
146 {
147 int err = 0;
148 struct sockaddr_storage to;
149 PosixNetworkInterface * thisIntf = (PosixNetworkInterface *)(InterfaceID);
150 int sendingsocket = -1;
151
152 (void)src; // Will need to use this parameter once we implement mDNSPlatformUDPSocket/mDNSPlatformUDPClose
153 (void) useBackgroundTrafficClass;
154
155 assert(m != NULL);
156 assert(msg != NULL);
157 assert(end != NULL);
158 assert((((char *) end) - ((char *) msg)) > 0);
159
160 if (dstPort.NotAnInteger == 0)
161 {
162 LogMsg("mDNSPlatformSendUDP: Invalid argument -dstPort is set to 0");
163 return PosixErrorToStatus(EINVAL);
164 }
165 if (dst->type == mDNSAddrType_IPv4)
166 {
167 struct sockaddr_in *sin = (struct sockaddr_in*)&to;
168 #ifndef NOT_HAVE_SA_LEN
169 sin->sin_len = sizeof(*sin);
170 #endif
171 sin->sin_family = AF_INET;
172 sin->sin_port = dstPort.NotAnInteger;
173 sin->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
174 sendingsocket = thisIntf ? thisIntf->multicastSocket4 : m->p->unicastSocket4;
175 }
176
177 #if HAVE_IPV6
178 else if (dst->type == mDNSAddrType_IPv6)
179 {
180 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&to;
181 mDNSPlatformMemZero(sin6, sizeof(*sin6));
182 #ifndef NOT_HAVE_SA_LEN
183 sin6->sin6_len = sizeof(*sin6);
184 #endif
185 sin6->sin6_family = AF_INET6;
186 sin6->sin6_port = dstPort.NotAnInteger;
187 sin6->sin6_addr = *(struct in6_addr*)&dst->ip.v6;
188 sendingsocket = thisIntf ? thisIntf->multicastSocket6 : m->p->unicastSocket6;
189 }
190 #endif
191
192 if (sendingsocket >= 0)
193 err = sendto(sendingsocket, msg, (char*)end - (char*)msg, 0, (struct sockaddr *)&to, GET_SA_LEN(to));
194
195 if (err > 0) err = 0;
196 else if (err < 0)
197 {
198 static int MessageCount = 0;
199 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
200 if (!mDNSAddressIsAllDNSLinkGroup(dst))
201 if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr);
202
203 if (MessageCount < 1000)
204 {
205 MessageCount++;
206 if (thisIntf)
207 LogMsg("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a on interface %#a/%s/%d",
208 errno, strerror(errno), dst, &thisIntf->coreIntf.ip, thisIntf->intfName, thisIntf->index);
209 else
210 LogMsg("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a", errno, strerror(errno), dst);
211 }
212 }
213
214 return PosixErrorToStatus(err);
215 }
216
TCPReadCallback(int fd,void * context)217 mDNSlocal void TCPReadCallback(int fd, void *context)
218 {
219 TCPSocket *sock = context;
220 (void)fd;
221
222 if (sock->flags & kTCPSocketFlags_UseTLS)
223 {
224 // implement
225 }
226 else
227 {
228 sock->callback(sock, sock->context, mDNSfalse, sock->err);
229 }
230 }
231
tcpConnectCallback(int fd,void * context)232 mDNSlocal void tcpConnectCallback(int fd, void *context)
233 {
234 TCPSocket *sock = context;
235 mDNSBool c = !sock->connected;
236 int result;
237 socklen_t len = sizeof result;
238
239 sock->connected = mDNStrue;
240
241 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &result, &len) < 0)
242 {
243 LogInfo("ERROR: TCPConnectCallback - unable to get connect error: socket %d: Error %d (%s)",
244 sock->events.fd, result, strerror(result));
245 sock->err = mStatus_ConnFailed;
246 }
247 else
248 {
249 if (result != 0)
250 {
251 sock->err = mStatus_ConnFailed;
252 if (result == EHOSTUNREACH || result == EADDRNOTAVAIL || result == ENETDOWN)
253 {
254 LogInfo("ERROR: TCPConnectCallback - connect failed: socket %d: Error %d (%s)",
255 sock->events.fd, result, strerror(result));
256 }
257 else
258 {
259 LogMsg("ERROR: TCPConnectCallback - connect failed: socket %d: Error %d (%s)",
260 sock->events.fd, result, strerror(result));
261 }
262 }
263 else
264 {
265 // The connection succeeded.
266 sock->connected = mDNStrue;
267 // Select for read events.
268 sock->events.fd = fd;
269 requestReadEvents(&sock->events, "mDNSPosix::tcpConnectCallback", TCPReadCallback, sock);
270 }
271 }
272
273 if (sock->callback)
274 {
275 sock->callback(sock, sock->context, c, sock->err);
276 // Here sock must be assumed to be invalid, in case the callback freed it.
277 return;
278 }
279 }
280
281 // This routine is called when the main loop detects that data is available on a socket.
SocketDataReady(mDNS * const m,PosixNetworkInterface * intf,int skt)282 mDNSlocal void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int skt)
283 {
284 mDNSAddr senderAddr, destAddr;
285 mDNSIPPort senderPort;
286 ssize_t packetLen;
287 DNSMessage packet;
288 struct my_in_pktinfo packetInfo;
289 struct sockaddr_storage from;
290 socklen_t fromLen;
291 int flags;
292 mDNSu8 ttl;
293 mDNSBool reject;
294 const mDNSInterfaceID InterfaceID = intf ? intf->coreIntf.InterfaceID : NULL;
295
296 assert(m != NULL);
297 assert(skt >= 0);
298
299 fromLen = sizeof(from);
300 flags = 0;
301 packetLen = recvfrom_flags(skt, &packet, sizeof(packet), &flags, (struct sockaddr *) &from, &fromLen, &packetInfo, &ttl);
302
303 if (packetLen >= 0)
304 {
305 SockAddrTomDNSAddr((struct sockaddr*)&from, &senderAddr, &senderPort);
306 SockAddrTomDNSAddr((struct sockaddr*)&packetInfo.ipi_addr, &destAddr, NULL);
307
308 // If we have broken IP_RECVDSTADDR functionality (so far
309 // I've only seen this on OpenBSD) then apply a hack to
310 // convince mDNS Core that this isn't a spoof packet.
311 // Basically what we do is check to see whether the
312 // packet arrived as a multicast and, if so, set its
313 // destAddr to the mDNS address.
314 //
315 // I must admit that I could just be doing something
316 // wrong on OpenBSD and hence triggering this problem
317 // but I'm at a loss as to how.
318 //
319 // If this platform doesn't have IP_PKTINFO or IP_RECVDSTADDR, then we have
320 // no way to tell the destination address or interface this packet arrived on,
321 // so all we can do is just assume it's a multicast
322
323 #if HAVE_BROKEN_RECVDSTADDR || (!defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR))
324 if ((destAddr.NotAnInteger == 0) && (flags & MSG_MCAST))
325 {
326 destAddr.type = senderAddr.type;
327 if (senderAddr.type == mDNSAddrType_IPv4) destAddr.ip.v4 = AllDNSLinkGroup_v4.ip.v4;
328 else if (senderAddr.type == mDNSAddrType_IPv6) destAddr.ip.v6 = AllDNSLinkGroup_v6.ip.v6;
329 }
330 #endif
331
332 // We only accept the packet if the interface on which it came
333 // in matches the interface associated with this socket.
334 // We do this match by name or by index, depending on which
335 // information is available. recvfrom_flags sets the name
336 // to "" if the name isn't available, or the index to -1
337 // if the index is available. This accomodates the various
338 // different capabilities of our target platforms.
339
340 reject = mDNSfalse;
341 if (!intf)
342 {
343 // Ignore multicasts accidentally delivered to our unicast receiving socket
344 if (mDNSAddrIsDNSMulticast(&destAddr)) packetLen = -1;
345 }
346 else
347 {
348 if (packetInfo.ipi_ifname[0] != 0) reject = (strcmp(packetInfo.ipi_ifname, intf->intfName) != 0);
349 else if (packetInfo.ipi_ifindex != -1) reject = (packetInfo.ipi_ifindex != intf->index);
350
351 if (reject)
352 {
353 verbosedebugf("SocketDataReady ignored a packet from %#a to %#a on interface %s/%d expecting %#a/%s/%d/%d",
354 &senderAddr, &destAddr, packetInfo.ipi_ifname, packetInfo.ipi_ifindex,
355 &intf->coreIntf.ip, intf->intfName, intf->index, skt);
356 packetLen = -1;
357 num_pkts_rejected++;
358 if (num_pkts_rejected > (num_pkts_accepted + 1) * (num_registered_interfaces + 1) * 2)
359 {
360 fprintf(stderr,
361 "*** WARNING: Received %d packets; Accepted %d packets; Rejected %d packets because of interface mismatch\n",
362 num_pkts_accepted + num_pkts_rejected, num_pkts_accepted, num_pkts_rejected);
363 num_pkts_accepted = 0;
364 num_pkts_rejected = 0;
365 }
366 }
367 else
368 {
369 verbosedebugf("SocketDataReady got a packet from %#a to %#a on interface %#a/%s/%d/%d",
370 &senderAddr, &destAddr, &intf->coreIntf.ip, intf->intfName, intf->index, skt);
371 num_pkts_accepted++;
372 }
373 }
374 }
375
376 if (packetLen >= 0)
377 mDNSCoreReceive(m, &packet, (mDNSu8 *)&packet + packetLen,
378 &senderAddr, senderPort, &destAddr, MulticastDNSPort, InterfaceID);
379 }
380
mDNSPlatformTCPSocket(TCPSocketFlags flags,mDNSAddr_Type addrType,mDNSIPPort * port,domainname * hostname,mDNSBool useBackgroundTrafficClass)381 mDNSexport TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSAddr_Type addrType, mDNSIPPort * port,
382 domainname *hostname, mDNSBool useBackgroundTrafficClass)
383 {
384 TCPSocket *sock;
385 int len = sizeof (TCPSocket);
386
387 (void)useBackgroundTrafficClass;
388
389 if (hostname)
390 {
391 len += sizeof (domainname);
392 }
393 sock = malloc(len);
394
395 if (sock == NULL)
396 {
397 LogMsg("mDNSPlatformTCPSocket: no memory for socket");
398 return NULL;
399 }
400 memset(sock, 0, sizeof *sock);
401
402 if (hostname)
403 {
404 sock->hostname = (domainname *)(sock + 1);
405 LogMsg("mDNSPlatformTCPSocket: hostname %##s", hostname->c);
406 AssignDomainName(sock->hostname, hostname);
407 }
408
409 sock->events.fd = -1;
410 if (!mDNSPosixTCPSocketSetup(&sock->events.fd, addrType, port, &sock->port))
411 {
412 if (sock->events.fd != -1) close(sock->events.fd);
413 free(sock);
414 return mDNSNULL;
415 }
416
417 // Set up the other fields in the structure.
418 sock->flags = flags;
419 sock->err = mStatus_NoError;
420 sock->setup = mDNSfalse;
421 sock->connected = mDNSfalse;
422 return sock;
423 }
424
mDNSPlatformTCPSocketSetCallback(TCPSocket * sock,TCPConnectionCallback callback,void * context)425 mDNSexport mStatus mDNSPlatformTCPSocketSetCallback(TCPSocket *sock, TCPConnectionCallback callback, void *context)
426 {
427 sock->callback = callback;
428 sock->context = context;
429 return mStatus_NoError;
430 }
431
mDNSPlatformTCPAccept(TCPSocketFlags flags,int fd)432 mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
433 {
434 TCPSocket *sock;
435
436 // XXX Add!
437 if (flags & kTCPSocketFlags_UseTLS)
438 {
439 return mDNSNULL; // not supported yet.
440 }
441
442 sock = (TCPSocket *) mDNSPlatformMemAllocateClear(sizeof *sock);
443 if (!sock)
444 {
445 return mDNSNULL;
446 }
447
448 sock->events.fd = fd;
449 sock->flags = flags;
450 sock->connected = mDNStrue;
451 return sock;
452 }
453
454
tcpListenCallback(int fd,void * context)455 mDNSlocal void tcpListenCallback(int fd, void *context)
456 {
457 TCPListener *listener = context;
458 TCPSocket *sock;
459
460 sock = mDNSPosixDoTCPListenCallback(fd, listener->addressType, listener->socketFlags,
461 listener->callback, listener->context);
462 if (sock != NULL)
463 {
464 requestReadEvents(&sock->events, "mDNSPosix::tcpListenCallback", TCPReadCallback, sock);
465 }
466 }
467
mDNSPlatformTCPListen(mDNSAddr_Type addrType,mDNSIPPort * port,mDNSAddr * addr,TCPSocketFlags socketFlags,mDNSBool reuseAddr,int queueLength,TCPAcceptedCallback callback,void * context)468 mDNSexport TCPListener *mDNSPlatformTCPListen(mDNSAddr_Type addrType, mDNSIPPort *port, mDNSAddr *addr,
469 TCPSocketFlags socketFlags, mDNSBool reuseAddr, int queueLength,
470 TCPAcceptedCallback callback, void *context)
471 {
472 TCPListener *ret;
473 int fd = -1;
474
475 if (!mDNSPosixTCPListen(&fd, addrType, port, addr, reuseAddr, queueLength))
476 {
477 if (fd != -1)
478 {
479 close(fd);
480 }
481 return mDNSNULL;
482 }
483
484 // Allocate a listener structure
485 ret = (TCPListener *) mDNSPlatformMemAllocateClear(sizeof *ret);
486 if (ret == NULL)
487 {
488 LogMsg("mDNSPlatformTCPListen: no memory for TCPListener struct.");
489 close(fd);
490 return mDNSNULL;
491 }
492 ret->events.fd = fd;
493 ret->callback = callback;
494 ret->context = context;
495 ret->addressType = addrType;
496 ret->socketFlags = socketFlags;
497
498 // When we get a connection, mDNSPosixListenCallback will be called, and it will invoke the
499 // callback we were passed.
500 requestReadEvents(&ret->events, "tcpListenCallback", tcpListenCallback, ret);
501 return ret;
502 }
503
mDNSPlatformTCPGetFD(TCPSocket * sock)504 mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
505 {
506 return sock->events.fd;
507 }
508
mDNSPlatformTCPConnect(TCPSocket * sock,const mDNSAddr * dst,mDNSOpaque16 dstport,mDNSInterfaceID InterfaceID,TCPConnectionCallback callback,void * context)509 mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport,
510 mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context)
511 {
512 int result;
513 union {
514 struct sockaddr sa;
515 struct sockaddr_in sin;
516 struct sockaddr_in6 sin6;
517 } addr;
518 socklen_t len;
519
520 sock->callback = callback;
521 sock->context = context;
522 sock->setup = mDNSfalse;
523 sock->connected = mDNSfalse;
524 sock->err = mStatus_NoError;
525
526 result = fcntl(sock->events.fd, F_GETFL, 0);
527 if (result < 0)
528 {
529 LogMsg("mDNSPlatformTCPConnect: F_GETFL failed: %s", strerror(errno));
530 return mStatus_UnknownErr;
531 }
532
533 result = fcntl(sock->events.fd, F_SETFL, result | O_NONBLOCK);
534 if (result < 0)
535 {
536 LogMsg("mDNSPlatformTCPConnect: F_SETFL failed: %s", strerror(errno));
537 return mStatus_UnknownErr;
538 }
539
540 // If we've been asked to bind to a single interface, do it. See comment in mDNSMacOSX.c for more info.
541 if (InterfaceID)
542 {
543 PosixNetworkInterface *iface = (PosixNetworkInterface *)InterfaceID;
544 #if defined(SO_BINDTODEVICE)
545 result = setsockopt(sock->events.fd,
546 SOL_SOCKET, SO_BINDTODEVICE, iface->intfName, strlen(iface->intfName));
547 if (result < 0)
548 {
549 LogMsg("mDNSPlatformTCPConnect: SO_BINDTODEVICE failed on %s: %s", iface->intfName, strerror(errno));
550 return mStatus_BadParamErr;
551 }
552 #else
553 if (dst->type == mDNSAddrType_IPv4)
554 {
555 #if defined(IP_BOUND_IF)
556 result = setsockopt(sock->events.fd, IPPROTO_IP, IP_BOUND_IF, &iface->index, sizeof iface->index);
557 if (result < 0)
558 {
559 LogMsg("mDNSPlatformTCPConnect: IP_BOUND_IF failed on %s (%d): %s",
560 iface->intfName, iface->index, strerror(errno));
561 return mStatus_BadParamErr;
562 }
563 #else
564 (void)iface;
565 #endif // IP_BOUND_IF
566 }
567 else
568 { // IPv6
569 #if defined(IPV6_BOUND_IF)
570 result = setsockopt(sock->events.fd, IPPROTO_IPV6, IPV6_BOUND_IF, &iface->index, sizeof iface->index);
571 if (result < 0)
572 {
573 LogMsg("mDNSPlatformTCPConnect: IP_BOUND_IF failed on %s (%d): %s",
574 iface->intfName, iface->index, strerror(errno));
575 return mStatus_BadParamErr;
576 }
577 #else
578 (void)iface;
579 #endif // IPV6_BOUND_IF
580 }
581 #endif // SO_BINDTODEVICE
582 }
583
584 memset(&addr, 0, sizeof addr);
585 if (dst->type == mDNSAddrType_IPv4)
586 {
587 addr.sa.sa_family = AF_INET;
588 addr.sin.sin_port = dstport.NotAnInteger;
589 len = sizeof (struct sockaddr_in);
590 addr.sin.sin_addr.s_addr = dst->ip.v4.NotAnInteger;
591 }
592 else
593 {
594 addr.sa.sa_family = AF_INET6;
595 len = sizeof (struct sockaddr_in6);
596 addr.sin6.sin6_port = dstport.NotAnInteger;
597 memcpy(&addr.sin6.sin6_addr.s6_addr, &dst->ip.v6, sizeof addr.sin6.sin6_addr.s6_addr);
598 }
599 #ifndef NOT_HAVE_SA_LEN
600 addr.sa.sa_len = len;
601 #endif
602
603 result = connect(sock->events.fd, (struct sockaddr *)&addr, len);
604 if (result < 0)
605 {
606 if (errno == EINPROGRESS)
607 {
608 requestWriteEvents(&sock->events, "mDNSPlatformConnect", tcpConnectCallback, sock);
609 return mStatus_ConnPending;
610 }
611 if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
612 {
613 LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)",
614 sock->events.fd, errno, strerror(errno));
615 }
616 else
617 {
618 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d",
619 sock->events.fd, errno, strerror(errno), len);
620 }
621 return mStatus_ConnFailed;
622 }
623
624 LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
625 return mStatus_NoError;
626 }
627
mDNSPlatformTCPCloseConnection(TCPSocket * sock)628 mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
629 {
630 if (sock)
631 { // can sock really be NULL when this is called?
632 shutdown(sock->events.fd, SHUT_RDWR);
633 stopReadOrWriteEvents(sock->events.fd, mDNSfalse, mDNStrue,
634 PosixEventFlag_Read | PosixEventFlag_Write);
635 close(sock->events.fd);
636 free(sock);
637 }
638 }
639
mDNSPlatformReadTCP(TCPSocket * sock,void * buf,unsigned long buflen,mDNSBool * closed)640 mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool * closed)
641 {
642 ssize_t nread;
643
644 *closed = mDNSfalse;
645 if (sock->flags & kTCPSocketFlags_UseTLS)
646 {
647 // Implement...
648 nread = -1;
649 *closed = mDNStrue;
650 } else {
651 nread = mDNSPosixReadTCP(sock->events.fd, buf, buflen, closed);
652 }
653 return nread;
654 }
655
mDNSPlatformTCPWritable(TCPSocket * sock)656 mDNSexport mDNSBool mDNSPlatformTCPWritable(TCPSocket *sock)
657 {
658 fd_set w;
659 int nfds = sock->events.fd + 1;
660 int count;
661 struct timeval tv;
662
663 if (nfds > FD_SETSIZE)
664 {
665 LogMsg("ERROR: mDNSPlatformTCPWritable called on an fd that won't fit in an fd_set.");
666 return mDNStrue; // hope for the best?
667 }
668 FD_SET(sock->events.fd, &w);
669 tv.tv_sec = tv.tv_usec = 0;
670 count = select(nfds, NULL, &w, NULL, &tv);
671 if (count > 0)
672 {
673 return mDNStrue;
674 }
675 return mDNSfalse;
676 }
677
mDNSPlatformWriteTCP(TCPSocket * sock,const char * msg,unsigned long len)678 mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
679 {
680 if (sock->flags & kTCPSocketFlags_UseTLS)
681 {
682 // implement
683 return -1;
684 }
685 else
686 {
687 return mDNSPosixWriteTCP(sock->events.fd, msg, len);
688 }
689 }
690
mDNSPlatformUDPSocket(mDNSIPPort port)691 mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNSIPPort port)
692 {
693 (void)port; // Unused
694 return NULL;
695 }
696
mDNSPlatformUDPClose(UDPSocket * sock)697 mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
698 {
699 (void)sock; // Unused
700 }
701
mDNSPlatformUpdateProxyList(const mDNSInterfaceID InterfaceID)702 mDNSexport void mDNSPlatformUpdateProxyList(const mDNSInterfaceID InterfaceID)
703 {
704 (void)InterfaceID; // Unused
705 }
706
mDNSPlatformSendRawPacket(const void * const msg,const mDNSu8 * const end,mDNSInterfaceID InterfaceID)707 mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
708 {
709 (void)msg; // Unused
710 (void)end; // Unused
711 (void)InterfaceID; // Unused
712 }
713
mDNSPlatformSetLocalAddressCacheEntry(const mDNSAddr * const tpa,const mDNSEthAddr * const tha,mDNSInterfaceID InterfaceID)714 mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
715 {
716 (void)tpa; // Unused
717 (void)tha; // Unused
718 (void)InterfaceID; // Unused
719 }
720
mDNSPlatformTLSSetupCerts(void)721 mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
722 {
723 return(mStatus_UnsupportedErr);
724 }
725
mDNSPlatformTLSTearDownCerts(void)726 mDNSexport void mDNSPlatformTLSTearDownCerts(void)
727 {
728 }
729
mDNSPlatformSetAllowSleep(mDNSBool allowSleep,const char * reason)730 mDNSexport void mDNSPlatformSetAllowSleep(mDNSBool allowSleep, const char *reason)
731 {
732 (void) allowSleep;
733 (void) reason;
734 }
735
736 #if COMPILER_LIKES_PRAGMA_MARK
737 #pragma mark -
738 #pragma mark - /etc/hosts support
739 #endif
740
FreeEtcHosts(mDNS * const m,AuthRecord * const rr,mStatus result)741 mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result)
742 {
743 (void)m; // unused
744 (void)rr;
745 (void)result;
746 }
747
748
749 #if COMPILER_LIKES_PRAGMA_MARK
750 #pragma mark ***** DDNS Config Platform Functions
751 #endif
752
mDNSPlatformSetDNSConfig(mDNSBool setservers,mDNSBool setsearch,domainname * const fqdn,DNameListElem ** RegDomains,DNameListElem ** BrowseDomains,mDNSBool ackConfig)753 mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains,
754 DNameListElem **BrowseDomains, mDNSBool ackConfig)
755 {
756 (void) setservers;
757 (void) setsearch;
758 (void) ackConfig;
759
760 if (fqdn ) fqdn->c[0] = 0;
761 if (RegDomains ) *RegDomains = NULL;
762 if (BrowseDomains) *BrowseDomains = NULL;
763
764 return mDNStrue;
765 }
766
mDNSPlatformGetPrimaryInterface(mDNSAddr * v4,mDNSAddr * v6,mDNSAddr * router)767 mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNSAddr * v4, mDNSAddr * v6, mDNSAddr * router)
768 {
769 (void) v4;
770 (void) v6;
771 (void) router;
772
773 return mStatus_UnsupportedErr;
774 }
775
mDNSPlatformDynDNSHostNameStatusChanged(const domainname * const dname,const mStatus status)776 mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
777 {
778 (void) dname;
779 (void) status;
780 }
781
782 #if COMPILER_LIKES_PRAGMA_MARK
783 #pragma mark ***** Init and Term
784 #endif
785
786 // This gets the current hostname, truncating it at the first dot if necessary
GetUserSpecifiedRFC1034ComputerName(domainlabel * const namelabel)787 mDNSlocal void GetUserSpecifiedRFC1034ComputerName(domainlabel *const namelabel)
788 {
789 int len = 0;
790 gethostname((char *)(&namelabel->c[1]), MAX_DOMAIN_LABEL);
791 while (len < MAX_DOMAIN_LABEL && namelabel->c[len+1] && namelabel->c[len+1] != '.') len++;
792 namelabel->c[0] = len;
793 }
794
795 // On OS X this gets the text of the field labelled "Computer Name" in the Sharing Prefs Control Panel
796 // Other platforms can either get the information from the appropriate place,
797 // or they can alternatively just require all registering services to provide an explicit name
GetUserSpecifiedFriendlyComputerName(domainlabel * const namelabel)798 mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
799 {
800 // On Unix we have no better name than the host name, so we just use that.
801 GetUserSpecifiedRFC1034ComputerName(namelabel);
802 }
803
ParseDNSServers(mDNS * m,const char * filePath)804 mDNSexport int ParseDNSServers(mDNS *m, const char *filePath)
805 {
806 char line[256];
807 char nameserver[16];
808 char keyword[11];
809 int numOfServers = 0;
810 FILE *fp = fopen(filePath, "r");
811 if (fp == NULL) return -1;
812 while (fgets(line,sizeof(line),fp))
813 {
814 struct in_addr ina;
815 line[255]='\0'; // just to be safe
816 if (sscanf(line,"%10s %15s", keyword, nameserver) != 2) continue; // it will skip whitespaces
817 if (strncasecmp(keyword,"nameserver",10)) continue;
818 if (inet_aton(nameserver, (struct in_addr *)&ina) != 0)
819 {
820 mDNSAddr DNSAddr;
821 DNSAddr.type = mDNSAddrType_IPv4;
822 DNSAddr.ip.v4.NotAnInteger = ina.s_addr;
823 mDNS_AddDNSServer(m, NULL, mDNSInterface_Any, 0, &DNSAddr, UnicastDNSPort, kScopeNone, 0, mDNSfalse, mDNSfalse, mDNSfalse, mDNSfalse, 0, mDNStrue, mDNStrue, mDNSfalse);
824 numOfServers++;
825 }
826 }
827 fclose(fp);
828 return (numOfServers > 0) ? 0 : -1;
829 }
830
831 // Searches the interface list looking for the named interface.
832 // Returns a pointer to if it found, or NULL otherwise.
SearchForInterfaceByName(mDNS * const m,const char * intfName)833 mDNSlocal PosixNetworkInterface *SearchForInterfaceByName(mDNS *const m, const char *intfName)
834 {
835 PosixNetworkInterface *intf;
836
837 assert(m != NULL);
838 assert(intfName != NULL);
839
840 intf = (PosixNetworkInterface*)(m->HostInterfaces);
841 while ((intf != NULL) && (strcmp(intf->intfName, intfName) != 0))
842 intf = (PosixNetworkInterface *)(intf->coreIntf.next);
843
844 return intf;
845 }
846
mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS * const m,mDNSu32 index)847 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 index)
848 {
849 PosixNetworkInterface *intf;
850
851 assert(m != NULL);
852
853 if (index == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
854 if (index == kDNSServiceInterfaceIndexP2P ) return(mDNSInterface_P2P);
855 if (index == kDNSServiceInterfaceIndexAny ) return(mDNSInterface_Any);
856
857 intf = (PosixNetworkInterface*)(m->HostInterfaces);
858 while ((intf != NULL) && (mDNSu32) intf->index != index)
859 intf = (PosixNetworkInterface *)(intf->coreIntf.next);
860
861 return (mDNSInterfaceID) intf;
862 }
863
mDNSPlatformInterfaceIndexfromInterfaceID(mDNS * const m,mDNSInterfaceID id,mDNSBool suppressNetworkChange)864 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id, mDNSBool suppressNetworkChange)
865 {
866 PosixNetworkInterface *intf;
867 (void) suppressNetworkChange; // Unused
868
869 assert(m != NULL);
870
871 if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
872 if (id == mDNSInterface_P2P ) return(kDNSServiceInterfaceIndexP2P);
873 if (id == mDNSInterface_Any ) return(kDNSServiceInterfaceIndexAny);
874
875 intf = (PosixNetworkInterface*)(m->HostInterfaces);
876 while ((intf != NULL) && (mDNSInterfaceID) intf != id)
877 intf = (PosixNetworkInterface *)(intf->coreIntf.next);
878
879 if (intf) return intf->index;
880
881 // If we didn't find the interface, check the RecentInterfaces list as well
882 intf = gRecentInterfaces;
883 while ((intf != NULL) && (mDNSInterfaceID) intf != id)
884 intf = (PosixNetworkInterface *)(intf->coreIntf.next);
885
886 return intf ? intf->index : 0;
887 }
888
889 // Frees the specified PosixNetworkInterface structure. The underlying
890 // interface must have already been deregistered with the mDNS core.
FreePosixNetworkInterface(PosixNetworkInterface * intf)891 mDNSlocal void FreePosixNetworkInterface(PosixNetworkInterface *intf)
892 {
893 int rv;
894 assert(intf != NULL);
895 if (intf->intfName != NULL) free((void *)intf->intfName);
896 if (intf->multicastSocket4 != -1)
897 {
898 rv = close(intf->multicastSocket4);
899 assert(rv == 0);
900 }
901 #if HAVE_IPV6
902 if (intf->multicastSocket6 != -1)
903 {
904 rv = close(intf->multicastSocket6);
905 assert(rv == 0);
906 }
907 #endif
908
909 // Move interface to the RecentInterfaces list for a minute
910 intf->LastSeen = mDNSPlatformUTC();
911 intf->coreIntf.next = &gRecentInterfaces->coreIntf;
912 gRecentInterfaces = intf;
913 }
914
915 // Grab the first interface, deregister it, free it, and repeat until done.
ClearInterfaceList(mDNS * const m)916 mDNSlocal void ClearInterfaceList(mDNS *const m)
917 {
918 assert(m != NULL);
919
920 while (m->HostInterfaces)
921 {
922 PosixNetworkInterface *intf = (PosixNetworkInterface*)(m->HostInterfaces);
923 mDNS_DeregisterInterface(m, &intf->coreIntf, NormalActivation);
924 if (gMDNSPlatformPosixVerboseLevel > 0) fprintf(stderr, "Deregistered interface %s\n", intf->intfName);
925 FreePosixNetworkInterface(intf);
926 }
927 num_registered_interfaces = 0;
928 num_pkts_accepted = 0;
929 num_pkts_rejected = 0;
930 }
931
932 // Sets up a send/receive socket.
933 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
934 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
SetupSocket(struct sockaddr * intfAddr,mDNSIPPort port,int interfaceIndex,int * sktPtr)935 mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interfaceIndex, int *sktPtr)
936 {
937 int err = 0;
938 static const int kOn = 1;
939 static const int kIntTwoFiveFive = 255;
940 static const unsigned char kByteTwoFiveFive = 255;
941 const mDNSBool JoinMulticastGroup = (port.NotAnInteger != 0);
942
943 (void) interfaceIndex; // This parameter unused on plaforms that don't have IPv6
944 assert(intfAddr != NULL);
945 assert(sktPtr != NULL);
946 assert(*sktPtr == -1);
947
948 // Open the socket...
949 if (intfAddr->sa_family == AF_INET) *sktPtr = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
950 #if HAVE_IPV6
951 else if (intfAddr->sa_family == AF_INET6) *sktPtr = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
952 #endif
953 else return EINVAL;
954
955 if (*sktPtr < 0) { err = errno; perror((intfAddr->sa_family == AF_INET) ? "socket AF_INET" : "socket AF_INET6"); }
956
957 // ... with a shared UDP port, if it's for multicast receiving
958 if (err == 0 && port.NotAnInteger)
959 {
960 // <rdar://problem/20946253> Suggestions from Jonny Törnbom at Axis Communications
961 // We test for SO_REUSEADDR first, as suggested by Jonny Törnbom from Axis Communications
962 // Linux kernel versions 3.9 introduces support for socket option
963 // SO_REUSEPORT, however this is not implemented the same as on *BSD
964 // systems. Linux version implements a "port hijacking" prevention
965 // mechanism, limiting processes wanting to bind to an already existing
966 // addr:port to have the same effective UID as the first who bound it. What
967 // this meant for us was that the daemon ran as one user and when for
968 // instance mDNSClientPosix was executed by another user, it wasn't allowed
969 // to bind to the socket. Our suggestion was to switch the order in which
970 // SO_REUSEPORT and SO_REUSEADDR was tested so that SO_REUSEADDR stays on
971 // top and SO_REUSEPORT to be used only if SO_REUSEADDR doesn't exist.
972 #if defined(SO_REUSEADDR) && !defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && !defined(__FreeBSD__)
973 err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
974 #elif defined(SO_REUSEPORT)
975 err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEPORT, &kOn, sizeof(kOn));
976 #else
977 #error This platform has no way to avoid address busy errors on multicast.
978 #endif
979 if (err < 0) { err = errno; perror("setsockopt - SO_REUSExxxx"); }
980
981 #if TARGET_OS_MAC
982 // Enable inbound packets on IFEF_AWDL interface.
983 // Only done for multicast sockets, since we don't expect unicast socket operations
984 // on the IFEF_AWDL interface. Operation is a no-op for other interface types.
985 #ifndef SO_RECV_ANYIF
986 #define SO_RECV_ANYIF 0x1104 /* unrestricted inbound processing */
987 #endif
988 if (setsockopt(*sktPtr, SOL_SOCKET, SO_RECV_ANYIF, &kOn, sizeof(kOn)) < 0) perror("setsockopt - SO_RECV_ANYIF");
989 #endif
990 }
991
992 // We want to receive destination addresses and interface identifiers.
993 if (intfAddr->sa_family == AF_INET)
994 {
995 struct ip_mreq imr;
996 struct sockaddr_in bindAddr;
997 if (err == 0)
998 {
999 #if defined(IP_PKTINFO) // Linux
1000 err = setsockopt(*sktPtr, IPPROTO_IP, IP_PKTINFO, &kOn, sizeof(kOn));
1001 if (err < 0) { err = errno; perror("setsockopt - IP_PKTINFO"); }
1002 #elif defined(IP_RECVDSTADDR) || defined(IP_RECVIF) // BSD and Solaris
1003 #if defined(IP_RECVDSTADDR)
1004 err = setsockopt(*sktPtr, IPPROTO_IP, IP_RECVDSTADDR, &kOn, sizeof(kOn));
1005 if (err < 0) { err = errno; perror("setsockopt - IP_RECVDSTADDR"); }
1006 #endif
1007 #if defined(IP_RECVIF)
1008 if (err == 0)
1009 {
1010 err = setsockopt(*sktPtr, IPPROTO_IP, IP_RECVIF, &kOn, sizeof(kOn));
1011 if (err < 0) { err = errno; perror("setsockopt - IP_RECVIF"); }
1012 }
1013 #endif
1014 #else
1015 #warning This platform has no way to get the destination interface information -- will only work for single-homed hosts
1016 #endif
1017 }
1018 #if defined(IP_RECVTTL) // Linux
1019 if (err == 0)
1020 {
1021 setsockopt(*sktPtr, IPPROTO_IP, IP_RECVTTL, &kOn, sizeof(kOn));
1022 // We no longer depend on being able to get the received TTL, so don't worry if the option fails
1023 }
1024 #endif
1025
1026 // Add multicast group membership on this interface
1027 if (err == 0 && JoinMulticastGroup)
1028 {
1029 imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
1030 imr.imr_interface = ((struct sockaddr_in*)intfAddr)->sin_addr;
1031 err = setsockopt(*sktPtr, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
1032 if (err < 0) { err = errno; perror("setsockopt - IP_ADD_MEMBERSHIP"); }
1033 }
1034
1035 // Specify outgoing interface too
1036 if (err == 0 && JoinMulticastGroup)
1037 {
1038 err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_IF, &((struct sockaddr_in*)intfAddr)->sin_addr, sizeof(struct in_addr));
1039 if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_IF"); }
1040 }
1041
1042 // Per the mDNS spec, send unicast packets with TTL 255
1043 if (err == 0)
1044 {
1045 err = setsockopt(*sktPtr, IPPROTO_IP, IP_TTL, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
1046 if (err < 0) { err = errno; perror("setsockopt - IP_TTL"); }
1047 }
1048
1049 // and multicast packets with TTL 255 too
1050 // There's some debate as to whether IP_MULTICAST_TTL is an int or a byte so we just try both.
1051 if (err == 0)
1052 {
1053 err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_TTL, &kByteTwoFiveFive, sizeof(kByteTwoFiveFive));
1054 if (err < 0 && errno == EINVAL)
1055 err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_TTL, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
1056 if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_TTL"); }
1057 }
1058
1059 // And start listening for packets
1060 if (err == 0)
1061 {
1062 bindAddr.sin_family = AF_INET;
1063 bindAddr.sin_port = port.NotAnInteger;
1064 bindAddr.sin_addr.s_addr = INADDR_ANY; // Want to receive multicasts AND unicasts on this socket
1065 err = bind(*sktPtr, (struct sockaddr *) &bindAddr, sizeof(bindAddr));
1066 if (err < 0) { err = errno; perror("bind"); fflush(stderr); }
1067 }
1068 } // endif (intfAddr->sa_family == AF_INET)
1069
1070 #if HAVE_IPV6
1071 else if (intfAddr->sa_family == AF_INET6)
1072 {
1073 struct ipv6_mreq imr6;
1074 struct sockaddr_in6 bindAddr6;
1075 #if defined(IPV6_RECVPKTINFO)
1076 if (err == 0)
1077 {
1078 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_RECVPKTINFO, &kOn, sizeof(kOn));
1079 if (err < 0) { err = errno; perror("setsockopt - IPV6_RECVPKTINFO"); }
1080 }
1081 #elif defined(IPV6_PKTINFO)
1082 if (err == 0)
1083 {
1084 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_2292_PKTINFO, &kOn, sizeof(kOn));
1085 if (err < 0) { err = errno; perror("setsockopt - IPV6_PKTINFO"); }
1086 }
1087 #else
1088 #warning This platform has no way to get the destination interface information for IPv6 -- will only work for single-homed hosts
1089 #endif
1090 #if defined(IPV6_RECVHOPLIMIT)
1091 if (err == 0)
1092 {
1093 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &kOn, sizeof(kOn));
1094 if (err < 0) { err = errno; perror("setsockopt - IPV6_RECVHOPLIMIT"); }
1095 }
1096 #elif defined(IPV6_HOPLIMIT)
1097 if (err == 0)
1098 {
1099 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_2292_HOPLIMIT, &kOn, sizeof(kOn));
1100 if (err < 0) { err = errno; perror("setsockopt - IPV6_HOPLIMIT"); }
1101 }
1102 #endif
1103
1104 // Add multicast group membership on this interface
1105 if (err == 0 && JoinMulticastGroup)
1106 {
1107 imr6.ipv6mr_multiaddr = *(const struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
1108 imr6.ipv6mr_interface = interfaceIndex;
1109 //LogMsg("Joining %.16a on %d", &imr6.ipv6mr_multiaddr, imr6.ipv6mr_interface);
1110 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_JOIN_GROUP, &imr6, sizeof(imr6));
1111 if (err < 0)
1112 {
1113 err = errno;
1114 verbosedebugf("IPV6_JOIN_GROUP %.16a on %d failed.\n", &imr6.ipv6mr_multiaddr, imr6.ipv6mr_interface);
1115 perror("setsockopt - IPV6_JOIN_GROUP");
1116 }
1117 }
1118
1119 // Specify outgoing interface too
1120 if (err == 0 && JoinMulticastGroup)
1121 {
1122 u_int multicast_if = interfaceIndex;
1123 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_if, sizeof(multicast_if));
1124 if (err < 0) { err = errno; perror("setsockopt - IPV6_MULTICAST_IF"); }
1125 }
1126
1127 // We want to receive only IPv6 packets on this socket.
1128 // Without this option, we may get IPv4 addresses as mapped addresses.
1129 if (err == 0)
1130 {
1131 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_V6ONLY, &kOn, sizeof(kOn));
1132 if (err < 0) { err = errno; perror("setsockopt - IPV6_V6ONLY"); }
1133 }
1134
1135 // Per the mDNS spec, send unicast packets with TTL 255
1136 if (err == 0)
1137 {
1138 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
1139 if (err < 0) { err = errno; perror("setsockopt - IPV6_UNICAST_HOPS"); }
1140 }
1141
1142 // and multicast packets with TTL 255 too
1143 // There's some debate as to whether IPV6_MULTICAST_HOPS is an int or a byte so we just try both.
1144 if (err == 0)
1145 {
1146 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &kByteTwoFiveFive, sizeof(kByteTwoFiveFive));
1147 if (err < 0 && errno == EINVAL)
1148 err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
1149 if (err < 0) { err = errno; perror("setsockopt - IPV6_MULTICAST_HOPS"); }
1150 }
1151
1152 // And start listening for packets
1153 if (err == 0)
1154 {
1155 mDNSPlatformMemZero(&bindAddr6, sizeof(bindAddr6));
1156 #ifndef NOT_HAVE_SA_LEN
1157 bindAddr6.sin6_len = sizeof(bindAddr6);
1158 #endif
1159 bindAddr6.sin6_family = AF_INET6;
1160 bindAddr6.sin6_port = port.NotAnInteger;
1161 bindAddr6.sin6_flowinfo = 0;
1162 bindAddr6.sin6_addr = in6addr_any; // Want to receive multicasts AND unicasts on this socket
1163 bindAddr6.sin6_scope_id = 0;
1164 err = bind(*sktPtr, (struct sockaddr *) &bindAddr6, sizeof(bindAddr6));
1165 if (err < 0) { err = errno; perror("bind"); fflush(stderr); }
1166 }
1167 } // endif (intfAddr->sa_family == AF_INET6)
1168 #endif
1169
1170 // Set the socket to non-blocking.
1171 if (err == 0)
1172 {
1173 err = fcntl(*sktPtr, F_GETFL, 0);
1174 if (err < 0) err = errno;
1175 else
1176 {
1177 err = fcntl(*sktPtr, F_SETFL, err | O_NONBLOCK);
1178 if (err < 0) err = errno;
1179 }
1180 }
1181
1182 // Clean up
1183 if (err != 0 && *sktPtr != -1)
1184 {
1185 int rv;
1186 rv = close(*sktPtr);
1187 assert(rv == 0);
1188 *sktPtr = -1;
1189 }
1190 assert((err == 0) == (*sktPtr != -1));
1191 return err;
1192 }
1193
1194 // Creates a PosixNetworkInterface for the interface whose IP address is
1195 // intfAddr and whose name is intfName and registers it with mDNS core.
SetupOneInterface(mDNS * const m,struct sockaddr * intfAddr,struct sockaddr * intfMask,const char * intfName,int intfIndex)1196 mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct sockaddr *intfMask, const char *intfName, int intfIndex)
1197 {
1198 int err = 0;
1199 PosixNetworkInterface *intf;
1200 PosixNetworkInterface *alias = NULL;
1201
1202 assert(m != NULL);
1203 assert(intfAddr != NULL);
1204 assert(intfName != NULL);
1205 assert(intfMask != NULL);
1206
1207 // Allocate the interface structure itself.
1208 intf = (PosixNetworkInterface*)calloc(1, sizeof(*intf));
1209 if (intf == NULL) { assert(0); err = ENOMEM; }
1210
1211 // And make a copy of the intfName.
1212 if (err == 0)
1213 {
1214 #ifdef LINUX
1215 char *s;
1216 int len;
1217 s = strchr(intfName, ':');
1218 if (s != NULL)
1219 {
1220 len = (s - intfName) + 1;
1221 }
1222 else
1223 {
1224 len = strlen(intfName) + 1;
1225 }
1226 intf->intfName = malloc(len);
1227 if (intf->intfName == NULL) { assert(0); err = ENOMEM; }
1228 memcpy(intf->intfName, intfName, len - 1);
1229 intfName[len - 1] = 0;
1230 #else
1231 intf->intfName = strdup(intfName);
1232 if (intf->intfName == NULL) { assert(0); err = ENOMEM; }
1233 #endif
1234 }
1235
1236 if (err == 0)
1237 {
1238 // Set up the fields required by the mDNS core.
1239 SockAddrTomDNSAddr(intfAddr, &intf->coreIntf.ip, NULL);
1240 SockAddrTomDNSAddr(intfMask, &intf->coreIntf.mask, NULL);
1241
1242 //LogMsg("SetupOneInterface: %#a %#a", &intf->coreIntf.ip, &intf->coreIntf.mask);
1243 strncpy(intf->coreIntf.ifname, intfName, sizeof(intf->coreIntf.ifname));
1244 intf->coreIntf.ifname[sizeof(intf->coreIntf.ifname)-1] = 0;
1245
1246 intf->coreIntf.Advertise = m->AdvertiseLocalAddresses;
1247 intf->coreIntf.McastTxRx = mDNStrue;
1248
1249 // Set up the extra fields in PosixNetworkInterface.
1250 assert(intf->intfName != NULL); // intf->intfName already set up above
1251 intf->index = intfIndex;
1252 intf->multicastSocket4 = -1;
1253 #if HAVE_IPV6
1254 intf->multicastSocket6 = -1;
1255 #endif
1256 alias = SearchForInterfaceByName(m, intf->intfName);
1257 if (alias == NULL) alias = intf;
1258 intf->coreIntf.InterfaceID = (mDNSInterfaceID)alias;
1259
1260 if (alias != intf)
1261 debugf("SetupOneInterface: %s %#a is an alias of %#a", intfName, &intf->coreIntf.ip, &alias->coreIntf.ip);
1262 }
1263
1264 // Set up the multicast socket
1265 if (err == 0)
1266 {
1267 if (alias->multicastSocket4 == -1 && intfAddr->sa_family == AF_INET)
1268 err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket4);
1269 #if HAVE_IPV6
1270 else if (alias->multicastSocket6 == -1 && intfAddr->sa_family == AF_INET6)
1271 err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket6);
1272 #endif
1273 }
1274
1275 // If interface is a direct link, address record will be marked as kDNSRecordTypeKnownUnique
1276 // and skip the probe phase of the probe/announce packet sequence.
1277 intf->coreIntf.DirectLink = mDNSfalse;
1278 #ifdef DIRECTLINK_INTERFACE_NAME
1279 if (strcmp(intfName, STRINGIFY(DIRECTLINK_INTERFACE_NAME)) == 0)
1280 intf->coreIntf.DirectLink = mDNStrue;
1281 #endif
1282 intf->coreIntf.SupportsUnicastMDNSResponse = mDNStrue;
1283
1284 // The interface is all ready to go, let's register it with the mDNS core.
1285 if (err == 0)
1286 err = mDNS_RegisterInterface(m, &intf->coreIntf, NormalActivation);
1287
1288 // Clean up.
1289 if (err == 0)
1290 {
1291 num_registered_interfaces++;
1292 debugf("SetupOneInterface: %s %#a Registered", intf->intfName, &intf->coreIntf.ip);
1293 if (gMDNSPlatformPosixVerboseLevel > 0)
1294 fprintf(stderr, "Registered interface %s\n", intf->intfName);
1295 }
1296 else
1297 {
1298 // Use intfName instead of intf->intfName in the next line to avoid dereferencing NULL.
1299 debugf("SetupOneInterface: %s %#a failed to register %d", intfName, &intf->coreIntf.ip, err);
1300 if (intf) { FreePosixNetworkInterface(intf); intf = NULL; }
1301 }
1302
1303 assert((err == 0) == (intf != NULL));
1304
1305 return err;
1306 }
1307
1308 // Call get_ifi_info() to obtain a list of active interfaces and call SetupOneInterface() on each one.
SetupInterfaceList(mDNS * const m)1309 mDNSlocal int SetupInterfaceList(mDNS *const m)
1310 {
1311 mDNSBool foundav4 = mDNSfalse;
1312 int err = 0;
1313 struct ifaddrs *intfList;
1314 struct ifaddrs *firstLoopback = NULL;
1315 int firstLoopbackIndex = 0;
1316
1317 assert(m != NULL);
1318 debugf("SetupInterfaceList");
1319
1320 if (getifaddrs(&intfList) < 0)
1321 {
1322 err = errno;
1323 }
1324 if (intfList == NULL) err = ENOENT;
1325
1326 if (err == 0)
1327 {
1328 struct ifaddrs *i = intfList;
1329 while (i)
1330 {
1331 if ( i->ifa_addr != NULL &&
1332 ((i->ifa_addr->sa_family == AF_INET)
1333 #if HAVE_IPV6
1334 || (i->ifa_addr->sa_family == AF_INET6)
1335 #endif
1336 ) && (i->ifa_flags & IFF_UP) && !(i->ifa_flags & IFF_POINTOPOINT))
1337 {
1338 int ifIndex = if_nametoindex(i->ifa_name);
1339 if (ifIndex == 0)
1340 {
1341 continue;
1342 }
1343 if (i->ifa_flags & IFF_LOOPBACK)
1344 {
1345 if (firstLoopback == NULL)
1346 {
1347 firstLoopback = i;
1348 firstLoopbackIndex = ifIndex;
1349 }
1350 }
1351 else
1352 {
1353 if (SetupOneInterface(m, i->ifa_addr, i->ifa_netmask, i->ifa_name, ifIndex) == 0)
1354 {
1355 if (i->ifa_addr->sa_family == AF_INET)
1356 {
1357 foundav4 = mDNStrue;
1358 }
1359 }
1360 }
1361 }
1362 i = i->ifa_next;
1363 }
1364
1365 // If we found no normal interfaces but we did find a loopback interface, register the
1366 // loopback interface. This allows self-discovery if no interfaces are configured.
1367 // Temporary workaround: Multicast loopback on IPv6 interfaces appears not to work.
1368 // In the interim, we skip loopback interface only if we found at least one v4 interface to use
1369 // if ((m->HostInterfaces == NULL) && (firstLoopback != NULL))
1370 if (!foundav4 && firstLoopback)
1371 {
1372 (void)SetupOneInterface(m, firstLoopback->ifa_addr, firstLoopback->ifa_netmask, firstLoopback->ifa_name,
1373 firstLoopbackIndex);
1374 }
1375 }
1376
1377 // Clean up.
1378 if (intfList != NULL) freeifaddrs(intfList);
1379
1380 // Clean up any interfaces that have been hanging around on the RecentInterfaces list for more than a minute
1381 PosixNetworkInterface **ri = &gRecentInterfaces;
1382 const mDNSs32 utc = mDNSPlatformUTC();
1383 while (*ri)
1384 {
1385 PosixNetworkInterface *pi = *ri;
1386 if (utc - pi->LastSeen < 60) ri = (PosixNetworkInterface **)&pi->coreIntf.next;
1387 else { *ri = (PosixNetworkInterface *)pi->coreIntf.next; free(pi); }
1388 }
1389
1390 return err;
1391 }
1392
1393 #if USES_NETLINK
1394
1395 // See <http://www.faqs.org/rfcs/rfc3549.html> for a description of NetLink
1396
1397 // Open a socket that will receive interface change notifications
OpenIfNotifySocket(int * pFD)1398 mDNSlocal mStatus OpenIfNotifySocket(int *pFD)
1399 {
1400 mStatus err = mStatus_NoError;
1401 struct sockaddr_nl snl;
1402 int sock;
1403 int ret;
1404
1405 sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
1406 if (sock < 0)
1407 return errno;
1408
1409 // Configure read to be non-blocking because inbound msg size is not known in advance
1410 (void) fcntl(sock, F_SETFL, O_NONBLOCK);
1411
1412 /* Subscribe the socket to Link & IP addr notifications. */
1413 mDNSPlatformMemZero(&snl, sizeof snl);
1414 snl.nl_family = AF_NETLINK;
1415 snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
1416 ret = bind(sock, (struct sockaddr *) &snl, sizeof snl);
1417 if (0 == ret)
1418 *pFD = sock;
1419 else
1420 err = errno;
1421
1422 return err;
1423 }
1424
1425 #if MDNS_DEBUGMSGS
PrintNetLinkMsg(const struct nlmsghdr * pNLMsg)1426 mDNSlocal void PrintNetLinkMsg(const struct nlmsghdr *pNLMsg)
1427 {
1428 const char *kNLMsgTypes[] = { "", "NLMSG_NOOP", "NLMSG_ERROR", "NLMSG_DONE", "NLMSG_OVERRUN" };
1429 const char *kNLRtMsgTypes[] = { "RTM_NEWLINK", "RTM_DELLINK", "RTM_GETLINK", "RTM_NEWADDR", "RTM_DELADDR", "RTM_GETADDR" };
1430
1431 printf("nlmsghdr len=%d, type=%s, flags=0x%x\n", pNLMsg->nlmsg_len,
1432 pNLMsg->nlmsg_type < RTM_BASE ? kNLMsgTypes[pNLMsg->nlmsg_type] : kNLRtMsgTypes[pNLMsg->nlmsg_type - RTM_BASE],
1433 pNLMsg->nlmsg_flags);
1434
1435 if (RTM_NEWLINK <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETLINK)
1436 {
1437 struct ifinfomsg *pIfInfo = (struct ifinfomsg*) NLMSG_DATA(pNLMsg);
1438 printf("ifinfomsg family=%d, type=%d, index=%d, flags=0x%x, change=0x%x\n", pIfInfo->ifi_family,
1439 pIfInfo->ifi_type, pIfInfo->ifi_index, pIfInfo->ifi_flags, pIfInfo->ifi_change);
1440
1441 }
1442 else if (RTM_NEWADDR <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETADDR)
1443 {
1444 struct ifaddrmsg *pIfAddr = (struct ifaddrmsg*) NLMSG_DATA(pNLMsg);
1445 printf("ifaddrmsg family=%d, index=%d, flags=0x%x\n", pIfAddr->ifa_family,
1446 pIfAddr->ifa_index, pIfAddr->ifa_flags);
1447 }
1448 printf("\n");
1449 }
1450 #endif
1451
ProcessRoutingNotification(int sd)1452 mDNSlocal mDNSu32 ProcessRoutingNotification(int sd)
1453 // Read through the messages on sd and if any indicate that any interface records should
1454 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
1455 {
1456 ssize_t readCount;
1457 char buff[4096];
1458 struct nlmsghdr *pNLMsg = (struct nlmsghdr*) buff;
1459 mDNSu32 result = 0;
1460
1461 // The structure here is more complex than it really ought to be because,
1462 // unfortunately, there's no good way to size a buffer in advance large
1463 // enough to hold all pending data and so avoid message fragmentation.
1464 // (Note that FIONREAD is not supported on AF_NETLINK.)
1465
1466 readCount = read(sd, buff, sizeof buff);
1467 while (1)
1468 {
1469 // Make sure we've got an entire nlmsghdr in the buffer, and payload, too.
1470 // If not, discard already-processed messages in buffer and read more data.
1471 if (((char*) &pNLMsg[1] > (buff + readCount)) || // i.e. *pNLMsg extends off end of buffer
1472 ((char*) pNLMsg + pNLMsg->nlmsg_len > (buff + readCount)))
1473 {
1474 if (buff < (char*) pNLMsg) // we have space to shuffle
1475 {
1476 // discard processed data
1477 readCount -= ((char*) pNLMsg - buff);
1478 memmove(buff, pNLMsg, readCount);
1479 pNLMsg = (struct nlmsghdr*) buff;
1480
1481 // read more data
1482 readCount += read(sd, buff + readCount, sizeof buff - readCount);
1483 continue; // spin around and revalidate with new readCount
1484 }
1485 else
1486 break; // Otherwise message does not fit in buffer
1487 }
1488
1489 #if MDNS_DEBUGMSGS
1490 PrintNetLinkMsg(pNLMsg);
1491 #endif
1492
1493 // Process the NetLink message
1494 if (pNLMsg->nlmsg_type == RTM_GETLINK || pNLMsg->nlmsg_type == RTM_NEWLINK)
1495 result |= 1 << ((struct ifinfomsg*) NLMSG_DATA(pNLMsg))->ifi_index;
1496 else if (pNLMsg->nlmsg_type == RTM_DELADDR || pNLMsg->nlmsg_type == RTM_NEWADDR)
1497 result |= 1 << ((struct ifaddrmsg*) NLMSG_DATA(pNLMsg))->ifa_index;
1498
1499 // Advance pNLMsg to the next message in the buffer
1500 if ((pNLMsg->nlmsg_flags & NLM_F_MULTI) != 0 && pNLMsg->nlmsg_type != NLMSG_DONE)
1501 {
1502 ssize_t len = readCount - ((char*)pNLMsg - buff);
1503 pNLMsg = NLMSG_NEXT(pNLMsg, len);
1504 }
1505 else
1506 break; // all done!
1507 }
1508
1509 return result;
1510 }
1511
1512 #else // USES_NETLINK
1513
1514 // Open a socket that will receive interface change notifications
OpenIfNotifySocket(int * pFD)1515 mDNSlocal mStatus OpenIfNotifySocket(int *pFD)
1516 {
1517 *pFD = socket(AF_ROUTE, SOCK_RAW, 0);
1518
1519 if (*pFD < 0)
1520 return mStatus_UnknownErr;
1521
1522 // Configure read to be non-blocking because inbound msg size is not known in advance
1523 (void) fcntl(*pFD, F_SETFL, O_NONBLOCK);
1524
1525 return mStatus_NoError;
1526 }
1527
1528 #if MDNS_DEBUGMSGS
PrintRoutingSocketMsg(const struct ifa_msghdr * pRSMsg)1529 mDNSlocal void PrintRoutingSocketMsg(const struct ifa_msghdr *pRSMsg)
1530 {
1531 const char *kRSMsgTypes[] = { "", "RTM_ADD", "RTM_DELETE", "RTM_CHANGE", "RTM_GET", "RTM_LOSING",
1532 "RTM_REDIRECT", "RTM_MISS", "RTM_LOCK", "RTM_OLDADD", "RTM_OLDDEL", "RTM_RESOLVE",
1533 "RTM_NEWADDR", "RTM_DELADDR", "RTM_IFINFO", "RTM_NEWMADDR", "RTM_DELMADDR" };
1534
1535 int index = pRSMsg->ifam_type == RTM_IFINFO ? ((struct if_msghdr*) pRSMsg)->ifm_index : pRSMsg->ifam_index;
1536
1537 printf("ifa_msghdr len=%d, type=%s, index=%d\n", pRSMsg->ifam_msglen, kRSMsgTypes[pRSMsg->ifam_type], index);
1538 }
1539 #endif
1540
ProcessRoutingNotification(int sd)1541 mDNSlocal mDNSu32 ProcessRoutingNotification(int sd)
1542 // Read through the messages on sd and if any indicate that any interface records should
1543 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
1544 {
1545 ssize_t readCount;
1546 char buff[4096];
1547 struct ifa_msghdr *pRSMsg = (struct ifa_msghdr*) buff;
1548 mDNSu32 result = 0;
1549
1550 readCount = read(sd, buff, sizeof buff);
1551 if (readCount < (ssize_t) sizeof(struct ifa_msghdr))
1552 return mStatus_UnsupportedErr; // cannot decipher message
1553
1554 #if MDNS_DEBUGMSGS
1555 PrintRoutingSocketMsg(pRSMsg);
1556 #endif
1557
1558 // Process the message
1559 if (pRSMsg->ifam_type == RTM_NEWADDR || pRSMsg->ifam_type == RTM_DELADDR ||
1560 pRSMsg->ifam_type == RTM_IFINFO)
1561 {
1562 if (pRSMsg->ifam_type == RTM_IFINFO)
1563 result |= 1 << ((struct if_msghdr*) pRSMsg)->ifm_index;
1564 else
1565 result |= 1 << pRSMsg->ifam_index;
1566 }
1567
1568 return result;
1569 }
1570
1571 #endif // USES_NETLINK
1572
1573 // Called when data appears on interface change notification socket
InterfaceChangeCallback(int fd,void * context)1574 mDNSlocal void InterfaceChangeCallback(int fd, void *context)
1575 {
1576 IfChangeRec *pChgRec = (IfChangeRec*) context;
1577 fd_set readFDs;
1578 mDNSu32 changedInterfaces = 0;
1579 struct timeval zeroTimeout = { 0, 0 };
1580
1581 (void)fd; // Unused
1582
1583 FD_ZERO(&readFDs);
1584 FD_SET(pChgRec->NotifySD, &readFDs);
1585
1586 do
1587 {
1588 changedInterfaces |= ProcessRoutingNotification(pChgRec->NotifySD);
1589 }
1590 while (0 < select(pChgRec->NotifySD + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout));
1591
1592 // Currently we rebuild the entire interface list whenever any interface change is
1593 // detected. If this ever proves to be a performance issue in a multi-homed
1594 // configuration, more care should be paid to changedInterfaces.
1595 if (changedInterfaces)
1596 mDNSPlatformPosixRefreshInterfaceList(pChgRec->mDNS);
1597 }
1598
1599 // Register with either a Routing Socket or RtNetLink to listen for interface changes.
WatchForInterfaceChange(mDNS * const m)1600 mDNSlocal mStatus WatchForInterfaceChange(mDNS *const m)
1601 {
1602 mStatus err;
1603 IfChangeRec *pChgRec;
1604
1605 pChgRec = (IfChangeRec*) mDNSPlatformMemAllocateClear(sizeof *pChgRec);
1606 if (pChgRec == NULL)
1607 return mStatus_NoMemoryErr;
1608
1609 pChgRec->mDNS = m;
1610 err = OpenIfNotifySocket(&pChgRec->NotifySD);
1611 if (err == 0)
1612 err = mDNSPosixAddFDToEventLoop(pChgRec->NotifySD, InterfaceChangeCallback, pChgRec);
1613 if (err)
1614 mDNSPlatformMemFree(pChgRec);
1615
1616 return err;
1617 }
1618
1619 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
1620 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
1621 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
mDNSPlatformInit_CanReceiveUnicast(void)1622 mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
1623 {
1624 int err;
1625 int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1626 struct sockaddr_in s5353;
1627 s5353.sin_family = AF_INET;
1628 s5353.sin_port = MulticastDNSPort.NotAnInteger;
1629 s5353.sin_addr.s_addr = 0;
1630 err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
1631 close(s);
1632 if (err) debugf("No unicast UDP responses");
1633 else debugf("Unicast UDP responses okay");
1634 return(err == 0);
1635 }
1636
1637 // mDNS core calls this routine to initialise the platform-specific data.
mDNSPlatformInit(mDNS * const m)1638 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
1639 {
1640 int err = 0;
1641 struct sockaddr sa;
1642 assert(m != NULL);
1643
1644 if (mDNSPlatformInit_CanReceiveUnicast()) m->CanReceiveUnicastOn5353 = mDNStrue;
1645
1646 // Tell mDNS core the names of this machine.
1647
1648 // Set up the nice label
1649 m->nicelabel.c[0] = 0;
1650 GetUserSpecifiedFriendlyComputerName(&m->nicelabel);
1651 if (m->nicelabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->nicelabel, "Computer");
1652
1653 // Set up the RFC 1034-compliant label
1654 m->hostlabel.c[0] = 0;
1655 GetUserSpecifiedRFC1034ComputerName(&m->hostlabel);
1656 if (m->hostlabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->hostlabel, "Computer");
1657
1658 mDNS_SetFQDN(m);
1659
1660 sa.sa_family = AF_INET;
1661 m->p->unicastSocket4 = -1;
1662 if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket4);
1663 #if HAVE_IPV6
1664 sa.sa_family = AF_INET6;
1665 m->p->unicastSocket6 = -1;
1666 if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket6);
1667 #endif
1668
1669 // Tell mDNS core about the network interfaces on this machine.
1670 if (err == mStatus_NoError) err = SetupInterfaceList(m);
1671
1672 // Tell mDNS core about DNS Servers
1673 mDNS_Lock(m);
1674 if (err == mStatus_NoError) ParseDNSServers(m, uDNS_SERVERS_FILE);
1675 mDNS_Unlock(m);
1676
1677 if (err == mStatus_NoError)
1678 {
1679 err = WatchForInterfaceChange(m);
1680 // Failure to observe interface changes is non-fatal.
1681 if (err != mStatus_NoError)
1682 {
1683 fprintf(stderr, "mDNS(%d) WARNING: Unable to detect interface changes (%d).\n", getpid(), err);
1684 err = mStatus_NoError;
1685 }
1686 }
1687
1688 // We don't do asynchronous initialization on the Posix platform, so by the time
1689 // we get here the setup will already have succeeded or failed. If it succeeded,
1690 // we should just call mDNSCoreInitComplete() immediately.
1691 if (err == mStatus_NoError)
1692 mDNSCoreInitComplete(m, mStatus_NoError);
1693
1694 return PosixErrorToStatus(err);
1695 }
1696
1697 // mDNS core calls this routine to clean up the platform-specific data.
1698 // In our case all we need to do is to tear down every network interface.
mDNSPlatformClose(mDNS * const m)1699 mDNSexport void mDNSPlatformClose(mDNS *const m)
1700 {
1701 int rv;
1702 assert(m != NULL);
1703 ClearInterfaceList(m);
1704 if (m->p->unicastSocket4 != -1)
1705 {
1706 rv = close(m->p->unicastSocket4);
1707 assert(rv == 0);
1708 }
1709 #if HAVE_IPV6
1710 if (m->p->unicastSocket6 != -1)
1711 {
1712 rv = close(m->p->unicastSocket6);
1713 assert(rv == 0);
1714 }
1715 #endif
1716 }
1717
1718 // This is used internally by InterfaceChangeCallback.
1719 // It's also exported so that the Standalone Responder (mDNSResponderPosix)
1720 // can call it in response to a SIGHUP (mainly for debugging purposes).
mDNSPlatformPosixRefreshInterfaceList(mDNS * const m)1721 mDNSexport mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m)
1722 {
1723 int err;
1724 // This is a pretty heavyweight way to process interface changes --
1725 // destroying the entire interface list and then making fresh one from scratch.
1726 // We should make it like the OS X version, which leaves unchanged interfaces alone.
1727 ClearInterfaceList(m);
1728 err = SetupInterfaceList(m);
1729 return PosixErrorToStatus(err);
1730 }
1731
1732 #if COMPILER_LIKES_PRAGMA_MARK
1733 #pragma mark ***** Locking
1734 #endif
1735
1736 // On the Posix platform, locking is a no-op because we only ever enter
1737 // mDNS core on the main thread.
1738
1739 // mDNS core calls this routine when it wants to prevent
1740 // the platform from reentering mDNS core code.
mDNSPlatformLock(const mDNS * const m)1741 mDNSexport void mDNSPlatformLock (const mDNS *const m)
1742 {
1743 (void) m; // Unused
1744 }
1745
1746 // mDNS core calls this routine when it release the lock taken by
1747 // mDNSPlatformLock and allow the platform to reenter mDNS core code.
mDNSPlatformUnlock(const mDNS * const m)1748 mDNSexport void mDNSPlatformUnlock (const mDNS *const m)
1749 {
1750 (void) m; // Unused
1751 }
1752
1753 #if COMPILER_LIKES_PRAGMA_MARK
1754 #pragma mark ***** Strings
1755 #endif
1756
mDNSPlatformStrLCopy(void * dst,const void * src,mDNSu32 len)1757 mDNSexport mDNSu32 mDNSPlatformStrLCopy(void *dst, const void *src, mDNSu32 len)
1758 {
1759 #if HAVE_STRLCPY
1760 return ((mDNSu32)strlcpy((char *)dst, (const char *)src, len));
1761 #else
1762 size_t srcLen;
1763
1764 srcLen = strlen((const char *)src);
1765 if (srcLen < len)
1766 {
1767 memcpy(dst, src, srcLen + 1);
1768 }
1769 else if (len > 0)
1770 {
1771 memcpy(dst, src, len - 1);
1772 ((char *)dst)[len - 1] = '\0';
1773 }
1774
1775 return ((mDNSu32)srcLen);
1776 #endif
1777 }
1778
1779 // mDNS core calls this routine to get the length of a C string.
1780 // On the Posix platform this maps directly to the ANSI C strlen.
mDNSPlatformStrLen(const void * src)1781 mDNSexport mDNSu32 mDNSPlatformStrLen (const void *src)
1782 {
1783 return strlen((const char*)src);
1784 }
1785
1786 // mDNS core calls this routine to copy memory.
1787 // On the Posix platform this maps directly to the ANSI C memcpy.
mDNSPlatformMemCopy(void * dst,const void * src,mDNSu32 len)1788 mDNSexport void mDNSPlatformMemCopy(void *dst, const void *src, mDNSu32 len)
1789 {
1790 memcpy(dst, src, len);
1791 }
1792
1793 // mDNS core calls this routine to test whether blocks of memory are byte-for-byte
1794 // identical. On the Posix platform this is a simple wrapper around ANSI C memcmp.
mDNSPlatformMemSame(const void * dst,const void * src,mDNSu32 len)1795 mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len)
1796 {
1797 return memcmp(dst, src, len) == 0;
1798 }
1799
1800 // If the caller wants to know the exact return of memcmp, then use this instead
1801 // of mDNSPlatformMemSame
mDNSPlatformMemCmp(const void * dst,const void * src,mDNSu32 len)1802 mDNSexport int mDNSPlatformMemCmp(const void *dst, const void *src, mDNSu32 len)
1803 {
1804 return (memcmp(dst, src, len));
1805 }
1806
mDNSPlatformQsort(void * base,int nel,int width,int (* compar)(const void *,const void *))1807 mDNSexport void mDNSPlatformQsort(void *base, int nel, int width, int (*compar)(const void *, const void *))
1808 {
1809 return (qsort(base, nel, width, compar));
1810 }
1811
1812 // Proxy stub functions
DNSProxySetAttributes(DNSQuestion * q,DNSMessageHeader * h,DNSMessage * msg,mDNSu8 * ptr,mDNSu8 * limit)1813 mDNSexport mDNSu8 *DNSProxySetAttributes(DNSQuestion *q, DNSMessageHeader *h, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *limit)
1814 {
1815 (void) q;
1816 (void) h;
1817 (void) msg;
1818 (void) ptr;
1819 (void) limit;
1820
1821 return ptr;
1822 }
1823
DNSProxyInit(mDNSu32 IpIfArr[],mDNSu32 OpIf)1824 mDNSexport void DNSProxyInit(mDNSu32 IpIfArr[], mDNSu32 OpIf)
1825 {
1826 (void) IpIfArr;
1827 (void) OpIf;
1828 }
1829
DNSProxyTerminate(void)1830 mDNSexport void DNSProxyTerminate(void)
1831 {
1832 }
1833
1834 // mDNS core calls this routine to clear blocks of memory.
1835 // On the Posix platform this is a simple wrapper around ANSI C memset.
mDNSPlatformMemZero(void * dst,mDNSu32 len)1836 mDNSexport void mDNSPlatformMemZero(void *dst, mDNSu32 len)
1837 {
1838 memset(dst, 0, len);
1839 }
1840
1841 #if !MDNS_MALLOC_DEBUGGING
mDNSPlatformMemAllocate(mDNSu32 len)1842 mDNSexport void *mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
mDNSPlatformMemAllocateClear(mDNSu32 len)1843 mDNSexport void *mDNSPlatformMemAllocateClear(mDNSu32 len) { return(callocL(name, len)); }
mDNSPlatformMemFree(void * mem)1844 mDNSexport void mDNSPlatformMemFree (void *mem) { freeL("mDNSPlatformMemFree", mem); }
1845 #endif
1846
1847 #if _PLATFORM_HAS_STRONG_PRNG_
mDNSPlatformRandomNumber(void)1848 mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
1849 {
1850 return(arc4random());
1851 }
1852 #else
mDNSPlatformRandomSeed(void)1853 mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
1854 {
1855 struct timeval tv;
1856 gettimeofday(&tv, NULL);
1857 return(tv.tv_usec);
1858 }
1859 #endif
1860
1861 mDNSexport mDNSs32 mDNSPlatformOneSecond = 1024;
1862
mDNSPlatformTimeInit(void)1863 mDNSexport mStatus mDNSPlatformTimeInit(void)
1864 {
1865 // No special setup is required on Posix -- we just use gettimeofday();
1866 // This is not really safe, because gettimeofday can go backwards if the user manually changes the date or time
1867 // We should find a better way to do this
1868 return(mStatus_NoError);
1869 }
1870
mDNSPlatformRawTime()1871 mDNSexport mDNSs32 mDNSPlatformRawTime()
1872 {
1873 struct timespec tm;
1874 int ret = clock_gettime(CLOCK_MONOTONIC, &tm);
1875 assert(ret == 0); // This call will only fail if the number of seconds does not fit in an object of type time_t.
1876
1877 // tm.tv_sec is seconds since some unspecified starting point (it is usually the system start up time)
1878 // tm.tv_nsec is nanoseconds since the start of this second (i.e. values 0 to 999999999)
1879 // We use the lower 22 bits of tm.tv_sec for the top 22 bits of our result
1880 // and we multiply tm.tv_nsec by 2 / 1953125 to get a value in the range 0-1023 to go in the bottom 10 bits.
1881 // This gives us a proper modular (cyclic) counter that has a resolution of roughly 1ms (actually 1/1024 second)
1882 // and correctly cycles every 2^22 seconds (4194304 seconds = approx 48 days).
1883
1884 return ((tm.tv_sec << 10) | (tm.tv_nsec * 2 / 1953125));
1885 }
1886
mDNSPlatformUTC(void)1887 mDNSexport mDNSs32 mDNSPlatformUTC(void)
1888 {
1889 return time(NULL);
1890 }
1891
mDNSPlatformSendWakeupPacket(mDNSInterfaceID InterfaceID,char * EthAddr,char * IPAddr,int iteration)1892 mDNSexport void mDNSPlatformSendWakeupPacket(mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
1893 {
1894 (void) InterfaceID;
1895 (void) EthAddr;
1896 (void) IPAddr;
1897 (void) iteration;
1898 }
1899
mDNSPlatformValidRecordForInterface(const AuthRecord * rr,mDNSInterfaceID InterfaceID)1900 mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(const AuthRecord *rr, mDNSInterfaceID InterfaceID)
1901 {
1902 (void) rr;
1903 (void) InterfaceID;
1904
1905 return 1;
1906 }
1907
mDNSPlatformValidQuestionForInterface(DNSQuestion * q,const NetworkInterfaceInfo * intf)1908 mDNSexport mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf)
1909 {
1910 (void) q;
1911 (void) intf;
1912
1913 return 1;
1914 }
1915
1916 // Used for debugging purposes. For now, just set the buffer to zero
mDNSPlatformFormatTime(unsigned long te,mDNSu8 * buf,int bufsize)1917 mDNSexport void mDNSPlatformFormatTime(unsigned long te, mDNSu8 *buf, int bufsize)
1918 {
1919 (void) te;
1920 if (bufsize) buf[0] = 0;
1921 }
1922
mDNSPlatformSendKeepalive(mDNSAddr * sadd,mDNSAddr * dadd,mDNSIPPort * lport,mDNSIPPort * rport,mDNSu32 seq,mDNSu32 ack,mDNSu16 win)1923 mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win)
1924 {
1925 (void) sadd; // Unused
1926 (void) dadd; // Unused
1927 (void) lport; // Unused
1928 (void) rport; // Unused
1929 (void) seq; // Unused
1930 (void) ack; // Unused
1931 (void) win; // Unused
1932 }
1933
mDNSPlatformRetrieveTCPInfo(mDNSAddr * laddr,mDNSIPPort * lport,mDNSAddr * raddr,mDNSIPPort * rport,mDNSTCPInfo * mti)1934 mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
1935 {
1936 (void) laddr; // Unused
1937 (void) raddr; // Unused
1938 (void) lport; // Unused
1939 (void) rport; // Unused
1940 (void) mti; // Unused
1941
1942 return mStatus_NoError;
1943 }
1944
mDNSPlatformGetRemoteMacAddr(mDNSAddr * raddr)1945 mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNSAddr *raddr)
1946 {
1947 (void) raddr; // Unused
1948
1949 return mStatus_NoError;
1950 }
1951
mDNSPlatformStoreSPSMACAddr(mDNSAddr * spsaddr,char * ifname)1952 mDNSexport mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname)
1953 {
1954 (void) spsaddr; // Unused
1955 (void) ifname; // Unused
1956
1957 return mStatus_NoError;
1958 }
1959
mDNSPlatformClearSPSData(void)1960 mDNSexport mStatus mDNSPlatformClearSPSData(void)
1961 {
1962 return mStatus_NoError;
1963 }
1964
mDNSPlatformStoreOwnerOptRecord(char * ifname,DNSMessage * msg,int length)1965 mDNSexport mStatus mDNSPlatformStoreOwnerOptRecord(char *ifname, DNSMessage *msg, int length)
1966 {
1967 (void) ifname; // Unused
1968 (void) msg; // Unused
1969 (void) length; // Unused
1970 return mStatus_UnsupportedErr;
1971 }
1972
mDNSPlatformGetUDPPort(UDPSocket * sock)1973 mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
1974 {
1975 (void) sock; // unused
1976
1977 return (mDNSu16)-1;
1978 }
1979
mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)1980 mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
1981 {
1982 (void) InterfaceID; // unused
1983
1984 return mDNSfalse;
1985 }
1986
mDNSPlatformSetSocktOpt(void * sock,mDNSTransport_Type transType,mDNSAddr_Type addrType,const DNSQuestion * q)1987 mDNSexport void mDNSPlatformSetSocktOpt(void *sock, mDNSTransport_Type transType, mDNSAddr_Type addrType, const DNSQuestion *q)
1988 {
1989 (void) sock;
1990 (void) transType;
1991 (void) addrType;
1992 (void) q;
1993 }
1994
mDNSPlatformGetPID()1995 mDNSexport mDNSs32 mDNSPlatformGetPID()
1996 {
1997 return 0;
1998 }
1999
mDNSPosixAddToFDSet(int * nfds,fd_set * readfds,int s)2000 mDNSlocal void mDNSPosixAddToFDSet(int *nfds, fd_set *readfds, int s)
2001 {
2002 if (*nfds < s + 1) *nfds = s + 1;
2003 FD_SET(s, readfds);
2004 }
2005
mDNSPosixGetFDSetForSelect(mDNS * m,int * nfds,fd_set * readfds,fd_set * writefds)2006 mDNSexport void mDNSPosixGetFDSetForSelect(mDNS *m, int *nfds, fd_set *readfds, fd_set *writefds)
2007 {
2008 int numFDs = *nfds;
2009 PosixEventSource *iSource;
2010
2011 // 2. Build our list of active file descriptors
2012 PosixNetworkInterface *info = (PosixNetworkInterface *)(m->HostInterfaces);
2013 if (m->p->unicastSocket4 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, m->p->unicastSocket4);
2014 #if HAVE_IPV6
2015 if (m->p->unicastSocket6 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, m->p->unicastSocket6);
2016 #endif
2017 while (info)
2018 {
2019 if (info->multicastSocket4 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, info->multicastSocket4);
2020 #if HAVE_IPV6
2021 if (info->multicastSocket6 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, info->multicastSocket6);
2022 #endif
2023 info = (PosixNetworkInterface *)(info->coreIntf.next);
2024 }
2025
2026 // Copy over the event fds. We have to do it this way because client-provided event loops expect
2027 // to initialize their FD sets first and then call mDNSPosixGetFDSet()
2028 for (iSource = gEventSources; iSource; iSource = iSource->next)
2029 {
2030 if (iSource->readCallback != NULL)
2031 FD_SET(iSource->fd, readfds);
2032 if (iSource->writeCallback != NULL)
2033 FD_SET(iSource->fd, writefds);
2034 if (numFDs <= iSource->fd)
2035 numFDs = iSource->fd + 1;
2036 }
2037 *nfds = numFDs;
2038 }
2039
mDNSPosixGetNextDNSEventTime(mDNS * m,struct timeval * timeout)2040 mDNSexport void mDNSPosixGetNextDNSEventTime(mDNS *m, struct timeval *timeout)
2041 {
2042 mDNSs32 ticks;
2043 struct timeval interval;
2044
2045 // 1. Call mDNS_Execute() to let mDNSCore do what it needs to do
2046 mDNSs32 nextevent = mDNS_Execute(m);
2047
2048 // 3. Calculate the time remaining to the next scheduled event (in struct timeval format)
2049 ticks = nextevent - mDNS_TimeNow(m);
2050 if (ticks < 1) ticks = 1;
2051 interval.tv_sec = ticks >> 10; // The high 22 bits are seconds
2052 interval.tv_usec = ((ticks & 0x3FF) * 15625) / 16; // The low 10 bits are 1024ths
2053
2054 // 4. If client's proposed timeout is more than what we want, then reduce it
2055 if (timeout->tv_sec > interval.tv_sec ||
2056 (timeout->tv_sec == interval.tv_sec && timeout->tv_usec > interval.tv_usec))
2057 *timeout = interval;
2058 }
2059
mDNSPosixGetFDSet(mDNS * m,int * nfds,fd_set * readfds,fd_set * writefds,struct timeval * timeout)2060 mDNSexport void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, fd_set *writefds, struct timeval *timeout)
2061 {
2062 mDNSPosixGetNextDNSEventTime(m, timeout);
2063 mDNSPosixGetFDSetForSelect(m, nfds, readfds, writefds);
2064 }
2065
mDNSPosixProcessFDSet(mDNS * const m,fd_set * readfds,fd_set * writefds)2066 mDNSexport void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds, fd_set *writefds)
2067 {
2068 PosixNetworkInterface *info;
2069 PosixEventSource *iSource;
2070 assert(m != NULL);
2071 assert(readfds != NULL);
2072 info = (PosixNetworkInterface *)(m->HostInterfaces);
2073
2074 if (m->p->unicastSocket4 != -1 && FD_ISSET(m->p->unicastSocket4, readfds))
2075 {
2076 FD_CLR(m->p->unicastSocket4, readfds);
2077 SocketDataReady(m, NULL, m->p->unicastSocket4);
2078 }
2079 #if HAVE_IPV6
2080 if (m->p->unicastSocket6 != -1 && FD_ISSET(m->p->unicastSocket6, readfds))
2081 {
2082 FD_CLR(m->p->unicastSocket6, readfds);
2083 SocketDataReady(m, NULL, m->p->unicastSocket6);
2084 }
2085 #endif
2086
2087 while (info)
2088 {
2089 if (info->multicastSocket4 != -1 && FD_ISSET(info->multicastSocket4, readfds))
2090 {
2091 FD_CLR(info->multicastSocket4, readfds);
2092 SocketDataReady(m, info, info->multicastSocket4);
2093 }
2094 #if HAVE_IPV6
2095 if (info->multicastSocket6 != -1 && FD_ISSET(info->multicastSocket6, readfds))
2096 {
2097 FD_CLR(info->multicastSocket6, readfds);
2098 SocketDataReady(m, info, info->multicastSocket6);
2099 }
2100 #endif
2101 info = (PosixNetworkInterface *)(info->coreIntf.next);
2102 }
2103
2104 // Now process routing socket events, discovery relay events and anything else of that ilk.
2105 for (iSource = gEventSources; iSource; iSource = iSource->next)
2106 {
2107 if (iSource->readCallback != NULL && FD_ISSET(iSource->fd, readfds))
2108 {
2109 iSource->readCallback(iSource->fd, iSource->readContext);
2110 break; // in case callback removed elements from gEventSources
2111 }
2112 else if (iSource->writeCallback != NULL && FD_ISSET(iSource->fd, writefds))
2113 {
2114 mDNSPosixEventCallback writeCallback = iSource->writeCallback;
2115 // Write events are one-shot: to get another event, the consumer has to put in a new request.
2116 // We reset this before calling the callback just in case the callback requests another write
2117 // callback, or deletes the event context from the list.
2118 iSource->writeCallback = NULL;
2119 writeCallback(iSource->fd, iSource->writeContext);
2120 break; // in case callback removed elements from gEventSources
2121 }
2122 }
2123 }
2124
2125 mDNSu32 mDNSPlatformEventContextSize = sizeof (PosixEventSource);
2126
requestIOEvents(PosixEventSource * newSource,const char * taskName,mDNSPosixEventCallback callback,void * context,int flag)2127 mDNSlocal void requestIOEvents(PosixEventSource *newSource, const char *taskName,
2128 mDNSPosixEventCallback callback, void *context, int flag)
2129 {
2130 PosixEventSource **epp = &gEventSources;
2131
2132 if (newSource->fd >= (int) FD_SETSIZE || newSource->fd < 0)
2133 {
2134 LogMsg("requestIOEvents called with fd %d > FD_SETSIZE %d.", newSource->fd, FD_SETSIZE);
2135 assert(0);
2136 }
2137 if (callback == NULL)
2138 {
2139 LogMsg("requestIOEvents called no callback.", newSource->fd, FD_SETSIZE);
2140 assert(0);
2141 }
2142
2143 // See if this event context is already on the list; if it is, no need to scan the list.
2144 if (!(newSource->flags & PosixEventFlag_OnList))
2145 {
2146 while (*epp)
2147 {
2148 // This should never happen.
2149 if (newSource == *epp)
2150 {
2151 LogMsg("Event context marked not on list but is on list.");
2152 assert(0);
2153 }
2154 epp = &(*epp)->next;
2155 }
2156 if (*epp == NULL)
2157 {
2158 *epp = newSource;
2159 newSource->next = NULL;
2160 newSource->flags = PosixEventFlag_OnList;
2161 }
2162 }
2163
2164 if (flag & PosixEventFlag_Read)
2165 {
2166 newSource->readCallback = callback;
2167 newSource->readContext = context;
2168 newSource->flags |= PosixEventFlag_Read;
2169 newSource->readTaskName = taskName;
2170 }
2171 if (flag & PosixEventFlag_Write)
2172 {
2173 newSource->writeCallback = callback;
2174 newSource->writeContext = context;
2175 newSource->flags |= PosixEventFlag_Write;
2176 newSource->writeTaskName = taskName;
2177 }
2178 }
2179
requestReadEvents(PosixEventSource * eventSource,const char * taskName,mDNSPosixEventCallback callback,void * context)2180 mDNSlocal void requestReadEvents(PosixEventSource *eventSource,
2181 const char *taskName, mDNSPosixEventCallback callback, void *context)
2182 {
2183 requestIOEvents(eventSource, taskName, callback, context, PosixEventFlag_Read);
2184 }
2185
requestWriteEvents(PosixEventSource * eventSource,const char * taskName,mDNSPosixEventCallback callback,void * context)2186 mDNSlocal void requestWriteEvents(PosixEventSource *eventSource,
2187 const char *taskName, mDNSPosixEventCallback callback, void *context)
2188 {
2189 requestIOEvents(eventSource, taskName, callback, context, PosixEventFlag_Write);
2190 }
2191
2192 // Remove a file descriptor from the set that mDNSPosixRunEventLoopOnce() listens to.
stopReadOrWriteEvents(int fd,mDNSBool freeContext,mDNSBool removeContext,int flags)2193 mDNSlocal mStatus stopReadOrWriteEvents(int fd, mDNSBool freeContext, mDNSBool removeContext, int flags)
2194 {
2195 PosixEventSource *iSource, **epp = &gEventSources;
2196
2197 while (*epp)
2198 {
2199 iSource = *epp;
2200 if (fd == iSource->fd)
2201 {
2202 if (flags & PosixEventFlag_Read)
2203 {
2204 iSource->readCallback = NULL;
2205 iSource->readContext = NULL;
2206 }
2207 if (flags & PosixEventFlag_Write)
2208 {
2209 iSource->writeCallback = NULL;
2210 iSource->writeContext = NULL;
2211 }
2212 if (iSource->writeCallback == NULL && iSource->readCallback == NULL)
2213 {
2214 if (removeContext || freeContext)
2215 *epp = iSource->next;
2216 if (freeContext)
2217 free(iSource);
2218 }
2219 return mStatus_NoError;
2220 }
2221 epp = &(*epp)->next;
2222 }
2223 return mStatus_NoSuchNameErr;
2224 }
2225
2226 // Some of the mDNSPosix client code relies on being able to add FDs to the event loop without
2227 // providing storage for the event-related info. mDNSPosixAddFDToEventLoop and
2228 // mDNSPosixRemoveFDFromEventLoop handle the event structure storage automatically.
mDNSPosixAddFDToEventLoop(int fd,mDNSPosixEventCallback callback,void * context)2229 mStatus mDNSPosixAddFDToEventLoop(int fd, mDNSPosixEventCallback callback, void *context)
2230 {
2231 PosixEventSource *newSource;
2232
2233 newSource = (PosixEventSource*) malloc(sizeof *newSource);
2234 if (NULL == newSource)
2235 return mStatus_NoMemoryErr;
2236 memset(newSource, 0, sizeof *newSource);
2237 newSource->fd = fd;
2238
2239 requestReadEvents(newSource, "mDNSPosixAddFDToEventLoop", callback, context);
2240 return mStatus_NoError;
2241 }
2242
mDNSPosixRemoveFDFromEventLoop(int fd)2243 mStatus mDNSPosixRemoveFDFromEventLoop(int fd)
2244 {
2245 return stopReadOrWriteEvents(fd, mDNStrue, mDNStrue, PosixEventFlag_Read | PosixEventFlag_Write);
2246 }
2247
2248 // Simply note the received signal in gEventSignals.
NoteSignal(int signum)2249 mDNSlocal void NoteSignal(int signum)
2250 {
2251 sigaddset(&gEventSignals, signum);
2252 }
2253
2254 // Tell the event package to listen for signal and report it in mDNSPosixRunEventLoopOnce().
mDNSPosixListenForSignalInEventLoop(int signum)2255 mStatus mDNSPosixListenForSignalInEventLoop(int signum)
2256 {
2257 struct sigaction action;
2258 mStatus err;
2259
2260 mDNSPlatformMemZero(&action, sizeof action); // more portable than member-wise assignment
2261 action.sa_handler = NoteSignal;
2262 err = sigaction(signum, &action, (struct sigaction*) NULL);
2263
2264 sigaddset(&gEventSignalSet, signum);
2265
2266 return err;
2267 }
2268
2269 // Tell the event package to stop listening for signal in mDNSPosixRunEventLoopOnce().
mDNSPosixIgnoreSignalInEventLoop(int signum)2270 mStatus mDNSPosixIgnoreSignalInEventLoop(int signum)
2271 {
2272 struct sigaction action;
2273 mStatus err;
2274
2275 mDNSPlatformMemZero(&action, sizeof action); // more portable than member-wise assignment
2276 action.sa_handler = SIG_DFL;
2277 err = sigaction(signum, &action, (struct sigaction*) NULL);
2278
2279 sigdelset(&gEventSignalSet, signum);
2280
2281 return err;
2282 }
2283
2284 // Do a single pass through the attendent event sources and dispatch any found to their callbacks.
2285 // Return as soon as internal timeout expires, or a signal we're listening for is received.
mDNSPosixRunEventLoopOnce(mDNS * m,const struct timeval * pTimeout,sigset_t * pSignalsReceived,mDNSBool * pDataDispatched)2286 mStatus mDNSPosixRunEventLoopOnce(mDNS *m, const struct timeval *pTimeout,
2287 sigset_t *pSignalsReceived, mDNSBool *pDataDispatched)
2288 {
2289 fd_set listenFDs;
2290 fd_set writeFDs;
2291 int numFDs = 0, numReady;
2292 struct timeval timeout = *pTimeout;
2293
2294 // 1. Set up the fd_set as usual here.
2295 // This example client has no file descriptors of its own,
2296 // but a real application would call FD_SET to add them to the set here
2297 FD_ZERO(&listenFDs);
2298 FD_ZERO(&writeFDs);
2299
2300 // 2. Set up the timeout.
2301 mDNSPosixGetNextDNSEventTime(m, &timeout);
2302
2303 // Include the sockets that are listening to the wire in our select() set
2304 mDNSPosixGetFDSetForSelect(m, &numFDs, &listenFDs, &writeFDs);
2305 numReady = select(numFDs, &listenFDs, &writeFDs, (fd_set*) NULL, &timeout);
2306
2307 if (numReady > 0)
2308 {
2309 mDNSPosixProcessFDSet(m, &listenFDs, &writeFDs);
2310 *pDataDispatched = mDNStrue;
2311 }
2312 else if (numReady < 0)
2313 {
2314 if (errno != EINTR) {
2315 // This should never happen, represents a coding error, and is not recoverable, since
2316 // we'll just sit here spinning and never receive another event. The usual reason for
2317 // it to happen is that an FD was closed but not removed from the event list.
2318 LogMsg("select failed: %s", strerror(errno));
2319 abort();
2320 }
2321 }
2322 else
2323 *pDataDispatched = mDNSfalse;
2324
2325 (void) sigprocmask(SIG_BLOCK, &gEventSignalSet, (sigset_t*) NULL);
2326 *pSignalsReceived = gEventSignals;
2327 sigemptyset(&gEventSignals);
2328 (void) sigprocmask(SIG_UNBLOCK, &gEventSignalSet, (sigset_t*) NULL);
2329
2330 return mStatus_NoError;
2331 }
2332