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-2020 Apple Inc. All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 // ***************************************************************************
19 // mDNSMacOSX.c:
20 // Supporting routines to run mDNS on a CFRunLoop platform
21 // ***************************************************************************
22 
23 // For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
24 // including ones that mDNSResponder chooses not to use.
25 #define LIST_ALL_INTERFACES 0
26 
27 #include "mDNSEmbeddedAPI.h"        // Defines the interface provided to the client layer above
28 #include "DNSCommon.h"
29 #include "uDNS.h"
30 #include "mDNSMacOSX.h"             // Defines the specific types needed to run mDNS on this platform
31 #include "dns_sd.h"                 // For mDNSInterface_LocalOnly etc.
32 #include "dns_sd_internal.h"
33 #include "PlatformCommon.h"
34 #include "uds_daemon.h"
35 #if MDNSRESPONDER_SUPPORTS(APPLE, ANALYTICS)
36 #include "dnssd_analytics.h"
37 #endif
38 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
39 #include "mdns_trust.h"
40 #include <os/feature_private.h>
41 #endif
42 
43 #include <stdio.h>
44 #include <stdarg.h>                 // For va_list support
45 #include <stdlib.h>                 // For arc4random
46 #include <net/if.h>
47 #include <net/if_types.h>           // For IFT_ETHER
48 #include <net/if_dl.h>
49 #include <net/bpf.h>                // For BIOCSETIF etc.
50 #include <sys/uio.h>
51 #include <sys/param.h>
52 #include <sys/socket.h>
53 #include <sys/sysctl.h>
54 #include <sys/event.h>
55 #include <fcntl.h>
56 #include <sys/ioctl.h>
57 #include <time.h>                   // platform support for UTC time
58 #include <arpa/inet.h>              // for inet_aton
59 #include <pthread.h>
60 #include <netdb.h>                  // for getaddrinfo
61 #include <sys/sockio.h>             // for SIOCGIFEFLAGS
62 #include <notify.h>
63 #include <netinet/in.h>             // For IP_RECVTTL
64 #ifndef IP_RECVTTL
65 #define IP_RECVTTL 24               // bool; receive reception TTL w/dgram
66 #endif
67 
68 #include <netinet/in_systm.h>       // For n_long, required by <netinet/ip.h> below
69 #include <netinet/ip.h>             // For IPTOS_LOWDELAY etc.
70 #include <netinet6/in6_var.h>       // For IN6_IFF_TENTATIVE etc.
71 
72 #include <netinet/tcp.h>
73 
74 #include <DebugServices.h>
75 #include "dnsinfo.h"
76 
77 #include <ifaddrs.h>
78 
79 #include <IOKit/IOKitLib.h>
80 #include <IOKit/IOMessage.h>
81 
82 #include <IOKit/ps/IOPowerSources.h>
83 #include <IOKit/ps/IOPowerSourcesPrivate.h>
84 #include <IOKit/ps/IOPSKeys.h>
85 
86 #include <mach/mach_error.h>
87 #include <mach/mach_port.h>
88 #include <mach/mach_time.h>
89 #include "helper.h"
90 #include "P2PPacketFilter.h"
91 
92 #include <SystemConfiguration/SCPrivate.h>
93 
94 #if (TARGET_OS_IPHONE && !TARGET_OS_MACCATALYST)
95 #include <MobileWiFi/WiFiManagerClient.h> // For WiFiManagerClientRef etc, declarations.
96 #include <dlfcn.h>
97 #endif // TARGET_OS_IPHONE
98 
99 #include "system_utilities.h"
100 
101 // Include definition of opaque_presence_indication for KEV_DL_NODE_PRESENCE handling logic.
102 #include <Kernel/IOKit/apple80211/apple80211_var.h>
103 
104 #if APPLE_OSX_mDNSResponder
105 #include <ne_session.h> // for ne_session_set_socket_attributes()
106 #endif
107 
108 #if APPLE_OSX_mDNSResponder && TARGET_OS_OSX
109 #include <IOKit/platform/IOPlatformSupportPrivate.h>
110 #endif
111 
112 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
113 #include "QuerierSupport.h"
114 #endif
115 
116 #ifdef UNIT_TEST
117 #include "unittest.h"
118 #endif
119 
120 #define kInterfaceSpecificOption "interface="
121 
122 #define mDNS_IOREG_KEY               "mDNS_KEY"
123 #define mDNS_IOREG_VALUE             "2009-07-30"
124 #define mDNS_IOREG_KA_KEY            "mDNS_Keepalive"
125 #define mDNS_USER_CLIENT_CREATE_TYPE 'mDNS'
126 
127 #define DARK_WAKE_TIME 16 // Time we hold an idle sleep assertion for maintenance after a wake notification
128 
129 // cache the InterfaceID of the AWDL interface
130 mDNSInterfaceID AWDLInterfaceID;
131 
132 // ***************************************************************************
133 // Globals
134 
135 #if COMPILER_LIKES_PRAGMA_MARK
136 #pragma mark - Globals
137 #endif
138 
139 // By default we don't offer sleep proxy service
140 // If OfferSleepProxyService is set non-zero (typically via command-line switch),
141 // then we'll offer sleep proxy service on desktop Macs that are set to never sleep.
142 // We currently do not offer sleep proxy service on laptops, or on machines that are set to go to sleep.
143 mDNSexport int OfferSleepProxyService = 0;
144 mDNSexport int DisableSleepProxyClient = 0;
145 mDNSexport int UseInternalSleepProxy = 1;       // Set to non-zero to use internal (in-NIC) Sleep Proxy
146 
147 mDNSexport int OSXVers, iOSVers;
148 mDNSexport int KQueueFD;
149 
150 #ifndef NO_SECURITYFRAMEWORK
151 static CFArrayRef ServerCerts;
152 OSStatus SSLSetAllowAnonymousCiphers(SSLContextRef context, Boolean enable);
153 #endif /* NO_SECURITYFRAMEWORK */
154 
155 static CFStringRef NetworkChangedKey_IPv4;
156 static CFStringRef NetworkChangedKey_IPv6;
157 static CFStringRef NetworkChangedKey_Hostnames;
158 static CFStringRef NetworkChangedKey_Computername;
159 static CFStringRef NetworkChangedKey_DNS;
160 static CFStringRef NetworkChangedKey_StateInterfacePrefix;
161 static CFStringRef NetworkChangedKey_DynamicDNS       = CFSTR("Setup:/Network/DynamicDNS");
162 static CFStringRef NetworkChangedKey_PowerSettings    = CFSTR("State:/IOKit/PowerManagement/CurrentSettings");
163 
164 static char HINFO_HWstring_buffer[32];
165 static char *HINFO_HWstring = "Device";
166 static int HINFO_HWstring_prefixlen = 6;
167 
168 mDNSexport int WatchDogReportingThreshold = 250;
169 
170 dispatch_queue_t SSLqueue;
171 
172 #if APPLE_OSX_mDNSResponder
173 static mDNSu8 SPMetricPortability   = 99;
174 static mDNSu8 SPMetricMarginalPower = 99;
175 static mDNSu8 SPMetricTotalPower    = 99;
176 static mDNSu8 SPMetricFeatures      = 1; /* The current version supports TCP Keep Alive Feature */
177 #endif // APPLE_OSX_mDNSResponder
178 
179 #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
180 domainname ActiveDirectoryPrimaryDomain;
181 static int ActiveDirectoryPrimaryDomainLabelCount;
182 static mDNSAddr ActiveDirectoryPrimaryDomainServer;
183 #endif
184 
185 // Don't send triggers too often. We arbitrarily limit it to three minutes.
186 #define DNS_TRIGGER_INTERVAL (180 * mDNSPlatformOneSecond)
187 
188 const char dnsprefix[] = "dns:";
189 
190 // String Array used to write list of private domains to Dynamic Store
191 static CFArrayRef privateDnsArray = NULL;
192 
193 // ***************************************************************************
194 // Functions
195 
196 #if COMPILER_LIKES_PRAGMA_MARK
197 #pragma mark -
198 #pragma mark - Utility Functions
199 #endif
200 
201 // We only attempt to send and receive multicast packets on interfaces that are
202 // (a) flagged as multicast-capable
203 // (b) *not* flagged as point-to-point (e.g. modem)
204 // Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
205 // to run up the user's bill sending multicast traffic over a link where there's only a single device at the
206 // other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
207 
208 #if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
209 #define MulticastInterface(i) ((i)->m->BonjourEnabled && ((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
210 #else
211 #define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
212 #endif
213 #define SPSInterface(i)       ((i)->ifinfo.McastTxRx && !((i)->ifa_flags & IFF_LOOPBACK) && !(i)->D2DInterface)
214 
215 mDNSlocal void SetNetworkChanged(mDNSs32 delay);
216 
NotifyOfElusiveBug(const char * title,const char * msg)217 mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg)  // Both strings are UTF-8 text
218 {
219     // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
220     #if !ForceAlerts
221     {
222         // Determine if we're at Apple (17.*.*.*)
223         NetworkInterfaceInfoOSX *i;
224         for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
225             if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && i->ifinfo.ip.ip.v4.b[0] == 17)
226                 break;
227         if (!i)
228             return; // If not at Apple, don't show the alert
229     }
230     #endif
231 
232     LogMsg("NotifyOfElusiveBug: %s", title);
233     LogMsg("NotifyOfElusiveBug: %s", msg);
234 
235     // If we display our alert early in the boot process, then it vanishes once the desktop appears.
236     // To avoid this, we don't try to display alerts in the first three minutes after boot.
237     if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180))
238     {
239         LogMsg("Suppressing notification early in boot: %d", mDNSPlatformRawTime());
240         return;
241     }
242 
243 #ifndef NO_CFUSERNOTIFICATION
244     static int notifyCount = 0; // To guard against excessive display of warning notifications
245     if (notifyCount < 5)
246     {
247         notifyCount++;
248         mDNSNotify(title, msg);
249     }
250 #endif /* NO_CFUSERNOTIFICATION */
251 
252 }
253 
254 // Write a syslog message and display an alert, then if ForceAlerts is set, generate a stack trace
255 #if MDNS_MALLOC_DEBUGGING >= 1
LogMemCorruption(const char * format,...)256 mDNSexport void LogMemCorruption(const char *format, ...)
257 {
258     char buffer[512];
259     va_list ptr;
260     va_start(ptr,format);
261     buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
262     va_end(ptr);
263     LogMsg("!!!! %s !!!!", buffer);
264     NotifyOfElusiveBug("Memory Corruption", buffer);
265 #if ForceAlerts
266     *(volatile long*)0 = 0;  // Trick to crash and get a stack trace right here, if that's what we want
267 #endif
268 }
269 #endif
270 
271 // Like LogMemCorruption above, but only display the alert if ForceAlerts is set and we're going to generate a stack trace
272 #if APPLE_OSX_mDNSResponder
LogFatalError(const char * format,...)273 mDNSexport void LogFatalError(const char *format, ...)
274 {
275     char buffer[512];
276     va_list ptr;
277     va_start(ptr,format);
278     buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
279     va_end(ptr);
280     LogMsg("!!!! %s !!!!", buffer);
281 #if ForceAlerts
282     NotifyOfElusiveBug("Fatal Error. See /Library/Logs/DiagnosticReports", buffer);
283     *(volatile long*)0 = 0;  // Trick to crash and get a stack trace right here, if that's what we want
284 #endif
285 }
286 #endif
287 
288 // Returns true if it is an AppleTV based hardware running iOS, false otherwise
IsAppleTV(void)289 mDNSlocal mDNSBool IsAppleTV(void)
290 {
291 #if TARGET_OS_TV
292     return mDNStrue;
293 #else
294     return mDNSfalse;
295 #endif
296 }
297 
myGetIfAddrs(int refresh)298 mDNSlocal struct ifaddrs *myGetIfAddrs(int refresh)
299 {
300     static struct ifaddrs *ifa = NULL;
301 
302     if (refresh && ifa)
303     {
304         freeifaddrs(ifa);
305         ifa = NULL;
306     }
307 
308     if (ifa == NULL)
309         getifaddrs(&ifa);
310     return ifa;
311 }
312 
DynamicStoreWrite(int key,const char * subkey,uintptr_t value,signed long valueCnt)313 mDNSlocal void DynamicStoreWrite(int key, const char* subkey, uintptr_t value, signed long valueCnt)
314 {
315     CFStringRef sckey       = NULL;
316     Boolean release_sckey   = FALSE;
317     CFDataRef bytes         = NULL;
318     CFPropertyListRef plist = NULL;
319 
320     switch ((enum mDNSDynamicStoreSetConfigKey)key)
321     {
322         case kmDNSMulticastConfig:
323             sckey = CFSTR("State:/Network/" kDNSServiceCompMulticastDNS);
324             break;
325         case kmDNSDynamicConfig:
326             sckey = CFSTR("State:/Network/DynamicDNS");
327             break;
328         case kmDNSPrivateConfig:
329             sckey = CFSTR("State:/Network/" kDNSServiceCompPrivateDNS);
330             break;
331         case kmDNSBackToMyMacConfig:
332             sckey = CFSTR("State:/Network/BackToMyMac");
333             break;
334         case kmDNSSleepProxyServersState:
335         {
336             CFMutableStringRef tmp = CFStringCreateMutable(kCFAllocatorDefault, 0);
337             CFStringAppend(tmp, CFSTR("State:/Network/Interface/"));
338             CFStringAppendCString(tmp, subkey, kCFStringEncodingUTF8);
339             CFStringAppend(tmp, CFSTR("/SleepProxyServers"));
340             sckey = CFStringCreateCopy(kCFAllocatorDefault, tmp);
341             release_sckey = TRUE;
342             CFRelease(tmp);
343             break;
344         }
345         case kmDNSDebugState:
346             sckey = CFSTR("State:/Network/mDNSResponder/DebugState");
347             break;
348         default:
349             LogMsg("unrecognized key %d", key);
350             goto fin;
351     }
352     if (NULL == (bytes = CFDataCreateWithBytesNoCopy(NULL, (void *)value,
353                                                      valueCnt, kCFAllocatorNull)))
354     {
355         LogMsg("CFDataCreateWithBytesNoCopy of value failed");
356         goto fin;
357     }
358     if (NULL == (plist = CFPropertyListCreateWithData(NULL, bytes, kCFPropertyListImmutable, NULL, NULL)))
359     {
360         LogMsg("CFPropertyListCreateWithData of bytes failed");
361         goto fin;
362     }
363     CFRelease(bytes);
364     bytes = NULL;
365     SCDynamicStoreSetValue(NULL, sckey, plist);
366 
367 fin:
368     if (NULL != bytes)
369         CFRelease(bytes);
370     if (NULL != plist)
371         CFRelease(plist);
372     if (release_sckey && sckey)
373         CFRelease(sckey);
374 }
375 
mDNSDynamicStoreSetConfig(int key,const char * subkey,CFPropertyListRef value)376 mDNSexport void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropertyListRef value)
377 {
378     CFPropertyListRef valueCopy;
379     char *subkeyCopy  = NULL;
380     if (!value)
381         return;
382 
383     // We need to copy the key and value before we dispatch off the block below as the
384     // caller will free the memory once we return from this function.
385     valueCopy = CFPropertyListCreateDeepCopy(NULL, value, kCFPropertyListImmutable);
386     if (!valueCopy)
387     {
388         LogMsg("mDNSDynamicStoreSetConfig: ERROR valueCopy NULL");
389         return;
390     }
391     if (subkey)
392     {
393         const mDNSu32 len = (mDNSu32)strlen(subkey);
394         subkeyCopy = mDNSPlatformMemAllocate(len + 1);
395         if (!subkeyCopy)
396         {
397             LogMsg("mDNSDynamicStoreSetConfig: ERROR subkeyCopy NULL");
398             CFRelease(valueCopy);
399             return;
400         }
401         mDNSPlatformMemCopy(subkeyCopy, subkey, len);
402         subkeyCopy[len] = 0;
403     }
404 
405     dispatch_async(dispatch_get_main_queue(), ^{
406         CFWriteStreamRef stream = NULL;
407         CFDataRef bytes = NULL;
408         CFIndex ret;
409         KQueueLock();
410 
411         if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(NULL, NULL)))
412         {
413             LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCreateWithAllocatedBuffers failed (Object creation failed)");
414             goto END;
415         }
416         CFWriteStreamOpen(stream);
417         ret = CFPropertyListWrite(valueCopy, stream, kCFPropertyListBinaryFormat_v1_0, 0, NULL);
418         if (ret == 0)
419         {
420             LogMsg("mDNSDynamicStoreSetConfig : CFPropertyListWriteToStream failed (Could not write property list to stream)");
421             goto END;
422         }
423         if (NULL == (bytes = CFWriteStreamCopyProperty(stream, kCFStreamPropertyDataWritten)))
424         {
425             LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCopyProperty failed (Object creation failed) ");
426             goto END;
427         }
428         CFWriteStreamClose(stream);
429         CFRelease(stream);
430         stream = NULL;
431         DynamicStoreWrite(key, subkeyCopy ? subkeyCopy : "", (uintptr_t)CFDataGetBytePtr(bytes), CFDataGetLength(bytes));
432 
433     END:
434         CFRelease(valueCopy);
435         if (NULL != stream)
436         {
437             CFWriteStreamClose(stream);
438             CFRelease(stream);
439         }
440         if (NULL != bytes)
441             CFRelease(bytes);
442         if (subkeyCopy)
443             mDNSPlatformMemFree(subkeyCopy);
444 
445         KQueueUnlock("mDNSDynamicStoreSetConfig");
446     });
447 }
448 
449 // To match *either* a v4 or v6 instance of this interface name, pass AF_UNSPEC for type
SearchForInterfaceByName(const char * ifname,int type)450 mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(const char *ifname, int type)
451 {
452     NetworkInterfaceInfoOSX *i;
453     for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
454         if (i->Exists && !strcmp(i->ifinfo.ifname, ifname) &&
455             ((type == AF_UNSPEC                                         ) ||
456              (type == AF_INET  && i->ifinfo.ip.type == mDNSAddrType_IPv4) ||
457              (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6))) return(i);
458     return(NULL);
459 }
460 
myIfIndexToName(u_short ifindex,char * name)461 mDNSlocal int myIfIndexToName(u_short ifindex, char *name)
462 {
463     struct ifaddrs *ifa;
464     for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
465         if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_LINK)
466             if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == ifindex)
467             { strlcpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; }
468     return -1;
469 }
470 
IfindexToInterfaceInfoOSX(mDNSInterfaceID ifindex)471 mDNSexport NetworkInterfaceInfoOSX *IfindexToInterfaceInfoOSX(mDNSInterfaceID ifindex)
472 {
473     mDNS *const m = &mDNSStorage;
474     mDNSu32 scope_id = (mDNSu32)(uintptr_t)ifindex;
475     NetworkInterfaceInfoOSX *i;
476 
477     // Don't get tricked by inactive interfaces
478     for (i = m->p->InterfaceList; i; i = i->next)
479         if (i->Registered && i->scope_id == scope_id) return(i);
480 
481     return mDNSNULL;
482 }
483 
484 #if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
GetInterfaceMonitorForIndex(uint32_t ifIndex)485 mDNSexport mdns_interface_monitor_t GetInterfaceMonitorForIndex(uint32_t ifIndex)
486 {
487     mDNS *const m = &mDNSStorage;
488 
489     // We assume that interface should always be real interface, and should never be 0.
490     if (ifIndex == 0) return NULL;
491 
492     if (!m->p->InterfaceMonitors)
493     {
494         m->p->InterfaceMonitors = CFArrayCreateMutable(kCFAllocatorDefault, 0, &mdns_cfarray_callbacks);
495         if (!m->p->InterfaceMonitors)
496         {
497             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR, "Failed to create InterfaceMonitors array");
498             return NULL;
499         }
500     }
501 
502     // Search for interface monitor given the interface index.
503     mdns_interface_monitor_t monitor;
504     for (CFIndex i = 0, n = CFArrayGetCount(m->p->InterfaceMonitors); i < n; i++)
505     {
506         monitor = (mdns_interface_monitor_t) CFArrayGetValueAtIndex(m->p->InterfaceMonitors, i);
507         if (mdns_interface_monitor_get_interface_index(monitor) == ifIndex) return monitor;
508     }
509 
510     // If we come here, it means the interface is a new interface that needs to be monitored.
511     monitor = mdns_interface_monitor_create(ifIndex);
512     if (!monitor)
513     {
514         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR, "Failed to create an interface monitor for index %u", ifIndex);
515         return NULL;
516     }
517     CFArrayAppendValue(m->p->InterfaceMonitors, monitor);
518 
519     // Put the monitor into serial queue.
520     mdns_interface_monitor_set_queue(monitor, dispatch_get_main_queue());
521 
522     // When the interface configuration is changed, this block will be called.
523     mdns_interface_monitor_set_update_handler(monitor,
524     ^(mdns_interface_flags_t changeFlags)
525     {
526         const mdns_interface_flags_t relevantFlags =
527             mdns_interface_flag_expensive   |
528             mdns_interface_flag_constrained |
529             mdns_interface_flag_clat46;
530         if ((changeFlags & relevantFlags) == 0) return;
531 
532         KQueueLock();
533         const CFRange range = CFRangeMake(0, CFArrayGetCount(m->p->InterfaceMonitors));
534         if (CFArrayContainsValue(m->p->InterfaceMonitors, range, monitor))
535         {
536             m->p->if_interface_changed = mDNStrue;
537 
538 #if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
539             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "Monitored interface changed: %@", monitor);
540 #endif
541             // Let mDNSResponder update its network configuration.
542             mDNS_Lock(m);
543             SetNetworkChanged((mDNSPlatformOneSecond + 39) / 40);   // 25 ms delay
544             mDNS_Unlock(m);
545         }
546         KQueueUnlock("interface monitor update handler");
547     });
548 
549     mdns_interface_monitor_set_event_handler(monitor,
550     ^(mdns_event_t event, OSStatus error)
551     {
552         switch (event)
553         {
554             case mdns_event_invalidated:
555                 mdns_release(monitor);
556                 break;
557 
558             case mdns_event_error:
559                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR, "Interface monitor for index %u error: %ld",
560                     mdns_interface_monitor_get_interface_index(monitor), (long) error);
561                 KQueueLock();
562                 if (m->p->InterfaceMonitors)
563                 {
564                     const CFRange range = CFRangeMake(0, CFArrayGetCount(m->p->InterfaceMonitors));
565                     const CFIndex i = CFArrayGetFirstIndexOfValue(m->p->InterfaceMonitors, range, monitor);
566                     if (i >= 0) CFArrayRemoveValueAtIndex(m->p->InterfaceMonitors, i);
567                 }
568                 KQueueUnlock("interface monitor event handler");
569                 mdns_interface_monitor_invalidate(monitor);
570                 break;
571 
572             default:
573                 break;
574         }
575     });
576     mdns_interface_monitor_activate(monitor);
577 
578     return monitor;
579 }
580 #endif
581 
mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS * const m,mDNSu32 ifindex)582 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex)
583 {
584     (void) m;
585     if (ifindex == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
586     if (ifindex == kDNSServiceInterfaceIndexP2P      ) return(mDNSInterface_P2P);
587     if (ifindex == kDNSServiceInterfaceIndexBLE      ) return(mDNSInterface_BLE);
588     if (ifindex == kDNSServiceInterfaceIndexAny      ) return(mDNSNULL);
589 
590     NetworkInterfaceInfoOSX* ifi = IfindexToInterfaceInfoOSX((mDNSInterfaceID)(uintptr_t)ifindex);
591     if (!ifi)
592     {
593         // Not found. Make sure our interface list is up to date, then try again.
594         LogInfo("mDNSPlatformInterfaceIDfromInterfaceIndex: InterfaceID for interface index %d not found; Updating interface list", ifindex);
595         mDNSMacOSXNetworkChanged();
596         ifi = IfindexToInterfaceInfoOSX((mDNSInterfaceID)(uintptr_t)ifindex);
597     }
598 
599     if (!ifi) return(mDNSNULL);
600 
601     return(ifi->ifinfo.InterfaceID);
602 }
603 
604 
mDNSPlatformInterfaceIndexfromInterfaceID(mDNS * const m,mDNSInterfaceID id,mDNSBool suppressNetworkChange)605 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id, mDNSBool suppressNetworkChange)
606 {
607     NetworkInterfaceInfoOSX *i;
608     if (id == mDNSInterface_Any      ) return(0);
609     if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
610     if (id == mDNSInterface_P2P      ) return(kDNSServiceInterfaceIndexP2P);
611     if (id == mDNSInterface_BLE      ) return(kDNSServiceInterfaceIndexBLE);
612 
613     mDNSu32 scope_id = (mDNSu32)(uintptr_t)id;
614 
615     // Don't use i->Registered here, because we DO want to find inactive interfaces, which have no Registered set
616     for (i = m->p->InterfaceList; i; i = i->next)
617         if (i->scope_id == scope_id) return(i->scope_id);
618 
619     // If we are supposed to suppress network change, return "id" back
620     if (suppressNetworkChange) return scope_id;
621 
622     // Not found. Make sure our interface list is up to date, then try again.
623     LogInfo("Interface index for InterfaceID %p not found; Updating interface list", id);
624     mDNSMacOSXNetworkChanged();
625     for (i = m->p->InterfaceList; i; i = i->next)
626         if (i->scope_id == scope_id) return(i->scope_id);
627 
628     return(0);
629 }
630 
GetInterfaceSupportsWakeOnLANPacket(mDNSInterfaceID id)631 mDNSlocal mDNSBool GetInterfaceSupportsWakeOnLANPacket(mDNSInterfaceID id)
632 {
633     NetworkInterfaceInfoOSX *info = IfindexToInterfaceInfoOSX(id);
634     if (info == NULL)
635     {
636         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR, "GetInterfaceSupportsWakeOnLANPacket: Invalid interface id %p", id);
637         return mDNSfalse;
638     }
639     else
640     {
641         return (info->ift_family == IFRTYPE_FAMILY_ETHERNET) ? mDNStrue : mDNSfalse;
642     }
643 }
644 
GetIFTFamily(const char * _Nonnull if_name)645 mDNSlocal uint32_t GetIFTFamily(const char * _Nonnull if_name)
646 {
647     uint32_t ift_family = IFRTYPE_FAMILY_ANY;
648     int s = socket(AF_INET, SOCK_DGRAM, 0);
649     if (s == -1)
650     {
651         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR, "GetIFTFamily: socket() failed: " PUB_S, strerror(errno));
652         return ift_family;
653     }
654     struct ifreq ifr;
655     memset(&ifr, 0, sizeof(ifr));
656     strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
657     if (ioctl(s, SIOCGIFTYPE, (caddr_t)&ifr) == -1)
658     {
659         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "GetIFTFamily: SIOCGIFTYPE failed: " PUB_S, strerror(errno));
660     }
661     else
662     {
663         ift_family = ifr.ifr_type.ift_family;
664     }
665     close(s);
666     return ift_family;
667 }
668 
669 #if COMPILER_LIKES_PRAGMA_MARK
670 #pragma mark -
671 #pragma mark - UDP & TCP send & receive
672 #endif
673 
AddrRequiresPPPConnection(const struct sockaddr * addr)674 mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr)
675 {
676     mDNSBool result = mDNSfalse;
677     SCNetworkConnectionFlags flags;
678     CFDataRef remote_addr;
679     CFMutableDictionaryRef options;
680     SCNetworkReachabilityRef ReachRef = NULL;
681 
682     options = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
683     remote_addr = CFDataCreate(NULL, (const UInt8 *)addr, addr->sa_len);
684     CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, remote_addr);
685     CFDictionarySetValue(options, kSCNetworkReachabilityOptionServerBypass, kCFBooleanTrue);
686     ReachRef = SCNetworkReachabilityCreateWithOptions(kCFAllocatorDefault, options);
687     CFRelease(options);
688     CFRelease(remote_addr);
689 
690     if (!ReachRef)
691     {
692         LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithOptions");
693         goto end;
694     }
695     if (!SCNetworkReachabilityGetFlags(ReachRef, &flags))
696     {
697         LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags");
698         goto end;
699     }
700     result = flags & kSCNetworkFlagsConnectionRequired;
701 
702 end:
703     if (ReachRef)
704         CFRelease(ReachRef);
705     return result;
706 }
707 
708 // Set traffic class for socket
setTrafficClass(int socketfd,mDNSBool useBackgroundTrafficClass)709 mDNSlocal void setTrafficClass(int socketfd, mDNSBool useBackgroundTrafficClass)
710 {
711     int traffic_class;
712 
713     if (useBackgroundTrafficClass)
714         traffic_class = SO_TC_BK_SYS;
715     else
716         traffic_class = SO_TC_CTL;
717 
718     (void) setsockopt(socketfd, SOL_SOCKET, SO_TRAFFIC_CLASS, (void *)&traffic_class, sizeof(traffic_class));
719 }
720 
721 #ifdef UNIT_TEST
722 UNITTEST_SETSOCKOPT
723 #else
724 mDNSlocal int mDNSPlatformGetSocktFd(void *sockCxt, mDNSTransport_Type transType, mDNSAddr_Type addrType)
725 {
726     if (transType == mDNSTransport_UDP)
727     {
728         UDPSocket* sock = (UDPSocket*) sockCxt;
729         return (addrType == mDNSAddrType_IPv4) ? sock->ss.sktv4 : sock->ss.sktv6;
730     }
731     else if (transType == mDNSTransport_TCP)
732     {
733         TCPSocket* sock = (TCPSocket*) sockCxt;
734         return sock->fd;
735     }
736     else
737     {
738         LogInfo("mDNSPlatformGetSocktFd: invalid transport %d", transType);
739         return kInvalidSocketRef;
740     }
741 }
742 
743 mDNSexport void mDNSPlatformSetSocktOpt(void *sockCxt, mDNSTransport_Type transType, mDNSAddr_Type addrType, const DNSQuestion *q)
744 {
745     int sockfd;
746     char unenc_name[MAX_ESCAPED_DOMAIN_NAME];
747 
748     // verify passed-in arguments exist and that sockfd is valid
749     if (q == mDNSNULL || sockCxt == mDNSNULL || (sockfd = mDNSPlatformGetSocktFd(sockCxt, transType, addrType)) < 0)
750         return;
751 
752     if (q->pid)
753     {
754         if (setsockopt(sockfd, SOL_SOCKET, SO_DELEGATED, &q->pid, sizeof(q->pid)) == -1)
755             LogMsg("mDNSPlatformSetSocktOpt: Delegate PID failed %s for PID %d", strerror(errno), q->pid);
756     }
757     else
758     {
759         if (setsockopt(sockfd, SOL_SOCKET, SO_DELEGATED_UUID, &q->uuid, sizeof(q->uuid)) == -1)
760             LogMsg("mDNSPlatformSetSocktOpt: Delegate UUID failed %s", strerror(errno));
761     }
762 
763     // set the domain on the socket
764     ConvertDomainNameToCString(&q->qname, unenc_name);
765     if (!(ne_session_set_socket_attributes(sockfd, unenc_name, NULL)))
766         LogInfo("mDNSPlatformSetSocktOpt: ne_session_set_socket_attributes()-> setting domain failed for %s", unenc_name);
767 
768     int nowake = 1;
769     if (setsockopt(sockfd, SOL_SOCKET, SO_NOWAKEFROMSLEEP, &nowake, sizeof(nowake)) == -1)
770         LogInfo("mDNSPlatformSetSocktOpt: SO_NOWAKEFROMSLEEP failed %s", strerror(errno));
771 }
772 #endif // UNIT_TEST
773 
774 // Note: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
775 // Note: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
776 // OR send via our primary v4 unicast socket
777 // UPDATE: The UDPSocket *src parameter now allows the caller to specify the source socket
mDNSPlatformSendUDP(const mDNS * const m,const void * const msg,const mDNSu8 * const end,mDNSInterfaceID InterfaceID,UDPSocket * src,const mDNSAddr * dst,mDNSIPPort dstPort,mDNSBool useBackgroundTrafficClass)778 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
779                                        mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,
780                                        mDNSIPPort dstPort, mDNSBool useBackgroundTrafficClass)
781 {
782     NetworkInterfaceInfoOSX *info = mDNSNULL;
783     struct sockaddr_storage to;
784     int s = -1;
785     mStatus result = mStatus_NoError;
786     ssize_t sentlen;
787     int sendto_errno;
788     const DNSMessage *const dns_msg = msg;
789 
790     if (InterfaceID)
791     {
792         info = IfindexToInterfaceInfoOSX(InterfaceID);
793         if (info == NULL)
794         {
795             // We may not have registered interfaces with the "core" as we may not have
796             // seen any interface notifications yet. This typically happens during wakeup
797             // where we might try to send DNS requests (non-SuppressUnusable questions internal
798             // to mDNSResponder) before we receive network notifications.
799             LogInfo("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
800             return mStatus_BadParamErr;
801         }
802     }
803 
804     char *ifa_name = InterfaceID ? info->ifinfo.ifname : "unicast";
805 
806     if (dst->type == mDNSAddrType_IPv4)
807     {
808         struct sockaddr_in *sin_to = (struct sockaddr_in*)&to;
809         sin_to->sin_len            = sizeof(*sin_to);
810         sin_to->sin_family         = AF_INET;
811         sin_to->sin_port           = dstPort.NotAnInteger;
812         sin_to->sin_addr.s_addr    = dst->ip.v4.NotAnInteger;
813         s = (src ? src->ss : m->p->permanentsockets).sktv4;
814 
815         if (!mDNSAddrIsDNSMulticast(dst))
816         {
817         #ifdef IP_BOUND_IF
818             const mDNSu32 ifindex = info ? info->scope_id : IFSCOPE_NONE;
819             setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &ifindex, sizeof(ifindex));
820         #else
821             static int displayed = 0;
822             if (displayed < 1000)
823             {
824                 displayed++;
825                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
826                           "[Q%u] IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets",
827                           mDNSVal16(dns_msg->h.id));
828             }
829         #endif
830         }
831         else if (info)
832         {
833             int err;
834         #ifdef IP_MULTICAST_IFINDEX
835             err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IFINDEX, &info->scope_id, sizeof(info->scope_id));
836             // We get an error when we compile on a machine that supports this option and run the binary on
837             // a different machine that does not support it
838             if (err < 0)
839             {
840                 if (errno != ENOPROTOOPT)
841                 {
842                     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
843                               "[Q%u] mDNSPlatformSendUDP: setsockopt: IP_MUTLTICAST_IFINDEX returned %d",
844                               mDNSVal16(dns_msg->h.id), errno);
845                 }
846                 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
847                 if (err < 0 && !m->NetworkChanged)
848                 {
849                     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
850                               "[Q%u] setsockopt - IP_MULTICAST_IF error " PRI_IPv4_ADDR " %d errno %d (" PUB_S ")",
851                               mDNSVal16(dns_msg->h.id), &info->ifa_v4addr, err, errno, strerror(errno));
852                 }
853             }
854         #else
855             err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
856             if (err < 0 && !m->NetworkChanged)
857             {
858                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
859                           "[Q%u] setsockopt - IP_MULTICAST_IF error " PRI_IPv4_ADDR " %d errno %d (" PUB_S ")",
860                           mDNSVal16(dns_msg->h.id), &info->ifa_v4addr, err, errno, strerror(errno));
861             }
862         #endif
863         }
864     }
865     else if (dst->type == mDNSAddrType_IPv6)
866     {
867         struct sockaddr_in6 *sin6_to = (struct sockaddr_in6*)&to;
868         sin6_to->sin6_len            = sizeof(*sin6_to);
869         sin6_to->sin6_family         = AF_INET6;
870         sin6_to->sin6_port           = dstPort.NotAnInteger;
871         sin6_to->sin6_flowinfo       = 0;
872         sin6_to->sin6_addr           = *(struct in6_addr*)&dst->ip.v6;
873         sin6_to->sin6_scope_id       = info ? info->scope_id : 0;
874         s = (src ? src->ss : m->p->permanentsockets).sktv6;
875         if (info && mDNSAddrIsDNSMulticast(dst))    // Specify outgoing interface
876         {
877             const int err = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &info->scope_id, sizeof(info->scope_id));
878             if (err < 0)
879             {
880                 const int setsockopt_errno = errno;
881                 char name[IFNAMSIZ];
882                 if (if_indextoname(info->scope_id, name) != NULL)
883                 {
884                     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
885                               "[Q%u] setsockopt - IPV6_MULTICAST_IF error %d errno %d (" PUB_S ")",
886                               mDNSVal16(dns_msg->h.id), err, setsockopt_errno, strerror(setsockopt_errno));
887                 }
888                 else
889                 {
890                     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
891                               "[Q%u] setsockopt - IPV6_MUTLICAST_IF scopeid %d, not a valid interface",
892                               mDNSVal16(dns_msg->h.id), info->scope_id);
893                 }
894             }
895         }
896 #ifdef IPV6_BOUND_IF
897         if (info)   // Specify outgoing interface for non-multicast destination
898         {
899             if (!mDNSAddrIsDNSMulticast(dst))
900             {
901                 if (info->scope_id == 0)
902                 {
903                     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
904                               "[Q%u] IPV6_BOUND_IF socket option not set -- info %p (" PUB_S ") scope_id is zero",
905                               mDNSVal16(dns_msg->h.id), info, ifa_name);
906                 }
907                 else
908                 {
909                     setsockopt(s, IPPROTO_IPV6, IPV6_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
910                 }
911             }
912         }
913 #endif
914     }
915     else
916     {
917         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_FAULT,
918                   "[Q%u] mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!", mDNSVal16(dns_msg->h.id));
919         return mStatus_BadParamErr;
920     }
921 
922     if (s >= 0)
923     {
924         verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
925                       InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s);
926     }
927     else
928     {
929         verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
930                       InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort));
931     }
932 
933     // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
934     // If we don't have the corresponding type of socket available, then return mStatus_Invalid
935     if (s < 0) return(mStatus_Invalid);
936 
937     // switch to background traffic class for this message if requested
938     if (useBackgroundTrafficClass)
939         setTrafficClass(s, useBackgroundTrafficClass);
940 
941     sentlen = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len);
942     sendto_errno = (sentlen < 0) ? errno : 0;
943 
944     // set traffic class back to default value
945     if (useBackgroundTrafficClass)
946         setTrafficClass(s, mDNSfalse);
947 
948     if (sentlen < 0)
949     {
950         static int MessageCount = 0;
951         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
952             "[Q%u] mDNSPlatformSendUDP -> sendto(%d) failed to send packet on InterfaceID %p " PUB_S "/%d to " PRI_IP_ADDR ":%d skt %d error %ld errno %d (" PUB_S ") %u",
953             mDNSVal16(dns_msg->h.id), s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, (long)sentlen, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow));
954         if (!mDNSAddressIsAllDNSLinkGroup(dst))
955         {
956             if ((sendto_errno == EHOSTUNREACH) || (sendto_errno == ENETUNREACH)) return(mStatus_HostUnreachErr);
957             if ((sendto_errno == EHOSTDOWN)    || (sendto_errno == ENETDOWN))    return(mStatus_TransientErr);
958         }
959         // Don't report EHOSTUNREACH in the first three minutes after boot
960         // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
961         // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
962         if (sendto_errno == EHOSTUNREACH && (mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(mStatus_TransientErr);
963         // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
964         if (sendto_errno == EADDRNOTAVAIL && m->NetworkChanged) return(mStatus_TransientErr);
965         if (sendto_errno == EHOSTUNREACH || sendto_errno == EADDRNOTAVAIL || sendto_errno == ENETDOWN)
966         {
967             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
968                 "[Q%u] mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p " PUB_S "/%d to " PRI_IP_ADDR ":%d skt %d error %ld errno %d (" PUB_S ") %u",
969                 mDNSVal16(dns_msg->h.id), s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, (long)sentlen, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow));
970         }
971         else
972         {
973             MessageCount++;
974             if (MessageCount < 50) // Cap and ensure NO spamming of LogMsgs
975             {
976                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
977                     "[Q%u] mDNSPlatformSendUDP: sendto(%d) failed to send packet on InterfaceID %p " PUB_S "/%d to " PRI_IP_ADDR ":%d skt %d error %ld errno %d (" PUB_S ") %u MessageCount is %d",
978                     mDNSVal16(dns_msg->h.id), s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, (long)sentlen, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow), MessageCount);
979             }
980             else // If logging is enabled, remove the cap and log aggressively
981             {
982                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
983                     "[Q%u] mDNSPlatformSendUDP: sendto(%d) failed to send packet on InterfaceID %p " PUB_S "/%d to " PRI_IP_ADDR ":%d skt %d error %ld errno %d (" PUB_S ") %u MessageCount is %d",
984                     mDNSVal16(dns_msg->h.id), s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, (long)sentlen, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow), MessageCount);
985             }
986         }
987 
988         result = mStatus_UnknownErr;
989     }
990 
991     return(result);
992 }
993 
myrecvfrom(const int s,void * const buffer,const size_t max,struct sockaddr * const from,socklen_t * const fromlen,mDNSAddr * dstaddr,char ifname[IF_NAMESIZE],mDNSu8 * ttl)994 mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
995                              struct sockaddr *const from, socklen_t *const fromlen, mDNSAddr *dstaddr, char ifname[IF_NAMESIZE], mDNSu8 *ttl)
996 {
997     static unsigned int numLogMessages = 0;
998     struct iovec databuffers = { (char *)buffer, max };
999     struct msghdr msg;
1000     ssize_t n;
1001     struct cmsghdr *cmPtr;
1002     char ancillary[1024];
1003 
1004     *ttl = 255;  // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
1005 
1006     // Set up the message
1007     msg.msg_name       = (caddr_t)from;
1008     msg.msg_namelen    = *fromlen;
1009     msg.msg_iov        = &databuffers;
1010     msg.msg_iovlen     = 1;
1011     msg.msg_control    = (caddr_t)&ancillary;
1012     msg.msg_controllen = sizeof(ancillary);
1013     msg.msg_flags      = 0;
1014 
1015     // Receive the data
1016     n = recvmsg(s, &msg, 0);
1017     if (n<0)
1018     {
1019         if (errno != EWOULDBLOCK && numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s, n, errno);
1020         return(-1);
1021     }
1022     if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
1023     {
1024         if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu, errno %d",
1025                                            s, n, msg.msg_controllen, sizeof(struct cmsghdr), errno);
1026         return(-1);
1027     }
1028     // Note: MSG_TRUNC means the datagram was truncated, while MSG_CTRUNC means that the control data was truncated.
1029     // The mDNS core is capable of handling truncated DNS messages, so MSG_TRUNC isn't checked.
1030     if (msg.msg_flags & MSG_CTRUNC)
1031     {
1032         if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
1033         return(-1);
1034     }
1035 
1036     *fromlen = msg.msg_namelen;
1037 
1038     // Parse each option out of the ancillary data.
1039     for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
1040     {
1041         // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
1042         if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVDSTADDR)
1043         {
1044             dstaddr->type = mDNSAddrType_IPv4;
1045             dstaddr->ip.v4 = *(mDNSv4Addr*)CMSG_DATA(cmPtr);
1046             //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
1047         }
1048         if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF)
1049         {
1050             struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr);
1051             if (sdl->sdl_nlen < IF_NAMESIZE)
1052             {
1053                 mDNSPlatformMemCopy(ifname, sdl->sdl_data, sdl->sdl_nlen);
1054                 ifname[sdl->sdl_nlen] = 0;
1055                 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
1056             }
1057         }
1058         if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVTTL)
1059             *ttl = *(u_char*)CMSG_DATA(cmPtr);
1060         if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_PKTINFO)
1061         {
1062             struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmPtr);
1063             dstaddr->type = mDNSAddrType_IPv6;
1064             dstaddr->ip.v6 = *(mDNSv6Addr*)&ip6_info->ipi6_addr;
1065             myIfIndexToName(ip6_info->ipi6_ifindex, ifname);
1066         }
1067         if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT)
1068             *ttl = *(int*)CMSG_DATA(cmPtr);
1069     }
1070 
1071     return(n);
1072 }
1073 
1074 // What is this for, and why does it use xor instead of a simple equality check? -- SC
FindMyInterface(const mDNSAddr * addr)1075 mDNSlocal mDNSInterfaceID FindMyInterface(const mDNSAddr *addr)
1076 {
1077     NetworkInterfaceInfo *intf;
1078 
1079     if (addr->type == mDNSAddrType_IPv4)
1080     {
1081         for (intf = mDNSStorage.HostInterfaces; intf; intf = intf->next)
1082         {
1083             if (intf->ip.type == addr->type && intf->McastTxRx)
1084             {
1085                 if ((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) == 0)
1086                 {
1087                     return(intf->InterfaceID);
1088                 }
1089             }
1090         }
1091     }
1092 
1093     if (addr->type == mDNSAddrType_IPv6)
1094     {
1095         for (intf = mDNSStorage.HostInterfaces; intf; intf = intf->next)
1096         {
1097             if (intf->ip.type == addr->type && intf->McastTxRx)
1098             {
1099                 if (((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) == 0) &&
1100                     ((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) == 0) &&
1101                     ((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) == 0) &&
1102                     (((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) == 0)))
1103                     {
1104                         return(intf->InterfaceID);
1105                     }
1106             }
1107         }
1108     }
1109     return(mDNSInterface_Any);
1110 }
1111 
myKQSocketCallBack(int s1,short filter,void * context,mDNSBool encounteredEOF)1112 mDNSexport void myKQSocketCallBack(int s1, short filter, void *context, mDNSBool encounteredEOF)
1113 {
1114     KQSocketSet *const ss = (KQSocketSet *)context;
1115     mDNS *const m = ss->m;
1116     ssize_t recvlen;
1117     int count = 0, closed = 0, recvfrom_errno = 0;
1118 
1119     if (filter != EVFILT_READ)
1120         LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter, EVFILT_READ);
1121 
1122     if (s1 != ss->sktv4 && s1 != ss->sktv6)
1123     {
1124         LogMsg("myKQSocketCallBack: native socket %d", s1);
1125         LogMsg("myKQSocketCallBack: sktv4 %d sktv6 %d", ss->sktv4, ss->sktv6);
1126     }
1127 
1128     if (encounteredEOF)
1129     {
1130         LogMsg("myKQSocketCallBack: socket %d is no longer readable (EOF)", s1);
1131         if (s1 == ss->sktv4)
1132         {
1133             ss->sktv4EOF = mDNStrue;
1134             KQueueSet(ss->sktv4, EV_DELETE, EVFILT_READ, &ss->kqsv4);
1135         }
1136         else if (s1 == ss->sktv6)
1137         {
1138             ss->sktv6EOF = mDNStrue;
1139             KQueueSet(ss->sktv6, EV_DELETE, EVFILT_READ, &ss->kqsv6);
1140         }
1141         return;
1142     }
1143 
1144     while (!closed)
1145     {
1146         mDNSAddr senderAddr, destAddr = zeroAddr;
1147         mDNSIPPort senderPort;
1148         struct sockaddr_storage from;
1149         socklen_t fromlen = sizeof(from);
1150         char packetifname[IF_NAMESIZE] = "";
1151         mDNSu8 ttl;
1152         recvlen = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl);
1153         if (recvlen < 0)
1154         {
1155             recvfrom_errno = errno;
1156             break;
1157         }
1158 
1159         if ((destAddr.type == mDNSAddrType_IPv4 && (destAddr.ip.v4.b[0] & 0xF0) == 0xE0) ||
1160             (destAddr.type == mDNSAddrType_IPv6 && (destAddr.ip.v6.b[0]         == 0xFF))) m->p->num_mcasts++;
1161 
1162         count++;
1163         if (from.ss_family == AF_INET)
1164         {
1165             struct sockaddr_in *s = (struct sockaddr_in*)&from;
1166             senderAddr.type = mDNSAddrType_IPv4;
1167             senderAddr.ip.v4.NotAnInteger = s->sin_addr.s_addr;
1168             senderPort.NotAnInteger = s->sin_port;
1169             //LogInfo("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1170         }
1171         else if (from.ss_family == AF_INET6)
1172         {
1173             struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&from;
1174             senderAddr.type = mDNSAddrType_IPv6;
1175             senderAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
1176             senderPort.NotAnInteger = sin6->sin6_port;
1177             //LogInfo("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1178         }
1179         else
1180         {
1181             LogMsg("myKQSocketCallBack from is unknown address family %d", from.ss_family);
1182             return;
1183         }
1184 
1185         // Note: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
1186         mDNSInterfaceID InterfaceID = mDNSNULL;
1187         NetworkInterfaceInfoOSX *intf = m->p->InterfaceList;
1188         while (intf)
1189         {
1190             if (intf->Exists && !strcmp(intf->ifinfo.ifname, packetifname))
1191                 break;
1192             intf = intf->next;
1193         }
1194 
1195         // When going to sleep we deregister all our interfaces, but if the machine
1196         // takes a few seconds to sleep we may continue to receive multicasts
1197         // during that time, which would confuse mDNSCoreReceive, because as far
1198         // as it's concerned, we should have no active interfaces any more.
1199         // Hence we ignore multicasts for which we can find no matching InterfaceID.
1200         if (intf)
1201             InterfaceID = intf->ifinfo.InterfaceID;
1202         else if (mDNSAddrIsDNSMulticast(&destAddr))
1203             continue;
1204 
1205         if (!InterfaceID)
1206         {
1207             InterfaceID = FindMyInterface(&destAddr);
1208         }
1209 
1210 //      LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
1211 //          &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
1212 
1213         // mDNSCoreReceive may close the socket we're reading from.  We must break out of our
1214         // loop when that happens, or we may try to read from an invalid FD.  We do this by
1215         // setting the closeFlag pointer in the socketset, so CloseSocketSet can inform us
1216         // if it closes the socketset.
1217         ss->closeFlag = &closed;
1218 
1219         if (ss->proxy)
1220         {
1221             m->p->UDPProxyCallback(&m->p->UDPProxy, &m->imsg.m, (unsigned char*)&m->imsg + recvlen, &senderAddr,
1222                 senderPort, &destAddr, ss->port, InterfaceID, NULL);
1223         }
1224         else
1225         {
1226             mDNSCoreReceive(m, &m->imsg.m, (unsigned char*)&m->imsg + recvlen, &senderAddr, senderPort, &destAddr, ss->port, InterfaceID);
1227         }
1228 
1229         // if we didn't close, we can safely dereference the socketset, and should to
1230         // reset the closeFlag, since it points to something on the stack
1231         if (!closed) ss->closeFlag = mDNSNULL;
1232     }
1233 
1234     // If a client application's sockets are marked as defunct
1235     // sockets we have delegated to it with SO_DELEGATED will also go defunct.
1236     // We get an ENOTCONN error for defunct sockets and should just close the socket in that case.
1237     if (recvlen < 0 && recvfrom_errno == ENOTCONN)
1238     {
1239         LogInfo("myKQSocketCallBack: ENOTCONN, closing socket");
1240         close(s1);
1241         return;
1242     }
1243 
1244     if (recvlen < 0 && (recvfrom_errno != EWOULDBLOCK || count == 0))
1245     {
1246         // Something is busted here.
1247         // kqueue says there is a packet, but myrecvfrom says there is not.
1248         // Try calling select() to get another opinion.
1249         // Find out about other socket parameter that can help understand why select() says the socket is ready for read
1250         // All of this is racy, as data may have arrived after the call to select()
1251         static unsigned int numLogMessages = 0;
1252         int so_error = -1;
1253         int so_nread = -1;
1254         int fionread = -1;
1255         socklen_t solen;
1256         fd_set readfds;
1257         struct timeval timeout;
1258         int selectresult;
1259         FD_ZERO(&readfds);
1260         FD_SET(s1, &readfds);
1261         timeout.tv_sec  = 0;
1262         timeout.tv_usec = 0;
1263         selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
1264         solen = (socklen_t)sizeof(so_error);
1265         if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1)
1266             LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno);
1267         solen = (socklen_t)sizeof(so_nread);
1268         if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1)
1269             LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno);
1270         if (ioctl(s1, FIONREAD, &fionread) == -1)
1271             LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno);
1272         if (numLogMessages++ < 100)
1273             LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
1274                    s1, (int)recvlen, recvfrom_errno, strerror(recvfrom_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
1275         if (numLogMessages > 5)
1276             NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
1277                                "Congratulations, you've reproduced an elusive bug.\r"
1278                                "Please send email to radar-3387020@group.apple.com.)\r"
1279                                "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1280 
1281         sleep(1);       // After logging this error, rate limit so we don't flood syslog
1282     }
1283 }
1284 
doTcpSocketCallback(TCPSocket * sock)1285 mDNSlocal void doTcpSocketCallback(TCPSocket *sock)
1286 {
1287     mDNSBool c = !sock->connected;
1288     if (!sock->connected && sock->err == mStatus_NoError)
1289     {
1290         sock->connected = mDNStrue;
1291     }
1292     sock->callback(sock, sock->context, c, sock->err);
1293     // Note: the callback may call CloseConnection here, which frees the context structure!
1294 }
1295 
1296 #ifndef NO_SECURITYFRAMEWORK
1297 
tlsWriteSock(SSLConnectionRef connection,const void * data,size_t * dataLength)1298 mDNSlocal OSStatus tlsWriteSock(SSLConnectionRef connection, const void *data, size_t *dataLength)
1299 {
1300     const ssize_t ret = send(((TCPSocket *)connection)->fd, data, *dataLength, 0);
1301     if (ret >= 0 && (size_t)ret < *dataLength) { *dataLength = (size_t)ret; return(errSSLWouldBlock); }
1302     if (ret >= 0)                              { *dataLength = (size_t)ret; return(noErr); }
1303     *dataLength = 0;
1304     if (errno == EAGAIN                      ) return(errSSLWouldBlock);
1305     if (errno == ENOENT                      ) return(errSSLClosedGraceful);
1306     if (errno == EPIPE || errno == ECONNRESET) return(errSSLClosedAbort);
1307     LogMsg("ERROR: tlsWriteSock: %d error %d (%s)\n", ((TCPSocket *)connection)->fd, errno, strerror(errno));
1308     return(errSSLClosedAbort);
1309 }
1310 
tlsReadSock(SSLConnectionRef connection,void * data,size_t * dataLength)1311 mDNSlocal OSStatus tlsReadSock(SSLConnectionRef connection, void *data, size_t *dataLength)
1312 {
1313     const ssize_t ret = recv(((TCPSocket *)connection)->fd, data, *dataLength, 0);
1314     if (ret > 0 && (size_t)ret < *dataLength) { *dataLength = (size_t)ret; return(errSSLWouldBlock); }
1315     if (ret > 0)                              { *dataLength = (size_t)ret; return(noErr); }
1316     *dataLength = 0;
1317     if (ret == 0 || errno == ENOENT    ) return(errSSLClosedGraceful);
1318     if (            errno == EAGAIN    ) return(errSSLWouldBlock);
1319     if (            errno == ECONNRESET) return(errSSLClosedAbort);
1320     LogMsg("ERROR: tlsSockRead: error %d (%s)\n", errno, strerror(errno));
1321     return(errSSLClosedAbort);
1322 }
1323 
tlsSetupSock(TCPSocket * sock,SSLProtocolSide pside,SSLConnectionType ctype)1324 mDNSlocal OSStatus tlsSetupSock(TCPSocket *sock, SSLProtocolSide pside, SSLConnectionType ctype)
1325 {
1326     char domname_cstr[MAX_ESCAPED_DOMAIN_NAME];
1327 
1328 #pragma clang diagnostic push
1329 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1330     sock->tlsContext = SSLCreateContext(kCFAllocatorDefault, pside, ctype);
1331     if (!sock->tlsContext)
1332     {
1333         LogMsg("ERROR: tlsSetupSock: SSLCreateContext failed");
1334         return(mStatus_UnknownErr);
1335     }
1336 
1337     mStatus err = SSLSetIOFuncs(sock->tlsContext, tlsReadSock, tlsWriteSock);
1338     if (err)
1339     {
1340         LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err);
1341         goto fail;
1342     }
1343 
1344     err = SSLSetConnection(sock->tlsContext, (SSLConnectionRef) sock);
1345     if (err)
1346     {
1347         LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err);
1348         goto fail;
1349     }
1350 
1351     // Set the default ciphersuite configuration
1352     err = SSLSetSessionConfig(sock->tlsContext, CFSTR("default"));
1353     if (err)
1354     {
1355         LogMsg("ERROR: tlsSetupSock: SSLSetSessionConfig failed with error code: %d", err);
1356         goto fail;
1357     }
1358 
1359     // We already checked for NULL in hostname and this should never happen. Hence, returning -1
1360     // (error not in OSStatus space) is okay.
1361     if (!sock->hostname || !sock->hostname->c[0])
1362     {
1363         LogMsg("ERROR: tlsSetupSock: hostname NULL");
1364         err = -1;
1365         goto fail;
1366     }
1367 
1368     ConvertDomainNameToCString(sock->hostname, domname_cstr);
1369     err = SSLSetPeerDomainName(sock->tlsContext, domname_cstr, strlen(domname_cstr));
1370     if (err)
1371     {
1372         LogMsg("ERROR: tlsSetupSock: SSLSetPeerDomainname: %s failed with error code: %d", domname_cstr, err);
1373         goto fail;
1374     }
1375 #pragma clang diagnostic pop
1376     return(err);
1377 
1378 fail:
1379     if (sock->tlsContext)
1380         CFRelease(sock->tlsContext);
1381     return(err);
1382 }
1383 
1384 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
doSSLHandshake(TCPSocket * sock)1385 mDNSlocal void doSSLHandshake(TCPSocket *sock)
1386 {
1387     mStatus err = SSLHandshake(sock->tlsContext);
1388 
1389     //Can't have multiple threads in mDNS core. When MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM is
1390     //defined, KQueueLock is a noop. Hence we need to serialize here
1391     //
1392     //NOTE: We just can't serialize doTcpSocketCallback alone on the main queue.
1393     //We need the rest of the logic also. Otherwise, we can enable the READ
1394     //events below, dispatch a doTcpSocketCallback on the main queue. Assume it is
1395     //ConnFailed which means we are going to free the tcpInfo. While it
1396     //is waiting to be dispatched, another read event can come into tcpKQSocketCallback
1397     //and potentially call doTCPCallback with error which can close the fd and free the
1398     //tcpInfo. Later when the thread gets dispatched it will crash because the tcpInfo
1399     //is already freed.
1400 
1401     dispatch_async(dispatch_get_main_queue(), ^{
1402 
1403                        LogInfo("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
1404 
1405                        if (sock->handshake == handshake_to_be_closed)
1406                        {
1407                            LogInfo("SSLHandshake completed after close");
1408                            mDNSPlatformTCPCloseConnection(sock);
1409                        }
1410                        else
1411                        {
1412                            if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
1413                            else LogMsg("doSSLHandshake: sock->fd is -1");
1414 
1415                            if (err == errSSLWouldBlock)
1416                                sock->handshake = handshake_required;
1417                            else
1418                            {
1419                                if (err)
1420                                {
1421                                    LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
1422                                    CFRelease(sock->tlsContext);
1423                                    sock->tlsContext = NULL;
1424                                }
1425 
1426                                sock->err = err ? mStatus_ConnFailed : 0;
1427                                sock->handshake = handshake_completed;
1428 
1429                                LogInfo("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
1430                                doTcpSocketCallback(sock);
1431                            }
1432                        }
1433 
1434                        LogInfo("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
1435                        return;
1436                    });
1437 }
1438 #else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
doSSLHandshake(TCPSocket * sock)1439 mDNSlocal void *doSSLHandshake(TCPSocket *sock)
1440 {
1441     // Warning: Touching sock without the kqueue lock!
1442     // We're protected because sock->handshake == handshake_in_progress
1443 #pragma clang diagnostic push
1444 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1445     mStatus err = SSLHandshake(sock->tlsContext);
1446 #pragma clang diagnostic pop
1447     KQueueLock();
1448     debugf("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
1449 
1450     if (sock->handshake == handshake_to_be_closed)
1451     {
1452         LogInfo("SSLHandshake completed after close");
1453         mDNSPlatformTCPCloseConnection(sock);
1454     }
1455     else
1456     {
1457         if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry);
1458         else LogMsg("doSSLHandshake: sock->fd is -1");
1459 
1460         if (err == errSSLWouldBlock)
1461             sock->handshake = handshake_required;
1462         else
1463         {
1464             if (err)
1465             {
1466                 LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
1467                 CFRelease(sock->tlsContext);
1468                 sock->tlsContext = NULL;
1469             }
1470 
1471             sock->err = err ? mStatus_ConnFailed : 0;
1472             sock->handshake = handshake_completed;
1473 
1474             debugf("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
1475             doTcpSocketCallback(sock);
1476         }
1477     }
1478 
1479     debugf("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
1480     KQueueUnlock("doSSLHandshake");
1481     return NULL;
1482 }
1483 #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1484 
spawnSSLHandshake(TCPSocket * sock)1485 mDNSlocal void spawnSSLHandshake(TCPSocket* sock)
1486 {
1487     debugf("spawnSSLHandshake %p: entry", sock);
1488 
1489     if (sock->handshake != handshake_required) LogMsg("spawnSSLHandshake: handshake status not required: %d", sock->handshake);
1490     sock->handshake = handshake_in_progress;
1491     KQueueSet(sock->fd, EV_DELETE, EVFILT_READ, &sock->kqEntry);
1492 
1493     // Dispatch it on a separate queue to help avoid blocking other threads/queues, and
1494     // to limit the number of threads used for SSLHandshake
1495     dispatch_async(SSLqueue, ^{doSSLHandshake(sock);});
1496 
1497     debugf("spawnSSLHandshake %p: done for %d", sock, sock->fd);
1498 }
1499 
1500 #endif /* NO_SECURITYFRAMEWORK */
1501 
tcpKQSocketCallback(__unused int fd,short filter,void * context,__unused mDNSBool encounteredEOF)1502 mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context, __unused mDNSBool encounteredEOF)
1503 {
1504     TCPSocket *sock = context;
1505     sock->err = mStatus_NoError;
1506 
1507     //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
1508     //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
1509     // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
1510     if (filter == EVFILT_WRITE)
1511     {
1512         // sock->connected gets set by doTcpSocketCallback(), which may be called from here, or may be called
1513         // from the TLS connect code.   If we asked for a writability test, we are connecting
1514         // (sock->connected == mDNSFalse).
1515         if (sock->connected)
1516         {
1517             LogInfo("ERROR: TCPConnectCallback called with write event when socket is connected.");
1518         }
1519         else
1520         {
1521             int result = 0;
1522             socklen_t len = (socklen_t)sizeof(result);
1523             if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &result, &len) < 0)
1524             {
1525                 LogInfo("ERROR: TCPConnectCallback - unable to get connect error: socket %d: Error %d (%s)",
1526                         sock->fd, errno, strerror(errno));
1527                 sock->err = mStatus_ConnFailed;
1528             }
1529             else
1530             {
1531                 if (result != 0)
1532                 {
1533                     sock->err = mStatus_ConnFailed;
1534                     if (result == EHOSTUNREACH || result == EADDRNOTAVAIL || result == ENETDOWN)
1535                     {
1536                         LogInfo("ERROR: TCPConnectCallback - connect failed: socket %d: Error %d (%s)",
1537                                 sock->fd, result, strerror(result));
1538                     }
1539                     else
1540                     {
1541                         LogMsg("ERROR: TCPConnectCallback - connect failed: socket %d: Error %d (%s)",
1542                                sock->fd, result, strerror(result));
1543                     }
1544                 }
1545             }
1546         }
1547         KQueueSet(sock->fd, EV_DELETE, EVFILT_WRITE, &sock->kqEntry);
1548 
1549         // If we set the EVFILT_READ event in mDNSPlatformTCPConnect, it's possible to get a read event
1550         // before the write event--apparently the socket is both readable and writable once that happens,
1551         // even if the connect fails.   If we set it here, after we've gotten a successful connection, then
1552         // we shouldn't run into that problem.
1553         if (sock->err == mStatus_NoError &&
1554             KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry))
1555         {
1556             // And of course if that fails, we can't use the connection even though we have it.
1557             LogMsg("ERROR: tcpKQSocketCallback - KQueueSet failed");
1558             sock->err = mStatus_TransientErr;
1559         }
1560     }
1561 
1562     if (sock->flags & kTCPSocketFlags_UseTLS)
1563     {
1564 #ifndef NO_SECURITYFRAMEWORK
1565         // Don't try to set up TLS if the connect failed.
1566         if (sock->err == mStatus_NoError) {
1567             if (!sock->setup)
1568             {
1569                 sock->setup = mDNStrue;
1570 #pragma clang diagnostic push
1571 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1572                 sock->err = tlsSetupSock(sock, kSSLClientSide, kSSLStreamType);
1573                 if (sock->err)
1574                 {
1575                     LogMsg("ERROR: tcpKQSocketCallback: tlsSetupSock failed with error code: %d", sock->err);
1576                     return;
1577                 }
1578 #pragma clang diagnostic pop
1579             }
1580             if (sock->handshake == handshake_required)
1581             {
1582                 spawnSSLHandshake(sock);
1583                 return;
1584             }
1585             else if (sock->handshake == handshake_in_progress || sock->handshake == handshake_to_be_closed)
1586             {
1587                 return;
1588             }
1589             else if (sock->handshake != handshake_completed)
1590             {
1591                 if (!sock->err)
1592                     sock->err = mStatus_UnknownErr;
1593                 LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock->handshake);
1594             }
1595         }
1596 #else  /* NO_SECURITYFRAMEWORK */
1597         sock->err = mStatus_UnsupportedErr;
1598 #endif /* NO_SECURITYFRAMEWORK */
1599     }
1600 
1601     doTcpSocketCallback(sock);
1602 }
1603 
1604 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
KQueueSet(int fd,u_short flags,short filter,KQueueEntry * const entryRef)1605 mDNSexport int KQueueSet(int fd, u_short flags, short filter, KQueueEntry *const entryRef)
1606 {
1607     dispatch_queue_t queue = dispatch_get_main_queue();
1608     dispatch_source_t source;
1609     if (flags == EV_DELETE)
1610     {
1611         if (filter == EVFILT_READ)
1612         {
1613             dispatch_source_cancel(entryRef->readSource);
1614             dispatch_release(entryRef->readSource);
1615             entryRef->readSource = mDNSNULL;
1616             debugf("KQueueSet: source cancel for read %p, %p", entryRef->readSource, entryRef->writeSource);
1617         }
1618         else if (filter == EVFILT_WRITE)
1619         {
1620             dispatch_source_cancel(entryRef->writeSource);
1621             dispatch_release(entryRef->writeSource);
1622             entryRef->writeSource = mDNSNULL;
1623             debugf("KQueueSet: source cancel for write %p, %p", entryRef->readSource, entryRef->writeSource);
1624         }
1625         else
1626             LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_DELETE", filter);
1627         return 0;
1628     }
1629     if (flags != EV_ADD) LogMsg("KQueueSet: Invalid flags %d", flags);
1630 
1631     if (filter == EVFILT_READ)
1632     {
1633         source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, queue);
1634     }
1635     else if (filter == EVFILT_WRITE)
1636     {
1637         source = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, fd, 0, queue);
1638     }
1639     else
1640     {
1641         LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_ADD", filter);
1642         return -1;
1643     }
1644     if (!source) return -1;
1645     dispatch_source_set_event_handler(source, ^{
1646 
1647                                           mDNSs32 stime = mDNSPlatformRawTime();
1648                                           entryRef->KQcallback(fd, filter, entryRef->KQcontext);
1649                                           mDNSs32 etime = mDNSPlatformRawTime();
1650                                           if (etime - stime >= WatchDogReportingThreshold)
1651                                               LogInfo("KQEntryCallback Block: WARNING: took %dms to complete", etime - stime);
1652 
1653                                           // Trigger the event delivery to the application. Even though we trigger the
1654                                           // event completion after handling every event source, these all will hopefully
1655                                           // get merged
1656                                           TriggerEventCompletion();
1657 
1658                                       });
1659     dispatch_source_set_cancel_handler(source, ^{
1660                                            if (entryRef->fdClosed)
1661                                            {
1662                                                //LogMsg("CancelHandler: closing fd %d", fd);
1663                                                close(fd);
1664                                            }
1665                                        });
1666     dispatch_resume(source);
1667     if (filter == EVFILT_READ)
1668         entryRef->readSource = source;
1669     else
1670         entryRef->writeSource = source;
1671 
1672     return 0;
1673 }
1674 
KQueueLock()1675 mDNSexport void KQueueLock()
1676 {
1677 }
KQueueUnlock(const char const * task)1678 mDNSexport void KQueueUnlock(const char const *task)
1679 {
1680     (void)task; //unused
1681 }
1682 #else
1683 
KQueueSet(int fd,u_short flags,short filter,const KQueueEntry * const entryRef)1684 mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef)
1685 {
1686     struct kevent new_event;
1687     EV_SET(&new_event, fd, filter, flags, 0, 0, (void*)entryRef);
1688     return (kevent(KQueueFD, &new_event, 1, NULL, 0, NULL) < 0) ? errno : 0;
1689 }
1690 
KQueueLock()1691 mDNSexport void KQueueLock()
1692 {
1693     mDNS *const m = &mDNSStorage;
1694     pthread_mutex_lock(&m->p->BigMutex);
1695     m->p->BigMutexStartTime = mDNSPlatformRawTime();
1696 }
1697 
KQueueUnlock(const char * task)1698 mDNSexport void KQueueUnlock(const char* task)
1699 {
1700     mDNS *const m = &mDNSStorage;
1701     mDNSs32 end = mDNSPlatformRawTime();
1702     (void)task;
1703     if (end - m->p->BigMutexStartTime >= WatchDogReportingThreshold)
1704     {
1705         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_WARNING,
1706             "WARNING: " PUB_S " took %d ms to complete", task, end - m->p->BigMutexStartTime);
1707     }
1708 
1709     pthread_mutex_unlock(&m->p->BigMutex);
1710 
1711     char wake = 1;
1712     if (send(m->p->WakeKQueueLoopFD, &wake, sizeof(wake), 0) == -1)
1713         LogMsg("ERROR: KQueueWake: send failed with error code: %d (%s)", errno, strerror(errno));
1714 }
1715 #endif
1716 
mDNSPlatformCloseFD(KQueueEntry * kq,int fd)1717 mDNSexport void mDNSPlatformCloseFD(KQueueEntry *kq, int fd)
1718 {
1719 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1720         (void) fd; //unused
1721     if (kq->readSource)
1722     {
1723         dispatch_source_cancel(kq->readSource);
1724         kq->readSource = mDNSNULL;
1725     }
1726     if (kq->writeSource)
1727     {
1728         dispatch_source_cancel(kq->writeSource);
1729         kq->writeSource = mDNSNULL;
1730     }
1731     // Close happens in the cancellation handler
1732     debugf("mDNSPlatformCloseFD: resetting sources for %d", fd);
1733     kq->fdClosed = mDNStrue;
1734 #else
1735     (void)kq; //unused
1736     close(fd);
1737 #endif
1738 }
1739 
SetupTCPSocket(TCPSocket * sock,mDNSAddr_Type addrtype,mDNSIPPort * port,mDNSBool useBackgroundTrafficClass)1740 mDNSlocal mStatus SetupTCPSocket(TCPSocket *sock, mDNSAddr_Type addrtype, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
1741 {
1742     int skt;
1743 
1744     skt = -1;
1745     if (!mDNSPosixTCPSocketSetup(&skt, addrtype, port, &sock->port))
1746     {
1747         if (skt != -1) close(skt);
1748         return mStatus_UnknownErr;
1749     }
1750 
1751     // for TCP sockets, the traffic class is set once and not changed
1752     setTrafficClass(skt, useBackgroundTrafficClass);
1753 
1754     sock->fd = skt;
1755     sock->kqEntry.KQcallback = tcpKQSocketCallback;
1756     sock->kqEntry.KQcontext  = sock;
1757     sock->kqEntry.KQtask     = "mDNSPlatformTCPSocket";
1758 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1759     sock->kqEntry.readSource = mDNSNULL;
1760     sock->kqEntry.writeSource = mDNSNULL;
1761     sock->kqEntry.fdClosed = mDNSfalse;
1762 #endif
1763     return mStatus_NoError;
1764 }
1765 
mDNSPlatformTCPSocket(TCPSocketFlags flags,mDNSAddr_Type addrtype,mDNSIPPort * port,domainname * hostname,mDNSBool useBackgroundTrafficClass)1766 mDNSexport TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSAddr_Type addrtype, mDNSIPPort *port, domainname *hostname, mDNSBool useBackgroundTrafficClass)
1767 {
1768     mStatus err;
1769     mDNSu32 lowWater = 16384;
1770     size_t len = sizeof (TCPSocket);
1771     if (hostname) {
1772         len += sizeof (domainname);
1773     }
1774 
1775     TCPSocket *sock = (TCPSocket *) callocL("TCPSocket/mDNSPlatformTCPSocket", len);
1776     if (!sock) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL); }
1777 
1778     if (hostname)
1779     {
1780         sock->hostname = (domainname *)(sock + 1); // Allocated together so can be freed together
1781         debugf("mDNSPlatformTCPSocket: hostname %##s", hostname->c);
1782         AssignDomainName(sock->hostname, hostname);
1783     }
1784 
1785     err = SetupTCPSocket(sock, addrtype, port, useBackgroundTrafficClass);
1786 
1787     if (err)
1788     {
1789         LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock->fd, errno, strerror(errno));
1790         freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
1791         return(mDNSNULL);
1792     }
1793 
1794     if (setsockopt(sock->fd, IPPROTO_TCP, TCP_NOTSENT_LOWAT, &lowWater, sizeof lowWater) < 0)
1795     {
1796         LogMsg("mDNSPlatformTCPSocket: TCP_NOTSENT_LOWAT returned %d", errno);
1797                mDNSPlatformTCPCloseConnection(sock);
1798         return mDNSNULL;
1799     }
1800 
1801     sock->callback          = mDNSNULL;
1802     sock->flags             = flags;
1803     sock->context           = mDNSNULL;
1804     sock->setup             = mDNSfalse;
1805     sock->connected         = mDNSfalse;
1806     sock->handshake         = handshake_required;
1807     sock->m                 =  &mDNSStorage;
1808     sock->err               = mStatus_NoError;
1809 
1810     return sock;
1811 }
1812 
mDNSPlatformTCPConnect(TCPSocket * sock,const mDNSAddr * dst,mDNSOpaque16 dstport,mDNSInterfaceID InterfaceID,TCPConnectionCallback callback,void * context)1813 mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context)
1814 {
1815     mStatus err = mStatus_NoError;
1816     struct sockaddr_storage ss;
1817 
1818     sock->callback          = callback;
1819     sock->context           = context;
1820     sock->setup             = mDNSfalse;
1821     sock->connected         = mDNSfalse;
1822     sock->handshake         = handshake_required;
1823     sock->err               = mStatus_NoError;
1824 
1825     if (dst->type == mDNSAddrType_IPv4)
1826     {
1827         struct sockaddr_in *saddr = (struct sockaddr_in *)&ss;
1828         mDNSPlatformMemZero(saddr, sizeof(*saddr));
1829         saddr->sin_family      = AF_INET;
1830         saddr->sin_port        = dstport.NotAnInteger;
1831         saddr->sin_len         = sizeof(*saddr);
1832         saddr->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
1833     }
1834     else
1835     {
1836         struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)&ss;
1837         mDNSPlatformMemZero(saddr6, sizeof(*saddr6));
1838         saddr6->sin6_family      = AF_INET6;
1839         saddr6->sin6_port        = dstport.NotAnInteger;
1840         saddr6->sin6_len         = sizeof(*saddr6);
1841         saddr6->sin6_addr        = *(struct in6_addr *)&dst->ip.v6;
1842     }
1843 
1844     // Watch for connect complete (write is ready)
1845     // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
1846     if (KQueueSet(sock->fd, EV_ADD /* | EV_ONESHOT */, EVFILT_WRITE, &sock->kqEntry))
1847     {
1848         LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1849         return errno;
1850     }
1851 
1852     if (fcntl(sock->fd, F_SETFL, fcntl(sock->fd, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
1853     {
1854         LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno));
1855         return mStatus_UnknownErr;
1856     }
1857 
1858     // We bind to the interface and all subsequent packets including the SYN will be sent out
1859     // on this interface
1860     //
1861     // Note: If we are in Active Directory domain, we may try TCP (if the response can't fit in
1862     // UDP).
1863     if (InterfaceID)
1864     {
1865         NetworkInterfaceInfoOSX *info = IfindexToInterfaceInfoOSX(InterfaceID);
1866         if (dst->type == mDNSAddrType_IPv4)
1867         {
1868         #ifdef IP_BOUND_IF
1869             if (info) setsockopt(sock->fd, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
1870             else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
1871         #else
1872             (void)InterfaceID; // Unused
1873             (void)info; // Unused
1874         #endif
1875         }
1876         else
1877         {
1878         #ifdef IPV6_BOUND_IF
1879             if (info) setsockopt(sock->fd, IPPROTO_IPV6, IPV6_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
1880             else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
1881         #else
1882             (void)InterfaceID; // Unused
1883             (void)info; // Unused
1884         #endif
1885         }
1886     }
1887 
1888     // mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address
1889     // from which we can infer the destination address family. Hence we need to remember that here.
1890     // Instead of remembering the address family, we remember the right fd.
1891     sock->fd = sock->fd;
1892     // initiate connection wth peer
1893     if (connect(sock->fd, (struct sockaddr *)&ss, ss.ss_len) < 0)
1894     {
1895         if (errno == EINPROGRESS) return mStatus_ConnPending;
1896         if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
1897             LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock->fd, errno, strerror(errno));
1898         else
1899             LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d", sock->fd, errno, strerror(errno), ss.ss_len);
1900         return mStatus_ConnFailed;
1901     }
1902 
1903     LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
1904     // kQueue should notify us, but this LogMsg is to help track down if it doesn't
1905     // Experimentation shows that even a connection to a local listener returns EINPROGRESS, so this
1906     // will likely never happen.
1907 
1908     return err;
1909 }
1910 
1911 // Replace the existing socket callback with a new one, or establish a callback where none was present.
mDNSPlatformTCPSocketSetCallback(TCPSocket * sock,TCPConnectionCallback callback,void * context)1912 mDNSexport mStatus mDNSPlatformTCPSocketSetCallback(TCPSocket *sock, TCPConnectionCallback callback, void *context)
1913 {
1914     sock->callback = callback;
1915     sock->context = context;
1916 
1917     // dnsextd currently reaches into the TCPSocket structure layer to do its own thing; this won't work for
1918     // any code (e.g., the Discovery Proxy or Discovery Relay) that actually uses the mDNSPlatform layer as
1919     // an opaque layer.   So for that code, we have this.   dnsextd should probably be platformized if it's
1920     // still relevant.
1921     if (!sock->callback) {
1922         // Watch for incoming data
1923         if (KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry))
1924         {
1925             LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1926             return mStatus_UnknownErr;
1927         }
1928     }
1929 
1930     sock->kqEntry.KQcallback = tcpKQSocketCallback;
1931     sock->kqEntry.KQcontext  = sock;
1932     sock->kqEntry.KQtask     = "mDNSPlatformTCPSocket";
1933 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1934     sock->kqEntry.readSource = mDNSNULL;
1935     sock->kqEntry.writeSource = mDNSNULL;
1936     sock->kqEntry.fdClosed = mDNSfalse;
1937 #endif
1938     return mStatus_NoError;
1939 }
1940 
1941 // Why doesn't mDNSPlatformTCPAccept actually call accept() ?
1942 // mDNSPlatformTCPAccept is only called by dnsextd.c.   It's called _after_ accept has returned
1943 // a connected socket.   The purpose appears to be to allocate and initialize the TCPSocket structure
1944 // and set up TLS, if required for this connection.   dnsextd appears to be the only thing in mDNSResponder
1945 // that accepts incoming TLS connections.
mDNSPlatformTCPAccept(TCPSocketFlags flags,int fd)1946 mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
1947 {
1948     mStatus err = mStatus_NoError;
1949 
1950     TCPSocket *sock = (TCPSocket *) callocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(*sock));
1951     if (!sock) return(mDNSNULL);
1952 
1953     sock->fd = fd;
1954     sock->flags = flags;
1955 
1956     if (flags & kTCPSocketFlags_UseTLS)
1957     {
1958 #ifndef NO_SECURITYFRAMEWORK
1959 #pragma clang diagnostic push
1960 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1961 
1962         if (!ServerCerts) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err = mStatus_UnknownErr; goto exit; }
1963 
1964         err = tlsSetupSock(sock, kSSLServerSide, kSSLStreamType);
1965         if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err); goto exit; }
1966 
1967         err = SSLSetCertificate(sock->tlsContext, ServerCerts);
1968         if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err); goto exit; }
1969 #pragma clang diagnostic pop
1970 #else
1971         err = mStatus_UnsupportedErr;
1972 #endif /* NO_SECURITYFRAMEWORK */
1973     }
1974 #ifndef NO_SECURITYFRAMEWORK
1975 exit:
1976 #endif
1977 
1978     if (err) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock); return(mDNSNULL); }
1979     return(sock);
1980 }
1981 
tcpListenCallback(int fd,__unused short filter,void * context,__unused mDNSBool encounteredEOF)1982 mDNSlocal void tcpListenCallback(int fd, __unused short filter, void *context, __unused mDNSBool encounteredEOF)
1983 {
1984     TCPListener *listener = context;
1985     TCPSocket *sock;
1986 
1987     sock = mDNSPosixDoTCPListenCallback(fd, listener->addressType, listener->socketFlags,
1988                                  listener->callback, listener->context);
1989 
1990     if (sock != mDNSNULL)
1991     {
1992         KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry);
1993 
1994         sock->kqEntry.KQcallback = tcpKQSocketCallback;
1995         sock->kqEntry.KQcontext  = sock;
1996         sock->kqEntry.KQtask     = "mDNSPlatformTCPListen";
1997 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1998         sock->kqEntry.readSource = mDNSNULL;
1999         sock->kqEntry.writeSource = mDNSNULL;
2000         sock->kqEntry.fdClosed = mDNSfalse;
2001 #endif
2002     }
2003 }
2004 
mDNSPlatformTCPListen(mDNSAddr_Type addrtype,mDNSIPPort * port,mDNSAddr * addr,TCPSocketFlags socketFlags,mDNSBool reuseAddr,int queueLength,TCPAcceptedCallback callback,void * context)2005 mDNSexport TCPListener *mDNSPlatformTCPListen(mDNSAddr_Type addrtype, mDNSIPPort *port, mDNSAddr *addr,
2006                                               TCPSocketFlags socketFlags, mDNSBool reuseAddr, int queueLength,
2007                                               TCPAcceptedCallback callback, void *context)
2008 {
2009     TCPListener *ret;
2010     int fd = -1;
2011 
2012     if (!mDNSPosixTCPListen(&fd, addrtype, port, addr, reuseAddr, queueLength)) {
2013         if (fd != -1) {
2014             close(fd);
2015         }
2016         return mDNSNULL;
2017     }
2018 
2019     // Allocate a listener structure
2020     ret = (TCPListener *) mDNSPlatformMemAllocateClear(sizeof *ret);
2021     if (ret == mDNSNULL)
2022     {
2023         LogMsg("mDNSPlatformTCPListen: no memory for TCPListener struct.");
2024         close(fd);
2025         return mDNSNULL;
2026     }
2027     ret->fd = fd;
2028     ret->callback = callback;
2029     ret->context = context;
2030     ret->socketFlags = socketFlags;
2031 
2032     // Watch for incoming data
2033     KQueueSet(ret->fd, EV_ADD, EVFILT_READ, &ret->kqEntry);
2034     ret->kqEntry.KQcallback = tcpListenCallback;
2035     ret->kqEntry.KQcontext  = ret;
2036     ret->kqEntry.KQtask     = "mDNSPlatformTCPListen";
2037 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2038     ret->kqEntry.readSource = mDNSNULL;
2039     ret->kqEntry.writeSource = mDNSNULL;
2040     ret->kqEntry.fdClosed = mDNSfalse;
2041 #endif
2042     return ret;
2043 }
2044 
mDNSPlatformGetUDPPort(UDPSocket * sock)2045 mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
2046 {
2047     mDNSu16 port;
2048 
2049     port = -1;
2050     if (sock)
2051     {
2052         port = sock->ss.port.NotAnInteger;
2053     }
2054     return port;
2055 }
2056 
CloseSocketSet(KQSocketSet * ss)2057 mDNSlocal void CloseSocketSet(KQSocketSet *ss)
2058 {
2059     if (ss->sktv4 != -1)
2060     {
2061         mDNSPlatformCloseFD(&ss->kqsv4,  ss->sktv4);
2062         ss->sktv4 = -1;
2063     }
2064     if (ss->sktv6 != -1)
2065     {
2066         mDNSPlatformCloseFD(&ss->kqsv6,  ss->sktv6);
2067         ss->sktv6 = -1;
2068     }
2069     if (ss->closeFlag) *ss->closeFlag = 1;
2070 }
2071 
mDNSPlatformTCPCloseConnection(TCPSocket * sock)2072 mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
2073 {
2074     if (sock)
2075     {
2076 #ifndef NO_SECURITYFRAMEWORK
2077         if (sock->tlsContext)
2078         {
2079             if (sock->handshake == handshake_in_progress) // SSLHandshake thread using this sock (esp. tlsContext)
2080             {
2081                 LogInfo("mDNSPlatformTCPCloseConnection: called while handshake in progress");
2082                 // When we come back from SSLHandshake, we will notice that a close was here and
2083                 // call this function again which will do the cleanup then.
2084                 sock->handshake = handshake_to_be_closed;
2085                 return;
2086             }
2087 #pragma clang diagnostic push
2088 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
2089             SSLClose(sock->tlsContext);
2090             CFRelease(sock->tlsContext);
2091             sock->tlsContext = NULL;
2092         }
2093 #pragma clang diagnostic pop
2094 #endif /* NO_SECURITYFRAMEWORK */
2095         if (sock->fd != -1) {
2096             shutdown(sock->fd, 2);
2097             mDNSPlatformCloseFD(&sock->kqEntry, sock->fd);
2098             sock->fd = -1;
2099         }
2100 
2101         freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock);
2102     }
2103 }
2104 
mDNSPlatformReadTCP(TCPSocket * sock,void * buf,unsigned long buflen,mDNSBool * closed)2105 mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed)
2106 {
2107     ssize_t nread = 0;
2108     *closed = mDNSfalse;
2109 
2110     // We can get here if the caller set up a TCP connection but didn't check the status when it got the
2111     // callback.
2112     if (!sock->connected) {
2113         return mStatus_DefunctConnection;
2114     }
2115 
2116     if (sock->flags & kTCPSocketFlags_UseTLS)
2117     {
2118 #ifndef NO_SECURITYFRAMEWORK
2119         if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformReadTCP called while handshake required"); return 0; }
2120         else if (sock->handshake == handshake_in_progress) return 0;
2121         else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformReadTCP called with unexpected SSLHandshake status: %d", sock->handshake);
2122 
2123         //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
2124 #pragma clang diagnostic push
2125 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
2126         mStatus err = SSLRead(sock->tlsContext, buf, buflen, (size_t *)&nread);
2127 #pragma clang diagnostic pop
2128         //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
2129         if (err == errSSLClosedGraceful) { nread = 0; *closed = mDNStrue; }
2130         else if (err && err != errSSLWouldBlock)
2131         { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err); nread = -1; *closed = mDNStrue; }
2132 #else
2133         nread = -1;
2134         *closed = mDNStrue;
2135 #endif /* NO_SECURITYFRAMEWORK */
2136     }
2137     else
2138     {
2139         nread = mDNSPosixReadTCP(sock->fd, buf, buflen, closed);
2140     }
2141 
2142     return nread;
2143 }
2144 
mDNSPlatformWriteTCP(TCPSocket * sock,const char * msg,unsigned long len)2145 mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
2146 {
2147     long nsent;
2148 
2149     if (!sock->connected) {
2150         return mStatus_DefunctConnection;
2151     }
2152 
2153     if (sock->flags & kTCPSocketFlags_UseTLS)
2154     {
2155 #ifndef NO_SECURITYFRAMEWORK
2156         size_t processed;
2157         if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformWriteTCP called while handshake required"); return 0; }
2158         if (sock->handshake == handshake_in_progress) return 0;
2159         else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformWriteTCP called with unexpected SSLHandshake status: %d", sock->handshake);
2160 
2161 #pragma clang diagnostic push
2162 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
2163         mStatus err = SSLWrite(sock->tlsContext, msg, len, &processed);
2164 #pragma clang diagnostic pop
2165 
2166         if (!err) nsent = (long)processed;
2167         else if (err == errSSLWouldBlock) nsent = 0;
2168         else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err); nsent = -1; }
2169 #else
2170         nsent = -1;
2171 #endif /* NO_SECURITYFRAMEWORK */
2172     }
2173     else
2174     {
2175         nsent = mDNSPosixWriteTCP(sock->fd, msg, len);
2176     }
2177     return nsent;
2178 }
2179 
mDNSPlatformTCPGetFD(TCPSocket * sock)2180 mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
2181 {
2182     return sock->fd;
2183 }
2184 
2185 // This function checks to see if the socket is writable.   It will be writable if the kernel TCP output
2186 // buffer is less full than TCP_NOTSENT_LOWAT.   This should be half or less of the actual kernel buffer
2187 // size.   This check is done in cases where data should be written if there's space, for example in the
2188 // Discovery Relay code, where we may be receiving mDNS messages at arbitrary times, and generally there
2189 // should be buffer space to relay them, but in exceptional cases there might not be.   In this case it's
2190 
mDNSPlatformTCPWritable(TCPSocket * sock)2191 mDNSexport mDNSBool mDNSPlatformTCPWritable(TCPSocket *sock)
2192 {
2193     int kfd = kqueue();
2194     struct kevent kin, kout;
2195     int count;
2196     struct timespec ts;
2197 
2198     if (kfd < 0)
2199     {
2200         LogMsg("ERROR: kqueue failed: %m");
2201         return mDNSfalse;
2202     }
2203     ts.tv_sec = 0;
2204     ts.tv_nsec = 0;
2205     EV_SET(&kin, sock->fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
2206     count = kevent(kfd, &kin, 1, &kout, 1, &ts);
2207     close(kfd);
2208     if (count == 1 && (int)kout.ident == sock->fd && kout.filter == EVFILT_WRITE)
2209     {
2210         return mDNStrue;
2211     }
2212     return mDNSfalse;
2213 }
2214 
2215 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
2216 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
SetupSocket(KQSocketSet * cp,const mDNSIPPort port,u_short sa_family,mDNSIPPort * const outport)2217 mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family, mDNSIPPort *const outport)
2218 {
2219     int         *s        = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
2220     KQueueEntry *k        = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
2221     const int on = 1;
2222     const int twofivefive = 255;
2223     mStatus err = mStatus_NoError;
2224     char *errstr = mDNSNULL;
2225     const int mtu = 0;
2226     int saved_errno;
2227 
2228     cp->closeFlag = mDNSNULL;
2229 
2230     int skt = socket(sa_family, SOCK_DGRAM, IPPROTO_UDP);
2231     if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno));return(skt); }
2232 
2233     // set default traffic class
2234     setTrafficClass(skt, mDNSfalse);
2235 
2236 #ifdef SO_RECV_ANYIF
2237     // Enable inbound packets on IFEF_AWDL interface.
2238     // Only done for multicast sockets, since we don't expect unicast socket operations
2239     // on the IFEF_AWDL interface. Operation is a no-op for other interface types.
2240     if (mDNSSameIPPort(port, MulticastDNSPort))
2241     {
2242         err = setsockopt(skt, SOL_SOCKET, SO_RECV_ANYIF, &on, sizeof(on));
2243         if (err < 0) { errstr = "setsockopt - SO_RECV_ANYIF"; goto fail; }
2244     }
2245 #endif // SO_RECV_ANYIF
2246 
2247     // ... with a shared UDP port, if it's for multicast receiving
2248     if (mDNSSameIPPort(port, MulticastDNSPort) || mDNSSameIPPort(port, NATPMPAnnouncementPort))
2249     {
2250         err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
2251         if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; }
2252     }
2253 
2254     // Don't want to wake from sleep for inbound packets on the mDNS sockets
2255     if (mDNSSameIPPort(port, MulticastDNSPort))
2256     {
2257         int nowake = 1;
2258         if (setsockopt(skt, SOL_SOCKET, SO_NOWAKEFROMSLEEP, &nowake, sizeof(nowake)) == -1)
2259             LogInfo("SetupSocket: SO_NOWAKEFROMSLEEP failed %s", strerror(errno));
2260     }
2261 
2262     if (sa_family == AF_INET)
2263     {
2264         // We want to receive destination addresses
2265         err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
2266         if (err < 0) { errstr = "setsockopt - IP_RECVDSTADDR"; goto fail; }
2267 
2268         // We want to receive interface identifiers
2269         err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
2270         if (err < 0) { errstr = "setsockopt - IP_RECVIF"; goto fail; }
2271 
2272         // We want to receive packet TTL value so we can check it
2273         err = setsockopt(skt, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on));
2274         if (err < 0) { errstr = "setsockopt - IP_RECVTTL"; goto fail; }
2275 
2276         // Send unicast packets with TTL 255
2277         err = setsockopt(skt, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive));
2278         if (err < 0) { errstr = "setsockopt - IP_TTL"; goto fail; }
2279 
2280         // And multicast packets with TTL 255 too
2281         err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive));
2282         if (err < 0) { errstr = "setsockopt - IP_MULTICAST_TTL"; goto fail; }
2283 
2284         // And start listening for packets
2285         struct sockaddr_in listening_sockaddr;
2286         listening_sockaddr.sin_family      = AF_INET;
2287         listening_sockaddr.sin_port        = port.NotAnInteger;     // Pass in opaque ID without any byte swapping
2288         listening_sockaddr.sin_addr.s_addr = mDNSSameIPPort(port, NATPMPAnnouncementPort) ? AllHosts_v4.NotAnInteger : 0;
2289         err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr));
2290         if (err) { errstr = "bind"; goto fail; }
2291         if (outport) outport->NotAnInteger = listening_sockaddr.sin_port;
2292     }
2293     else if (sa_family == AF_INET6)
2294     {
2295         // NAT-PMP Announcements make no sense on IPv6, and we don't support IPv6 for PCP, so bail early w/o error
2296         if (mDNSSameIPPort(port, NATPMPAnnouncementPort)) { if (outport) *outport = zeroIPPort; close(skt); return mStatus_NoError; }
2297 
2298         // We want to receive destination addresses and receive interface identifiers
2299         err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
2300         if (err < 0) { errstr = "setsockopt - IPV6_RECVPKTINFO"; goto fail; }
2301 
2302         // We want to receive packet hop count value so we can check it
2303         err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on));
2304         if (err < 0) { errstr = "setsockopt - IPV6_RECVHOPLIMIT"; goto fail; }
2305 
2306         // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
2307         // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
2308         err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
2309         if (err < 0) { errstr = "setsockopt - IPV6_V6ONLY"; goto fail; }
2310 
2311         // Send unicast packets with TTL 255
2312         err = setsockopt(skt, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &twofivefive, sizeof(twofivefive));
2313         if (err < 0) { errstr = "setsockopt - IPV6_UNICAST_HOPS"; goto fail; }
2314 
2315         // And multicast packets with TTL 255 too
2316         err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive));
2317         if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_HOPS"; goto fail; }
2318 
2319         // Want to receive our own packets
2320         err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on));
2321         if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_LOOP"; goto fail; }
2322 
2323         // Disable default option to send mDNSv6 packets at min IPv6 MTU: RFC 3542, Sec 11
2324         err = setsockopt(skt, IPPROTO_IPV6, IPV6_USE_MIN_MTU, &mtu, sizeof(mtu));
2325         if (err < 0) // Since it is an optimization if we fail just log the err, no need to close the skt
2326             LogMsg("SetupSocket: setsockopt - IPV6_USE_MIN_MTU: IP6PO_MINMTU_DISABLE socket %d err %d errno %d (%s)",
2327                     skt, err, errno, strerror(errno));
2328 
2329         // And start listening for packets
2330         struct sockaddr_in6 listening_sockaddr6;
2331         mDNSPlatformMemZero(&listening_sockaddr6, sizeof(listening_sockaddr6));
2332         listening_sockaddr6.sin6_len         = sizeof(listening_sockaddr6);
2333         listening_sockaddr6.sin6_family      = AF_INET6;
2334         listening_sockaddr6.sin6_port        = port.NotAnInteger;       // Pass in opaque ID without any byte swapping
2335         listening_sockaddr6.sin6_flowinfo    = 0;
2336         listening_sockaddr6.sin6_addr        = in6addr_any; // Want to receive multicasts AND unicasts on this socket
2337         listening_sockaddr6.sin6_scope_id    = 0;
2338         err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6));
2339         if (err) { errstr = "bind"; goto fail; }
2340         if (outport) outport->NotAnInteger = listening_sockaddr6.sin6_port;
2341     }
2342 
2343     fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
2344     fcntl(skt, F_SETFD, 1); // set close-on-exec
2345     *s = skt;
2346     k->KQcallback = myKQSocketCallBack;
2347     k->KQcontext  = cp;
2348     k->KQtask     = "UDP packet reception";
2349 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2350     k->readSource = mDNSNULL;
2351     k->writeSource = mDNSNULL;
2352     k->fdClosed = mDNSfalse;
2353 #endif
2354     KQueueSet(*s, EV_ADD, EVFILT_READ, k);
2355 
2356     return(mStatus_NoError);
2357 
2358 fail:
2359     saved_errno = errno;
2360     // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
2361     if (strcmp(errstr, "bind") || mDNSSameIPPort(port, MulticastDNSPort) || mDNSIPPortIsZero(port))
2362         LogMsg("%s skt %d port %d error %d errno %d (%s)", errstr, skt, mDNSVal16(port), err, saved_errno, strerror(saved_errno));
2363 
2364     // If we got a "bind" failure of EADDRINUSE, inform the caller as it might need to try another random port
2365     if (!strcmp(errstr, "bind") && saved_errno == EADDRINUSE)
2366     {
2367         err = EADDRINUSE;
2368         if (mDNSSameIPPort(port, MulticastDNSPort))
2369             NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
2370                                "Congratulations, you've reproduced an elusive bug.\r"
2371                                "Please contact the current assignee of <rdar://problem/3814904>.\r"
2372                                "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
2373                                "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
2374     }
2375 
2376     mDNSPlatformCloseFD(k, skt);
2377     return(err);
2378 }
2379 
mDNSPlatformUDPSocket(const mDNSIPPort requestedport)2380 mDNSexport UDPSocket *mDNSPlatformUDPSocket(const mDNSIPPort requestedport)
2381 {
2382     mStatus err;
2383     mDNSIPPort port = requestedport;
2384     mDNSBool randomizePort = mDNSIPPortIsZero(requestedport);
2385     int i = 10000; // Try at most 10000 times to get a unique random port
2386     UDPSocket *p = (UDPSocket *) callocL("UDPSocket", sizeof(*p));
2387     if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); }
2388     p->ss.port  = zeroIPPort;
2389     p->ss.m     = &mDNSStorage;
2390     p->ss.sktv4 = -1;
2391     p->ss.sktv6 = -1;
2392     p->ss.proxy = mDNSfalse;
2393 
2394     do
2395     {
2396         // The kernel doesn't do cryptographically strong random port allocation, so we do it ourselves here
2397         if (randomizePort) port = mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF));
2398         err = SetupSocket(&p->ss, port, AF_INET, &p->ss.port);
2399         if (!err)
2400         {
2401             err = SetupSocket(&p->ss, port, AF_INET6, &p->ss.port);
2402             if (err) { mDNSPlatformCloseFD(&p->ss.kqsv4, p->ss.sktv4); p->ss.sktv4 = -1; }
2403         }
2404         i--;
2405     } while (err == EADDRINUSE && randomizePort && i);
2406 
2407     if (err)
2408     {
2409         // In customer builds we don't want to log failures with port 5351, because this is a known issue
2410         // of failing to bind to this port when Internet Sharing has already bound to it
2411         // We also don't want to log about port 5350, due to a known bug when some other
2412         // process is bound to it.
2413         if (mDNSSameIPPort(requestedport, NATPMPPort) || mDNSSameIPPort(requestedport, NATPMPAnnouncementPort))
2414             LogInfo("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
2415         else LogMsg("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
2416         freeL("UDPSocket", p);
2417         return(mDNSNULL);
2418     }
2419     return(p);
2420 }
2421 
2422 #ifdef UNIT_TEST
2423 UNITTEST_UDPCLOSE
2424 #else
2425 mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
2426 {
2427     CloseSocketSet(&sock->ss);
2428     freeL("UDPSocket", sock);
2429 }
2430 #endif
2431 
mDNSPlatformUDPSocketEncounteredEOF(const UDPSocket * sock)2432 mDNSexport mDNSBool mDNSPlatformUDPSocketEncounteredEOF(const UDPSocket *sock)
2433 {
2434     return (sock->ss.sktv4EOF || sock->ss.sktv6EOF);
2435 }
2436 
2437 #if COMPILER_LIKES_PRAGMA_MARK
2438 #pragma mark -
2439 #pragma mark - BPF Raw packet sending/receiving
2440 #endif
2441 
2442 #if APPLE_OSX_mDNSResponder
2443 
mDNSPlatformSendRawPacket(const void * const msg,const mDNSu8 * const end,mDNSInterfaceID InterfaceID)2444 mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
2445 {
2446     if (!InterfaceID) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; }
2447     NetworkInterfaceInfoOSX *info;
2448 
2449     info = IfindexToInterfaceInfoOSX(InterfaceID);
2450     if (info == NULL)
2451     {
2452         LogMsg("mDNSPlatformSendRawPacket: Invalid interface index %p", InterfaceID);
2453         return;
2454     }
2455     if (info->BPF_fd < 0)
2456         LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info->ifinfo.ifname, info->BPF_fd);
2457     else
2458     {
2459         //LogMsg("mDNSPlatformSendRawPacket %d bytes on %s", end - (mDNSu8 *)msg, info->ifinfo.ifname);
2460         if (write(info->BPF_fd, msg, end - (mDNSu8 *)msg) < 0)
2461             LogMsg("mDNSPlatformSendRawPacket: BPF write(%d) failed %d (%s)", info->BPF_fd, errno, strerror(errno));
2462     }
2463 }
2464 
mDNSPlatformSetLocalAddressCacheEntry(const mDNSAddr * const tpa,const mDNSEthAddr * const tha,mDNSInterfaceID InterfaceID)2465 mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
2466 {
2467     if (!InterfaceID) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: No InterfaceID specified"); return; }
2468     NetworkInterfaceInfoOSX *info;
2469     info = IfindexToInterfaceInfoOSX(InterfaceID);
2470     if (info == NULL) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: Invalid interface index %p", InterfaceID); return; }
2471     // Manually inject an entry into our local ARP cache.
2472     // (We can't do this by sending an ARP broadcast, because the kernel only pays attention to incoming ARP packets, not outgoing.)
2473     if (!mDNS_AddressIsLocalSubnet(&mDNSStorage, InterfaceID, tpa))
2474         LogSPS("Don't need address cache entry for %s %#a %.6a",            info->ifinfo.ifname, tpa, tha);
2475     else
2476     {
2477         int result = mDNSSetLocalAddressCacheEntry(info->scope_id, tpa->type, tpa->ip.v6.b, tha->b);
2478         if (result) LogMsg("Set local address cache entry for %s %#a %.6a failed: %d", info->ifinfo.ifname, tpa, tha, result);
2479         else LogSPS("Set local address cache entry for %s %#a %.6a",            info->ifinfo.ifname, tpa, tha);
2480     }
2481 }
2482 
CloseBPF(NetworkInterfaceInfoOSX * const i)2483 mDNSlocal void CloseBPF(NetworkInterfaceInfoOSX *const i)
2484 {
2485     LogSPS("%s closing BPF fd %d", i->ifinfo.ifname, i->BPF_fd);
2486 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2487     // close will happen in the cancel handler
2488     dispatch_source_cancel(i->BPF_source);
2489 #else
2490 
2491     // Note: MUST NOT close() the underlying native BSD sockets.
2492     // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, because
2493     // it first has to unhook the sockets from its select() call on its other thread, before it can safely close them.
2494     CFRunLoopRemoveSource(CFRunLoopGetMain(), i->BPF_rls, kCFRunLoopDefaultMode);
2495     CFRelease(i->BPF_rls);
2496     CFSocketInvalidate(i->BPF_cfs);
2497     CFRelease(i->BPF_cfs);
2498 #endif
2499     i->BPF_fd = -1;
2500     if (i->BPF_mcfd >= 0) { close(i->BPF_mcfd); i->BPF_mcfd = -1; }
2501 }
2502 
bpf_callback_common(NetworkInterfaceInfoOSX * info)2503 mDNSlocal void bpf_callback_common(NetworkInterfaceInfoOSX *info)
2504 {
2505     KQueueLock();
2506 
2507     // Now we've got the lock, make sure the kqueue thread didn't close the fd out from under us (will not be a problem once the OS X
2508     // kernel has a mechanism for dispatching all events to a single thread, but for now we have to guard against this race condition).
2509     if (info->BPF_fd < 0) goto exit;
2510 
2511     ssize_t n = read(info->BPF_fd, &info->m->imsg, info->BPF_len);
2512     const mDNSu8 *ptr = (const mDNSu8 *)&info->m->imsg;
2513     const mDNSu8 *end = (const mDNSu8 *)&info->m->imsg + n;
2514     debugf("%3d: bpf_callback got %d bytes on %s", info->BPF_fd, n, info->ifinfo.ifname);
2515 
2516     if (n<0)
2517     {
2518         /* <rdar://problem/10287386>
2519          * sometimes there can be a race condition btw when the bpf socket
2520          * gets data and the callback get scheduled and when we call BIOCSETF (which
2521          * clears the socket).  this can cause the read to hang for a really long time
2522          * and effectively prevent us from responding to requests for long periods of time.
2523          * to prevent this make the socket non blocking and just bail if we dont get anything
2524          */
2525         if (errno == EAGAIN)
2526         {
2527             LogMsg("bpf_callback got EAGAIN bailing");
2528             goto exit;
2529         }
2530         LogMsg("Closing %s BPF fd %d due to error %d (%s)", info->ifinfo.ifname, info->BPF_fd, errno, strerror(errno));
2531         CloseBPF(info);
2532         goto exit;
2533     }
2534 
2535     while (ptr < end)
2536     {
2537         const struct bpf_hdr *const bh = (const struct bpf_hdr *)ptr;
2538         debugf("%3d: bpf_callback ptr %p bh_hdrlen %d data %p bh_caplen %4d bh_datalen %4d next %p remaining %4d",
2539                info->BPF_fd, ptr, bh->bh_hdrlen, ptr + bh->bh_hdrlen, bh->bh_caplen, bh->bh_datalen,
2540                ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen), end - (ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen)));
2541         // Note that BPF guarantees that the NETWORK LAYER header will be word aligned, not the link-layer header.
2542         // Given that An Ethernet header is 14 bytes, this means that if the network layer header (e.g. IP header,
2543         // ARP message, etc.) is 4-byte aligned, then necessarily the Ethernet header will be NOT be 4-byte aligned.
2544         mDNSCoreReceiveRawPacket(info->m, ptr + bh->bh_hdrlen, ptr + bh->bh_hdrlen + bh->bh_caplen, info->ifinfo.InterfaceID);
2545         ptr += BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen);
2546     }
2547 exit:
2548     KQueueUnlock("bpf_callback");
2549 }
2550 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
bpf_callback_dispatch(NetworkInterfaceInfoOSX * const info)2551 mDNSlocal void bpf_callback_dispatch(NetworkInterfaceInfoOSX *const info)
2552 {
2553     bpf_callback_common(info);
2554 }
2555 #else
bpf_callback(const CFSocketRef cfs,const CFSocketCallBackType CallBackType,const CFDataRef address,const void * const data,void * const context)2556 mDNSlocal void bpf_callback(const CFSocketRef cfs, const CFSocketCallBackType CallBackType, const CFDataRef address, const void *const data, void *const context)
2557 {
2558     (void)cfs;
2559     (void)CallBackType;
2560     (void)address;
2561     (void)data;
2562     bpf_callback_common((NetworkInterfaceInfoOSX *)context);
2563 }
2564 #endif
2565 
mDNSPlatformSendKeepalive(mDNSAddr * sadd,mDNSAddr * dadd,mDNSIPPort * lport,mDNSIPPort * rport,mDNSu32 seq,mDNSu32 ack,mDNSu16 win)2566 mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win)
2567 {
2568     LogMsg("mDNSPlatformSendKeepalive called\n");
2569     mDNSSendKeepalive(sadd->ip.v6.b, dadd->ip.v6.b, lport->NotAnInteger, rport->NotAnInteger, seq, ack, win);
2570 }
2571 
mDNSPlatformClearSPSData(void)2572 mDNSexport mStatus mDNSPlatformClearSPSData(void)
2573 {
2574     CFStringRef  spsAddressKey  = NULL;
2575     CFStringRef  ownerOPTRecKey = NULL;
2576     SCDynamicStoreRef addrStore = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:SPSAddresses"), NULL, NULL);
2577     SCDynamicStoreRef optStore  = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:SPSOPTRecord"), NULL, NULL);
2578 
2579     spsAddressKey = SCDynamicStoreKeyCreateNetworkInterfaceEntity (kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCCompAnyRegex, CFSTR("BonjourSleepProxyAddress"));
2580     if (spsAddressKey != NULL)
2581     {
2582         CFArrayRef keyList = SCDynamicStoreCopyKeyList(addrStore, spsAddressKey);
2583         if (keyList != NULL)
2584         {
2585             if (SCDynamicStoreSetMultiple(addrStore, NULL, keyList, NULL) == false)
2586                 LogSPS("mDNSPlatformClearSPSData: Unable to remove %s : error %s", CFStringGetCStringPtr( spsAddressKey, kCFStringEncodingASCII), SCErrorString(SCError()));
2587         }
2588         if (keyList) CFRelease(keyList);
2589     }
2590     ownerOPTRecKey= SCDynamicStoreKeyCreateNetworkInterfaceEntity (kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCCompAnyRegex, CFSTR("BonjourSleepProxyOPTRecord"));
2591     if(ownerOPTRecKey != NULL)
2592     {
2593         CFArrayRef keyList = SCDynamicStoreCopyKeyList(addrStore, ownerOPTRecKey);
2594         if (keyList != NULL)
2595         {
2596             if (SCDynamicStoreSetMultiple(optStore, NULL, keyList, NULL) == false)
2597                 LogSPS("mDNSPlatformClearSPSData: Unable to remove %s : error %s", CFStringGetCStringPtr(ownerOPTRecKey, kCFStringEncodingASCII), SCErrorString(SCError()));
2598         }
2599         if (keyList) CFRelease(keyList);
2600     }
2601 
2602     if (addrStore)   CFRelease(addrStore);
2603     if (optStore)    CFRelease(optStore);
2604     if (spsAddressKey)  CFRelease(spsAddressKey);
2605     if (ownerOPTRecKey) CFRelease(ownerOPTRecKey);
2606     return KERN_SUCCESS;
2607 }
2608 
getMACAddress(int family,v6addr_t raddr,v6addr_t gaddr,int * gfamily,ethaddr_t eth)2609 mDNSlocal int getMACAddress(int family, v6addr_t raddr, v6addr_t gaddr, int *gfamily, ethaddr_t eth)
2610 {
2611     struct
2612     {
2613         struct rt_msghdr m_rtm;
2614         char   m_space[512];
2615     } m_rtmsg;
2616 
2617     struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
2618     char  *cp  = m_rtmsg.m_space;
2619     int    seq = 6367, sock, i;
2620     ssize_t rlen;
2621     struct sockaddr_in      *sin  = NULL;
2622     struct sockaddr_in6     *sin6 = NULL;
2623     struct sockaddr_dl      *sdl  = NULL;
2624     struct sockaddr_storage  sins;
2625     struct sockaddr_dl       sdl_m;
2626 
2627 #define NEXTADDR(w, s, len)         \
2628 if (rtm->rtm_addrs & (w))       \
2629 {                               \
2630 bcopy((char *)s, cp, len);  \
2631 cp += len;                  \
2632 }
2633 
2634     bzero(&sins,  sizeof(struct sockaddr_storage));
2635     bzero(&sdl_m, sizeof(struct sockaddr_dl));
2636     bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
2637 
2638     sock = socket(PF_ROUTE, SOCK_RAW, 0);
2639     if (sock < 0)
2640     {
2641         const int socket_errno = errno;
2642         LogMsg("getMACAddress: Can not open the socket - %s", strerror(socket_errno));
2643         return socket_errno;
2644     }
2645 
2646     rtm->rtm_addrs   |= RTA_DST | RTA_GATEWAY;
2647     rtm->rtm_type     = RTM_GET;
2648     rtm->rtm_flags    = 0;
2649     rtm->rtm_version  = RTM_VERSION;
2650     rtm->rtm_seq      = ++seq;
2651 
2652     sdl_m.sdl_len     = sizeof(sdl_m);
2653     sdl_m.sdl_family  = AF_LINK;
2654     if (family == AF_INET)
2655     {
2656         sin = (struct sockaddr_in*)&sins;
2657         sin->sin_family = AF_INET;
2658         sin->sin_len    = sizeof(struct sockaddr_in);
2659         memcpy(&sin->sin_addr, raddr, sizeof(struct in_addr));
2660         NEXTADDR(RTA_DST, sin, sin->sin_len);
2661     }
2662     else if (family == AF_INET6)
2663     {
2664         sin6 = (struct sockaddr_in6 *)&sins;
2665         sin6->sin6_len    = sizeof(struct sockaddr_in6);
2666         sin6->sin6_family = AF_INET6;
2667         memcpy(&sin6->sin6_addr, raddr, sizeof(struct in6_addr));
2668         NEXTADDR(RTA_DST, sin6, sin6->sin6_len);
2669     }
2670     NEXTADDR(RTA_GATEWAY, &sdl_m, sdl_m.sdl_len);
2671     rtm->rtm_msglen = (u_short)(cp - (char *)&m_rtmsg);
2672     rlen = rtm->rtm_msglen;
2673 
2674     if (write(sock, (char *)&m_rtmsg, rlen) < 0)
2675     {
2676         const int write_errno = errno;
2677         LogMsg("getMACAddress: writing to routing socket: %s", strerror(write_errno));
2678         close(sock);
2679         return write_errno;
2680     }
2681 
2682     do
2683     {
2684         rlen = read(sock, (char *)&m_rtmsg, sizeof(m_rtmsg));
2685     }
2686     while (rlen > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != getpid()));
2687 
2688     if (rlen < 0)
2689         LogMsg("getMACAddress: Read from routing socket failed");
2690 
2691     if (family == AF_INET)
2692     {
2693         sin = (struct sockaddr_in *) (rtm + 1);
2694         sdl = (struct sockaddr_dl *) (sin->sin_len + (char *) sin);
2695     }
2696     else if (family == AF_INET6)
2697     {
2698         sin6 = (struct sockaddr_in6 *) (rtm +1);
2699         sdl  = (struct sockaddr_dl  *) (sin6->sin6_len + (char *) sin6);
2700     }
2701 
2702     if (!sdl)
2703     {
2704         LogMsg("getMACAddress: sdl is NULL for family %d", family);
2705         close(sock);
2706         return -1;
2707     }
2708 
2709     // If the address is not on the local net, we get the IP address of the gateway.
2710     // We would have to repeat the process to get the MAC address of the gateway
2711     *gfamily = sdl->sdl_family;
2712     if (sdl->sdl_family == AF_INET)
2713     {
2714         if (sin)
2715         {
2716             struct sockaddr_in *new_sin = (struct sockaddr_in *)(sin->sin_len +(char*) sin);
2717             memcpy(gaddr, &new_sin->sin_addr, sizeof(struct in_addr));
2718         }
2719         else
2720         {
2721             LogMsg("getMACAddress: sin is NULL");
2722         }
2723         close(sock);
2724         return -1;
2725     }
2726     else if (sdl->sdl_family == AF_INET6)
2727     {
2728         if (sin6)
2729         {
2730             struct sockaddr_in6 *new_sin6 = (struct sockaddr_in6 *)(sin6->sin6_len +(char*) sin6);
2731             memcpy(gaddr, &new_sin6->sin6_addr, sizeof(struct in6_addr));
2732         }
2733         else
2734         {
2735             LogMsg("getMACAddress: sin6 is NULL");
2736         }
2737         close(sock);
2738         return -1;
2739     }
2740 
2741     unsigned char *ptr = (unsigned char *)LLADDR(sdl);
2742     for (i = 0; i < ETHER_ADDR_LEN; i++)
2743         (eth)[i] = *(ptr +i);
2744 
2745     close(sock);
2746 
2747     return KERN_SUCCESS;
2748 }
2749 
GetRemoteMacinternal(int family,v6addr_t raddr,ethaddr_t eth)2750 mDNSlocal int GetRemoteMacinternal(int family, v6addr_t raddr, ethaddr_t eth)
2751 {
2752     int      ret = 0;
2753     v6addr_t gateway;
2754     int      gfamily = 0;
2755     int      count = 0;
2756 
2757     do
2758     {
2759         ret = getMACAddress(family, raddr, gateway, &gfamily, eth);
2760         if (ret == -1)
2761         {
2762             memcpy(raddr, gateway, (gfamily == AF_INET) ? 4 : 16);
2763             family = gfamily;
2764             count++;
2765         }
2766     }
2767     while ((ret == -1) && (count < 5));
2768     return ret;
2769 }
2770 
StoreSPSMACAddressinternal(int family,v6addr_t spsaddr,const char * ifname)2771 mDNSlocal int StoreSPSMACAddressinternal(int family, v6addr_t spsaddr, const char *ifname)
2772 {
2773     ethaddr_t              eth;
2774     char                   spsip[INET6_ADDRSTRLEN];
2775     int                    ret        = 0;
2776     CFStringRef            sckey      = NULL;
2777     SCDynamicStoreRef      store      = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:StoreSPSMACAddress"), NULL, NULL);
2778     SCDynamicStoreRef      ipstore    = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetIPv6Addresses"), NULL, NULL);
2779     CFMutableDictionaryRef dict       = NULL;
2780     CFStringRef            entityname = NULL;
2781     CFDictionaryRef        ipdict     = NULL;
2782     CFArrayRef             addrs      = NULL;
2783 
2784     if ((store == NULL) || (ipstore == NULL))
2785     {
2786         LogMsg("StoreSPSMACAddressinternal: Unable to accesss SC Dynamic Store");
2787         ret = -1;
2788         goto fin;
2789     }
2790 
2791     // Get the MAC address of the Sleep Proxy Server
2792     memset(eth, 0, sizeof(eth));
2793     ret = GetRemoteMacinternal(family, spsaddr, eth);
2794     if (ret !=  0)
2795     {
2796         LogMsg("StoreSPSMACAddressinternal: Failed to determine the MAC address");
2797         goto fin;
2798     }
2799 
2800     // Create/Update the dynamic store entry for the specified interface
2801     sckey = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname, "/BonjourSleepProxyAddress");
2802     dict  = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2803     if (!dict)
2804     {
2805         LogMsg("StoreSPSMACAddressinternal: SPSCreateDict() Could not create CFDictionary dict");
2806         ret = -1;
2807         goto fin;
2808     }
2809 
2810     CFStringRef macaddr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%02x:%02x:%02x:%02x:%02x:%02x"), eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
2811     CFDictionarySetValue(dict, CFSTR("MACAddress"), macaddr);
2812     if (NULL != macaddr)
2813         CFRelease(macaddr);
2814 
2815     if( NULL == inet_ntop(family, (void *)spsaddr, spsip, sizeof(spsip)))
2816     {
2817         LogMsg("StoreSPSMACAddressinternal: inet_ntop failed: %s", strerror(errno));
2818         ret = -1;
2819         goto fin;
2820     }
2821 
2822     CFStringRef ipaddr = CFStringCreateWithCString(NULL, spsip, kCFStringEncodingUTF8);
2823     CFDictionarySetValue(dict, CFSTR("IPAddress"), ipaddr);
2824     if (NULL != ipaddr)
2825         CFRelease(ipaddr);
2826 
2827     // Get the current IPv6 addresses on this interface and store them so NAs can be sent on wakeup
2828     if ((entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/IPv6"), ifname)) != NULL)
2829     {
2830         if ((ipdict = SCDynamicStoreCopyValue(ipstore, entityname)) != NULL)
2831         {
2832             if((addrs = CFDictionaryGetValue(ipdict, CFSTR("Addresses"))) != NULL)
2833             {
2834                 addrs = CFRetain(addrs);
2835                 CFDictionarySetValue(dict, CFSTR("RegisteredAddresses"), addrs);
2836             }
2837         }
2838     }
2839     SCDynamicStoreSetValue(store, sckey, dict);
2840 
2841 fin:
2842     if (store)      CFRelease(store);
2843     if (ipstore)    CFRelease(ipstore);
2844     if (sckey)      CFRelease(sckey);
2845     if (dict)       CFRelease(dict);
2846     if (ipdict)     CFRelease(ipdict);
2847     if (entityname) CFRelease(entityname);
2848     if (addrs)      CFRelease(addrs);
2849 
2850     return ret;
2851 }
2852 
mDNSStoreSPSMACAddress(int family,v6addr_t spsaddr,char * ifname)2853 mDNSlocal void mDNSStoreSPSMACAddress(int family, v6addr_t spsaddr, char *ifname)
2854 {
2855     struct
2856     {
2857         v6addr_t saddr;
2858     } addr;
2859     int err = 0;
2860 
2861     mDNSPlatformMemCopy(addr.saddr, spsaddr, sizeof(v6addr_t));
2862 
2863     err = StoreSPSMACAddressinternal(family, (uint8_t *)addr.saddr, ifname);
2864     if (err != 0)
2865         LogMsg("mDNSStoreSPSMACAddress : failed");
2866 }
2867 
mDNSPlatformStoreSPSMACAddr(mDNSAddr * spsaddr,char * ifname)2868 mDNSexport mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname)
2869 {
2870     int family = (spsaddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
2871 
2872     LogInfo("mDNSPlatformStoreSPSMACAddr : Storing %#a on interface %s", spsaddr, ifname);
2873     mDNSStoreSPSMACAddress(family, spsaddr->ip.v6.b, ifname);
2874 
2875     return KERN_SUCCESS;
2876 }
2877 
2878 
mDNSPlatformStoreOwnerOptRecord(char * ifname,DNSMessage * msg,int length)2879 mDNSexport mStatus mDNSPlatformStoreOwnerOptRecord(char *ifname, DNSMessage* msg, int length)
2880 {
2881     int                    ret   = 0;
2882     CFStringRef            sckey = NULL;
2883     SCDynamicStoreRef      store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:StoreOwnerOPTRecord"), NULL, NULL);
2884     CFMutableDictionaryRef dict  = NULL;
2885 
2886     if (store == NULL)
2887     {
2888         LogMsg("mDNSPlatformStoreOwnerOptRecord: Unable to accesss SC Dynamic Store");
2889         ret = -1;
2890         goto fin;
2891     }
2892 
2893     // Create/Update the dynamic store entry for the specified interface
2894     sckey = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname, "/BonjourSleepProxyOPTRecord");
2895     dict  = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2896     if (!dict)
2897     {
2898         LogMsg("mDNSPlatformStoreOwnerOptRecord: Could not create CFDictionary dictionary to store OPT Record");
2899         ret =-1;
2900         goto fin;
2901     }
2902 
2903     CFDataRef optRec = NULL;
2904     optRec = CFDataCreate(NULL, (const uint8_t *)msg, (CFIndex)length);
2905     CFDictionarySetValue(dict, CFSTR("OwnerOPTRecord"), optRec);
2906     if (NULL != optRec) CFRelease(optRec);
2907 
2908     SCDynamicStoreSetValue(store, sckey, dict);
2909 
2910 fin:
2911     if (NULL != store)  CFRelease(store);
2912     if (NULL != sckey)  CFRelease(sckey);
2913     if (NULL != dict)   CFRelease(dict);
2914     return ret;
2915 }
2916 
mDNSGet_RemoteMAC(int family,v6addr_t raddr)2917 mDNSlocal void mDNSGet_RemoteMAC(int family, v6addr_t raddr)
2918 {
2919     ethaddr_t            eth;
2920     IPAddressMACMapping *addrMapping;
2921     int kr = KERN_FAILURE;
2922     struct
2923     {
2924         v6addr_t addr;
2925     } dst;
2926 
2927     bzero(eth, sizeof(ethaddr_t));
2928     mDNSPlatformMemCopy(dst.addr, raddr, sizeof(v6addr_t));
2929 
2930     kr = GetRemoteMacinternal(family, (uint8_t *)dst.addr, eth);
2931 
2932     // If the call to get the remote MAC address succeeds, allocate and copy
2933     // the values and schedule a task to update the MAC address in the TCP Keepalive record.
2934     if (kr == 0)
2935     {
2936         addrMapping = (IPAddressMACMapping *) mDNSPlatformMemAllocateClear(sizeof(*addrMapping));
2937         // This memory allocation is not checked for failure
2938         // It also shoudn’t need to be a memory allocation at all -- why not just use a stack variable? -- SC
2939         snprintf(addrMapping->ethaddr, sizeof(addrMapping->ethaddr), "%02x:%02x:%02x:%02x:%02x:%02x",
2940                      eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
2941         // Why is the address represented using text? The UpdateRMAC routine just parses it back into a six-byte MAC address. -- SC
2942         if (family == AF_INET)
2943         {
2944             addrMapping->ipaddr.type = mDNSAddrType_IPv4;
2945             mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v4.b, raddr, sizeof(v6addr_t));
2946             // This is the wrong size. It’s using sizeof(v6addr_t) for an IPv4 address -- SC
2947         }
2948         else
2949         {
2950             addrMapping->ipaddr.type = mDNSAddrType_IPv6;
2951             mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v6.b, raddr, sizeof(v6addr_t));
2952         }
2953         UpdateRMAC(&mDNSStorage, addrMapping);
2954     }
2955 }
2956 
mDNSPlatformGetRemoteMacAddr(mDNSAddr * raddr)2957 mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNSAddr *raddr)
2958 {
2959     int family = (raddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
2960 
2961     LogInfo("mDNSPlatformGetRemoteMacAddr calling mDNSGet_RemoteMAC");
2962     mDNSGet_RemoteMAC(family, raddr->ip.v6.b);
2963 
2964     return KERN_SUCCESS;
2965 }
2966 
mDNSPlatformRetrieveTCPInfo(mDNSAddr * laddr,mDNSIPPort * lport,mDNSAddr * raddr,mDNSIPPort * rport,mDNSTCPInfo * mti)2967 mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
2968 {
2969     mDNSs32 intfid;
2970     mDNSs32 error  = 0;
2971     int     family = (laddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
2972 
2973     error = mDNSRetrieveTCPInfo(family, laddr->ip.v6.b, lport->NotAnInteger, raddr->ip.v6.b, rport->NotAnInteger, (uint32_t *)&(mti->seq), (uint32_t *)&(mti->ack), (uint16_t *)&(mti->window), (int32_t*)&intfid);
2974     if (error != KERN_SUCCESS)
2975     {
2976         LogMsg("%s: mDNSRetrieveTCPInfo returned : %d", __func__, error);
2977         return error;
2978     }
2979     mti->IntfId = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, intfid);
2980     return error;
2981 }
2982 
2983 #define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from)
2984 
CountProxyTargets(NetworkInterfaceInfoOSX * x,int * p4,int * p6)2985 mDNSlocal int CountProxyTargets(NetworkInterfaceInfoOSX *x, int *p4, int *p6)
2986 {
2987     int numv4 = 0, numv6 = 0;
2988     AuthRecord *rr;
2989 
2990     for (rr = mDNSStorage.ResourceRecords; rr; rr=rr->next)
2991         if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
2992         {
2993             if (p4) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.4a", x->BPF_fd, x->ifinfo.ifname, numv4, &rr->AddressProxy.ip.v4);
2994             numv4++;
2995         }
2996 
2997     for (rr = mDNSStorage.ResourceRecords; rr; rr=rr->next)
2998         if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
2999         {
3000             if (p6) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.16a", x->BPF_fd, x->ifinfo.ifname, numv6, &rr->AddressProxy.ip.v6);
3001             numv6++;
3002         }
3003 
3004     if (p4) *p4 = numv4;
3005     if (p6) *p6 = numv6;
3006     return(numv4 + numv6);
3007 }
3008 
mDNSPlatformUpdateProxyList(const mDNSInterfaceID InterfaceID)3009 mDNSexport void mDNSPlatformUpdateProxyList(const mDNSInterfaceID InterfaceID)
3010 {
3011     mDNS *const m = &mDNSStorage;
3012     NetworkInterfaceInfoOSX *x;
3013 
3014     // Note: We can't use IfIndexToInterfaceInfoOSX because that looks for Registered also.
3015     for (x = m->p->InterfaceList; x; x = x->next) if ((x->ifinfo.InterfaceID == InterfaceID) && (x->BPF_fd >= 0)) break;
3016 
3017     if (!x) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID); return; }
3018 
3019     #define MAX_BPF_ADDRS 250
3020     int numv4 = 0, numv6 = 0;
3021 
3022     if (CountProxyTargets(x, &numv4, &numv6) > MAX_BPF_ADDRS)
3023     {
3024         LogMsg("mDNSPlatformUpdateProxyList: ERROR Too many address proxy records v4 %d v6 %d", numv4, numv6);
3025         if (numv4 > MAX_BPF_ADDRS) numv4 = MAX_BPF_ADDRS;
3026         numv6 = MAX_BPF_ADDRS - numv4;
3027     }
3028 
3029     LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s MAC  %.6a %d v4 %d v6", x->BPF_fd, x->ifinfo.ifname, &x->ifinfo.MAC, numv4, numv6);
3030 
3031     // Caution: This is a static structure, so we need to be careful that any modifications we make to it
3032     // are done in such a way that they work correctly when mDNSPlatformUpdateProxyList is called multiple times
3033     static struct bpf_insn filter[17 + MAX_BPF_ADDRS] =
3034     {
3035         BPF_STMT(BPF_LD  + BPF_H   + BPF_ABS, 12),              // 0 Read Ethertype (bytes 12,13)
3036 
3037         BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0806, 0, 1),      // 1 If Ethertype == ARP goto next, else 3
3038         BPF_STMT(BPF_RET + BPF_K,             42),              // 2 Return 42-byte ARP
3039 
3040         BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0800, 4, 0),      // 3 If Ethertype == IPv4 goto 8 (IPv4 address list check) else next
3041 
3042         BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x86DD, 0, 9),      // 4 If Ethertype == IPv6 goto next, else exit
3043         BPF_STMT(BPF_LD  + BPF_H   + BPF_ABS, 20),              // 5 Read Protocol and Hop Limit (bytes 20,21)
3044         BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x3AFF, 0, 9),      // 6 If (Prot,TTL) == (3A,FF) goto next, else IPv6 address list check
3045         BPF_STMT(BPF_RET + BPF_K,             86),              // 7 Return 86-byte ND
3046 
3047         // Is IPv4 packet; check if it's addressed to any IPv4 address we're proxying for
3048         BPF_STMT(BPF_LD  + BPF_W   + BPF_ABS, 30),              // 8 Read IPv4 Dst (bytes 30,31,32,33)
3049     };
3050 
3051     // Special filter program to use when there are no address proxy records
3052     static struct bpf_insn nullfilter[] =
3053     {
3054         BPF_STMT(BPF_RET | BPF_K, 0)                            // 0 Match no packets and return size 0
3055     };
3056 
3057     struct bpf_program prog;
3058     if (!numv4 && !numv6)
3059     {
3060         LogSPS("mDNSPlatformUpdateProxyList: No need for filter");
3061         if (m->timenow == 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0");
3062 
3063         // Cancel any previous ND group memberships we had
3064         if (x->BPF_mcfd >= 0)
3065         {
3066             close(x->BPF_mcfd);
3067             x->BPF_mcfd = -1;
3068         }
3069 
3070         // Schedule check to see if we can close this BPF_fd now
3071         if (!m->NetworkChanged) m->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
3072         if (x->BPF_fd < 0) return;      // If we've already closed our BPF_fd, no need to generate an error message below
3073         prog.bf_len   = 1;
3074         prog.bf_insns = nullfilter;
3075     }
3076     else
3077     {
3078         struct bpf_insn *pc   = &filter[9];
3079         struct bpf_insn *chk6 = pc   + numv4 + 1;   // numv4 address checks, plus a "return 0"
3080         struct bpf_insn *fail = chk6 + 1 + numv6;   // Get v6 Dst LSW, plus numv6 address checks
3081         struct bpf_insn *ret4 = fail + 1;
3082         struct bpf_insn *ret6 = ret4 + 4;
3083 
3084         static const struct bpf_insn rf  = BPF_STMT(BPF_RET + BPF_K, 0);                // No match: Return nothing
3085 
3086         static const struct bpf_insn g6  = BPF_STMT(BPF_LD  + BPF_W   + BPF_ABS, 50);   // Read IPv6 Dst LSW (bytes 50,51,52,53)
3087 
3088         static const struct bpf_insn r4a = BPF_STMT(BPF_LDX + BPF_B   + BPF_MSH, 14);   // Get IP Header length (normally 20)
3089         static const struct bpf_insn r4b = BPF_STMT(BPF_LD  + BPF_IMM,           54);   // A = 54 (14-byte Ethernet plus 20-byte TCP + 20 bytes spare)
3090         static const struct bpf_insn r4c = BPF_STMT(BPF_ALU + BPF_ADD + BPF_X,    0);   // A += IP Header length
3091         static const struct bpf_insn r4d = BPF_STMT(BPF_RET + BPF_A, 0);                // Success: Return Ethernet + IP + TCP + 20 bytes spare (normally 74)
3092 
3093         static const struct bpf_insn r6a = BPF_STMT(BPF_RET + BPF_K, 94);               // Success: Return Eth + IPv6 + TCP + 20 bytes spare
3094 
3095         BPF_SetOffset(&filter[4], jf, fail);    // If Ethertype not ARP, IPv4, or IPv6, fail
3096         BPF_SetOffset(&filter[6], jf, chk6);    // If IPv6 but not ICMPv6, go to IPv6 address list check
3097 
3098         // BPF Byte-Order Note
3099         // The BPF API designers apparently thought that programmers would not be smart enough to use htons
3100         // and htonl correctly to convert numeric values to network byte order on little-endian machines,
3101         // so instead they chose to make the API implicitly byte-swap *ALL* values, even literal byte strings
3102         // that shouldn't be byte-swapped, like ASCII text, Ethernet addresses, IP addresses, etc.
3103         // As a result, if we put Ethernet addresses and IP addresses in the right byte order, the BPF API
3104         // will byte-swap and make them backwards, and then our filter won't work. So, we have to arrange
3105         // that on little-endian machines we deliberately put addresses in memory with the bytes backwards,
3106         // so that when the BPF API goes through and swaps them all, they end up back as they should be.
3107         // In summary, if we byte-swap all the non-numeric fields that shouldn't be swapped, and we *don't*
3108         // swap any of the numeric values that *should* be byte-swapped, then the filter will work correctly.
3109 
3110         // IPSEC capture size notes:
3111         //  8 bytes UDP header
3112         //  4 bytes Non-ESP Marker
3113         // 28 bytes IKE Header
3114         // --
3115         // 40 Total. Capturing TCP Header + 20 gets us enough bytes to receive the IKE Header in a UDP-encapsulated IKE packet.
3116 
3117         AuthRecord *rr;
3118         for (rr = m->ResourceRecords; rr; rr=rr->next)
3119             if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
3120             {
3121                 mDNSv4Addr a = rr->AddressProxy.ip.v4;
3122                 pc->code = BPF_JMP + BPF_JEQ + BPF_K;
3123                 BPF_SetOffset(pc, jt, ret4);
3124                 pc->jf   = 0;
3125                 pc->k    = (bpf_u_int32)a.b[0] << 24 | (bpf_u_int32)a.b[1] << 16 | (bpf_u_int32)a.b[2] << 8 | (bpf_u_int32)a.b[3];
3126                 pc++;
3127             }
3128         *pc++ = rf;
3129 
3130         if (pc != chk6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc, chk6);
3131         *pc++ = g6; // chk6 points here
3132 
3133         // First cancel any previous ND group memberships we had, then create a fresh socket
3134         if (x->BPF_mcfd >= 0) close(x->BPF_mcfd);
3135         x->BPF_mcfd = socket(AF_INET6, SOCK_DGRAM, 0);
3136 
3137         for (rr = m->ResourceRecords; rr; rr=rr->next)
3138             if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
3139             {
3140                 const mDNSv6Addr *const a = &rr->AddressProxy.ip.v6;
3141                 pc->code = BPF_JMP + BPF_JEQ + BPF_K;
3142                 BPF_SetOffset(pc, jt, ret6);
3143                 pc->jf   = 0;
3144                 pc->k    = (bpf_u_int32)a->b[0x0C] << 24 | (bpf_u_int32)a->b[0x0D] << 16 | (bpf_u_int32)a->b[0x0E] << 8 | (bpf_u_int32)a->b[0x0F];
3145                 pc++;
3146 
3147                 struct ipv6_mreq i6mr;
3148                 i6mr.ipv6mr_interface = x->scope_id;
3149                 i6mr.ipv6mr_multiaddr = *(const struct in6_addr*)&NDP_prefix;
3150                 i6mr.ipv6mr_multiaddr.s6_addr[0xD] = a->b[0xD];
3151                 i6mr.ipv6mr_multiaddr.s6_addr[0xE] = a->b[0xE];
3152                 i6mr.ipv6mr_multiaddr.s6_addr[0xF] = a->b[0xF];
3153 
3154                 // Do precautionary IPV6_LEAVE_GROUP first, necessary to clear stale kernel state
3155                 mStatus err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
3156                 if (err < 0 && (errno != EADDRNOTAVAIL))
3157                     LogMsg("mDNSPlatformUpdateProxyList: IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
3158 
3159                 err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
3160                 if (err < 0 && (errno != EADDRINUSE))   // Joining same group twice can give "Address already in use" error -- no need to report that
3161                     LogMsg("mDNSPlatformUpdateProxyList: IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
3162 
3163                 LogSPS("Joined IPv6 ND multicast group %.16a for %.16a", &i6mr.ipv6mr_multiaddr, a);
3164             }
3165 
3166         if (pc != fail) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc, fail);
3167         *pc++ = rf;     // fail points here
3168 
3169         if (pc != ret4) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc, ret4);
3170         *pc++ = r4a;    // ret4 points here
3171         *pc++ = r4b;
3172         *pc++ = r4c;
3173         *pc++ = r4d;
3174 
3175         if (pc != ret6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc, ret6);
3176         *pc++ = r6a;    // ret6 points here
3177 #if 0
3178         // For debugging BPF filter program
3179         unsigned int q;
3180         for (q=0; q<prog.bf_len; q++)
3181             LogSPS("mDNSPlatformUpdateProxyList: %2d { 0x%02x, %d, %d, 0x%08x },", q, prog.bf_insns[q].code, prog.bf_insns[q].jt, prog.bf_insns[q].jf, prog.bf_insns[q].k);
3182 #endif
3183         prog.bf_len   = (u_int)(pc - filter);
3184         prog.bf_insns = filter;
3185     }
3186 
3187     if (ioctl(x->BPF_fd, BIOCSETFNR, &prog) < 0) LogMsg("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) failed %d (%s)", prog.bf_len, errno, strerror(errno));
3188     else LogSPS("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) successful", prog.bf_len);
3189 }
3190 
mDNSPlatformReceiveBPF_fd(int fd)3191 mDNSexport void mDNSPlatformReceiveBPF_fd(int fd)
3192 {
3193     mDNS *const m = &mDNSStorage;
3194     mDNS_Lock(m);
3195 
3196     NetworkInterfaceInfoOSX *i;
3197     for (i = m->p->InterfaceList; i; i = i->next) if (i->BPF_fd == -2) break;
3198     if (!i) { LogSPS("mDNSPlatformReceiveBPF_fd: No Interfaces awaiting BPF fd %d; closing", fd); close(fd); }
3199     else
3200     {
3201         LogSPS("%s using   BPF fd %d", i->ifinfo.ifname, fd);
3202 
3203         struct bpf_version v;
3204         if (ioctl(fd, BIOCVERSION, &v) < 0)
3205             LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3206         else if (BPF_MAJOR_VERSION != v.bv_major || BPF_MINOR_VERSION != v.bv_minor)
3207             LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION header %d.%d kernel %d.%d",
3208                    fd, i->ifinfo.ifname, BPF_MAJOR_VERSION, BPF_MINOR_VERSION, v.bv_major, v.bv_minor);
3209 
3210         if (ioctl(fd, BIOCGBLEN, &i->BPF_len) < 0)
3211             LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCGBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3212 
3213         if (i->BPF_len > sizeof(m->imsg))
3214         {
3215             i->BPF_len = sizeof(m->imsg);
3216             if (ioctl(fd, BIOCSBLEN, &i->BPF_len) < 0)
3217                 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3218             else
3219                 LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", fd, i->ifinfo.ifname, i->BPF_len);
3220         }
3221 
3222         static const u_int opt_one = 1;
3223         if (ioctl(fd, BIOCIMMEDIATE, &opt_one) < 0)
3224             LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCIMMEDIATE failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3225 
3226         //if (ioctl(fd, BIOCPROMISC, &opt_one) < 0)
3227         //  LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCPROMISC failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3228 
3229         //if (ioctl(fd, BIOCSHDRCMPLT, &opt_one) < 0)
3230         //  LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSHDRCMPLT failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3231 
3232         /*  <rdar://problem/10287386>
3233          *  make socket non blocking see comments in bpf_callback_common for more info
3234          */
3235         if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
3236         {
3237             LogMsg("mDNSPlatformReceiveBPF_fd: %d %s O_NONBLOCK failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3238         }
3239 
3240         struct ifreq ifr;
3241         mDNSPlatformMemZero(&ifr, sizeof(ifr));
3242         strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
3243         if (ioctl(fd, BIOCSETIF, &ifr) < 0)
3244         { LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSETIF failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); i->BPF_fd = -3; }
3245         else
3246         {
3247 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
3248             i->BPF_fd  = fd;
3249             i->BPF_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, dispatch_get_main_queue());
3250             if (!i->BPF_source) {LogMsg("mDNSPlatformReceiveBPF_fd: dispatch source create failed"); return;}
3251             dispatch_source_set_event_handler(i->BPF_source, ^{bpf_callback_dispatch(i);});
3252             dispatch_source_set_cancel_handler(i->BPF_source, ^{close(fd);});
3253             dispatch_resume(i->BPF_source);
3254 #else
3255             CFSocketContext myCFSocketContext = { 0, i, NULL, NULL, NULL };
3256             i->BPF_fd  = fd;
3257             i->BPF_cfs = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack, bpf_callback, &myCFSocketContext);
3258             i->BPF_rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, i->BPF_cfs, 0);
3259             CFRunLoopAddSource(CFRunLoopGetMain(), i->BPF_rls, kCFRunLoopDefaultMode);
3260 #endif
3261             mDNSPlatformUpdateProxyList(i->ifinfo.InterfaceID);
3262         }
3263     }
3264 
3265     mDNS_Unlock(m);
3266 }
3267 
3268 #endif // APPLE_OSX_mDNSResponder
3269 
3270 #if COMPILER_LIKES_PRAGMA_MARK
3271 #pragma mark -
3272 #pragma mark - Key Management
3273 #endif
3274 
3275 #ifndef NO_SECURITYFRAMEWORK
CopyCertChain(SecIdentityRef identity)3276 mDNSlocal CFArrayRef CopyCertChain(SecIdentityRef identity)
3277 {
3278     CFMutableArrayRef certChain = NULL;
3279     if (!identity) { LogMsg("CopyCertChain: identity is NULL"); return(NULL); }
3280     SecCertificateRef cert;
3281     OSStatus err = SecIdentityCopyCertificate(identity, &cert);
3282     if (err || !cert) LogMsg("CopyCertChain: SecIdentityCopyCertificate() returned %d", (int) err);
3283     else
3284     {
3285 #pragma clang diagnostic push
3286 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
3287         SecPolicySearchRef searchRef;
3288         err = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef);
3289         if (err || !searchRef) LogMsg("CopyCertChain: SecPolicySearchCreate() returned %d", (int) err);
3290         else
3291         {
3292             SecPolicyRef policy;
3293             err = SecPolicySearchCopyNext(searchRef, &policy);
3294             if (err || !policy) LogMsg("CopyCertChain: SecPolicySearchCopyNext() returned %d", (int) err);
3295             else
3296             {
3297                 CFArrayRef wrappedCert = CFArrayCreate(NULL, (const void**) &cert, 1, &kCFTypeArrayCallBacks);
3298                 if (!wrappedCert) LogMsg("CopyCertChain: wrappedCert is NULL");
3299                 else
3300                 {
3301                     SecTrustRef trust;
3302                     err = SecTrustCreateWithCertificates(wrappedCert, policy, &trust);
3303                     if (err || !trust) LogMsg("CopyCertChain: SecTrustCreateWithCertificates() returned %d", (int) err);
3304                     else
3305                     {
3306                         err = SecTrustEvaluate(trust, NULL);
3307                         if (err) LogMsg("CopyCertChain: SecTrustEvaluate() returned %d", (int) err);
3308                         else
3309                         {
3310                             CFArrayRef rawCertChain;
3311                             CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
3312                             err = SecTrustGetResult(trust, NULL, &rawCertChain, &statusChain);
3313                             if (err || !rawCertChain || !statusChain) LogMsg("CopyCertChain: SecTrustGetResult() returned %d", (int) err);
3314                             else
3315                             {
3316                                 certChain = CFArrayCreateMutableCopy(NULL, 0, rawCertChain);
3317                                 if (!certChain) LogMsg("CopyCertChain: certChain is NULL");
3318                                 else
3319                                 {
3320                                     // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
3321                                     // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
3322                                     CFArraySetValueAtIndex(certChain, 0, identity);
3323                                     // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
3324                                     if (CFArrayGetCount(certChain) > 1) CFArrayRemoveValueAtIndex(certChain, CFArrayGetCount(certChain) - 1);
3325                                 }
3326                                 CFRelease(rawCertChain);
3327                                 // Do not free statusChain:
3328                                 // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
3329                                 // certChain: Call the CFRelease function to release this object when you are finished with it.
3330                                 // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
3331                             }
3332                         }
3333                         CFRelease(trust);
3334                     }
3335                     CFRelease(wrappedCert);
3336                 }
3337                 CFRelease(policy);
3338             }
3339             CFRelease(searchRef);
3340         }
3341 #pragma clang diagnostic pop
3342         CFRelease(cert);
3343     }
3344     return certChain;
3345 }
3346 #endif /* NO_SECURITYFRAMEWORK */
3347 
mDNSPlatformTLSSetupCerts(void)3348 mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
3349 {
3350 #ifdef NO_SECURITYFRAMEWORK
3351     return mStatus_UnsupportedErr;
3352 #else
3353     SecIdentityRef identity = nil;
3354     SecIdentitySearchRef srchRef = nil;
3355     OSStatus err;
3356 
3357 #pragma clang diagnostic push
3358 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
3359     // search for "any" identity matching specified key use
3360     // In this app, we expect there to be exactly one
3361     err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_DECRYPT, &srchRef);
3362     if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err); return err; }
3363 
3364     err = SecIdentitySearchCopyNext(srchRef, &identity);
3365     if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err); return err; }
3366 #pragma clang diagnostic pop
3367 
3368     if (CFGetTypeID(identity) != SecIdentityGetTypeID())
3369     { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr; }
3370 
3371     // Found one. Call CopyCertChain to create the correct certificate chain.
3372     ServerCerts = CopyCertChain(identity);
3373     if (ServerCerts == nil) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: CopyCertChain error"); return mStatus_UnknownErr; }
3374 
3375     return mStatus_NoError;
3376 #endif /* NO_SECURITYFRAMEWORK */
3377 }
3378 
mDNSPlatformTLSTearDownCerts(void)3379 mDNSexport void  mDNSPlatformTLSTearDownCerts(void)
3380 {
3381 #ifndef NO_SECURITYFRAMEWORK
3382     if (ServerCerts) { CFRelease(ServerCerts); ServerCerts = NULL; }
3383 #endif /* NO_SECURITYFRAMEWORK */
3384 }
3385 
3386 
3387 mDNSlocal void mDNSDomainLabelFromCFString(CFStringRef cfs, domainlabel *const namelabel);
3388 
3389 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
GetUserSpecifiedFriendlyComputerName(domainlabel * const namelabel)3390 mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
3391 {
3392     CFStringEncoding encoding = kCFStringEncodingUTF8;
3393     CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
3394 
3395     if (cfs == mDNSNULL) {
3396         return;
3397     }
3398 
3399     mDNSDomainLabelFromCFString(cfs, namelabel);
3400 
3401     CFRelease(cfs);
3402 }
3403 
GetUserSpecifiedLocalHostName(domainlabel * const namelabel)3404 mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel)
3405 {
3406     CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
3407 
3408     if (cfs == mDNSNULL) {
3409         return;
3410     }
3411 
3412     mDNSDomainLabelFromCFString(cfs, namelabel);
3413 
3414     CFRelease(cfs);
3415 }
3416 
mDNSDomainLabelFromCFString(CFStringRef cfs,domainlabel * const namelabel)3417 mDNSlocal void mDNSDomainLabelFromCFString(CFStringRef cfs, domainlabel *const namelabel)
3418 {
3419     CFIndex num_of_bytes_write = 0;
3420     CFStringGetBytes(cfs, CFRangeMake(0, CFStringGetLength(cfs)), kCFStringEncodingUTF8, 0, FALSE, namelabel->c + 1, sizeof(*namelabel) - 1, &num_of_bytes_write);
3421     namelabel->c[0] = num_of_bytes_write;
3422 }
3423 
DictionaryIsEnabled(CFDictionaryRef dict)3424 mDNSexport mDNSBool DictionaryIsEnabled(CFDictionaryRef dict)
3425 {
3426     mDNSs32 val;
3427     CFNumberRef state = (CFNumberRef)CFDictionaryGetValue(dict, CFSTR("Enabled"));
3428     if (state == NULL) return mDNSfalse;
3429     if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val))
3430     { LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse; }
3431     return val ? mDNStrue : mDNSfalse;
3432 }
3433 
SetupAddr(mDNSAddr * ip,const struct sockaddr * const sa)3434 mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
3435 {
3436     if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
3437 
3438     if (sa->sa_family == AF_INET)
3439     {
3440         struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
3441         ip->type = mDNSAddrType_IPv4;
3442         ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
3443         return(mStatus_NoError);
3444     }
3445 
3446     if (sa->sa_family == AF_INET6)
3447     {
3448         struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
3449         // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
3450         // value into the second word of the IPv6 link-local address, so they can just
3451         // pass around IPv6 address structures instead of full sockaddr_in6 structures.
3452         // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
3453         // To work around this we always whack the second word of any IPv6 link-local address back to zero.
3454         if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
3455         ip->type = mDNSAddrType_IPv6;
3456         ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
3457         return(mStatus_NoError);
3458     }
3459 
3460     LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
3461     return(mStatus_Invalid);
3462 }
3463 
GetBSSID(char * ifa_name)3464 mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name)
3465 {
3466     mDNSEthAddr eth = zeroEthAddr;
3467 
3468     CFStringRef entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name);
3469     if (entityname)
3470     {
3471         CFDictionaryRef dict = SCDynamicStoreCopyValue(NULL, entityname);
3472         if (dict)
3473         {
3474             CFRange range = { 0, 6 };       // Offset, length
3475             CFDataRef data = CFDictionaryGetValue(dict, CFSTR("BSSID"));
3476             if (data && CFDataGetLength(data) == 6)
3477                 CFDataGetBytes(data, range, eth.b);
3478             CFRelease(dict);
3479         }
3480         CFRelease(entityname);
3481     }
3482 
3483     return(eth);
3484 }
3485 
GetMAC(mDNSEthAddr * eth,u_short ifindex)3486 mDNSlocal int GetMAC(mDNSEthAddr *eth, u_short ifindex)
3487 {
3488     struct ifaddrs *ifa;
3489     for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
3490         if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_LINK)
3491         {
3492             const struct sockaddr_dl *const sdl = (const struct sockaddr_dl *)ifa->ifa_addr;
3493             if (sdl->sdl_index == ifindex)
3494             { mDNSPlatformMemCopy(eth->b, sdl->sdl_data + sdl->sdl_nlen, 6); return 0; }
3495         }
3496     *eth = zeroEthAddr;
3497     return -1;
3498 }
3499 
3500 #ifndef SIOCGIFWAKEFLAGS
3501 #define SIOCGIFWAKEFLAGS _IOWR('i', 136, struct ifreq) /* get interface wake property flags */
3502 #endif
3503 
3504 #ifndef IF_WAKE_ON_MAGIC_PACKET
3505 #define IF_WAKE_ON_MAGIC_PACKET 0x01
3506 #endif
3507 
3508 #ifndef ifr_wake_flags
3509 #define ifr_wake_flags ifr_ifru.ifru_intval
3510 #endif
3511 
3512 mDNSlocal
3513 kern_return_t
RegistryEntrySearchCFPropertyAndIOObject(io_registry_entry_t entry,const io_name_t plane,CFStringRef keystr,CFTypeRef * outProperty,io_registry_entry_t * outEntry)3514 RegistryEntrySearchCFPropertyAndIOObject( io_registry_entry_t     entry,
3515                                           const io_name_t         plane,
3516                                           CFStringRef             keystr,
3517                                           CFTypeRef *             outProperty,
3518                                           io_registry_entry_t *   outEntry)
3519 {
3520     kern_return_t       kr;
3521 
3522     IOObjectRetain(entry);
3523     while (entry)
3524     {
3525         CFTypeRef ref = IORegistryEntryCreateCFProperty(entry, keystr, kCFAllocatorDefault, mDNSNULL);
3526         if (ref)
3527         {
3528             if (outProperty) *outProperty = ref;
3529             else             CFRelease(ref);
3530             break;
3531         }
3532         io_registry_entry_t parent;
3533         kr = IORegistryEntryGetParentEntry(entry, plane, &parent);
3534         if (kr != KERN_SUCCESS) parent = mDNSNULL;
3535         IOObjectRelease(entry);
3536         entry = parent;
3537     }
3538     if (!entry)          kr = kIOReturnNoDevice;
3539     else
3540     {
3541         if (outEntry)   *outEntry = entry;
3542         else            IOObjectRelease(entry);
3543         kr = KERN_SUCCESS;
3544     }
3545     return(kr);
3546 }
3547 
CheckInterfaceSupport(NetworkInterfaceInfo * const intf,const char * key)3548 mDNSlocal mDNSBool  CheckInterfaceSupport(NetworkInterfaceInfo *const intf, const char *key)
3549 {
3550     io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname));
3551     if (!service)
3552     {
3553         LogSPS("CheckInterfaceSupport: No service for interface %s", intf->ifname);
3554         return mDNSfalse;
3555     }
3556 
3557     mDNSBool    ret    = mDNSfalse;
3558 
3559     CFStringRef keystr =  CFStringCreateWithCString(NULL, key, kCFStringEncodingUTF8);
3560     kern_return_t kr = RegistryEntrySearchCFPropertyAndIOObject(service, kIOServicePlane, keystr, mDNSNULL, mDNSNULL);
3561     CFRelease(keystr);
3562     if (kr == KERN_SUCCESS) ret = mDNStrue;
3563     else
3564     {
3565         io_name_t n1;
3566         IOObjectGetClass(service, n1);
3567         LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_INFO,
3568             "CheckInterfaceSupport: No " PUB_S " for interface " PUB_S "/" PUB_S " kr 0x%X", key, intf->ifname, n1, kr);
3569         ret = mDNSfalse;
3570     }
3571 
3572     IOObjectRelease(service);
3573     return ret;
3574 }
3575 
3576 
3577 #if !TARGET_OS_WATCH
InterfaceSupportsKeepAlive(NetworkInterfaceInfo * const intf)3578 mDNSlocal  mDNSBool InterfaceSupportsKeepAlive(NetworkInterfaceInfo *const intf)
3579 {
3580     return CheckInterfaceSupport(intf, mDNS_IOREG_KA_KEY);
3581 }
3582 #endif
3583 
NetWakeInterface(NetworkInterfaceInfoOSX * i)3584 mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i)
3585 {
3586 #if TARGET_OS_WATCH
3587     (void) i;   // unused
3588     return(mDNSfalse);
3589 #else
3590     // We only use Sleep Proxy Service on multicast-capable interfaces, except loopback and D2D.
3591     if (!MulticastInterface(i) || (i->ifa_flags & IFF_LOOPBACK) || i->D2DInterface)
3592     {
3593         LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_DEBUG,
3594             "NetWakeInterface: returning false for " PUB_S, i->ifinfo.ifname);
3595         return(mDNSfalse);
3596     }
3597 
3598     // If the interface supports TCPKeepalive, it is capable of waking up for a magic packet
3599     // This check is needed since the SIOCGIFWAKEFLAGS ioctl returns wrong values for WOMP capability
3600     // when the power source is not AC Power.
3601     if (InterfaceSupportsKeepAlive(&i->ifinfo))
3602     {
3603         LogSPS("NetWakeInterface: %s supports TCP Keepalive returning true", i->ifinfo.ifname);
3604         return mDNStrue;
3605     }
3606 
3607     int s = socket(AF_INET, SOCK_DGRAM, 0);
3608     if (s < 0) { LogMsg("NetWakeInterface socket failed %s error %d errno %d (%s)", i->ifinfo.ifname, s, errno, strerror(errno)); return(mDNSfalse); }
3609 
3610     struct ifreq ifr;
3611     strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
3612     if (ioctl(s, SIOCGIFWAKEFLAGS, &ifr) < 0)
3613     {
3614         const int ioctl_errno = errno;
3615         // For some strange reason, in /usr/include/sys/errno.h, EOPNOTSUPP is defined to be
3616         // 102 when compiling kernel code, and 45 when compiling user-level code. Since this
3617         // error code is being returned from the kernel, we need to use the kernel version.
3618         #define KERNEL_EOPNOTSUPP 102
3619         if (ioctl_errno != KERNEL_EOPNOTSUPP) // "Operation not supported on socket", the expected result on Leopard and earlier
3620             LogMsg("NetWakeInterface SIOCGIFWAKEFLAGS %s errno %d (%s)", i->ifinfo.ifname, ioctl_errno, strerror(ioctl_errno));
3621         // If on Leopard or earlier, we get EOPNOTSUPP, so in that case
3622         // we enable WOL if this interface is not AirPort and "Wake for Network access" is turned on.
3623         ifr.ifr_wake_flags = (ioctl_errno == KERNEL_EOPNOTSUPP && !(i)->BSSID.l[0] && i->m->SystemWakeOnLANEnabled) ? IF_WAKE_ON_MAGIC_PACKET : 0;
3624     }
3625 
3626     close(s);
3627 
3628     // ifr.ifr_wake_flags = IF_WAKE_ON_MAGIC_PACKET;    // For testing with MacBook Air, using a USB dongle that doesn't actually support Wake-On-LAN
3629 
3630     LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_INFO,
3631         "NetWakeInterface: " PUB_S " " PRI_IP_ADDR " " PUB_S " WOMP",
3632         i->ifinfo.ifname, &i->ifinfo.ip, (ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) ? "supports" : "no");
3633 
3634     return((ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) != 0);
3635 #endif  // TARGET_OS_WATCH
3636 }
3637 
getExtendedFlags(const char * ifa_name)3638 mDNSlocal u_int64_t getExtendedFlags(const char *ifa_name)
3639 {
3640     int sockFD;
3641     struct ifreq ifr;
3642 
3643     sockFD = socket(AF_INET, SOCK_DGRAM, 0);
3644     if (sockFD < 0)
3645     {
3646         LogMsg("getExtendedFlags: socket() call failed, errno = %d (%s)", errno, strerror(errno));
3647         return 0;
3648     }
3649 
3650     ifr.ifr_addr.sa_family = AF_INET;
3651     strlcpy(ifr.ifr_name, ifa_name, sizeof(ifr.ifr_name));
3652 
3653     if (ioctl(sockFD, SIOCGIFEFLAGS, (caddr_t)&ifr) == -1)
3654     {
3655         LogMsg("getExtendedFlags: SIOCGIFEFLAGS failed for %s, errno = %d (%s)", ifa_name, errno, strerror(errno));
3656         ifr.ifr_eflags = 0;
3657     }
3658 
3659     close(sockFD);
3660     return ifr.ifr_eflags;
3661 }
3662 
isExcludedInterface(int sockFD,char * ifa_name)3663 mDNSlocal mDNSBool isExcludedInterface(int sockFD, char * ifa_name)
3664 {
3665     struct ifreq ifr;
3666 
3667     // llw0 and nan0 interfaces are excluded from Bonjour discover.
3668     // There currently is no interface attributed based way to identify these interfaces
3669     // until rdar://problem/47933782 is addressed.
3670     if ((strncmp(ifa_name, "llw", 3) == 0) || (strncmp(ifa_name, "nan", 3) == 0))
3671     {
3672         LogMsg("isExcludedInterface: excluding %s", ifa_name);
3673         return mDNStrue;
3674     }
3675 
3676     // Coprocessor interfaces are also excluded.
3677     if (sockFD < 0)
3678     {
3679         LogMsg("isExcludedInterface: invalid socket FD passed: %d", sockFD);
3680         return mDNSfalse;
3681     }
3682 
3683     memset(&ifr, 0, sizeof(struct ifreq));
3684     strlcpy(ifr.ifr_name, ifa_name, sizeof(ifr.ifr_name));
3685 
3686     if (ioctl(sockFD, SIOCGIFFUNCTIONALTYPE, (caddr_t)&ifr) == -1)
3687     {
3688         LogMsg("isExcludedInterface: SIOCGIFFUNCTIONALTYPE failed, errno = %d (%s)", errno, strerror(errno));
3689         return mDNSfalse;
3690     }
3691 
3692     if (ifr.ifr_functional_type == IFRTYPE_FUNCTIONAL_INTCOPROC)
3693     {
3694         LogMsg("isExcludedInterface: excluding coprocessor interface %s", ifa_name);
3695         return mDNStrue;
3696     }
3697     else
3698         return mDNSfalse;
3699 }
3700 
3701 #if (TARGET_OS_IPHONE && !TARGET_OS_MACCATALYST)
3702 
3703 // Function pointers for the routines we use in the MobileWiFi framework.
3704 static WiFiManagerClientRef (*WiFiManagerClientCreate_p)(CFAllocatorRef allocator, WiFiClientType type) = mDNSNULL;
3705 static CFArrayRef (*WiFiManagerClientCopyDevices_p)(WiFiManagerClientRef manager) = mDNSNULL;
3706 static WiFiNetworkRef (*WiFiDeviceClientCopyCurrentNetwork_p)(WiFiDeviceClientRef device) = mDNSNULL;
3707 static bool (*WiFiNetworkIsCarPlay_p)(WiFiNetworkRef network) = mDNSNULL;
3708 
MobileWiFiLibLoad(void)3709 mDNSlocal mDNSBool MobileWiFiLibLoad(void)
3710 {
3711     static mDNSBool isInitialized = mDNSfalse;
3712     static void *MobileWiFiLib_p = mDNSNULL;
3713     static const char path[] = "/System/Library/PrivateFrameworks/MobileWiFi.framework/MobileWiFi";
3714 
3715     if (!isInitialized)
3716     {
3717         if (!MobileWiFiLib_p)
3718         {
3719             MobileWiFiLib_p = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
3720             if (!MobileWiFiLib_p)
3721             {
3722                 LogInfo("MobileWiFiLibLoad: dlopen() failed.");
3723                 goto exit;
3724             }
3725         }
3726 
3727         if (!WiFiManagerClientCreate_p)
3728         {
3729             WiFiManagerClientCreate_p = dlsym(MobileWiFiLib_p, "WiFiManagerClientCreate");
3730             if (!WiFiManagerClientCreate_p)
3731             {
3732                 LogInfo("MobileWiFiLibLoad: load of WiFiManagerClientCreate symbol failed.");
3733                 goto exit;
3734             }
3735         }
3736 
3737         if (!WiFiManagerClientCopyDevices_p)
3738         {
3739             WiFiManagerClientCopyDevices_p = dlsym(MobileWiFiLib_p, "WiFiManagerClientCopyDevices");
3740             if (!WiFiManagerClientCopyDevices_p)
3741             {
3742                 LogInfo("MobileWiFiLibLoad: load of WiFiManagerClientCopyDevices symbol failed.");
3743                 goto exit;
3744             }
3745         }
3746 
3747         if (!WiFiDeviceClientCopyCurrentNetwork_p)
3748         {
3749             WiFiDeviceClientCopyCurrentNetwork_p = dlsym(MobileWiFiLib_p, "WiFiDeviceClientCopyCurrentNetwork");
3750             if (!WiFiDeviceClientCopyCurrentNetwork_p)
3751             {
3752                 LogInfo("MobileWiFiLibLoad: load of WiFiDeviceClientCopyCurrentNetwork symbol failed.");
3753                 goto exit;
3754             }
3755         }
3756 
3757         if (!WiFiNetworkIsCarPlay_p)
3758         {
3759             WiFiNetworkIsCarPlay_p = dlsym(MobileWiFiLib_p, "WiFiNetworkIsCarPlay");
3760             if (!WiFiNetworkIsCarPlay_p)
3761             {
3762                 LogInfo("MobileWiFiLibLoad: load of WiFiNetworkIsCarPlay symbol failed.");
3763                 goto exit;
3764             }
3765         }
3766 
3767         isInitialized = mDNStrue;
3768     }
3769 
3770 exit:
3771     return isInitialized;
3772 }
3773 
3774 #define CARPLAY_DEBUG 0
3775 
3776 // Return true if the interface is associate to a CarPlay hosted SSID.
3777 // If we have associated with a CarPlay hosted SSID, then use the same
3778 // optimizations that are used when an interface has the IFEF_DIRECTLINK flag set.
IsCarPlaySSID(char * ifa_name)3779 mDNSlocal mDNSBool IsCarPlaySSID(char *ifa_name)
3780 {
3781     static WiFiManagerClientRef manager = NULL;
3782     CFArrayRef              devices;
3783     WiFiDeviceClientRef     device;
3784     WiFiNetworkRef          network;
3785     mDNSBool                rvalue = mDNSfalse;
3786 
3787     if (!MobileWiFiLibLoad())
3788     {
3789         LogInfo("IsCarPlaySSID: MobileWiFiLibLoad() failed!");
3790         return mDNSfalse;
3791     }
3792 
3793     // Cache the WiFiManagerClientRef.
3794     if (manager == NULL)
3795         manager = WiFiManagerClientCreate_p(NULL, kWiFiClientTypeNormal);
3796 
3797     if (manager == NULL)
3798     {
3799         LogInfo("IsCarPlaySSID: WiFiManagerClientCreate() failed!");
3800         return mDNSfalse;
3801     }
3802 
3803     devices = WiFiManagerClientCopyDevices_p(manager);
3804 
3805     // If the first call fails, update the cached WiFiManagerClientRef pointer and try again.
3806     if (devices == NULL)
3807     {
3808         LogInfo("IsCarPlaySSID: First call to WiFiManagerClientCopyDevices() returned NULL for %s", ifa_name);
3809 
3810         // Release the previously cached WiFiManagerClientRef which is apparently now stale.
3811         CFRelease(manager);
3812         manager = WiFiManagerClientCreate_p(NULL, kWiFiClientTypeNormal);
3813         if (manager == NULL)
3814         {
3815             LogInfo("IsCarPlaySSID: WiFiManagerClientCreate() failed!");
3816             return mDNSfalse;
3817         }
3818         devices = WiFiManagerClientCopyDevices_p(manager);
3819         if (devices == NULL)
3820         {
3821             LogInfo("IsCarPlaySSID: Second call to WiFiManagerClientCopyDevices() returned NULL for %s", ifa_name);
3822             return mDNSfalse;
3823         }
3824     }
3825 
3826     device = (WiFiDeviceClientRef)CFArrayGetValueAtIndex(devices, 0);
3827     network = WiFiDeviceClientCopyCurrentNetwork_p(device);
3828     if (network != NULL)
3829     {
3830         if (WiFiNetworkIsCarPlay_p(network))
3831         {
3832             LogInfo("IsCarPlaySSID: %s is CarPlay hosted", ifa_name);
3833             rvalue = mDNStrue;
3834         }
3835 #if CARPLAY_DEBUG
3836         else
3837             LogInfo("IsCarPlaySSID: %s is NOT CarPlay hosted", ifa_name);
3838 #endif // CARPLAY_DEBUG
3839 
3840         CFRelease(network);
3841     }
3842     else
3843         LogInfo("IsCarPlaySSID: WiFiDeviceClientCopyCurrentNetwork() returned NULL for %s", ifa_name);
3844 
3845     CFRelease(devices);
3846 
3847     return rvalue;
3848 }
3849 
3850 #else   // TARGET_OS_IPHONE
3851 
IsCarPlaySSID(char * ifa_name)3852 mDNSlocal mDNSBool IsCarPlaySSID(char *ifa_name)
3853 {
3854     (void)ifa_name;  // unused
3855 
3856     // OSX WifiManager currently does not implement WiFiNetworkIsCarPlay()
3857     return mDNSfalse;;
3858 }
3859 
3860 #endif  // TARGET_OS_IPHONE
3861 
3862 // Returns pointer to newly created NetworkInterfaceInfoOSX object, or
3863 // pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
3864 // may return NULL if out of memory (unlikely) or parameters are invalid for some reason
3865 // (e.g. sa_family not AF_INET or AF_INET6)
3866 
AddInterfaceToList(const struct ifaddrs * ifa,const mDNSs32 utc)3867 mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(const struct ifaddrs *ifa, const mDNSs32 utc)
3868 {
3869     mDNS *const m = &mDNSStorage;
3870     mDNSu32 scope_id  = if_nametoindex(ifa->ifa_name);
3871     mDNSEthAddr bssid = GetBSSID(ifa->ifa_name);
3872     u_int64_t   eflags = getExtendedFlags(ifa->ifa_name);
3873 
3874     mDNSAddr ip, mask;
3875     if (SetupAddr(&ip,   ifa->ifa_addr   ) != mStatus_NoError) return(NULL);
3876     if (SetupAddr(&mask, ifa->ifa_netmask) != mStatus_NoError) return(NULL);
3877 
3878     NetworkInterfaceInfoOSX **p;
3879     for (p = &m->p->InterfaceList; *p; p = &(*p)->next)
3880     {
3881         if (scope_id == (*p)->scope_id &&
3882             mDNSSameAddress(&ip, &(*p)->ifinfo.ip) &&
3883             mDNSSameEthAddress(&bssid, &(*p)->BSSID))
3884         {
3885             debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p, ifname before %s, after %s", scope_id, &bssid, &ip, *p, (*p)->ifinfo.ifname, ifa->ifa_name);
3886             if ((*p)->Exists)
3887             {
3888                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
3889                     "Ignoring attempt to re-add interface (" PUB_S ", " PRI_IP_ADDR ") already marked as existing",
3890                     ifa->ifa_name, &ip);
3891                 return(*p);
3892             }
3893             // The name should be updated to the new name so that we don't report a wrong name in our SIGINFO output.
3894             // When interfaces are created with same MAC address, kernel resurrects the old interface.
3895             // Even though the interface index is the same (which should be sufficient), when we receive a UDP packet
3896             // we get the corresponding name for the interface index on which the packet was received and check against
3897             // the InterfaceList for a matching name. So, keep the name in sync.
3898             strlcpy((*p)->ifinfo.ifname, ifa->ifa_name, sizeof((*p)->ifinfo.ifname));
3899 
3900             // Determine if multicast state has changed.
3901             const mDNSBool txrx = MulticastInterface(*p);
3902             if ((*p)->ifinfo.McastTxRx != txrx)
3903             {
3904                 (*p)->ifinfo.McastTxRx = txrx;
3905                 (*p)->Exists = MulticastStateChanged; // State change; need to deregister and reregister this interface
3906             }
3907             else
3908                  (*p)->Exists = mDNStrue;
3909 
3910             // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
3911             if ((*p)->LastSeen != utc) (*p)->AppearanceTime = utc;
3912 
3913             // If Wake-on-LAN capability of this interface has changed (e.g. because power cable on laptop has been disconnected)
3914             // we may need to start or stop or sleep proxy browse operation
3915             const mDNSBool NetWake = NetWakeInterface(*p);
3916             if ((*p)->ifinfo.NetWake != NetWake)
3917             {
3918                 (*p)->ifinfo.NetWake = NetWake;
3919                 // If this interface is already registered with mDNSCore, then we need to start or stop its NetWake browse on-the-fly.
3920                 // If this interface is not already registered (i.e. it's a dormant interface we had in our list
3921                 // from when we previously saw it) then we mustn't do that, because mDNSCore doesn't know about it yet.
3922                 // In this case, the mDNS_RegisterInterface() call will take care of starting the NetWake browse if necessary.
3923                 if ((*p)->Registered)
3924                 {
3925                     mDNS_Lock(m);
3926                     if (NetWake) mDNS_ActivateNetWake_internal  (m, &(*p)->ifinfo);
3927                     else         mDNS_DeactivateNetWake_internal(m, &(*p)->ifinfo);
3928                     mDNS_Unlock(m);
3929                 }
3930             }
3931             // Reset the flag if it has changed this time.
3932             (*p)->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue;
3933 
3934             return(*p);
3935         }
3936     }
3937     NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *) callocL("NetworkInterfaceInfoOSX", sizeof(*i));
3938     debugf("AddInterfaceToList: Making   new   interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i);
3939     if (!i) return(mDNSNULL);
3940     i->ifinfo.InterfaceID = (mDNSInterfaceID)(uintptr_t)scope_id;
3941     i->ifinfo.ip          = ip;
3942     i->ifinfo.mask        = mask;
3943     strlcpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname));
3944     i->ifinfo.ifname[sizeof(i->ifinfo.ifname)-1] = 0;
3945     // We can be configured to disable multicast advertisement, but we want to to support
3946     // local-only services, which need a loopback address record.
3947     i->ifinfo.Advertise   = m->DivertMulticastAdvertisements ? ((ifa->ifa_flags & IFF_LOOPBACK) ? mDNStrue : mDNSfalse) : m->AdvertiseLocalAddresses;
3948     i->ifinfo.Loopback    = ((ifa->ifa_flags & IFF_LOOPBACK) != 0) ? mDNStrue : mDNSfalse;
3949     i->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue;
3950 
3951     // Setting DirectLink indicates we can do the optimization of skipping the probe phase
3952     // for the interface address records since they should be unique.
3953     // Unfortunately, the legacy p2p* interfaces do not set the IFEF_LOCALNET_PRIVATE
3954     // or IFEF_DIRECTLINK flags, so we have to match against the name.
3955     if ((eflags & (IFEF_DIRECTLINK | IFEF_AWDL)) || (strncmp(i->ifinfo.ifname, "p2p", 3) == 0))
3956         i->ifinfo.DirectLink  = mDNStrue;
3957     else
3958         i->ifinfo.DirectLink  = IsCarPlaySSID(ifa->ifa_name);
3959 
3960     if (i->ifinfo.DirectLink)
3961         LogInfo("AddInterfaceToList: DirectLink set for %s", ifa->ifa_name);
3962 
3963     i->next            = mDNSNULL;
3964     i->m               = m;
3965     i->Exists          = mDNStrue;
3966     i->Flashing        = mDNSfalse;
3967     i->Occulting       = mDNSfalse;
3968 
3969     i->D2DInterface    = ((eflags & IFEF_LOCALNET_PRIVATE) || (strncmp(i->ifinfo.ifname, "p2p", 3) == 0)) ? mDNStrue: mDNSfalse;
3970     if (i->D2DInterface)
3971         LogInfo("AddInterfaceToList: D2DInterface set for %s", ifa->ifa_name);
3972     i->isAWDL          = (eflags & IFEF_AWDL)      ? mDNStrue: mDNSfalse;
3973 
3974     if (eflags & IFEF_AWDL)
3975     {
3976         // Set SupportsUnicastMDNSResponse false for the AWDL interface since unicast reserves
3977         // limited AWDL resources so we don't set the kDNSQClass_UnicastResponse bit in
3978         // Bonjour requests over the AWDL interface.
3979         i->ifinfo.SupportsUnicastMDNSResponse = mDNSfalse;
3980     }
3981     else
3982     {
3983         i->ifinfo.SupportsUnicastMDNSResponse = mDNStrue;
3984     }
3985     i->AppearanceTime  = utc;       // Brand new interface; AppearanceTime is now
3986     i->LastSeen        = utc;
3987     i->ifa_flags       = ifa->ifa_flags;
3988     i->scope_id        = scope_id;
3989     i->BSSID           = bssid;
3990     i->sa_family       = ifa->ifa_addr->sa_family;
3991     i->BPF_fd          = -1;
3992     i->BPF_mcfd        = -1;
3993     i->BPF_len         = 0;
3994     i->Registered      = mDNSNULL;
3995 
3996     // MulticastInterface() depends on the "m" and "ifa_flags" values being initialized above.
3997     i->ifinfo.McastTxRx   = MulticastInterface(i);
3998     // Do this AFTER i->BSSID has been set up
3999     i->ifinfo.NetWake  = (eflags & IFEF_EXPENSIVE)? mDNSfalse :  NetWakeInterface(i);
4000     GetMAC(&i->ifinfo.MAC, scope_id);
4001     if (i->ifinfo.NetWake && !i->ifinfo.MAC.l[0])
4002         LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i->ifinfo.MAC, scope_id, i->ifinfo.ifname, &ip);
4003     i->ift_family = GetIFTFamily(i->ifinfo.ifname);
4004 
4005     *p = i;
4006     return(i);
4007 }
4008 
4009 #if COMPILER_LIKES_PRAGMA_MARK
4010 #pragma mark -
4011 #pragma mark - Power State & Configuration Change Management
4012 #endif
4013 
ReorderInterfaceList()4014 mDNSlocal mStatus ReorderInterfaceList()
4015 {
4016     // Disable Reorder lists till <rdar://problem/30071012> is fixed to prevent spurious name conflicts
4017 #ifdef PR_30071012_FIXED
4018     mDNS *const m = &mDNSStorage;
4019     nwi_state_t state = nwi_state_copy();
4020 
4021     if (state == mDNSNULL)
4022     {
4023         LogMsg("NWI State is NULL!");
4024         return (mStatus_Invalid);
4025     }
4026 
4027     // Get the count of interfaces
4028     mDNSu32 count =  nwi_state_get_interface_names(state, mDNSNULL, 0);
4029     if (count == 0)
4030     {
4031         LogMsg("Unable to get the ordered list of interface names");
4032         nwi_state_release(state);
4033         return (mStatus_Invalid);
4034     }
4035 
4036     // Get the ordered interface list
4037     int i;
4038     const char *names[count];
4039     count = nwi_state_get_interface_names(state, names, count);
4040 
4041     NetworkInterfaceInfo *newList = mDNSNULL;
4042     for (i = count-1; i >= 0; i--)
4043     {   // Build a new ordered interface list
4044         NetworkInterfaceInfo **ptr = &m->HostInterfaces;
4045         while (*ptr != mDNSNULL )
4046         {
4047             if (strcmp((*ptr)->ifname, names[i]) == 0)
4048             {
4049                 NetworkInterfaceInfo *node = *ptr;
4050                 *ptr = (*ptr)->next;
4051                 node->next = newList;
4052                 newList = node;
4053             }
4054             else
4055                 ptr = &((*ptr)->next);
4056         }
4057     }
4058 
4059     // Get to the end of the list
4060     NetworkInterfaceInfo *newListEnd = newList;
4061     while (newListEnd != mDNSNULL && newListEnd->next != mDNSNULL)
4062         newListEnd = newListEnd->next;
4063 
4064     // Add any remaing interfaces to the end of the sorted list
4065     if (newListEnd != mDNSNULL)
4066         newListEnd->next  = m->HostInterfaces;
4067 
4068     // If we have a valid new list, point to that now
4069     if (newList != mDNSNULL)
4070         m->HostInterfaces = newList;
4071 
4072     nwi_state_release(state);
4073 #endif // PR_30071012_FIXED
4074     return (mStatus_NoError);
4075 }
4076 
UpdateInterfaceList(mDNSs32 utc)4077 mDNSlocal mStatus UpdateInterfaceList(mDNSs32 utc)
4078 {
4079     mDNS *const m = &mDNSStorage;
4080     struct ifaddrs *ifa = myGetIfAddrs(0);
4081     char defaultname[64];
4082     int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
4083     if (InfoSocket < 3 && errno != EAFNOSUPPORT)
4084         LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno));
4085 
4086     if (m->SleepState == SleepState_Sleeping) ifa = NULL;
4087 
4088     for (; ifa; ifa = ifa->ifa_next)
4089     {
4090 #if LIST_ALL_INTERFACES
4091         if (ifa->ifa_addr)
4092         {
4093             if (ifa->ifa_addr->sa_family == AF_APPLETALK)
4094                 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
4095                        ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
4096             else if (ifa->ifa_addr->sa_family == AF_LINK)
4097                 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
4098                        ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
4099             else if (ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6)
4100                 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
4101                        ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
4102         }
4103         else
4104             LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X ifa_addr is NOT set",
4105                    ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags);
4106 
4107         if (!(ifa->ifa_flags & IFF_UP))
4108             LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
4109                    ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags,
4110                    ifa->ifa_addr ? ifa->ifa_addr->sa_family : 0);
4111         if (!(ifa->ifa_flags & IFF_MULTICAST))
4112             LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
4113                    ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags,
4114                    ifa->ifa_addr ? ifa->ifa_addr->sa_family : 0);
4115         if (ifa->ifa_flags & IFF_POINTOPOINT)
4116             LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
4117                    ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags,
4118                    ifa->ifa_addr ? ifa->ifa_addr->sa_family : 0);
4119         if (ifa->ifa_flags & IFF_LOOPBACK)
4120             LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
4121                    ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags,
4122                    ifa->ifa_addr ? ifa->ifa_addr->sa_family : 0);
4123 #endif
4124 
4125         if (!ifa->ifa_addr || isExcludedInterface(InfoSocket, ifa->ifa_name))
4126         {
4127             continue;
4128         }
4129 
4130         if (ifa->ifa_addr->sa_family == AF_LINK)
4131         {
4132             const struct sockaddr_dl *const sdl = (const struct sockaddr_dl *)ifa->ifa_addr;
4133             if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == sizeof(m->PrimaryMAC) && mDNSSameEthAddress(&m->PrimaryMAC, &zeroEthAddr))
4134             {
4135                 mDNSPlatformMemCopy(m->PrimaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6);
4136             }
4137             if (!AWDLInterfaceID && (sdl->sdl_index > 0))
4138             {
4139                 const uint64_t eflags = getExtendedFlags(ifa->ifa_name);
4140                 if (eflags & IFEF_AWDL)
4141                 {
4142                     AWDLInterfaceID = (mDNSInterfaceID)((uintptr_t)sdl->sdl_index);
4143                     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
4144                         "UpdateInterfaceList: AWDLInterfaceID = %lu", (unsigned long) AWDLInterfaceID);
4145                 }
4146             }
4147         }
4148 
4149         if (ifa->ifa_flags & IFF_UP)
4150         {
4151             if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6)
4152             {
4153                 if (!ifa->ifa_netmask)
4154                 {
4155                     mDNSAddr ip;
4156                     SetupAddr(&ip, ifa->ifa_addr);
4157                     LogMsg("UpdateInterfaceList: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
4158                            ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip);
4159                 }
4160                 // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be zero, so we don't complain about that
4161                 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
4162                 else if (ifa->ifa_netmask->sa_family != ifa->ifa_addr->sa_family && ifa->ifa_netmask->sa_family != 0)
4163                 {
4164                     mDNSAddr ip;
4165                     SetupAddr(&ip, ifa->ifa_addr);
4166                     LogMsg("UpdateInterfaceList: ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
4167                            ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip, ifa->ifa_netmask->sa_family);
4168                 }
4169                 // Currently we use a few internal ones like mDNSInterfaceID_LocalOnly etc. that are negative values (0, -1, -2).
4170                 else if ((int)if_nametoindex(ifa->ifa_name) <= 0)
4171                 {
4172                     LogMsg("UpdateInterfaceList: if_nametoindex returned zero/negative value for %5s(%d)", ifa->ifa_name, if_nametoindex(ifa->ifa_name));
4173                 }
4174                 else
4175                 {
4176                     // Make sure ifa_netmask->sa_family is set correctly
4177                     // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
4178                     ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family;
4179                     int ifru_flags6 = 0;
4180 
4181                     struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
4182                     if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
4183                     {
4184                         struct in6_ifreq ifr6;
4185                         mDNSPlatformMemZero((char *)&ifr6, sizeof(ifr6));
4186                         strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
4187                         ifr6.ifr_addr = *sin6;
4188                         if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
4189                             ifru_flags6 = ifr6.ifr_ifru.ifru_flags6;
4190                         verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6);
4191                     }
4192 
4193                     if (!(ifru_flags6 & (IN6_IFF_TENTATIVE | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
4194                     {
4195                         AddInterfaceToList(ifa, utc);
4196                     }
4197                 }
4198             }
4199         }
4200     }
4201 
4202     if (InfoSocket >= 0)
4203         close(InfoSocket);
4204 
4205     mDNS_snprintf(defaultname, sizeof(defaultname), "%.*s-%02X%02X%02X%02X%02X%02X", HINFO_HWstring_prefixlen, HINFO_HWstring,
4206                   m->PrimaryMAC.b[0], m->PrimaryMAC.b[1], m->PrimaryMAC.b[2], m->PrimaryMAC.b[3], m->PrimaryMAC.b[4], m->PrimaryMAC.b[5]);
4207 
4208     // Set up the nice label
4209     domainlabel nicelabel;
4210     nicelabel.c[0] = 0;
4211     GetUserSpecifiedFriendlyComputerName(&nicelabel);
4212     if (nicelabel.c[0] == 0)
4213     {
4214         debugf("Couldn’t read user-specified Computer Name; using default “%s” instead", defaultname);
4215         MakeDomainLabelFromLiteralString(&nicelabel, defaultname);
4216     }
4217 
4218     // Set up the RFC 1034-compliant label
4219     domainlabel hostlabel;
4220     hostlabel.c[0] = 0;
4221     GetUserSpecifiedLocalHostName(&hostlabel);
4222     if (hostlabel.c[0] == 0)
4223     {
4224         debugf("Couldn’t read user-specified Local Hostname; using default “%s.local” instead", defaultname);
4225         MakeDomainLabelFromLiteralString(&hostlabel, defaultname);
4226     }
4227 
4228     // We use a case-sensitive comparison here because even though changing the capitalization
4229     // of the name alone is not significant to DNS, it's still a change from the user's point of view
4230     if (SameDomainLabelCS(m->p->usernicelabel.c, nicelabel.c))
4231         debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m->p->usernicelabel.c, m->nicelabel.c);
4232     else
4233     {
4234         if (m->p->usernicelabel.c[0])   // Don't show message first time through, when we first read name from prefs on boot
4235             LogMsg("User updated Computer Name from “%#s” to “%#s”", m->p->usernicelabel.c, nicelabel.c);
4236         m->p->usernicelabel = m->nicelabel = nicelabel;
4237     }
4238 
4239     if (SameDomainLabelCS(m->p->userhostlabel.c, hostlabel.c))
4240         debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m->p->userhostlabel.c, m->hostlabel.c);
4241     else
4242     {
4243         if (m->p->userhostlabel.c[0])   // Don't show message first time through, when we first read name from prefs on boot
4244             LogMsg("User updated Local Hostname from “%#s” to “%#s”", m->p->userhostlabel.c, hostlabel.c);
4245         m->p->userhostlabel = m->hostlabel = hostlabel;
4246         mDNS_SetFQDN(m);
4247     }
4248 
4249     return(mStatus_NoError);
4250 }
4251 
4252 // Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
4253 // Returns -1 if all the one-bits are not contiguous
CountMaskBits(mDNSAddr * mask)4254 mDNSlocal int CountMaskBits(mDNSAddr *mask)
4255 {
4256     int i = 0, bits = 0;
4257     int bytes = mask->type == mDNSAddrType_IPv4 ? 4 : mask->type == mDNSAddrType_IPv6 ? 16 : 0;
4258     while (i < bytes)
4259     {
4260         mDNSu8 b = mask->ip.v6.b[i++];
4261         while (b & 0x80) { bits++; b <<= 1; }
4262         if (b) return(-1);
4263     }
4264     while (i < bytes) if (mask->ip.v6.b[i++]) return(-1);
4265     return(bits);
4266 }
4267 
mDNSGroupJoinOrLeave(const int sock,const NetworkInterfaceInfoOSX * const i,const mDNSBool join)4268 mDNSlocal void mDNSGroupJoinOrLeave(const int sock, const NetworkInterfaceInfoOSX *const i, const mDNSBool join)
4269 {
4270     int level;
4271     struct group_req gr;
4272     mDNSPlatformMemZero(&gr, sizeof(gr));
4273     gr.gr_interface = i->scope_id;
4274     switch (i->sa_family)
4275     {
4276         case AF_INET: {
4277             struct sockaddr_in *const sin = (struct sockaddr_in *)&gr.gr_group;
4278             sin->sin_len         = sizeof(*sin);
4279             sin->sin_family      = AF_INET;
4280             sin->sin_addr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
4281             level = IPPROTO_IP;
4282             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, PUB_S "ing mcast group " PUB_IPv4_ADDR " on " PUB_S " (%u)",
4283                 join ? "Join" : "Leav", &sin->sin_addr.s_addr, i->ifinfo.ifname, i->scope_id);
4284             break;
4285         }
4286         case AF_INET6: {
4287             struct sockaddr_in6 *const sin6 = (struct sockaddr_in6 *)&gr.gr_group;
4288             sin6->sin6_len    = sizeof(*sin6);
4289             sin6->sin6_family = AF_INET6;
4290             memcpy(sin6->sin6_addr.s6_addr, AllDNSLinkGroup_v6.ip.v6.b, sizeof(sin6->sin6_addr.s6_addr));
4291             level = IPPROTO_IPV6;
4292             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, PUB_S "ing mcast group " PUB_IPv6_ADDR " on " PUB_S " (%u)",
4293                 join ? "Join" : "Leav", sin6->sin6_addr.s6_addr, i->ifinfo.ifname, i->scope_id);
4294             break;
4295         }
4296         default:
4297             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
4298                 "Cannot " PUB_S " mcast group on " PUB_S " (%u) for unrecognized address family %d",
4299                 join ? "join" : "leave", i->ifinfo.ifname, i->scope_id, i->sa_family);
4300             goto exit;
4301     }
4302     const int err = setsockopt(sock, level, join ? MCAST_JOIN_GROUP : MCAST_LEAVE_GROUP, &gr, sizeof(gr));
4303     if (err)
4304     {
4305         // When joining a group, ignore EADDRINUSE errors, which can ocur when the same group is joined twice.
4306         // When leaving a group, ignore EADDRNOTAVAIL errors, which can occur when an interface is no longer present.
4307         const int opterrno = errno;
4308         if ((join && (opterrno != EADDRINUSE)) || (!join && (opterrno != EADDRNOTAVAIL)))
4309         {
4310             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
4311                 "setsockopt - IPPROTO_IP" PUB_S "/MCAST_" PUB_S "_GROUP error %d errno %d (%s) on " PUB_S " (%u)",
4312                 (level == IPPROTO_IPV6) ? "V6" : "", join ? "JOIN" : "LEAVE", err, opterrno, strerror(opterrno),
4313                 i->ifinfo.ifname, i->scope_id);
4314         }
4315     }
4316 
4317 exit:
4318     return;
4319 }
4320 #define mDNSGroupJoin(SOCK, INTERFACE)  mDNSGroupJoinOrLeave(SOCK, INTERFACE, mDNStrue)
4321 #define mDNSGroupLeave(SOCK, INTERFACE) mDNSGroupJoinOrLeave(SOCK, INTERFACE, mDNSfalse)
4322 
4323 // Returns count of non-link local V4 addresses registered (why? -- SC)
SetupActiveInterfaces(mDNSs32 utc)4324 mDNSlocal int SetupActiveInterfaces(mDNSs32 utc)
4325 {
4326     mDNS *const m = &mDNSStorage;
4327     NetworkInterfaceInfoOSX *i;
4328     int count = 0;
4329 
4330     // Recalculate SuppressProbes time based on the current set of active interfaces.
4331     m->SuppressProbes = 0;
4332     for (i = m->p->InterfaceList; i; i = i->next)
4333         if (i->Exists)
4334         {
4335             NetworkInterfaceInfo *const n = &i->ifinfo;
4336             NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(i->ifinfo.ifname, AF_UNSPEC);
4337 
4338             if (i->Registered && i->Registered != primary)  // Sanity check
4339             {
4340                 LogMsg("SetupActiveInterfaces ERROR! n->Registered %p != primary %p", i->Registered, primary);
4341                 i->Registered = mDNSNULL;
4342             }
4343 
4344             if (!i->Registered)
4345             {
4346                 InterfaceActivationSpeed activationSpeed;
4347 
4348                 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
4349                 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
4350                 // If i->Registered is NOT set, then we haven't registered it and we should not try to deregister it.
4351                 i->Registered = primary;
4352 
4353                 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
4354                 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
4355                 // If the interface is an old one that went away and came back in less than a minute, then we're in a flapping scenario.
4356                 i->Occulting = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->LastSeen > 0 && utc - i->LastSeen < 60);
4357 
4358                 // The "p2p*" interfaces used for legacy AirDrop reuse the scope-id, MAC address and the IP address
4359                 // every time a new interface is created. We think it is a duplicate and hence consider it
4360                 // as flashing and occulting, that is, flapping. If an interface is marked as flapping,
4361                 // mDNS_RegisterInterface() changes the probe delay from 1/2 second to 5 seconds and
4362                 // logs a warning message to system.log noting frequent interface transitions.
4363                 // The same logic applies when the IFEF_DIRECTLINK flag is set on the interface.
4364                 if ((strncmp(i->ifinfo.ifname, "p2p", 3) == 0) || i->ifinfo.DirectLink)
4365                 {
4366                     activationSpeed = FastActivation;
4367                     LogInfo("SetupActiveInterfaces: %s DirectLink interface registering", i->ifinfo.ifname);
4368                 }
4369 #if MDNSRESPONDER_SUPPORTS(APPLE, SLOW_ACTIVATION)
4370                 else if (i->Flashing && i->Occulting)
4371                 {
4372                     activationSpeed = SlowActivation;
4373                 }
4374 #endif
4375                 else
4376                 {
4377                     activationSpeed = NormalActivation;
4378                 }
4379 
4380                 mDNS_RegisterInterface(m, n, activationSpeed);
4381 
4382                 if (!mDNSAddressIsLinkLocal(&n->ip)) count++;
4383                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
4384                         "SetupActiveInterfaces: Registered " PUB_S " (%u) BSSID " PRI_MAC_ADDR " Struct addr %p, primary %p,"
4385                         " " PRI_IP_ADDR "/%d" PUB_S PUB_S PUB_S,
4386                         i->ifinfo.ifname, i->scope_id, &i->BSSID, i, primary, &n->ip, CountMaskBits(&n->mask),
4387                         i->Flashing        ? " (Flashing)"  : "",
4388                         i->Occulting       ? " (Occulting)" : "",
4389                         n->InterfaceActive ? " (Primary)"   : "");
4390 
4391                 if (!n->McastTxRx)
4392                 {
4393                     debugf("SetupActiveInterfaces:   No Tx/Rx on   %5s(%lu) %.6a InterfaceID %p %#a", i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, &n->ip);
4394 #if TARGET_OS_IPHONE
4395                     // We join the Bonjour multicast group on Apple embedded platforms ONLY when a client request is active,
4396                     // so we leave the multicast group here to clear any residual group membership.
4397                     if ((i->sa_family == AF_INET) || (i->sa_family == AF_INET6))
4398                     {
4399                         const int sock = (i->sa_family == AF_INET) ? m->p->permanentsockets.sktv4 : m->p->permanentsockets.sktv6;
4400                         if (SearchForInterfaceByName(i->ifinfo.ifname, i->sa_family) == i)
4401                         {
4402                             mDNSGroupLeave(sock, i);
4403                         }
4404                     }
4405 #endif
4406                 }
4407                 else
4408                 {
4409                     if ((i->sa_family == AF_INET) || (i->sa_family == AF_INET6))
4410                     {
4411                         // If this is our *first* address family instance for this interface name, we need to do a leave first,
4412                         // before trying to join the group, to clear out stale kernel state which may be lingering.
4413                         // In particular, this happens with removable network interfaces like USB Ethernet adapters -- the kernel has stale state
4414                         // from the last time the USB Ethernet adapter was connected, and part of the kernel thinks we've already joined the group
4415                         // on that interface (so we get EADDRINUSE when we try to join again) but a different part of the kernel thinks we haven't
4416                         // joined the group (so we receive no multicasts). Doing a leave before joining seems to flush the stale state.
4417                         // Also, trying to make the code leave the group when the adapter is removed doesn't work either,
4418                         // because by the time we get the configuration change notification, the interface is already gone,
4419                         // so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address").
4420                         // <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
4421                         const int sock = (i->sa_family == AF_INET) ? m->p->permanentsockets.sktv4 : m->p->permanentsockets.sktv6;
4422                         if (SearchForInterfaceByName(i->ifinfo.ifname, i->sa_family) == i)
4423                         {
4424                             mDNSGroupLeave(sock, i);
4425                         }
4426                         mDNSGroupJoin(sock, i);
4427                     }
4428                 }
4429             }
4430         }
4431 
4432     return count;
4433 }
4434 
MarkAllInterfacesInactive(mDNSs32 utc)4435 mDNSlocal void MarkAllInterfacesInactive(mDNSs32 utc)
4436 {
4437     NetworkInterfaceInfoOSX *i;
4438     for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
4439     {
4440         if (i->Exists) i->LastSeen = utc;
4441         i->Exists = mDNSfalse;
4442     }
4443 }
4444 
4445 // Returns count of non-link local V4 addresses deregistered (why? -- SC)
ClearInactiveInterfaces(mDNSs32 utc)4446 mDNSlocal int ClearInactiveInterfaces(mDNSs32 utc)
4447 {
4448     mDNS *const m = &mDNSStorage;
4449     // First pass:
4450     // If an interface is going away, then deregister this from the mDNSCore.
4451     // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
4452     // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
4453     // it refers to has gone away we'll crash.
4454     NetworkInterfaceInfoOSX *i;
4455     int count = 0;
4456     for (i = m->p->InterfaceList; i; i = i->next)
4457     {
4458         // If this interface is no longer active, or its InterfaceID is changing, deregister it
4459         NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(i->ifinfo.ifname, AF_UNSPEC);
4460         if (i->Registered)
4461         {
4462             if (i->Exists == 0 || i->Exists == MulticastStateChanged || i->Registered != primary)
4463             {
4464                 InterfaceActivationSpeed activationSpeed;
4465 
4466                 i->Flashing = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->AppearanceTime < 60);
4467                 LogInfo("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
4468                         i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i, primary,
4469                         &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask),
4470                         i->Flashing               ? " (Flashing)"  : "",
4471                         i->Occulting              ? " (Occulting)" : "",
4472                         i->ifinfo.InterfaceActive ? " (Primary)"   : "");
4473 
4474                 // "p2p*" interfaces used for legacy AirDrop reuse the scope-id, MAC address and the IP address
4475                 // every time it creates a new interface. We think it is a duplicate and hence consider it
4476                 // as flashing and occulting. The "core" does not flush the cache for this case. This leads to
4477                 // stale data returned to the application even after the interface is removed. The application
4478                 // then starts to send data but the new interface is not yet created.
4479                 // The same logic applies when the IFEF_DIRECTLINK flag is set on the interface.
4480                 if ((strncmp(i->ifinfo.ifname, "p2p", 3) == 0) || i->ifinfo.DirectLink)
4481                 {
4482                     activationSpeed = FastActivation;
4483                     LogInfo("ClearInactiveInterfaces: %s DirectLink interface deregistering", i->ifinfo.ifname);
4484                 }
4485 #if MDNSRESPONDER_SUPPORTS(APPLE, SLOW_ACTIVATION)
4486                 else if (i->Flashing && i->Occulting)
4487                 {
4488                     activationSpeed = SlowActivation;
4489                 }
4490 #endif
4491                 else
4492                 {
4493                     activationSpeed = NormalActivation;
4494                 }
4495                 mDNS_DeregisterInterface(m, &i->ifinfo, activationSpeed);
4496 
4497                 if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++;
4498                 i->Registered = mDNSNULL;
4499                 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
4500                 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
4501                 // If i->Registered is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
4502 
4503                 // Caution: If we ever decide to add code here to leave the multicast group, we need to make sure that this
4504                 // is the LAST representative of this physical interface, or we'll unsubscribe from the group prematurely.
4505             }
4506         }
4507     }
4508 
4509     // Second pass:
4510     // Now that everything that's going to deregister has done so, we can clean up and free the memory
4511     NetworkInterfaceInfoOSX **p = &m->p->InterfaceList;
4512     while (*p)
4513     {
4514         i = *p;
4515         // If no longer active, delete interface from list and free memory
4516         if (!i->Exists)
4517         {
4518             if (i->LastSeen == utc) i->LastSeen = utc - 1;
4519             const mDNSBool delete = ((utc - i->LastSeen) >= 60) ? mDNStrue : mDNSfalse;
4520             LogInfo("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p(%p) %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
4521                     i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i,
4522                     &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), utc - i->LastSeen,
4523                     i->ifinfo.InterfaceActive ? " (Primary)" : "");
4524 #if APPLE_OSX_mDNSResponder
4525             if (i->BPF_fd >= 0) CloseBPF(i);
4526 #endif // APPLE_OSX_mDNSResponder
4527             if (delete)
4528             {
4529                 *p = i->next;
4530                 freeL("NetworkInterfaceInfoOSX", i);
4531                 continue;   // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
4532             }
4533         }
4534         p = &i->next;
4535     }
4536     return count;
4537 }
4538 
AppendDNameListElem(DNameListElem *** List,mDNSu32 uid,domainname * name)4539 mDNSlocal void AppendDNameListElem(DNameListElem ***List, mDNSu32 uid, domainname *name)
4540 {
4541     DNameListElem *dnle = (DNameListElem*) callocL("DNameListElem/AppendDNameListElem", sizeof(*dnle));
4542     if (!dnle) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
4543     else
4544     {
4545         dnle->next = mDNSNULL;
4546         dnle->uid  = uid;
4547         AssignDomainName(&dnle->name, name);
4548         **List = dnle;
4549         *List = &dnle->next;
4550     }
4551 }
4552 
compare_dns_configs(const void * aa,const void * bb)4553 mDNSlocal int compare_dns_configs(const void *aa, const void *bb)
4554 {
4555     dns_resolver_t *a = *(dns_resolver_t**)aa;
4556     dns_resolver_t *b = *(dns_resolver_t**)bb;
4557 
4558     return (a->search_order < b->search_order) ? -1 : (a->search_order == b->search_order) ? 0 : 1;
4559 }
4560 
UpdateSearchDomainHash(MD5_CTX * sdc,char * domain,mDNSInterfaceID InterfaceID)4561 mDNSlocal void UpdateSearchDomainHash(MD5_CTX *sdc, char *domain, mDNSInterfaceID InterfaceID)
4562 {
4563     mDNS *const m = &mDNSStorage;
4564     char *buf = ".";
4565     mDNSu32 scopeid = 0;
4566     char ifid_buf[16];
4567 
4568     if (domain)
4569         buf = domain;
4570     //
4571     // Hash the search domain name followed by the InterfaceID.
4572     // As we have scoped search domains, we also included InterfaceID. If either of them change,
4573     // we will detect it. Even if the order of them change, we will detect it.
4574     //
4575     // Note: We have to handle a few of these tricky cases.
4576     //
4577     // 1) Current: com, apple.com Changing to: comapple.com
4578     // 2) Current: a.com,b.com Changing to a.comb.com
4579     // 3) Current: a.com,b.com (ifid 8), Changing to a.com8b.com (ifid 8)
4580     // 4) Current: a.com (ifid 12), Changing to a.com1 (ifid: 2)
4581     //
4582     // There are more variants of the above. The key thing is if we include the null in each case
4583     // at the end of name and the InterfaceID, it will prevent a new name (which can't include
4584     // NULL as part of the name) to be mistakenly thought of as a old name.
4585 
4586     scopeid = mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID, mDNStrue);
4587     // mDNS_snprintf always null terminates
4588     if (mDNS_snprintf(ifid_buf, sizeof(ifid_buf), "%u", scopeid) >= sizeof(ifid_buf))
4589         LogMsg("UpdateSearchDomainHash: mDNS_snprintf failed for scopeid %u", scopeid);
4590 
4591     LogInfo("UpdateSearchDomainHash: buf %s, ifid_buf %s", buf, ifid_buf);
4592     MD5_Update(sdc, buf, strlen(buf) + 1);
4593     MD5_Update(sdc, ifid_buf, strlen(ifid_buf) + 1);
4594 }
4595 
FinalizeSearchDomainHash(MD5_CTX * sdc)4596 mDNSlocal void FinalizeSearchDomainHash(MD5_CTX *sdc)
4597 {
4598     mDNS *const m = &mDNSStorage;
4599     mDNSu8 md5_hash[MD5_LEN];
4600 
4601     MD5_Final(md5_hash, sdc);
4602 
4603     if (memcmp(md5_hash, m->SearchDomainsHash, MD5_LEN))
4604     {
4605         // If the hash is different, either the search domains have changed or
4606         // the ordering between them has changed. Restart the questions that
4607         // would be affected by this.
4608         LogInfo("FinalizeSearchDomains: The hash is different");
4609         memcpy(m->SearchDomainsHash, md5_hash, MD5_LEN);
4610         RetrySearchDomainQuestions(m);
4611     }
4612     else { LogInfo("FinalizeSearchDomains: The hash is same"); }
4613 }
4614 
ConfigSearchDomains(dns_resolver_t * resolver,mDNSInterfaceID interfaceId,mDNSu32 scope,MD5_CTX * sdc,uint64_t generation)4615 mDNSlocal void ConfigSearchDomains(dns_resolver_t *resolver, mDNSInterfaceID interfaceId, mDNSu32 scope,  MD5_CTX *sdc, uint64_t generation)
4616 {
4617     const char *scopeString = DNSScopeToString(scope);
4618     int j;
4619     domainname d;
4620 
4621     if (scope == kScopeNone)
4622         interfaceId = mDNSInterface_Any;
4623 
4624     if (scope == kScopeNone || scope == kScopeInterfaceID)
4625     {
4626         for (j = 0; j < resolver->n_search; j++)
4627         {
4628             if (MakeDomainNameFromDNSNameString(&d, resolver->search[j]) != NULL)
4629             {
4630                 char interface_buf[32];
4631                 mDNS_snprintf(interface_buf, sizeof(interface_buf), "for interface %s", InterfaceNameForID(&mDNSStorage,  interfaceId));
4632                 LogInfo("ConfigSearchDomains: (%s) configuring search domain %s %s (generation= %llu)", scopeString,
4633                         resolver->search[j], (interfaceId == mDNSInterface_Any) ? "" : interface_buf, generation);
4634                 UpdateSearchDomainHash(sdc, resolver->search[j], interfaceId);
4635                 mDNS_AddSearchDomain_CString(resolver->search[j], interfaceId);
4636             }
4637             else
4638             {
4639                 LogInfo("ConfigSearchDomains: An invalid search domain was detected for %s domain %s n_nameserver %d, (generation= %llu)",
4640                         DNSScopeToString(scope), resolver->domain, resolver->n_nameserver, generation);
4641             }
4642         }
4643     }
4644     else
4645     {
4646         LogInfo("ConfigSearchDomains: (%s) Ignoring search domain for interface %s", scopeString, InterfaceNameForID(&mDNSStorage, interfaceId));
4647     }
4648 }
4649 
ConfigParseInterfaceID(mDNSu32 ifindex)4650 mDNSlocal mDNSInterfaceID ConfigParseInterfaceID(mDNSu32 ifindex)
4651 {
4652     NetworkInterfaceInfoOSX *ni;
4653     mDNSInterfaceID interface;
4654 
4655     for (ni = mDNSStorage.p->InterfaceList; ni; ni = ni->next)
4656     {
4657         if (ni->ifinfo.InterfaceID && ni->scope_id == ifindex)
4658             break;
4659     }
4660     if (ni != NULL)
4661     {
4662         interface = ni->ifinfo.InterfaceID;
4663     }
4664     else
4665     {
4666         // In rare circumstances, we could potentially hit this case where we cannot parse the InterfaceID
4667         // (see <rdar://problem/13214785>). At this point, we still accept the DNS Config from configd
4668         // Note: We currently ack the whole dns configuration and not individual resolvers or DNS servers.
4669         // As the caller is going to ack the configuration always, we have to add all the DNS servers
4670         // in the configuration. Otherwise, we won't have any DNS servers up until the network change.
4671 
4672         LogMsg("ConfigParseInterfaceID: interface specific index %d not found (interface may not be UP)",ifindex);
4673 
4674         // Set the correct interface from configd before passing this to mDNS_AddDNSServer() below
4675         interface = (mDNSInterfaceID)(unsigned long)ifindex;
4676     }
4677     return interface;
4678 }
4679 
ConfigNonUnicastResolver(dns_resolver_t * r)4680 mDNSlocal void ConfigNonUnicastResolver(dns_resolver_t *r)
4681 {
4682     char *opt = r->options;
4683     domainname d;
4684 
4685     if (opt && !strncmp(opt, "mdns", strlen(opt)))
4686     {
4687         if (!MakeDomainNameFromDNSNameString(&d, r->domain))
4688         {
4689             LogMsg("ConfigNonUnicastResolver: config->resolver bad domain %s", r->domain);
4690             return;
4691         }
4692         mDNS_AddMcastResolver(&mDNSStorage, &d, mDNSInterface_Any, r->timeout);
4693     }
4694 }
4695 
4696 #if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
ConfigDNSServers(dns_resolver_t * r,mDNSInterfaceID interfaceID,mDNSu32 scope,mDNSu32 resGroupID)4697 mDNSlocal void ConfigDNSServers(dns_resolver_t *r, mDNSInterfaceID interfaceID, mDNSu32 scope, mDNSu32 resGroupID)
4698 {
4699     domainname domain;
4700     if (!r->domain || (*r->domain == '\0'))
4701     {
4702         domain.c[0] = 0;
4703     }
4704     else if (!MakeDomainNameFromDNSNameString(&domain, r->domain))
4705     {
4706         LogMsg("ConfigDNSServers: bad domain %s", r->domain);
4707         return;
4708     }
4709     // Parse the resolver specific attributes that affects all the DNS servers.
4710     const int32_t serviceID = (scope == kScopeServiceID) ? r->service_identifier : 0;
4711 
4712     const mdns_interface_monitor_t monitor = GetInterfaceMonitorForIndex((uint32_t)((uintptr_t)interfaceID));
4713     const mDNSBool isExpensive   = (monitor && mdns_interface_monitor_is_expensive(monitor))   ? mDNStrue : mDNSfalse;
4714     const mDNSBool isConstrained = (monitor && mdns_interface_monitor_is_constrained(monitor)) ? mDNStrue : mDNSfalse;
4715     const mDNSBool isCLAT46      = (monitor && mdns_interface_monitor_is_clat46(monitor))      ? mDNStrue : mDNSfalse;
4716     const mDNSBool usableA       = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS)           ? mDNStrue : mDNSfalse;
4717     const mDNSBool usableAAAA    = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS)        ? mDNStrue : mDNSfalse;
4718 #if TARGET_OS_IPHONE
4719     const mDNSBool isCell        = (r->reach_flags & kSCNetworkReachabilityFlagsIsWWAN)        ? mDNStrue : mDNSfalse;
4720 #else
4721     const mDNSBool isCell        = mDNSfalse;
4722 #endif
4723 
4724     const mDNSIPPort port = (r->port != 0) ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort;
4725     for (int32_t i = 0; i < r->n_nameserver; i++)
4726     {
4727         const int family = r->nameserver[i]->sa_family;
4728         if ((family != AF_INET) && (family != AF_INET6)) continue;
4729 
4730         mDNSAddr saddr;
4731         if (SetupAddr(&saddr, r->nameserver[i]))
4732         {
4733             LogMsg("ConfigDNSServers: Bad address");
4734             continue;
4735         }
4736 
4737         // The timeout value is for all the DNS servers in a given resolver, hence we pass
4738         // the timeout value only for the first DNSServer. If we don't have a value in the
4739         // resolver, then use the core's default value
4740         //
4741         // Note: this assumes that when the core picks a list of DNSServers for a question,
4742         // it takes the sum of all the timeout values for all DNS servers. By doing this, it
4743         // tries all the DNS servers in a specified timeout
4744         DNSServer *s = mDNS_AddDNSServer(&mDNSStorage, &domain, interfaceID, serviceID, &saddr, port, scope,
4745             (i == 0) ? (r->timeout ? r->timeout : DEFAULT_UDNS_TIMEOUT) : 0, isCell, isExpensive, isConstrained, isCLAT46,
4746             resGroupID, usableA, usableAAAA, mDNStrue);
4747         if (s)
4748         {
4749             LogInfo("ConfigDNSServers(%s): DNS server %#a:%d for domain %##s",
4750                 DNSScopeToString(scope), &s->addr, mDNSVal16(s->port), domain.c);
4751         }
4752     }
4753 }
4754 #endif
4755 
4756 // ConfigResolvers is called for different types of resolvers: Unscoped resolver, Interface scope resolver and
4757 // Service scope resolvers. This is indicated by the scope argument.
4758 //
4759 // "resolver" has entries that should only be used for unscoped questions.
4760 //
4761 // "scoped_resolver" has entries that should only be used for Interface scoped question i.e., questions that specify an
4762 // interface index (q->InterfaceID)
4763 //
4764 // "service_specific_resolver" has entries that should be used for Service scoped question i.e., questions that specify
4765 // a service identifier (q->ServiceID)
4766 //
ConfigResolvers(dns_config_t * config,mDNSu32 scope,mDNSBool setsearch,mDNSBool setservers,MD5_CTX * sdc)4767 mDNSlocal void ConfigResolvers(dns_config_t *config, mDNSu32 scope, mDNSBool setsearch, mDNSBool setservers, MD5_CTX *sdc)
4768 {
4769     int i;
4770     dns_resolver_t **resolver;
4771     int nresolvers;
4772     const char *scopeString = DNSScopeToString(scope);
4773     mDNSInterfaceID interface;
4774 
4775     switch (scope)
4776     {
4777         case kScopeNone:
4778             resolver = config->resolver;
4779             nresolvers = config->n_resolver;
4780             break;
4781         case kScopeInterfaceID:
4782             resolver = config->scoped_resolver;
4783             nresolvers = config->n_scoped_resolver;
4784             break;
4785         case kScopeServiceID:
4786             resolver = config->service_specific_resolver;
4787             nresolvers = config->n_service_specific_resolver;
4788             break;
4789         default:
4790             return;
4791     }
4792     qsort(resolver, nresolvers, sizeof(dns_resolver_t*), compare_dns_configs);
4793 
4794     for (i = 0; i < nresolvers; i++)
4795     {
4796         dns_resolver_t *r = resolver[i];
4797 
4798         LogInfo("ConfigResolvers: %s resolver[%d] domain %s n_nameserver %d", scopeString, i, r->domain, r->n_nameserver);
4799 
4800         interface = mDNSInterface_Any;
4801 
4802         // Parse the interface index
4803         if (r->if_index != 0)
4804         {
4805             interface = ConfigParseInterfaceID(r->if_index);
4806         }
4807 
4808         if (setsearch)
4809         {
4810             ConfigSearchDomains(resolver[i], interface, scope, sdc, config->generation);
4811 
4812             // Parse other scoped resolvers for search lists
4813             if (!setservers)
4814                 continue;
4815         }
4816 
4817         if (r->port == 5353 || r->n_nameserver == 0)
4818         {
4819             ConfigNonUnicastResolver(r);
4820         }
4821 #if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
4822         else
4823         {
4824             ConfigDNSServers(r, interface, scope, mDNS_GetNextResolverGroupID());
4825         }
4826 #endif
4827     }
4828 }
4829 
4830 #if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
QuestionValidForDNSTrigger(const DNSQuestion * q)4831 mDNSlocal mDNSBool QuestionValidForDNSTrigger(const DNSQuestion *q)
4832 {
4833     if (q->Suppressed)
4834     {
4835         debugf("QuestionValidForDNSTrigger: Suppressed: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4836         return mDNSfalse;
4837     }
4838     if (mDNSOpaque16IsZero(q->TargetQID))
4839     {
4840         debugf("QuestionValidForDNSTrigger: Multicast: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4841         return mDNSfalse;
4842     }
4843     // If we answered using LocalOnly records e.g., /etc/hosts, don't consider that a valid response
4844     // for trigger.
4845     if (q->LOAddressAnswers)
4846     {
4847         debugf("QuestionValidForDNSTrigger: LocalOnly answers: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4848         return mDNSfalse;
4849     }
4850     return mDNStrue;
4851 }
4852 
4853 // This function is called if we are not delivering unicast answers to "A" or "AAAA" questions.
4854 // We set our state appropriately so that if we start receiving answers, trigger the
4855 // upper layer to retry DNS questions.
mDNSPlatformUpdateDNSStatus(const DNSQuestion * q)4856 mDNSexport void mDNSPlatformUpdateDNSStatus(const DNSQuestion *q)
4857 {
4858     mDNS *const m = &mDNSStorage;
4859     if (!QuestionValidForDNSTrigger(q))
4860         return;
4861 
4862 #if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
4863     // Ignore applications that start and stop queries for no reason before we ever talk
4864     // to any DNS server.
4865     if (!q->triedAllServersOnce)
4866     {
4867         LogInfo("QuestionValidForDNSTrigger: question %##s (%s) stopped too soon", q->qname.c, DNSTypeName(q->qtype));
4868         return;
4869     }
4870 #endif
4871     if (q->qtype == kDNSType_A)
4872         m->p->v4answers = 0;
4873     if (q->qtype == kDNSType_AAAA)
4874         m->p->v6answers = 0;
4875     if (!m->p->v4answers || !m->p->v6answers)
4876     {
4877         LogInfo("mDNSPlatformUpdateDNSStatus: Trigger needed v4 %d, v6 %d, question %##s (%s)", m->p->v4answers, m->p->v6answers, q->qname.c,
4878             DNSTypeName(q->qtype));
4879     }
4880 }
4881 #endif  // MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
4882 
AckConfigd(dns_config_t * config)4883 mDNSlocal void AckConfigd(dns_config_t *config)
4884 {
4885     mDNS_CheckLock(&mDNSStorage);
4886 
4887     // Acking the configuration triggers configd to reissue the reachability queries
4888     mDNSStorage.p->DNSTrigger = NonZeroTime(mDNSStorage.timenow);
4889     _dns_configuration_ack(config, "com.apple.mDNSResponder");
4890 }
4891 
4892 #if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
4893 // If v4q is non-NULL, it means we have received some answers for "A" type questions
4894 // If v6q is non-NULL, it means we have received some answers for "AAAA" type questions
mDNSPlatformTriggerDNSRetry(const DNSQuestion * v4q,const DNSQuestion * v6q)4895 mDNSexport void mDNSPlatformTriggerDNSRetry(const DNSQuestion *v4q, const DNSQuestion *v6q)
4896 {
4897     mDNS *const m = &mDNSStorage;
4898     mDNSBool trigger = mDNSfalse;
4899     mDNSs32 timenow;
4900 
4901     // Don't send triggers too often.
4902     // If we have started delivering answers to questions, we should send a trigger
4903     // if the time permits. If we are delivering answers, we should set the state
4904     // of v4answers/v6answers to 1 and avoid sending a trigger.  But, we don't know
4905     // whether the answers that are being delivered currently is for configd or some
4906     // other application. If we set the v4answers/v6answers to 1 and not deliver a trigger,
4907     // then we won't deliver the trigger later when it is okay to send one as the
4908     // "answers" are already set to 1. Hence, don't affect the state of v4answers and
4909     // v6answers if we are not delivering triggers.
4910     mDNS_Lock(m);
4911     timenow = m->timenow;
4912     if (m->p->DNSTrigger && (timenow - m->p->DNSTrigger) < DNS_TRIGGER_INTERVAL)
4913     {
4914         if (!m->p->v4answers || !m->p->v6answers)
4915         {
4916             debugf("mDNSPlatformTriggerDNSRetry: not triggering, time since last trigger %d ms, v4ans %d, v6ans %d",
4917                 (timenow - m->p->DNSTrigger), m->p->v4answers, m->p->v6answers);
4918         }
4919         mDNS_Unlock(m);
4920         return;
4921     }
4922     mDNS_Unlock(m);
4923     if (v4q != NULL && QuestionValidForDNSTrigger(v4q))
4924     {
4925         int old = m->p->v4answers;
4926 
4927         m->p->v4answers = 1;
4928 
4929         // If there are IPv4 answers now and previously we did not have
4930         // any answers, trigger a DNS change so that reachability
4931         // can retry the queries again.
4932         if (!old)
4933         {
4934             LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv4, last trigger %d ms, %##s (%s)", (timenow - m->p->DNSTrigger),
4935                 v4q->qname.c, DNSTypeName(v4q->qtype));
4936             trigger = mDNStrue;
4937         }
4938     }
4939     if (v6q != NULL && QuestionValidForDNSTrigger(v6q))
4940     {
4941         int old = m->p->v6answers;
4942 
4943         m->p->v6answers = 1;
4944         // If there are IPv6 answers now and previously we did not have
4945         // any answers, trigger a DNS change so that reachability
4946         // can retry the queries again.
4947         if (!old)
4948         {
4949             LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv6, last trigger %d ms, %##s (%s)", (timenow - m->p->DNSTrigger),
4950                 v6q->qname.c, DNSTypeName(v6q->qtype));
4951             trigger = mDNStrue;
4952         }
4953     }
4954     if (trigger)
4955     {
4956         dns_config_t *config = dns_configuration_copy();
4957         if (config)
4958         {
4959             mDNS_Lock(m);
4960             AckConfigd(config);
4961             mDNS_Unlock(m);
4962             dns_configuration_free(config);
4963         }
4964         else
4965         {
4966             LogMsg("mDNSPlatformTriggerDNSRetry: ERROR!! configd did not return config");
4967         }
4968     }
4969 }
4970 #endif  // MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
4971 
4972 #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
SetupActiveDirectoryDomain(dns_config_t * config)4973 mDNSlocal void SetupActiveDirectoryDomain(dns_config_t *config)
4974 {
4975     // Record the so-called "primary" domain, which we use as a hint to tell if the user is on a network set up
4976     // by someone using Microsoft Active Directory using "local" as a private internal top-level domain
4977     if (config->n_resolver && config->resolver[0]->domain && config->resolver[0]->n_nameserver &&
4978         config->resolver[0]->nameserver[0])
4979     {
4980         MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, config->resolver[0]->domain);
4981     }
4982     else
4983     {
4984          ActiveDirectoryPrimaryDomain.c[0] = 0;
4985     }
4986 
4987     //MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, "test.local");
4988     ActiveDirectoryPrimaryDomainLabelCount = CountLabels(&ActiveDirectoryPrimaryDomain);
4989     if (config->n_resolver && config->resolver[0]->n_nameserver &&
4990         SameDomainName(SkipLeadingLabels(&ActiveDirectoryPrimaryDomain, ActiveDirectoryPrimaryDomainLabelCount - 1), &localdomain))
4991     {
4992         SetupAddr(&ActiveDirectoryPrimaryDomainServer, config->resolver[0]->nameserver[0]);
4993     }
4994     else
4995     {
4996         AssignConstStringDomainName(&ActiveDirectoryPrimaryDomain, "");
4997         ActiveDirectoryPrimaryDomainLabelCount = 0;
4998         ActiveDirectoryPrimaryDomainServer = zeroAddr;
4999     }
5000 }
5001 #endif
5002 
SetupDDNSDomains(domainname * const fqdn,DNameListElem ** RegDomains,DNameListElem ** BrowseDomains)5003 mDNSlocal void SetupDDNSDomains(domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains)
5004 {
5005     int i;
5006     char buf[MAX_ESCAPED_DOMAIN_NAME];  // Max legal C-string name, including terminating NULL
5007     domainname d;
5008 
5009     CFDictionaryRef ddnsdict = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_DynamicDNS);
5010     if (ddnsdict)
5011     {
5012         if (fqdn)
5013         {
5014             CFArrayRef fqdnArray = CFDictionaryGetValue(ddnsdict, CFSTR("HostNames"));
5015             if (fqdnArray && CFArrayGetCount(fqdnArray) > 0)
5016             {
5017                 // for now, we only look at the first array element.  if we ever support multiple configurations, we will walk the list
5018                 CFDictionaryRef fqdnDict = CFArrayGetValueAtIndex(fqdnArray, 0);
5019                 if (fqdnDict && DictionaryIsEnabled(fqdnDict))
5020                 {
5021                     CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain"));
5022                     if (name)
5023                     {
5024                         if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
5025                             !MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0])
5026                             LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)");
5027                         else
5028                             debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf);
5029                     }
5030                 }
5031             }
5032         }
5033         if (RegDomains)
5034         {
5035             CFArrayRef regArray = CFDictionaryGetValue(ddnsdict, CFSTR("RegistrationDomains"));
5036             if (regArray && CFArrayGetCount(regArray) > 0)
5037             {
5038                 CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0);
5039                 if (regDict && DictionaryIsEnabled(regDict))
5040                 {
5041                     CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain"));
5042                     if (name)
5043                     {
5044                         if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
5045                             !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
5046                             LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)");
5047                         else
5048                         {
5049                             debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf);
5050                             AppendDNameListElem(&RegDomains, 0, &d);
5051                         }
5052                     }
5053                 }
5054             }
5055         }
5056         if (BrowseDomains)
5057         {
5058             CFArrayRef browseArray = CFDictionaryGetValue(ddnsdict, CFSTR("BrowseDomains"));
5059             if (browseArray)
5060             {
5061                 for (i = 0; i < CFArrayGetCount(browseArray); i++)
5062                 {
5063                     CFDictionaryRef browseDict = CFArrayGetValueAtIndex(browseArray, i);
5064                     if (browseDict && DictionaryIsEnabled(browseDict))
5065                     {
5066                         CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain"));
5067                         if (name)
5068                         {
5069                             if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
5070                                 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
5071                                 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf[0] ? buf : "(unknown)");
5072                             else
5073                             {
5074                                 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf);
5075                                 AppendDNameListElem(&BrowseDomains, 0, &d);
5076                             }
5077                         }
5078                     }
5079                 }
5080             }
5081         }
5082         CFRelease(ddnsdict);
5083     }
5084 }
5085 
5086 // Returns mDNSfalse, if it does not set the configuration i.e., if the DNS configuration did not change
mDNSPlatformSetDNSConfig(mDNSBool setservers,mDNSBool setsearch,domainname * const fqdn,DNameListElem ** RegDomains,DNameListElem ** BrowseDomains,mDNSBool ackConfig)5087 mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn,
5088                                              DNameListElem **RegDomains, DNameListElem **BrowseDomains, mDNSBool ackConfig)
5089 {
5090     mDNS *const m = &mDNSStorage;
5091     MD5_CTX sdc;    // search domain context
5092 
5093     // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
5094     if (fqdn         ) fqdn->c[0]      = 0;
5095     if (RegDomains   ) *RegDomains     = NULL;
5096     if (BrowseDomains) *BrowseDomains  = NULL;
5097 
5098     LogInfo("mDNSPlatformSetDNSConfig:%s%s%s%s%s",
5099             setservers    ? " setservers"    : "",
5100             setsearch     ? " setsearch"     : "",
5101             fqdn          ? " fqdn"          : "",
5102             RegDomains    ? " RegDomains"    : "",
5103             BrowseDomains ? " BrowseDomains" : "");
5104 
5105     if (setsearch) MD5_Init(&sdc);
5106 
5107     // Add the inferred address-based configuration discovery domains
5108     // (should really be in core code I think, not platform-specific)
5109     if (setsearch)
5110     {
5111         struct ifaddrs *ifa = mDNSNULL;
5112         struct sockaddr_in saddr;
5113         mDNSPlatformMemZero(&saddr, sizeof(saddr));
5114         saddr.sin_len = sizeof(saddr);
5115         saddr.sin_family = AF_INET;
5116         saddr.sin_port = 0;
5117         saddr.sin_addr.s_addr = *(in_addr_t *)&m->Router.ip.v4;
5118 
5119         // Don't add any reverse-IP search domains if doing the WAB bootstrap queries would cause dial-on-demand connection initiation
5120         if (!AddrRequiresPPPConnection((struct sockaddr *)&saddr)) ifa =  myGetIfAddrs(1);
5121 
5122         while (ifa)
5123         {
5124             mDNSAddr a, n;
5125             char buf[64];
5126 
5127             if (ifa->ifa_addr->sa_family == AF_INET &&
5128                 ifa->ifa_netmask                    &&
5129                 !(ifa->ifa_flags & IFF_LOOPBACK)    &&
5130                 !SetupAddr(&a, ifa->ifa_addr)       &&
5131                 !mDNSv4AddressIsLinkLocal(&a.ip.v4)  )
5132             {
5133                 // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be incorrect, so we explicitly fix it here before calling SetupAddr
5134                 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
5135                 ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family;     // Make sure ifa_netmask->sa_family is set correctly
5136                 SetupAddr(&n, ifa->ifa_netmask);
5137                 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
5138                 mDNS_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa.", a.ip.v4.b[3] & n.ip.v4.b[3],
5139                               a.ip.v4.b[2] & n.ip.v4.b[2],
5140                               a.ip.v4.b[1] & n.ip.v4.b[1],
5141                               a.ip.v4.b[0] & n.ip.v4.b[0]);
5142                 UpdateSearchDomainHash(&sdc, buf, NULL);
5143                 mDNS_AddSearchDomain_CString(buf, mDNSNULL);
5144             }
5145             ifa = ifa->ifa_next;
5146         }
5147     }
5148 
5149 #ifndef MDNS_NO_DNSINFO
5150     if (setservers || setsearch)
5151     {
5152         dns_config_t *config = dns_configuration_copy();
5153         if (!config)
5154         {
5155             // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
5156             // Apparently this is expected behaviour -- "not a bug".
5157             // Accordingly, we suppress syslog messages for the first three minutes after boot.
5158             // If we are still getting failures after three minutes, then we log them.
5159             if ((mDNSu32)mDNSPlatformRawTime() > (mDNSu32)(mDNSPlatformOneSecond * 180))
5160                 LogMsg("mDNSPlatformSetDNSConfig: Error: dns_configuration_copy returned NULL");
5161         }
5162         else
5163         {
5164             LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d, generation %llu, last %llu", config->n_resolver, config->generation, m->p->LastConfigGeneration);
5165 
5166             // For every network change, mDNSPlatformSetDNSConfig is called twice. First,
5167             // to update the search domain list (in which case, the setsearch bool is set);
5168             // and second, to update the DNS server list (in which case, the setservers bool
5169             // is set). The code assumes only one of these flags, setsearch or setserver,
5170             // will be set when mDNSPlatformSetDNSConfig is called to handle a network change.
5171             // The mDNSPlatformSetDNSConfig function also assumes that ackCfg will be set
5172             // when setservers is set.
5173 
5174             // The search domains update occurs on every network change to avoid sync issues
5175             // that may occur if a network change happens during the processing
5176             // of a network change.  The dns servers update occurs when the DNS config
5177             // changes. The dns servers stay in sync by saving the config's generation number
5178             // on every update; and only updating when the generation number changes.
5179 
5180             // If this is a DNS server update and the configuration hasn't changed, then skip update
5181 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
5182             if (setservers && m->p->LastConfigGeneration == config->generation)
5183 #else
5184             if (setservers && !m->p->if_interface_changed && m->p->LastConfigGeneration == config->generation)
5185 #endif
5186             {
5187                 LogInfo("mDNSPlatformSetDNSConfig(setservers): generation number %llu same, not processing", config->generation);
5188                 dns_configuration_free(config);
5189                 SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
5190                 return mDNSfalse;
5191             }
5192 #if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
5193             if (setservers) {
5194                 // Must check if setservers is true, because mDNSPlatformSetDNSConfig can be called for multiple times
5195                 // with setservers equals to false. If setservers is false, we will end up with clearing if_interface_changed
5196                 // without really updating the server.
5197                 m->p->if_interface_changed = mDNSfalse;
5198             }
5199 #endif
5200 
5201 #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
5202             SetupActiveDirectoryDomain(config);
5203 #endif
5204 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
5205             if (setservers) Querier_ApplyDNSConfig(config);
5206 #endif
5207             ConfigResolvers(config, kScopeNone, setsearch, setservers, &sdc);
5208             ConfigResolvers(config, kScopeInterfaceID, setsearch, setservers, &sdc);
5209             ConfigResolvers(config, kScopeServiceID, setsearch, setservers, &sdc);
5210 
5211 #if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
5212             const CFIndex n = m->p->InterfaceMonitors ? CFArrayGetCount(m->p->InterfaceMonitors) : 0;
5213             for (CFIndex i = n - 1; i >= 0; i--)
5214             {
5215                 mdns_interface_monitor_t monitor;
5216                 monitor = (mdns_interface_monitor_t) CFArrayGetValueAtIndex(m->p->InterfaceMonitors, i);
5217                 const uint32_t ifIndex = mdns_interface_monitor_get_interface_index(monitor);
5218                 DNSServer *server;
5219                 for (server = m->DNSServers; server; server = server->next)
5220                 {
5221                     if ((((uintptr_t)server->interface) == ifIndex) && !(server->flags & DNSServerFlag_Delete))
5222                     {
5223                         break;
5224                     }
5225                 }
5226                 if (!server)
5227                 {
5228                     mdns_retain(monitor);
5229                     CFArrayRemoveValueAtIndex(m->p->InterfaceMonitors, i);
5230                     mdns_interface_monitor_invalidate(monitor);
5231                     mdns_release(monitor);
5232                 }
5233             }
5234 #endif
5235             // Acking provides a hint to other processes that the current DNS configuration has completed
5236             // its update.  When configd receives the ack, it publishes a notification.
5237             // Applications monitoring the notification then know when to re-issue their DNS queries
5238             // after a network change occurs.
5239             if (ackConfig)
5240             {
5241                 // Note: We have to set the generation number here when we are acking.
5242                 // For every DNS configuration change, we do the following:
5243                 //
5244                 // 1) Copy dns configuration, handle search domains change
5245                 // 2) Copy dns configuration, handle dns server change
5246                 //
5247                 // If we update the generation number at step (1), we won't process the
5248                 // DNS servers the second time because generation number would be the same.
5249                 // As we ack only when we process dns servers, we set the generation number
5250                 // during acking.
5251                 m->p->LastConfigGeneration = config->generation;
5252                 LogInfo("mDNSPlatformSetDNSConfig: Acking configuration setservers %d, setsearch %d", setservers, setsearch);
5253                 AckConfigd(config);
5254             }
5255             dns_configuration_free(config);
5256             if (setsearch) FinalizeSearchDomainHash(&sdc);
5257         }
5258     }
5259 #endif // MDNS_NO_DNSINFO
5260     SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
5261     return mDNStrue;
5262 }
5263 
5264 
mDNSPlatformGetPrimaryInterface(mDNSAddr * v4,mDNSAddr * v6,mDNSAddr * r)5265 mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *r)
5266 {
5267     char buf[256];
5268 
5269     CFDictionaryRef dict = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_IPv4);
5270     if (dict)
5271     {
5272         r->type  = mDNSAddrType_IPv4;
5273         r->ip.v4 = zerov4Addr;
5274         CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
5275         if (string)
5276         {
5277             if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8))
5278                 LogMsg("Could not convert router to CString");
5279             else
5280             {
5281                 struct sockaddr_in saddr;
5282                 saddr.sin_len = sizeof(saddr);
5283                 saddr.sin_family = AF_INET;
5284                 saddr.sin_port = 0;
5285                 inet_aton(buf, &saddr.sin_addr);
5286                 *(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr;
5287             }
5288         }
5289         string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
5290         if (string)
5291         {
5292             mDNSBool HavePrimaryGlobalv6 = mDNSfalse;  // does the primary interface have a global v6 address?
5293             struct ifaddrs *ifa = myGetIfAddrs(1);
5294             *v4 = *v6 = zeroAddr;
5295 
5296             if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8))
5297             {
5298                 LogMsg("Could not convert router to CString");
5299                 goto exit;
5300             }
5301             // find primary interface in list
5302             while (ifa && (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4) || !HavePrimaryGlobalv6))
5303             {
5304                 if (!ifa->ifa_addr)
5305                 {
5306                     LogMsg("Skip interface, %s, since ifa_addr is not set.", (ifa->ifa_name) ? ifa->ifa_name: "name not found");
5307                     ifa = ifa->ifa_next;
5308                     continue;
5309                 }
5310                 mDNSAddr tmp6 = zeroAddr;
5311                 if (!strcmp(buf, ifa->ifa_name))
5312                 {
5313                     if (ifa->ifa_addr->sa_family == AF_INET)
5314                     {
5315                         if (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4))
5316                             SetupAddr(v4, ifa->ifa_addr);
5317                     }
5318                     else if (ifa->ifa_addr->sa_family == AF_INET6)
5319                     {
5320                         SetupAddr(&tmp6, ifa->ifa_addr);
5321                         if (tmp6.ip.v6.b[0] >> 5 == 1)   // global prefix: 001
5322                         {
5323                             HavePrimaryGlobalv6 = mDNStrue;
5324                             *v6 = tmp6;
5325                         }
5326                     }
5327                 }
5328                 else
5329                 {
5330                     // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
5331                     if (!HavePrimaryGlobalv6 && ifa->ifa_addr->sa_family == AF_INET6 && !v6->ip.v6.b[0])
5332                     {
5333                         SetupAddr(&tmp6, ifa->ifa_addr);
5334                         if (tmp6.ip.v6.b[0] >> 5 == 1)
5335                             *v6 = tmp6;
5336                     }
5337                 }
5338                 ifa = ifa->ifa_next;
5339             }
5340             // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
5341             // V4 to communicate w/ our DNS server
5342         }
5343 
5344 exit:
5345         CFRelease(dict);
5346     }
5347     return mStatus_NoError;
5348 }
5349 
mDNSPlatformDynDNSHostNameStatusChanged(const domainname * const dname,const mStatus status)5350 mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
5351 {
5352     LogInfo("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status, dname->c);
5353     char uname[MAX_ESCAPED_DOMAIN_NAME];    // Max legal C-string name, including terminating NUL
5354     ConvertDomainNameToCString(dname, uname);
5355 
5356     char *p = uname;
5357     while (*p)
5358     {
5359         *p = tolower(*p);
5360         if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
5361         p++;
5362     }
5363 
5364     // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
5365     // That single entity is a CFDictionary with name "HostNames".
5366     // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
5367     // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
5368     // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
5369     // The CFDictionary for each FQDN holds (at present) a single name/value pair,
5370     // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
5371 
5372     const CFStringRef StateKeys [1] = { CFSTR("HostNames") };
5373     const CFStringRef HostKeys  [1] = { CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8) };
5374     const CFStringRef StatusKeys[1] = { CFSTR("Status") };
5375     if (!HostKeys[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname);
5376     else
5377     {
5378         const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) };
5379         if (StatusVals[0] == NULL) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status);
5380         else
5381         {
5382             const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
5383             if (HostVals[0])
5384             {
5385                 const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
5386                 if (StateVals[0])
5387                 {
5388                     CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
5389                     if (StateDict)
5390                     {
5391                         mDNSDynamicStoreSetConfig(kmDNSDynamicConfig, mDNSNULL, StateDict);
5392                         CFRelease(StateDict);
5393                     }
5394                     CFRelease(StateVals[0]);
5395                 }
5396                 CFRelease(HostVals[0]);
5397             }
5398             CFRelease(StatusVals[0]);
5399         }
5400         CFRelease(HostKeys[0]);
5401     }
5402 }
5403 
5404 // MUST be called holding the lock
SetDomainSecrets_internal(mDNS * m)5405 mDNSlocal void SetDomainSecrets_internal(mDNS *m)
5406 {
5407 #ifdef NO_SECURITYFRAMEWORK
5408         (void) m;
5409     LogMsg("Note: SetDomainSecrets: no keychain support");
5410 #else
5411 
5412     LogInfo("SetDomainSecrets");
5413 
5414     // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
5415     // In the case where the user simultaneously removes their DDNS host name and the key
5416     // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
5417     // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
5418     // address records behind that we no longer have permission to delete.
5419     DomainAuthInfo *ptr;
5420     for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
5421         ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10);
5422 
5423     // String Array used to write list of private domains to Dynamic Store
5424     CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
5425     if (!sa) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
5426     CFIndex i;
5427     CFDataRef data = NULL;
5428     const int itemsPerEntry = 4; // domain name, key name, key value, Name value
5429     CFArrayRef secrets = NULL;
5430     int err = mDNSKeychainGetSecrets(&secrets);
5431     if (err || !secrets)
5432         LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err, secrets);
5433     else
5434     {
5435         CFIndex ArrayCount = CFArrayGetCount(secrets);
5436         // Iterate through the secrets
5437         for (i = 0; i < ArrayCount; ++i)
5438         {
5439             int j;
5440             size_t offset;
5441             CFArrayRef entry = CFArrayGetValueAtIndex(secrets, i);
5442             if (CFArrayGetTypeID() != CFGetTypeID(entry) || itemsPerEntry != CFArrayGetCount(entry))
5443             { LogMsg("SetDomainSecrets: malformed entry %d, itemsPerEntry %d", i, itemsPerEntry); continue; }
5444             for (j = 0; j < CFArrayGetCount(entry); ++j)
5445                 if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry, j)))
5446                 { LogMsg("SetDomainSecrets: malformed entry item %d", j); continue; }
5447 
5448             // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
5449 
5450             // Max legal domainname as C-string, including space for dnsprefix and terminating NUL
5451             // Get DNS domain this key is for (kmDNSKcWhere)
5452             char stringbuf[MAX_ESCAPED_DOMAIN_NAME + sizeof(dnsprefix)];
5453             data = CFArrayGetValueAtIndex(entry, kmDNSKcWhere);
5454             if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
5455             { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data)); continue; }
5456             CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
5457             stringbuf[CFDataGetLength(data)] = '\0';
5458 
5459             offset = 0;
5460             if (!strncmp(stringbuf, dnsprefix, strlen(dnsprefix)))
5461                 offset = strlen(dnsprefix);
5462 
5463             domainname domain;
5464             if (!MakeDomainNameFromDNSNameString(&domain, stringbuf + offset)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf); continue; }
5465 
5466             // Get key name (kmDNSKcAccount)
5467             data = CFArrayGetValueAtIndex(entry, kmDNSKcAccount);
5468             if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
5469             { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data)); continue; }
5470             CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)stringbuf);
5471             stringbuf[CFDataGetLength(data)] = '\0';
5472 
5473             domainname keyname;
5474             if (!MakeDomainNameFromDNSNameString(&keyname, stringbuf)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf); continue; }
5475 
5476             // Get key data (kmDNSKcKey)
5477             data = CFArrayGetValueAtIndex(entry, kmDNSKcKey);
5478             if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
5479             {
5480                 LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data));
5481                 continue;
5482             }
5483             CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
5484             stringbuf[CFDataGetLength(data)] = '\0';    // mDNS_SetSecretForDomain requires NULL-terminated C string for key
5485 
5486             // Get the Name of the keychain entry (kmDNSKcName) host or host:port
5487             // The hostname also has the port number and ":". It should take a maximum of 6 bytes.
5488             char hostbuf[MAX_ESCAPED_DOMAIN_NAME + 6];  // Max legal domainname as C-string, including terminating NUL
5489             data = CFArrayGetValueAtIndex(entry, kmDNSKcName);
5490             if (CFDataGetLength(data) >= (int)sizeof(hostbuf))
5491             {
5492                 LogMsg("SetDomainSecrets: host:port data too long: %d", CFDataGetLength(data));
5493                 continue;
5494             }
5495             CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)hostbuf);
5496             hostbuf[CFDataGetLength(data)] = '\0';
5497 
5498             domainname hostname;
5499             mDNSIPPort port;
5500             char *hptr;
5501             hptr = strchr(hostbuf, ':');
5502 
5503             port.NotAnInteger = 0;
5504             if (hptr)
5505             {
5506                 mDNSu8 *p;
5507                 mDNSu16 val = 0;
5508 
5509                 *hptr++ = '\0';
5510                 while(hptr && *hptr != 0)
5511                 {
5512                     if (*hptr < '0' || *hptr > '9')
5513                     { LogMsg("SetDomainSecrets: Malformed Port number %d, val %d", *hptr, val); val = 0; break;}
5514                     val = val * 10 + *hptr - '0';
5515                     hptr++;
5516                 }
5517                 if (!val) continue;
5518                 p = (mDNSu8 *)&val;
5519                 port.NotAnInteger = p[0] << 8 | p[1];
5520             }
5521             // The hostbuf is of the format dsid@hostname:port. We don't care about the dsid.
5522             hptr = strchr(hostbuf, '@');
5523             if (hptr)
5524                 hptr++;
5525             else
5526                 hptr = hostbuf;
5527             if (!MakeDomainNameFromDNSNameString(&hostname, hptr)) { LogMsg("SetDomainSecrets: bad host name %s", hptr); continue; }
5528 
5529             DomainAuthInfo *FoundInList;
5530             for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
5531                 if (SameDomainName(&FoundInList->domain, &domain)) break;
5532 
5533             // Uncomment the line below to view the keys as they're read out of the system keychain
5534             // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
5535             //LogInfo("SetDomainSecrets: domain %##s keyname %##s key %s hostname %##s port %d", &domain.c, &keyname.c, stringbuf, hostname.c, (port.b[0] << 8 | port.b[1]));
5536             LogInfo("SetDomainSecrets: domain %##s keyname %##s hostname %##s port %d", &domain.c, &keyname.c, hostname.c, (port.b[0] << 8 | port.b[1]));
5537 
5538             // If didn't find desired domain in the list, make a new entry
5539             ptr = FoundInList;
5540             if (!FoundInList)
5541             {
5542                 ptr = (DomainAuthInfo*) callocL("DomainAuthInfo", sizeof(*ptr));
5543                 if (!ptr) { LogMsg("SetDomainSecrets: No memory"); continue; }
5544             }
5545 
5546             if (mDNS_SetSecretForDomain(m, ptr, &domain, &keyname, stringbuf, &hostname, &port) == mStatus_BadParamErr)
5547             {
5548                 if (!FoundInList) mDNSPlatformMemFree(ptr);     // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
5549                 continue;
5550             }
5551 
5552             ConvertDomainNameToCString(&domain, stringbuf);
5553             CFStringRef cfs = CFStringCreateWithCString(NULL, stringbuf, kCFStringEncodingUTF8);
5554             if (cfs) { CFArrayAppendValue(sa, cfs); CFRelease(cfs); }
5555         }
5556         CFRelease(secrets);
5557     }
5558 
5559     if (!privateDnsArray || !CFEqual(privateDnsArray, sa))
5560     {
5561         if (privateDnsArray)
5562             CFRelease(privateDnsArray);
5563 
5564         privateDnsArray = sa;
5565         CFRetain(privateDnsArray);
5566         mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray);
5567     }
5568     CFRelease(sa);
5569 
5570     CheckSuppressUnusableQuestions(m);
5571 
5572 #endif /* NO_SECURITYFRAMEWORK */
5573 }
5574 
SetDomainSecrets(mDNS * m)5575 mDNSexport void SetDomainSecrets(mDNS *m)
5576 {
5577 #if DEBUG
5578     // Don't get secrets for BTMM if running in debug mode
5579     if (!IsDebugSocketInUse())
5580 #endif
5581     SetDomainSecrets_internal(m);
5582 }
5583 
SetLocalDomains(void)5584 mDNSlocal void SetLocalDomains(void)
5585 {
5586     CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
5587     if (!sa) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
5588 
5589     CFArrayAppendValue(sa, CFSTR("local"));
5590     CFArrayAppendValue(sa, CFSTR("254.169.in-addr.arpa"));
5591     CFArrayAppendValue(sa, CFSTR("8.e.f.ip6.arpa"));
5592     CFArrayAppendValue(sa, CFSTR("9.e.f.ip6.arpa"));
5593     CFArrayAppendValue(sa, CFSTR("a.e.f.ip6.arpa"));
5594     CFArrayAppendValue(sa, CFSTR("b.e.f.ip6.arpa"));
5595 
5596     mDNSDynamicStoreSetConfig(kmDNSMulticastConfig, mDNSNULL, sa);
5597     CFRelease(sa);
5598 }
5599 
5600 #if !MDNSRESPONDER_SUPPORTS(APPLE, NO_WAKE_FOR_NET_ACCESS)
GetCurrentPMSetting(const CFStringRef name,mDNSs32 * val)5601 mDNSlocal void GetCurrentPMSetting(const CFStringRef name, mDNSs32 *val)
5602 {
5603     CFDictionaryRef dict = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_PowerSettings);
5604     if (!dict)
5605     {
5606         LogSPS("GetCurrentPMSetting: Could not get IOPM CurrentSettings dict");
5607     }
5608     else
5609     {
5610         CFNumberRef number = CFDictionaryGetValue(dict, name);
5611         if ((number == NULL) || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
5612             *val = 0;
5613         CFRelease(dict);
5614     }
5615 }
5616 #endif
5617 
5618 #if APPLE_OSX_mDNSResponder
5619 
5620 static CFMutableDictionaryRef spsStatusDict = NULL;
5621 static const CFStringRef kMetricRef = CFSTR("Metric");
5622 
SPSStatusPutNumber(CFMutableDictionaryRef dict,const mDNSu8 * const ptr,CFStringRef key)5623 mDNSlocal void SPSStatusPutNumber(CFMutableDictionaryRef dict, const mDNSu8* const ptr, CFStringRef key)
5624 {
5625     mDNSu8 tmp = (ptr[0] - '0') * 10 + ptr[1] - '0';
5626     CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt8Type, &tmp);
5627     if (num == NULL)
5628         LogMsg("SPSStatusPutNumber: Could not create CFNumber");
5629     else
5630     {
5631         CFDictionarySetValue(dict, key, num);
5632         CFRelease(num);
5633     }
5634 }
5635 
SPSCreateDict(const mDNSu8 * const ptr)5636 mDNSlocal CFMutableDictionaryRef SPSCreateDict(const mDNSu8* const ptr)
5637 {
5638     CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
5639     if (!dict) { LogMsg("SPSCreateDict: Could not create CFDictionary dict"); return dict; }
5640 
5641     char buffer[1024];
5642     buffer[mDNS_snprintf(buffer, sizeof(buffer), "%##s", ptr) - 1] = 0;
5643     CFStringRef spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
5644     if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname full"); CFRelease(dict); return NULL; }
5645     CFDictionarySetValue(dict, CFSTR("FullName"), spsname);
5646     CFRelease(spsname);
5647 
5648     if (ptr[0] >=  2) SPSStatusPutNumber(dict, ptr + 1, CFSTR("Type"));
5649     if (ptr[0] >=  5) SPSStatusPutNumber(dict, ptr + 4, CFSTR("Portability"));
5650     if (ptr[0] >=  8) SPSStatusPutNumber(dict, ptr + 7, CFSTR("MarginalPower"));
5651     if (ptr[0] >= 11) SPSStatusPutNumber(dict, ptr +10, CFSTR("TotalPower"));
5652 
5653     mDNSu32 tmp = SPSMetric(ptr);
5654     CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tmp);
5655     if (num == NULL)
5656         LogMsg("SPSCreateDict: Could not create CFNumber");
5657     else
5658     {
5659         CFDictionarySetValue(dict, kMetricRef, num);
5660         CFRelease(num);
5661     }
5662 
5663     if (ptr[0] >= 12)
5664     {
5665         memcpy(buffer, ptr + 13, ptr[0] - 12);
5666         buffer[ptr[0] - 12] = 0;
5667         spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
5668         if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname"); CFRelease(dict); return NULL; }
5669         else
5670         {
5671             CFDictionarySetValue(dict, CFSTR("PrettyName"), spsname);
5672             CFRelease(spsname);
5673         }
5674     }
5675 
5676     return dict;
5677 }
5678 
CompareSPSEntries(const void * val1,const void * val2,void * context)5679 mDNSlocal CFComparisonResult CompareSPSEntries(const void *val1, const void *val2, void *context)
5680 {
5681     (void)context;
5682     return CFNumberCompare((CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val1, kMetricRef),
5683                            (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val2, kMetricRef),
5684                            NULL);
5685 }
5686 
UpdateSPSStatus(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,QC_result AddRecord)5687 mDNSlocal void UpdateSPSStatus(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
5688 {
5689     NetworkInterfaceInfo* info = (NetworkInterfaceInfo*)question->QuestionContext;
5690     debugf("UpdateSPSStatus: %s %##s %s %s", info->ifname, question->qname.c, AddRecord ? "Add" : "Rmv", answer ? RRDisplayString(m, answer) : "<null>");
5691 
5692     mDNS_Lock(m);
5693     mDNS_UpdateAllowSleep(m);
5694     mDNS_Unlock(m);
5695 
5696     if (answer && SPSMetric(answer->rdata->u.name.c) > 999999) return;  // Ignore instances with invalid names
5697 
5698     if (!spsStatusDict)
5699     {
5700         spsStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
5701         if (!spsStatusDict) { LogMsg("UpdateSPSStatus: Could not create CFDictionary spsStatusDict"); return; }
5702     }
5703 
5704     CFStringRef ifname = CFStringCreateWithCString(NULL, info->ifname, kCFStringEncodingUTF8);
5705     if (!ifname) { LogMsg("UpdateSPSStatus: Could not create CFString ifname"); return; }
5706 
5707     CFMutableArrayRef array = NULL;
5708 
5709     if (!CFDictionaryGetValueIfPresent(spsStatusDict, ifname, (const void**) &array))
5710     {
5711         array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
5712         if (!array) { LogMsg("UpdateSPSStatus: Could not create CFMutableArray"); CFRelease(ifname); return; }
5713         CFDictionarySetValue(spsStatusDict, ifname, array);
5714         CFRelease(array); // let go of our reference, now that the dict has one
5715     }
5716     else
5717     if (!array) { LogMsg("UpdateSPSStatus: Could not get CFMutableArray for %s", info->ifname); CFRelease(ifname); return; }
5718 
5719     if (!answer) // special call that means the question has been stopped (because the interface is going away)
5720         CFArrayRemoveAllValues(array);
5721     else
5722     {
5723         CFMutableDictionaryRef dict = SPSCreateDict(answer->rdata->u.name.c);
5724         if (!dict) { CFRelease(ifname); return; }
5725 
5726         if (AddRecord)
5727         {
5728             if (!CFArrayContainsValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict))
5729             {
5730                 int i=0;
5731                 for (i=0; i<CFArrayGetCount(array); i++)
5732                     if (CompareSPSEntries(CFArrayGetValueAtIndex(array, i), dict, NULL) != kCFCompareLessThan)
5733                         break;
5734                 CFArrayInsertValueAtIndex(array, i, dict);
5735             }
5736             else LogMsg("UpdateSPSStatus: %s array already contains %##s", info->ifname, answer->rdata->u.name.c);
5737         }
5738         else
5739         {
5740             CFIndex i = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict);
5741             if (i != -1) CFArrayRemoveValueAtIndex(array, i);
5742             else LogMsg("UpdateSPSStatus: %s array does not contain %##s", info->ifname, answer->rdata->u.name.c);
5743         }
5744 
5745         CFRelease(dict);
5746     }
5747 
5748     if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, info->ifname, array);
5749 
5750     CFRelease(ifname);
5751 }
5752 
GetSystemSleepTimerSetting(void)5753 mDNSlocal mDNSs32 GetSystemSleepTimerSetting(void)
5754 {
5755     mDNSs32 val = -1;
5756     SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetSystemSleepTimerSetting"), NULL, NULL);
5757     if (!store)
5758         LogMsg("GetSystemSleepTimerSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
5759     else
5760     {
5761         CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_PowerSettings);
5762         if (dict)
5763         {
5764             CFNumberRef number = CFDictionaryGetValue(dict, CFSTR("System Sleep Timer"));
5765             if (number != NULL) CFNumberGetValue(number, kCFNumberSInt32Type, &val);
5766             CFRelease(dict);
5767         }
5768         CFRelease(store);
5769     }
5770     return val;
5771 }
5772 
SetSPS(mDNS * const m)5773 mDNSlocal void SetSPS(mDNS *const m)
5774 {
5775 
5776     // If we ever want to know InternetSharing status in the future, use DNSXEnableProxy()
5777     mDNSu8 sps = (OfferSleepProxyService && GetSystemSleepTimerSetting() == 0) ? mDNSSleepProxyMetric_IncidentalSoftware : 0;
5778 
5779     // For devices that are not running NAT, but are set to never sleep, we may choose to act
5780     // as a Sleep Proxy, but only for non-portable Macs (Portability > 35 means nominal weight < 3kg)
5781     //if (sps > mDNSSleepProxyMetric_PrimarySoftware && SPMetricPortability > 35) sps = 0;
5782 
5783     // If we decide to let laptops act as Sleep Proxy, we should do it only when running on AC power, not on battery
5784 
5785     // For devices that are unable to sleep at all to save power, or save 1W or less by sleeping,
5786     // it makes sense for them to offer low-priority Sleep Proxy service on the network.
5787     // We rate such a device as metric 70 ("Incidentally Available Hardware")
5788     if (SPMetricMarginalPower <= 60 && !sps) sps = mDNSSleepProxyMetric_IncidentalHardware;
5789 
5790     // If the launchd plist specifies an explicit value for the Intent Metric, then use that instead of the
5791     // computed value (currently 40 "Primary Network Infrastructure Software" or 80 "Incidentally Available Software")
5792     if (sps && OfferSleepProxyService && OfferSleepProxyService < 100) sps = OfferSleepProxyService;
5793 
5794 #ifdef NO_APPLETV_SLEEP_PROXY_ON_WIFI
5795     // AppleTVs are not reliable sleep proxy servers on WiFi. Do not offer to be a BSP if the WiFi interface is active.
5796     if (IsAppleTV())
5797     {
5798         NetworkInterfaceInfo *intf  = mDNSNULL;
5799         mDNSEthAddr           bssid = zeroEthAddr;
5800         for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
5801         {
5802             if (intf->InterfaceID == AWDLInterfaceID) continue;
5803             bssid = GetBSSID(intf->ifname);
5804             if (!mDNSSameEthAddress(&bssid, &zeroEthAddr))
5805             {
5806                 LogMsg("SetSPS: AppleTV on WiFi - not advertising BSP services");
5807                 sps = 0;
5808                 break;
5809             }
5810         }
5811     }
5812 #endif  //  NO_APPLETV_SLEEP_PROXY_ON_WIFI
5813 
5814     mDNSCoreBeSleepProxyServer(m, sps, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures);
5815 }
5816 
5817 // The definitions below should eventually come from some externally-supplied header file.
5818 // However, since these definitions can't really be changed without breaking binary compatibility,
5819 // they should never change, so in practice it should not be a big problem to have them defined here.
5820 
5821 enum
5822 {                               // commands from the daemon to the driver
5823     cmd_mDNSOffloadRR = 21,     // give the mdns update buffer to the driver
5824 };
5825 
5826 typedef union { void *ptr; mDNSOpaque64 sixtyfourbits; } FatPtr;
5827 
5828 typedef struct
5829 {                                       // cmd_mDNSOffloadRR structure
5830     uint32_t command;                 // set to OffloadRR
5831     uint32_t rrBufferSize;            // number of bytes of RR records
5832     uint32_t numUDPPorts;             // number of SRV UDP ports
5833     uint32_t numTCPPorts;             // number of SRV TCP ports
5834     uint32_t numRRRecords;            // number of RR records
5835     uint32_t compression;             // rrRecords - compression is base for compressed strings
5836     FatPtr rrRecords;                 // address of array of pointers to the rr records
5837     FatPtr udpPorts;                  // address of udp port list (SRV)
5838     FatPtr tcpPorts;                  // address of tcp port list (SRV)
5839 } mDNSOffloadCmd;
5840 
5841 #include <IOKit/IOKitLib.h>
5842 #include <dns_util.h>
5843 
GetPortArray(int trans,mDNSIPPort * portarray)5844 mDNSlocal mDNSu32 GetPortArray(int trans, mDNSIPPort *portarray)
5845 {
5846     mDNS *const m = &mDNSStorage;
5847     const domainlabel *const tp = (trans == mDNSTransport_UDP) ? (const domainlabel *)"\x4_udp" : (const domainlabel *)"\x4_tcp";
5848     mDNSu32 count = 0;
5849 
5850     AuthRecord *rr;
5851     for (rr = m->ResourceRecords; rr; rr=rr->next)
5852     {
5853         if (rr->resrec.rrtype == kDNSType_SRV && SameDomainLabel(ThirdLabel(rr->resrec.name)->c, tp->c))
5854         {
5855             if (!portarray)
5856                 count++;
5857             else
5858             {
5859                 mDNSu32 i;
5860                 for (i = 0; i < count; i++)
5861                     if (mDNSSameIPPort(portarray[i], rr->resrec.rdata->u.srv.port))
5862                         break;
5863 
5864                 // Add it into the port list only if it not already present in the list
5865                 if (i >= count)
5866                     portarray[count++] = rr->resrec.rdata->u.srv.port;
5867             }
5868         }
5869     }
5870     return(count);
5871 }
5872 
5873 #if APPLE_OSX_mDNSResponder && TARGET_OS_OSX
SupportsTCPKeepAlive()5874 mDNSlocal mDNSBool SupportsTCPKeepAlive()
5875 {
5876     IOReturn  ret      = kIOReturnSuccess;
5877     CFTypeRef obj      = NULL;
5878     mDNSBool  supports = mDNSfalse;
5879 
5880     ret = IOPlatformCopyFeatureActive(CFSTR("TCPKeepAliveDuringSleep"), &obj);
5881     if ((kIOReturnSuccess == ret) && (obj != NULL))
5882     {
5883         supports = (obj ==  kCFBooleanTrue)? mDNStrue : mDNSfalse;
5884         CFRelease(obj);
5885     }
5886     LogSPS("%s: The hardware %s TCP Keep Alive", __func__, (supports ? "supports" : "does not support"));
5887     return supports;
5888 }
5889 
OnBattery(void)5890 mDNSlocal mDNSBool OnBattery(void)
5891 {
5892     CFTypeRef powerInfo = IOPSCopyPowerSourcesInfo();
5893     CFTypeRef powerSrc  = IOPSGetProvidingPowerSourceType(powerInfo);
5894     mDNSBool  result    = mDNSfalse;
5895 
5896     if (powerInfo != NULL)
5897     {
5898         result = CFEqual(CFSTR(kIOPSBatteryPowerValue), powerSrc);
5899         CFRelease(powerInfo);
5900     }
5901     LogSPS("%s: The system is on %s", __func__, (result)? "Battery" : "AC Power");
5902     return result;
5903 }
5904 #endif
5905 
5906 #define TfrRecordToNIC(RR) \
5907     ((!(RR)->resrec.InterfaceID && ((RR)->ForceMCast || IsLocalDomain((RR)->resrec.name))))
5908 
CountProxyRecords(uint32_t * const numbytes,mDNSBool TCPKAOnly,mDNSBool supportsTCPKA)5909 mDNSlocal mDNSu32 CountProxyRecords(uint32_t *const numbytes, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
5910 {
5911     mDNS *const m = &mDNSStorage;
5912     *numbytes = 0;
5913     uint32_t count = 0;
5914     mDNSBool isKeepAliveRecord = mDNSfalse;
5915 
5916     AuthRecord *rr;
5917 
5918     for (rr = m->ResourceRecords; rr; rr=rr->next)
5919     {
5920         if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
5921         {
5922 #if APPLE_OSX_mDNSResponder && TARGET_OS_OSX
5923             isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
5924             // Skip over all other records if we are registering TCP KeepAlive records only
5925             // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive.
5926             if ((TCPKAOnly && !isKeepAliveRecord) || (isKeepAliveRecord && !supportsTCPKA))
5927                 continue;
5928 #else
5929             (void) TCPKAOnly;     // unused
5930             (void) supportsTCPKA; // unused
5931 #endif
5932             if (TfrRecordToNIC(rr))
5933             {
5934                 // For KeepAlive records, use an estimated length of 256, which is the maximum size.
5935                 const uint32_t rdataLen   = isKeepAliveRecord ? ((uint32_t)sizeof(UTF8str255)) : rr->resrec.rdestimate;
5936                 const uint32_t recordSize = DomainNameLength(rr->resrec.name) + 10 + rdataLen;
5937                 *numbytes += recordSize;
5938                 LogSPS("CountProxyRecords: %3u size %5u total %5u %s", count, recordSize, *numbytes, ARDisplayString(m,rr));
5939                 count++;
5940             }
5941         }
5942     }
5943     return(count);
5944 }
5945 
GetProxyRecords(DNSMessage * const msg,uint32_t * const numbytes,FatPtr * const records,uint32_t * outRecordCount,NetworkInterfaceInfo * const intf,mDNSBool TCPKAOnly,mDNSBool supportsTCPKA)5946 mDNSlocal void GetProxyRecords(DNSMessage *const msg, uint32_t *const numbytes, FatPtr *const records,
5947     uint32_t *outRecordCount, NetworkInterfaceInfo *const intf, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
5948 {
5949     mDNS *const m = &mDNSStorage;
5950     mDNSu8 *p = msg->data;
5951     const mDNSu8 *const limit = p + *numbytes;
5952     InitializeDNSMessage(&msg->h, zeroID, zeroID);
5953 
5954     uint32_t count = 0;
5955     AuthRecord *rr;
5956 
5957     for (rr = m->ResourceRecords; rr; rr=rr->next)
5958     {
5959         if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
5960         {
5961 #if APPLE_OSX_mDNSResponder && TARGET_OS_OSX
5962             const mDNSBool isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
5963 
5964             // Skip over all other records if we are registering TCP KeepAlive records only
5965             // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive
5966             // supportsTCPKA is set to true if both policy and interface allow TCP Keepalive
5967             if ((TCPKAOnly && !isKeepAliveRecord) || (isKeepAliveRecord && !supportsTCPKA))
5968                 continue;
5969 
5970             // Update the record before calculating the number of bytes required
5971             // We offload the TCP Keepalive record even if the update fails. When the driver gets the record, it will
5972             // attempt to update the record again.
5973             if (isKeepAliveRecord)
5974             {
5975                 if (UpdateKeepaliveRData(m, rr, intf, mDNSfalse, mDNSNULL) != mStatus_NoError)
5976                 {
5977                     LogSPS("GetProxyRecords: Failed to update keepalive record - %s", ARDisplayString(m, rr));
5978                     continue;
5979                 }
5980                 // Offload only Valid Keepalive records
5981                 if (!mDNSValidKeepAliveRecord(rr))
5982                 {
5983                     continue;
5984                 }
5985             }
5986 #else
5987             (void) intf;          // unused
5988             (void) TCPKAOnly;     // unused
5989             (void) supportsTCPKA; // unused
5990 #endif
5991             if (TfrRecordToNIC(rr))
5992             {
5993                 records[count].sixtyfourbits = zeroOpaque64;
5994                 records[count].ptr = p;
5995                 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
5996                     rr->resrec.rrclass |= kDNSClass_UniqueRRSet;    // Temporarily set the 'unique' bit so PutResourceRecord will set it
5997                 p = PutResourceRecordTTLWithLimit(msg, p, &msg->h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit);
5998                 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;       // Make sure to clear 'unique' bit back to normal state
5999                 LogSPS("GetProxyRecords: %3d start %p end %p size %5d total %5d %s",
6000                        count, records[count].ptr, p, p - (mDNSu8 *)records[count].ptr, p - msg->data, ARDisplayString(m,rr));
6001                 count++;
6002             }
6003         }
6004     }
6005     *numbytes = (mDNSu32)(p - msg->data);
6006     if (outRecordCount) *outRecordCount = count;
6007 }
6008 
SupportsInNICProxy(NetworkInterfaceInfo * const intf)6009 mDNSexport mDNSBool SupportsInNICProxy(NetworkInterfaceInfo *const intf)
6010 {
6011     if(!UseInternalSleepProxy)
6012     {
6013         LogMsg("SupportsInNICProxy: Internal Sleep Proxy is disabled");
6014         return mDNSfalse;
6015     }
6016     return CheckInterfaceSupport(intf, mDNS_IOREG_KEY);
6017 }
6018 
6019 // Called with the lock held
ActivateLocalProxy(NetworkInterfaceInfo * const intf,mDNSBool offloadKeepAlivesOnly,mDNSBool * keepaliveOnly)6020 mDNSexport mStatus ActivateLocalProxy(NetworkInterfaceInfo *const intf, mDNSBool offloadKeepAlivesOnly, mDNSBool *keepaliveOnly)
6021 {
6022     mStatus      result        = mStatus_UnknownErr;
6023     mDNSBool     TCPKAOnly     = mDNSfalse;
6024     mDNSBool     supportsTCPKA = mDNSfalse;
6025     io_service_t service       = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname));
6026 
6027 #if APPLE_OSX_mDNSResponder && TARGET_OS_OSX
6028     // Check if the interface supports TCP Keepalives and the system policy says it is ok to offload TCP Keepalive records
6029     supportsTCPKA = (InterfaceSupportsKeepAlive(intf) && SupportsTCPKeepAlive()) ? mDNStrue : mDNSfalse;
6030     if (!offloadKeepAlivesOnly)
6031     {
6032         // Only TCP Keepalive records are to be offloaded if
6033         // - The system is on battery
6034         // - OR wake for network access is not set but powernap is enabled
6035         TCPKAOnly = supportsTCPKA && ((mDNSStorage.SystemWakeOnLANEnabled == mDNS_WakeOnBattery) || OnBattery());
6036     }
6037     else
6038     {
6039         TCPKAOnly = mDNStrue;
6040     }
6041 #else
6042     (void)offloadKeepAlivesOnly; // Unused.
6043 #endif
6044     if (!service) { LogMsg("ActivateLocalProxy: No service for interface %s", intf->ifname); return(mStatus_UnknownErr); }
6045 
6046     io_name_t       n1, n2;
6047     IOObjectGetClass(service, n1);
6048 
6049     CFTypeRef       ref;
6050     io_object_t     parent;
6051     kern_return_t   kr = RegistryEntrySearchCFPropertyAndIOObject(service, kIOServicePlane, CFSTR(mDNS_IOREG_KEY), &ref, &parent);
6052     IOObjectRelease(service);
6053     if (kr != KERN_SUCCESS) LogSPS("ActivateLocalProxy: No mDNS_IOREG_KEY for interface %s/%s kr %d", intf->ifname, n1, kr);
6054     else
6055     {
6056         IOObjectGetClass(parent, n2);
6057         LogSPS("ActivateLocalProxy: Interface %s service %s parent %s", intf->ifname, n1, n2);
6058 
6059         if (CFGetTypeID(ref) != CFStringGetTypeID() || !CFEqual(ref, CFSTR(mDNS_IOREG_VALUE)))
6060             LogMsg("ActivateLocalProxy: mDNS_IOREG_KEY for interface %s/%s/%s value %s != %s",
6061                    intf->ifname, n1, n2, CFStringGetCStringPtr(ref, mDNSNULL), mDNS_IOREG_VALUE);
6062         else if (!UseInternalSleepProxy)
6063             LogSPS("ActivateLocalProxy: Not using internal (NIC) sleep proxy for interface %s", intf->ifname);
6064         else
6065         {
6066             io_connect_t conObj;
6067             kr = IOServiceOpen(parent, mach_task_self(), mDNS_USER_CLIENT_CREATE_TYPE, &conObj);
6068             if (kr != KERN_SUCCESS) LogMsg("ActivateLocalProxy: IOServiceOpen for %s/%s/%s failed %d", intf->ifname, n1, n2, kr);
6069             else
6070             {
6071                 mDNSOffloadCmd cmd;
6072                 mDNSPlatformMemZero(&cmd, sizeof(cmd)); // When compiling 32-bit, make sure top 32 bits of 64-bit pointers get initialized to zero
6073                 cmd.command       = cmd_mDNSOffloadRR;
6074                 cmd.numUDPPorts   = TCPKAOnly ? 0 : GetPortArray(mDNSTransport_UDP, mDNSNULL);
6075                 cmd.numTCPPorts   = TCPKAOnly ? 0 : GetPortArray(mDNSTransport_TCP, mDNSNULL);
6076                 cmd.numRRRecords  = CountProxyRecords(&cmd.rrBufferSize, TCPKAOnly, supportsTCPKA);
6077                 cmd.compression   = sizeof(DNSMessageHeader);
6078 
6079                 DNSMessage *msg   = (DNSMessage *) callocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader) + cmd.rrBufferSize);
6080                 cmd.rrRecords.ptr = cmd.numRRRecords ? callocL("mDNSOffloadCmd rrRecords", cmd.numRRRecords * sizeof(FatPtr))     : NULL;
6081                 cmd.udpPorts.ptr  = cmd.numUDPPorts  ? callocL("mDNSOffloadCmd udpPorts" , cmd.numUDPPorts  * sizeof(mDNSIPPort)) : NULL;
6082                 cmd.tcpPorts.ptr  = cmd.numTCPPorts  ? callocL("mDNSOffloadCmd tcpPorts" , cmd.numTCPPorts  * sizeof(mDNSIPPort)) : NULL;
6083 
6084                 LogSPS("ActivateLocalProxy: msg %p %u RR %p %u, UDP %p %u, TCP %p %u",
6085                        msg, cmd.rrBufferSize,
6086                        cmd.rrRecords.ptr, cmd.numRRRecords,
6087                        cmd.udpPorts.ptr, cmd.numUDPPorts,
6088                        cmd.tcpPorts.ptr, cmd.numTCPPorts);
6089 
6090                 if (msg && cmd.rrRecords.ptr)
6091                 {
6092                     GetProxyRecords(msg, &cmd.rrBufferSize, cmd.rrRecords.ptr, &cmd.numRRRecords, intf, TCPKAOnly, supportsTCPKA);
6093                 }
6094                 if (cmd.udpPorts.ptr) cmd.numUDPPorts = TCPKAOnly ? 0 : GetPortArray(mDNSTransport_UDP, cmd.udpPorts.ptr);
6095                 if (cmd.tcpPorts.ptr) cmd.numTCPPorts = TCPKAOnly ? 0 : GetPortArray(mDNSTransport_TCP, cmd.tcpPorts.ptr);
6096 
6097                 char outputData[2];
6098                 size_t outputDataSize = sizeof(outputData);
6099                 kr = IOConnectCallStructMethod(conObj, 0, &cmd, sizeof(cmd), outputData, &outputDataSize);
6100                 LogSPS("ActivateLocalProxy: IOConnectCallStructMethod for %s/%s/%s %d", intf->ifname, n1, n2, kr);
6101                 if (kr == KERN_SUCCESS) result = mStatus_NoError;
6102 
6103                 if (cmd.tcpPorts.ptr) freeL("mDNSOffloadCmd udpPorts",  cmd.tcpPorts.ptr);
6104                 if (cmd.udpPorts.ptr) freeL("mDNSOffloadCmd tcpPorts",  cmd.udpPorts.ptr);
6105                 if (cmd.rrRecords.ptr) freeL("mDNSOffloadCmd rrRecords", cmd.rrRecords.ptr);
6106                 if (msg) freeL("mDNSOffloadCmd msg",       msg);
6107                 IOServiceClose(conObj);
6108             }
6109         }
6110         CFRelease(ref);
6111         IOObjectRelease(parent);
6112     }
6113     *keepaliveOnly = (TCPKAOnly && supportsTCPKA) ? mDNStrue : mDNSfalse;
6114     return result;
6115 }
6116 
6117 #endif // APPLE_OSX_mDNSResponder
6118 
SystemWakeForNetworkAccess(void)6119 mDNSlocal mDNSu8 SystemWakeForNetworkAccess(void)
6120 {
6121 #if MDNSRESPONDER_SUPPORTS(APPLE, NO_WAKE_FOR_NET_ACCESS)
6122     LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_DEBUG, "SystemWakeForNetworkAccess: compile-time disabled");
6123     return ((mDNSu8)mDNS_NoWake);
6124 #else
6125     mDNSs32 val = 0;
6126     mDNSu8  ret = (mDNSu8)mDNS_NoWake;
6127 
6128     if (DisableSleepProxyClient)
6129     {
6130        LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option");
6131        return ret;
6132     }
6133 
6134     GetCurrentPMSetting(CFSTR("Wake On LAN"), &val);
6135 
6136     ret = (mDNSu8)(val != 0) ? mDNS_WakeOnAC : mDNS_NoWake;
6137 
6138 #if APPLE_OSX_mDNSResponder && TARGET_OS_OSX
6139     // If we have TCP Keepalive support, system is capable of registering for TCP Keepalives.
6140     // Further policy decisions on whether to offload the records is handled during sleep processing.
6141     if ((ret == mDNS_NoWake) && SupportsTCPKeepAlive())
6142         ret = (mDNSu8)mDNS_WakeOnBattery;
6143 #endif // APPLE_OSX_mDNSResponder
6144 
6145     LogSPS("SystemWakeForNetworkAccess: Wake On LAN: %d", ret);
6146     return ret;
6147 #endif
6148 }
6149 
SystemSleepOnlyIfWakeOnLAN(void)6150 mDNSlocal mDNSBool SystemSleepOnlyIfWakeOnLAN(void)
6151 {
6152     mDNSs32 val = 0;
6153     // PrioritizeNetworkReachabilityOverSleep has been deprecated.
6154     // GetCurrentPMSetting(CFSTR("PrioritizeNetworkReachabilityOverSleep"), &val);
6155     // Statically set the PrioritizeNetworkReachabilityOverSleep value to 1 for AppleTV
6156     if (IsAppleTV())
6157         val = 1;
6158     return val != 0 ? mDNStrue : mDNSfalse;
6159 }
6160 
IsAppleNetwork(mDNS * const m)6161 mDNSlocal mDNSBool IsAppleNetwork(mDNS *const m)
6162 {
6163 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
6164     (void)m;
6165 #else
6166     DNSServer *s;
6167     // Determine if we're on AppleNW based on DNSServer having 17.x.y.z IPv4 addr
6168     for (s = m->DNSServers; s; s = s->next)
6169     {
6170         if (s->addr.ip.v4.b[0] == 17)
6171         {
6172             LogInfo("IsAppleNetwork: Found 17.x.y.z DNSServer concluding that we are on AppleNW: %##s %#a", s->domain.c, &s->addr);
6173             return mDNStrue;
6174         }
6175     }
6176 #endif
6177     return mDNSfalse;
6178 }
6179 
6180 // Called with KQueueLock & mDNS lock
6181 // SetNetworkChanged is allowed to shorten (but not extend) the pause while we wait for configuration changes to settle
SetNetworkChanged(mDNSs32 delay)6182 mDNSlocal void SetNetworkChanged(mDNSs32 delay)
6183 {
6184     mDNS *const m = &mDNSStorage;
6185     mDNS_CheckLock(m);
6186     if (!m->NetworkChanged || m->NetworkChanged - NonZeroTime(m->timenow + delay) > 0)
6187     {
6188         m->NetworkChanged = NonZeroTime(m->timenow + delay);
6189         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "SetNetworkChanged: Scheduling in %d ticks", delay);
6190     }
6191     else
6192    	{
6193         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
6194             "SetNetworkChanged: *NOT* increasing delay from %d to %d", m->NetworkChanged - m->timenow, delay);
6195     }
6196 }
6197 
6198 // Called with KQueueLock & mDNS lock
SetKeyChainTimer(mDNSs32 delay)6199 mDNSlocal void SetKeyChainTimer(mDNSs32 delay)
6200 {
6201     mDNS *const m = &mDNSStorage;
6202     // If it's not set or it needs to happen sooner than when it's currently set
6203     if (!m->p->KeyChainTimer || m->p->KeyChainTimer - NonZeroTime(m->timenow + delay) > 0)
6204     {
6205         m->p->KeyChainTimer = NonZeroTime(m->timenow + delay);
6206         LogInfo("SetKeyChainTimer: %d", delay);
6207     }
6208 }
6209 
mDNSMacOSXNetworkChanged(void)6210 mDNSexport void mDNSMacOSXNetworkChanged(void)
6211 {
6212     mDNS *const m = &mDNSStorage;
6213     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
6214         "*** Network Configuration Change ***  %d ticks late" PUB_S,
6215         m->NetworkChanged ? mDNS_TimeNow(m) - m->NetworkChanged : 0,
6216         m->NetworkChanged ? "" : " (no scheduled configuration change)");
6217     m->NetworkChanged = 0;       // If we received a network change event and deferred processing, we're now dealing with it
6218 
6219     // If we have *any* TENTATIVE IPv6 addresses, wait until they've finished configuring
6220     int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
6221     if (InfoSocket > 0)
6222     {
6223         mDNSBool tentative = mDNSfalse;
6224         struct ifaddrs *ifa = myGetIfAddrs(1);
6225         while (ifa)
6226         {
6227             if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6)
6228             {
6229                 struct in6_ifreq ifr6;
6230                 mDNSPlatformMemZero((char *)&ifr6, sizeof(ifr6));
6231                 strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
6232                 ifr6.ifr_addr = *(struct sockaddr_in6 *)ifa->ifa_addr;
6233                 // We need to check for IN6_IFF_TENTATIVE here, not IN6_IFF_NOTREADY, because
6234                 // IN6_IFF_NOTREADY includes both IN6_IFF_TENTATIVE and IN6_IFF_DUPLICATED addresses.
6235                 // We can expect that an IN6_IFF_TENTATIVE address will shortly become ready,
6236                 // but an IN6_IFF_DUPLICATED address may not.
6237                 if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
6238                 {
6239                     if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
6240                     {
6241                         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
6242                             "*** Network Configuration Change ***  IPv6 address " PRI_IPv6_ADDR " TENTATIVE, will retry",
6243                             &ifr6.ifr_addr.sin6_addr);
6244                         tentative = mDNStrue;
6245                         // no need to check other interfaces if we already found out that one interface is TENTATIVE
6246                         break;
6247                     }
6248                 }
6249             }
6250             ifa = ifa->ifa_next;
6251         }
6252         close(InfoSocket);
6253         if (tentative)
6254         {
6255             mDNS_Lock(m);
6256             SetNetworkChanged(mDNSPlatformOneSecond / 2);
6257             mDNS_Unlock(m);
6258             return;
6259         }
6260         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
6261             "*** Network Configuration Change ***  No IPv6 address TENTATIVE, will continue");
6262     }
6263 
6264     mDNSs32 utc = mDNSPlatformUTC();
6265     m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
6266     m->SystemSleepOnlyIfWakeOnLAN = SystemSleepOnlyIfWakeOnLAN();
6267     MarkAllInterfacesInactive(utc);
6268     UpdateInterfaceList(utc);
6269     ClearInactiveInterfaces(utc);
6270     SetupActiveInterfaces(utc);
6271     ReorderInterfaceList();
6272 
6273 #if APPLE_OSX_mDNSResponder
6274     SetSPS(m);
6275 
6276     NetworkInterfaceInfoOSX *i;
6277     for (i = m->p->InterfaceList; i; i = i->next)
6278     {
6279         if (!m->SPSSocket) // Not being Sleep Proxy Server; close any open BPF fds
6280         {
6281             if (i->BPF_fd >= 0 && CountProxyTargets(i, mDNSNULL, mDNSNULL) == 0)
6282                 CloseBPF(i);
6283         }
6284         else // else, we're Sleep Proxy Server; open BPF fds
6285         {
6286             if (i->Exists && (i->Registered == i) && SPSInterface(i) && i->BPF_fd == -1)
6287             {
6288                 LogMsg("%s mDNSMacOSXNetworkChanged: requesting BPF", i->ifinfo.ifname);
6289                 i->BPF_fd = -2;
6290                 mDNSRequestBPF();
6291             }
6292         }
6293     }
6294 
6295 #endif // APPLE_OSX_mDNSResponder
6296 
6297     uDNS_SetupDNSConfig(m);
6298     mDNS_ConfigChanged(m);
6299 
6300     if (IsAppleNetwork(m) != mDNS_McastTracingEnabled)
6301     {
6302         mDNS_McastTracingEnabled = mDNS_McastTracingEnabled ? mDNSfalse : mDNStrue;
6303         LogInfo("mDNSMacOSXNetworkChanged: Multicast Tracing %s", mDNS_McastTracingEnabled ? "Enabled" : "Disabled");
6304         UpdateDebugState();
6305     }
6306 
6307 }
6308 
6309 // Copy the fourth slash-delimited element from either:
6310 //   State:/Network/Interface/<bsdname>/IPv4
6311 // or
6312 //   Setup:/Network/Service/<servicename>/Interface
CopyNameFromKey(CFStringRef key)6313 mDNSlocal CFStringRef CopyNameFromKey(CFStringRef key)
6314 {
6315     CFArrayRef a;
6316     CFStringRef name = NULL;
6317 
6318     a = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
6319     if (a && CFArrayGetCount(a) == 5) name = CFRetain(CFArrayGetValueAtIndex(a, 3));
6320     if (a != NULL) CFRelease(a);
6321 
6322     return name;
6323 }
6324 
6325 // Whether a key from a network change notification corresponds to
6326 // an IP service that is explicitly configured for IPv4 Link Local
ChangedKeysHaveIPv4LL(CFArrayRef inkeys)6327 mDNSlocal int ChangedKeysHaveIPv4LL(CFArrayRef inkeys)
6328 {
6329     CFDictionaryRef dict = NULL;
6330     CFMutableArrayRef a;
6331     const void **keys = NULL, **vals = NULL;
6332     CFStringRef pattern = NULL;
6333     CFIndex i, ic, j, jc;
6334     int found = 0;
6335 
6336     jc = CFArrayGetCount(inkeys);
6337     if (jc <= 0) goto done;
6338 
6339     a = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
6340     if (a == NULL) goto done;
6341 
6342     // Setup:/Network/Service/[^/]+/Interface
6343     pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetInterface);
6344     if (pattern == NULL) goto done;
6345     CFArrayAppendValue(a, pattern);
6346     CFRelease(pattern);
6347 
6348     // Setup:/Network/Service/[^/]+/IPv4
6349     pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetIPv4);
6350     if (pattern == NULL) goto done;
6351     CFArrayAppendValue(a, pattern);
6352     CFRelease(pattern);
6353 
6354     dict = SCDynamicStoreCopyMultiple(NULL, NULL, a);
6355     CFRelease(a);
6356 
6357     if (!dict)
6358     {
6359         LogMsg("ChangedKeysHaveIPv4LL: No dictionary");
6360         goto done;
6361     }
6362 
6363     ic = CFDictionaryGetCount(dict);
6364     if (ic <= 0)
6365     {
6366         LogMsg("ChangedKeysHaveIPv4LL: Empty dictionary");
6367         goto done;
6368     }
6369 
6370     vals = (const void **) mDNSPlatformMemAllocate(sizeof(void *) * (mDNSu32)ic);
6371     keys = (const void **) mDNSPlatformMemAllocate(sizeof(void *) * (mDNSu32)ic);
6372     CFDictionaryGetKeysAndValues(dict, keys, vals);
6373 
6374     // For each key we were given...
6375     for (j = 0; j < jc; j++)
6376     {
6377         CFStringRef key = CFArrayGetValueAtIndex(inkeys, j);
6378         CFStringRef ifname = NULL;
6379 
6380         char buf[256];
6381 
6382         // It would be nice to use a regex here
6383         if (!CFStringHasPrefix(key, CFSTR("State:/Network/Interface/")) || !CFStringHasSuffix(key, kSCEntNetIPv4)) continue;
6384 
6385         if ((ifname = CopyNameFromKey(key)) == NULL) continue;
6386         if (mDNS_LoggingEnabled)
6387         {
6388             if (!CFStringGetCString(ifname, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
6389             LogInfo("ChangedKeysHaveIPv4LL: potential ifname %s", buf);
6390         }
6391 
6392         // Loop over the interfaces to find matching the ifname, and see if that one has kSCValNetIPv4ConfigMethodLinkLocal
6393         for (i = 0; i < ic; i++)
6394         {
6395             CFDictionaryRef ipv4dict;
6396             CFStringRef name;
6397             CFStringRef serviceid;
6398             CFStringRef configmethod;
6399 
6400             if (!CFStringHasSuffix(keys[i], kSCEntNetInterface)) continue;
6401 
6402             if (CFDictionaryGetTypeID() != CFGetTypeID(vals[i])) continue;
6403 
6404             if ((name = CFDictionaryGetValue(vals[i], kSCPropNetInterfaceDeviceName)) == NULL) continue;
6405 
6406             if (!CFEqual(ifname, name)) continue;
6407 
6408             if ((serviceid = CopyNameFromKey(keys[i])) == NULL) continue;
6409             if (mDNS_LoggingEnabled)
6410             {
6411                 if (!CFStringGetCString(serviceid, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
6412                 LogInfo("ChangedKeysHaveIPv4LL: found serviceid %s", buf);
6413             }
6414 
6415             pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceid, kSCEntNetIPv4);
6416             CFRelease(serviceid);
6417             if (pattern == NULL) continue;
6418 
6419             ipv4dict = CFDictionaryGetValue(dict, pattern);
6420             CFRelease(pattern);
6421             if (!ipv4dict || CFDictionaryGetTypeID() != CFGetTypeID(ipv4dict)) continue;
6422 
6423             configmethod = CFDictionaryGetValue(ipv4dict, kSCPropNetIPv4ConfigMethod);
6424             if (!configmethod) continue;
6425 
6426             if (mDNS_LoggingEnabled)
6427             {
6428                 if (!CFStringGetCString(configmethod, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
6429                 LogInfo("ChangedKeysHaveIPv4LL: configmethod %s", buf);
6430             }
6431 
6432             if (CFEqual(configmethod, kSCValNetIPv4ConfigMethodLinkLocal)) { found++; break; }
6433         }
6434 
6435         CFRelease(ifname);
6436     }
6437 
6438 done:
6439     if (vals != NULL) mDNSPlatformMemFree(vals);
6440     if (keys != NULL) mDNSPlatformMemFree(keys);
6441     if (dict != NULL) CFRelease(dict);
6442 
6443     return found;
6444 }
6445 
NetworkChanged(SCDynamicStoreRef store,CFArrayRef changedKeys,void * context)6446 mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
6447 {
6448     (void)store;        // Parameter not used
6449     mDNS *const m = (mDNS *const)context;
6450     KQueueLock();
6451     mDNS_Lock(m);
6452 
6453     //mDNSs32 delay = mDNSPlatformOneSecond * 2;                // Start off assuming a two-second delay
6454     const mDNSs32 delay = (mDNSPlatformOneSecond + 39) / 40;    // 25 ms delay
6455 
6456     const CFIndex c = CFArrayGetCount(changedKeys);             // Count changes
6457     CFRange range = { 0, c };
6458     const int c_host = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Hostnames   ) != 0);
6459     const int c_comp = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Computername) != 0);
6460     const int c_udns = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DNS         ) != 0);
6461     const int c_ddns = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DynamicDNS  ) != 0);
6462     const int c_v4ll = ChangedKeysHaveIPv4LL(changedKeys);
6463     int c_fast = 0;
6464 
6465     // Do immediate network changed processing for "p2p*" interfaces and
6466     // for interfaces with the IFEF_DIRECTLINK or IFEF_AWDL flag set or association with a CarPlay
6467     // hosted SSID.
6468     {
6469         CFArrayRef  labels;
6470         CFIndex     n;
6471         for (CFIndex i = 0; i < c; i++)
6472         {
6473             CFStringRef key = CFArrayGetValueAtIndex(changedKeys, i);
6474 
6475             // Only look at keys with prefix "State:/Network/Interface/"
6476             if (!CFStringHasPrefix(key, NetworkChangedKey_StateInterfacePrefix))
6477                 continue;
6478 
6479             // And suffix "IPv6" or "IPv4".
6480             if (!CFStringHasSuffix(key, kSCEntNetIPv6) && !CFStringHasSuffix(key, kSCEntNetIPv4))
6481                 continue;
6482 
6483             labels = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
6484             if (labels == NULL)
6485                 break;
6486             n = CFArrayGetCount(labels);
6487 
6488             // Interface changes will have keys of the form:
6489             //     State:/Network/Interface/<interfaceName>/IPv6
6490             // Thus five '/' seperated fields, the 4th one being the <interfaceName> string.
6491             if (n == 5)
6492             {
6493                 char buf[256];
6494 
6495                 // The 4th label (index = 3) should be the interface name.
6496                 if (CFStringGetCString(CFArrayGetValueAtIndex(labels, 3), buf, sizeof(buf), kCFStringEncodingUTF8)
6497                     && (strstr(buf, "p2p") || (getExtendedFlags(buf) & (IFEF_DIRECTLINK | IFEF_AWDL)) || IsCarPlaySSID(buf)))
6498                 {
6499                     LogInfo("NetworkChanged: interface %s qualifies for reduced change handling delay", buf);
6500                     c_fast++;
6501                     CFRelease(labels);
6502                     break;
6503                 }
6504             }
6505             CFRelease(labels);
6506         }
6507     }
6508 
6509     //if (c && c - c_host - c_comp - c_udns - c_ddns - c_v4ll - c_fast == 0)
6510     //    delay = mDNSPlatformOneSecond/10;  // If these were the only changes, shorten delay
6511 
6512     if (mDNS_LoggingEnabled)
6513     {
6514         CFIndex i;
6515         for (i=0; i<c; i++)
6516         {
6517             char buf[256];
6518             if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys, i), buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
6519             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "*** Network Configuration Change *** SC key: " PUB_S, buf);
6520         }
6521         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
6522             "*** Network Configuration Change *** %ld change" PUB_S " " PUB_S PUB_S PUB_S PUB_S PUB_S PUB_S "delay %d" PUB_S,
6523             (long)c, c>1 ? "s" : "",
6524             c_host ? "(Local Hostname) " : "",
6525             c_comp ? "(Computer Name) "  : "",
6526             c_udns ? "(DNS) "            : "",
6527             c_ddns ? "(DynamicDNS) "     : "",
6528             c_v4ll ? "(kSCValNetIPv4ConfigMethodLinkLocal) " : "",
6529             c_fast ? "(P2P/IFEF_DIRECTLINK/IFEF_AWDL/IsCarPlaySSID) "  : "",
6530             delay,
6531             c_ddns ? " + SetKeyChainTimer" : "");
6532     }
6533 
6534     SetNetworkChanged(delay);
6535 
6536     // Other software might pick up these changes to register or browse in WAB or BTMM domains,
6537     // so in order for secure updates to be made to the server, make sure to read the keychain and
6538     // setup the DomainAuthInfo before handing the network change.
6539     // If we don't, then we will first try to register services in the clear, then later setup the
6540     // DomainAuthInfo, which is incorrect.
6541     if (c_ddns)
6542         SetKeyChainTimer(delay);
6543 
6544     // Don't try to call mDNSMacOSXNetworkChanged() here -- we're running on the wrong thread
6545 
6546     mDNS_Unlock(m);
6547     KQueueUnlock("NetworkChanged");
6548 }
6549 
6550 #if APPLE_OSX_mDNSResponder
RefreshSPSStatus(const void * key,const void * value,void * context)6551 mDNSlocal void RefreshSPSStatus(const void *key, const void *value, void *context)
6552 {
6553     (void)context;
6554     char buf[IFNAMSIZ];
6555 
6556     CFStringRef ifnameStr = (CFStringRef)key;
6557     CFArrayRef array = (CFArrayRef)value;
6558     if (!CFStringGetCString(ifnameStr, buf, sizeof(buf), kCFStringEncodingUTF8))
6559         buf[0] = 0;
6560 
6561     LogInfo("RefreshSPSStatus: Updating SPS state for key %s, array count %d", buf, CFArrayGetCount(array));
6562     mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, buf, value);
6563 }
6564 #endif
6565 
DynamicStoreReconnected(SCDynamicStoreRef store,void * info)6566 mDNSlocal void DynamicStoreReconnected(SCDynamicStoreRef store, void *info)
6567 {
6568     mDNS *const m = (mDNS *const)info;
6569     (void)store;
6570 
6571     KQueueLock();   // serialize with KQueueLoop()
6572 
6573     LogInfo("DynamicStoreReconnected: Reconnected");
6574 
6575     // State:/Network/MulticastDNS
6576     SetLocalDomains();
6577 
6578     // State:/Network/DynamicDNS
6579     if (m->FQDN.c[0])
6580         mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1);
6581 
6582     // Note: PrivateDNS and BackToMyMac are automatically populated when configd is restarted
6583     // as we receive network change notifications and thus not necessary. But we leave it here
6584     // so that if things are done differently in the future, this code still works.
6585 
6586     // State:/Network/PrivateDNS
6587     if (privateDnsArray)
6588         mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray);
6589 
6590 #if APPLE_OSX_mDNSResponder
6591     // State:/Network/Interface/en0/SleepProxyServers
6592     if (spsStatusDict)
6593         CFDictionaryApplyFunction(spsStatusDict, RefreshSPSStatus, NULL);
6594 #endif
6595     KQueueUnlock("DynamicStoreReconnected");
6596 }
6597 
WatchForNetworkChanges(mDNS * const m)6598 mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
6599 {
6600     mStatus err = -1;
6601     SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
6602     SCDynamicStoreRef store    = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged, &context);
6603     CFMutableArrayRef keys     = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
6604     CFStringRef pattern1 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
6605     CFStringRef pattern2 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
6606     CFMutableArrayRef patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
6607 
6608     if (!store) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error; }
6609     if (!keys || !pattern1 || !pattern2 || !patterns) goto error;
6610 
6611     CFArrayAppendValue(keys, NetworkChangedKey_IPv4);
6612     CFArrayAppendValue(keys, NetworkChangedKey_IPv6);
6613     CFArrayAppendValue(keys, NetworkChangedKey_Hostnames);
6614     CFArrayAppendValue(keys, NetworkChangedKey_Computername);
6615     CFArrayAppendValue(keys, NetworkChangedKey_DNS);
6616     CFArrayAppendValue(keys, NetworkChangedKey_DynamicDNS);
6617     CFArrayAppendValue(keys, NetworkChangedKey_PowerSettings);
6618     CFArrayAppendValue(patterns, pattern1);
6619     CFArrayAppendValue(patterns, pattern2);
6620     CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
6621     if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns))
6622     { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error; }
6623 
6624 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
6625     if (!SCDynamicStoreSetDispatchQueue(store, dispatch_get_main_queue()))
6626     { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
6627 #else
6628     m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
6629     if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
6630     CFRunLoopAddSource(CFRunLoopGetMain(), m->p->StoreRLS, kCFRunLoopDefaultMode);
6631 #endif
6632     SCDynamicStoreSetDisconnectCallBack(store, DynamicStoreReconnected);
6633     m->p->Store = store;
6634     err = 0;
6635     goto exit;
6636 
6637 error:
6638     if (store) CFRelease(store);
6639 
6640 exit:
6641     if (patterns) CFRelease(patterns);
6642     if (pattern2) CFRelease(pattern2);
6643     if (pattern1) CFRelease(pattern1);
6644     if (keys) CFRelease(keys);
6645 
6646     return(err);
6647 }
6648 
6649 #if TARGET_OS_OSX
mDNSSetPacketFilterRules(char * ifname,const ResourceRecord * const excludeRecord)6650 mDNSlocal void mDNSSetPacketFilterRules(char * ifname, const ResourceRecord *const excludeRecord)
6651 {
6652     mDNS *const m = &mDNSStorage;
6653     AuthRecord  *rr;
6654     pfArray_t portArray;
6655     pfArray_t protocolArray;
6656     uint32_t count = 0;
6657 
6658     for (rr = m->ResourceRecords; rr; rr=rr->next)
6659     {
6660         if ((rr->resrec.rrtype == kDNSServiceType_SRV)
6661             && ((rr->ARType == AuthRecordAnyIncludeP2P) || (rr->ARType == AuthRecordAnyIncludeAWDLandP2P)))
6662         {
6663             const mDNSu8    *p;
6664 
6665             if (count >= PFPortArraySize)
6666             {
6667                 LogMsg("mDNSSetPacketFilterRules: %d service limit, skipping %s", PFPortArraySize, ARDisplayString(m, rr));
6668                 continue;
6669             }
6670 
6671             if (excludeRecord && IdenticalResourceRecord(&rr->resrec, excludeRecord))
6672             {
6673                 LogInfo("mDNSSetPacketFilterRules: record being removed, skipping %s", ARDisplayString(m, rr));
6674                 continue;
6675             }
6676 
6677             LogMsg("mDNSSetPacketFilterRules: found %s", ARDisplayString(m, rr));
6678 
6679             portArray[count] = rr->resrec.rdata->u.srv.port.NotAnInteger;
6680 
6681             // Assume <Service Instance>.<App Protocol>.<Transport Protocol>.<Name>
6682             p = rr->resrec.name->c;
6683 
6684             // Skip to App Protocol
6685             if (p[0])
6686                 p += 1 + p[0];
6687 
6688             // Skip to Transport Protocol
6689             if (p[0])
6690                 p += 1 + p[0];
6691 
6692             if      (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp"))
6693             {
6694                 protocolArray[count] = IPPROTO_TCP;
6695             }
6696             else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp"))
6697             {
6698                 protocolArray[count] = IPPROTO_UDP;
6699             }
6700             else
6701             {
6702                 LogMsg("mDNSSetPacketFilterRules: could not determine transport protocol of service");
6703                 LogMsg("mDNSSetPacketFilterRules: %s", ARDisplayString(m, rr));
6704                 return;
6705             }
6706             count++;
6707         }
6708     }
6709     mDNSPacketFilterControl(PF_SET_RULES, ifname, count, portArray, protocolArray);
6710 }
6711 
6712 // If the p2p interface already exists, update the Bonjour packet filter rules for it.
mDNSUpdatePacketFilter(const ResourceRecord * const excludeRecord)6713 mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord)
6714 {
6715     mDNS *const m = &mDNSStorage;
6716 
6717     NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces);
6718     while (intf)
6719     {
6720         if (strncmp(intf->ifname, "p2p", 3) == 0)
6721         {
6722             LogInfo("mDNSInitPacketFilter: Setting rules for ifname %s", intf->ifname);
6723             mDNSSetPacketFilterRules(intf->ifname, excludeRecord);
6724             break;
6725         }
6726         intf = GetFirstActiveInterface(intf->next);
6727     }
6728 }
6729 #else // !TARGET_OS_OSX
6730 // Currently no packet filter setup required on embedded platforms.
mDNSUpdatePacketFilter(const ResourceRecord * const excludeRecord)6731 mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord)
6732 {
6733     (void) excludeRecord; // unused
6734 }
6735 #endif
6736 
6737 // AWDL should no longer generate KEV_DL_MASTER_ELECTED events, so just log a message if we receive one.
newMasterElected(struct net_event_data * ptr)6738 mDNSlocal void newMasterElected(struct net_event_data * ptr)
6739 {
6740     char        ifname[IFNAMSIZ];
6741     mDNSu32     interfaceIndex;
6742 
6743     snprintf(ifname, IFNAMSIZ, "%s%d", ptr->if_name, ptr->if_unit);
6744     interfaceIndex  = if_nametoindex(ifname);
6745 
6746     if (!interfaceIndex)
6747     {
6748         LogMsg("newMasterElected: if_nametoindex(%s) failed", ifname);
6749         return;
6750     }
6751 
6752     LogInfo("newMasterElected: KEV_DL_MASTER_ELECTED received on ifname = %s, interfaceIndex = %d", ifname, interfaceIndex);
6753 }
6754 
6755 // An ssth array of all zeroes indicates the peer has no services registered.
allZeroSSTH(struct opaque_presence_indication * op)6756 mDNSlocal mDNSBool allZeroSSTH(struct opaque_presence_indication *op)
6757 {
6758     int i;
6759     int *intp = (int *) op->ssth;
6760 
6761     // MAX_SSTH_SIZE should always be a multiple of sizeof(int), if
6762     // it's not, print an error message and return false so that
6763     // corresponding peer records are not flushed when KEV_DL_NODE_PRESENCE event
6764     // is received.
6765     if (MAX_SSTH_SIZE % sizeof(int))
6766     {
6767         LogInfo("allZeroSSTH: MAX_SSTH_SIZE = %d not a multiple of sizeof(int)", MAX_SSTH_SIZE);
6768         return mDNSfalse;
6769     }
6770 
6771     for (i = 0; i < (int)(MAX_SSTH_SIZE / sizeof(int)); i++, intp++)
6772     {
6773         if (*intp)
6774             return mDNSfalse;
6775     }
6776     return mDNStrue;
6777 }
6778 
6779 // Mark records from this peer for deletion from the cache.
removeCachedPeerRecords(mDNSu32 ifindex,mDNSAddr * ap,bool purgeNow)6780 mDNSlocal void removeCachedPeerRecords(mDNSu32 ifindex, mDNSAddr *ap, bool purgeNow)
6781 {
6782     mDNS *const m = &mDNSStorage;
6783     mDNSu32     slot;
6784     CacheGroup  *cg;
6785     CacheRecord *cr;
6786     NetworkInterfaceInfoOSX *infoOSX;
6787     mDNSInterfaceID InterfaceID;
6788 
6789     // Using mDNSPlatformInterfaceIDfromInterfaceIndex() would lead to recursive
6790     // locking issues, see: <rdar://problem/21332983>
6791     infoOSX = IfindexToInterfaceInfoOSX((mDNSInterfaceID)(uintptr_t)ifindex);
6792     if (!infoOSX)
6793     {
6794         LogInfo("removeCachedPeerRecords: interface %d not yet active", ifindex);
6795         return;
6796     }
6797     InterfaceID = infoOSX->ifinfo.InterfaceID;
6798 
6799     FORALL_CACHERECORDS(slot, cg, cr)
6800     {
6801         if ((InterfaceID == cr->resrec.InterfaceID) && mDNSSameAddress(ap, & cr->sourceAddress))
6802         {
6803             LogInfo("removeCachedPeerRecords: %s %##s marking for deletion",
6804                  DNSTypeName(cr->resrec.rrtype), cr->resrec.name->c);
6805 
6806             if (purgeNow)
6807                 mDNS_PurgeCacheResourceRecord(m, cr);
6808             else
6809                 mDNS_Reconfirm_internal(m, cr, 0);  // use default minimum reconfirm time
6810         }
6811     }
6812 }
6813 
6814 // Handle KEV_DL_NODE_PRESENCE event.
nodePresence(struct kev_dl_node_presence * p)6815 mDNSlocal void nodePresence(struct kev_dl_node_presence * p)
6816 {
6817     struct opaque_presence_indication *op = (struct opaque_presence_indication *) p->node_service_info;
6818 
6819     LogInfo("nodePresence: IPv6 address: %.16a, SUI %d", p->sin6_node_address.sin6_addr.s6_addr, op->SUI);
6820 
6821     // AWDL will generate a KEV_DL_NODE_PRESENCE event with SSTH field of
6822     // all zeroes when a node is present and has no services registered.
6823     if (allZeroSSTH(op))
6824     {
6825         mDNSAddr    peerAddr;
6826 
6827         peerAddr.type = mDNSAddrType_IPv6;
6828         peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr;
6829 
6830         LogInfo("nodePresence: ssth is all zeroes, reconfirm cached records for this peer");
6831         removeCachedPeerRecords(p->sdl_node_address.sdl_index, & peerAddr, false);
6832     }
6833 }
6834 
6835 // Handle KEV_DL_NODE_ABSENCE event.
nodeAbsence(struct kev_dl_node_absence * p)6836 mDNSlocal void nodeAbsence(struct kev_dl_node_absence * p)
6837 {
6838     mDNSAddr    peerAddr;
6839 
6840     peerAddr.type = mDNSAddrType_IPv6;
6841     peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr;
6842 
6843     LogInfo("nodeAbsence: immediately purge cached records from %.16a", p->sin6_node_address.sin6_addr.s6_addr);
6844     removeCachedPeerRecords(p->sdl_node_address.sdl_index, & peerAddr, true);
6845 }
6846 
SysEventCallBack(int s1,short __unused filter,void * context,__unused mDNSBool encounteredEOF)6847 mDNSlocal void SysEventCallBack(int s1, short __unused filter, void *context, __unused mDNSBool encounteredEOF)
6848 {
6849     mDNS *const m = (mDNS *const)context;
6850 
6851     mDNS_Lock(m);
6852 
6853     struct { struct kern_event_msg k; char extra[256]; } msg;
6854     ssize_t bytes = recv(s1, &msg, sizeof(msg), 0);
6855     if (bytes < 0)
6856         LogMsg("SysEventCallBack: recv error %ld errno %d (%s)", (long)bytes, errno, strerror(errno));
6857     else
6858     {
6859         LogInfo("SysEventCallBack got %ld bytes size %u %X %s %X %s %X %s id %d code %d %s",
6860                 (long)bytes, msg.k.total_size,
6861                 msg.k.vendor_code, msg.k.vendor_code  == KEV_VENDOR_APPLE  ? "KEV_VENDOR_APPLE"  : "?",
6862                 msg.k.kev_class, msg.k.kev_class    == KEV_NETWORK_CLASS ? "KEV_NETWORK_CLASS" : "?",
6863                 msg.k.kev_subclass, msg.k.kev_subclass == KEV_DL_SUBCLASS   ? "KEV_DL_SUBCLASS"   : "?",
6864                 msg.k.id, msg.k.event_code,
6865                 msg.k.event_code == KEV_DL_SIFFLAGS             ? "KEV_DL_SIFFLAGS"             :
6866                 msg.k.event_code == KEV_DL_SIFMETRICS           ? "KEV_DL_SIFMETRICS"           :
6867                 msg.k.event_code == KEV_DL_SIFMTU               ? "KEV_DL_SIFMTU"               :
6868                 msg.k.event_code == KEV_DL_SIFPHYS              ? "KEV_DL_SIFPHYS"              :
6869                 msg.k.event_code == KEV_DL_SIFMEDIA             ? "KEV_DL_SIFMEDIA"             :
6870                 msg.k.event_code == KEV_DL_SIFGENERIC           ? "KEV_DL_SIFGENERIC"           :
6871                 msg.k.event_code == KEV_DL_ADDMULTI             ? "KEV_DL_ADDMULTI"             :
6872                 msg.k.event_code == KEV_DL_DELMULTI             ? "KEV_DL_DELMULTI"             :
6873                 msg.k.event_code == KEV_DL_IF_ATTACHED          ? "KEV_DL_IF_ATTACHED"          :
6874                 msg.k.event_code == KEV_DL_IF_DETACHING         ? "KEV_DL_IF_DETACHING"         :
6875                 msg.k.event_code == KEV_DL_IF_DETACHED          ? "KEV_DL_IF_DETACHED"          :
6876                 msg.k.event_code == KEV_DL_LINK_OFF             ? "KEV_DL_LINK_OFF"             :
6877                 msg.k.event_code == KEV_DL_LINK_ON              ? "KEV_DL_LINK_ON"              :
6878                 msg.k.event_code == KEV_DL_PROTO_ATTACHED       ? "KEV_DL_PROTO_ATTACHED"       :
6879                 msg.k.event_code == KEV_DL_PROTO_DETACHED       ? "KEV_DL_PROTO_DETACHED"       :
6880                 msg.k.event_code == KEV_DL_LINK_ADDRESS_CHANGED ? "KEV_DL_LINK_ADDRESS_CHANGED" :
6881                 msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED    ? "KEV_DL_WAKEFLAGS_CHANGED"    :
6882                 msg.k.event_code == KEV_DL_IF_IDLE_ROUTE_REFCNT ? "KEV_DL_IF_IDLE_ROUTE_REFCNT" :
6883                 msg.k.event_code == KEV_DL_IFCAP_CHANGED        ? "KEV_DL_IFCAP_CHANGED"        :
6884                 msg.k.event_code == KEV_DL_LINK_QUALITY_METRIC_CHANGED    ? "KEV_DL_LINK_QUALITY_METRIC_CHANGED"    :
6885                 msg.k.event_code == KEV_DL_NODE_PRESENCE        ? "KEV_DL_NODE_PRESENCE"        :
6886                 msg.k.event_code == KEV_DL_NODE_ABSENCE         ? "KEV_DL_NODE_ABSENCE"         :
6887                 msg.k.event_code == KEV_DL_MASTER_ELECTED       ? "KEV_DL_MASTER_ELECTED"       :
6888                  "?");
6889 
6890         if (msg.k.event_code == KEV_DL_NODE_PRESENCE)
6891             nodePresence((struct kev_dl_node_presence *) &msg.k.event_data);
6892 
6893         if (msg.k.event_code == KEV_DL_NODE_ABSENCE)
6894             nodeAbsence((struct kev_dl_node_absence *) &msg.k.event_data);
6895 
6896         if (msg.k.event_code == KEV_DL_MASTER_ELECTED)
6897             newMasterElected((struct net_event_data *) &msg.k.event_data);
6898 
6899         // We receive network change notifications both through configd and through SYSPROTO_EVENT socket.
6900         // Configd may not generate network change events for manually configured interfaces (i.e., non-DHCP)
6901         // always during sleep/wakeup due to some race conditions (See radar:8666757). At the same time, if
6902         // "Wake on Network Access" is not turned on, the notification will not have KEV_DL_WAKEFLAGS_CHANGED.
6903         // Hence, during wake up, if we see a KEV_DL_LINK_ON (i.e., link is UP), we trigger a network change.
6904 
6905         if (msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED || msg.k.event_code == KEV_DL_LINK_ON)
6906             SetNetworkChanged(mDNSPlatformOneSecond * 2);
6907 
6908 #if TARGET_OS_OSX
6909         // For p2p interfaces, need to open the advertised service port in the firewall.
6910         if (msg.k.event_code == KEV_DL_IF_ATTACHED)
6911         {
6912             struct net_event_data   * p;
6913             p = (struct net_event_data *) &msg.k.event_data;
6914 
6915             if (strncmp(p->if_name, "p2p", 3) == 0)
6916             {
6917                 char ifname[IFNAMSIZ];
6918                 snprintf(ifname, IFNAMSIZ, "%s%d", p->if_name, p->if_unit);
6919 
6920                 LogInfo("SysEventCallBack: KEV_DL_IF_ATTACHED if_family = %d, if_unit = %d, if_name = %s", p->if_family, p->if_unit, p->if_name);
6921 
6922                 mDNSSetPacketFilterRules(ifname, NULL);
6923             }
6924         }
6925 
6926         // For p2p interfaces, need to clear the firewall rules on interface detach
6927         if (msg.k.event_code == KEV_DL_IF_DETACHED)
6928         {
6929             struct net_event_data   * p;
6930             p = (struct net_event_data *) &msg.k.event_data;
6931 
6932             if (strncmp(p->if_name, "p2p", 3) == 0)
6933             {
6934                 pfArray_t portArray, protocolArray; // not initialized since count is 0 for PF_CLEAR_RULES
6935                 char ifname[IFNAMSIZ];
6936                 snprintf(ifname, IFNAMSIZ, "%s%d", p->if_name, p->if_unit);
6937 
6938                 LogInfo("SysEventCallBack: KEV_DL_IF_DETACHED if_family = %d, if_unit = %d, if_name = %s", p->if_family, p->if_unit, p->if_name);
6939 
6940                 mDNSPacketFilterControl(PF_CLEAR_RULES, ifname, 0, portArray, protocolArray);
6941             }
6942         }
6943 #endif
6944     }
6945 
6946     mDNS_Unlock(m);
6947 }
6948 
WatchForSysEvents(mDNS * const m)6949 mDNSlocal mStatus WatchForSysEvents(mDNS *const m)
6950 {
6951     m->p->SysEventNotifier = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
6952     if (m->p->SysEventNotifier < 0)
6953     { LogMsg("WatchForSysEvents: socket failed error %d errno %d (%s)", m->p->SysEventNotifier, errno, strerror(errno)); return(mStatus_NoMemoryErr); }
6954 
6955     struct kev_request kev_req = { KEV_VENDOR_APPLE, KEV_NETWORK_CLASS, KEV_DL_SUBCLASS };
6956     int err = ioctl(m->p->SysEventNotifier, SIOCSKEVFILT, &kev_req);
6957     if (err < 0)
6958     {
6959         LogMsg("WatchForSysEvents: SIOCSKEVFILT failed error %d errno %d (%s)", err, errno, strerror(errno));
6960         close(m->p->SysEventNotifier);
6961         m->p->SysEventNotifier = -1;
6962         return(mStatus_UnknownErr);
6963     }
6964 
6965     m->p->SysEventKQueue.KQcallback = SysEventCallBack;
6966     m->p->SysEventKQueue.KQcontext  = m;
6967     m->p->SysEventKQueue.KQtask     = "System Event Notifier";
6968     KQueueSet(m->p->SysEventNotifier, EV_ADD, EVFILT_READ, &m->p->SysEventKQueue);
6969 
6970     return(mStatus_NoError);
6971 }
6972 
6973 #ifndef NO_SECURITYFRAMEWORK
KeychainChanged(SecKeychainEvent keychainEvent,SecKeychainCallbackInfo * info,void * context)6974 mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCallbackInfo *info, void *context)
6975 {
6976     LogInfo("***   Keychain Changed   ***");
6977     mDNS *const m = (mDNS *const)context;
6978     SecKeychainRef skc;
6979     OSStatus err = SecKeychainCopyDefault(&skc);
6980     if (!err)
6981     {
6982         if (info->keychain == skc)
6983         {
6984             // For delete events, attempt to verify what item was deleted fail because the item is already gone, so we just assume they may be relevant
6985             mDNSBool relevant = (keychainEvent == kSecDeleteEvent);
6986             if (!relevant)
6987             {
6988                 UInt32 tags[3] = { kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr };
6989                 SecKeychainAttributeInfo attrInfo = { 3, tags, NULL };  // Count, array of tags, array of formats
6990                 SecKeychainAttributeList *a = NULL;
6991                 err = SecKeychainItemCopyAttributesAndData(info->item, &attrInfo, NULL, &a, NULL, NULL);
6992                 if (!err)
6993                 {
6994                     relevant = ((a->attr[0].length == 4 && (!strncasecmp(a->attr[0].data, "ddns", 4) || !strncasecmp(a->attr[0].data, "sndd", 4))) ||
6995                                 (a->attr[1].length >= mDNSPlatformStrLen(dnsprefix) && (!strncasecmp(a->attr[1].data, dnsprefix, mDNSPlatformStrLen(dnsprefix)))));
6996                     SecKeychainItemFreeAttributesAndData(a, NULL);
6997                 }
6998             }
6999             if (relevant)
7000             {
7001                 LogInfo("***   Keychain Changed   *** KeychainEvent=%d %s",
7002                         keychainEvent,
7003                         keychainEvent == kSecAddEvent    ? "kSecAddEvent"    :
7004                         keychainEvent == kSecDeleteEvent ? "kSecDeleteEvent" :
7005                         keychainEvent == kSecUpdateEvent ? "kSecUpdateEvent" : "<Unknown>");
7006                 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
7007                 KQueueLock();
7008                 mDNS_Lock(m);
7009 
7010                 // To not read the keychain twice: when BTMM is enabled, changes happen to the keychain
7011                 // then the BTMM DynStore dictionary, so delay reading the keychain for a second.
7012                 // NetworkChanged() will reset the keychain timer to fire immediately when the DynStore changes.
7013                 //
7014                 // In the "fixup" case where the BTMM DNS servers aren't accepting the key mDNSResponder has,
7015                 // the DynStore dictionary won't change (because the BTMM zone won't change).  In that case,
7016                 // a one second delay is ok, as we'll still converge to correctness, and there's no race
7017                 // condition between the RegistrationDomain and the DomainAuthInfo.
7018                 //
7019                 // Lastly, non-BTMM WAB cases can use the keychain but not the DynStore, so we need to set
7020                 // the timer here, as it will not get set by NetworkChanged().
7021                 SetKeyChainTimer(mDNSPlatformOneSecond);
7022 
7023                 mDNS_Unlock(m);
7024                 KQueueUnlock("KeychainChanged");
7025             }
7026         }
7027         CFRelease(skc);
7028     }
7029 
7030     return 0;
7031 }
7032 #endif
7033 
PowerOn(mDNS * const m)7034 mDNSlocal void PowerOn(mDNS *const m)
7035 {
7036     mDNSCoreMachineSleep(m, false);     // Will set m->SleepState = SleepState_Awake;
7037 
7038     if (m->p->WakeAtUTC)
7039     {
7040         long utc = mDNSPlatformUTC();
7041         mDNSPowerRequest(-1,-1);        // Need to explicitly clear any previous power requests -- they're not cleared automatically on wake
7042         if (m->p->WakeAtUTC - utc > 30)
7043         {
7044             LogSPS("PowerChanged PowerOn %d seconds early, assuming not maintenance wake", m->p->WakeAtUTC - utc);
7045         }
7046         else if (utc - m->p->WakeAtUTC > 30)
7047         {
7048             LogSPS("PowerChanged PowerOn %d seconds late, assuming not maintenance wake", utc - m->p->WakeAtUTC);
7049         }
7050         else if (IsAppleTV())
7051         {
7052             LogSPS("PowerChanged PowerOn %d seconds late, device is an AppleTV running iOS so not re-sleeping", utc - m->p->WakeAtUTC);
7053         }
7054         else
7055         {
7056             LogSPS("PowerChanged: Waking for network maintenance operations %d seconds early; re-sleeping in 20 seconds", m->p->WakeAtUTC - utc);
7057             m->p->RequestReSleep = mDNS_TimeNow(m) + 20 * mDNSPlatformOneSecond;
7058         }
7059     }
7060 
7061     // Hold on to a sleep assertion to allow mDNSResponder to perform its maintenance activities.
7062     // This allows for the network link to come up, DHCP to get an address, mDNS to issue queries etc.
7063     // We will clear this assertion as soon as we think the mainenance activities are done.
7064     mDNSPlatformPreventSleep(DARK_WAKE_TIME, "mDNSResponder:maintenance");
7065 
7066 }
7067 
PowerChanged(void * refcon,io_service_t service,natural_t messageType,void * messageArgument)7068 mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
7069 {
7070     mDNS *const m = (mDNS *const)refcon;
7071     KQueueLock();
7072     (void)service;    // Parameter not used
7073     debugf("PowerChanged %X %lX", messageType, messageArgument);
7074 
7075     // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
7076     m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
7077 
7078     switch(messageType)
7079     {
7080     case kIOMessageCanSystemPowerOff:       LogSPS("PowerChanged kIOMessageCanSystemPowerOff     (no action)"); break;          // E0000240
7081     case kIOMessageSystemWillPowerOff:      LogSPS("PowerChanged kIOMessageSystemWillPowerOff");                                // E0000250
7082         mDNSCoreMachineSleep(m, true);
7083         if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged();
7084         break;
7085     case kIOMessageSystemWillNotPowerOff:   LogSPS("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break;          // E0000260
7086     case kIOMessageCanSystemSleep:          LogSPS("PowerChanged kIOMessageCanSystemSleep");                    break;          // E0000270
7087     case kIOMessageSystemWillSleep:         LogSPS("PowerChanged kIOMessageSystemWillSleep");                                   // E0000280
7088         mDNSCoreMachineSleep(m, true);
7089         break;
7090     case kIOMessageSystemWillNotSleep:      LogSPS("PowerChanged kIOMessageSystemWillNotSleep    (no action)"); break;          // E0000290
7091     case kIOMessageSystemHasPoweredOn:      LogSPS("PowerChanged kIOMessageSystemHasPoweredOn");                                // E0000300
7092         // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
7093         if (m->SleepState)
7094         {
7095             LogMsg("PowerChanged kIOMessageSystemHasPoweredOn: ERROR m->SleepState %d", m->SleepState);
7096             PowerOn(m);
7097         }
7098         // Just to be safe, schedule a mDNSMacOSXNetworkChanged(), in case we never received
7099         // the System Configuration Framework "network changed" event that we expect
7100         // to receive some time shortly after the kIOMessageSystemWillPowerOn message
7101         mDNS_Lock(m);
7102         SetNetworkChanged(mDNSPlatformOneSecond * 2);
7103         mDNS_Unlock(m);
7104 
7105         break;
7106     case kIOMessageSystemWillRestart:       LogSPS("PowerChanged kIOMessageSystemWillRestart     (no action)"); break;          // E0000310
7107     case kIOMessageSystemWillPowerOn:       LogSPS("PowerChanged kIOMessageSystemWillPowerOn");                                 // E0000320
7108 
7109         // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
7110         if (m->SleepState != SleepState_Sleeping)
7111         {
7112             LogMsg("kIOMessageSystemWillPowerOn: ERROR m->SleepState %d", m->SleepState);
7113             m->SleepState = SleepState_Sleeping;
7114             mDNSMacOSXNetworkChanged();
7115         }
7116         PowerOn(m);
7117         break;
7118     default:                                LogSPS("PowerChanged unknown message %X", messageType); break;
7119     }
7120 
7121     if (messageType == kIOMessageSystemWillSleep)
7122         m->p->SleepCookie = (long)messageArgument;
7123     else if (messageType == kIOMessageCanSystemSleep)
7124         IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
7125 
7126     KQueueUnlock("PowerChanged Sleep/Wake");
7127 }
7128 
7129 // iPhone OS doesn't currently have SnowLeopard's IO Power Management
7130 // but it does define kIOPMAcknowledgmentOptionSystemCapabilityRequirements
7131 #if defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) && TARGET_OS_OSX
SnowLeopardPowerChanged(void * refcon,IOPMConnection connection,IOPMConnectionMessageToken token,IOPMSystemPowerStateCapabilities eventDescriptor)7132 mDNSlocal void SnowLeopardPowerChanged(void *refcon, IOPMConnection connection, IOPMConnectionMessageToken token, IOPMSystemPowerStateCapabilities eventDescriptor)
7133 {
7134     mDNS *const m = (mDNS *const)refcon;
7135     KQueueLock();
7136     LogSPS("SnowLeopardPowerChanged %X %X %X%s%s%s%s%s",
7137            connection, token, eventDescriptor,
7138            eventDescriptor & kIOPMSystemPowerStateCapabilityCPU     ? " CPU"     : "",
7139            eventDescriptor & kIOPMSystemPowerStateCapabilityVideo   ? " Video"   : "",
7140            eventDescriptor & kIOPMSystemPowerStateCapabilityAudio   ? " Audio"   : "",
7141            eventDescriptor & kIOPMSystemPowerStateCapabilityNetwork ? " Network" : "",
7142            eventDescriptor & kIOPMSystemPowerStateCapabilityDisk    ? " Disk"    : "");
7143 
7144     // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
7145     m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
7146 
7147     if (eventDescriptor & kIOPMSystemPowerStateCapabilityCPU)
7148     {
7149         // We might be in Sleeping or Transferring state. When we go from "wakeup" to "sleep" state, we don't
7150         // go directly to sleep state, but transfer in to the sleep state during which SleepState is set to
7151         // SleepState_Transferring. During that time, we might get another wakeup before we transition to Sleeping
7152         // state. In that case, we need to acknowledge the previous "sleep" before we acknowledge the wakeup.
7153         if (m->SleepLimit)
7154         {
7155             LogSPS("SnowLeopardPowerChanged: Waking up, Acking old Sleep, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
7156             IOPMConnectionAcknowledgeEvent(connection, (IOPMConnectionMessageToken)m->p->SleepCookie);
7157             m->SleepLimit = 0;
7158         }
7159         LogSPS("SnowLeopardPowerChanged: Waking up, Acking Wakeup, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
7160         // CPU Waking. Note: Can get this message repeatedly, as other subsystems power up or down.
7161         if (m->SleepState != SleepState_Awake)
7162         {
7163             PowerOn(m);
7164             // If the network notifications have already come before we got the wakeup, we ignored them and
7165             // in case we get no more, we need to trigger one.
7166             mDNS_Lock(m);
7167             SetNetworkChanged(mDNSPlatformOneSecond * 2);
7168             mDNS_Unlock(m);
7169         }
7170         IOPMConnectionAcknowledgeEvent(connection, token);
7171     }
7172     else
7173     {
7174         // CPU sleeping. Should not get this repeatedly -- once we're told that the CPU is halting
7175         // we should hear nothing more until we're told that the CPU has started executing again.
7176         if (m->SleepState) LogMsg("SnowLeopardPowerChanged: Sleep Error %X m->SleepState %d", eventDescriptor, m->SleepState);
7177         //sleep(5);
7178         //mDNSMacOSXNetworkChanged(m);
7179         mDNSCoreMachineSleep(m, true);
7180         //if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
7181         m->p->SleepCookie = token;
7182     }
7183 
7184     KQueueUnlock("SnowLeopardPowerChanged Sleep/Wake");
7185 }
7186 #endif
7187 
7188 #if COMPILER_LIKES_PRAGMA_MARK
7189 #pragma mark -
7190 #pragma mark - /etc/hosts support
7191 #endif
7192 
7193 // Implementation Notes
7194 //
7195 // As /etc/hosts file can be huge (1000s of entries - when this comment was written, the test file had about
7196 // 23000 entries with about 4000 duplicates), we can't use a linked list to store these entries. So, we parse
7197 // them into a hash table. The implementation need to be able to do the following things efficiently
7198 //
7199 // 1. Detect duplicates e.g., two entries with "1.2.3.4 foo"
7200 // 2. Detect whether /etc/hosts has changed and what has changed since the last read from the disk
7201 // 3. Ability to support multiple addresses per name e.g., "1.2.3.4 foo, 2.3.4.5 foo". To support this, we
7202 //    need to be able set the RRSet of a resource record to the first one in the list and also update when
7203 //    one of them go away. This is needed so that the core thinks that they are all part of the same RRSet and
7204 //    not a duplicate
7205 // 4. Don't maintain any local state about any records registered with the core to detect changes to /etc/hosts
7206 //
7207 // CFDictionary is not a suitable candidate because it does not support duplicates and even if we use a custom
7208 // "hash" function to solve this, the others are hard to solve. Hence, we share the hash (AuthHash) implementation
7209 // of the core layer which does all of the above very efficiently
7210 
7211 #define ETCHOSTS_BUFSIZE    1024    // Buffer size to parse a single line in /etc/hosts
7212 
FreeEtcHosts(mDNS * const m,AuthRecord * const rr,mStatus result)7213 mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result)
7214 {
7215     (void)m;  // unused
7216     (void)rr;
7217     (void)result;
7218     if (result == mStatus_MemFree)
7219     {
7220         LogInfo("FreeEtcHosts: %s", ARDisplayString(m, rr));
7221         freeL("etchosts", rr);
7222     }
7223 }
7224 
7225 // Returns true on success and false on failure
mDNSMacOSXCreateEtcHostsEntry(const domainname * domain,const struct sockaddr * sa,const domainname * cname,char * ifname,AuthHash * auth)7226 mDNSlocal mDNSBool mDNSMacOSXCreateEtcHostsEntry(const domainname *domain, const struct sockaddr *sa, const domainname *cname, char *ifname, AuthHash *auth)
7227 {
7228     AuthRecord *rr;
7229     mDNSu32 namehash;
7230     AuthGroup *ag;
7231     mDNSInterfaceID InterfaceID = mDNSInterface_LocalOnly;
7232     mDNSu16 rrtype;
7233 
7234     if (!domain)
7235     {
7236         LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! name NULL");
7237         return mDNSfalse;
7238     }
7239     if (!sa && !cname)
7240     {
7241         LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa and cname both NULL");
7242         return mDNSfalse;
7243     }
7244 
7245     if (sa && sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
7246     {
7247         LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa with bad family %d", sa->sa_family);
7248         return mDNSfalse;
7249     }
7250 
7251 
7252     if (ifname)
7253     {
7254         mDNSu32 ifindex = if_nametoindex(ifname);
7255         if (!ifindex)
7256         {
7257             LogMsg("mDNSMacOSXCreateEtcHostsEntry: hosts entry %##s with invalid ifname %s", domain->c, ifname);
7258             return mDNSfalse;
7259         }
7260         InterfaceID = (mDNSInterfaceID)(uintptr_t)ifindex;
7261     }
7262 
7263     if (sa)
7264         rrtype = (sa->sa_family == AF_INET ? kDNSType_A : kDNSType_AAAA);
7265     else
7266         rrtype = kDNSType_CNAME;
7267 
7268     // Check for duplicates. See whether we parsed an entry before like this ?
7269     namehash = DomainNameHashValue(domain);
7270     ag = AuthGroupForName(auth, namehash, domain);
7271     if (ag)
7272     {
7273         rr = ag->members;
7274         while (rr)
7275         {
7276             if (rr->resrec.rrtype == rrtype)
7277             {
7278                 if (rrtype == kDNSType_A)
7279                 {
7280                     mDNSv4Addr ip;
7281                     ip.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr;
7282                     if (mDNSSameIPv4Address(rr->resrec.rdata->u.ipv4, ip) && InterfaceID == rr->resrec.InterfaceID)
7283                     {
7284                         LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv4 address and InterfaceID for name %##s ID %d", domain->c, IIDPrintable(InterfaceID));
7285                         return mDNSfalse;
7286                     }
7287                 }
7288                 else if (rrtype == kDNSType_AAAA)
7289                 {
7290                     mDNSv6Addr ip6;
7291                     ip6.l[0] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[0];
7292                     ip6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1];
7293                     ip6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2];
7294                     ip6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3];
7295                     if (mDNSSameIPv6Address(rr->resrec.rdata->u.ipv6, ip6) && InterfaceID == rr->resrec.InterfaceID)
7296                     {
7297                         LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv6 address and InterfaceID for name %##s ID %d", domain->c, IIDPrintable(InterfaceID));
7298                         return mDNSfalse;
7299                     }
7300                 }
7301                 else if (rrtype == kDNSType_CNAME)
7302                 {
7303                     if (SameDomainName(&rr->resrec.rdata->u.name, cname))
7304                     {
7305                         LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same cname %##s for name %##s", cname->c, domain->c);
7306                         return mDNSfalse;
7307                     }
7308                 }
7309             }
7310             rr = rr->next;
7311         }
7312     }
7313     rr = (AuthRecord *) callocL("etchosts", sizeof(*rr));
7314     if (rr == NULL) return mDNSfalse;
7315     mDNS_SetupResourceRecord(rr, NULL, InterfaceID, rrtype, 1, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, FreeEtcHosts, NULL);
7316     AssignDomainName(&rr->namestorage, domain);
7317 
7318     if (sa)
7319     {
7320         rr->resrec.rdlength = sa->sa_family == AF_INET ? sizeof(mDNSv4Addr) : sizeof(mDNSv6Addr);
7321         if (sa->sa_family == AF_INET)
7322             rr->resrec.rdata->u.ipv4.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr;
7323         else
7324         {
7325             rr->resrec.rdata->u.ipv6.l[0] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[0];
7326             rr->resrec.rdata->u.ipv6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1];
7327             rr->resrec.rdata->u.ipv6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2];
7328             rr->resrec.rdata->u.ipv6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3];
7329         }
7330     }
7331     else
7332     {
7333         rr->resrec.rdlength = DomainNameLength(cname);
7334         rr->resrec.rdata->u.name.c[0] = 0;
7335         AssignDomainName(&rr->resrec.rdata->u.name, cname);
7336     }
7337     rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
7338     SetNewRData(&rr->resrec, mDNSNULL, 0);  // Sets rr->rdatahash for us
7339     LogInfo("mDNSMacOSXCreateEtcHostsEntry: Adding resource record %s ID %d", ARDisplayString(&mDNSStorage, rr), IIDPrintable(rr->resrec.InterfaceID));
7340     InsertAuthRecord(&mDNSStorage, auth, rr);
7341     return mDNStrue;
7342 }
7343 
EtcHostsParseOneName(int start,int length,char * buffer,char ** name)7344 mDNSlocal int EtcHostsParseOneName(int start, int length, char *buffer, char **name)
7345 {
7346     int i;
7347 
7348     *name = NULL;
7349     for (i = start; i < length; i++)
7350     {
7351         if (buffer[i] == '#')
7352             return -1;
7353         if (buffer[i] != ' ' && buffer[i] != ',' && buffer[i] != '\t')
7354         {
7355             *name = &buffer[i];
7356 
7357             // Found the start of a name, find the end and null terminate
7358             for (i++; i < length; i++)
7359             {
7360                 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t')
7361                 {
7362                     buffer[i] = 0;
7363                     break;
7364                 }
7365             }
7366             return i;
7367         }
7368     }
7369     return -1;
7370 }
7371 
mDNSMacOSXParseEtcHostsLine(char * buffer,int length,AuthHash * auth)7372 mDNSlocal void mDNSMacOSXParseEtcHostsLine(char *buffer, int length, AuthHash *auth)
7373 {
7374     int i;
7375     int ifStart = 0;
7376     char *ifname = NULL;
7377     domainname name1d;
7378     domainname name2d;
7379     char *name1;
7380     char *name2;
7381     int aliasIndex;
7382 
7383     //Ignore leading whitespaces and tabs
7384     while (*buffer == ' ' || *buffer == '\t')
7385     {
7386         buffer++;
7387         length--;
7388     }
7389 
7390     // Find the end of the address string
7391     for (i = 0; i < length; i++)
7392     {
7393         if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t' || buffer[i] == '%')
7394         {
7395             if (buffer[i] == '%')
7396                 ifStart = i + 1;
7397             buffer[i] = 0;
7398             break;
7399         }
7400     }
7401 
7402     // Convert the address string to an address
7403     struct addrinfo hints;
7404     bzero(&hints, sizeof(hints));
7405     hints.ai_flags = AI_NUMERICHOST;
7406     struct addrinfo *gairesults = NULL;
7407     if (getaddrinfo(buffer, NULL, &hints, &gairesults) != 0)
7408     {
7409         LogInfo("mDNSMacOSXParseEtcHostsLine: getaddrinfo returning null");
7410         return;
7411     }
7412 
7413     if (ifStart)
7414     {
7415         // Parse the interface
7416         ifname = &buffer[ifStart];
7417         for (i = ifStart + 1; i < length; i++)
7418         {
7419             if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t')
7420             {
7421                 buffer[i] = 0;
7422                 break;
7423             }
7424         }
7425     }
7426 
7427     i = EtcHostsParseOneName(i + 1, length, buffer, &name1);
7428     if (i == length)
7429     {
7430         // Common case (no aliases) : The entry is of the form "1.2.3.4 somehost" with no trailing white spaces/tabs etc.
7431         if (!MakeDomainNameFromDNSNameString(&name1d, name1))
7432         {
7433             LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1);
7434             freeaddrinfo(gairesults);
7435             return;
7436         }
7437         mDNSMacOSXCreateEtcHostsEntry(&name1d, gairesults->ai_addr, mDNSNULL, ifname, auth);
7438     }
7439     else if (i != -1)
7440     {
7441         domainname first;
7442         // We might have some extra white spaces at the end for the common case of "1.2.3.4 somehost".
7443         // When we parse again below, EtchHostsParseOneName would return -1 and we will end up
7444         // doing the right thing.
7445 
7446         if (!MakeDomainNameFromDNSNameString(&first, name1))
7447         {
7448             LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1);
7449             freeaddrinfo(gairesults);
7450             return;
7451         }
7452         mDNSMacOSXCreateEtcHostsEntry(&first, gairesults->ai_addr, mDNSNULL, ifname, auth);
7453 
7454         // /etc/hosts alias discussion:
7455         //
7456         // If the /etc/hosts has an entry like this
7457         //
7458         //  ip_address cname [aliases...]
7459         //  1.2.3.4    sun    star    bright
7460         //
7461         // star and bright are aliases (gethostbyname h_alias should point to these) and sun is the canonical
7462         // name (getaddrinfo ai_cannonname and gethostbyname h_name points to "sun")
7463         //
7464         // To achieve this, we need to add the entry like this:
7465         //
7466         // sun A 1.2.3.4
7467         // star CNAME sun
7468         // bright CNAME sun
7469         //
7470         // We store the first name we parsed in "first" and add the address (A/AAAA) record.
7471         // Then we parse additional names adding CNAME records till we reach the end.
7472 
7473         aliasIndex = 0;
7474         while (i < length)
7475         {
7476             // Continue to parse additional aliases until we reach end of the line and
7477             // for each "alias" parsed, add a CNAME record where "alias" points to the first "name".
7478             // See also /etc/hosts alias discussion above
7479 
7480             i = EtcHostsParseOneName(i + 1, length, buffer, &name2);
7481 
7482             if (name2)
7483             {
7484                 if ((aliasIndex) && (*buffer == *name2))
7485                     break; // break out of the loop if we wrap around
7486 
7487                 if (!MakeDomainNameFromDNSNameString(&name2d, name2))
7488                 {
7489                     LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name2);
7490                     freeaddrinfo(gairesults);
7491                     return;
7492                 }
7493                 // Ignore if it points to itself
7494                 if (!SameDomainName(&first, &name2d))
7495                 {
7496                     if (!mDNSMacOSXCreateEtcHostsEntry(&name2d, mDNSNULL, &first, ifname, auth))
7497                     {
7498                         freeaddrinfo(gairesults);
7499                         return;
7500                     }
7501                 }
7502                 else
7503                 {
7504                     LogInfo("mDNSMacOSXParseEtcHostsLine: Ignoring entry with same names first %##s, name2 %##s", first.c, name2d.c);
7505                 }
7506                 aliasIndex++;
7507             }
7508             else if (!aliasIndex)
7509             {
7510                 // We have never parsed any aliases. This case happens if there
7511                 // is just one name and some extra white spaces at the end.
7512                 LogInfo("mDNSMacOSXParseEtcHostsLine: White space at the end of %##s", first.c);
7513                 break;
7514             }
7515         }
7516     }
7517     freeaddrinfo(gairesults);
7518 }
7519 
mDNSMacOSXParseEtcHosts(int fd,AuthHash * auth)7520 mDNSlocal void mDNSMacOSXParseEtcHosts(int fd, AuthHash *auth)
7521 {
7522     mDNSBool good;
7523     char buf[ETCHOSTS_BUFSIZE];
7524     size_t len;
7525     FILE *fp;
7526 
7527     if (fd == -1) { LogInfo("mDNSMacOSXParseEtcHosts: fd is -1"); return; }
7528 
7529     fp = fopen("/etc/hosts", "r");
7530     if (!fp) { LogInfo("mDNSMacOSXParseEtcHosts: fp is NULL"); return; }
7531 
7532     while (1)
7533     {
7534         good = (fgets(buf, ETCHOSTS_BUFSIZE, fp) != NULL);
7535         if (!good) break;
7536 
7537         // skip comment and empty lines
7538         if (buf[0] == '#' || buf[0] == '\r' || buf[0] == '\n')
7539             continue;
7540 
7541         len = strlen(buf);
7542         if (!len) break;    // sanity check
7543         //Check for end of line code(mostly only \n but pre-OS X Macs could have only \r)
7544         if (buf[len - 1] == '\r' || buf[len - 1] == '\n')
7545         {
7546             buf[len - 1] = '\0';
7547             len = len - 1;
7548         }
7549         // fgets always null terminates and hence even if we have no
7550         // newline at the end, it is null terminated. The callee
7551         // (mDNSMacOSXParseEtcHostsLine) expects the length to be such that
7552         // buf[length] is zero and hence we decrement len to reflect that.
7553         if (len)
7554         {
7555             //Additional check when end of line code is 2 chars ie\r\n(DOS, other old OSes)
7556             //here we need to check for just \r but taking extra caution.
7557             if (buf[len - 1] == '\r' || buf[len - 1] == '\n')
7558             {
7559                 buf[len - 1] = '\0';
7560                 len = len - 1;
7561             }
7562         }
7563         if (!len) //Sanity Check: len should never be zero
7564         {
7565             LogMsg("mDNSMacOSXParseEtcHosts: Length is zero!");
7566             continue;
7567         }
7568         mDNSMacOSXParseEtcHostsLine(buf, (int)len, auth);
7569     }
7570     fclose(fp);
7571 }
7572 
7573 mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m);
7574 
mDNSMacOSXGetEtcHostsFD(void)7575 mDNSlocal int mDNSMacOSXGetEtcHostsFD(void)
7576 {
7577     mDNS *const m = &mDNSStorage;
7578 #ifdef __DISPATCH_GROUP__
7579     // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
7580     static dispatch_queue_t etcq     = 0;
7581     static dispatch_source_t etcsrc   = 0;
7582     static dispatch_source_t hostssrc = 0;
7583 
7584     // First time through? just schedule ourselves on the main queue and we'll do the work later
7585     if (!etcq)
7586     {
7587         etcq = dispatch_get_main_queue();
7588         if (etcq)
7589         {
7590             // Do this work on the queue, not here - solves potential synchronization issues
7591             dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
7592         }
7593         return -1;
7594     }
7595 
7596     if (hostssrc) return (int)dispatch_source_get_handle(hostssrc);
7597 #endif
7598 
7599     int fd = open("/etc/hosts", O_RDONLY);
7600 
7601 #ifdef __DISPATCH_GROUP__
7602     // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
7603     if (fd == -1)
7604     {
7605         // If the open failed and we're already watching /etc, we're done
7606         if (etcsrc) { LogInfo("mDNSMacOSXGetEtcHostsFD: Returning etcfd because no etchosts"); return fd; }
7607 
7608         // we aren't watching /etc, we should be
7609         fd = open("/etc", O_RDONLY);
7610         if (fd == -1) { LogInfo("mDNSMacOSXGetEtcHostsFD: etc does not exist"); return -1; }
7611         etcsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_RENAME, etcq);
7612         if (etcsrc == NULL)
7613         {
7614             close(fd);
7615             return -1;
7616         }
7617         dispatch_source_set_event_handler(etcsrc,
7618                                           ^{
7619                                               const unsigned long flags = dispatch_source_get_data(etcsrc);
7620                                               LogMsg("mDNSMacOSXGetEtcHostsFD: /etc changed 0x%x", flags);
7621                                               if ((flags & (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME)) != 0)
7622                                               {
7623                                                   dispatch_source_cancel(etcsrc);
7624                                                   dispatch_release(etcsrc);
7625                                                   etcsrc = NULL;
7626                                                   dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
7627                                                   return;
7628                                               }
7629                                               if ((flags & DISPATCH_VNODE_WRITE) != 0 && hostssrc == NULL)
7630                                               {
7631                                                   mDNSMacOSXUpdateEtcHosts(m);
7632                                               }
7633                                           });
7634         dispatch_source_set_cancel_handler(etcsrc, ^{close(fd);});
7635         dispatch_resume(etcsrc);
7636 
7637         // Try and open /etc/hosts once more now that we're watching /etc, in case we missed the creation
7638         fd = open("/etc/hosts", O_RDONLY | O_EVTONLY);
7639         if (fd == -1) { LogMsg("mDNSMacOSXGetEtcHostsFD etc hosts does not exist, watching etc"); return -1; }
7640     }
7641 
7642     // create a dispatch source to watch for changes to hosts file
7643     hostssrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd,
7644                                       (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_RENAME |
7645                                        DISPATCH_VNODE_ATTRIB | DISPATCH_VNODE_EXTEND | DISPATCH_VNODE_LINK | DISPATCH_VNODE_REVOKE), etcq);
7646     if (hostssrc == NULL)
7647     {
7648         close(fd);
7649         return -1;
7650     }
7651     dispatch_source_set_event_handler(hostssrc,
7652                                       ^{
7653                                           const unsigned long flags = dispatch_source_get_data(hostssrc);
7654                                           LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts changed 0x%x", flags);
7655                                           if ((flags & (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME)) != 0)
7656                                           {
7657                                               dispatch_source_cancel(hostssrc);
7658                                               dispatch_release(hostssrc);
7659                                               hostssrc = NULL;
7660                                               // Bug in LibDispatch: wait a second before scheduling the block. If we schedule
7661                                               // the block immediately, we try to open the file and the file may not exist and may
7662                                               // fail to get a notification in the future. When the file does not exist and
7663                                               // we start to monitor the directory, on "dispatch_resume" of that source, there
7664                                               // is no guarantee that the file creation will be notified always because when
7665                                               // the dispatch_resume returns, the kevent manager may not have registered the
7666                                               // kevent yet but the file may have been created
7667                                               usleep(1000000);
7668                                               dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
7669                                               return;
7670                                           }
7671                                           if ((flags & DISPATCH_VNODE_WRITE) != 0)
7672                                           {
7673                                               mDNSMacOSXUpdateEtcHosts(m);
7674                                           }
7675                                       });
7676     dispatch_source_set_cancel_handler(hostssrc, ^{LogInfo("mDNSMacOSXGetEtcHostsFD: Closing etchosts fd %d", fd); close(fd);});
7677     dispatch_resume(hostssrc);
7678 
7679     // Cleanup /etc source, no need to watch it if we already have /etc/hosts
7680     if (etcsrc)
7681     {
7682         dispatch_source_cancel(etcsrc);
7683         dispatch_release(etcsrc);
7684         etcsrc = NULL;
7685     }
7686 
7687     LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts being monitored, and not etc");
7688     return hostssrc ? (int)dispatch_source_get_handle(hostssrc) : -1;
7689 #else
7690     (void)m;
7691     return fd;
7692 #endif
7693 }
7694 
7695 // When /etc/hosts is modified, flush all the cache records as there may be local
7696 // authoritative answers now
FlushAllCacheRecords(mDNS * const m)7697 mDNSlocal void FlushAllCacheRecords(mDNS *const m)
7698 {
7699     CacheRecord *cr;
7700     mDNSu32 slot;
7701     CacheGroup *cg;
7702 
7703     FORALL_CACHERECORDS(slot, cg, cr)
7704     {
7705         // Skip multicast.
7706         if (cr->resrec.InterfaceID) continue;
7707 
7708         // If a resource record can answer A or AAAA, they need to be flushed so that we will
7709         // never used to deliver an ADD or RMV
7710         if (RRTypeAnswersQuestionType(&cr->resrec, kDNSType_A) ||
7711             RRTypeAnswersQuestionType(&cr->resrec, kDNSType_AAAA))
7712         {
7713             LogInfo("FlushAllCacheRecords: Purging Resourcerecord %s", CRDisplayString(m, cr));
7714             mDNS_PurgeCacheResourceRecord(m, cr);
7715         }
7716     }
7717 }
7718 
7719 // Add new entries to the core. If justCheck is set, this function does not add, just returns true
EtcHostsAddNewEntries(AuthHash * newhosts,mDNSBool justCheck)7720 mDNSlocal mDNSBool EtcHostsAddNewEntries(AuthHash *newhosts, mDNSBool justCheck)
7721 {
7722     mDNS *const m = &mDNSStorage;
7723     AuthGroup *ag;
7724     mDNSu32 slot;
7725     AuthRecord *rr, *primary, *rrnext;
7726     for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
7727         for (ag = newhosts->rrauth_hash[slot]; ag; ag = ag->next)
7728         {
7729             primary = NULL;
7730             for (rr = ag->members; rr; rr = rrnext)
7731             {
7732                 rrnext = rr->next;
7733                 AuthGroup *ag1;
7734                 AuthRecord *rr1;
7735                 mDNSBool found = mDNSfalse;
7736                 ag1 = AuthGroupForRecord(&m->rrauth, &rr->resrec);
7737                 if (ag1 && ag1->members)
7738                 {
7739                     if (!primary) primary = ag1->members;
7740                     rr1 = ag1->members;
7741                     while (rr1)
7742                     {
7743                         // We are not using InterfaceID in checking for duplicates. This means,
7744                         // if there are two addresses for a given name e.g., fe80::1%en0 and
7745                         // fe80::1%en1, we only add the first one. It is not clear whether
7746                         // this is a common case. To fix this, we also need to modify
7747                         // mDNS_Register_internal in how it handles duplicates. If it becomes a
7748                         // common case, we will fix it then.
7749                         if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec) && rr1->resrec.InterfaceID == rr->resrec.InterfaceID)
7750                         {
7751                             LogInfo("EtcHostsAddNewEntries: Skipping, not adding %s", ARDisplayString(m, rr1));
7752                             found = mDNStrue;
7753                             break;
7754                         }
7755                         rr1 = rr1->next;
7756                     }
7757                 }
7758                 if (!found)
7759                 {
7760                     if (justCheck)
7761                     {
7762                         LogInfo("EtcHostsAddNewEntries: Entry %s not registered with core yet", ARDisplayString(m, rr));
7763                         return mDNStrue;
7764                     }
7765                     RemoveAuthRecord(m, newhosts, rr);
7766                     // if there is no primary, point to self
7767                     rr->RRSet = (primary ? primary : rr);
7768                     rr->next = NULL;
7769                     LogInfo("EtcHostsAddNewEntries: Adding %s ID %d", ARDisplayString(m, rr), IIDPrintable(rr->resrec.InterfaceID));
7770                     if (mDNS_Register_internal(m, rr) != mStatus_NoError)
7771                         LogMsg("EtcHostsAddNewEntries: mDNS_Register failed for %s", ARDisplayString(m, rr));
7772                 }
7773             }
7774         }
7775     return mDNSfalse;
7776 }
7777 
7778 // Delete entries from the core that are no longer needed. If justCheck is set, this function
7779 // does not delete, just returns true
EtcHostsDeleteOldEntries(AuthHash * newhosts,mDNSBool justCheck)7780 mDNSlocal mDNSBool EtcHostsDeleteOldEntries(AuthHash *newhosts, mDNSBool justCheck)
7781 {
7782     mDNS *const m = &mDNSStorage;
7783     AuthGroup *ag;
7784     mDNSu32 slot;
7785     AuthRecord *rr, *rrnext;
7786     for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
7787         for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next)
7788             for (rr = ag->members; rr; rr = rrnext)
7789             {
7790                 mDNSBool found = mDNSfalse;
7791                 AuthGroup *ag1;
7792                 AuthRecord *rr1;
7793                 rrnext = rr->next;
7794                 if (rr->RecordCallback != FreeEtcHosts) continue;
7795                 ag1 = AuthGroupForRecord(newhosts, &rr->resrec);
7796                 if (ag1)
7797                 {
7798                     rr1 = ag1->members;
7799                     while (rr1)
7800                     {
7801                         if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec))
7802                         {
7803                             LogInfo("EtcHostsDeleteOldEntries: Old record %s found in new, skipping", ARDisplayString(m, rr));
7804                             found = mDNStrue;
7805                             break;
7806                         }
7807                         rr1 = rr1->next;
7808                     }
7809                 }
7810                 // there is no corresponding record in newhosts for the same name. This means
7811                 // we should delete this from the core.
7812                 if (!found)
7813                 {
7814                     if (justCheck)
7815                     {
7816                         LogInfo("EtcHostsDeleteOldEntries: Record %s not found in new, deleting", ARDisplayString(m, rr));
7817                         return mDNStrue;
7818                     }
7819                     // if primary is going away, make sure that the rest of the records
7820                     // point to the new primary
7821                     if (rr == ag->members)
7822                     {
7823                         AuthRecord *new_primary = rr->next;
7824                         AuthRecord *r = new_primary;
7825                         while (r)
7826                         {
7827                             if (r->RRSet == rr)
7828                             {
7829                                 LogInfo("EtcHostsDeleteOldEntries: Updating Resource Record %s to primary", ARDisplayString(m, r));
7830                                 r->RRSet = new_primary;
7831                             }
7832                             else LogMsg("EtcHostsDeleteOldEntries: ERROR!! Resource Record %s not pointing to primary %##s", ARDisplayString(m, r), r->resrec.name);
7833                             r = r->next;
7834                         }
7835                     }
7836                     LogInfo("EtcHostsDeleteOldEntries: Deleting %s", ARDisplayString(m, rr));
7837                     mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
7838                 }
7839             }
7840     return mDNSfalse;
7841 }
7842 
UpdateEtcHosts(mDNS * const m,void * context)7843 mDNSlocal void UpdateEtcHosts(mDNS *const m, void *context)
7844 {
7845     AuthHash *newhosts = (AuthHash *)context;
7846 
7847     mDNS_CheckLock(m);
7848 
7849     //Delete old entries from the core if they are not present in the newhosts
7850     EtcHostsDeleteOldEntries(newhosts, mDNSfalse);
7851     // Add the new entries to the core if not already present in the core
7852     EtcHostsAddNewEntries(newhosts, mDNSfalse);
7853 }
7854 
FreeNewHosts(AuthHash * newhosts)7855 mDNSlocal void FreeNewHosts(AuthHash *newhosts)
7856 {
7857     mDNSu32 slot;
7858     AuthGroup *ag, *agnext;
7859     AuthRecord *rr, *rrnext;
7860 
7861     for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
7862         for (ag = newhosts->rrauth_hash[slot]; ag; ag = agnext)
7863         {
7864             agnext = ag->next;
7865             for (rr = ag->members; rr; rr = rrnext)
7866             {
7867                 rrnext = rr->next;
7868                 freeL("etchosts", rr);
7869             }
7870             freeL("AuthGroups", ag);
7871         }
7872 }
7873 
mDNSMacOSXUpdateEtcHosts(mDNS * const m)7874 mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m)
7875 {
7876     AuthHash newhosts;
7877 
7878     // As we will be modifying the core, we can only have one thread running at
7879     // any point in time.
7880     KQueueLock();
7881 
7882     mDNSPlatformMemZero(&newhosts, sizeof(AuthHash));
7883 
7884     // Get the file desecriptor (will trigger us to start watching for changes)
7885     int fd = mDNSMacOSXGetEtcHostsFD();
7886     if (fd != -1)
7887     {
7888         LogInfo("mDNSMacOSXUpdateEtcHosts: Parsing /etc/hosts fd %d", fd);
7889         mDNSMacOSXParseEtcHosts(fd, &newhosts);
7890     }
7891     else LogInfo("mDNSMacOSXUpdateEtcHosts: /etc/hosts is not present");
7892 
7893     // Optimization: Detect whether /etc/hosts changed or not.
7894     //
7895     // 1. Check to see if there are any new entries. We do this by seeing whether any entries in
7896     //    newhosts is already registered with core.  If we find at least one entry that is not
7897     //    registered with core, then it means we have work to do.
7898     //
7899     // 2. Next, we check to see if any of the entries that are registered with core is not present
7900     //   in newhosts. If we find at least one entry that is not present, it means we have work to
7901     //   do.
7902     //
7903     // Note: We may not have to hold the lock right here as KQueueLock is held which prevents any
7904     // other thread from running. But mDNS_Lock is needed here as we will be traversing the core
7905     // data structure in EtcHostsDeleteOldEntries/NewEntries which might expect the lock to be held
7906     // in the future and this code does not have to change.
7907     mDNS_Lock(m);
7908     // Add the new entries to the core if not already present in the core
7909     if (!EtcHostsAddNewEntries(&newhosts, mDNStrue))
7910     {
7911         // No new entries to add, check to see if we need to delete any old entries from the
7912         // core if they are not present in the newhosts
7913         if (!EtcHostsDeleteOldEntries(&newhosts, mDNStrue))
7914         {
7915             LogInfo("mDNSMacOSXUpdateEtcHosts: No work");
7916             FreeNewHosts(&newhosts);
7917             mDNS_Unlock(m);
7918             KQueueUnlock("/etc/hosts changed");
7919             return;
7920         }
7921     }
7922 
7923     // This will flush the cache, stop and start the query so that the queries
7924     // can look at the /etc/hosts again
7925     //
7926     // Notes:
7927     //
7928     // We can't delete and free the records here. We wait for the mDNSCoreRestartAddressQueries to
7929     // deliver RMV events. It has to be done in a deferred way because we can't deliver RMV
7930     // events for local records *before* the RMV events for cache records. mDNSCoreRestartAddressQueries
7931     // delivers these events in the right order and then calls us back to delete them.
7932     //
7933     // Similarly, we do a deferred Registration of the record because mDNSCoreRestartAddressQueries
7934     // is a common function that looks at all local auth records and delivers a RMV including
7935     // the records that we might add here. If we deliver a ADD here, it will get a RMV and then when
7936     // the query is restarted, it will get another ADD. To avoid this (ADD-RMV-ADD), we defer registering
7937     // the record until the RMVs are delivered in mDNSCoreRestartAddressQueries after which UpdateEtcHosts
7938     // is called back where we do the Registration of the record. This results in RMV followed by ADD which
7939     // looks normal.
7940     mDNSCoreRestartAddressQueries(m, mDNSfalse, FlushAllCacheRecords, UpdateEtcHosts, &newhosts);
7941     FreeNewHosts(&newhosts);
7942     mDNS_Unlock(m);
7943     KQueueUnlock("/etc/hosts changed");
7944 }
7945 
7946 #if COMPILER_LIKES_PRAGMA_MARK
7947 #pragma mark -
7948 #pragma mark - Initialization & Teardown
7949 #endif
7950 
7951 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
7952 CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
7953 CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
7954 CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
7955 
7956 // Major version 13 is 10.9.x
mDNSMacOSXSystemBuildNumber(char * HINFO_SWstring)7957 mDNSexport void mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
7958 {
7959     int major = 0, minor = 0;
7960     char letter = 0, prodname[256]="<Unknown>", prodvers[256]="<Unknown>", buildver[256]="<Unknown>";
7961     CFDictionaryRef vers = _CFCopySystemVersionDictionary();
7962     if (vers)
7963     {
7964         CFStringRef cfprodname = CFDictionaryGetValue(vers, _kCFSystemVersionProductNameKey);
7965         CFStringRef cfprodvers = CFDictionaryGetValue(vers, _kCFSystemVersionProductVersionKey);
7966         CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
7967         if (cfprodname)
7968             CFStringGetCString(cfprodname, prodname, sizeof(prodname), kCFStringEncodingUTF8);
7969         if (cfprodvers)
7970             CFStringGetCString(cfprodvers, prodvers, sizeof(prodvers), kCFStringEncodingUTF8);
7971         if (cfbuildver && CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8))
7972             sscanf(buildver, "%d%c%d", &major, &letter, &minor);
7973         CFRelease(vers);
7974     }
7975     if (!major)
7976     {
7977         major = 13;
7978         LogMsg("Note: No Major Build Version number found; assuming 13");
7979     }
7980     if (HINFO_SWstring)
7981         mDNS_snprintf(HINFO_SWstring, 256, "%s %s (%s), %s", prodname, prodvers, buildver, STRINGIFY(mDNSResponderVersion));
7982     //LogMsg("%s %s (%s), %d %c %d", prodname, prodvers, buildver, major, letter, minor);
7983 
7984     // If product name starts with "M" (case insensitive), thus it the current ProductName attribute "macOS"
7985     // for macOS; or it matches the old ProductName attribute "Mac OS X" for macOS, we set OSXVers, else we set iOSVers.
7986     // Note that "& 0xDF" operation converts prodname[0] to uppercase alphabetic character, do not use it make the ASCII
7987     // character uppercase, since "& 0xDF" will incorrectly change the ASCII characters that are not in the A~Z, a~z
7988     // range. For the detail, go to https://blog.cloudflare.com/the-oldest-trick-in-the-ascii-book/
7989     if ((prodname[0] & 0xDF) == 'M')
7990         OSXVers = major;
7991     else
7992         iOSVers = major;
7993 }
7994 
7995 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
7996 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
7997 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
mDNSPlatformInit_CanReceiveUnicast(void)7998 mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
7999 {
8000     int err = -1;
8001     int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
8002     if (s < 3)
8003         LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s, errno, strerror(errno));
8004     else
8005     {
8006         struct sockaddr_in s5353;
8007         s5353.sin_family      = AF_INET;
8008         s5353.sin_port        = MulticastDNSPort.NotAnInteger;
8009         s5353.sin_addr.s_addr = 0;
8010         err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
8011         close(s);
8012     }
8013 
8014     if (err) LogMsg("No unicast UDP responses");
8015     else debugf("Unicast UDP responses okay");
8016     return(err == 0);
8017 }
8018 
CreatePTRRecord(const domainname * domain)8019 mDNSlocal void CreatePTRRecord(const domainname *domain)
8020 {
8021     AuthRecord *rr;
8022     const domainname *pname = (domainname *)"\x9" "localhost";
8023 
8024     rr = (AuthRecord *) callocL("localhosts", sizeof(*rr));
8025     if (rr == NULL) return;
8026 
8027     mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, mDNSNULL, mDNSNULL);
8028     AssignDomainName(&rr->namestorage, domain);
8029 
8030     rr->resrec.rdlength = DomainNameLength(pname);
8031     rr->resrec.rdata->u.name.c[0] = 0;
8032     AssignDomainName(&rr->resrec.rdata->u.name, pname);
8033 
8034     rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
8035     SetNewRData(&rr->resrec, mDNSNULL, 0);  // Sets rr->rdatahash for us
8036     mDNS_Register(&mDNSStorage, rr);
8037 }
8038 
8039 // Setup PTR records for 127.0.0.1 and ::1. This helps answering them locally rather than relying
8040 // on the external DNS server to answer this. Sometimes, the DNS servers don't respond in a timely
8041 // fashion and applications depending on this e.g., telnetd, times out after 30 seconds creating
8042 // a bad user experience. For now, we specifically create only localhosts to handle radar://9354225
8043 //
8044 // Note: We could have set this up while parsing the entries in /etc/hosts. But this is kept separate
8045 // intentionally to avoid adding to the complexity of code handling /etc/hosts.
SetupLocalHostRecords(void)8046 mDNSlocal void SetupLocalHostRecords(void)
8047 {
8048     domainname name;
8049 
8050     MakeDomainNameFromDNSNameString(&name, "1.0.0.127.in-addr.arpa.");
8051     CreatePTRRecord(&name);
8052 
8053     MakeDomainNameFromDNSNameString(&name, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.");
8054     CreatePTRRecord(&name);
8055 }
8056 
8057 #if APPLE_OSX_mDNSResponder // Don't compile for dnsextd target
8058 mDNSlocal void setSameDomainLabelPointer(void);
8059 #endif
8060 
8061 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
8062 // 1) query for b._dns-sd._udp.local on LocalOnly interface
8063 //    (.local manually generated via explicit callback)
8064 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
8065 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
8066 // 4) result above should generate a callback from question in (1).  result added to global list
8067 // 5) global list delivered to client via GetSearchDomainList()
8068 // 6) client calls to enumerate domains now go over LocalOnly interface
8069 //    (!!!KRS may add outgoing interface in addition)
8070 
8071 #if MDNSRESPONDER_SUPPORTS(APPLE, IGNORE_HOSTS_FILE)
RegisterLocalOnlyAddressRecord(const domainname * const name,mDNSu16 type,const void * rdata,mDNSu16 rdlength)8072 mDNSlocal mStatus RegisterLocalOnlyAddressRecord(const domainname *const name, mDNSu16 type, const void *rdata, mDNSu16 rdlength)
8073 {
8074     switch(type)
8075     {
8076     case kDNSType_A:
8077         if (rdlength != 4) return (mStatus_BadParamErr);
8078         break;
8079 
8080     case kDNSType_AAAA:
8081         if (rdlength != 16) return (mStatus_BadParamErr);
8082         break;
8083 
8084     default:
8085         return (mStatus_BadParamErr);
8086     }
8087 
8088     AuthRecord *rr = (AuthRecord *) callocL("etchosts", sizeof(*rr));
8089     if (!rr) return (mStatus_NoMemoryErr);
8090 
8091     mDNS_SetupResourceRecord(rr, NULL, mDNSInterface_LocalOnly, type, 1, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, FreeEtcHosts, NULL);
8092     AssignDomainName(&rr->namestorage, name);
8093     mDNSPlatformMemCopy(rr->resrec.rdata->u.data, rdata, rdlength);
8094 
8095     const mStatus err = mDNS_Register_internal(&mDNSStorage, rr);
8096     if (err)
8097     {
8098         LogMsg("RegisterLocalOnlyAddressRecord: mDNS_Register error %d registering %s", err, ARDisplayString(&mDNSStorage, rr));
8099         freeL("etchosts", rr);
8100     }
8101     return (err);
8102 }
8103 
RegisterLocalOnlyARecord(const domainname * const name,const mDNSv4Addr * const addr)8104 mDNSlocal void RegisterLocalOnlyARecord(const domainname *const name, const mDNSv4Addr *const addr)
8105 {
8106     RegisterLocalOnlyAddressRecord(name, kDNSType_A, addr->b, (mDNSu16)sizeof(mDNSv4Addr));
8107 }
8108 
RegisterLocalOnlyAAAARecord(const domainname * const name,const mDNSv6Addr * const addr)8109 mDNSlocal void RegisterLocalOnlyAAAARecord(const domainname *const name, const mDNSv6Addr *const addr)
8110 {
8111     RegisterLocalOnlyAddressRecord(name, kDNSType_AAAA, addr->b, (mDNSu16)sizeof(mDNSv6Addr));
8112 }
8113 #endif  // MDNSRESPONDER_SUPPORTS(APPLE, IGNORE_HOSTS_FILE)
8114 
mDNSPlatformInit_setup(mDNS * const m)8115 mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
8116 {
8117     mStatus err;
8118 
8119     char HINFO_SWstring[256] = "";
8120     mDNSMacOSXSystemBuildNumber(HINFO_SWstring);
8121 
8122 #if APPLE_OSX_mDNSResponder
8123     setSameDomainLabelPointer();
8124 #endif
8125 
8126     err = mDNSHelperInit();
8127     if (err)
8128         return err;
8129 
8130     // Store mDNSResponder Platform
8131     if (OSXVers)
8132     {
8133         m->mDNS_plat = platform_OSX;
8134     }
8135     else if (iOSVers)
8136     {
8137         if (IsAppleTV())
8138             m->mDNS_plat = platform_Atv;
8139         else
8140             m->mDNS_plat = platform_iOS;
8141     }
8142     else
8143     {
8144         m->mDNS_plat = platform_NonApple;
8145     }
8146 
8147     // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
8148     // If we can't read the user's preferences, then we sleep a bit and try again, for up to five seconds before we give up.
8149     int i;
8150     for (i=0; i<100; i++)
8151     {
8152         domainlabel testlabel;
8153         testlabel.c[0] = 0;
8154         GetUserSpecifiedLocalHostName(&testlabel);
8155         if (testlabel.c[0]) break;
8156         usleep(50000);
8157     }
8158 
8159     m->hostlabel.c[0]        = 0;
8160 
8161 #if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
8162     GetRandomUUIDLocalHostname(&m->RandomizedHostname);
8163 #endif
8164     int get_model[2] = { CTL_HW, HW_MODEL };
8165     size_t len_model = sizeof(HINFO_HWstring_buffer);
8166 
8167     // Normal Apple model names are of the form "iPhone2,1", and
8168     // internal code names are strings containing no commas, e.g. "N88AP".
8169     // We used to ignore internal code names, but Apple now uses these internal code names
8170     // even in released shipping products, so we no longer ignore strings containing no commas.
8171 //  if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ','))
8172     if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0)
8173         HINFO_HWstring = HINFO_HWstring_buffer;
8174 
8175     // For names of the form "iPhone2,1" we use "iPhone" as the prefix for automatic name generation.
8176     // For names of the form "N88AP" containg no comma, we use the entire string.
8177     HINFO_HWstring_prefixlen = (int)(strchr(HINFO_HWstring_buffer, ',') ? strcspn(HINFO_HWstring, "0123456789") : strlen(HINFO_HWstring));
8178 
8179     if (mDNSPlatformInit_CanReceiveUnicast())
8180         m->CanReceiveUnicastOn5353 = mDNStrue;
8181 
8182     mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
8183     mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
8184     if (hlen + slen < 254)
8185     {
8186         m->HIHardware.c[0] = hlen;
8187         m->HISoftware.c[0] = slen;
8188         mDNSPlatformMemCopy(&m->HIHardware.c[1], HINFO_HWstring, hlen);
8189         mDNSPlatformMemCopy(&m->HISoftware.c[1], HINFO_SWstring, slen);
8190     }
8191 
8192     m->p->permanentsockets.port  = MulticastDNSPort;
8193     m->p->permanentsockets.m     = m;
8194     m->p->permanentsockets.sktv4 = -1;
8195     m->p->permanentsockets.kqsv4.KQcallback = myKQSocketCallBack;
8196     m->p->permanentsockets.kqsv4.KQcontext  = &m->p->permanentsockets;
8197     m->p->permanentsockets.kqsv4.KQtask     = "IPv4 UDP packet reception";
8198     m->p->permanentsockets.sktv6 = -1;
8199     m->p->permanentsockets.kqsv6.KQcallback = myKQSocketCallBack;
8200     m->p->permanentsockets.kqsv6.KQcontext  = &m->p->permanentsockets;
8201     m->p->permanentsockets.kqsv6.KQtask     = "IPv6 UDP packet reception";
8202 
8203     err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET, mDNSNULL);
8204     if (err) LogMsg("mDNSPlatformInit_setup: SetupSocket(AF_INET) failed error %d errno %d (%s)", err, errno, strerror(errno));
8205     err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET6, mDNSNULL);
8206     if (err) LogMsg("mDNSPlatformInit_setup: SetupSocket(AF_INET6) failed error %d errno %d (%s)", err, errno, strerror(errno));
8207 
8208     struct sockaddr_in s4;
8209     socklen_t n4 = sizeof(s4);
8210     if (getsockname(m->p->permanentsockets.sktv4, (struct sockaddr *)&s4, &n4) < 0)
8211         LogMsg("getsockname v4 error %d (%s)", errno, strerror(errno));
8212     else
8213         m->UnicastPort4.NotAnInteger = s4.sin_port;
8214 
8215     if (m->p->permanentsockets.sktv6 >= 0)
8216     {
8217         struct sockaddr_in6 s6;
8218         socklen_t n6 = sizeof(s6);
8219         if (getsockname(m->p->permanentsockets.sktv6, (struct sockaddr *)&s6, &n6) < 0) LogMsg("getsockname v6 error %d (%s)", errno, strerror(errno));
8220         else m->UnicastPort6.NotAnInteger = s6.sin6_port;
8221     }
8222 
8223     m->p->InterfaceList         = mDNSNULL;
8224 #if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
8225     m->p->InterfaceMonitors     = NULL;
8226 #endif
8227     m->p->userhostlabel.c[0]    = 0;
8228     m->p->usernicelabel.c[0]    = 0;
8229     m->p->prevoldnicelabel.c[0] = 0;
8230     m->p->prevnewnicelabel.c[0] = 0;
8231     m->p->prevoldhostlabel.c[0] = 0;
8232     m->p->prevnewhostlabel.c[0] = 0;
8233     m->p->NotifyUser         = 0;
8234     m->p->KeyChainTimer      = 0;
8235     m->p->WakeAtUTC          = 0;
8236     m->p->RequestReSleep     = 0;
8237     // Assume that everything is good to begin with. If something is not working,
8238     // we will detect that when we start sending questions.
8239     m->p->v4answers          = 1;
8240     m->p->v6answers          = 1;
8241     m->p->DNSTrigger         = 0;
8242     m->p->LastConfigGeneration = 0;
8243 #if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
8244     m->p->if_interface_changed = mDNSfalse;
8245 #endif
8246 
8247     NetworkChangedKey_IPv4         = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
8248     NetworkChangedKey_IPv6         = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
8249     NetworkChangedKey_Hostnames    = SCDynamicStoreKeyCreateHostNames(NULL);
8250     NetworkChangedKey_Computername = SCDynamicStoreKeyCreateComputerName(NULL);
8251     NetworkChangedKey_DNS          = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
8252     NetworkChangedKey_StateInterfacePrefix = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, CFSTR(""), NULL);
8253     if (!NetworkChangedKey_IPv4 || !NetworkChangedKey_IPv6 || !NetworkChangedKey_Hostnames || !NetworkChangedKey_Computername || !NetworkChangedKey_DNS || !NetworkChangedKey_StateInterfacePrefix)
8254     { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr); }
8255 
8256     err = WatchForNetworkChanges(m);
8257     if (err) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err); return(err); }
8258 
8259     err = WatchForSysEvents(m);
8260     if (err) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err); return(err); }
8261 
8262     mDNSs32 utc = mDNSPlatformUTC();
8263     m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
8264     myGetIfAddrs(1);
8265     UpdateInterfaceList(utc);
8266     SetupActiveInterfaces(utc);
8267     ReorderInterfaceList();
8268 
8269     // Explicitly ensure that our Keychain operations utilize the system domain.
8270 #ifndef NO_SECURITYFRAMEWORK
8271     SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
8272 #endif
8273 
8274     mDNS_Lock(m);
8275     SetDomainSecrets(m);
8276     SetLocalDomains();
8277     mDNS_Unlock(m);
8278 
8279 #ifndef NO_SECURITYFRAMEWORK
8280     err = SecKeychainAddCallback(KeychainChanged, kSecAddEventMask|kSecDeleteEventMask|kSecUpdateEventMask, m);
8281     if (err) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err); return(err); }
8282 #endif
8283 
8284 #if !defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) || TARGET_OS_IPHONE
8285     LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support");
8286 #else
8287     IOPMConnection c;
8288     IOReturn iopmerr = IOPMConnectionCreate(CFSTR("mDNSResponder"), kIOPMSystemPowerStateCapabilityCPU, &c);
8289     if (iopmerr) LogMsg("IOPMConnectionCreate failed %d", iopmerr);
8290     else
8291     {
8292         iopmerr = IOPMConnectionSetNotification(c, m, SnowLeopardPowerChanged);
8293         if (iopmerr) LogMsg("IOPMConnectionSetNotification failed %d", iopmerr);
8294         else
8295         {
8296 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
8297             IOPMConnectionSetDispatchQueue(c, dispatch_get_main_queue());
8298             LogInfo("IOPMConnectionSetDispatchQueue is now running");
8299 #else
8300             iopmerr = IOPMConnectionScheduleWithRunLoop(c, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
8301             if (iopmerr) LogMsg("IOPMConnectionScheduleWithRunLoop failed %d", iopmerr);
8302             LogInfo("IOPMConnectionScheduleWithRunLoop is now running");
8303 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
8304         }
8305     }
8306     m->p->IOPMConnection = iopmerr ? mDNSNULL : c;
8307     if (iopmerr) // If IOPMConnectionCreate unavailable or failed, proceed with old-style power notification code below
8308 #endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements
8309     {
8310         m->p->PowerConnection = IORegisterForSystemPower(m, &m->p->PowerPortRef, PowerChanged, &m->p->PowerNotifier);
8311         if (!m->p->PowerConnection) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
8312         else
8313         {
8314 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
8315             IONotificationPortSetDispatchQueue(m->p->PowerPortRef, dispatch_get_main_queue());
8316 #else
8317             CFRunLoopAddSource(CFRunLoopGetMain(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
8318 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
8319         }
8320     }
8321 
8322 #if APPLE_OSX_mDNSResponder
8323     // Note: We use SPMetricPortability > 35 to indicate a laptop of some kind
8324     // SPMetricPortability <= 35 means nominally a non-portable machine (i.e. Mac mini or better)
8325     // Apple TVs, AirPort base stations, and Time Capsules do not actually weigh 3kg, but we assign them
8326     // higher 'nominal' masses to indicate they should be treated as being relatively less portable than a laptop
8327     if      (!strncasecmp(HINFO_HWstring, "Xserve",       6)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
8328     else if (!strncasecmp(HINFO_HWstring, "RackMac",      7)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
8329     else if (!strncasecmp(HINFO_HWstring, "MacPro",       6)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
8330     else if (!strncasecmp(HINFO_HWstring, "PowerMac",     8)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 82 /* 160W */; SPMetricTotalPower = 83 /* 200W */; }
8331     else if (!strncasecmp(HINFO_HWstring, "iMac",         4)) { SPMetricPortability = 30 /* 10kg */; SPMetricMarginalPower = 77 /*  50W */; SPMetricTotalPower = 78 /*  60W */; }
8332     else if (!strncasecmp(HINFO_HWstring, "Macmini",      7)) { SPMetricPortability = 33 /*  5kg */; SPMetricMarginalPower = 73 /*  20W */; SPMetricTotalPower = 74 /*  25W */; }
8333     else if (!strncasecmp(HINFO_HWstring, "TimeCapsule", 11)) { SPMetricPortability = 34 /*  4kg */; SPMetricMarginalPower = 10 /*  ~0W */; SPMetricTotalPower = 70 /*  13W */; }
8334     else if (!strncasecmp(HINFO_HWstring, "AirPort",      7)) { SPMetricPortability = 35 /*  3kg */; SPMetricMarginalPower = 10 /*  ~0W */; SPMetricTotalPower = 70 /*  12W */; }
8335     else if (  IsAppleTV()  )                                 { SPMetricPortability = 35 /*  3kg */; SPMetricMarginalPower = 60 /*   1W */; SPMetricTotalPower = 63 /*   2W */; }
8336     else if (!strncasecmp(HINFO_HWstring, "MacBook",      7)) { SPMetricPortability = 37 /*  2kg */; SPMetricMarginalPower = 71 /*  13W */; SPMetricTotalPower = 72 /*  15W */; }
8337     else if (!strncasecmp(HINFO_HWstring, "PowerBook",    9)) { SPMetricPortability = 37 /*  2kg */; SPMetricMarginalPower = 71 /*  13W */; SPMetricTotalPower = 72 /*  15W */; }
8338     LogSPS("HW_MODEL: %.*s (%s) Portability %d Marginal Power %d Total Power %d Features %d",
8339            HINFO_HWstring_prefixlen, HINFO_HWstring, HINFO_HWstring, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures);
8340 #endif // APPLE_OSX_mDNSResponder
8341 
8342     // Currently this is not defined. SSL code will eventually fix this. If it becomes
8343     // critical, we will define this to workaround the bug in SSL.
8344 #ifdef __SSL_NEEDS_SERIALIZATION__
8345     SSLqueue = dispatch_queue_create("com.apple.mDNSResponder.SSLQueue", NULL);
8346 #else
8347     SSLqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
8348 #endif
8349     if (SSLqueue == mDNSNULL) LogMsg("dispatch_queue_create: SSL queue NULL");
8350 
8351 #if MDNSRESPONDER_SUPPORTS(APPLE, IGNORE_HOSTS_FILE)
8352     // On device OSes (iOS, tvOS, watchOS, etc.), ignore /etc/hosts unless the OS is an internal build. When the /etc/hosts
8353     // file is ignored, LocalOnly auth records will be registered for localhost and broadcasthost addresses contained in the
8354     // standard /etc/hosts file:
8355     //
8356     //  127.0.0.1       localhost
8357     //  255.255.255.255 broadcasthost
8358     //  ::1             localhost
8359 
8360     if (!IsAppleInternalBuild())
8361     {
8362         const domainname *const localHostName     = (const domainname *) "\x9" "localhost";
8363         const domainname *const broadcastHostName = (const domainname *) "\xd" "broadcasthost";
8364         const mDNSv4Addr        localHostV4       = { { 127, 0, 0, 1 } };
8365         mDNSv6Addr              localHostV6;
8366 
8367         // Register localhost 127.0.0.1 A record.
8368 
8369         RegisterLocalOnlyARecord(localHostName, &localHostV4);
8370 
8371         // Register broadcasthost 255.255.255.255 A record.
8372 
8373         RegisterLocalOnlyARecord(broadcastHostName, &onesIPv4Addr);
8374 
8375         // Register localhost ::1 AAAA record.
8376 
8377         mDNSPlatformMemZero(&localHostV6, sizeof(localHostV6));
8378         localHostV6.b[15] = 1;
8379         RegisterLocalOnlyAAAARecord(localHostName, &localHostV6);
8380     }
8381     else
8382 #endif
8383     {
8384         mDNSMacOSXUpdateEtcHosts(m);
8385     }
8386     SetupLocalHostRecords();
8387 
8388 #if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
8389     dso_transport_init();
8390 #endif
8391 
8392 #if MDNSRESPONDER_SUPPORTS(APPLE, ANALYTICS)
8393     dnssd_analytics_init();
8394 #endif
8395 
8396 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
8397     if (os_feature_enabled(mDNSResponder, bonjour_privacy))
8398     {
8399         mdns_trust_init();
8400    }
8401 #endif
8402 
8403     return(mStatus_NoError);
8404 }
8405 
mDNSPlatformInit(mDNS * const m)8406 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
8407 {
8408 #if MDNS_NO_DNSINFO
8409     LogMsg("Note: Compiled without Apple-specific Split-DNS support");
8410 #endif
8411 
8412     // Adding interfaces will use this flag, so set it now.
8413     m->DivertMulticastAdvertisements = !m->AdvertiseLocalAddresses;
8414 
8415 #if APPLE_OSX_mDNSResponder
8416     m->SPSBrowseCallback = UpdateSPSStatus;
8417 #endif // APPLE_OSX_mDNSResponder
8418 
8419     mStatus result = mDNSPlatformInit_setup(m);
8420 
8421     // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
8422     // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
8423     if (result == mStatus_NoError)
8424     {
8425         mDNSCoreInitComplete(m, mStatus_NoError);
8426 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
8427         initializeD2DPlugins(m);
8428 #endif
8429     }
8430     return(result);
8431 }
8432 
mDNSPlatformClose(mDNS * const m)8433 mDNSexport void mDNSPlatformClose(mDNS *const m)
8434 {
8435     if (m->p->PowerConnection)
8436     {
8437 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
8438         IONotificationPortSetDispatchQueue(m->p->PowerPortRef, NULL);
8439 #else
8440         CFRunLoopRemoveSource(CFRunLoopGetMain(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
8441 #endif
8442         // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
8443         // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
8444         IODeregisterForSystemPower(&m->p->PowerNotifier);
8445         IOServiceClose            ( m->p->PowerConnection);
8446         IONotificationPortDestroy ( m->p->PowerPortRef);
8447         m->p->PowerConnection = 0;
8448     }
8449 
8450     if (m->p->Store)
8451     {
8452 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
8453         if (!SCDynamicStoreSetDispatchQueue(m->p->Store, NULL))
8454             LogMsg("mDNSPlatformClose: SCDynamicStoreSetDispatchQueue failed");
8455 #else
8456         CFRunLoopRemoveSource(CFRunLoopGetMain(), m->p->StoreRLS, kCFRunLoopDefaultMode);
8457         CFRunLoopSourceInvalidate(m->p->StoreRLS);
8458         CFRelease(m->p->StoreRLS);
8459         m->p->StoreRLS = NULL;
8460 #endif
8461         CFRelease(m->p->Store);
8462         m->p->Store    = NULL;
8463     }
8464 
8465     if (m->p->PMRLS)
8466     {
8467         CFRunLoopRemoveSource(CFRunLoopGetMain(), m->p->PMRLS, kCFRunLoopDefaultMode);
8468         CFRunLoopSourceInvalidate(m->p->PMRLS);
8469         CFRelease(m->p->PMRLS);
8470         m->p->PMRLS = NULL;
8471     }
8472 
8473     if (m->p->SysEventNotifier >= 0) { close(m->p->SysEventNotifier); m->p->SysEventNotifier = -1; }
8474 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
8475     terminateD2DPlugins();
8476 #endif
8477 
8478     mDNSs32 utc = mDNSPlatformUTC();
8479     MarkAllInterfacesInactive(utc);
8480     ClearInactiveInterfaces(utc);
8481     CloseSocketSet(&m->p->permanentsockets);
8482 
8483 #if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
8484     if (m->p->InterfaceMonitors)
8485     {
8486         CFArrayRef monitors = m->p->InterfaceMonitors;
8487         m->p->InterfaceMonitors = NULL;
8488         const CFIndex n = CFArrayGetCount(monitors);
8489         for (CFIndex i = 0; i < n; i++)
8490         {
8491             mdns_interface_monitor_invalidate((mdns_interface_monitor_t) CFArrayGetValueAtIndex(monitors, i));
8492         }
8493         CFRelease(monitors);
8494     }
8495 #endif
8496 }
8497 
8498 #if COMPILER_LIKES_PRAGMA_MARK
8499 #pragma mark -
8500 #pragma mark - General Platform Support Layer functions
8501 #endif
8502 
mDNSPlatformRandomNumber(void)8503 mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
8504 {
8505     return(arc4random());
8506 }
8507 
8508 mDNSexport mDNSs32 mDNSPlatformOneSecond = 1000;
8509 mDNSexport mDNSu32 mDNSPlatformClockDivisor = 0;
8510 
mDNSPlatformTimeInit(void)8511 mDNSexport mStatus mDNSPlatformTimeInit(void)
8512 {
8513     // Notes: Typical values for mach_timebase_info:
8514     // tbi.numer = 1000 million
8515     // tbi.denom =   33 million
8516     // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
8517     //          numer  / denom = nanoseconds per hardware clock tick (e.g. 30);
8518     //          denom  / numer = hardware clock ticks per nanosecond (e.g. 0.033)
8519     // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
8520     // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
8521     //
8522     // Arithmetic notes:
8523     // tbi.denom is at least 1, and not more than 2^32-1.
8524     // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
8525     // tbi.denom is at least 1, and not more than 2^32-1.
8526     // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
8527     // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
8528     // which is unlikely on any current or future Macintosh.
8529     // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
8530     // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
8531     struct mach_timebase_info tbi;
8532     kern_return_t result = mach_timebase_info(&tbi);
8533     if (result == KERN_SUCCESS) mDNSPlatformClockDivisor = (mDNSu32)(((uint64_t)tbi.denom * 1000000) / tbi.numer);
8534     return(result);
8535 }
8536 
mDNSPlatformRawTime(void)8537 mDNSexport mDNSs32 mDNSPlatformRawTime(void)
8538 {
8539     if (mDNSPlatformClockDivisor == 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
8540 
8541     static uint64_t last_mach_absolute_time = 0;
8542     //static uint64_t last_mach_absolute_time = 0x8000000000000000LL;   // Use this value for testing the alert display
8543     uint64_t this_mach_absolute_time = mach_absolute_time();
8544     if ((int64_t)this_mach_absolute_time - (int64_t)last_mach_absolute_time < 0)
8545     {
8546         LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time);
8547         LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time);
8548         // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
8549         last_mach_absolute_time = this_mach_absolute_time;
8550         // Note: This bug happens all the time on 10.3
8551         NotifyOfElusiveBug("mach_absolute_time went backwards!",
8552                            "This error occurs from time to time, often on newly released hardware, "
8553                            "and usually the exact cause is different in each instance.\r\r"
8554                            "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
8555                            "and assign it to Radar Component “Kernel” Version “X”.");
8556     }
8557     last_mach_absolute_time = this_mach_absolute_time;
8558 
8559     return((mDNSs32)(this_mach_absolute_time / mDNSPlatformClockDivisor));
8560 }
8561 
mDNSPlatformUTC(void)8562 mDNSexport mDNSs32 mDNSPlatformUTC(void)
8563 {
8564     return (mDNSs32)time(NULL);
8565 }
8566 
8567 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
mDNSPlatformLock(const mDNS * const m)8568 mDNSexport void     mDNSPlatformLock   (const mDNS *const m) { (void)m; }
mDNSPlatformUnlock(const mDNS * const m)8569 mDNSexport void     mDNSPlatformUnlock (const mDNS *const m) { (void)m; }
mDNSPlatformStrLCopy(void * dst,const void * src,mDNSu32 dstlen)8570 mDNSexport mDNSu32  mDNSPlatformStrLCopy(     void *dst, const void *src, mDNSu32 dstlen) { return((mDNSu32)strlcpy((char *)dst, (const char *)src, dstlen)); }
mDNSPlatformStrLen(const void * src)8571 mDNSexport mDNSu32  mDNSPlatformStrLen (                 const void *src)              { return((mDNSu32)strlen((const char*)src)); }
mDNSPlatformMemCopy(void * dst,const void * src,mDNSu32 len)8572 mDNSexport void     mDNSPlatformMemCopy(      void *dst, const void *src, mDNSu32 len) { memcpy(dst, src, len); }
mDNSPlatformMemSame(const void * dst,const void * src,mDNSu32 len)8573 mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len) == 0); }
mDNSPlatformMemCmp(const void * dst,const void * src,mDNSu32 len)8574 mDNSexport int      mDNSPlatformMemCmp(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len)); }
mDNSPlatformMemZero(void * dst,mDNSu32 len)8575 mDNSexport void     mDNSPlatformMemZero(      void *dst,                  mDNSu32 len) { memset(dst, 0, len); }
mDNSPlatformQsort(void * base,int nel,int width,int (* compar)(const void *,const void *))8576 mDNSexport void     mDNSPlatformQsort  (      void *base, int nel, int width, int (*compar)(const void *, const void *))
8577 {
8578     return (qsort(base, nel, width, compar));
8579 }
8580 #if !MDNS_MALLOC_DEBUGGING
mDNSPlatformMemAllocate(mDNSu32 len)8581 mDNSexport void *mDNSPlatformMemAllocate(mDNSu32 len)      { return(mallocL("mDNSPlatformMemAllocate", len)); }
mDNSPlatformMemAllocateClear(mDNSu32 len)8582 mDNSexport void *mDNSPlatformMemAllocateClear(mDNSu32 len) { return(callocL("mDNSPlatformMemAllocateClear", len)); }
mDNSPlatformMemFree(void * mem)8583 mDNSexport void  mDNSPlatformMemFree    (void *mem)                 { freeL("mDNSPlatformMemFree", mem); }
8584 #endif
8585 
mDNSPlatformSetAllowSleep(mDNSBool allowSleep,const char * reason)8586 mDNSexport void mDNSPlatformSetAllowSleep(mDNSBool allowSleep, const char *reason)
8587 {
8588     mDNS *const m = &mDNSStorage;
8589     if (allowSleep && m->p->IOPMAssertion)
8590     {
8591         LogInfo("%s Destroying NoIdleSleep power assertion", __FUNCTION__);
8592         IOPMAssertionRelease(m->p->IOPMAssertion);
8593         m->p->IOPMAssertion = 0;
8594     }
8595     else if (!allowSleep)
8596     {
8597 #ifdef kIOPMAssertionTypeNoIdleSleep
8598         if (m->p->IOPMAssertion)
8599         {
8600             IOPMAssertionRelease(m->p->IOPMAssertion);
8601             m->p->IOPMAssertion = 0;
8602         }
8603 
8604         CFStringRef assertionName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s.%d %s"), getprogname(), getpid(), reason ? reason : "");
8605         IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, assertionName ? assertionName : CFSTR("mDNSResponder"), &m->p->IOPMAssertion);
8606         if (assertionName) CFRelease(assertionName);
8607         LogInfo("%s Creating NoIdleSleep power assertion", __FUNCTION__);
8608 #endif
8609     }
8610 }
8611 
mDNSPlatformPreventSleep(mDNSu32 timeout,const char * reason)8612 mDNSexport void mDNSPlatformPreventSleep(mDNSu32 timeout, const char *reason)
8613 {
8614     mDNS *const m = &mDNSStorage;
8615     if (m->p->IOPMAssertion)
8616     {
8617         LogSPS("Sleep Assertion is already being held. Will not attempt to get it again for %d seconds for %s", timeout, reason);
8618         return;
8619     }
8620 #ifdef kIOPMAssertionTypeNoIdleSleep
8621 
8622 #if TARGET_OS_IPHONE
8623     if (!IsAppleTV())
8624         return; // No need for maintenance wakes on non-AppleTV embedded devices.
8625 #endif
8626 
8627     double timeoutVal = (double)timeout;
8628     CFStringRef str = CFStringCreateWithCString(NULL, reason, kCFStringEncodingUTF8);
8629     CFNumberRef Timeout_num = CFNumberCreate(NULL, kCFNumberDoubleType, &timeoutVal);
8630     CFMutableDictionaryRef assertionProperties = CFDictionaryCreateMutable(NULL, 0,
8631                                                                            &kCFTypeDictionaryKeyCallBacks,
8632                                                                            &kCFTypeDictionaryValueCallBacks);
8633     if (IsAppleTV())
8634         CFDictionarySetValue(assertionProperties, kIOPMAssertionTypeKey, kIOPMAssertPreventUserIdleSystemSleep);
8635     else
8636         CFDictionarySetValue(assertionProperties, kIOPMAssertionTypeKey, kIOPMAssertMaintenanceActivity);
8637 
8638     CFDictionarySetValue(assertionProperties, kIOPMAssertionTimeoutKey, Timeout_num);
8639     CFDictionarySetValue(assertionProperties, kIOPMAssertionNameKey,    str);
8640 
8641     IOPMAssertionCreateWithProperties(assertionProperties, (IOPMAssertionID *)&m->p->IOPMAssertion);
8642     CFRelease(str);
8643     CFRelease(Timeout_num);
8644     CFRelease(assertionProperties);
8645     LogSPS("Got an idle sleep assertion for %d seconds for %s", timeout, reason);
8646 #endif
8647 }
8648 
mDNSPlatformSendWakeupPacket(mDNSInterfaceID InterfaceID,char * EthAddr,char * IPAddr,int iteration)8649 mDNSexport void mDNSPlatformSendWakeupPacket(mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
8650 {
8651     if (GetInterfaceSupportsWakeOnLANPacket(InterfaceID))
8652     {
8653         mDNSu32 ifindex;
8654 
8655         // Sanity check
8656         ifindex = mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, InterfaceID, mDNStrue);
8657         if (ifindex <= 0)
8658         {
8659             LogMsg("mDNSPlatformSendWakeupPacket: ERROR!! Invalid InterfaceID %u", ifindex);
8660             return;
8661         }
8662         mDNSSendWakeupPacket(ifindex, EthAddr, IPAddr, iteration);
8663     }
8664 }
8665 
mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)8666 mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
8667 {
8668     NetworkInterfaceInfoOSX *info;
8669 
8670     if (InterfaceID == mDNSInterface_P2P)
8671         return mDNStrue;
8672 
8673     // mDNSInterface_BLE not considered a D2D interface for the purpose of this
8674     // routine, since it's not implemented via a D2D plugin.
8675     if (InterfaceID == mDNSInterface_BLE)
8676         return mDNSfalse;
8677 
8678     if (   (InterfaceID == mDNSInterface_Any)
8679         || (InterfaceID == mDNSInterfaceMark)
8680         || (InterfaceID == mDNSInterface_LocalOnly))
8681         return mDNSfalse;
8682 
8683     // Compare to cached AWDL interface ID.
8684     if (AWDLInterfaceID && (InterfaceID == AWDLInterfaceID))
8685         return mDNStrue;
8686 
8687     info = IfindexToInterfaceInfoOSX(InterfaceID);
8688     if (info == NULL)
8689     {
8690         // this log message can print when operations are stopped on an interface that has gone away
8691         LogInfo("mDNSPlatformInterfaceIsD2D: Invalid interface index %d", InterfaceID);
8692         return mDNSfalse;
8693     }
8694 
8695     return (mDNSBool) info->D2DInterface;
8696 }
8697 
8698 #if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
mDNSPlatformInterfaceIsAWDL(const mDNSInterfaceID interfaceID)8699 mDNSexport mDNSBool mDNSPlatformInterfaceIsAWDL(const mDNSInterfaceID interfaceID)
8700 {
8701     return ((AWDLInterfaceID && (interfaceID == AWDLInterfaceID)) ? mDNStrue : mDNSfalse);
8702 }
8703 #endif
8704 
8705 // Filter records send over P2P (D2D) type interfaces
8706 // Note that the terms P2P and D2D are used synonymously in the current code and comments.
mDNSPlatformValidRecordForInterface(const AuthRecord * rr,mDNSInterfaceID InterfaceID)8707 mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(const AuthRecord *rr, mDNSInterfaceID InterfaceID)
8708 {
8709     // For an explicit match to a valid interface ID, return true.
8710     if (rr->resrec.InterfaceID == InterfaceID)
8711         return mDNStrue;
8712 
8713     // Only filtering records for D2D type interfaces, return true for all other interface types.
8714     if (!mDNSPlatformInterfaceIsD2D(InterfaceID))
8715         return mDNStrue;
8716 
8717     // If it's an AWDL interface the record must be explicitly marked to include AWDL.
8718     if (InterfaceID == AWDLInterfaceID)
8719     {
8720         if (rr->ARType == AuthRecordAnyIncludeAWDL || rr->ARType == AuthRecordAnyIncludeAWDLandP2P)
8721             return mDNStrue;
8722         else
8723             return mDNSfalse;
8724     }
8725 
8726     // Send record if it is explicitly marked to include all other P2P type interfaces.
8727     if (rr->ARType == AuthRecordAnyIncludeP2P || rr->ARType == AuthRecordAnyIncludeAWDLandP2P)
8728         return mDNStrue;
8729 
8730     // Don't send the record over this interface.
8731     return mDNSfalse;
8732 }
8733 
8734 // Filter questions send over P2P (D2D) type interfaces.
mDNSPlatformValidQuestionForInterface(DNSQuestion * q,const NetworkInterfaceInfo * intf)8735 mDNSexport mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf)
8736 {
8737     // For an explicit match to a valid interface ID, return true.
8738     if (q->InterfaceID == intf->InterfaceID)
8739         return mDNStrue;
8740 
8741     // Only filtering questions for D2D type interfaces
8742     if (!mDNSPlatformInterfaceIsD2D(intf->InterfaceID))
8743         return mDNStrue;
8744 
8745     // If it's an AWDL interface the question must be explicitly marked to include AWDL.
8746     if (intf->InterfaceID == AWDLInterfaceID)
8747     {
8748         if (q->flags & kDNSServiceFlagsIncludeAWDL)
8749             return mDNStrue;
8750         else
8751             return mDNSfalse;
8752     }
8753 
8754     // Sent question if it is explicitly marked to include all other P2P type interfaces.
8755     if (q->flags & kDNSServiceFlagsIncludeP2P)
8756         return mDNStrue;
8757 
8758     // Don't send the question over this interface.
8759     return mDNSfalse;
8760 }
8761 
8762 // Returns true unless record was received over the AWDL interface and
8763 // the question was not specific to the AWDL interface or did not specify kDNSServiceInterfaceIndexAny
8764 // with the kDNSServiceFlagsIncludeAWDL flag set.
mDNSPlatformValidRecordForQuestion(const ResourceRecord * const rr,const DNSQuestion * const q)8765 mDNSexport mDNSBool   mDNSPlatformValidRecordForQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
8766 {
8767     if (!rr->InterfaceID || (rr->InterfaceID == q->InterfaceID))
8768         return mDNStrue;
8769 
8770     if ((rr->InterfaceID == AWDLInterfaceID) && !(q->flags & kDNSServiceFlagsIncludeAWDL))
8771         return mDNSfalse;
8772 
8773     return mDNStrue;
8774 }
8775 
8776 // formating time to RFC 4034 format
mDNSPlatformFormatTime(unsigned long te,mDNSu8 * buf,int bufsize)8777 mDNSexport void mDNSPlatformFormatTime(unsigned long te, mDNSu8 *buf, int bufsize)
8778 {
8779     struct tm tmTime;
8780     time_t t = (time_t)te;
8781     // Time since epoch : strftime takes "tm". Convert seconds to "tm" using
8782     // gmtime_r first and then use strftime
8783     gmtime_r(&t, &tmTime);
8784     strftime((char *)buf, bufsize, "%Y%m%d%H%M%S", &tmTime);
8785 }
8786 
mDNSPlatformGetPID()8787 mDNSexport mDNSs32 mDNSPlatformGetPID()
8788 {
8789     return getpid();
8790 }
8791 
8792 // Schedule a function asynchronously on the main queue
mDNSPlatformDispatchAsync(mDNS * const m,void * context,AsyncDispatchFunc func)8793 mDNSexport void mDNSPlatformDispatchAsync(mDNS *const m, void *context, AsyncDispatchFunc func)
8794 {
8795     // KQueueLock/Unlock is used for two purposes
8796     //
8797     // 1. We can't be running along with the KQueue thread and hence acquiring the lock
8798     //    serializes the access to the "core"
8799     //
8800     // 2. KQueueUnlock also sends a message wake up the KQueue thread which in turn wakes
8801     //    up and calls udsserver_idle which schedules the messages across the uds socket.
8802     //    If "func" delivers something to the uds socket from the dispatch thread, it will
8803     //    not be delivered immediately if not for the Unlock.
8804     dispatch_async(dispatch_get_main_queue(), ^{
8805         KQueueLock();
8806         func(m, context);
8807         KQueueUnlock("mDNSPlatformDispatchAsync");
8808 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
8809         // KQueueUnlock is a noop. Hence, we need to run kick off the idle loop
8810         // to handle any message that "func" might deliver.
8811         TriggerEventCompletion();
8812 #endif
8813     });
8814 }
8815 
8816 // definitions for device-info record construction
8817 #define DEVINFO_MODEL       "model="
8818 #define DEVINFO_MODEL_LEN   sizeof_string(DEVINFO_MODEL)
8819 
8820 #define OSX_VER         "osxvers="
8821 #define OSX_VER_LEN     sizeof_string(OSX_VER)
8822 #define VER_NUM_LEN     2  // 2 digits of version number added to base string
8823 
8824 #define MODEL_RGB_COLOR       "ecolor="
8825 #define MODEL_INDEX_COLOR     "icolor="
8826 #define MODEL_COLOR_LEN       sizeof_string(MODEL_RGB_COLOR) // Same len as MODEL_INDEX_COLOR
8827 #define MODEL_COLOR_VALUE_LEN sizeof_string("255,255,255")   // 'r,g,b', 'i' MAXUINT32('4294967295')
8828 
8829 // Bytes available in TXT record for model name after subtracting space for other
8830 // fixed size strings and their length bytes.
8831 #define MAX_MODEL_NAME_LEN   (256 - (DEVINFO_MODEL_LEN + 1) - (OSX_VER_LEN + VER_NUM_LEN + 1) - (MODEL_COLOR_LEN + MODEL_COLOR_VALUE_LEN + 1))
8832 
8833 // Initialize device-info TXT record contents and return total length of record data.
initializeDeviceInfoTXT(mDNS * m,mDNSu8 * ptr)8834 mDNSexport mDNSu32 initializeDeviceInfoTXT(mDNS *m, mDNSu8 *ptr)
8835 {
8836     mDNSu8 *bufferStart = ptr;
8837     mDNSu8 len = m->HIHardware.c[0] < MAX_MODEL_NAME_LEN ? m->HIHardware.c[0] : MAX_MODEL_NAME_LEN;
8838 
8839     *ptr = DEVINFO_MODEL_LEN + len; // total length of DEVINFO_MODEL string plus the hardware name string
8840     ptr++;
8841     mDNSPlatformMemCopy(ptr, DEVINFO_MODEL, DEVINFO_MODEL_LEN);
8842     ptr += DEVINFO_MODEL_LEN;
8843     mDNSPlatformMemCopy(ptr, m->HIHardware.c + 1, len);
8844     ptr += len;
8845 
8846     // only include this string for OSX
8847     if (OSXVers)
8848     {
8849         char    ver_num[VER_NUM_LEN + 1]; // version digits + null written by snprintf
8850         *ptr = OSX_VER_LEN + VER_NUM_LEN; // length byte
8851         ptr++;
8852         mDNSPlatformMemCopy(ptr, OSX_VER, OSX_VER_LEN);
8853         ptr += OSX_VER_LEN;
8854         // convert version number to ASCII, add 1 for terminating null byte written by snprintf()
8855         // WARNING: This code assumes that OSXVers is always exactly two digits
8856         snprintf(ver_num, VER_NUM_LEN + 1, "%d", OSXVers);
8857         mDNSPlatformMemCopy(ptr, ver_num, VER_NUM_LEN);
8858         ptr += VER_NUM_LEN;
8859 
8860         const uint8_t max_color_len = MODEL_COLOR_VALUE_LEN + 1;
8861         char color[max_color_len]; // Color string value + null written by snprintf
8862         util_enclosure_color_t color_type = util_get_enclosure_color_str(color, max_color_len, &len);
8863         if (color_type != util_enclosure_color_none && len < max_color_len)
8864         {
8865             *ptr = MODEL_COLOR_LEN + len; // length byte
8866             ptr++;
8867 
8868             if (color_type == util_enclosure_color_rgb) {
8869                 mDNSPlatformMemCopy(ptr, MODEL_RGB_COLOR, MODEL_COLOR_LEN);
8870             } else {
8871                 mDNSPlatformMemCopy(ptr, MODEL_INDEX_COLOR, MODEL_COLOR_LEN);
8872             }
8873             ptr += MODEL_COLOR_LEN;
8874 
8875             mDNSPlatformMemCopy(ptr, color, len);
8876             ptr += len;
8877         }
8878     }
8879 
8880     return (mDNSu32)(ptr - bufferStart);
8881 }
8882 
8883 #if APPLE_OSX_mDNSResponder // Don't compile for dnsextd target
8884 
8885 // Use the scalar version of SameDomainLabel() by default
8886 mDNSlocal mDNSBool scalarSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b);
8887 mDNSlocal mDNSBool vectorSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b);
8888 mDNSlocal mDNSBool (*SameDomainLabelPointer)(const mDNSu8 *a, const mDNSu8 *b) = scalarSameDomainLabel;
8889 
8890 #include <System/machine/cpu_capabilities.h>
8891 // `address_space(1)` attribute opts access out of ASan instrumentation see rdar://problem/68953642 .
8892 #define _cpu_capabilities   ((__attribute__((address_space(1))) uint32_t*) _COMM_PAGE_CPU_CAPABILITIES)[0]
8893 
8894 #if __arm64__ || __arm__
8895 #include <arm_neon.h>
8896 
8897 // Cache line aligned table that returns 32 for the upper case letters.
8898 // This will take up 4 cache lines.
8899 static const __attribute__ ((aligned(64))) uint8_t upper_to_lower_case_table[256] = {
8900     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8901     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8902     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8903     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8904     0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
8905     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
8906     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8907     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8908     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8909     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8910     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8911     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8912     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8913     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8914     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8915     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
8916 };
8917 
8918 // Neon version
vectorSameDomainLabel(const mDNSu8 * a,const mDNSu8 * b)8919 mDNSlocal mDNSBool vectorSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
8920 {
8921     const int len = *a++;
8922 
8923     if (len > MAX_DOMAIN_LABEL)
8924     {
8925         fprintf(stderr, "v: Malformed label (too long)\n");
8926         return(mDNSfalse);
8927     }
8928 
8929     if (len != *b++)
8930     {
8931         return(mDNSfalse);
8932     }
8933 
8934     uint32_t len_count = len;
8935 
8936     uint8x16_t vA, vB, vARotated, vBRotated, vMaskA, vMaskB;
8937 
8938     uint8x16_t v32 = vdupq_n_u8(32);
8939     uint8x16_t v37 = vdupq_n_u8(37);
8940     uint8x16_t v101 = vdupq_n_u8(101);
8941 #if !defined __arm64__
8942     uint32x4_t vtemp32;
8943     uint32x2_t vtemp32d;
8944     uint32_t sum;
8945 #endif
8946 
8947     while(len_count > 15)
8948     {
8949         vA = vld1q_u8(a);
8950         vB = vld1q_u8(b);
8951         a += 16;
8952         b += 16;
8953 
8954         //Make vA to lowercase if there is any uppercase.
8955         vARotated = vaddq_u8(vA, v37);            //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
8956         vMaskA    = vcgtq_s8(vARotated, v101);    //Check if anything is greater than '101' which means we have uppercase letters.
8957         vMaskA    = vandq_u8(vMaskA, v32);        //Prepare 32 for the elements with uppercase letters.
8958         vA        = vaddq_u8(vA, vMaskA);         //Add 32 only to the uppercase letters to make them lowercase letters.
8959 
8960         //Make vB to lowercase if there is any uppercase.
8961         vBRotated = vaddq_u8(vB, v37);            //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
8962         vMaskB    = vcgtq_s8(vBRotated, v101);    //Check if anything is greater than '101' which means we have uppercase letters.
8963         vMaskB    = vandq_u8(vMaskB, v32);        //Prepare 32 for the elements with uppercase letters.
8964         vB        = vaddq_u8(vB, vMaskB);         //Add 32 only to the uppercase letters to make them lowercase letters.
8965 
8966         //Compare vA & vB
8967         vA = vceqq_u8(vA, vB);
8968 
8969 #if defined __arm64__
8970         //View 8-bit element as 32-bit => a3 a2 a1 a0
8971         //If min of 4 32-bit values in vA is 0xffffffff, then it means we have 0xff for all 16.
8972         if(vminvq_u32(vA) != 0xffffffffU)
8973         {
8974             return(mDNSfalse);
8975 
8976         }
8977 #else
8978         //See if any element was not same.
8979         //View 8-bit element as 16-bit => a7 a6 a5 a4  a3 a2 a1 a0
8980         //(a7+a6) (a5+a4) (a3+a2) (a1+a0) => Each will be 0xffff + 0xffff = 0x0001fffe when all same.
8981         vtemp32  = vpaddlq_u16(vA);
8982         vtemp32d = vpadd_u32(vget_low_u32(vtemp32), vget_high_u32(vtemp32));
8983         vtemp32d = vpadd_u32(vtemp32d, vtemp32d);
8984         sum      = vget_lane_u32(vtemp32d, 0);
8985 
8986         //0x0001fffe + 0x0001fffe + 0x0001fffe + 0x0001fffe = 0x0007fff8U when all same.
8987         if(sum != 0x0007fff8U)
8988         {
8989             return(mDNSfalse);
8990         }
8991 #endif
8992 
8993         len_count -= 16;
8994     }
8995 
8996     uint8x8_t vAd, vBd, vARotatedd, vBRotatedd, vMaskAd, vMaskBd;
8997 
8998     uint8x8_t v32d = vdup_n_u8(32);
8999     uint8x8_t v37d = vdup_n_u8(37);
9000     uint8x8_t v101d = vdup_n_u8(101);
9001 
9002     while(len_count > 7)
9003     {
9004         vAd = vld1_u8(a);
9005         vBd = vld1_u8(b);
9006         a += 8;
9007         b += 8;
9008 
9009         //Make vA to lowercase if there is any uppercase.
9010         vARotatedd = vadd_u8(vAd, v37d);            //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
9011         vMaskAd    = vcgt_s8(vARotatedd, v101d);    //Check if anything is greater than '101' which means we have uppercase letters.
9012         vMaskAd    = vand_u8(vMaskAd, v32d);        //Prepare 32 for the elements with uppercase letters.
9013         vAd        = vadd_u8(vAd, vMaskAd);         //Add 32 only to the uppercase letters to make them lowercase letters.
9014 
9015         //Make vB to lowercase if there is any uppercase.
9016         vBRotatedd = vadd_u8(vBd, v37d);            //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
9017         vMaskBd    = vcgt_s8(vBRotatedd, v101d);    //Check if anything is greater than '101' which means we have uppercase letters.
9018         vMaskBd    = vand_u8(vMaskBd, v32d);        //Prepare 32 for the elements with uppercase letters.
9019         vBd        = vadd_u8(vBd, vMaskBd);         //Add 32 only to the uppercase letters to make them lowercase letters.
9020 
9021         //Compare vA & vB
9022         vAd = vceq_u8(vAd, vBd);
9023 
9024 #if defined __arm64__
9025         //View 8-bit element as 32-bit => a1 a0
9026         //If min of 2 32-bit values in vAd is 0xffffffff, then it means we have 0xff for all 16.
9027         if(vminv_u32(vAd) != 0xffffffffU)
9028         {
9029             return(mDNSfalse);
9030 
9031         }
9032 #else
9033         //See if any element was not same.
9034         //View 8-bit element as 16-bit => a3 a2 a1 a0
9035         //(a3+a2) (a1+a0) => Each will be 0xffff + 0xffff = 0x0001fffe when all same.
9036         vtemp32d = vpaddl_u16(vAd);
9037         vtemp32d = vpadd_u32(vtemp32d, vtemp32d);
9038         sum      = vget_lane_u32(vtemp32d, 0);
9039 
9040         //0x0001fffe + 0x0001fffe = 0x0003fffc when all same.
9041         if(sum != 0x0003fffcU)
9042         {
9043             return(mDNSfalse);
9044         }
9045 #endif
9046 
9047         len_count -= 8;
9048     }
9049 
9050     while(len_count > 0)
9051     {
9052         mDNSu8 ac = *a++;
9053         mDNSu8 bc = *b++;
9054 
9055         ac += upper_to_lower_case_table[ac];
9056         bc += upper_to_lower_case_table[bc];
9057 
9058         if (ac != bc)
9059         {
9060             return(mDNSfalse);
9061         }
9062 
9063         len_count -= 1;
9064     }
9065     return(mDNStrue);
9066 }
9067 
9068 // Use vectorized implementation if it is supported on this platform.
setSameDomainLabelPointer(void)9069 mDNSlocal void setSameDomainLabelPointer(void)
9070 {
9071     if(_cpu_capabilities & kHasNeon)
9072     {
9073         // Use Neon Code
9074         SameDomainLabelPointer = vectorSameDomainLabel;
9075         LogMsg("setSameDomainLabelPointer: using vector code");
9076     }
9077     else
9078         LogMsg("setSameDomainLabelPointer: using scalar code");
9079 }
9080 #endif // __arm64__ || __arm__
9081 
9082 #if __x86_64__
9083 #include <smmintrin.h>
9084 
9085 // Cache line aligned table that returns 32 for the upper case letters.
9086 // This will take up 4 cache lines.
9087 static const __attribute__ ((aligned(64))) uint8_t upper_to_lower_case_table[256] = {
9088     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9089     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9090     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9091     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9092     0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
9093     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
9094     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9095     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9096     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9097     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9098     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9099     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9100     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9101     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9102     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9103     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
9104 };
9105 
9106 // SSE2 version
vectorSameDomainLabel(const mDNSu8 * a,const mDNSu8 * b)9107 mDNSlocal mDNSBool vectorSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
9108 {
9109     const int len = *a++;
9110 
9111     if (len > MAX_DOMAIN_LABEL)
9112     {
9113         fprintf(stderr, "v: Malformed label (too long)\n");
9114         return(mDNSfalse);
9115     }
9116 
9117     if (len != *b++)
9118     {
9119         return(mDNSfalse);
9120     }
9121 
9122     uint32_t len_count = len;
9123 
9124     static const __attribute__ ((aligned(16))) unsigned char c_32[16] = { 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32 };
9125     static const __attribute__ ((aligned(16))) unsigned char c_37[16] = { 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37 };
9126     static const __attribute__ ((aligned(16))) unsigned char c_101[16] = { 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101 };
9127     __m128i v37  = _mm_load_si128((__m128i*)c_37);
9128     __m128i v101 = _mm_load_si128((__m128i*)c_101);
9129     __m128i v32  = _mm_load_si128((__m128i*)c_32);
9130 
9131     uint32_t is_equal;
9132     __m128i vA, vB, vARotated, vBRotated, vMaskA, vMaskB;
9133 
9134     //AVX code that uses higher bandwidth (more elements per vector) was removed
9135     //to speed up the processing on the small sizes.
9136     //When I had them, the performance of 1 ~ 8 characters were slower by about 10% ~ 30%.
9137     while(len_count > 15)
9138     {
9139         vA = _mm_loadu_si128((__m128i*)a);
9140         vB = _mm_loadu_si128((__m128i*)b);
9141         a += 16;
9142         b += 16;
9143 
9144         //Make vA to lowercase if there is any uppercase.
9145         vARotated = _mm_add_epi8(vA, v37);              //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
9146         vMaskA    = _mm_cmpgt_epi8(vARotated, v101);    //Check if anything is greater than '101' which means we have uppercase letters.
9147         vMaskA    = _mm_and_si128(vMaskA, v32);         //Prepare 32 for the elements with uppercase letters.
9148         vA        = _mm_add_epi8(vA, vMaskA);           //Add 32 only to the uppercase letters to make them lowercase letters.
9149 
9150         //Make vB to lowercase if there is any uppercase.
9151         vBRotated = _mm_add_epi8(vB, v37);              //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
9152         vMaskB    = _mm_cmpgt_epi8(vBRotated, v101);    //Check if anything is greater than '101' which means we have uppercase letters.
9153         vMaskB    = _mm_and_si128(vMaskB, v32);         //Prepare 32 for the elements with uppercase letters.
9154         vB        = _mm_add_epi8(vB, vMaskB);           //Add 32 only to the uppercase letters to make them lowercase letters.
9155 
9156         //Compare vA & vB
9157         vA = _mm_cmpeq_epi8(vA, vB);
9158 
9159         //Return if any different.
9160         is_equal = _mm_movemask_epi8(vA);
9161         is_equal = is_equal & 0xffff;
9162         if(is_equal != 0xffff)
9163         {
9164             return(mDNSfalse);
9165         }
9166 
9167         len_count -= 16;
9168     }
9169 
9170     while(len_count > 0)
9171     {
9172         mDNSu8 ac = *a++;
9173         mDNSu8 bc = *b++;
9174 
9175         //Table will return 32 for upper case letters only.
9176         //0 will be returned for all others.
9177         ac += upper_to_lower_case_table[ac];
9178         bc += upper_to_lower_case_table[bc];
9179 
9180         //Return if a & b are different.
9181         if (ac != bc)
9182         {
9183             return(mDNSfalse);
9184         }
9185 
9186         len_count -= 1;
9187     }
9188     return(mDNStrue);
9189 }
9190 
9191 // Use vectorized implementation if it is supported on this platform.
setSameDomainLabelPointer(void)9192 mDNSlocal void setSameDomainLabelPointer(void)
9193 {
9194     if(_cpu_capabilities & kHasSSE4_1)
9195     {
9196         // Use SSE Code
9197         SameDomainLabelPointer = vectorSameDomainLabel;
9198         LogMsg("setSameDomainLabelPointer: using vector code");
9199     }
9200     else
9201         LogMsg("setSameDomainLabelPointer: using scalar code");
9202 }
9203 #endif // __x86_64__
9204 
9205 // Original SameDomainLabel() implementation.
scalarSameDomainLabel(const mDNSu8 * a,const mDNSu8 * b)9206 mDNSlocal mDNSBool scalarSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
9207 {
9208     int i;
9209     const int len = *a++;
9210 
9211     if (len > MAX_DOMAIN_LABEL)
9212     { debugf("Malformed label (too long)"); return(mDNSfalse); }
9213 
9214     if (len != *b++) return(mDNSfalse);
9215     for (i=0; i<len; i++)
9216     {
9217         mDNSu8 ac = *a++;
9218         mDNSu8 bc = *b++;
9219         if (mDNSIsUpperCase(ac)) ac += 'a' - 'A';
9220         if (mDNSIsUpperCase(bc)) bc += 'a' - 'A';
9221         if (ac != bc) return(mDNSfalse);
9222     }
9223     return(mDNStrue);
9224 }
9225 
SameDomainLabel(const mDNSu8 * a,const mDNSu8 * b)9226 mDNSexport mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
9227 {
9228     return (*SameDomainLabelPointer)(a, b);
9229 }
9230 
9231 #endif // APPLE_OSX_mDNSResponder
9232 
9233 #if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
GetRandomUUIDLabel(domainlabel * label)9234 mDNSexport void GetRandomUUIDLabel(domainlabel *label)
9235 {
9236     uuid_t uuid;
9237     uuid_string_t uuidStr;
9238     uuid_generate_random(uuid);
9239     uuid_unparse_lower(uuid, uuidStr);
9240     MakeDomainLabelFromLiteralString(label, uuidStr);
9241 }
9242 
GetRandomUUIDLocalHostname(domainname * hostname)9243 mDNSexport void GetRandomUUIDLocalHostname(domainname *hostname)
9244 {
9245     domainlabel uuidLabel;
9246     GetRandomUUIDLabel(&uuidLabel);
9247     hostname->c[0] = 0;
9248     AppendDomainLabel(hostname, &uuidLabel);
9249     AppendLiteralLabelString(hostname, "local");
9250 }
9251 #endif
9252 
9253 #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
uDNSMetricsClear(uDNSMetrics * const metrics)9254 mDNSexport void uDNSMetricsClear(uDNSMetrics *const metrics)
9255 {
9256     if (metrics->originalQName)
9257     {
9258         mDNSPlatformMemFree(metrics->originalQName);
9259         metrics->originalQName = mDNSNULL;
9260     }
9261     mDNSPlatformMemZero(metrics, (mDNSu32)sizeof(*metrics));
9262 }
9263 #endif
9264 
9265 #ifdef UNIT_TEST
9266 #include "../unittests/mdns_macosx_ut.c"
9267 #endif
9268