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