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):
26 Revision 1.115.2.5 2005/01/28 05:02:06 cheshire
27 <rdar://problem/3770559> SUPan: Replace IP TTL 255 check with local-subnet check
29 Revision 1.115.2.4 2004/04/23 00:34:06 cheshire
30 <rdar://problem/3628978>: mDNSResponder messages on wake
31 Take care to correctly update InterfaceIDs when a dormant interface comes back to life
33 Revision 1.115.2.3 2004/04/08 23:18:11 cheshire
34 <rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
35 Refinement from Bob Bradley: Should use "mDNS *const m" instead of referencing mDNSStorage directly
37 Revision 1.115.2.2 2004/04/08 00:42:37 cheshire
38 <rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
39 Unify use of the InterfaceID field, and make code that walks the list respect the CurrentlyActive flag
41 Revision 1.115.2.1 2004/04/07 01:08:15 cheshire
42 <rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
44 Revision 1.115 2003/09/10 00:45:55 cheshire
45 <rdar://problem/3412328> Don't log "sendto failed" errors during the first two minutes of startup
47 Revision 1.114 2003/08/27 02:55:13 cheshire
48 <rdar://problem/3387910>: Bug: Don't report mDNSPlatformSendUDP sendto errno 64 (Host is down)
50 Revision 1.113 2003/08/19 22:20:00 cheshire
51 <rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
52 More minor refinements
54 Revision 1.112 2003/08/19 03:04:43 cheshire
55 <rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
57 Revision 1.111 2003/08/18 22:53:37 cheshire
58 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformTimeNow()
60 Revision 1.110 2003/08/16 03:39:00 cheshire
61 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
63 Revision 1.109 2003/08/15 02:19:49 cheshire
64 <rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
65 Also limit number of messages to at most 100
67 Revision 1.108 2003/08/12 22:24:52 cheshire
68 <rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
69 This message indicates a kernel bug, but still we don't want to flood syslog.
70 Do a sleep(1) after writing this log message, to limit the rate.
72 Revision 1.107 2003/08/12 19:56:25 cheshire
75 Revision 1.106 2003/08/12 13:48:32 cheshire
76 Add comment explaining clockdivisor calculation
78 Revision 1.105 2003/08/12 13:44:14 cheshire
79 <rdar://problem/3370229> mDNSResponder *VERY* unhappy if time goes backwards
80 Use mach_absolute_time() (which is guaranteed to always go forwards, resetting only on reboot)
81 instead of gettimeofday() (which can jump back if the user manually changes their time/date)
83 Revision 1.104 2003/08/12 13:12:07 cheshire
84 Textual search/replace: Indicate local functions using "mDNSlocal" instead of "static"
86 Revision 1.103 2003/08/08 18:36:04 cheshire
87 <rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
89 Revision 1.102 2003/08/06 00:14:52 cheshire
90 <rdar://problem/3330324> Need to check IP TTL on responses
91 Also add corresponding checks in the IPv6 code path
93 Revision 1.101 2003/08/05 22:20:16 cheshire
94 <rdar://problem/3330324> Need to check IP TTL on responses
96 Revision 1.100 2003/08/05 21:18:50 cheshire
97 <rdar://problem/3363185> mDNSResponder should ignore 6to4
98 Only use interfaces that are marked as multicast-capable (IFF_MULTICAST)
100 Revision 1.99 2003/08/05 20:13:52 cheshire
101 <rdar://problem/3294080> mDNSResponder using IPv6 interfaces before they are ready
102 Ignore interfaces with the IN6_IFF_NOTREADY flag set
104 Revision 1.98 2003/07/20 03:38:51 ksekar
106 Completed support for Unix-domain socket based API.
108 Revision 1.97 2003/07/19 03:15:16 cheshire
109 Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
110 and add the obvious trivial implementations to each platform support layer
112 Revision 1.96 2003/07/18 00:30:00 cheshire
113 <rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
115 Revision 1.95 2003/07/12 03:15:20 cheshire
116 <rdar://problem/3324848> After SCDynamicStore notification, mDNSResponder updates
117 m->hostlabel even if user hasn't actually actually changed their dot-local hostname
119 Revision 1.94 2003/07/03 00:51:54 cheshire
120 <rdar://problem/3287213> When select() and recvmgs() disagree, get more info from kernel about the socket state
122 Revision 1.93 2003/07/03 00:09:14 cheshire
123 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
124 Additional refinement suggested by Josh: Use info->scope_id instead of if_nametoindex(info->ifa_name);
126 Revision 1.92 2003/07/02 21:19:51 cheshire
127 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
129 Revision 1.91 2003/06/24 01:53:51 cheshire
130 Minor update to comments
132 Revision 1.90 2003/06/24 01:51:47 cheshire
133 <rdar://problem/3303118> Oops: Double-dispose of sockets
134 Don't need to close sockets: CFSocketInvalidate() does that for us
136 Revision 1.89 2003/06/21 18:12:47 cheshire
137 <rdar://problem/3296061> Rendezvous cannot handle interfaces whose total name is >3 chars
138 One-line change: should say "IF_NAMESIZE", not sizeof(ifname)
140 Revision 1.88 2003/06/12 23:38:37 cheshire
141 <rdar://problem/3291162> mDNSResponder doesn't detect some configuration changes
142 Also check that scope_id matches before concluding that two interfaces are the same
144 Revision 1.87 2003/06/10 01:14:11 cheshire
145 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
147 Revision 1.86 2003/05/28 02:41:52 cheshire
148 <rdar://problem/3034346> Time to remove Mac OS 9 UDP Port 53 legacy support
150 Revision 1.85 2003/05/28 02:39:47 cheshire
151 Minor change to debugging messages
153 Revision 1.84 2003/05/27 22:29:40 cheshire
154 Remove out-dated comment
156 Revision 1.83 2003/05/26 03:21:29 cheshire
157 Tidy up address structure naming:
158 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
159 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
160 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
162 Revision 1.82 2003/05/26 03:01:27 cheshire
163 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
165 Revision 1.81 2003/05/24 02:06:42 cheshire
166 <rdar://problem/3268480> IPv6 Multicast Loopback doesn't work
167 Tried setting IPV6_MULTICAST_LOOP; it doesn't help.
168 However, it is probably wise to have the code explicitly set this socket
169 option anyway, in case the default changes in later versions of Unix.
171 Revision 1.80 2003/05/24 02:02:24 cheshire
172 <rdar://problem/3221880> if_indextoname consumes a lot of CPU
173 Fix error in myIfIndexToName; was returning prematurely
175 Revision 1.79 2003/05/23 23:07:44 cheshire
176 <rdar://problem/3268199> Must not write to stderr when running as daemon
178 Revision 1.78 2003/05/23 01:19:04 cheshire
179 <rdar://problem/3267085> mDNSResponder needs to signal type of service to AirPort
180 Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
182 Revision 1.77 2003/05/23 01:12:05 cheshire
185 Revision 1.76 2003/05/22 01:26:01 cheshire
188 Revision 1.75 2003/05/22 00:07:09 cheshire
189 <rdar://problem/3264366> myCFSocketCallBack recvfrom(5) error 1, errno 35
190 Extra logging to determine whether there is a bug in CFSocket
192 Revision 1.74 2003/05/21 20:20:12 cheshire
193 Fix warnings (mainly printf format string warnings, like using "%d" where
194 it should say "%lu", etc.) and improve error logging (use strerror()
195 to include textual error message as well as numeric error in log messages).
197 Revision 1.73 2003/05/21 17:56:29 ksekar
198 Bug #: <rdar://problem/3191277>: mDNSResponder doesn't watch for IPv6 address changes
200 Revision 1.72 2003/05/14 18:48:41 cheshire
201 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
202 More minor refinements:
203 CFSocket.c needs to do *all* its mDNS_DeregisterInterface calls before freeing memory
204 mDNS_DeregisterInterface revalidates cache record when *any* representative of an interface goes away
206 Revision 1.71 2003/05/14 07:08:37 cheshire
207 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
208 Previously, when there was any network configuration change, mDNSResponder
209 would tear down the entire list of active interfaces and start again.
210 That was very disruptive, and caused the entire cache to be flushed,
211 and caused lots of extra network traffic. Now it only removes interfaces
212 that have really gone, and only adds new ones that weren't there before.
214 Revision 1.70 2003/05/07 18:30:24 cheshire
215 Fix signed/unsigned comparison warning
217 Revision 1.69 2003/05/06 20:14:44 cheshire
220 Revision 1.68 2003/05/06 00:00:49 cheshire
221 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
223 Revision 1.67 2003/04/29 00:43:44 cheshire
224 Fix compiler warnings
226 Revision 1.66 2003/04/26 02:41:58 cheshire
227 <rdar://problem/3241281> Change timenow from a local variable to a structure member
229 Revision 1.65 2003/04/26 02:34:01 cheshire
230 Add missing mDNSexport
232 Revision 1.64 2003/04/15 16:48:06 jgraessl
234 Modified code in CFSocket notifier function to read all packets on the socket
235 instead of reading only one packet every time the notifier was called.
237 Revision 1.63 2003/04/15 16:33:50 jgraessl
239 Switched to our own copy of if_indextoname to improve performance.
241 Revision 1.62 2003/03/28 01:55:44 cheshire
242 Minor improvements to debugging messages
244 Revision 1.61 2003/03/27 03:30:56 cheshire
245 <rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
246 Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
248 1. Make mDNS_DeregisterInterface() safe to call from a callback
249 2. Make HostNameCallback() use mDNS_DeadvertiseInterface() instead
250 (it never really needed to deregister the interface at all)
252 Revision 1.60 2003/03/15 04:40:38 cheshire
253 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
255 Revision 1.59 2003/03/11 01:23:26 cheshire
256 Bug #: 3194246 mDNSResponder socket problems
258 Revision 1.58 2003/03/06 01:43:04 cheshire
259 Bug #: 3189097 Additional debugging code in mDNSResponder
260 Improve "LIST_ALL_INTERFACES" output
262 Revision 1.57 2003/03/05 22:36:27 cheshire
263 Bug #: 3186338 Loopback doesn't work with mDNSResponder-27
264 Temporary workaround: Skip loopback interface *only* if we found at least one v4 interface to use
266 Revision 1.56 2003/03/05 01:50:38 cheshire
267 Bug #: 3189097 Additional debugging code in mDNSResponder
269 Revision 1.55 2003/02/21 01:54:09 cheshire
270 Bug #: 3099194 mDNSResponder needs performance improvements
271 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
273 Revision 1.54 2003/02/20 06:48:35 cheshire
274 Bug #: 3169535 Xserve RAID needs to do interface-specific registrations
275 Reviewed by: Josh Graessley, Bob Bradley
277 Revision 1.53 2003/01/29 02:21:23 cheshire
278 Return mStatus_Invalid if can't send packet because socket not available
280 Revision 1.52 2003/01/28 19:39:43 jgraessl
281 Enabling AAAA over IPv4 support.
283 Revision 1.51 2003/01/28 05:11:23 cheshire
284 Fixed backwards comparison in SearchForInterfaceByName
286 Revision 1.50 2003/01/13 23:49:44 jgraessl
287 Merged changes for the following fixes in to top of tree:
288 3086540 computer name changes not handled properly
289 3124348 service name changes are not properly handled
290 3124352 announcements sent in pairs, failing chattiness test
292 Revision 1.49 2002/12/23 22:13:30 jgraessl
293 Reviewed by: Stuart Cheshire
294 Initial IPv6 support for mDNSResponder.
296 Revision 1.48 2002/11/22 01:37:52 cheshire
297 Bug #: 3108426 mDNSResponder is monitoring ServiceEntities instead of InterfaceEntities
299 Revision 1.47 2002/09/21 20:44:51 zarzycki
302 Revision 1.46 2002/09/19 21:25:35 cheshire
303 mDNS_snprintf() doesn't need to be in a separate file
305 Revision 1.45 2002/09/17 01:45:13 cheshire
306 Add LIST_ALL_INTERFACES symbol for debugging
308 Revision 1.44 2002/09/17 01:36:23 cheshire
309 Move Puma support to CFSocketPuma.c
311 Revision 1.43 2002/09/17 01:05:28 cheshire
312 Change mDNS_AdvertiseLocalAddresses to be an Init parameter instead of a global
314 Revision 1.42 2002/09/16 23:13:50 cheshire
319 // ***************************************************************************
321 // Supporting routines to run mDNS on a CFRunLoop platform
322 // ***************************************************************************
324 // Open Transport 2.7.x on Mac OS 9 used to send Multicast DNS queries to UDP port 53,
325 // before the Multicast DNS port was changed to 5353. For this reason, the mDNSResponder
326 // in earlier versions of Mac OS X 10.2 Jaguar used to set mDNS_AllowPort53 to 1 to allow
327 // it to also listen and answer queries on UDP port 53. Now that Transport 2.8 (included in
328 // the Classic subsystem of Mac OS X 10.2 Jaguar) has been corrected to issue Multicast DNS
329 // queries on UDP port 5353, this backwards-compatibility legacy support is no longer needed.
330 #define mDNS_AllowPort53 0
332 // For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
333 // including ones that mDNSResponder chooses not to use.
334 #define LIST_ALL_INTERFACES 0
336 // For enabling AAAA records over IPv4. Setting this to 0 sends only
337 // A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both
338 // AAAA and A records over both IPv4 and IPv6.
339 #define AAAA_OVER_V4 1
341 #include "mDNSClientAPI.h" // Defines the interface provided to the client layer above
342 #include "mDNSPlatformFunctions.h" // Defines the interface to the supporting layer below
343 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
346 #include <unistd.h> // For select() and close()
347 #include <stdarg.h> // For va_list support
349 #include <net/if_dl.h>
351 #include <sys/param.h>
352 #include <sys/socket.h>
353 #include <sys/sysctl.h>
355 #include <sys/ioctl.h>
357 #include <netinet/in.h> // For IP_RECVTTL
359 #define IP_RECVTTL 24 /* bool; receive reception TTL w/dgram */
362 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
363 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
364 #include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
366 // Code contributed by Dave Heller:
367 // Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
368 // work on Mac OS X 10.1, which does not have the getifaddrs call.
369 #define RUN_ON_PUMA_WITHOUT_IFADDRS 0
370 #if RUN_ON_PUMA_WITHOUT_IFADDRS
371 #include "CFSocketPuma.c"
376 #include <IOKit/IOKitLib.h>
377 #include <IOKit/IOMessage.h>
378 #include <mach/mach_time.h>
380 // ***************************************************************************
383 static mDNSu32 clockdivisor
= 0;
385 // ***************************************************************************
388 #define mDNSSameIPv4Address(A,B) ((A).NotAnInteger == (B).NotAnInteger)
389 #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])
391 #define mDNSAddressIsAllDNSLinkGroup(X) ( \
392 ((X)->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address((X)->ip.v4, AllDNSLinkGroup )) || \
393 ((X)->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address((X)->ip.v6, AllDNSLinkGroupv6)) )
395 // ***************************************************************************
398 // Note, this uses mDNS_vsnprintf instead of standard "vsnprintf", because mDNS_vsnprintf knows
399 // how to print special data types like IP addresses and length-prefixed domain names
401 mDNSexport
void debugf_(const char *format
, ...)
403 unsigned char buffer
[512];
405 va_start(ptr
,format
);
406 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
408 fprintf(stderr
,"%s\n", buffer
);
413 #if MDNS_DEBUGMSGS > 1
414 mDNSexport
void verbosedebugf_(const char *format
, ...)
416 unsigned char buffer
[512];
418 va_start(ptr
,format
);
419 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
421 fprintf(stderr
,"%s\n", buffer
);
426 mDNSexport
void LogMsg(const char *format
, ...)
428 unsigned char buffer
[512];
430 va_start(ptr
,format
);
431 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
434 extern int debug_mode
;
435 if (debug_mode
) // In debug_mode we write to stderr
437 fprintf(stderr
,"%s\n", buffer
);
440 else // else, in production mode, we write to syslog
442 openlog("mDNSResponder", LOG_CONS
| LOG_PERROR
| LOG_PID
, LOG_DAEMON
);
443 syslog(LOG_ERR
, "%s", buffer
);
448 mDNSlocal
struct ifaddrs
* myGetIfAddrs(int refresh
)
450 static struct ifaddrs
*ifa
= NULL
;
458 if (ifa
== NULL
) getifaddrs(&ifa
);
463 mDNSlocal
int myIfIndexToName(u_short index
, char* name
)
466 for (ifa
= myGetIfAddrs(0); ifa
; ifa
= ifa
->ifa_next
)
467 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
468 if (((struct sockaddr_dl
*)ifa
->ifa_addr
)->sdl_index
== index
)
469 { strncpy(name
, ifa
->ifa_name
, IF_NAMESIZE
); return 0; }
473 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS
*const m
, mDNSu32 index
)
475 NetworkInterfaceInfoOSX
*i
;
476 if (index
== (uint32_t)~0) return((mDNSInterfaceID
)~0);
478 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
479 if (i
->ifinfo
.InterfaceID
&& i
->scope_id
== index
) // Don't get tricked by inactive interfaces
480 return(i
->ifinfo
.InterfaceID
);
484 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS
*const m
, mDNSInterfaceID id
)
486 NetworkInterfaceInfoOSX
*i
;
487 if (id
== (mDNSInterfaceID
)~0) return((mDNSu32
)~0);
489 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
490 // Don't use i->ifinfo.InterfaceID here because we want to find inactive interfaces where that's not set
491 if ((mDNSInterfaceID
)i
== id
)
496 mDNSexport mStatus
mDNSPlatformSendUDP(const mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
,
497 mDNSInterfaceID InterfaceID
, mDNSIPPort srcPort
, const mDNSAddr
*dst
, mDNSIPPort dstPort
)
500 NetworkInterfaceInfoOSX
*info
= (NetworkInterfaceInfoOSX
*)InterfaceID
;
501 struct sockaddr_storage to
;
504 if (!InterfaceID
) { LogMsg("mDNSPlatformSendUDP ERROR! Cannot send from zero InterfaceID"); return mStatus_BadParamErr
; }
506 if (dst
->type
== mDNSAddrType_IPv4
)
508 struct sockaddr_in
* sin_to
= (struct sockaddr_in
*)&to
;
509 sin_to
->sin_len
= sizeof(*sin_to
);
510 sin_to
->sin_family
= AF_INET
;
511 sin_to
->sin_port
= dstPort
.NotAnInteger
;
512 sin_to
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
514 else if (dst
->type
== mDNSAddrType_IPv6
)
516 struct sockaddr_in6
* sin6_to
= (struct sockaddr_in6
*)&to
;
517 sin6_to
->sin6_len
= sizeof(*sin6_to
);
518 sin6_to
->sin6_family
= AF_INET6
;
519 sin6_to
->sin6_port
= dstPort
.NotAnInteger
;
520 sin6_to
->sin6_flowinfo
= 0;
521 sin6_to
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
522 sin6_to
->sin6_scope_id
= info
->scope_id
;
526 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!\n");
527 return mStatus_BadParamErr
;
530 if (srcPort
.NotAnInteger
== MulticastDNSPort
.NotAnInteger
)
532 if (dst
->type
== mDNSAddrType_IPv4
) s
= info
->sktv4
;
533 else if (dst
->type
== mDNSAddrType_IPv6
) s
= info
->sktv6
;
537 else if (srcPort
.NotAnInteger
== UnicastDNSPort
.NotAnInteger
&& dst
->type
== mDNSAddrType_IPv4
)
540 else { LogMsg("Source port %d not allowed", (mDNSu16
)srcPort
.b
[0]<<8 | srcPort
.b
[1]); return(-1); }
543 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %X %s/%d to %#a:%d skt %d",
544 InterfaceID
, info
->ifa_name
, dst
->type
, dst
, (mDNSu16
)dstPort
.b
[0]<<8 | dstPort
.b
[1], s
);
546 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %X %s/%d (socket of this type not available)",
547 InterfaceID
, info
->ifa_name
, dst
->type
, dst
, (mDNSu16
)dstPort
.b
[0]<<8 | dstPort
.b
[1]);
549 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
550 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
551 if (s
< 0) return(mStatus_Invalid
);
553 err
= sendto(s
, msg
, (UInt8
*)end
- (UInt8
*)msg
, 0, (struct sockaddr
*)&to
, to
.ss_len
);
556 // Don't report EHOSTDOWN (i.e. ARP failure) to unicast destinations
557 if (errno
== EHOSTDOWN
&& !mDNSAddressIsAllDNSLinkGroup(dst
)) return(err
);
558 // Don't report EHOSTUNREACH in the first two minutes after boot
559 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
560 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
561 if (errno
== EHOSTUNREACH
&& (mDNSu32
)(m
->timenow
) < (mDNSu32
)(mDNSPlatformOneSecond
* 120)) return(err
);
562 LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %s/%ld to %#a:%d skt %d error %d errno %d (%s)",
563 InterfaceID
, info
->ifa_name
, dst
->type
, dst
, (mDNSu16
)dstPort
.b
[0]<<8 | dstPort
.b
[1], s
, err
, errno
, strerror(errno
));
567 return(mStatus_NoError
);
570 mDNSlocal ssize_t
myrecvfrom(const int s
, void *const buffer
, const size_t max
,
571 struct sockaddr
*const from
, size_t *const fromlen
, mDNSAddr
*dstaddr
, char ifname
[IF_NAMESIZE
], mDNSu8
*ttl
)
573 static unsigned int numLogMessages
= 0;
574 struct iovec databuffers
= { (char *)buffer
, max
};
577 struct cmsghdr
*cmPtr
;
578 char ancillary
[1024];
580 *ttl
= 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
582 // Set up the message
583 msg
.msg_name
= (caddr_t
)from
;
584 msg
.msg_namelen
= *fromlen
;
585 msg
.msg_iov
= &databuffers
;
587 msg
.msg_control
= (caddr_t
)&ancillary
;
588 msg
.msg_controllen
= sizeof(ancillary
);
592 n
= recvmsg(s
, &msg
, 0);
595 if (errno
!= EWOULDBLOCK
&& numLogMessages
++ < 100) LogMsg("CFSocket.c: recvmsg(%d) returned error %d errno %d", s
, n
, errno
);
598 if (msg
.msg_controllen
< (int)sizeof(struct cmsghdr
))
600 if (numLogMessages
++ < 100) LogMsg("CFSocket.c: recvmsg(%d) msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
601 s
, msg
.msg_controllen
, sizeof(struct cmsghdr
));
604 if (msg
.msg_flags
& MSG_CTRUNC
)
606 if (numLogMessages
++ < 100) LogMsg("CFSocket.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s
);
610 *fromlen
= msg
.msg_namelen
;
612 // Parse each option out of the ancillary data.
613 for (cmPtr
= CMSG_FIRSTHDR(&msg
); cmPtr
; cmPtr
= CMSG_NXTHDR(&msg
, cmPtr
))
615 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
616 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVDSTADDR
)
618 dstaddr
->type
= mDNSAddrType_IPv4
;
619 dstaddr
->ip
.v4
.NotAnInteger
= *(u_int32_t
*)CMSG_DATA(cmPtr
);
621 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVIF
)
623 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)CMSG_DATA(cmPtr
);
624 if (sdl
->sdl_nlen
< IF_NAMESIZE
)
626 mDNSPlatformMemCopy(sdl
->sdl_data
, ifname
, sdl
->sdl_nlen
);
627 ifname
[sdl
->sdl_nlen
] = 0;
628 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
631 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVTTL
)
633 *ttl
= *(u_char
*)CMSG_DATA(cmPtr
);
635 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_PKTINFO
)
637 struct in6_pktinfo
*ip6_info
= (struct in6_pktinfo
*)CMSG_DATA(cmPtr
);
638 dstaddr
->type
= mDNSAddrType_IPv6
;
639 dstaddr
->ip
.v6
= *(mDNSv6Addr
*)&ip6_info
->ipi6_addr
;
640 myIfIndexToName(ip6_info
->ipi6_ifindex
, ifname
);
642 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_HOPLIMIT
)
644 *ttl
= *(int*)CMSG_DATA(cmPtr
);
651 mDNSlocal
void myCFSocketCallBack(CFSocketRef cfs
, CFSocketCallBackType CallBackType
, CFDataRef address
, const void *data
, void *context
)
653 mDNSAddr senderAddr
, destAddr
;
654 mDNSIPPort senderPort
, destPort
= MulticastDNSPort
;
655 NetworkInterfaceInfoOSX
*info
= (NetworkInterfaceInfoOSX
*)context
;
656 mDNS
*const m
= info
->m
;
657 mDNSInterfaceID InterfaceID
= info
->ifinfo
.InterfaceID
;
659 struct sockaddr_storage from
;
660 size_t fromlen
= sizeof(from
);
661 char packetifname
[IF_NAMESIZE
] = "";
662 int err
, s1
= -1, skt
= CFSocketGetNative(cfs
);
665 (void)address
; // Parameter not used
666 (void)data
; // Parameter not used
668 if (CallBackType
!= kCFSocketReadCallBack
) LogMsg("myCFSocketCallBack: Why is CallBackType %d not kCFSocketReadCallBack?", CallBackType
);
671 if (cfs
== info
->cfs53
) { s1
= info
->skt53
; destPort
= UnicastDNSPort
; }
674 if (cfs
== info
->cfsv4
) s1
= info
->sktv4
;
675 else if (cfs
== info
->cfsv6
) s1
= info
->sktv6
;
677 if (s1
< 0 || s1
!= skt
)
679 LogMsg("myCFSocketCallBack: s1 %d native socket %d, cfs %p", s1
, skt
, cfs
);
681 LogMsg("myCFSocketCallBack: cfs53 %p, skt53 %d", info
->cfs53
, info
->skt53
);
683 LogMsg("myCFSocketCallBack: cfsv4 %p, sktv4 %d", info
->cfsv4
, info
->sktv4
);
684 LogMsg("myCFSocketCallBack: cfsv6 %p, sktv6 %d", info
->cfsv6
, info
->sktv6
);
688 while ((err
= myrecvfrom(s1
, &packet
, sizeof(packet
), (struct sockaddr
*)&from
, &fromlen
, &destAddr
, packetifname
, &ttl
)) >= 0)
691 if (from
.ss_family
== AF_INET
)
693 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&from
;
694 senderAddr
.type
= mDNSAddrType_IPv4
;
695 senderAddr
.ip
.v4
.NotAnInteger
= sin
->sin_addr
.s_addr
;
696 senderPort
.NotAnInteger
= sin
->sin_port
;
698 else if (from
.ss_family
== AF_INET6
)
700 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&from
;
701 senderAddr
.type
= mDNSAddrType_IPv6
;
702 senderAddr
.ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
703 senderPort
.NotAnInteger
= sin6
->sin6_port
;
707 LogMsg("myCFSocketCallBack from is unknown address family %d", from
.ss_family
);
711 if (mDNSAddrIsDNSMulticast(&destAddr
))
713 // Even though we indicated a specific interface in the IP_ADD_MEMBERSHIP call, a weirdness of the
714 // sockets API means that even though this socket has only officially joined the multicast group
715 // on one specific interface, the kernel will still deliver multicast packets to it no matter which
716 // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
717 // To work around this weirdness, we use the IP_RECVIF option to find the name of the interface
718 // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
719 if (strcmp(info
->ifa_name
, packetifname
))
721 verbosedebugf("myCFSocketCallBack got a packet from %#a to %#a on interface %#a/%s (Ignored -- really arrived on interface %s)",
722 &senderAddr
, &destAddr
, &info
->ifinfo
.ip
, info
->ifa_name
, packetifname
);
726 verbosedebugf("myCFSocketCallBack got a packet from %#a to %#a on interface %#a/%s",
727 &senderAddr
, &destAddr
, &info
->ifinfo
.ip
, info
->ifa_name
);
731 verbosedebugf("myCFSocketCallBack got a unicast from %#a to %#a on interface %#a/%s packetifname %s)",
732 &senderAddr
, &destAddr
, &info
->ifinfo
.ip
, info
->ifa_name
, packetifname
);
733 // Note: For unicast packets, try to find the matching mDNSCore interface object
734 // (though we may not be able to, for unicast packets received over something like a PPP link)
735 NetworkInterfaceInfo
*intf
= m
->HostInterfaces
;
736 while (intf
&& strcmp(intf
->ifname
, packetifname
)) intf
= intf
->next
;
737 if (intf
) InterfaceID
= intf
->InterfaceID
;
740 if (err
< (int)sizeof(DNSMessageHeader
)) { debugf("myCFSocketCallBack packet length (%d) too short", err
); return; }
742 mDNSCoreReceive(m
, &packet
, (unsigned char*)&packet
+ err
, &senderAddr
, senderPort
, &destAddr
, destPort
, InterfaceID
, ttl
);
745 if (err
< 0 && (errno
!= EWOULDBLOCK
|| count
== 0))
747 // Something is busted here.
748 // CFSocket says there is a packet, but myrecvfrom says there is not.
749 // Try calling select() to get another opinion.
750 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
751 // All of this is racy, as data may have arrived after the call to select()
752 int save_errno
= errno
;
756 int solen
= sizeof(int);
759 FD_SET(s1
, &readfds
);
760 struct timeval timeout
;
763 int selectresult
= select(s1
+1, &readfds
, NULL
, NULL
, &timeout
);
764 if (getsockopt(s1
, SOL_SOCKET
, SO_ERROR
, &so_error
, &solen
) == -1)
765 LogMsg("myCFSocketCallBack getsockopt(SO_ERROR) error %d", errno
);
766 if (getsockopt(s1
, SOL_SOCKET
, SO_NREAD
, &so_nread
, &solen
) == -1)
767 LogMsg("myCFSocketCallBack getsockopt(SO_NREAD) error %d", errno
);
768 if (ioctl(s1
, FIONREAD
, &fionread
) == -1)
769 LogMsg("myCFSocketCallBack ioctl(FIONREAD) error %d", errno
);
770 static unsigned int numLogMessages
= 0;
771 if (numLogMessages
++ < 100)
772 LogMsg("myCFSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
773 s1
, err
, save_errno
, strerror(save_errno
), selectresult
, FD_ISSET(s1
, &readfds
) ? "" : "*NO* ", so_error
, so_nread
, fionread
, count
);
774 sleep(1); // After logging this error, rate limit so we don't flood syslog
778 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
779 mDNSlocal
void GetUserSpecifiedFriendlyComputerName(domainlabel
*const namelabel
)
781 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
782 CFStringRef cfs
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
785 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
790 // This gets the text of the field currently labelled "Rendezvous Name" in the Sharing Prefs Control Panel
791 mDNSlocal
void GetUserSpecifiedRFC1034ComputerName(domainlabel
*const namelabel
)
793 CFStringRef cfs
= SCDynamicStoreCopyLocalHostName(NULL
);
796 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
801 mDNSlocal mStatus
SetupSocket(NetworkInterfaceInfoOSX
*i
, mDNSIPPort port
, int *s
, CFSocketRef
*c
)
804 const int twofivefive
= 255;
806 if (*s
>= 0) { LogMsg("SetupSocket ERROR: socket %d is already set", *s
); return(-1); }
807 if (*c
) { LogMsg("SetupSocket ERROR: CFSocketRef %p is already set", *c
); return(-1); }
809 // Open the socket...
810 int skt
= socket(i
->sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
811 if (skt
< 0) { LogMsg("socket error %d errno %d (%s)", skt
, errno
, strerror(errno
)); return(skt
); }
813 // ... with a shared UDP port
814 mStatus err
= setsockopt(skt
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
815 if (err
< 0) { LogMsg("setsockopt - SO_REUSEPORT error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
817 if (i
->sa_family
== AF_INET
)
819 // We want to receive destination addresses
820 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVDSTADDR
, &on
, sizeof(on
));
821 if (err
< 0) { LogMsg("setsockopt - IP_RECVDSTADDR error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
823 // We want to receive interface identifiers
824 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
825 if (err
< 0) { LogMsg("setsockopt - IP_RECVIF error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
827 // We want to receive packet TTL value so we can check it
828 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVTTL
, &on
, sizeof(on
));
829 // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
831 // Add multicast group membership on this interface
832 struct in_addr addr
= { i
->ifinfo
.ip
.ip
.v4
.NotAnInteger
};
834 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroup
.NotAnInteger
;
835 imr
.imr_interface
= addr
;
836 err
= setsockopt(skt
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &imr
, sizeof(imr
));
837 if (err
< 0) { LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
839 // Specify outgoing interface too
840 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_IF
, &addr
, sizeof(addr
));
841 if (err
< 0) { LogMsg("setsockopt - IP_MULTICAST_IF error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
843 // Send unicast packets with TTL 255
844 err
= setsockopt(skt
, IPPROTO_IP
, IP_TTL
, &twofivefive
, sizeof(twofivefive
));
845 if (err
< 0) { LogMsg("setsockopt - IP_TTL error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
847 // And multicast packets with TTL 255 too
848 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_TTL
, &twofivefive
, sizeof(twofivefive
));
849 if (err
< 0) { LogMsg("setsockopt - IP_MULTICAST_TTL error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
851 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
852 const int ip_tosbits
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
;
853 err
= setsockopt(skt
, IPPROTO_IP
, IP_TOS
, &ip_tosbits
, sizeof(ip_tosbits
));
854 if (err
< 0) { LogMsg("setsockopt - IP_TOS error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
856 // And start listening for packets
857 struct sockaddr_in listening_sockaddr
;
858 listening_sockaddr
.sin_family
= AF_INET
;
859 listening_sockaddr
.sin_port
= port
.NotAnInteger
;
860 listening_sockaddr
.sin_addr
.s_addr
= 0; // Want to receive multicasts AND unicasts on this socket
861 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr
, sizeof(listening_sockaddr
));
864 // If we fail to bind to port 53 (because we're not root), that's okay, just tidy up and silently continue
865 if (port
.NotAnInteger
== UnicastDNSPort
.NotAnInteger
) { close(skt
); err
= 0; }
866 else LogMsg("bind error %ld errno %d (%s)", err
, errno
, strerror(errno
));
870 else if (i
->sa_family
== AF_INET6
)
872 // We want to receive destination addresses and receive interface identifiers
873 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_PKTINFO
, &on
, sizeof(on
));
874 if (err
< 0) { LogMsg("setsockopt - IPV6_PKTINFO error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
876 // We want to receive packet hop count value so we can check it
877 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_HOPLIMIT
, &on
, sizeof(on
));
878 if (err
< 0) { LogMsg("setsockopt - IPV6_HOPLIMIT error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
880 // We want to receive only IPv6 packets, without this option, we may
881 // get IPv4 addresses as mapped addresses.
882 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
));
883 if (err
< 0) { LogMsg("setsockopt - IPV6_V6ONLY error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
885 // Add multicast group membership on this interface
886 int interface_id
= if_nametoindex(i
->ifa_name
);
887 struct ipv6_mreq i6mr
;
888 i6mr
.ipv6mr_interface
= interface_id
;
889 i6mr
.ipv6mr_multiaddr
= *(struct in6_addr
*)&AllDNSLinkGroupv6
;
890 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &i6mr
, sizeof(i6mr
));
891 if (err
< 0) { LogMsg("setsockopt - IPV6_JOIN_GROUP error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
893 // Specify outgoing interface too
894 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &interface_id
, sizeof(interface_id
));
895 if (err
< 0) { LogMsg("setsockopt - IPV6_MULTICAST_IF error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
897 // Send unicast packets with TTL 255
898 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
899 if (err
< 0) { LogMsg("setsockopt - IPV6_UNICAST_HOPS error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
901 // And multicast packets with TTL 255 too
902 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
903 if (err
< 0) { LogMsg("setsockopt - IPV6_MULTICAST_HOPS error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
905 // Note: IPV6_TCLASS appears not to be implemented on OS X right now (or indeed on ANY version of Unix?)
907 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
908 int tclass
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
; // This may not be right (since tclass is not implemented on OS X, I can't test it)
909 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_TCLASS
, &tclass
, sizeof(tclass
));
910 if (err
< 0) { LogMsg("setsockopt - IPV6_TCLASS error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
913 // Want to receive our own packets
914 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &on
, sizeof(on
));
915 if (err
< 0) { LogMsg("setsockopt - IPV6_MULTICAST_LOOP error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
917 // And start listening for packets
918 struct sockaddr_in6 listening_sockaddr6
;
919 bzero(&listening_sockaddr6
, sizeof(listening_sockaddr6
));
920 listening_sockaddr6
.sin6_len
= sizeof(listening_sockaddr6
);
921 listening_sockaddr6
.sin6_family
= AF_INET6
;
922 listening_sockaddr6
.sin6_port
= port
.NotAnInteger
;
923 listening_sockaddr6
.sin6_flowinfo
= 0;
924 // listening_sockaddr6.sin6_addr = IN6ADDR_ANY_INIT; // Want to receive multicasts AND unicasts on this socket
925 listening_sockaddr6
.sin6_scope_id
= 0;
926 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr6
, sizeof(listening_sockaddr6
));
927 if (err
) { LogMsg("bind error %ld errno %d (%s)", err
, errno
, strerror(errno
)); return(err
); }
930 fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
932 CFSocketContext myCFSocketContext
= { 0, i
->ifinfo
.InterfaceID
, NULL
, NULL
, NULL
};
933 *c
= CFSocketCreateWithNative(kCFAllocatorDefault
, *s
, kCFSocketReadCallBack
, myCFSocketCallBack
, &myCFSocketContext
);
934 CFRunLoopSourceRef rls
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, *c
, 0);
935 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
941 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
)
943 if (sa
->sa_family
== AF_INET
)
945 struct sockaddr_in
*ifa_addr
= (struct sockaddr_in
*)sa
;
946 ip
->type
= mDNSAddrType_IPv4
;
947 ip
->ip
.v4
.NotAnInteger
= ifa_addr
->sin_addr
.s_addr
;
950 else if (sa
->sa_family
== AF_INET6
)
952 struct sockaddr_in6
*ifa_addr
= (struct sockaddr_in6
*)sa
;
953 ip
->type
= mDNSAddrType_IPv6
;
954 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr
->sin6_addr
)) ifa_addr
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
955 ip
->ip
.v6
= *(mDNSv6Addr
*)&ifa_addr
->sin6_addr
;
960 LogMsg("SetupAddr invalid sa_family %d", sa
->sa_family
);
965 mDNSlocal mStatus
AddInterfaceToList(mDNS
*const m
, struct ifaddrs
*ifa
)
967 mDNSu32 scope_id
= if_nametoindex(ifa
->ifa_name
);
969 SetupAddr(&ip
, ifa
->ifa_addr
);
970 NetworkInterfaceInfoOSX
**p
;
971 for (p
= &m
->p
->InterfaceList
; *p
; p
= &(*p
)->next
)
972 if (scope_id
== (*p
)->scope_id
&& mDNSSameAddress(&ip
, &(*p
)->ifinfo
.ip
))
974 debugf("AddInterfaceToList: Found existing interface %u with address %#a", scope_id
, &ip
);
975 (*p
)->CurrentlyActive
= mDNStrue
;
979 debugf("AddInterfaceToList: Making new interface %u with address %#a", scope_id
, &ip
);
980 NetworkInterfaceInfoOSX
*i
= (NetworkInterfaceInfoOSX
*)mallocL("NetworkInterfaceInfoOSX", sizeof(*i
));
982 i
->ifa_name
= (char *)mallocL("NetworkInterfaceInfoOSX name", strlen(ifa
->ifa_name
) + 1);
983 if (!i
->ifa_name
) { freeL("NetworkInterfaceInfoOSX", i
); return(-1); }
984 strcpy(i
->ifa_name
, ifa
->ifa_name
);
986 i
->ifinfo
.InterfaceID
= mDNSNULL
;
988 SetupAddr(&i
->ifinfo
.mask
, ifa
->ifa_netmask
);
989 strncpy(i
->ifinfo
.ifname
, ifa
->ifa_name
, sizeof(i
->ifinfo
.ifname
));
990 i
->ifinfo
.ifname
[sizeof(i
->ifinfo
.ifname
)-1] = 0;
991 i
->ifinfo
.Advertise
= m
->AdvertiseLocalAddresses
;
992 i
->ifinfo
.TxAndRx
= mDNSfalse
; // For now; will be set up later at the end of UpdateInterfaceList
996 i
->scope_id
= scope_id
;
997 i
->CurrentlyActive
= mDNStrue
;
998 i
->sa_family
= ifa
->ifa_addr
->sa_family
;
1008 if (!i
->ifa_name
) return(-1);
1013 mDNSlocal NetworkInterfaceInfoOSX
*FindRoutableIPv4(mDNS
*const m
, mDNSu32 scope_id
)
1015 NetworkInterfaceInfoOSX
*i
;
1016 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1017 if (i
->CurrentlyActive
&& i
->scope_id
== scope_id
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
1018 if (!(i
->ifinfo
.ip
.ip
.v4
.b
[0] == 169 && i
->ifinfo
.ip
.ip
.v4
.b
[1] == 254))
1023 mDNSlocal mStatus
UpdateInterfaceList(mDNS
*const m
)
1025 mDNSBool foundav4
= mDNSfalse
;
1026 struct ifaddrs
*ifa
= myGetIfAddrs(1);
1027 struct ifaddrs
*theLoopback
= NULL
;
1028 int err
= (ifa
!= NULL
) ? 0 : (errno
!= 0 ? errno
: -1);
1029 int InfoSocket
= err
? -1 : socket(AF_INET6
, SOCK_DGRAM
, 0);
1030 if (err
) return(err
);
1032 // Set up the nice label
1033 m
->nicelabel
.c
[0] = 0;
1034 GetUserSpecifiedFriendlyComputerName(&m
->nicelabel
);
1035 if (m
->nicelabel
.c
[0] == 0) MakeDomainLabelFromLiteralString(&m
->nicelabel
, "Macintosh");
1037 // Set up the RFC 1034-compliant label
1038 domainlabel hostlabel
;
1040 GetUserSpecifiedRFC1034ComputerName(&hostlabel
);
1041 if (hostlabel
.c
[0] == 0) MakeDomainLabelFromLiteralString(&hostlabel
, "Macintosh");
1042 // If the user has changed their dot-local host name since the last time we checked, then update our local copy.
1043 // If the user has not changed their dot-local host name, then leave ours alone (m->hostlabel may have gone through
1044 // repeated conflict resolution to get to its current value, and if we reset it, we'll have to go through all that again.)
1045 if (SameDomainLabel(m
->p
->userhostlabel
.c
, hostlabel
.c
))
1046 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
1049 debugf("Updating m->hostlabel to %#s", hostlabel
.c
);
1050 m
->p
->userhostlabel
= m
->hostlabel
= hostlabel
;
1051 mDNS_GenerateFQDN(m
);
1056 #if LIST_ALL_INTERFACES
1057 if (ifa
->ifa_addr
->sa_family
== AF_APPLETALK
)
1058 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d is AF_APPLETALK",
1059 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1060 else if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
1061 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d is AF_LINK",
1062 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1063 else if (ifa
->ifa_addr
->sa_family
!= AF_INET
&& ifa
->ifa_addr
->sa_family
!= AF_INET6
)
1064 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
1065 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1066 if (!(ifa
->ifa_flags
& IFF_UP
))
1067 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d Interface not IFF_UP",
1068 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1069 if (ifa
->ifa_flags
& IFF_POINTOPOINT
)
1070 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
1071 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1072 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
1073 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
1074 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1076 if ((ifa
->ifa_addr
->sa_family
== AF_INET
|| ifa
->ifa_addr
->sa_family
== AF_INET6
) &&
1077 (ifa
->ifa_flags
& IFF_MULTICAST
) &&
1078 (ifa
->ifa_flags
& IFF_UP
) && !(ifa
->ifa_flags
& IFF_POINTOPOINT
))
1080 int ifru_flags6
= 0;
1081 if (ifa
->ifa_addr
->sa_family
== AF_INET6
&& InfoSocket
>= 0)
1083 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
1084 struct in6_ifreq ifr6
;
1085 bzero((char *)&ifr6
, sizeof(ifr6
));
1086 strncpy(ifr6
.ifr_name
, ifa
->ifa_name
, sizeof(ifr6
.ifr_name
));
1087 ifr6
.ifr_addr
= *sin6
;
1088 if (ioctl(InfoSocket
, SIOCGIFAFLAG_IN6
, &ifr6
) != -1)
1089 ifru_flags6
= ifr6
.ifr_ifru
.ifru_flags6
;
1090 verbosedebugf("%s %.16a %04X %04X", ifa
->ifa_name
, &sin6
->sin6_addr
, ifa
->ifa_flags
, ifru_flags6
);
1092 if (!(ifru_flags6
& (IN6_IFF_NOTREADY
| IN6_IFF_DETACHED
| IN6_IFF_DEPRECATED
| IN6_IFF_TEMPORARY
)))
1094 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
1098 AddInterfaceToList(m
, ifa
);
1099 if (ifa
->ifa_addr
->sa_family
== AF_INET
)
1100 foundav4
= mDNStrue
;
1104 ifa
= ifa
->ifa_next
;
1107 // Temporary workaround: Multicast loopback on IPv6 interfaces appears not to work.
1108 // In the interim, we skip loopback interface only if we found at least one v4 interface to use
1109 if (!foundav4
&& theLoopback
)
1110 AddInterfaceToList(m
, theLoopback
);
1112 // Now the list is complete, set the TxAndRx setting for each interface.
1113 // We always send and receive using IPv4.
1114 // To reduce traffic, we send and receive using IPv6 only on interfaces that have no routable IPv4 address.
1115 // Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
1116 // which means there's a good chance that most or all the other devices on that network should also have v4.
1117 // 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.
1118 // At this time, reducing the packet rate is more important than v6-only devices on a large configured network,
1119 // so we are willing to make that sacrifice.
1120 NetworkInterfaceInfoOSX
*i
;
1121 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1122 if (i
->CurrentlyActive
)
1124 mDNSBool txrx
= ((i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) || !FindRoutableIPv4(m
, i
->scope_id
));
1125 if (i
->ifinfo
.TxAndRx
!= txrx
)
1127 i
->ifinfo
.TxAndRx
= txrx
;
1128 i
->CurrentlyActive
= 2; // State change; need to deregister and reregister this interface
1132 if (InfoSocket
>= 0) close(InfoSocket
);
1136 mDNSlocal NetworkInterfaceInfoOSX
*SearchForInterfaceByName(mDNS
*const m
, char *ifname
, int type
)
1138 NetworkInterfaceInfoOSX
*i
;
1139 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1140 if (!strcmp(i
->ifa_name
, ifname
) &&
1141 i
->CurrentlyActive
&&
1143 (type
== AF_INET
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) ||
1144 (type
== AF_INET6
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
) )) return(i
);
1148 mDNSlocal
void SetupActiveInterfaces(mDNS
*const m
)
1150 NetworkInterfaceInfoOSX
*i
;
1151 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1152 if (i
->CurrentlyActive
)
1155 NetworkInterfaceInfo
*n
= &i
->ifinfo
;
1156 NetworkInterfaceInfoOSX
*alias
= SearchForInterfaceByName(m
, i
->ifa_name
, i
->sa_family
);
1157 if (!alias
) alias
= i
;
1159 if (n
->InterfaceID
&& n
->InterfaceID
!= (mDNSInterfaceID
)alias
)
1161 LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != alias %p", n
->InterfaceID
, alias
);
1162 n
->InterfaceID
= mDNSNULL
;
1165 if (!n
->InterfaceID
)
1167 n
->InterfaceID
= (mDNSInterfaceID
)alias
;
1168 mDNS_RegisterInterface(m
, n
);
1169 debugf("SetupActiveInterfaces: Registered %s(%lu) InterfaceID %p %#a%s",
1170 i
->ifa_name
, i
->scope_id
, alias
, &n
->ip
, n
->InterfaceActive
? " (Primary)" : "");
1174 debugf("SetupActiveInterfaces: No TX/Rx on %s(%lu) InterfaceID %p %#a", i
->ifa_name
, i
->scope_id
, alias
, &n
->ip
);
1177 if (i
->sa_family
== AF_INET
&& alias
->sktv4
== -1)
1179 #if mDNS_AllowPort53
1180 err
= SetupSocket(i
, UnicastDNSPort
, &alias
->skt53
, &alias
->cfs53
);
1182 if (!err
) err
= SetupSocket(i
, MulticastDNSPort
, &alias
->sktv4
, &alias
->cfsv4
);
1183 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
);
1184 else LogMsg("SetupActiveInterfaces: v4 socket%2d %s(%lu) InterfaceID %p %#a FAILED", alias
->sktv4
, i
->ifa_name
, i
->scope_id
, n
->InterfaceID
, &n
->ip
);
1187 if (i
->sa_family
== AF_INET6
&& alias
->sktv6
== -1)
1189 err
= SetupSocket(i
, MulticastDNSPort
, &alias
->sktv6
, &alias
->cfsv6
);
1190 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
);
1191 else LogMsg("SetupActiveInterfaces: v6 socket%2d %s(%lu) InterfaceID %p %#a FAILED", alias
->sktv6
, i
->ifa_name
, i
->scope_id
, n
->InterfaceID
, &n
->ip
);
1197 mDNSlocal
void MarkAllInterfacesInactive(mDNS
*const m
)
1199 NetworkInterfaceInfoOSX
*i
;
1200 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1201 i
->CurrentlyActive
= mDNSfalse
;
1204 mDNSlocal mDNSu32
NumCacheRecordsForInterfaceID(mDNS
*const m
, mDNSInterfaceID id
)
1206 mDNSu32 slot
, used
= 0;
1208 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++)
1209 for (rr
= m
->rrcache_hash
[slot
]; rr
; rr
=rr
->next
)
1210 if (rr
->resrec
.InterfaceID
== id
) used
++;
1214 mDNSlocal
void ClearInactiveInterfaces(mDNS
*const m
)
1217 // If an interface is going away, then deregister this from the mDNSCore.
1218 // We also have to deregister it if the alias interface that it's using for its InterfaceID is going away.
1219 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
1220 // it refers to has gone away we'll crash.
1221 // Don't actually close the sockets or free the memory yet: When the last representative of an interface goes away
1222 // mDNSCore may want to send goodbye packets on that interface. (Not yet implemented, but a good idea anyway.)
1223 NetworkInterfaceInfoOSX
*i
;
1224 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1226 // 1. If this interface is no longer active, or its InterfaceID is changing, deregister it
1227 NetworkInterfaceInfoOSX
*alias
= (NetworkInterfaceInfoOSX
*)(i
->ifinfo
.InterfaceID
);
1228 NetworkInterfaceInfoOSX
*newalias
= SearchForInterfaceByName(m
, i
->ifa_name
, i
->sa_family
);
1229 if (!newalias
) newalias
= i
;
1230 if (i
->ifinfo
.InterfaceID
&& (!i
->CurrentlyActive
|| (alias
&& !alias
->CurrentlyActive
) || i
->CurrentlyActive
== 2 || newalias
!= alias
))
1232 debugf("ClearInactiveInterfaces: Deregistering %#a", &i
->ifinfo
.ip
);
1233 mDNS_DeregisterInterface(m
, &i
->ifinfo
);
1234 i
->ifinfo
.InterfaceID
= mDNSNULL
;
1239 // Now that everything that's going to deregister has done so, we can close sockets and free the memory
1240 NetworkInterfaceInfoOSX
**p
= &m
->p
->InterfaceList
;
1244 // 2. Close all our CFSockets. We'll recreate them later as necessary.
1245 // (We may have previously had both v4 and v6, and we may not need both any more.)
1246 // Note: MUST NOT close the underlying native BSD sockets.
1247 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately,
1248 // because it first has to unhook the sockets from its select() call, before it can safely close them.
1249 #if mDNS_AllowPort53
1250 if (i
->cfs53
) { CFSocketInvalidate(i
->cfs53
); CFRelease(i
->cfs53
); }
1254 if (i
->cfsv4
) { CFSocketInvalidate(i
->cfsv4
); CFRelease(i
->cfsv4
); }
1255 if (i
->cfsv6
) { CFSocketInvalidate(i
->cfsv6
); CFRelease(i
->cfsv6
); }
1256 i
->sktv4
= i
->sktv6
= -1;
1257 i
->cfsv4
= i
->cfsv6
= NULL
;
1259 // 3. If no longer active, delete interface from list and free memory
1260 if (!i
->CurrentlyActive
&& NumCacheRecordsForInterfaceID(m
, (mDNSInterfaceID
)i
) == 0)
1262 debugf("ClearInactiveInterfaces: Deleting %#a", &i
->ifinfo
.ip
);
1264 if (i
->ifa_name
) freeL("NetworkInterfaceInfoOSX name", i
->ifa_name
);
1265 freeL("NetworkInterfaceInfoOSX", i
);
1272 mDNSlocal
void NetworkChanged(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *context
)
1274 (void)store
; // Parameter not used
1275 (void)changedKeys
; // Parameter not used
1276 debugf("*** Network Configuration Change ***");
1278 mDNS
*const m
= (mDNS
*const)context
;
1279 MarkAllInterfacesInactive(m
);
1280 UpdateInterfaceList(m
);
1281 ClearInactiveInterfaces(m
);
1282 SetupActiveInterfaces(m
);
1284 if (m
->MainCallback
)
1285 m
->MainCallback(m
, mStatus_ConfigChanged
);
1288 mDNSlocal mStatus
WatchForNetworkChanges(mDNS
*const m
)
1291 SCDynamicStoreContext context
= { 0, m
, NULL
, NULL
, NULL
};
1292 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder"), NetworkChanged
, &context
);
1293 CFStringRef key1
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
1294 CFStringRef key2
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv6
);
1295 CFStringRef key3
= SCDynamicStoreKeyCreateComputerName(NULL
);
1296 CFStringRef key4
= SCDynamicStoreKeyCreateHostNames(NULL
);
1297 CFStringRef pattern1
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv4
);
1298 CFStringRef pattern2
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv6
);
1300 CFMutableArrayRef keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1301 CFMutableArrayRef patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1303 if (!store
) { LogMsg("SCDynamicStoreCreate failed: %s\n", SCErrorString(SCError())); goto error
; }
1304 if (!key1
|| !key2
|| !key3
|| !key4
|| !keys
|| !pattern1
|| !pattern2
|| !patterns
) goto error
;
1306 CFArrayAppendValue(keys
, key1
);
1307 CFArrayAppendValue(keys
, key2
);
1308 CFArrayAppendValue(keys
, key3
);
1309 CFArrayAppendValue(keys
, key4
);
1310 CFArrayAppendValue(patterns
, pattern1
);
1311 CFArrayAppendValue(patterns
, pattern2
);
1312 if (!SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
1313 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s\n", SCErrorString(SCError())); goto error
; }
1315 m
->p
->StoreRLS
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
1316 if (!m
->p
->StoreRLS
) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s\n", SCErrorString(SCError())); goto error
; }
1318 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
1319 m
->p
->Store
= store
;
1324 if (store
) CFRelease(store
);
1327 if (key1
) CFRelease(key1
);
1328 if (key2
) CFRelease(key2
);
1329 if (key3
) CFRelease(key3
);
1330 if (key4
) CFRelease(key4
);
1331 if (pattern1
) CFRelease(pattern1
);
1332 if (pattern2
) CFRelease(pattern2
);
1333 if (keys
) CFRelease(keys
);
1334 if (patterns
) CFRelease(patterns
);
1339 mDNSlocal
void PowerChanged(void *refcon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
1341 mDNS
*const m
= (mDNS
*const)refcon
;
1342 (void)service
; // Parameter not used
1345 case kIOMessageCanSystemPowerOff
: debugf("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
1346 case kIOMessageSystemWillPowerOff
: debugf("PowerChanged kIOMessageSystemWillPowerOff"); mDNSCoreMachineSleep(m
, true); break; // E0000250
1347 case kIOMessageSystemWillNotPowerOff
: debugf("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
1348 case kIOMessageCanSystemSleep
: debugf("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
1349 case kIOMessageSystemWillSleep
: debugf("PowerChanged kIOMessageSystemWillSleep"); mDNSCoreMachineSleep(m
, true); break; // E0000280
1350 case kIOMessageSystemWillNotSleep
: debugf("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
1351 case kIOMessageSystemHasPoweredOn
: debugf("PowerChanged kIOMessageSystemHasPoweredOn"); mDNSCoreMachineSleep(m
, false); break; // E0000300
1352 default: debugf("PowerChanged unknown message %X", messageType
); break;
1354 IOAllowPowerChange(m
->p
->PowerConnection
, (long)messageArgument
);
1357 mDNSlocal mStatus
WatchForPowerChanges(mDNS
*const m
)
1359 IONotificationPortRef thePortRef
;
1360 m
->p
->PowerConnection
= IORegisterForSystemPower(m
, &thePortRef
, PowerChanged
, &m
->p
->PowerNotifier
);
1361 if (m
->p
->PowerConnection
)
1363 m
->p
->PowerRLS
= IONotificationPortGetRunLoopSource(thePortRef
);
1364 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->PowerRLS
, kCFRunLoopDefaultMode
);
1365 return(mStatus_NoError
);
1370 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
1371 CF_EXPORT
const CFStringRef _kCFSystemVersionProductNameKey
;
1372 CF_EXPORT
const CFStringRef _kCFSystemVersionProductVersionKey
;
1373 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
1375 mDNSexport mDNSBool
mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring
)
1377 int major
= 0, minor
= 0;
1378 char letter
= 0, prodname
[256]="Mac OS X", prodvers
[256]="", buildver
[256]="?";
1379 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
1382 CFStringRef cfprodname
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductNameKey
);
1383 CFStringRef cfprodvers
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductVersionKey
);
1384 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
1385 if (cfprodname
) CFStringGetCString(cfprodname
, prodname
, sizeof(prodname
), kCFStringEncodingUTF8
);
1386 if (cfprodvers
) CFStringGetCString(cfprodvers
, prodvers
, sizeof(prodvers
), kCFStringEncodingUTF8
);
1387 if (cfbuildver
) CFStringGetCString(cfbuildver
, buildver
, sizeof(buildver
), kCFStringEncodingUTF8
);
1388 sscanf(buildver
, "%d%c%d", &major
, &letter
, &minor
);
1391 if (HINFO_SWstring
) mDNS_snprintf(HINFO_SWstring
, 256, "%s %s (%s), %s", prodname
, prodvers
, buildver
, mDNSResponderVersionString
);
1395 mDNSlocal mStatus
mDNSPlatformInit_setup(mDNS
*const m
)
1399 m
->hostlabel
.c
[0] = 0;
1401 char *HINFO_HWstring
= "Macintosh";
1402 char HINFO_HWstring_buffer
[256];
1403 int get_model
[2] = { CTL_HW
, HW_MODEL
};
1404 size_t len_model
= sizeof(HINFO_HWstring_buffer
);
1405 if (sysctl(get_model
, 2, HINFO_HWstring_buffer
, &len_model
, NULL
, 0) == 0)
1406 HINFO_HWstring
= HINFO_HWstring_buffer
;
1408 char HINFO_SWstring
[256] = "";
1409 if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring
) < 7) m
->KnownBugs
= mDNS_KnownBug_PhantomInterfaces
;
1411 mDNSu32 hlen
= mDNSPlatformStrLen(HINFO_HWstring
);
1412 mDNSu32 slen
= mDNSPlatformStrLen(HINFO_SWstring
);
1413 if (hlen
+ slen
< 254)
1415 m
->HIHardware
.c
[0] = hlen
;
1416 m
->HISoftware
.c
[0] = slen
;
1417 mDNSPlatformMemCopy(HINFO_HWstring
, &m
->HIHardware
.c
[1], hlen
);
1418 mDNSPlatformMemCopy(HINFO_SWstring
, &m
->HISoftware
.c
[1], slen
);
1421 m
->p
->InterfaceList
= mDNSNULL
;
1422 m
->p
->userhostlabel
.c
[0] = 0;
1423 UpdateInterfaceList(m
);
1424 SetupActiveInterfaces(m
);
1426 err
= WatchForNetworkChanges(m
);
1427 if (err
) return(err
);
1429 err
= WatchForPowerChanges(m
);
1433 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
1435 mStatus result
= mDNSPlatformInit_setup(m
);
1436 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
1437 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
1438 if (result
== mStatus_NoError
) mDNSCoreInitComplete(m
, mStatus_NoError
);
1442 mDNSexport
void mDNSPlatformClose(mDNS
*const m
)
1444 if (m
->p
->PowerConnection
)
1446 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->PowerRLS
, kCFRunLoopDefaultMode
);
1447 CFRunLoopSourceInvalidate(m
->p
->PowerRLS
);
1448 CFRelease(m
->p
->PowerRLS
);
1449 IODeregisterForSystemPower(&m
->p
->PowerNotifier
);
1450 m
->p
->PowerConnection
= NULL
;
1451 m
->p
->PowerNotifier
= NULL
;
1452 m
->p
->PowerRLS
= NULL
;
1457 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
1458 CFRunLoopSourceInvalidate(m
->p
->StoreRLS
);
1459 CFRelease(m
->p
->StoreRLS
);
1460 CFRelease(m
->p
->Store
);
1462 m
->p
->StoreRLS
= NULL
;
1465 MarkAllInterfacesInactive(m
);
1466 ClearInactiveInterfaces(m
);
1469 mDNSexport mDNSs32 mDNSPlatformOneSecond
= 1000;
1471 mDNSexport mStatus
mDNSPlatformTimeInit(mDNSs32
*timenow
)
1473 // Notes: Typical values for mach_timebase_info:
1474 // tbi.numer = 1000 million
1475 // tbi.denom = 33 million
1476 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
1477 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
1478 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
1479 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
1480 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
1482 // Arithmetic notes:
1483 // tbi.denom is at least 1, and not more than 2^32-1.
1484 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
1485 // tbi.denom is at least 1, and not more than 2^32-1.
1486 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
1487 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
1488 // which is unlikely on any current or future Macintosh.
1489 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
1490 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
1491 struct mach_timebase_info tbi
;
1492 kern_return_t result
= mach_timebase_info(&tbi
);
1493 if (result
!= KERN_SUCCESS
) return(result
);
1494 clockdivisor
= ((uint64_t)tbi
.denom
* 1000000) / tbi
.numer
;
1495 *timenow
= mDNSPlatformTimeNow();
1496 return(mStatus_NoError
);
1499 mDNSexport mDNSs32
mDNSPlatformTimeNow(void)
1501 if (clockdivisor
== 0) { LogMsg("mDNSPlatformTimeNow called before mDNSPlatformTimeInit"); return(0); }
1502 return((mDNSs32
)(mach_absolute_time() / clockdivisor
));
1505 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
1506 mDNSexport
void mDNSPlatformLock (const mDNS
*const m
) { (void)m
; }
1507 mDNSexport
void mDNSPlatformUnlock (const mDNS
*const m
) { (void)m
; }
1508 mDNSexport
void mDNSPlatformStrCopy(const void *src
, void *dst
) { strcpy((char *)dst
, (char *)src
); }
1509 mDNSexport mDNSu32
mDNSPlatformStrLen (const void *src
) { return(strlen((char*)src
)); }
1510 mDNSexport
void mDNSPlatformMemCopy(const void *src
, void *dst
, mDNSu32 len
) { memcpy(dst
, src
, len
); }
1511 mDNSexport mDNSBool
mDNSPlatformMemSame(const void *src
, const void *dst
, mDNSu32 len
) { return(memcmp(dst
, src
, len
) == 0); }
1512 mDNSexport
void mDNSPlatformMemZero( void *dst
, mDNSu32 len
) { bzero(dst
, len
); }
1513 mDNSexport
void * mDNSPlatformMemAllocate(mDNSu32 len
) { return(mallocL("mDNSPlatformMemAllocate", len
)); }
1514 mDNSexport
void mDNSPlatformMemFree (void *mem
) { freeL("mDNSPlatformMemFree", mem
); }