2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
25 $Log: mDNSMacOSX.c,v $
26 Revision 1.115.2.4 2004/04/23 00:34:06 cheshire
27 <rdar://problem/3628978>: mDNSResponder messages on wake
28 Take care to correctly update InterfaceIDs when a dormant interface comes back to life
30 Revision 1.115.2.3 2004/04/08 23:18:11 cheshire
31 <rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
32 Refinement from Bob Bradley: Should use "mDNS *const m" instead of referencing mDNSStorage directly
34 Revision 1.115.2.2 2004/04/08 00:42:37 cheshire
35 <rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
36 Unify use of the InterfaceID field, and make code that walks the list respect the CurrentlyActive flag
38 Revision 1.115.2.1 2004/04/07 01:08:15 cheshire
39 <rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
41 Revision 1.115 2003/09/10 00:45:55 cheshire
42 <rdar://problem/3412328> Don't log "sendto failed" errors during the first two minutes of startup
44 Revision 1.114 2003/08/27 02:55:13 cheshire
45 <rdar://problem/3387910>: Bug: Don't report mDNSPlatformSendUDP sendto errno 64 (Host is down)
47 Revision 1.113 2003/08/19 22:20:00 cheshire
48 <rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
49 More minor refinements
51 Revision 1.112 2003/08/19 03:04:43 cheshire
52 <rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
54 Revision 1.111 2003/08/18 22:53:37 cheshire
55 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformTimeNow()
57 Revision 1.110 2003/08/16 03:39:00 cheshire
58 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
60 Revision 1.109 2003/08/15 02:19:49 cheshire
61 <rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
62 Also limit number of messages to at most 100
64 Revision 1.108 2003/08/12 22:24:52 cheshire
65 <rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
66 This message indicates a kernel bug, but still we don't want to flood syslog.
67 Do a sleep(1) after writing this log message, to limit the rate.
69 Revision 1.107 2003/08/12 19:56:25 cheshire
72 Revision 1.106 2003/08/12 13:48:32 cheshire
73 Add comment explaining clockdivisor calculation
75 Revision 1.105 2003/08/12 13:44:14 cheshire
76 <rdar://problem/3370229> mDNSResponder *VERY* unhappy if time goes backwards
77 Use mach_absolute_time() (which is guaranteed to always go forwards, resetting only on reboot)
78 instead of gettimeofday() (which can jump back if the user manually changes their time/date)
80 Revision 1.104 2003/08/12 13:12:07 cheshire
81 Textual search/replace: Indicate local functions using "mDNSlocal" instead of "static"
83 Revision 1.103 2003/08/08 18:36:04 cheshire
84 <rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
86 Revision 1.102 2003/08/06 00:14:52 cheshire
87 <rdar://problem/3330324> Need to check IP TTL on responses
88 Also add corresponding checks in the IPv6 code path
90 Revision 1.101 2003/08/05 22:20:16 cheshire
91 <rdar://problem/3330324> Need to check IP TTL on responses
93 Revision 1.100 2003/08/05 21:18:50 cheshire
94 <rdar://problem/3363185> mDNSResponder should ignore 6to4
95 Only use interfaces that are marked as multicast-capable (IFF_MULTICAST)
97 Revision 1.99 2003/08/05 20:13:52 cheshire
98 <rdar://problem/3294080> mDNSResponder using IPv6 interfaces before they are ready
99 Ignore interfaces with the IN6_IFF_NOTREADY flag set
101 Revision 1.98 2003/07/20 03:38:51 ksekar
103 Completed support for Unix-domain socket based API.
105 Revision 1.97 2003/07/19 03:15:16 cheshire
106 Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
107 and add the obvious trivial implementations to each platform support layer
109 Revision 1.96 2003/07/18 00:30:00 cheshire
110 <rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
112 Revision 1.95 2003/07/12 03:15:20 cheshire
113 <rdar://problem/3324848> After SCDynamicStore notification, mDNSResponder updates
114 m->hostlabel even if user hasn't actually actually changed their dot-local hostname
116 Revision 1.94 2003/07/03 00:51:54 cheshire
117 <rdar://problem/3287213> When select() and recvmgs() disagree, get more info from kernel about the socket state
119 Revision 1.93 2003/07/03 00:09:14 cheshire
120 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
121 Additional refinement suggested by Josh: Use info->scope_id instead of if_nametoindex(info->ifa_name);
123 Revision 1.92 2003/07/02 21:19:51 cheshire
124 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
126 Revision 1.91 2003/06/24 01:53:51 cheshire
127 Minor update to comments
129 Revision 1.90 2003/06/24 01:51:47 cheshire
130 <rdar://problem/3303118> Oops: Double-dispose of sockets
131 Don't need to close sockets: CFSocketInvalidate() does that for us
133 Revision 1.89 2003/06/21 18:12:47 cheshire
134 <rdar://problem/3296061> Rendezvous cannot handle interfaces whose total name is >3 chars
135 One-line change: should say "IF_NAMESIZE", not sizeof(ifname)
137 Revision 1.88 2003/06/12 23:38:37 cheshire
138 <rdar://problem/3291162> mDNSResponder doesn't detect some configuration changes
139 Also check that scope_id matches before concluding that two interfaces are the same
141 Revision 1.87 2003/06/10 01:14:11 cheshire
142 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
144 Revision 1.86 2003/05/28 02:41:52 cheshire
145 <rdar://problem/3034346> Time to remove Mac OS 9 UDP Port 53 legacy support
147 Revision 1.85 2003/05/28 02:39:47 cheshire
148 Minor change to debugging messages
150 Revision 1.84 2003/05/27 22:29:40 cheshire
151 Remove out-dated comment
153 Revision 1.83 2003/05/26 03:21:29 cheshire
154 Tidy up address structure naming:
155 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
156 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
157 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
159 Revision 1.82 2003/05/26 03:01:27 cheshire
160 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
162 Revision 1.81 2003/05/24 02:06:42 cheshire
163 <rdar://problem/3268480> IPv6 Multicast Loopback doesn't work
164 Tried setting IPV6_MULTICAST_LOOP; it doesn't help.
165 However, it is probably wise to have the code explicitly set this socket
166 option anyway, in case the default changes in later versions of Unix.
168 Revision 1.80 2003/05/24 02:02:24 cheshire
169 <rdar://problem/3221880> if_indextoname consumes a lot of CPU
170 Fix error in myIfIndexToName; was returning prematurely
172 Revision 1.79 2003/05/23 23:07:44 cheshire
173 <rdar://problem/3268199> Must not write to stderr when running as daemon
175 Revision 1.78 2003/05/23 01:19:04 cheshire
176 <rdar://problem/3267085> mDNSResponder needs to signal type of service to AirPort
177 Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
179 Revision 1.77 2003/05/23 01:12:05 cheshire
182 Revision 1.76 2003/05/22 01:26:01 cheshire
185 Revision 1.75 2003/05/22 00:07:09 cheshire
186 <rdar://problem/3264366> myCFSocketCallBack recvfrom(5) error 1, errno 35
187 Extra logging to determine whether there is a bug in CFSocket
189 Revision 1.74 2003/05/21 20:20:12 cheshire
190 Fix warnings (mainly printf format string warnings, like using "%d" where
191 it should say "%lu", etc.) and improve error logging (use strerror()
192 to include textual error message as well as numeric error in log messages).
194 Revision 1.73 2003/05/21 17:56:29 ksekar
195 Bug #: <rdar://problem/3191277>: mDNSResponder doesn't watch for IPv6 address changes
197 Revision 1.72 2003/05/14 18:48:41 cheshire
198 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
199 More minor refinements:
200 CFSocket.c needs to do *all* its mDNS_DeregisterInterface calls before freeing memory
201 mDNS_DeregisterInterface revalidates cache record when *any* representative of an interface goes away
203 Revision 1.71 2003/05/14 07:08:37 cheshire
204 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
205 Previously, when there was any network configuration change, mDNSResponder
206 would tear down the entire list of active interfaces and start again.
207 That was very disruptive, and caused the entire cache to be flushed,
208 and caused lots of extra network traffic. Now it only removes interfaces
209 that have really gone, and only adds new ones that weren't there before.
211 Revision 1.70 2003/05/07 18:30:24 cheshire
212 Fix signed/unsigned comparison warning
214 Revision 1.69 2003/05/06 20:14:44 cheshire
217 Revision 1.68 2003/05/06 00:00:49 cheshire
218 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
220 Revision 1.67 2003/04/29 00:43:44 cheshire
221 Fix compiler warnings
223 Revision 1.66 2003/04/26 02:41:58 cheshire
224 <rdar://problem/3241281> Change timenow from a local variable to a structure member
226 Revision 1.65 2003/04/26 02:34:01 cheshire
227 Add missing mDNSexport
229 Revision 1.64 2003/04/15 16:48:06 jgraessl
231 Modified code in CFSocket notifier function to read all packets on the socket
232 instead of reading only one packet every time the notifier was called.
234 Revision 1.63 2003/04/15 16:33:50 jgraessl
236 Switched to our own copy of if_indextoname to improve performance.
238 Revision 1.62 2003/03/28 01:55:44 cheshire
239 Minor improvements to debugging messages
241 Revision 1.61 2003/03/27 03:30:56 cheshire
242 <rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
243 Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
245 1. Make mDNS_DeregisterInterface() safe to call from a callback
246 2. Make HostNameCallback() use mDNS_DeadvertiseInterface() instead
247 (it never really needed to deregister the interface at all)
249 Revision 1.60 2003/03/15 04:40:38 cheshire
250 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
252 Revision 1.59 2003/03/11 01:23:26 cheshire
253 Bug #: 3194246 mDNSResponder socket problems
255 Revision 1.58 2003/03/06 01:43:04 cheshire
256 Bug #: 3189097 Additional debugging code in mDNSResponder
257 Improve "LIST_ALL_INTERFACES" output
259 Revision 1.57 2003/03/05 22:36:27 cheshire
260 Bug #: 3186338 Loopback doesn't work with mDNSResponder-27
261 Temporary workaround: Skip loopback interface *only* if we found at least one v4 interface to use
263 Revision 1.56 2003/03/05 01:50:38 cheshire
264 Bug #: 3189097 Additional debugging code in mDNSResponder
266 Revision 1.55 2003/02/21 01:54:09 cheshire
267 Bug #: 3099194 mDNSResponder needs performance improvements
268 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
270 Revision 1.54 2003/02/20 06:48:35 cheshire
271 Bug #: 3169535 Xserve RAID needs to do interface-specific registrations
272 Reviewed by: Josh Graessley, Bob Bradley
274 Revision 1.53 2003/01/29 02:21:23 cheshire
275 Return mStatus_Invalid if can't send packet because socket not available
277 Revision 1.52 2003/01/28 19:39:43 jgraessl
278 Enabling AAAA over IPv4 support.
280 Revision 1.51 2003/01/28 05:11:23 cheshire
281 Fixed backwards comparison in SearchForInterfaceByName
283 Revision 1.50 2003/01/13 23:49:44 jgraessl
284 Merged changes for the following fixes in to top of tree:
285 3086540 computer name changes not handled properly
286 3124348 service name changes are not properly handled
287 3124352 announcements sent in pairs, failing chattiness test
289 Revision 1.49 2002/12/23 22:13:30 jgraessl
290 Reviewed by: Stuart Cheshire
291 Initial IPv6 support for mDNSResponder.
293 Revision 1.48 2002/11/22 01:37:52 cheshire
294 Bug #: 3108426 mDNSResponder is monitoring ServiceEntities instead of InterfaceEntities
296 Revision 1.47 2002/09/21 20:44:51 zarzycki
299 Revision 1.46 2002/09/19 21:25:35 cheshire
300 mDNS_snprintf() doesn't need to be in a separate file
302 Revision 1.45 2002/09/17 01:45:13 cheshire
303 Add LIST_ALL_INTERFACES symbol for debugging
305 Revision 1.44 2002/09/17 01:36:23 cheshire
306 Move Puma support to CFSocketPuma.c
308 Revision 1.43 2002/09/17 01:05:28 cheshire
309 Change mDNS_AdvertiseLocalAddresses to be an Init parameter instead of a global
311 Revision 1.42 2002/09/16 23:13:50 cheshire
316 // ***************************************************************************
318 // Supporting routines to run mDNS on a CFRunLoop platform
319 // ***************************************************************************
321 // Open Transport 2.7.x on Mac OS 9 used to send Multicast DNS queries to UDP port 53,
322 // before the Multicast DNS port was changed to 5353. For this reason, the mDNSResponder
323 // in earlier versions of Mac OS X 10.2 Jaguar used to set mDNS_AllowPort53 to 1 to allow
324 // it to also listen and answer queries on UDP port 53. Now that Transport 2.8 (included in
325 // the Classic subsystem of Mac OS X 10.2 Jaguar) has been corrected to issue Multicast DNS
326 // queries on UDP port 5353, this backwards-compatibility legacy support is no longer needed.
327 #define mDNS_AllowPort53 0
329 // For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
330 // including ones that mDNSResponder chooses not to use.
331 #define LIST_ALL_INTERFACES 0
333 // For enabling AAAA records over IPv4. Setting this to 0 sends only
334 // A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both
335 // AAAA and A records over both IPv4 and IPv6.
336 #define AAAA_OVER_V4 1
338 #include "mDNSClientAPI.h" // Defines the interface provided to the client layer above
339 #include "mDNSPlatformFunctions.h" // Defines the interface to the supporting layer below
340 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
343 #include <unistd.h> // For select() and close()
344 #include <stdarg.h> // For va_list support
346 #include <net/if_dl.h>
348 #include <sys/param.h>
349 #include <sys/socket.h>
350 #include <sys/sysctl.h>
352 #include <sys/ioctl.h>
354 #include <netinet/in.h> // For IP_RECVTTL
356 #define IP_RECVTTL 24 /* bool; receive reception TTL w/dgram */
359 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
360 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
361 #include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
363 // Code contributed by Dave Heller:
364 // Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
365 // work on Mac OS X 10.1, which does not have the getifaddrs call.
366 #define RUN_ON_PUMA_WITHOUT_IFADDRS 0
367 #if RUN_ON_PUMA_WITHOUT_IFADDRS
368 #include "CFSocketPuma.c"
373 #include <IOKit/IOKitLib.h>
374 #include <IOKit/IOMessage.h>
375 #include <mach/mach_time.h>
377 // ***************************************************************************
380 static mDNSu32 clockdivisor
= 0;
382 // ***************************************************************************
385 #define mDNSSameIPv4Address(A,B) ((A).NotAnInteger == (B).NotAnInteger)
386 #define mDNSSameIPv6Address(A,B) ((A).l[0] == (B).l[0] && (A).l[1] == (B).l[1] && (A).l[2] == (B).l[2] && (A).l[3] == (B).l[3])
388 #define mDNSAddressIsAllDNSLinkGroup(X) ( \
389 ((X)->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address((X)->ip.v4, AllDNSLinkGroup )) || \
390 ((X)->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address((X)->ip.v6, AllDNSLinkGroupv6)) )
392 // ***************************************************************************
395 // Note, this uses mDNS_vsnprintf instead of standard "vsnprintf", because mDNS_vsnprintf knows
396 // how to print special data types like IP addresses and length-prefixed domain names
398 mDNSexport
void debugf_(const char *format
, ...)
400 unsigned char buffer
[512];
402 va_start(ptr
,format
);
403 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
405 fprintf(stderr
,"%s\n", buffer
);
410 #if MDNS_DEBUGMSGS > 1
411 mDNSexport
void verbosedebugf_(const char *format
, ...)
413 unsigned char buffer
[512];
415 va_start(ptr
,format
);
416 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
418 fprintf(stderr
,"%s\n", buffer
);
423 mDNSexport
void LogMsg(const char *format
, ...)
425 unsigned char buffer
[512];
427 va_start(ptr
,format
);
428 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
431 extern int debug_mode
;
432 if (debug_mode
) // In debug_mode we write to stderr
434 fprintf(stderr
,"%s\n", buffer
);
437 else // else, in production mode, we write to syslog
439 openlog("mDNSResponder", LOG_CONS
| LOG_PERROR
| LOG_PID
, LOG_DAEMON
);
440 syslog(LOG_ERR
, "%s", buffer
);
445 mDNSlocal
struct ifaddrs
* myGetIfAddrs(int refresh
)
447 static struct ifaddrs
*ifa
= NULL
;
455 if (ifa
== NULL
) getifaddrs(&ifa
);
460 mDNSlocal
int myIfIndexToName(u_short index
, char* name
)
463 for (ifa
= myGetIfAddrs(0); ifa
; ifa
= ifa
->ifa_next
)
464 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
465 if (((struct sockaddr_dl
*)ifa
->ifa_addr
)->sdl_index
== index
)
466 { strncpy(name
, ifa
->ifa_name
, IF_NAMESIZE
); return 0; }
470 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS
*const m
, mDNSu32 index
)
472 NetworkInterfaceInfoOSX
*i
;
473 if (index
== (uint32_t)~0) return((mDNSInterfaceID
)~0);
475 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
476 if (i
->ifinfo
.InterfaceID
&& i
->scope_id
== index
) // Don't get tricked by inactive interfaces
477 return(i
->ifinfo
.InterfaceID
);
481 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS
*const m
, mDNSInterfaceID id
)
483 NetworkInterfaceInfoOSX
*i
;
484 if (id
== (mDNSInterfaceID
)~0) return((mDNSu32
)~0);
486 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
487 // Don't use i->ifinfo.InterfaceID here because we want to find inactive interfaces where that's not set
488 if ((mDNSInterfaceID
)i
== id
)
493 mDNSexport mStatus
mDNSPlatformSendUDP(const mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
,
494 mDNSInterfaceID InterfaceID
, mDNSIPPort srcPort
, const mDNSAddr
*dst
, mDNSIPPort dstPort
)
497 NetworkInterfaceInfoOSX
*info
= (NetworkInterfaceInfoOSX
*)InterfaceID
;
498 struct sockaddr_storage to
;
501 if (!InterfaceID
) { LogMsg("mDNSPlatformSendUDP ERROR! Cannot send from zero InterfaceID"); return mStatus_BadParamErr
; }
503 if (dst
->type
== mDNSAddrType_IPv4
)
505 struct sockaddr_in
* sin_to
= (struct sockaddr_in
*)&to
;
506 sin_to
->sin_len
= sizeof(*sin_to
);
507 sin_to
->sin_family
= AF_INET
;
508 sin_to
->sin_port
= dstPort
.NotAnInteger
;
509 sin_to
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
511 else if (dst
->type
== mDNSAddrType_IPv6
)
513 struct sockaddr_in6
* sin6_to
= (struct sockaddr_in6
*)&to
;
514 sin6_to
->sin6_len
= sizeof(*sin6_to
);
515 sin6_to
->sin6_family
= AF_INET6
;
516 sin6_to
->sin6_port
= dstPort
.NotAnInteger
;
517 sin6_to
->sin6_flowinfo
= 0;
518 sin6_to
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
519 sin6_to
->sin6_scope_id
= info
->scope_id
;
523 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!\n");
524 return mStatus_BadParamErr
;
527 if (srcPort
.NotAnInteger
== MulticastDNSPort
.NotAnInteger
)
529 if (dst
->type
== mDNSAddrType_IPv4
) s
= info
->sktv4
;
530 else if (dst
->type
== mDNSAddrType_IPv6
) s
= info
->sktv6
;
534 else if (srcPort
.NotAnInteger
== UnicastDNSPort
.NotAnInteger
&& dst
->type
== mDNSAddrType_IPv4
)
537 else { LogMsg("Source port %d not allowed", (mDNSu16
)srcPort
.b
[0]<<8 | srcPort
.b
[1]); return(-1); }
540 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %X %s/%d to %#a:%d skt %d",
541 InterfaceID
, info
->ifa_name
, dst
->type
, dst
, (mDNSu16
)dstPort
.b
[0]<<8 | dstPort
.b
[1], s
);
543 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %X %s/%d (socket of this type not available)",
544 InterfaceID
, info
->ifa_name
, dst
->type
, dst
, (mDNSu16
)dstPort
.b
[0]<<8 | dstPort
.b
[1]);
546 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
547 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
548 if (s
< 0) return(mStatus_Invalid
);
550 err
= sendto(s
, msg
, (UInt8
*)end
- (UInt8
*)msg
, 0, (struct sockaddr
*)&to
, to
.ss_len
);
553 // Don't report EHOSTDOWN (i.e. ARP failure) to unicast destinations
554 if (errno
== EHOSTDOWN
&& !mDNSAddressIsAllDNSLinkGroup(dst
)) return(err
);
555 // Don't report EHOSTUNREACH in the first two minutes after boot
556 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
557 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
558 if (errno
== EHOSTUNREACH
&& (mDNSu32
)(m
->timenow
) < (mDNSu32
)(mDNSPlatformOneSecond
* 120)) return(err
);
559 LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %s/%ld to %#a:%d skt %d error %d errno %d (%s)",
560 InterfaceID
, info
->ifa_name
, dst
->type
, dst
, (mDNSu16
)dstPort
.b
[0]<<8 | dstPort
.b
[1], s
, err
, errno
, strerror(errno
));
564 return(mStatus_NoError
);
567 mDNSlocal ssize_t
myrecvfrom(const int s
, void *const buffer
, const size_t max
,
568 struct sockaddr
*const from
, size_t *const fromlen
, mDNSAddr
*dstaddr
, char ifname
[IF_NAMESIZE
], mDNSu8
*ttl
)
570 static unsigned int numLogMessages
= 0;
571 struct iovec databuffers
= { (char *)buffer
, max
};
574 struct cmsghdr
*cmPtr
;
575 char ancillary
[1024];
577 *ttl
= 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
579 // Set up the message
580 msg
.msg_name
= (caddr_t
)from
;
581 msg
.msg_namelen
= *fromlen
;
582 msg
.msg_iov
= &databuffers
;
584 msg
.msg_control
= (caddr_t
)&ancillary
;
585 msg
.msg_controllen
= sizeof(ancillary
);
589 n
= recvmsg(s
, &msg
, 0);
592 if (errno
!= EWOULDBLOCK
&& numLogMessages
++ < 100) LogMsg("CFSocket.c: recvmsg(%d) returned error %d errno %d", s
, n
, errno
);
595 if (msg
.msg_controllen
< (int)sizeof(struct cmsghdr
))
597 if (numLogMessages
++ < 100) LogMsg("CFSocket.c: recvmsg(%d) msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
598 s
, msg
.msg_controllen
, sizeof(struct cmsghdr
));
601 if (msg
.msg_flags
& MSG_CTRUNC
)
603 if (numLogMessages
++ < 100) LogMsg("CFSocket.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s
);
607 *fromlen
= msg
.msg_namelen
;
609 // Parse each option out of the ancillary data.
610 for (cmPtr
= CMSG_FIRSTHDR(&msg
); cmPtr
; cmPtr
= CMSG_NXTHDR(&msg
, cmPtr
))
612 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
613 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVDSTADDR
)
615 dstaddr
->type
= mDNSAddrType_IPv4
;
616 dstaddr
->ip
.v4
.NotAnInteger
= *(u_int32_t
*)CMSG_DATA(cmPtr
);
618 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVIF
)
620 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)CMSG_DATA(cmPtr
);
621 if (sdl
->sdl_nlen
< IF_NAMESIZE
)
623 mDNSPlatformMemCopy(sdl
->sdl_data
, ifname
, sdl
->sdl_nlen
);
624 ifname
[sdl
->sdl_nlen
] = 0;
625 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
628 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVTTL
)
630 *ttl
= *(u_char
*)CMSG_DATA(cmPtr
);
632 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_PKTINFO
)
634 struct in6_pktinfo
*ip6_info
= (struct in6_pktinfo
*)CMSG_DATA(cmPtr
);
635 dstaddr
->type
= mDNSAddrType_IPv6
;
636 dstaddr
->ip
.v6
= *(mDNSv6Addr
*)&ip6_info
->ipi6_addr
;
637 myIfIndexToName(ip6_info
->ipi6_ifindex
, ifname
);
639 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_HOPLIMIT
)
641 *ttl
= *(int*)CMSG_DATA(cmPtr
);
648 mDNSlocal
void myCFSocketCallBack(CFSocketRef cfs
, CFSocketCallBackType CallBackType
, CFDataRef address
, const void *data
, void *context
)
650 mDNSAddr senderAddr
, destAddr
;
651 mDNSIPPort senderPort
, destPort
= MulticastDNSPort
;
652 NetworkInterfaceInfoOSX
*info
= (NetworkInterfaceInfoOSX
*)context
;
653 mDNS
*const m
= info
->m
;
655 struct sockaddr_storage from
;
656 size_t fromlen
= sizeof(from
);
657 char packetifname
[IF_NAMESIZE
] = "";
658 int err
, s1
= -1, skt
= CFSocketGetNative(cfs
);
661 (void)address
; // Parameter not used
662 (void)data
; // Parameter not used
664 if (CallBackType
!= kCFSocketReadCallBack
) LogMsg("myCFSocketCallBack: Why is CallBackType %d not kCFSocketReadCallBack?", CallBackType
);
667 if (cfs
== info
->cfs53
) { s1
= info
->skt53
; destPort
= UnicastDNSPort
; }
670 if (cfs
== info
->cfsv4
) s1
= info
->sktv4
;
671 else if (cfs
== info
->cfsv6
) s1
= info
->sktv6
;
673 if (s1
< 0 || s1
!= skt
)
675 LogMsg("myCFSocketCallBack: s1 %d native socket %d, cfs %p", s1
, skt
, cfs
);
677 LogMsg("myCFSocketCallBack: cfs53 %p, skt53 %d", info
->cfs53
, info
->skt53
);
679 LogMsg("myCFSocketCallBack: cfsv4 %p, sktv4 %d", info
->cfsv4
, info
->sktv4
);
680 LogMsg("myCFSocketCallBack: cfsv6 %p, sktv6 %d", info
->cfsv6
, info
->sktv6
);
684 while ((err
= myrecvfrom(s1
, &packet
, sizeof(packet
), (struct sockaddr
*)&from
, &fromlen
, &destAddr
, packetifname
, &ttl
)) >= 0)
687 if (from
.ss_family
== AF_INET
)
689 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&from
;
690 senderAddr
.type
= mDNSAddrType_IPv4
;
691 senderAddr
.ip
.v4
.NotAnInteger
= sin
->sin_addr
.s_addr
;
692 senderPort
.NotAnInteger
= sin
->sin_port
;
694 else if (from
.ss_family
== AF_INET6
)
696 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&from
;
697 senderAddr
.type
= mDNSAddrType_IPv6
;
698 senderAddr
.ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
699 senderPort
.NotAnInteger
= sin6
->sin6_port
;
703 LogMsg("myCFSocketCallBack from is unknown address family %d", from
.ss_family
);
707 // Even though we indicated a specific interface in the IP_ADD_MEMBERSHIP call, a weirdness of the
708 // sockets API means that even though this socket has only officially joined the multicast group
709 // on one specific interface, the kernel will still deliver multicast packets to it no matter which
710 // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
711 // To work around this weirdness, we use the IP_RECVIF option to find the name of the interface
712 // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
713 if (strcmp(info
->ifa_name
, packetifname
))
715 verbosedebugf("myCFSocketCallBack got a packet from %#a to %#a on interface %#a/%s (Ignored -- really arrived on interface %s)",
716 &senderAddr
, &destAddr
, &info
->ifinfo
.ip
, info
->ifa_name
, packetifname
);
720 verbosedebugf("myCFSocketCallBack got a packet from %#a to %#a on interface %#a/%s",
721 &senderAddr
, &destAddr
, &info
->ifinfo
.ip
, info
->ifa_name
);
723 if (err
< (int)sizeof(DNSMessageHeader
)) { debugf("myCFSocketCallBack packet length (%d) too short", err
); return; }
725 mDNSCoreReceive(m
, &packet
, (unsigned char*)&packet
+ err
, &senderAddr
, senderPort
, &destAddr
, destPort
, info
->ifinfo
.InterfaceID
, ttl
);
728 if (err
< 0 && (errno
!= EWOULDBLOCK
|| count
== 0))
730 // Something is busted here.
731 // CFSocket says there is a packet, but myrecvfrom says there is not.
732 // Try calling select() to get another opinion.
733 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
734 // All of this is racy, as data may have arrived after the call to select()
735 int save_errno
= errno
;
739 int solen
= sizeof(int);
742 FD_SET(s1
, &readfds
);
743 struct timeval timeout
;
746 int selectresult
= select(s1
+1, &readfds
, NULL
, NULL
, &timeout
);
747 if (getsockopt(s1
, SOL_SOCKET
, SO_ERROR
, &so_error
, &solen
) == -1)
748 LogMsg("myCFSocketCallBack getsockopt(SO_ERROR) error %d", errno
);
749 if (getsockopt(s1
, SOL_SOCKET
, SO_NREAD
, &so_nread
, &solen
) == -1)
750 LogMsg("myCFSocketCallBack getsockopt(SO_NREAD) error %d", errno
);
751 if (ioctl(s1
, FIONREAD
, &fionread
) == -1)
752 LogMsg("myCFSocketCallBack ioctl(FIONREAD) error %d", errno
);
753 static unsigned int numLogMessages
= 0;
754 if (numLogMessages
++ < 100)
755 LogMsg("myCFSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
756 s1
, err
, save_errno
, strerror(save_errno
), selectresult
, FD_ISSET(s1
, &readfds
) ? "" : "*NO* ", so_error
, so_nread
, fionread
, count
);
757 sleep(1); // After logging this error, rate limit so we don't flood syslog
761 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
762 mDNSlocal
void GetUserSpecifiedFriendlyComputerName(domainlabel
*const namelabel
)
764 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
765 CFStringRef cfs
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
768 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
773 // This gets the text of the field currently labelled "Rendezvous Name" in the Sharing Prefs Control Panel
774 mDNSlocal
void GetUserSpecifiedRFC1034ComputerName(domainlabel
*const namelabel
)
776 CFStringRef cfs
= SCDynamicStoreCopyLocalHostName(NULL
);
779 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
784 mDNSlocal mStatus
SetupSocket(NetworkInterfaceInfoOSX
*i
, mDNSIPPort port
, int *s
, CFSocketRef
*c
)
787 const int twofivefive
= 255;
789 if (*s
>= 0) { LogMsg("SetupSocket ERROR: socket %d is already set", *s
); return(-1); }
790 if (*c
) { LogMsg("SetupSocket ERROR: CFSocketRef %p is already set", *c
); return(-1); }
792 // Open the socket...
793 int skt
= socket(i
->sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
794 if (skt
< 0) { LogMsg("socket error %d errno %d (%s)", skt
, errno
, strerror(errno
)); return(skt
); }
796 // ... with a shared UDP port
797 mStatus err
= setsockopt(skt
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
798 if (err
< 0) { LogMsg("setsockopt - SO_REUSEPORT error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
800 if (i
->sa_family
== AF_INET
)
802 // We want to receive destination addresses
803 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVDSTADDR
, &on
, sizeof(on
));
804 if (err
< 0) { LogMsg("setsockopt - IP_RECVDSTADDR error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
806 // We want to receive interface identifiers
807 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
808 if (err
< 0) { LogMsg("setsockopt - IP_RECVIF error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
810 // We want to receive packet TTL value so we can check it
811 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVTTL
, &on
, sizeof(on
));
812 // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
814 // Add multicast group membership on this interface
815 struct in_addr addr
= { i
->ifinfo
.ip
.ip
.v4
.NotAnInteger
};
817 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroup
.NotAnInteger
;
818 imr
.imr_interface
= addr
;
819 err
= setsockopt(skt
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &imr
, sizeof(imr
));
820 if (err
< 0) { LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
822 // Specify outgoing interface too
823 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_IF
, &addr
, sizeof(addr
));
824 if (err
< 0) { LogMsg("setsockopt - IP_MULTICAST_IF error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
826 // Send unicast packets with TTL 255
827 err
= setsockopt(skt
, IPPROTO_IP
, IP_TTL
, &twofivefive
, sizeof(twofivefive
));
828 if (err
< 0) { LogMsg("setsockopt - IP_TTL error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
830 // And multicast packets with TTL 255 too
831 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_TTL
, &twofivefive
, sizeof(twofivefive
));
832 if (err
< 0) { LogMsg("setsockopt - IP_MULTICAST_TTL error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
834 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
835 const int ip_tosbits
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
;
836 err
= setsockopt(skt
, IPPROTO_IP
, IP_TOS
, &ip_tosbits
, sizeof(ip_tosbits
));
837 if (err
< 0) { LogMsg("setsockopt - IP_TOS error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
839 // And start listening for packets
840 struct sockaddr_in listening_sockaddr
;
841 listening_sockaddr
.sin_family
= AF_INET
;
842 listening_sockaddr
.sin_port
= port
.NotAnInteger
;
843 listening_sockaddr
.sin_addr
.s_addr
= 0; // Want to receive multicasts AND unicasts on this socket
844 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr
, sizeof(listening_sockaddr
));
847 // If we fail to bind to port 53 (because we're not root), that's okay, just tidy up and silently continue
848 if (port
.NotAnInteger
== UnicastDNSPort
.NotAnInteger
) { close(skt
); err
= 0; }
849 else LogMsg("bind error %ld errno %d (%s)", err
, errno
, strerror(errno
));
853 else if (i
->sa_family
== AF_INET6
)
855 // We want to receive destination addresses and receive interface identifiers
856 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_PKTINFO
, &on
, sizeof(on
));
857 if (err
< 0) { LogMsg("setsockopt - IPV6_PKTINFO error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
859 // We want to receive packet hop count value so we can check it
860 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_HOPLIMIT
, &on
, sizeof(on
));
861 if (err
< 0) { LogMsg("setsockopt - IPV6_HOPLIMIT error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
863 // We want to receive only IPv6 packets, without this option, we may
864 // get IPv4 addresses as mapped addresses.
865 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
));
866 if (err
< 0) { LogMsg("setsockopt - IPV6_V6ONLY error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
868 // Add multicast group membership on this interface
869 int interface_id
= if_nametoindex(i
->ifa_name
);
870 struct ipv6_mreq i6mr
;
871 i6mr
.ipv6mr_interface
= interface_id
;
872 i6mr
.ipv6mr_multiaddr
= *(struct in6_addr
*)&AllDNSLinkGroupv6
;
873 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &i6mr
, sizeof(i6mr
));
874 if (err
< 0) { LogMsg("setsockopt - IPV6_JOIN_GROUP error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
876 // Specify outgoing interface too
877 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &interface_id
, sizeof(interface_id
));
878 if (err
< 0) { LogMsg("setsockopt - IPV6_MULTICAST_IF error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
880 // Send unicast packets with TTL 255
881 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
882 if (err
< 0) { LogMsg("setsockopt - IPV6_UNICAST_HOPS error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
884 // And multicast packets with TTL 255 too
885 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
886 if (err
< 0) { LogMsg("setsockopt - IPV6_MULTICAST_HOPS error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
888 // Note: IPV6_TCLASS appears not to be implemented on OS X right now (or indeed on ANY version of Unix?)
890 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
891 int tclass
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
; // This may not be right (since tclass is not implemented on OS X, I can't test it)
892 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_TCLASS
, &tclass
, sizeof(tclass
));
893 if (err
< 0) { LogMsg("setsockopt - IPV6_TCLASS error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
896 // Want to receive our own packets
897 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &on
, sizeof(on
));
898 if (err
< 0) { LogMsg("setsockopt - IPV6_MULTICAST_LOOP error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
900 // And start listening for packets
901 struct sockaddr_in6 listening_sockaddr6
;
902 bzero(&listening_sockaddr6
, sizeof(listening_sockaddr6
));
903 listening_sockaddr6
.sin6_len
= sizeof(listening_sockaddr6
);
904 listening_sockaddr6
.sin6_family
= AF_INET6
;
905 listening_sockaddr6
.sin6_port
= port
.NotAnInteger
;
906 listening_sockaddr6
.sin6_flowinfo
= 0;
907 // listening_sockaddr6.sin6_addr = IN6ADDR_ANY_INIT; // Want to receive multicasts AND unicasts on this socket
908 listening_sockaddr6
.sin6_scope_id
= 0;
909 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr6
, sizeof(listening_sockaddr6
));
910 if (err
) { LogMsg("bind error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
913 fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
915 CFSocketContext myCFSocketContext
= { 0, i
->ifinfo
.InterfaceID
, NULL
, NULL
, NULL
};
916 *c
= CFSocketCreateWithNative(kCFAllocatorDefault
, *s
, kCFSocketReadCallBack
, myCFSocketCallBack
, &myCFSocketContext
);
917 CFRunLoopSourceRef rls
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, *c
, 0);
918 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
924 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
)
926 if (sa
->sa_family
== AF_INET
)
928 struct sockaddr_in
*ifa_addr
= (struct sockaddr_in
*)sa
;
929 ip
->type
= mDNSAddrType_IPv4
;
930 ip
->ip
.v4
.NotAnInteger
= ifa_addr
->sin_addr
.s_addr
;
933 else if (sa
->sa_family
== AF_INET6
)
935 struct sockaddr_in6
*ifa_addr
= (struct sockaddr_in6
*)sa
;
936 ip
->type
= mDNSAddrType_IPv6
;
937 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr
->sin6_addr
)) ifa_addr
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
938 ip
->ip
.v6
= *(mDNSv6Addr
*)&ifa_addr
->sin6_addr
;
943 LogMsg("SetupAddr invalid sa_family %d", sa
->sa_family
);
948 mDNSlocal mStatus
AddInterfaceToList(mDNS
*const m
, struct ifaddrs
*ifa
)
950 mDNSu32 scope_id
= if_nametoindex(ifa
->ifa_name
);
952 SetupAddr(&ip
, ifa
->ifa_addr
);
953 NetworkInterfaceInfoOSX
**p
;
954 for (p
= &m
->p
->InterfaceList
; *p
; p
= &(*p
)->next
)
955 if (scope_id
== (*p
)->scope_id
&& mDNSSameAddress(&ip
, &(*p
)->ifinfo
.ip
))
957 debugf("AddInterfaceToList: Found existing interface %u with address %#a", scope_id
, &ip
);
958 (*p
)->CurrentlyActive
= mDNStrue
;
962 debugf("AddInterfaceToList: Making new interface %u with address %#a", scope_id
, &ip
);
963 NetworkInterfaceInfoOSX
*i
= (NetworkInterfaceInfoOSX
*)mallocL("NetworkInterfaceInfoOSX", sizeof(*i
));
965 i
->ifa_name
= (char *)mallocL("NetworkInterfaceInfoOSX name", strlen(ifa
->ifa_name
) + 1);
966 if (!i
->ifa_name
) { freeL("NetworkInterfaceInfoOSX", i
); return(-1); }
967 strcpy(i
->ifa_name
, ifa
->ifa_name
);
969 i
->ifinfo
.InterfaceID
= mDNSNULL
;
971 i
->ifinfo
.Advertise
= m
->AdvertiseLocalAddresses
;
972 i
->ifinfo
.TxAndRx
= mDNSfalse
; // For now; will be set up later at the end of UpdateInterfaceList
976 i
->scope_id
= scope_id
;
977 i
->CurrentlyActive
= mDNStrue
;
978 i
->sa_family
= ifa
->ifa_addr
->sa_family
;
988 if (!i
->ifa_name
) return(-1);
993 mDNSlocal NetworkInterfaceInfoOSX
*FindRoutableIPv4(mDNS
*const m
, mDNSu32 scope_id
)
995 NetworkInterfaceInfoOSX
*i
;
996 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
997 if (i
->CurrentlyActive
&& i
->scope_id
== scope_id
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
998 if (!(i
->ifinfo
.ip
.ip
.v4
.b
[0] == 169 && i
->ifinfo
.ip
.ip
.v4
.b
[1] == 254))
1003 mDNSlocal mStatus
UpdateInterfaceList(mDNS
*const m
)
1005 mDNSBool foundav4
= mDNSfalse
;
1006 struct ifaddrs
*ifa
= myGetIfAddrs(1);
1007 struct ifaddrs
*theLoopback
= NULL
;
1008 int err
= (ifa
!= NULL
) ? 0 : (errno
!= 0 ? errno
: -1);
1009 int InfoSocket
= err
? -1 : socket(AF_INET6
, SOCK_DGRAM
, 0);
1010 if (err
) return(err
);
1012 // Set up the nice label
1013 m
->nicelabel
.c
[0] = 0;
1014 GetUserSpecifiedFriendlyComputerName(&m
->nicelabel
);
1015 if (m
->nicelabel
.c
[0] == 0) MakeDomainLabelFromLiteralString(&m
->nicelabel
, "Macintosh");
1017 // Set up the RFC 1034-compliant label
1018 domainlabel hostlabel
;
1020 GetUserSpecifiedRFC1034ComputerName(&hostlabel
);
1021 if (hostlabel
.c
[0] == 0) MakeDomainLabelFromLiteralString(&hostlabel
, "Macintosh");
1022 // If the user has changed their dot-local host name since the last time we checked, then update our local copy.
1023 // If the user has not changed their dot-local host name, then leave ours alone (m->hostlabel may have gone through
1024 // repeated conflict resolution to get to its current value, and if we reset it, we'll have to go through all that again.)
1025 if (SameDomainLabel(m
->p
->userhostlabel
.c
, hostlabel
.c
))
1026 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
1029 debugf("Updating m->hostlabel to %#s", hostlabel
.c
);
1030 m
->p
->userhostlabel
= m
->hostlabel
= hostlabel
;
1031 mDNS_GenerateFQDN(m
);
1036 #if LIST_ALL_INTERFACES
1037 if (ifa
->ifa_addr
->sa_family
== AF_APPLETALK
)
1038 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d is AF_APPLETALK",
1039 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1040 else if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
1041 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d is AF_LINK",
1042 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1043 else if (ifa
->ifa_addr
->sa_family
!= AF_INET
&& ifa
->ifa_addr
->sa_family
!= AF_INET6
)
1044 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
1045 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1046 if (!(ifa
->ifa_flags
& IFF_UP
))
1047 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d Interface not IFF_UP",
1048 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1049 if (ifa
->ifa_flags
& IFF_POINTOPOINT
)
1050 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
1051 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1052 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
1053 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
1054 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1056 if ((ifa
->ifa_addr
->sa_family
== AF_INET
|| ifa
->ifa_addr
->sa_family
== AF_INET6
) &&
1057 (ifa
->ifa_flags
& IFF_MULTICAST
) &&
1058 (ifa
->ifa_flags
& IFF_UP
) && !(ifa
->ifa_flags
& IFF_POINTOPOINT
))
1060 int ifru_flags6
= 0;
1061 if (ifa
->ifa_addr
->sa_family
== AF_INET6
&& InfoSocket
>= 0)
1063 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
1064 struct in6_ifreq ifr6
;
1065 bzero((char *)&ifr6
, sizeof(ifr6
));
1066 strncpy(ifr6
.ifr_name
, ifa
->ifa_name
, sizeof(ifr6
.ifr_name
));
1067 ifr6
.ifr_addr
= *sin6
;
1068 if (ioctl(InfoSocket
, SIOCGIFAFLAG_IN6
, &ifr6
) != -1)
1069 ifru_flags6
= ifr6
.ifr_ifru
.ifru_flags6
;
1070 verbosedebugf("%s %.16a %04X %04X", ifa
->ifa_name
, &sin6
->sin6_addr
, ifa
->ifa_flags
, ifru_flags6
);
1072 if (!(ifru_flags6
& (IN6_IFF_NOTREADY
| IN6_IFF_DETACHED
| IN6_IFF_DEPRECATED
| IN6_IFF_TEMPORARY
)))
1074 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
1078 AddInterfaceToList(m
, ifa
);
1079 if (ifa
->ifa_addr
->sa_family
== AF_INET
)
1080 foundav4
= mDNStrue
;
1084 ifa
= ifa
->ifa_next
;
1087 // Temporary workaround: Multicast loopback on IPv6 interfaces appears not to work.
1088 // In the interim, we skip loopback interface only if we found at least one v4 interface to use
1089 if (!foundav4
&& theLoopback
)
1090 AddInterfaceToList(m
, theLoopback
);
1092 // Now the list is complete, set the TxAndRx setting for each interface.
1093 // We always send and receive using IPv4.
1094 // To reduce traffic, we send and receive using IPv6 only on interfaces that have no routable IPv4 address.
1095 // Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
1096 // which means there's a good chance that most or all the other devices on that network should also have v4.
1097 // By doing this we lose the ability to talk to true v6-only devices on that link, but we cut the packet rate in half.
1098 // At this time, reducing the packet rate is more important than v6-only devices on a large configured network,
1099 // so we are willing to make that sacrifice.
1100 NetworkInterfaceInfoOSX
*i
;
1101 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1102 if (i
->CurrentlyActive
)
1104 mDNSBool txrx
= ((i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) || !FindRoutableIPv4(m
, i
->scope_id
));
1105 if (i
->ifinfo
.TxAndRx
!= txrx
)
1107 i
->ifinfo
.TxAndRx
= txrx
;
1108 i
->CurrentlyActive
= 2; // State change; need to deregister and reregister this interface
1112 if (InfoSocket
>= 0) close(InfoSocket
);
1116 mDNSlocal NetworkInterfaceInfoOSX
*SearchForInterfaceByName(mDNS
*const m
, char *ifname
, int type
)
1118 NetworkInterfaceInfoOSX
*i
;
1119 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1120 if (!strcmp(i
->ifa_name
, ifname
) &&
1121 i
->CurrentlyActive
&&
1123 (type
== AF_INET
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) ||
1124 (type
== AF_INET6
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
) )) return(i
);
1128 mDNSlocal
void SetupActiveInterfaces(mDNS
*const m
)
1130 NetworkInterfaceInfoOSX
*i
;
1131 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1132 if (i
->CurrentlyActive
)
1135 NetworkInterfaceInfo
*n
= &i
->ifinfo
;
1136 NetworkInterfaceInfoOSX
*alias
= SearchForInterfaceByName(m
, i
->ifa_name
, i
->sa_family
);
1137 if (!alias
) alias
= i
;
1139 if (n
->InterfaceID
&& n
->InterfaceID
!= (mDNSInterfaceID
)alias
)
1141 LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != alias %p", n
->InterfaceID
, alias
);
1142 n
->InterfaceID
= mDNSNULL
;
1145 if (!n
->InterfaceID
)
1147 n
->InterfaceID
= (mDNSInterfaceID
)alias
;
1148 mDNS_RegisterInterface(m
, n
);
1149 debugf("SetupActiveInterfaces: Registered %s(%lu) InterfaceID %p %#a%s",
1150 i
->ifa_name
, i
->scope_id
, alias
, &n
->ip
, n
->InterfaceActive
? " (Primary)" : "");
1154 debugf("SetupActiveInterfaces: No TX/Rx on %s(%lu) InterfaceID %p %#a", i
->ifa_name
, i
->scope_id
, alias
, &n
->ip
);
1157 if (i
->sa_family
== AF_INET
&& alias
->sktv4
== -1)
1159 #if mDNS_AllowPort53
1160 err
= SetupSocket(i
, UnicastDNSPort
, &alias
->skt53
, &alias
->cfs53
);
1162 if (!err
) err
= SetupSocket(i
, MulticastDNSPort
, &alias
->sktv4
, &alias
->cfsv4
);
1163 if (err
== 0) debugf("SetupActiveInterfaces: v4 socket%2d %s(%lu) InterfaceID %p %#a", alias
->sktv4
, i
->ifa_name
, i
->scope_id
, n
->InterfaceID
, &n
->ip
);
1164 else LogMsg("SetupActiveInterfaces: v4 socket%2d %s(%lu) InterfaceID %p %#a FAILED", alias
->sktv4
, i
->ifa_name
, i
->scope_id
, n
->InterfaceID
, &n
->ip
);
1167 if (i
->sa_family
== AF_INET6
&& alias
->sktv6
== -1)
1169 err
= SetupSocket(i
, MulticastDNSPort
, &alias
->sktv6
, &alias
->cfsv6
);
1170 if (err
== 0) debugf("SetupActiveInterfaces: v6 socket%2d %s(%lu) InterfaceID %p %#a", alias
->sktv6
, i
->ifa_name
, i
->scope_id
, n
->InterfaceID
, &n
->ip
);
1171 else LogMsg("SetupActiveInterfaces: v6 socket%2d %s(%lu) InterfaceID %p %#a FAILED", alias
->sktv6
, i
->ifa_name
, i
->scope_id
, n
->InterfaceID
, &n
->ip
);
1177 mDNSlocal
void MarkAllInterfacesInactive(mDNS
*const m
)
1179 NetworkInterfaceInfoOSX
*i
;
1180 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1181 i
->CurrentlyActive
= mDNSfalse
;
1184 mDNSlocal mDNSu32
NumCacheRecordsForInterfaceID(mDNS
*const m
, mDNSInterfaceID id
)
1186 mDNSu32 slot
, used
= 0;
1188 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++)
1189 for (rr
= m
->rrcache_hash
[slot
]; rr
; rr
=rr
->next
)
1190 if (rr
->resrec
.InterfaceID
== id
) used
++;
1194 mDNSlocal
void ClearInactiveInterfaces(mDNS
*const m
)
1197 // If an interface is going away, then deregister this from the mDNSCore.
1198 // We also have to deregister it if the alias interface that it's using for its InterfaceID is going away.
1199 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
1200 // it refers to has gone away we'll crash.
1201 // Don't actually close the sockets or free the memory yet: When the last representative of an interface goes away
1202 // mDNSCore may want to send goodbye packets on that interface. (Not yet implemented, but a good idea anyway.)
1203 NetworkInterfaceInfoOSX
*i
;
1204 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1206 // 1. If this interface is no longer active, or its InterfaceID is changing, deregister it
1207 NetworkInterfaceInfoOSX
*alias
= (NetworkInterfaceInfoOSX
*)(i
->ifinfo
.InterfaceID
);
1208 NetworkInterfaceInfoOSX
*newalias
= SearchForInterfaceByName(m
, i
->ifa_name
, i
->sa_family
);
1209 if (!newalias
) newalias
= i
;
1210 if (i
->ifinfo
.InterfaceID
&& (!i
->CurrentlyActive
|| (alias
&& !alias
->CurrentlyActive
) || i
->CurrentlyActive
== 2 || newalias
!= alias
))
1212 debugf("ClearInactiveInterfaces: Deregistering %#a", &i
->ifinfo
.ip
);
1213 mDNS_DeregisterInterface(m
, &i
->ifinfo
);
1214 i
->ifinfo
.InterfaceID
= mDNSNULL
;
1219 // Now that everything that's going to deregister has done so, we can close sockets and free the memory
1220 NetworkInterfaceInfoOSX
**p
= &m
->p
->InterfaceList
;
1224 // 2. Close all our CFSockets. We'll recreate them later as necessary.
1225 // (We may have previously had both v4 and v6, and we may not need both any more.)
1226 // Note: MUST NOT close the underlying native BSD sockets.
1227 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately,
1228 // because it first has to unhook the sockets from its select() call, before it can safely close them.
1229 #if mDNS_AllowPort53
1230 if (i
->cfs53
) { CFSocketInvalidate(i
->cfs53
); CFRelease(i
->cfs53
); }
1234 if (i
->cfsv4
) { CFSocketInvalidate(i
->cfsv4
); CFRelease(i
->cfsv4
); }
1235 if (i
->cfsv6
) { CFSocketInvalidate(i
->cfsv6
); CFRelease(i
->cfsv6
); }
1236 i
->sktv4
= i
->sktv6
= -1;
1237 i
->cfsv4
= i
->cfsv6
= NULL
;
1239 // 3. If no longer active, delete interface from list and free memory
1240 if (!i
->CurrentlyActive
&& NumCacheRecordsForInterfaceID(m
, (mDNSInterfaceID
)i
) == 0)
1242 debugf("ClearInactiveInterfaces: Deleting %#a", &i
->ifinfo
.ip
);
1244 if (i
->ifa_name
) freeL("NetworkInterfaceInfoOSX name", i
->ifa_name
);
1245 freeL("NetworkInterfaceInfoOSX", i
);
1252 mDNSlocal
void NetworkChanged(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *context
)
1254 (void)store
; // Parameter not used
1255 (void)changedKeys
; // Parameter not used
1256 debugf("*** Network Configuration Change ***");
1258 mDNS
*const m
= (mDNS
*const)context
;
1259 MarkAllInterfacesInactive(m
);
1260 UpdateInterfaceList(m
);
1261 ClearInactiveInterfaces(m
);
1262 SetupActiveInterfaces(m
);
1264 if (m
->MainCallback
)
1265 m
->MainCallback(m
, mStatus_ConfigChanged
);
1268 mDNSlocal mStatus
WatchForNetworkChanges(mDNS
*const m
)
1271 SCDynamicStoreContext context
= { 0, m
, NULL
, NULL
, NULL
};
1272 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder"), NetworkChanged
, &context
);
1273 CFStringRef key1
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
1274 CFStringRef key2
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv6
);
1275 CFStringRef key3
= SCDynamicStoreKeyCreateComputerName(NULL
);
1276 CFStringRef key4
= SCDynamicStoreKeyCreateHostNames(NULL
);
1277 CFStringRef pattern1
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv4
);
1278 CFStringRef pattern2
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv6
);
1280 CFMutableArrayRef keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1281 CFMutableArrayRef patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1283 if (!store
) { LogMsg("SCDynamicStoreCreate failed: %s\n", SCErrorString(SCError())); goto error
; }
1284 if (!key1
|| !key2
|| !key3
|| !key4
|| !keys
|| !pattern1
|| !pattern2
|| !patterns
) goto error
;
1286 CFArrayAppendValue(keys
, key1
);
1287 CFArrayAppendValue(keys
, key2
);
1288 CFArrayAppendValue(keys
, key3
);
1289 CFArrayAppendValue(keys
, key4
);
1290 CFArrayAppendValue(patterns
, pattern1
);
1291 CFArrayAppendValue(patterns
, pattern2
);
1292 if (!SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
1293 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s\n", SCErrorString(SCError())); goto error
; }
1295 m
->p
->StoreRLS
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
1296 if (!m
->p
->StoreRLS
) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s\n", SCErrorString(SCError())); goto error
; }
1298 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
1299 m
->p
->Store
= store
;
1304 if (store
) CFRelease(store
);
1307 if (key1
) CFRelease(key1
);
1308 if (key2
) CFRelease(key2
);
1309 if (key3
) CFRelease(key3
);
1310 if (key4
) CFRelease(key4
);
1311 if (pattern1
) CFRelease(pattern1
);
1312 if (pattern2
) CFRelease(pattern2
);
1313 if (keys
) CFRelease(keys
);
1314 if (patterns
) CFRelease(patterns
);
1319 mDNSlocal
void PowerChanged(void *refcon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
1321 mDNS
*const m
= (mDNS
*const)refcon
;
1322 (void)service
; // Parameter not used
1325 case kIOMessageCanSystemPowerOff
: debugf("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
1326 case kIOMessageSystemWillPowerOff
: debugf("PowerChanged kIOMessageSystemWillPowerOff"); mDNSCoreMachineSleep(m
, true); break; // E0000250
1327 case kIOMessageSystemWillNotPowerOff
: debugf("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
1328 case kIOMessageCanSystemSleep
: debugf("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
1329 case kIOMessageSystemWillSleep
: debugf("PowerChanged kIOMessageSystemWillSleep"); mDNSCoreMachineSleep(m
, true); break; // E0000280
1330 case kIOMessageSystemWillNotSleep
: debugf("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
1331 case kIOMessageSystemHasPoweredOn
: debugf("PowerChanged kIOMessageSystemHasPoweredOn"); mDNSCoreMachineSleep(m
, false); break; // E0000300
1332 default: debugf("PowerChanged unknown message %X", messageType
); break;
1334 IOAllowPowerChange(m
->p
->PowerConnection
, (long)messageArgument
);
1337 mDNSlocal mStatus
WatchForPowerChanges(mDNS
*const m
)
1339 IONotificationPortRef thePortRef
;
1340 m
->p
->PowerConnection
= IORegisterForSystemPower(m
, &thePortRef
, PowerChanged
, &m
->p
->PowerNotifier
);
1341 if (m
->p
->PowerConnection
)
1343 m
->p
->PowerRLS
= IONotificationPortGetRunLoopSource(thePortRef
);
1344 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->PowerRLS
, kCFRunLoopDefaultMode
);
1345 return(mStatus_NoError
);
1350 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
1351 CF_EXPORT
const CFStringRef _kCFSystemVersionProductNameKey
;
1352 CF_EXPORT
const CFStringRef _kCFSystemVersionProductVersionKey
;
1353 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
1355 mDNSexport mDNSBool
mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring
)
1357 int major
= 0, minor
= 0;
1358 char letter
= 0, prodname
[256]="Mac OS X", prodvers
[256]="", buildver
[256]="?";
1359 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
1362 CFStringRef cfprodname
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductNameKey
);
1363 CFStringRef cfprodvers
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductVersionKey
);
1364 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
1365 if (cfprodname
) CFStringGetCString(cfprodname
, prodname
, sizeof(prodname
), kCFStringEncodingUTF8
);
1366 if (cfprodvers
) CFStringGetCString(cfprodvers
, prodvers
, sizeof(prodvers
), kCFStringEncodingUTF8
);
1367 if (cfbuildver
) CFStringGetCString(cfbuildver
, buildver
, sizeof(buildver
), kCFStringEncodingUTF8
);
1368 sscanf(buildver
, "%d%c%d", &major
, &letter
, &minor
);
1371 if (HINFO_SWstring
) mDNS_snprintf(HINFO_SWstring
, 256, "%s %s (%s), %s", prodname
, prodvers
, buildver
, mDNSResponderVersionString
);
1375 mDNSlocal mStatus
mDNSPlatformInit_setup(mDNS
*const m
)
1379 m
->hostlabel
.c
[0] = 0;
1381 char *HINFO_HWstring
= "Macintosh";
1382 char HINFO_HWstring_buffer
[256];
1383 int get_model
[2] = { CTL_HW
, HW_MODEL
};
1384 size_t len_model
= sizeof(HINFO_HWstring_buffer
);
1385 if (sysctl(get_model
, 2, HINFO_HWstring_buffer
, &len_model
, NULL
, 0) == 0)
1386 HINFO_HWstring
= HINFO_HWstring_buffer
;
1388 char HINFO_SWstring
[256] = "";
1389 if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring
) < 7) m
->KnownBugs
= mDNS_KnownBug_PhantomInterfaces
;
1391 mDNSu32 hlen
= mDNSPlatformStrLen(HINFO_HWstring
);
1392 mDNSu32 slen
= mDNSPlatformStrLen(HINFO_SWstring
);
1393 if (hlen
+ slen
< 254)
1395 m
->HIHardware
.c
[0] = hlen
;
1396 m
->HISoftware
.c
[0] = slen
;
1397 mDNSPlatformMemCopy(HINFO_HWstring
, &m
->HIHardware
.c
[1], hlen
);
1398 mDNSPlatformMemCopy(HINFO_SWstring
, &m
->HISoftware
.c
[1], slen
);
1401 m
->p
->InterfaceList
= mDNSNULL
;
1402 m
->p
->userhostlabel
.c
[0] = 0;
1403 UpdateInterfaceList(m
);
1404 SetupActiveInterfaces(m
);
1406 err
= WatchForNetworkChanges(m
);
1407 if (err
) return(err
);
1409 err
= WatchForPowerChanges(m
);
1413 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
1415 mStatus result
= mDNSPlatformInit_setup(m
);
1416 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
1417 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
1418 if (result
== mStatus_NoError
) mDNSCoreInitComplete(m
, mStatus_NoError
);
1422 mDNSexport
void mDNSPlatformClose(mDNS
*const m
)
1424 if (m
->p
->PowerConnection
)
1426 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->PowerRLS
, kCFRunLoopDefaultMode
);
1427 CFRunLoopSourceInvalidate(m
->p
->PowerRLS
);
1428 CFRelease(m
->p
->PowerRLS
);
1429 IODeregisterForSystemPower(&m
->p
->PowerNotifier
);
1430 m
->p
->PowerConnection
= NULL
;
1431 m
->p
->PowerNotifier
= NULL
;
1432 m
->p
->PowerRLS
= NULL
;
1437 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
1438 CFRunLoopSourceInvalidate(m
->p
->StoreRLS
);
1439 CFRelease(m
->p
->StoreRLS
);
1440 CFRelease(m
->p
->Store
);
1442 m
->p
->StoreRLS
= NULL
;
1445 MarkAllInterfacesInactive(m
);
1446 ClearInactiveInterfaces(m
);
1449 mDNSexport mDNSs32 mDNSPlatformOneSecond
= 1000;
1451 mDNSexport mStatus
mDNSPlatformTimeInit(mDNSs32
*timenow
)
1453 // Notes: Typical values for mach_timebase_info:
1454 // tbi.numer = 1000 million
1455 // tbi.denom = 33 million
1456 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
1457 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
1458 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
1459 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
1460 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
1462 // Arithmetic notes:
1463 // tbi.denom is at least 1, and not more than 2^32-1.
1464 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
1465 // tbi.denom is at least 1, and not more than 2^32-1.
1466 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
1467 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
1468 // which is unlikely on any current or future Macintosh.
1469 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
1470 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
1471 struct mach_timebase_info tbi
;
1472 kern_return_t result
= mach_timebase_info(&tbi
);
1473 if (result
!= KERN_SUCCESS
) return(result
);
1474 clockdivisor
= ((uint64_t)tbi
.denom
* 1000000) / tbi
.numer
;
1475 *timenow
= mDNSPlatformTimeNow();
1476 return(mStatus_NoError
);
1479 mDNSexport mDNSs32
mDNSPlatformTimeNow(void)
1481 if (clockdivisor
== 0) { LogMsg("mDNSPlatformTimeNow called before mDNSPlatformTimeInit"); return(0); }
1482 return((mDNSs32
)(mach_absolute_time() / clockdivisor
));
1485 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
1486 mDNSexport
void mDNSPlatformLock (const mDNS
*const m
) { (void)m
; }
1487 mDNSexport
void mDNSPlatformUnlock (const mDNS
*const m
) { (void)m
; }
1488 mDNSexport
void mDNSPlatformStrCopy(const void *src
, void *dst
) { strcpy((char *)dst
, (char *)src
); }
1489 mDNSexport mDNSu32
mDNSPlatformStrLen (const void *src
) { return(strlen((char*)src
)); }
1490 mDNSexport
void mDNSPlatformMemCopy(const void *src
, void *dst
, mDNSu32 len
) { memcpy(dst
, src
, len
); }
1491 mDNSexport mDNSBool
mDNSPlatformMemSame(const void *src
, const void *dst
, mDNSu32 len
) { return(memcmp(dst
, src
, len
) == 0); }
1492 mDNSexport
void mDNSPlatformMemZero( void *dst
, mDNSu32 len
) { bzero(dst
, len
); }
1493 mDNSexport
void * mDNSPlatformMemAllocate(mDNSu32 len
) { return(mallocL("mDNSPlatformMemAllocate", len
)); }
1494 mDNSexport
void mDNSPlatformMemFree (void *mem
) { freeL("mDNSPlatformMemFree", mem
); }