]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/CFSocket.c
mDNSResponder-58.8.1.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / CFSocket.c
1 /*
2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22
23 Change History (most recent first):
24
25 $Log: CFSocket.c,v $
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
28
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
32
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
36
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
40
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
43
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
46
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)
49
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
53
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
56
57 Revision 1.111 2003/08/18 22:53:37 cheshire
58 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformTimeNow()
59
60 Revision 1.110 2003/08/16 03:39:00 cheshire
61 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
62
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
66
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.
71
72 Revision 1.107 2003/08/12 19:56:25 cheshire
73 Update to APSL 2.0
74
75 Revision 1.106 2003/08/12 13:48:32 cheshire
76 Add comment explaining clockdivisor calculation
77
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)
82
83 Revision 1.104 2003/08/12 13:12:07 cheshire
84 Textual search/replace: Indicate local functions using "mDNSlocal" instead of "static"
85
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
88
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
92
93 Revision 1.101 2003/08/05 22:20:16 cheshire
94 <rdar://problem/3330324> Need to check IP TTL on responses
95
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)
99
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
103
104 Revision 1.98 2003/07/20 03:38:51 ksekar
105 Bug #: 3320722
106 Completed support for Unix-domain socket based API.
107
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
111
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
114
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
118
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
121
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);
125
126 Revision 1.92 2003/07/02 21:19:51 cheshire
127 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
128
129 Revision 1.91 2003/06/24 01:53:51 cheshire
130 Minor update to comments
131
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
135
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)
139
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
143
144 Revision 1.87 2003/06/10 01:14:11 cheshire
145 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
146
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
149
150 Revision 1.85 2003/05/28 02:39:47 cheshire
151 Minor change to debugging messages
152
153 Revision 1.84 2003/05/27 22:29:40 cheshire
154 Remove out-dated comment
155
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
161
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
164
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.
170
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
174
175 Revision 1.79 2003/05/23 23:07:44 cheshire
176 <rdar://problem/3268199> Must not write to stderr when running as daemon
177
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
181
182 Revision 1.77 2003/05/23 01:12:05 cheshire
183 Minor code tidying
184
185 Revision 1.76 2003/05/22 01:26:01 cheshire
186 Tidy up log messages
187
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
191
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).
196
197 Revision 1.73 2003/05/21 17:56:29 ksekar
198 Bug #: <rdar://problem/3191277>: mDNSResponder doesn't watch for IPv6 address changes
199
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
205
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.
213
214 Revision 1.70 2003/05/07 18:30:24 cheshire
215 Fix signed/unsigned comparison warning
216
217 Revision 1.69 2003/05/06 20:14:44 cheshire
218 Change "tp" to "tv"
219
220 Revision 1.68 2003/05/06 00:00:49 cheshire
221 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
222
223 Revision 1.67 2003/04/29 00:43:44 cheshire
224 Fix compiler warnings
225
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
228
229 Revision 1.65 2003/04/26 02:34:01 cheshire
230 Add missing mDNSexport
231
232 Revision 1.64 2003/04/15 16:48:06 jgraessl
233 Bug #: 3228833
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.
236
237 Revision 1.63 2003/04/15 16:33:50 jgraessl
238 Bug #: 3221880
239 Switched to our own copy of if_indextoname to improve performance.
240
241 Revision 1.62 2003/03/28 01:55:44 cheshire
242 Minor improvements to debugging messages
243
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
247 Fixes:
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)
251
252 Revision 1.60 2003/03/15 04:40:38 cheshire
253 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
254
255 Revision 1.59 2003/03/11 01:23:26 cheshire
256 Bug #: 3194246 mDNSResponder socket problems
257
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
261
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
265
266 Revision 1.56 2003/03/05 01:50:38 cheshire
267 Bug #: 3189097 Additional debugging code in mDNSResponder
268
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")
272
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
276
277 Revision 1.53 2003/01/29 02:21:23 cheshire
278 Return mStatus_Invalid if can't send packet because socket not available
279
280 Revision 1.52 2003/01/28 19:39:43 jgraessl
281 Enabling AAAA over IPv4 support.
282
283 Revision 1.51 2003/01/28 05:11:23 cheshire
284 Fixed backwards comparison in SearchForInterfaceByName
285
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
291
292 Revision 1.49 2002/12/23 22:13:30 jgraessl
293 Reviewed by: Stuart Cheshire
294 Initial IPv6 support for mDNSResponder.
295
296 Revision 1.48 2002/11/22 01:37:52 cheshire
297 Bug #: 3108426 mDNSResponder is monitoring ServiceEntities instead of InterfaceEntities
298
299 Revision 1.47 2002/09/21 20:44:51 zarzycki
300 Added APSL info
301
302 Revision 1.46 2002/09/19 21:25:35 cheshire
303 mDNS_snprintf() doesn't need to be in a separate file
304
305 Revision 1.45 2002/09/17 01:45:13 cheshire
306 Add LIST_ALL_INTERFACES symbol for debugging
307
308 Revision 1.44 2002/09/17 01:36:23 cheshire
309 Move Puma support to CFSocketPuma.c
310
311 Revision 1.43 2002/09/17 01:05:28 cheshire
312 Change mDNS_AdvertiseLocalAddresses to be an Init parameter instead of a global
313
314 Revision 1.42 2002/09/16 23:13:50 cheshire
315 Minor code tidying
316
317 */
318
319 // ***************************************************************************
320 // mDNS-CFSocket.c:
321 // Supporting routines to run mDNS on a CFRunLoop platform
322 // ***************************************************************************
323
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
331
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
335
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
340
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
344
345 #include <stdio.h>
346 #include <unistd.h> // For select() and close()
347 #include <stdarg.h> // For va_list support
348 #include <net/if.h>
349 #include <net/if_dl.h>
350 #include <sys/uio.h>
351 #include <sys/param.h>
352 #include <sys/socket.h>
353 #include <sys/sysctl.h>
354 #include <fcntl.h>
355 #include <sys/ioctl.h>
356
357 #include <netinet/in.h> // For IP_RECVTTL
358 #ifndef IP_RECVTTL
359 #define IP_RECVTTL 24 /* bool; receive reception TTL w/dgram */
360 #endif
361
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.
365
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"
372 #else
373 #include <ifaddrs.h>
374 #endif
375
376 #include <IOKit/IOKitLib.h>
377 #include <IOKit/IOMessage.h>
378 #include <mach/mach_time.h>
379
380 // ***************************************************************************
381 // Globals
382
383 static mDNSu32 clockdivisor = 0;
384
385 // ***************************************************************************
386 // Macros
387
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])
390
391 #define mDNSAddressIsAllDNSLinkGroup(X) ( \
392 ((X)->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address((X)->ip.v4, AllDNSLinkGroup )) || \
393 ((X)->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address((X)->ip.v6, AllDNSLinkGroupv6)) )
394
395 // ***************************************************************************
396 // Functions
397
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
400 #if MDNS_DEBUGMSGS
401 mDNSexport void debugf_(const char *format, ...)
402 {
403 unsigned char buffer[512];
404 va_list ptr;
405 va_start(ptr,format);
406 buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
407 va_end(ptr);
408 fprintf(stderr,"%s\n", buffer);
409 fflush(stderr);
410 }
411 #endif
412
413 #if MDNS_DEBUGMSGS > 1
414 mDNSexport void verbosedebugf_(const char *format, ...)
415 {
416 unsigned char buffer[512];
417 va_list ptr;
418 va_start(ptr,format);
419 buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
420 va_end(ptr);
421 fprintf(stderr,"%s\n", buffer);
422 fflush(stderr);
423 }
424 #endif
425
426 mDNSexport void LogMsg(const char *format, ...)
427 {
428 unsigned char buffer[512];
429 va_list ptr;
430 va_start(ptr,format);
431 buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
432 va_end(ptr);
433
434 extern int debug_mode;
435 if (debug_mode) // In debug_mode we write to stderr
436 {
437 fprintf(stderr,"%s\n", buffer);
438 fflush(stderr);
439 }
440 else // else, in production mode, we write to syslog
441 {
442 openlog("mDNSResponder", LOG_CONS | LOG_PERROR | LOG_PID, LOG_DAEMON);
443 syslog(LOG_ERR, "%s", buffer);
444 closelog();
445 }
446 }
447
448 mDNSlocal struct ifaddrs* myGetIfAddrs(int refresh)
449 {
450 static struct ifaddrs *ifa = NULL;
451
452 if (refresh && ifa)
453 {
454 freeifaddrs(ifa);
455 ifa = NULL;
456 }
457
458 if (ifa == NULL) getifaddrs(&ifa);
459
460 return ifa;
461 }
462
463 mDNSlocal int myIfIndexToName(u_short index, char* name)
464 {
465 struct ifaddrs *ifa;
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; }
470 return -1;
471 }
472
473 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS *const m, mDNSu32 index)
474 {
475 NetworkInterfaceInfoOSX *i;
476 if (index == (uint32_t)~0) return((mDNSInterfaceID)~0);
477 if (index)
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);
481 return(mDNSNULL);
482 }
483
484 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m, mDNSInterfaceID id)
485 {
486 NetworkInterfaceInfoOSX *i;
487 if (id == (mDNSInterfaceID)~0) return((mDNSu32)~0);
488 if (id)
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)
492 return i->scope_id;
493 return 0;
494 }
495
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)
498 {
499 #pragma unused(m)
500 NetworkInterfaceInfoOSX *info = (NetworkInterfaceInfoOSX *)InterfaceID;
501 struct sockaddr_storage to;
502 int s, err;
503
504 if (!InterfaceID) { LogMsg("mDNSPlatformSendUDP ERROR! Cannot send from zero InterfaceID"); return mStatus_BadParamErr; }
505
506 if (dst->type == mDNSAddrType_IPv4)
507 {
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;
513 }
514 else if (dst->type == mDNSAddrType_IPv6)
515 {
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;
523 }
524 else
525 {
526 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!\n");
527 return mStatus_BadParamErr;
528 }
529
530 if (srcPort.NotAnInteger == MulticastDNSPort.NotAnInteger)
531 {
532 if (dst->type == mDNSAddrType_IPv4) s = info->sktv4;
533 else if (dst->type == mDNSAddrType_IPv6) s = info->sktv6;
534 else s = -1;
535 }
536 #if mDNS_AllowPort53
537 else if (srcPort.NotAnInteger == UnicastDNSPort.NotAnInteger && dst->type == mDNSAddrType_IPv4)
538 s = info->skt53;
539 #endif
540 else { LogMsg("Source port %d not allowed", (mDNSu16)srcPort.b[0]<<8 | srcPort.b[1]); return(-1); }
541
542 if (s >= 0)
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);
545 else
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]);
548
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);
552
553 err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len);
554 if (err < 0)
555 {
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));
564 return(err);
565 }
566
567 return(mStatus_NoError);
568 }
569
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)
572 {
573 static unsigned int numLogMessages = 0;
574 struct iovec databuffers = { (char *)buffer, max };
575 struct msghdr msg;
576 ssize_t n;
577 struct cmsghdr *cmPtr;
578 char ancillary[1024];
579
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
581
582 // Set up the message
583 msg.msg_name = (caddr_t)from;
584 msg.msg_namelen = *fromlen;
585 msg.msg_iov = &databuffers;
586 msg.msg_iovlen = 1;
587 msg.msg_control = (caddr_t)&ancillary;
588 msg.msg_controllen = sizeof(ancillary);
589 msg.msg_flags = 0;
590
591 // Receive the data
592 n = recvmsg(s, &msg, 0);
593 if (n<0)
594 {
595 if (errno != EWOULDBLOCK && numLogMessages++ < 100) LogMsg("CFSocket.c: recvmsg(%d) returned error %d errno %d", s, n, errno);
596 return(-1);
597 }
598 if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
599 {
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));
602 return(-1);
603 }
604 if (msg.msg_flags & MSG_CTRUNC)
605 {
606 if (numLogMessages++ < 100) LogMsg("CFSocket.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
607 return(-1);
608 }
609
610 *fromlen = msg.msg_namelen;
611
612 // Parse each option out of the ancillary data.
613 for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
614 {
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)
617 {
618 dstaddr->type = mDNSAddrType_IPv4;
619 dstaddr->ip.v4.NotAnInteger = *(u_int32_t*)CMSG_DATA(cmPtr);
620 }
621 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF)
622 {
623 struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr);
624 if (sdl->sdl_nlen < IF_NAMESIZE)
625 {
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);
629 }
630 }
631 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVTTL)
632 {
633 *ttl = *(u_char*)CMSG_DATA(cmPtr);
634 }
635 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_PKTINFO)
636 {
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);
641 }
642 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT)
643 {
644 *ttl = *(int*)CMSG_DATA(cmPtr);
645 }
646 }
647
648 return(n);
649 }
650
651 mDNSlocal void myCFSocketCallBack(CFSocketRef cfs, CFSocketCallBackType CallBackType, CFDataRef address, const void *data, void *context)
652 {
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;
658 DNSMessage packet;
659 struct sockaddr_storage from;
660 size_t fromlen = sizeof(from);
661 char packetifname[IF_NAMESIZE] = "";
662 int err, s1 = -1, skt = CFSocketGetNative(cfs);
663 int count = 0;
664
665 (void)address; // Parameter not used
666 (void)data; // Parameter not used
667
668 if (CallBackType != kCFSocketReadCallBack) LogMsg("myCFSocketCallBack: Why is CallBackType %d not kCFSocketReadCallBack?", CallBackType);
669
670 #if mDNS_AllowPort53
671 if (cfs == info->cfs53) { s1 = info->skt53; destPort = UnicastDNSPort; }
672 else
673 #endif
674 if (cfs == info->cfsv4) s1 = info->sktv4;
675 else if (cfs == info->cfsv6) s1 = info->sktv6;
676
677 if (s1 < 0 || s1 != skt)
678 {
679 LogMsg("myCFSocketCallBack: s1 %d native socket %d, cfs %p", s1, skt, cfs);
680 #if mDNS_AllowPort53
681 LogMsg("myCFSocketCallBack: cfs53 %p, skt53 %d", info->cfs53, info->skt53);
682 #endif
683 LogMsg("myCFSocketCallBack: cfsv4 %p, sktv4 %d", info->cfsv4, info->sktv4);
684 LogMsg("myCFSocketCallBack: cfsv6 %p, sktv6 %d", info->cfsv6, info->sktv6);
685 }
686
687 mDNSu8 ttl;
688 while ((err = myrecvfrom(s1, &packet, sizeof(packet), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl)) >= 0)
689 {
690 count++;
691 if (from.ss_family == AF_INET)
692 {
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;
697 }
698 else if (from.ss_family == AF_INET6)
699 {
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;
704 }
705 else
706 {
707 LogMsg("myCFSocketCallBack from is unknown address family %d", from.ss_family);
708 return;
709 }
710
711 if (mDNSAddrIsDNSMulticast(&destAddr))
712 {
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))
720 {
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);
723 return;
724 }
725 else
726 verbosedebugf("myCFSocketCallBack got a packet from %#a to %#a on interface %#a/%s",
727 &senderAddr, &destAddr, &info->ifinfo.ip, info->ifa_name);
728 }
729 else
730 {
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;
738 }
739
740 if (err < (int)sizeof(DNSMessageHeader)) { debugf("myCFSocketCallBack packet length (%d) too short", err); return; }
741
742 mDNSCoreReceive(m, &packet, (unsigned char*)&packet + err, &senderAddr, senderPort, &destAddr, destPort, InterfaceID, ttl);
743 }
744
745 if (err < 0 && (errno != EWOULDBLOCK || count == 0))
746 {
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;
753 int so_error = -1;
754 int so_nread = -1;
755 int fionread = -1;
756 int solen = sizeof(int);
757 fd_set readfds;
758 FD_ZERO(&readfds);
759 FD_SET(s1, &readfds);
760 struct timeval timeout;
761 timeout.tv_sec = 0;
762 timeout.tv_usec = 0;
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
775 }
776 }
777
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)
780 {
781 CFStringEncoding encoding = kCFStringEncodingUTF8;
782 CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
783 if (cfs)
784 {
785 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
786 CFRelease(cfs);
787 }
788 }
789
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)
792 {
793 CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
794 if (cfs)
795 {
796 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
797 CFRelease(cfs);
798 }
799 }
800
801 mDNSlocal mStatus SetupSocket(NetworkInterfaceInfoOSX *i, mDNSIPPort port, int *s, CFSocketRef *c)
802 {
803 const int on = 1;
804 const int twofivefive = 255;
805
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); }
808
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); }
812
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); }
816
817 if (i->sa_family == AF_INET)
818 {
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); }
822
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); }
826
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
830
831 // Add multicast group membership on this interface
832 struct in_addr addr = { i->ifinfo.ip.ip.v4.NotAnInteger };
833 struct ip_mreq imr;
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); }
838
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); }
842
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); }
846
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); }
850
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); }
855
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));
862 if (err)
863 {
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));
867 return(err);
868 }
869 }
870 else if (i->sa_family == AF_INET6)
871 {
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); }
875
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); }
879
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); }
884
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); }
892
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); }
896
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); }
900
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); }
904
905 // Note: IPV6_TCLASS appears not to be implemented on OS X right now (or indeed on ANY version of Unix?)
906 #ifdef IPV6_TCLASS
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); }
911 #endif
912
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); }
916
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); }
928 }
929
930 fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
931 *s = skt;
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);
936 CFRelease(rls);
937
938 return(err);
939 }
940
941 mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
942 {
943 if (sa->sa_family == AF_INET)
944 {
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;
948 return(0);
949 }
950 else if (sa->sa_family == AF_INET6)
951 {
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;
956 return(0);
957 }
958 else
959 {
960 LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
961 return(-1);
962 }
963 }
964
965 mDNSlocal mStatus AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa)
966 {
967 mDNSu32 scope_id = if_nametoindex(ifa->ifa_name);
968 mDNSAddr ip;
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))
973 {
974 debugf("AddInterfaceToList: Found existing interface %u with address %#a", scope_id, &ip);
975 (*p)->CurrentlyActive = mDNStrue;
976 return(0);
977 }
978
979 debugf("AddInterfaceToList: Making new interface %u with address %#a", scope_id, &ip);
980 NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
981 if (!i) return(-1);
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);
985
986 i->ifinfo.InterfaceID = mDNSNULL;
987 i->ifinfo.ip = ip;
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
993
994 i->next = mDNSNULL;
995 i->m = m;
996 i->scope_id = scope_id;
997 i->CurrentlyActive = mDNStrue;
998 i->sa_family = ifa->ifa_addr->sa_family;
999 #if mDNS_AllowPort53
1000 i->skt53 = -1;
1001 i->cfs53 = NULL;
1002 #endif
1003 i->sktv4 = -1;
1004 i->cfsv4 = NULL;
1005 i->sktv6 = -1;
1006 i->cfsv6 = NULL;
1007
1008 if (!i->ifa_name) return(-1);
1009 *p = i;
1010 return(0);
1011 }
1012
1013 mDNSlocal NetworkInterfaceInfoOSX *FindRoutableIPv4(mDNS *const m, mDNSu32 scope_id)
1014 {
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))
1019 return(i);
1020 return(mDNSNULL);
1021 }
1022
1023 mDNSlocal mStatus UpdateInterfaceList(mDNS *const m)
1024 {
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);
1031
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");
1036
1037 // Set up the RFC 1034-compliant label
1038 domainlabel hostlabel;
1039 hostlabel.c[0] = 0;
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);
1047 else
1048 {
1049 debugf("Updating m->hostlabel to %#s", hostlabel.c);
1050 m->p->userhostlabel = m->hostlabel = hostlabel;
1051 mDNS_GenerateFQDN(m);
1052 }
1053
1054 while (ifa)
1055 {
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);
1075 #endif
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))
1079 {
1080 int ifru_flags6 = 0;
1081 if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
1082 {
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);
1091 }
1092 if (!(ifru_flags6 & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
1093 {
1094 if (ifa->ifa_flags & IFF_LOOPBACK)
1095 theLoopback = ifa;
1096 else
1097 {
1098 AddInterfaceToList(m, ifa);
1099 if (ifa->ifa_addr->sa_family == AF_INET)
1100 foundav4 = mDNStrue;
1101 }
1102 }
1103 }
1104 ifa = ifa->ifa_next;
1105 }
1106
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);
1111
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)
1123 {
1124 mDNSBool txrx = ((i->ifinfo.ip.type == mDNSAddrType_IPv4) || !FindRoutableIPv4(m, i->scope_id));
1125 if (i->ifinfo.TxAndRx != txrx)
1126 {
1127 i->ifinfo.TxAndRx = txrx;
1128 i->CurrentlyActive = 2; // State change; need to deregister and reregister this interface
1129 }
1130 }
1131
1132 if (InfoSocket >= 0) close(InfoSocket);
1133 return(err);
1134 }
1135
1136 mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, char *ifname, int type)
1137 {
1138 NetworkInterfaceInfoOSX *i;
1139 for (i = m->p->InterfaceList; i; i = i->next)
1140 if (!strcmp(i->ifa_name, ifname) &&
1141 i->CurrentlyActive &&
1142 ((AAAA_OVER_V4 ) ||
1143 (type == AF_INET && i->ifinfo.ip.type == mDNSAddrType_IPv4) ||
1144 (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6) )) return(i);
1145 return(NULL);
1146 }
1147
1148 mDNSlocal void SetupActiveInterfaces(mDNS *const m)
1149 {
1150 NetworkInterfaceInfoOSX *i;
1151 for (i = m->p->InterfaceList; i; i = i->next)
1152 if (i->CurrentlyActive)
1153 {
1154 mStatus err = 0;
1155 NetworkInterfaceInfo *n = &i->ifinfo;
1156 NetworkInterfaceInfoOSX *alias = SearchForInterfaceByName(m, i->ifa_name, i->sa_family);
1157 if (!alias) alias = i;
1158
1159 if (n->InterfaceID && n->InterfaceID != (mDNSInterfaceID)alias)
1160 {
1161 LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != alias %p", n->InterfaceID, alias);
1162 n->InterfaceID = mDNSNULL;
1163 }
1164
1165 if (!n->InterfaceID)
1166 {
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)" : "");
1171 }
1172
1173 if (!n->TxAndRx)
1174 debugf("SetupActiveInterfaces: No TX/Rx on %s(%lu) InterfaceID %p %#a", i->ifa_name, i->scope_id, alias, &n->ip);
1175 else
1176 {
1177 if (i->sa_family == AF_INET && alias->sktv4 == -1)
1178 {
1179 #if mDNS_AllowPort53
1180 err = SetupSocket(i, UnicastDNSPort, &alias->skt53, &alias->cfs53);
1181 #endif
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);
1185 }
1186
1187 if (i->sa_family == AF_INET6 && alias->sktv6 == -1)
1188 {
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);
1192 }
1193 }
1194 }
1195 }
1196
1197 mDNSlocal void MarkAllInterfacesInactive(mDNS *const m)
1198 {
1199 NetworkInterfaceInfoOSX *i;
1200 for (i = m->p->InterfaceList; i; i = i->next)
1201 i->CurrentlyActive = mDNSfalse;
1202 }
1203
1204 mDNSlocal mDNSu32 NumCacheRecordsForInterfaceID(mDNS *const m, mDNSInterfaceID id)
1205 {
1206 mDNSu32 slot, used = 0;
1207 CacheRecord *rr;
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++;
1211 return(used);
1212 }
1213
1214 mDNSlocal void ClearInactiveInterfaces(mDNS *const m)
1215 {
1216 // First pass:
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)
1225 {
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))
1231 {
1232 debugf("ClearInactiveInterfaces: Deregistering %#a", &i->ifinfo.ip);
1233 mDNS_DeregisterInterface(m, &i->ifinfo);
1234 i->ifinfo.InterfaceID = mDNSNULL;
1235 }
1236 }
1237
1238 // Second pass:
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;
1241 while (*p)
1242 {
1243 i = *p;
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); }
1251 i->skt53 = -1;
1252 i->cfs53 = NULL;
1253 #endif
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;
1258
1259 // 3. If no longer active, delete interface from list and free memory
1260 if (!i->CurrentlyActive && NumCacheRecordsForInterfaceID(m, (mDNSInterfaceID)i) == 0)
1261 {
1262 debugf("ClearInactiveInterfaces: Deleting %#a", &i->ifinfo.ip);
1263 *p = i->next;
1264 if (i->ifa_name) freeL("NetworkInterfaceInfoOSX name", i->ifa_name);
1265 freeL("NetworkInterfaceInfoOSX", i);
1266 }
1267 else
1268 p = &i->next;
1269 }
1270 }
1271
1272 mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
1273 {
1274 (void)store; // Parameter not used
1275 (void)changedKeys; // Parameter not used
1276 debugf("*** Network Configuration Change ***");
1277
1278 mDNS *const m = (mDNS *const)context;
1279 MarkAllInterfacesInactive(m);
1280 UpdateInterfaceList(m);
1281 ClearInactiveInterfaces(m);
1282 SetupActiveInterfaces(m);
1283
1284 if (m->MainCallback)
1285 m->MainCallback(m, mStatus_ConfigChanged);
1286 }
1287
1288 mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
1289 {
1290 mStatus err = -1;
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);
1299
1300 CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1301 CFMutableArrayRef patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1302
1303 if (!store) { LogMsg("SCDynamicStoreCreate failed: %s\n", SCErrorString(SCError())); goto error; }
1304 if (!key1 || !key2 || !key3 || !key4 || !keys || !pattern1 || !pattern2 || !patterns) goto error;
1305
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; }
1314
1315 m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
1316 if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s\n", SCErrorString(SCError())); goto error; }
1317
1318 CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
1319 m->p->Store = store;
1320 err = 0;
1321 goto exit;
1322
1323 error:
1324 if (store) CFRelease(store);
1325
1326 exit:
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);
1335
1336 return(err);
1337 }
1338
1339 mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
1340 {
1341 mDNS *const m = (mDNS *const)refcon;
1342 (void)service; // Parameter not used
1343 switch(messageType)
1344 {
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;
1353 }
1354 IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
1355 }
1356
1357 mDNSlocal mStatus WatchForPowerChanges(mDNS *const m)
1358 {
1359 IONotificationPortRef thePortRef;
1360 m->p->PowerConnection = IORegisterForSystemPower(m, &thePortRef, PowerChanged, &m->p->PowerNotifier);
1361 if (m->p->PowerConnection)
1362 {
1363 m->p->PowerRLS = IONotificationPortGetRunLoopSource(thePortRef);
1364 CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->PowerRLS, kCFRunLoopDefaultMode);
1365 return(mStatus_NoError);
1366 }
1367 return(-1);
1368 }
1369
1370 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
1371 CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
1372 CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
1373 CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
1374
1375 mDNSexport mDNSBool mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
1376 {
1377 int major = 0, minor = 0;
1378 char letter = 0, prodname[256]="Mac OS X", prodvers[256]="", buildver[256]="?";
1379 CFDictionaryRef vers = _CFCopySystemVersionDictionary();
1380 if (vers)
1381 {
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);
1389 CFRelease(vers);
1390 }
1391 if (HINFO_SWstring) mDNS_snprintf(HINFO_SWstring, 256, "%s %s (%s), %s", prodname, prodvers, buildver, mDNSResponderVersionString);
1392 return(major);
1393 }
1394
1395 mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
1396 {
1397 mStatus err;
1398
1399 m->hostlabel.c[0] = 0;
1400
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;
1407
1408 char HINFO_SWstring[256] = "";
1409 if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring) < 7) m->KnownBugs = mDNS_KnownBug_PhantomInterfaces;
1410
1411 mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
1412 mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
1413 if (hlen + slen < 254)
1414 {
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);
1419 }
1420
1421 m->p->InterfaceList = mDNSNULL;
1422 m->p->userhostlabel.c[0] = 0;
1423 UpdateInterfaceList(m);
1424 SetupActiveInterfaces(m);
1425
1426 err = WatchForNetworkChanges(m);
1427 if (err) return(err);
1428
1429 err = WatchForPowerChanges(m);
1430 return(err);
1431 }
1432
1433 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
1434 {
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);
1439 return(result);
1440 }
1441
1442 mDNSexport void mDNSPlatformClose(mDNS *const m)
1443 {
1444 if (m->p->PowerConnection)
1445 {
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;
1453 }
1454
1455 if (m->p->Store)
1456 {
1457 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
1458 CFRunLoopSourceInvalidate(m->p->StoreRLS);
1459 CFRelease(m->p->StoreRLS);
1460 CFRelease(m->p->Store);
1461 m->p->Store = NULL;
1462 m->p->StoreRLS = NULL;
1463 }
1464
1465 MarkAllInterfacesInactive(m);
1466 ClearInactiveInterfaces(m);
1467 }
1468
1469 mDNSexport mDNSs32 mDNSPlatformOneSecond = 1000;
1470
1471 mDNSexport mStatus mDNSPlatformTimeInit(mDNSs32 *timenow)
1472 {
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
1481 //
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);
1497 }
1498
1499 mDNSexport mDNSs32 mDNSPlatformTimeNow(void)
1500 {
1501 if (clockdivisor == 0) { LogMsg("mDNSPlatformTimeNow called before mDNSPlatformTimeInit"); return(0); }
1502 return((mDNSs32)(mach_absolute_time() / clockdivisor));
1503 }
1504
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); }