]> git.saurik.com Git - apple/mdnsresponder.git/blame - mDNSMacOSX/CFSocket.c
mDNSResponder-58.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / CFSocket.c
CommitLineData
c9b9ae52
A
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 $
26Revision 1.115 2003/09/10 00:45:55 cheshire
27<rdar://problem/3412328> Don't log "sendto failed" errors during the first two minutes of startup
28
29Revision 1.114 2003/08/27 02:55:13 cheshire
30<rdar://problem/3387910>: Bug: Don't report mDNSPlatformSendUDP sendto errno 64 (Host is down)
31
32Revision 1.113 2003/08/19 22:20:00 cheshire
33<rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
34More minor refinements
35
36Revision 1.112 2003/08/19 03:04:43 cheshire
37<rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
38
39Revision 1.111 2003/08/18 22:53:37 cheshire
40<rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformTimeNow()
41
42Revision 1.110 2003/08/16 03:39:00 cheshire
43<rdar://problem/3338440> InterfaceID -1 indicates "local only"
44
45Revision 1.109 2003/08/15 02:19:49 cheshire
46<rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
47Also limit number of messages to at most 100
48
49Revision 1.108 2003/08/12 22:24:52 cheshire
50<rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
51This message indicates a kernel bug, but still we don't want to flood syslog.
52Do a sleep(1) after writing this log message, to limit the rate.
53
54Revision 1.107 2003/08/12 19:56:25 cheshire
55Update to APSL 2.0
56
57Revision 1.106 2003/08/12 13:48:32 cheshire
58Add comment explaining clockdivisor calculation
59
60Revision 1.105 2003/08/12 13:44:14 cheshire
61<rdar://problem/3370229> mDNSResponder *VERY* unhappy if time goes backwards
62Use mach_absolute_time() (which is guaranteed to always go forwards, resetting only on reboot)
63instead of gettimeofday() (which can jump back if the user manually changes their time/date)
64
65Revision 1.104 2003/08/12 13:12:07 cheshire
66Textual search/replace: Indicate local functions using "mDNSlocal" instead of "static"
67
68Revision 1.103 2003/08/08 18:36:04 cheshire
69<rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
70
71Revision 1.102 2003/08/06 00:14:52 cheshire
72<rdar://problem/3330324> Need to check IP TTL on responses
73Also add corresponding checks in the IPv6 code path
74
75Revision 1.101 2003/08/05 22:20:16 cheshire
76<rdar://problem/3330324> Need to check IP TTL on responses
77
78Revision 1.100 2003/08/05 21:18:50 cheshire
79<rdar://problem/3363185> mDNSResponder should ignore 6to4
80Only use interfaces that are marked as multicast-capable (IFF_MULTICAST)
81
82Revision 1.99 2003/08/05 20:13:52 cheshire
83<rdar://problem/3294080> mDNSResponder using IPv6 interfaces before they are ready
84Ignore interfaces with the IN6_IFF_NOTREADY flag set
85
86Revision 1.98 2003/07/20 03:38:51 ksekar
87Bug #: 3320722
88Completed support for Unix-domain socket based API.
89
90Revision 1.97 2003/07/19 03:15:16 cheshire
91Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
92and add the obvious trivial implementations to each platform support layer
93
94Revision 1.96 2003/07/18 00:30:00 cheshire
95<rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
96
97Revision 1.95 2003/07/12 03:15:20 cheshire
98<rdar://problem/3324848> After SCDynamicStore notification, mDNSResponder updates
99m->hostlabel even if user hasn't actually actually changed their dot-local hostname
100
101Revision 1.94 2003/07/03 00:51:54 cheshire
102<rdar://problem/3287213> When select() and recvmgs() disagree, get more info from kernel about the socket state
103
104Revision 1.93 2003/07/03 00:09:14 cheshire
105<rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
106Additional refinement suggested by Josh: Use info->scope_id instead of if_nametoindex(info->ifa_name);
107
108Revision 1.92 2003/07/02 21:19:51 cheshire
109<rdar://problem/3313413> Update copyright notices, etc., in source code comments
110
111Revision 1.91 2003/06/24 01:53:51 cheshire
112Minor update to comments
113
114Revision 1.90 2003/06/24 01:51:47 cheshire
115<rdar://problem/3303118> Oops: Double-dispose of sockets
116Don't need to close sockets: CFSocketInvalidate() does that for us
117
118Revision 1.89 2003/06/21 18:12:47 cheshire
119<rdar://problem/3296061> Rendezvous cannot handle interfaces whose total name is >3 chars
120One-line change: should say "IF_NAMESIZE", not sizeof(ifname)
121
122Revision 1.88 2003/06/12 23:38:37 cheshire
123<rdar://problem/3291162> mDNSResponder doesn't detect some configuration changes
124Also check that scope_id matches before concluding that two interfaces are the same
125
126Revision 1.87 2003/06/10 01:14:11 cheshire
127<rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
128
129Revision 1.86 2003/05/28 02:41:52 cheshire
130<rdar://problem/3034346> Time to remove Mac OS 9 UDP Port 53 legacy support
131
132Revision 1.85 2003/05/28 02:39:47 cheshire
133Minor change to debugging messages
134
135Revision 1.84 2003/05/27 22:29:40 cheshire
136Remove out-dated comment
137
138Revision 1.83 2003/05/26 03:21:29 cheshire
139Tidy up address structure naming:
140mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
141mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
142mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
143
144Revision 1.82 2003/05/26 03:01:27 cheshire
145<rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
146
147Revision 1.81 2003/05/24 02:06:42 cheshire
148<rdar://problem/3268480> IPv6 Multicast Loopback doesn't work
149Tried setting IPV6_MULTICAST_LOOP; it doesn't help.
150However, it is probably wise to have the code explicitly set this socket
151option anyway, in case the default changes in later versions of Unix.
152
153Revision 1.80 2003/05/24 02:02:24 cheshire
154<rdar://problem/3221880> if_indextoname consumes a lot of CPU
155Fix error in myIfIndexToName; was returning prematurely
156
157Revision 1.79 2003/05/23 23:07:44 cheshire
158<rdar://problem/3268199> Must not write to stderr when running as daemon
159
160Revision 1.78 2003/05/23 01:19:04 cheshire
161<rdar://problem/3267085> mDNSResponder needs to signal type of service to AirPort
162Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
163
164Revision 1.77 2003/05/23 01:12:05 cheshire
165Minor code tidying
166
167Revision 1.76 2003/05/22 01:26:01 cheshire
168Tidy up log messages
169
170Revision 1.75 2003/05/22 00:07:09 cheshire
171<rdar://problem/3264366> myCFSocketCallBack recvfrom(5) error 1, errno 35
172Extra logging to determine whether there is a bug in CFSocket
173
174Revision 1.74 2003/05/21 20:20:12 cheshire
175Fix warnings (mainly printf format string warnings, like using "%d" where
176it should say "%lu", etc.) and improve error logging (use strerror()
177to include textual error message as well as numeric error in log messages).
178
179Revision 1.73 2003/05/21 17:56:29 ksekar
180Bug #: <rdar://problem/3191277>: mDNSResponder doesn't watch for IPv6 address changes
181
182Revision 1.72 2003/05/14 18:48:41 cheshire
183<rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
184More minor refinements:
185CFSocket.c needs to do *all* its mDNS_DeregisterInterface calls before freeing memory
186mDNS_DeregisterInterface revalidates cache record when *any* representative of an interface goes away
187
188Revision 1.71 2003/05/14 07:08:37 cheshire
189<rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
190Previously, when there was any network configuration change, mDNSResponder
191would tear down the entire list of active interfaces and start again.
192That was very disruptive, and caused the entire cache to be flushed,
193and caused lots of extra network traffic. Now it only removes interfaces
194that have really gone, and only adds new ones that weren't there before.
195
196Revision 1.70 2003/05/07 18:30:24 cheshire
197Fix signed/unsigned comparison warning
198
199Revision 1.69 2003/05/06 20:14:44 cheshire
200Change "tp" to "tv"
201
202Revision 1.68 2003/05/06 00:00:49 cheshire
203<rdar://problem/3248914> Rationalize naming of domainname manipulation functions
204
205Revision 1.67 2003/04/29 00:43:44 cheshire
206Fix compiler warnings
207
208Revision 1.66 2003/04/26 02:41:58 cheshire
209<rdar://problem/3241281> Change timenow from a local variable to a structure member
210
211Revision 1.65 2003/04/26 02:34:01 cheshire
212Add missing mDNSexport
213
214Revision 1.64 2003/04/15 16:48:06 jgraessl
215Bug #: 3228833
216Modified code in CFSocket notifier function to read all packets on the socket
217instead of reading only one packet every time the notifier was called.
218
219Revision 1.63 2003/04/15 16:33:50 jgraessl
220Bug #: 3221880
221Switched to our own copy of if_indextoname to improve performance.
222
223Revision 1.62 2003/03/28 01:55:44 cheshire
224Minor improvements to debugging messages
225
226Revision 1.61 2003/03/27 03:30:56 cheshire
227<rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
228Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
229Fixes:
2301. Make mDNS_DeregisterInterface() safe to call from a callback
2312. Make HostNameCallback() use mDNS_DeadvertiseInterface() instead
232 (it never really needed to deregister the interface at all)
233
234Revision 1.60 2003/03/15 04:40:38 cheshire
235Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
236
237Revision 1.59 2003/03/11 01:23:26 cheshire
238Bug #: 3194246 mDNSResponder socket problems
239
240Revision 1.58 2003/03/06 01:43:04 cheshire
241Bug #: 3189097 Additional debugging code in mDNSResponder
242Improve "LIST_ALL_INTERFACES" output
243
244Revision 1.57 2003/03/05 22:36:27 cheshire
245Bug #: 3186338 Loopback doesn't work with mDNSResponder-27
246Temporary workaround: Skip loopback interface *only* if we found at least one v4 interface to use
247
248Revision 1.56 2003/03/05 01:50:38 cheshire
249Bug #: 3189097 Additional debugging code in mDNSResponder
250
251Revision 1.55 2003/02/21 01:54:09 cheshire
252Bug #: 3099194 mDNSResponder needs performance improvements
253Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
254
255Revision 1.54 2003/02/20 06:48:35 cheshire
256Bug #: 3169535 Xserve RAID needs to do interface-specific registrations
257Reviewed by: Josh Graessley, Bob Bradley
258
259Revision 1.53 2003/01/29 02:21:23 cheshire
260Return mStatus_Invalid if can't send packet because socket not available
261
262Revision 1.52 2003/01/28 19:39:43 jgraessl
263Enabling AAAA over IPv4 support.
264
265Revision 1.51 2003/01/28 05:11:23 cheshire
266Fixed backwards comparison in SearchForInterfaceByName
267
268Revision 1.50 2003/01/13 23:49:44 jgraessl
269Merged changes for the following fixes in to top of tree:
2703086540 computer name changes not handled properly
2713124348 service name changes are not properly handled
2723124352 announcements sent in pairs, failing chattiness test
273
274Revision 1.49 2002/12/23 22:13:30 jgraessl
275Reviewed by: Stuart Cheshire
276Initial IPv6 support for mDNSResponder.
277
278Revision 1.48 2002/11/22 01:37:52 cheshire
279Bug #: 3108426 mDNSResponder is monitoring ServiceEntities instead of InterfaceEntities
280
281Revision 1.47 2002/09/21 20:44:51 zarzycki
282Added APSL info
283
284Revision 1.46 2002/09/19 21:25:35 cheshire
285mDNS_snprintf() doesn't need to be in a separate file
286
287Revision 1.45 2002/09/17 01:45:13 cheshire
288Add LIST_ALL_INTERFACES symbol for debugging
289
290Revision 1.44 2002/09/17 01:36:23 cheshire
291Move Puma support to CFSocketPuma.c
292
293Revision 1.43 2002/09/17 01:05:28 cheshire
294Change mDNS_AdvertiseLocalAddresses to be an Init parameter instead of a global
295
296Revision 1.42 2002/09/16 23:13:50 cheshire
297Minor code tidying
298
299 */
300
301// ***************************************************************************
302// mDNS-CFSocket.c:
303// Supporting routines to run mDNS on a CFRunLoop platform
304// ***************************************************************************
305
306// Open Transport 2.7.x on Mac OS 9 used to send Multicast DNS queries to UDP port 53,
307// before the Multicast DNS port was changed to 5353. For this reason, the mDNSResponder
308// in earlier versions of Mac OS X 10.2 Jaguar used to set mDNS_AllowPort53 to 1 to allow
309// it to also listen and answer queries on UDP port 53. Now that Transport 2.8 (included in
310// the Classic subsystem of Mac OS X 10.2 Jaguar) has been corrected to issue Multicast DNS
311// queries on UDP port 5353, this backwards-compatibility legacy support is no longer needed.
312#define mDNS_AllowPort53 0
313
314// For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
315// including ones that mDNSResponder chooses not to use.
316#define LIST_ALL_INTERFACES 0
317
318// For enabling AAAA records over IPv4. Setting this to 0 sends only
319// A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both
320// AAAA and A records over both IPv4 and IPv6.
321#define AAAA_OVER_V4 1
322
323#include "mDNSClientAPI.h" // Defines the interface provided to the client layer above
324#include "mDNSPlatformFunctions.h" // Defines the interface to the supporting layer below
325#include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
326
327#include <stdio.h>
328#include <unistd.h> // For select() and close()
329#include <stdarg.h> // For va_list support
330#include <net/if.h>
331#include <net/if_dl.h>
332#include <sys/uio.h>
333#include <sys/param.h>
334#include <sys/socket.h>
335#include <sys/sysctl.h>
336#include <fcntl.h>
337#include <sys/ioctl.h>
338
339#include <netinet/in.h> // For IP_RECVTTL
340#ifndef IP_RECVTTL
341#define IP_RECVTTL 24 /* bool; receive reception TTL w/dgram */
342#endif
343
344#include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
345#include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
346#include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
347
348// Code contributed by Dave Heller:
349// Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
350// work on Mac OS X 10.1, which does not have the getifaddrs call.
351#define RUN_ON_PUMA_WITHOUT_IFADDRS 0
352#if RUN_ON_PUMA_WITHOUT_IFADDRS
353#include "CFSocketPuma.c"
354#else
355#include <ifaddrs.h>
356#endif
357
358#include <IOKit/IOKitLib.h>
359#include <IOKit/IOMessage.h>
360#include <mach/mach_time.h>
361
362// ***************************************************************************
363// Globals
364
365static mDNSu32 clockdivisor = 0;
366
367// ***************************************************************************
368// Macros
369
370#define mDNSSameIPv4Address(A,B) ((A).NotAnInteger == (B).NotAnInteger)
371#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])
372
373#define mDNSAddressIsAllDNSLinkGroup(X) ( \
374 ((X)->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address((X)->ip.v4, AllDNSLinkGroup )) || \
375 ((X)->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address((X)->ip.v6, AllDNSLinkGroupv6)) )
376
377// ***************************************************************************
378// Functions
379
380// Note, this uses mDNS_vsnprintf instead of standard "vsnprintf", because mDNS_vsnprintf knows
381// how to print special data types like IP addresses and length-prefixed domain names
382#if MDNS_DEBUGMSGS
383mDNSexport void debugf_(const char *format, ...)
384 {
385 unsigned char buffer[512];
386 va_list ptr;
387 va_start(ptr,format);
388 buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
389 va_end(ptr);
390 fprintf(stderr,"%s\n", buffer);
391 fflush(stderr);
392 }
393#endif
394
395#if MDNS_DEBUGMSGS > 1
396mDNSexport void verbosedebugf_(const char *format, ...)
397 {
398 unsigned char buffer[512];
399 va_list ptr;
400 va_start(ptr,format);
401 buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
402 va_end(ptr);
403 fprintf(stderr,"%s\n", buffer);
404 fflush(stderr);
405 }
406#endif
407
408mDNSexport void LogMsg(const char *format, ...)
409 {
410 unsigned char buffer[512];
411 va_list ptr;
412 va_start(ptr,format);
413 buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
414 va_end(ptr);
415
416 extern int debug_mode;
417 if (debug_mode) // In debug_mode we write to stderr
418 {
419 fprintf(stderr,"%s\n", buffer);
420 fflush(stderr);
421 }
422 else // else, in production mode, we write to syslog
423 {
424 openlog("mDNSResponder", LOG_CONS | LOG_PERROR | LOG_PID, LOG_DAEMON);
425 syslog(LOG_ERR, "%s", buffer);
426 closelog();
427 }
428 }
429
430mDNSlocal struct ifaddrs* myGetIfAddrs(int refresh)
431 {
432 static struct ifaddrs *ifa = NULL;
433
434 if (refresh && ifa)
435 {
436 freeifaddrs(ifa);
437 ifa = NULL;
438 }
439
440 if (ifa == NULL) getifaddrs(&ifa);
441
442 return ifa;
443 }
444
445mDNSlocal int myIfIndexToName(u_short index, char* name)
446 {
447 struct ifaddrs *ifa;
448 for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
449 if (ifa->ifa_addr->sa_family == AF_LINK)
450 if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == index)
451 { strncpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; }
452 return -1;
453 }
454
455mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS *const m, mDNSu32 index)
456 {
457 NetworkInterfaceInfoOSX *i;
458 if (index == (uint32_t)~0) return((mDNSInterfaceID)~0);
459 if (index)
460 for (i = m->p->InterfaceList; i; i = i->next)
461 if (i->scope_id == index)
462 return(i->ifinfo.InterfaceID);
463 return(mDNSNULL);
464 }
465
466mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m, mDNSInterfaceID id)
467 {
468 NetworkInterfaceInfoOSX *i;
469 if (id == (mDNSInterfaceID)~0) return((mDNSu32)~0);
470 if (id)
471 for (i = m->p->InterfaceList; i; i = i->next)
472 if (i->ifinfo.InterfaceID == id)
473 return i->scope_id;
474 return 0;
475 }
476
477mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
478 mDNSInterfaceID InterfaceID, mDNSIPPort srcPort, const mDNSAddr *dst, mDNSIPPort dstPort)
479 {
480 #pragma unused(m)
481 NetworkInterfaceInfoOSX *info = (NetworkInterfaceInfoOSX *)InterfaceID;
482 struct sockaddr_storage to;
483 int s, err;
484
485 if (!InterfaceID) { LogMsg("mDNSPlatformSendUDP ERROR! Cannot send from zero InterfaceID"); return mStatus_BadParamErr; }
486
487 if (dst->type == mDNSAddrType_IPv4)
488 {
489 struct sockaddr_in* sin_to = (struct sockaddr_in*)&to;
490 sin_to->sin_len = sizeof(*sin_to);
491 sin_to->sin_family = AF_INET;
492 sin_to->sin_port = dstPort.NotAnInteger;
493 sin_to->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
494 }
495 else if (dst->type == mDNSAddrType_IPv6)
496 {
497 struct sockaddr_in6* sin6_to = (struct sockaddr_in6*)&to;
498 sin6_to->sin6_len = sizeof(*sin6_to);
499 sin6_to->sin6_family = AF_INET6;
500 sin6_to->sin6_port = dstPort.NotAnInteger;
501 sin6_to->sin6_flowinfo = 0;
502 sin6_to->sin6_addr = *(struct in6_addr*)&dst->ip.v6;
503 sin6_to->sin6_scope_id = info->scope_id;
504 }
505 else
506 {
507 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!\n");
508 return mStatus_BadParamErr;
509 }
510
511 if (srcPort.NotAnInteger == MulticastDNSPort.NotAnInteger)
512 {
513 if (dst->type == mDNSAddrType_IPv4) s = info->sktv4;
514 else if (dst->type == mDNSAddrType_IPv6) s = info->sktv6;
515 else s = -1;
516 }
517#if mDNS_AllowPort53
518 else if (srcPort.NotAnInteger == UnicastDNSPort.NotAnInteger && dst->type == mDNSAddrType_IPv4)
519 s = info->skt53;
520#endif
521 else { LogMsg("Source port %d not allowed", (mDNSu16)srcPort.b[0]<<8 | srcPort.b[1]); return(-1); }
522
523 if (s >= 0)
524 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %X %s/%d to %#a:%d skt %d",
525 InterfaceID, info->ifa_name, dst->type, dst, (mDNSu16)dstPort.b[0]<<8 | dstPort.b[1], s);
526 else
527 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %X %s/%d (socket of this type not available)",
528 InterfaceID, info->ifa_name, dst->type, dst, (mDNSu16)dstPort.b[0]<<8 | dstPort.b[1]);
529
530 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
531 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
532 if (s < 0) return(mStatus_Invalid);
533
534 err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len);
535 if (err < 0)
536 {
537 // Don't report EHOSTDOWN (i.e. ARP failure) to unicast destinations
538 if (errno == EHOSTDOWN && !mDNSAddressIsAllDNSLinkGroup(dst)) return(err);
539 // Don't report EHOSTUNREACH in the first two minutes after boot
540 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
541 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
542 if (errno == EHOSTUNREACH && (mDNSu32)(m->timenow) < (mDNSu32)(mDNSPlatformOneSecond * 120)) return(err);
543 LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %s/%ld to %#a:%d skt %d error %d errno %d (%s)",
544 InterfaceID, info->ifa_name, dst->type, dst, (mDNSu16)dstPort.b[0]<<8 | dstPort.b[1], s, err, errno, strerror(errno));
545 return(err);
546 }
547
548 return(mStatus_NoError);
549 }
550
551mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
552 struct sockaddr *const from, size_t *const fromlen, mDNSAddr *dstaddr, char ifname[IF_NAMESIZE], mDNSu8 *ttl)
553 {
554 static unsigned int numLogMessages = 0;
555 struct iovec databuffers = { (char *)buffer, max };
556 struct msghdr msg;
557 ssize_t n;
558 struct cmsghdr *cmPtr;
559 char ancillary[1024];
560
561 *ttl = 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
562
563 // Set up the message
564 msg.msg_name = (caddr_t)from;
565 msg.msg_namelen = *fromlen;
566 msg.msg_iov = &databuffers;
567 msg.msg_iovlen = 1;
568 msg.msg_control = (caddr_t)&ancillary;
569 msg.msg_controllen = sizeof(ancillary);
570 msg.msg_flags = 0;
571
572 // Receive the data
573 n = recvmsg(s, &msg, 0);
574 if (n<0)
575 {
576 if (errno != EWOULDBLOCK && numLogMessages++ < 100) LogMsg("CFSocket.c: recvmsg(%d) returned error %d errno %d", s, n, errno);
577 return(-1);
578 }
579 if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
580 {
581 if (numLogMessages++ < 100) LogMsg("CFSocket.c: recvmsg(%d) msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
582 s, msg.msg_controllen, sizeof(struct cmsghdr));
583 return(-1);
584 }
585 if (msg.msg_flags & MSG_CTRUNC)
586 {
587 if (numLogMessages++ < 100) LogMsg("CFSocket.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
588 return(-1);
589 }
590
591 *fromlen = msg.msg_namelen;
592
593 // Parse each option out of the ancillary data.
594 for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
595 {
596 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
597 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVDSTADDR)
598 {
599 dstaddr->type = mDNSAddrType_IPv4;
600 dstaddr->ip.v4.NotAnInteger = *(u_int32_t*)CMSG_DATA(cmPtr);
601 }
602 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF)
603 {
604 struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr);
605 if (sdl->sdl_nlen < IF_NAMESIZE)
606 {
607 mDNSPlatformMemCopy(sdl->sdl_data, ifname, sdl->sdl_nlen);
608 ifname[sdl->sdl_nlen] = 0;
609 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
610 }
611 }
612 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVTTL)
613 {
614 *ttl = *(u_char*)CMSG_DATA(cmPtr);
615 }
616 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_PKTINFO)
617 {
618 struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmPtr);
619 dstaddr->type = mDNSAddrType_IPv6;
620 dstaddr->ip.v6 = *(mDNSv6Addr*)&ip6_info->ipi6_addr;
621 myIfIndexToName(ip6_info->ipi6_ifindex, ifname);
622 }
623 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT)
624 {
625 *ttl = *(int*)CMSG_DATA(cmPtr);
626 }
627 }
628
629 return(n);
630 }
631
632mDNSlocal void myCFSocketCallBack(CFSocketRef cfs, CFSocketCallBackType CallBackType, CFDataRef address, const void *data, void *context)
633 {
634 mDNSAddr senderAddr, destAddr;
635 mDNSIPPort senderPort, destPort = MulticastDNSPort;
636 NetworkInterfaceInfoOSX *info = (NetworkInterfaceInfoOSX *)context;
637 mDNS *const m = info->m;
638 DNSMessage packet;
639 struct sockaddr_storage from;
640 size_t fromlen = sizeof(from);
641 char packetifname[IF_NAMESIZE] = "";
642 int err, s1 = -1, skt = CFSocketGetNative(cfs);
643 int count = 0;
644
645 (void)address; // Parameter not used
646 (void)data; // Parameter not used
647
648 if (CallBackType != kCFSocketReadCallBack) LogMsg("myCFSocketCallBack: Why is CallBackType %d not kCFSocketReadCallBack?", CallBackType);
649
650#if mDNS_AllowPort53
651 if (cfs == info->cfs53) { s1 = info->skt53; destPort = UnicastDNSPort; }
652 else
653#endif
654 if (cfs == info->cfsv4) s1 = info->sktv4;
655 else if (cfs == info->cfsv6) s1 = info->sktv6;
656
657 if (s1 < 0 || s1 != skt)
658 {
659 LogMsg("myCFSocketCallBack: s1 %d native socket %d, cfs %p", s1, skt, cfs);
660#if mDNS_AllowPort53
661 LogMsg("myCFSocketCallBack: cfs53 %p, skt53 %d", info->cfs53, info->skt53);
662#endif
663 LogMsg("myCFSocketCallBack: cfsv4 %p, sktv4 %d", info->cfsv4, info->sktv4);
664 LogMsg("myCFSocketCallBack: cfsv6 %p, sktv6 %d", info->cfsv6, info->sktv6);
665 }
666
667 mDNSu8 ttl;
668 while ((err = myrecvfrom(s1, &packet, sizeof(packet), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl)) >= 0)
669 {
670 count++;
671 if (from.ss_family == AF_INET)
672 {
673 struct sockaddr_in *sin = (struct sockaddr_in*)&from;
674 senderAddr.type = mDNSAddrType_IPv4;
675 senderAddr.ip.v4.NotAnInteger = sin->sin_addr.s_addr;
676 senderPort.NotAnInteger = sin->sin_port;
677 }
678 else if (from.ss_family == AF_INET6)
679 {
680 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&from;
681 senderAddr.type = mDNSAddrType_IPv6;
682 senderAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
683 senderPort.NotAnInteger = sin6->sin6_port;
684 }
685 else
686 {
687 LogMsg("myCFSocketCallBack from is unknown address family %d", from.ss_family);
688 return;
689 }
690
691 // Even though we indicated a specific interface in the IP_ADD_MEMBERSHIP call, a weirdness of the
692 // sockets API means that even though this socket has only officially joined the multicast group
693 // on one specific interface, the kernel will still deliver multicast packets to it no matter which
694 // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
695 // To work around this weirdness, we use the IP_RECVIF option to find the name of the interface
696 // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
697 if (strcmp(info->ifa_name, packetifname))
698 {
699 verbosedebugf("myCFSocketCallBack got a packet from %#a to %#a on interface %#a/%s (Ignored -- really arrived on interface %s)",
700 &senderAddr, &destAddr, &info->ifinfo.ip, info->ifa_name, packetifname);
701 return;
702 }
703 else
704 verbosedebugf("myCFSocketCallBack got a packet from %#a to %#a on interface %#a/%s",
705 &senderAddr, &destAddr, &info->ifinfo.ip, info->ifa_name);
706
707 if (err < (int)sizeof(DNSMessageHeader)) { debugf("myCFSocketCallBack packet length (%d) too short", err); return; }
708
709 mDNSCoreReceive(m, &packet, (unsigned char*)&packet + err, &senderAddr, senderPort, &destAddr, destPort, info->ifinfo.InterfaceID, ttl);
710 }
711
712 if (err < 0 && (errno != EWOULDBLOCK || count == 0))
713 {
714 // Something is busted here.
715 // CFSocket says there is a packet, but myrecvfrom says there is not.
716 // Try calling select() to get another opinion.
717 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
718 // All of this is racy, as data may have arrived after the call to select()
719 int save_errno = errno;
720 int so_error = -1;
721 int so_nread = -1;
722 int fionread = -1;
723 int solen = sizeof(int);
724 fd_set readfds;
725 FD_ZERO(&readfds);
726 FD_SET(s1, &readfds);
727 struct timeval timeout;
728 timeout.tv_sec = 0;
729 timeout.tv_usec = 0;
730 int selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
731 if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1)
732 LogMsg("myCFSocketCallBack getsockopt(SO_ERROR) error %d", errno);
733 if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1)
734 LogMsg("myCFSocketCallBack getsockopt(SO_NREAD) error %d", errno);
735 if (ioctl(s1, FIONREAD, &fionread) == -1)
736 LogMsg("myCFSocketCallBack ioctl(FIONREAD) error %d", errno);
737 static unsigned int numLogMessages = 0;
738 if (numLogMessages++ < 100)
739 LogMsg("myCFSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
740 s1, err, save_errno, strerror(save_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
741 sleep(1); // After logging this error, rate limit so we don't flood syslog
742 }
743 }
744
745// This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
746mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
747 {
748 CFStringEncoding encoding = kCFStringEncodingUTF8;
749 CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
750 if (cfs)
751 {
752 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
753 CFRelease(cfs);
754 }
755 }
756
757// This gets the text of the field currently labelled "Rendezvous Name" in the Sharing Prefs Control Panel
758mDNSlocal void GetUserSpecifiedRFC1034ComputerName(domainlabel *const namelabel)
759 {
760 CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
761 if (cfs)
762 {
763 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
764 CFRelease(cfs);
765 }
766 }
767
768mDNSlocal mStatus SetupSocket(NetworkInterfaceInfoOSX *i, mDNSIPPort port, int *s, CFSocketRef *c)
769 {
770 const int on = 1;
771 const int twofivefive = 255;
772
773 if (*s >= 0) { LogMsg("SetupSocket ERROR: socket %d is already set", *s); return(-1); }
774 if (*c) { LogMsg("SetupSocket ERROR: CFSocketRef %p is already set", *c); return(-1); }
775
776 // Open the socket...
777 int skt = socket(i->sa_family, SOCK_DGRAM, IPPROTO_UDP);
778 if (skt < 0) { LogMsg("socket error %d errno %d (%s)", skt, errno, strerror(errno)); return(skt); }
779
780 // ... with a shared UDP port
781 mStatus err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
782 if (err < 0) { LogMsg("setsockopt - SO_REUSEPORT error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
783
784 if (i->sa_family == AF_INET)
785 {
786 // We want to receive destination addresses
787 err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
788 if (err < 0) { LogMsg("setsockopt - IP_RECVDSTADDR error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
789
790 // We want to receive interface identifiers
791 err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
792 if (err < 0) { LogMsg("setsockopt - IP_RECVIF error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
793
794 // We want to receive packet TTL value so we can check it
795 err = setsockopt(skt, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on));
796 // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
797
798 // Add multicast group membership on this interface
799 struct in_addr addr = { i->ifinfo.ip.ip.v4.NotAnInteger };
800 struct ip_mreq imr;
801 imr.imr_multiaddr.s_addr = AllDNSLinkGroup.NotAnInteger;
802 imr.imr_interface = addr;
803 err = setsockopt(skt, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
804 if (err < 0) { LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
805
806 // Specify outgoing interface too
807 err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_IF, &addr, sizeof(addr));
808 if (err < 0) { LogMsg("setsockopt - IP_MULTICAST_IF error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
809
810 // Send unicast packets with TTL 255
811 err = setsockopt(skt, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive));
812 if (err < 0) { LogMsg("setsockopt - IP_TTL error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
813
814 // And multicast packets with TTL 255 too
815 err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive));
816 if (err < 0) { LogMsg("setsockopt - IP_MULTICAST_TTL error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
817
818 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
819 const int ip_tosbits = IPTOS_LOWDELAY | IPTOS_THROUGHPUT;
820 err = setsockopt(skt, IPPROTO_IP, IP_TOS, &ip_tosbits, sizeof(ip_tosbits));
821 if (err < 0) { LogMsg("setsockopt - IP_TOS error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
822
823 // And start listening for packets
824 struct sockaddr_in listening_sockaddr;
825 listening_sockaddr.sin_family = AF_INET;
826 listening_sockaddr.sin_port = port.NotAnInteger;
827 listening_sockaddr.sin_addr.s_addr = 0; // Want to receive multicasts AND unicasts on this socket
828 err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr));
829 if (err)
830 {
831 // If we fail to bind to port 53 (because we're not root), that's okay, just tidy up and silently continue
832 if (port.NotAnInteger == UnicastDNSPort.NotAnInteger) { close(skt); err = 0; }
833 else LogMsg("bind error %ld errno %d (%s)", err, errno, strerror(errno));
834 return(err);
835 }
836 }
837 else if (i->sa_family == AF_INET6)
838 {
839 // We want to receive destination addresses and receive interface identifiers
840 err = setsockopt(skt, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on));
841 if (err < 0) { LogMsg("setsockopt - IPV6_PKTINFO error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
842
843 // We want to receive packet hop count value so we can check it
844 err = setsockopt(skt, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof(on));
845 if (err < 0) { LogMsg("setsockopt - IPV6_HOPLIMIT error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
846
847 // We want to receive only IPv6 packets, without this option, we may
848 // get IPv4 addresses as mapped addresses.
849 err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
850 if (err < 0) { LogMsg("setsockopt - IPV6_V6ONLY error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
851
852 // Add multicast group membership on this interface
853 int interface_id = if_nametoindex(i->ifa_name);
854 struct ipv6_mreq i6mr;
855 i6mr.ipv6mr_interface = interface_id;
856 i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroupv6;
857 err = setsockopt(skt, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
858 if (err < 0) { LogMsg("setsockopt - IPV6_JOIN_GROUP error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
859
860 // Specify outgoing interface too
861 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_IF, &interface_id, sizeof(interface_id));
862 if (err < 0) { LogMsg("setsockopt - IPV6_MULTICAST_IF error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
863
864 // Send unicast packets with TTL 255
865 err = setsockopt(skt, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &twofivefive, sizeof(twofivefive));
866 if (err < 0) { LogMsg("setsockopt - IPV6_UNICAST_HOPS error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
867
868 // And multicast packets with TTL 255 too
869 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive));
870 if (err < 0) { LogMsg("setsockopt - IPV6_MULTICAST_HOPS error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
871
872 // Note: IPV6_TCLASS appears not to be implemented on OS X right now (or indeed on ANY version of Unix?)
873 #ifdef IPV6_TCLASS
874 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
875 int tclass = IPTOS_LOWDELAY | IPTOS_THROUGHPUT; // This may not be right (since tclass is not implemented on OS X, I can't test it)
876 err = setsockopt(skt, IPPROTO_IPV6, IPV6_TCLASS, &tclass, sizeof(tclass));
877 if (err < 0) { LogMsg("setsockopt - IPV6_TCLASS error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
878 #endif
879
880 // Want to receive our own packets
881 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on));
882 if (err < 0) { LogMsg("setsockopt - IPV6_MULTICAST_LOOP error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
883
884 // And start listening for packets
885 struct sockaddr_in6 listening_sockaddr6;
886 bzero(&listening_sockaddr6, sizeof(listening_sockaddr6));
887 listening_sockaddr6.sin6_len = sizeof(listening_sockaddr6);
888 listening_sockaddr6.sin6_family = AF_INET6;
889 listening_sockaddr6.sin6_port = port.NotAnInteger;
890 listening_sockaddr6.sin6_flowinfo = 0;
891// listening_sockaddr6.sin6_addr = IN6ADDR_ANY_INIT; // Want to receive multicasts AND unicasts on this socket
892 listening_sockaddr6.sin6_scope_id = 0;
893 err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6));
894 if (err) { LogMsg("bind error %ld errno %d (%s)", err, errno, strerror(errno)); return(err); }
895 }
896
897 fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
898 *s = skt;
899 CFSocketContext myCFSocketContext = { 0, i->ifinfo.InterfaceID, NULL, NULL, NULL };
900 *c = CFSocketCreateWithNative(kCFAllocatorDefault, *s, kCFSocketReadCallBack, myCFSocketCallBack, &myCFSocketContext);
901 CFRunLoopSourceRef rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, *c, 0);
902 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
903 CFRelease(rls);
904
905 return(err);
906 }
907
908mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
909 {
910 if (sa->sa_family == AF_INET)
911 {
912 struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
913 ip->type = mDNSAddrType_IPv4;
914 ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
915 return(0);
916 }
917 else if (sa->sa_family == AF_INET6)
918 {
919 struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
920 ip->type = mDNSAddrType_IPv6;
921 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
922 ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
923 return(0);
924 }
925 else
926 {
927 LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
928 return(-1);
929 }
930 }
931
932mDNSlocal mStatus AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa)
933 {
934 mDNSu32 scope_id = if_nametoindex(ifa->ifa_name);
935 mDNSAddr ip;
936 SetupAddr(&ip, ifa->ifa_addr);
937 NetworkInterfaceInfoOSX **p;
938 for (p = &m->p->InterfaceList; *p; p = &(*p)->next)
939 if (scope_id == (*p)->scope_id && mDNSSameAddress(&ip, &(*p)->ifinfo.ip))
940 {
941 debugf("AddInterfaceToList: Found existing interface %u with address %#a", scope_id, &ip);
942 (*p)->CurrentlyActive = mDNStrue;
943 return(0);
944 }
945
946 debugf("AddInterfaceToList: Making new interface %u with address %#a", scope_id, &ip);
947 NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
948 if (!i) return(-1);
949 i->ifa_name = (char *)mallocL("NetworkInterfaceInfoOSX name", strlen(ifa->ifa_name) + 1);
950 if (!i->ifa_name) { freeL("NetworkInterfaceInfoOSX", i); return(-1); }
951 strcpy(i->ifa_name, ifa->ifa_name);
952
953 i->ifinfo.InterfaceID = mDNSNULL;
954 i->ifinfo.ip = ip;
955 i->ifinfo.Advertise = m->AdvertiseLocalAddresses;
956 i->ifinfo.TxAndRx = mDNSfalse; // For now; will be set up later at the end of UpdateInterfaceList
957
958 i->next = mDNSNULL;
959 i->m = m;
960 i->scope_id = scope_id;
961 i->CurrentlyActive = mDNStrue;
962 i->sa_family = ifa->ifa_addr->sa_family;
963 #if mDNS_AllowPort53
964 i->skt53 = -1;
965 i->cfs53 = NULL;
966 #endif
967 i->sktv4 = -1;
968 i->cfsv4 = NULL;
969 i->sktv6 = -1;
970 i->cfsv6 = NULL;
971
972 if (!i->ifa_name) return(-1);
973 *p = i;
974 return(0);
975 }
976
977mDNSlocal NetworkInterfaceInfoOSX *FindRoutableIPv4(mDNS *const m, mDNSu32 scope_id)
978 {
979 NetworkInterfaceInfoOSX *i;
980 for (i = m->p->InterfaceList; i; i = i->next)
981 if (i->CurrentlyActive && i->scope_id == scope_id && i->ifinfo.ip.type == mDNSAddrType_IPv4)
982 if (!(i->ifinfo.ip.ip.v4.b[0] == 169 && i->ifinfo.ip.ip.v4.b[1] == 254))
983 return(i);
984 return(mDNSNULL);
985 }
986
987mDNSlocal mStatus UpdateInterfaceList(mDNS *const m)
988 {
989 mDNSBool foundav4 = mDNSfalse;
990 struct ifaddrs *ifa = myGetIfAddrs(1);
991 struct ifaddrs *theLoopback = NULL;
992 int err = (ifa != NULL) ? 0 : (errno != 0 ? errno : -1);
993 int InfoSocket = err ? -1 : socket(AF_INET6, SOCK_DGRAM, 0);
994 if (err) return(err);
995
996 // Set up the nice label
997 m->nicelabel.c[0] = 0;
998 GetUserSpecifiedFriendlyComputerName(&m->nicelabel);
999 if (m->nicelabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->nicelabel, "Macintosh");
1000
1001 // Set up the RFC 1034-compliant label
1002 domainlabel hostlabel;
1003 hostlabel.c[0] = 0;
1004 GetUserSpecifiedRFC1034ComputerName(&hostlabel);
1005 if (hostlabel.c[0] == 0) MakeDomainLabelFromLiteralString(&hostlabel, "Macintosh");
1006 // If the user has changed their dot-local host name since the last time we checked, then update our local copy.
1007 // If the user has not changed their dot-local host name, then leave ours alone (m->hostlabel may have gone through
1008 // repeated conflict resolution to get to its current value, and if we reset it, we'll have to go through all that again.)
1009 if (SameDomainLabel(m->p->userhostlabel.c, hostlabel.c))
1010 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m->p->userhostlabel.c, m->hostlabel.c);
1011 else
1012 {
1013 debugf("Updating m->hostlabel to %#s", hostlabel.c);
1014 m->p->userhostlabel = m->hostlabel = hostlabel;
1015 mDNS_GenerateFQDN(m);
1016 }
1017
1018 while (ifa)
1019 {
1020#if LIST_ALL_INTERFACES
1021 if (ifa->ifa_addr->sa_family == AF_APPLETALK)
1022 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d is AF_APPLETALK",
1023 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
1024 else if (ifa->ifa_addr->sa_family == AF_LINK)
1025 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d is AF_LINK",
1026 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
1027 else if (ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6)
1028 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
1029 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
1030 if (!(ifa->ifa_flags & IFF_UP))
1031 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d Interface not IFF_UP",
1032 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
1033 if (ifa->ifa_flags & IFF_POINTOPOINT)
1034 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
1035 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
1036 if (ifa->ifa_flags & IFF_LOOPBACK)
1037 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
1038 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
1039#endif
1040 if ((ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6) &&
1041 (ifa->ifa_flags & IFF_MULTICAST) &&
1042 (ifa->ifa_flags & IFF_UP) && !(ifa->ifa_flags & IFF_POINTOPOINT))
1043 {
1044 int ifru_flags6 = 0;
1045 if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
1046 {
1047 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
1048 struct in6_ifreq ifr6;
1049 bzero((char *)&ifr6, sizeof(ifr6));
1050 strncpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
1051 ifr6.ifr_addr = *sin6;
1052 if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
1053 ifru_flags6 = ifr6.ifr_ifru.ifru_flags6;
1054 verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6);
1055 }
1056 if (!(ifru_flags6 & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
1057 {
1058 if (ifa->ifa_flags & IFF_LOOPBACK)
1059 theLoopback = ifa;
1060 else
1061 {
1062 AddInterfaceToList(m, ifa);
1063 if (ifa->ifa_addr->sa_family == AF_INET)
1064 foundav4 = mDNStrue;
1065 }
1066 }
1067 }
1068 ifa = ifa->ifa_next;
1069 }
1070
1071// Temporary workaround: Multicast loopback on IPv6 interfaces appears not to work.
1072// In the interim, we skip loopback interface only if we found at least one v4 interface to use
1073 if (!foundav4 && theLoopback)
1074 AddInterfaceToList(m, theLoopback);
1075
1076 // Now the list is complete, set the TxAndRx setting for each interface.
1077 // We always send and receive using IPv4.
1078 // To reduce traffic, we send and receive using IPv6 only on interfaces that have no routable IPv4 address.
1079 // Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
1080 // which means there's a good chance that most or all the other devices on that network should also have v4.
1081 // 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.
1082 // At this time, reducing the packet rate is more important than v6-only devices on a large configured network,
1083 // so we are willing to make that sacrifice.
1084 NetworkInterfaceInfoOSX *i;
1085 for (i = m->p->InterfaceList; i; i = i->next)
1086 if (i->CurrentlyActive)
1087 {
1088 mDNSBool txrx = ((i->ifinfo.ip.type == mDNSAddrType_IPv4) || !FindRoutableIPv4(m, i->scope_id));
1089 if (i->ifinfo.TxAndRx != txrx)
1090 {
1091 i->ifinfo.TxAndRx = txrx;
1092 i->CurrentlyActive = 2; // State change; need to deregister and reregister this interface
1093 }
1094 }
1095
1096 if (InfoSocket >= 0) close(InfoSocket);
1097 return(err);
1098 }
1099
1100mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, char *ifname, int type)
1101 {
1102 NetworkInterfaceInfoOSX *i;
1103 for (i = m->p->InterfaceList; i; i = i->next)
1104 if (!strcmp(i->ifa_name, ifname) &&
1105 ((AAAA_OVER_V4 ) ||
1106 (type == AF_INET && i->ifinfo.ip.type == mDNSAddrType_IPv4) ||
1107 (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6) )) return(i);
1108 return(NULL);
1109 }
1110
1111mDNSlocal void SetupActiveInterfaces(mDNS *const m)
1112 {
1113 NetworkInterfaceInfoOSX *i;
1114 for (i = m->p->InterfaceList; i; i = i->next)
1115 {
1116 mStatus err = 0;
1117 NetworkInterfaceInfo *n = &i->ifinfo;
1118 NetworkInterfaceInfoOSX *alias = SearchForInterfaceByName(m, i->ifa_name, i->sa_family);
1119 if (!alias) alias = i;
1120
1121 if (n->InterfaceID && n->InterfaceID != (mDNSInterfaceID)alias)
1122 {
1123 LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != alias %p", n->InterfaceID, alias);
1124 n->InterfaceID = mDNSNULL;
1125 }
1126
1127 if (!n->InterfaceID)
1128 {
1129 n->InterfaceID = (mDNSInterfaceID)alias;
1130 mDNS_RegisterInterface(m, n);
1131 debugf("SetupActiveInterfaces: Registered %s(%lu) InterfaceID %p %#a%s",
1132 i->ifa_name, i->scope_id, alias, &n->ip, n->InterfaceActive ? " (Primary)" : "");
1133 }
1134
1135 if (!n->TxAndRx)
1136 debugf("SetupActiveInterfaces: No TX/Rx on %s(%lu) InterfaceID %p %#a", i->ifa_name, i->scope_id, alias, &n->ip);
1137 else
1138 {
1139 if (i->sa_family == AF_INET && alias->sktv4 == -1)
1140 {
1141 #if mDNS_AllowPort53
1142 err = SetupSocket(i, UnicastDNSPort, &alias->skt53, &alias->cfs53);
1143 #endif
1144 if (!err) err = SetupSocket(i, MulticastDNSPort, &alias->sktv4, &alias->cfsv4);
1145 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);
1146 else LogMsg("SetupActiveInterfaces: v4 socket%2d %s(%lu) InterfaceID %p %#a FAILED", alias->sktv4, i->ifa_name, i->scope_id, n->InterfaceID, &n->ip);
1147 }
1148
1149 if (i->sa_family == AF_INET6 && alias->sktv6 == -1)
1150 {
1151 err = SetupSocket(i, MulticastDNSPort, &alias->sktv6, &alias->cfsv6);
1152 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);
1153 else LogMsg("SetupActiveInterfaces: v6 socket%2d %s(%lu) InterfaceID %p %#a FAILED", alias->sktv6, i->ifa_name, i->scope_id, n->InterfaceID, &n->ip);
1154 }
1155 }
1156 }
1157 }
1158
1159mDNSlocal void MarkAllInterfacesInactive(mDNS *const m)
1160 {
1161 NetworkInterfaceInfoOSX *i;
1162 for (i = m->p->InterfaceList; i; i = i->next)
1163 i->CurrentlyActive = mDNSfalse;
1164 }
1165
1166mDNSlocal void ClearInactiveInterfaces(mDNS *const m)
1167 {
1168 // First pass:
1169 // If an interface is going away, then deregister this from the mDNSCore.
1170 // We also have to deregister it if the alias interface that it's using for its InterfaceID is going away.
1171 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
1172 // it refers to has gone away we'll crash.
1173 // Don't actually close the sockets or free the memory yet: When the last representative of an interface goes away
1174 // mDNSCore may want to send goodbye packets on that interface. (Not yet implemented, but a good idea anyway.)
1175 NetworkInterfaceInfoOSX *i;
1176 for (i = m->p->InterfaceList; i; i = i->next)
1177 {
1178 // 1. If this interface is no longer active, or it's InterfaceID is changing, deregister it
1179 NetworkInterfaceInfoOSX *alias = (NetworkInterfaceInfoOSX *)(i->ifinfo.InterfaceID);
1180 if (i->ifinfo.InterfaceID && (!i->CurrentlyActive || (alias && !alias->CurrentlyActive) || i->CurrentlyActive == 2))
1181 {
1182 debugf("ClearInactiveInterfaces: Deregistering %#a", &i->ifinfo.ip);
1183 mDNS_DeregisterInterface(m, &i->ifinfo);
1184 i->ifinfo.InterfaceID = mDNSNULL;
1185 }
1186 }
1187
1188 // Second pass:
1189 // Now that everything that's going to deregister has done so, we can close sockets and free the memory
1190 NetworkInterfaceInfoOSX **p = &m->p->InterfaceList;
1191 while (*p)
1192 {
1193 i = *p;
1194 // 2. Close all our CFSockets. We'll recreate them later as necessary.
1195 // (We may have previously had both v4 and v6, and we may not need both any more.)
1196 // Note: MUST NOT close the underlying native BSD sockets.
1197 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately,
1198 // because it first has to unhook the sockets from its select() call, before it can safely close them.
1199 #if mDNS_AllowPort53
1200 if (i->cfs53) { CFSocketInvalidate(i->cfs53); CFRelease(i->cfs53); }
1201 i->skt53 = -1;
1202 i->cfs53 = NULL;
1203 #endif
1204 if (i->cfsv4) { CFSocketInvalidate(i->cfsv4); CFRelease(i->cfsv4); }
1205 if (i->cfsv6) { CFSocketInvalidate(i->cfsv6); CFRelease(i->cfsv6); }
1206 i->sktv4 = i->sktv6 = -1;
1207 i->cfsv4 = i->cfsv6 = NULL;
1208
1209 // 3. If no longer active, delete interface from list and free memory
1210 if (!i->CurrentlyActive)
1211 {
1212 debugf("ClearInactiveInterfaces: Deleting %#a", &i->ifinfo.ip);
1213 *p = i->next;
1214 if (i->ifa_name) freeL("NetworkInterfaceInfoOSX name", i->ifa_name);
1215 freeL("NetworkInterfaceInfoOSX", i);
1216 }
1217 else
1218 p = &i->next;
1219 }
1220 }
1221
1222mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
1223 {
1224 (void)store; // Parameter not used
1225 (void)changedKeys; // Parameter not used
1226 debugf("*** Network Configuration Change ***");
1227
1228 mDNS *const m = (mDNS *const)context;
1229 MarkAllInterfacesInactive(m);
1230 UpdateInterfaceList(m);
1231 ClearInactiveInterfaces(m);
1232 SetupActiveInterfaces(m);
1233
1234 if (m->MainCallback)
1235 m->MainCallback(m, mStatus_ConfigChanged);
1236 }
1237
1238mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
1239 {
1240 mStatus err = -1;
1241 SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
1242 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder"), NetworkChanged, &context);
1243 CFStringRef key1 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
1244 CFStringRef key2 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
1245 CFStringRef key3 = SCDynamicStoreKeyCreateComputerName(NULL);
1246 CFStringRef key4 = SCDynamicStoreKeyCreateHostNames(NULL);
1247 CFStringRef pattern1 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
1248 CFStringRef pattern2 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
1249
1250 CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1251 CFMutableArrayRef patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1252
1253 if (!store) { LogMsg("SCDynamicStoreCreate failed: %s\n", SCErrorString(SCError())); goto error; }
1254 if (!key1 || !key2 || !key3 || !key4 || !keys || !pattern1 || !pattern2 || !patterns) goto error;
1255
1256 CFArrayAppendValue(keys, key1);
1257 CFArrayAppendValue(keys, key2);
1258 CFArrayAppendValue(keys, key3);
1259 CFArrayAppendValue(keys, key4);
1260 CFArrayAppendValue(patterns, pattern1);
1261 CFArrayAppendValue(patterns, pattern2);
1262 if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns))
1263 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s\n", SCErrorString(SCError())); goto error; }
1264
1265 m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
1266 if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s\n", SCErrorString(SCError())); goto error; }
1267
1268 CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
1269 m->p->Store = store;
1270 err = 0;
1271 goto exit;
1272
1273error:
1274 if (store) CFRelease(store);
1275
1276exit:
1277 if (key1) CFRelease(key1);
1278 if (key2) CFRelease(key2);
1279 if (key3) CFRelease(key3);
1280 if (key4) CFRelease(key4);
1281 if (pattern1) CFRelease(pattern1);
1282 if (pattern2) CFRelease(pattern2);
1283 if (keys) CFRelease(keys);
1284 if (patterns) CFRelease(patterns);
1285
1286 return(err);
1287 }
1288
1289mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
1290 {
1291 mDNS *const m = (mDNS *const)refcon;
1292 (void)service; // Parameter not used
1293 switch(messageType)
1294 {
1295 case kIOMessageCanSystemPowerOff: debugf("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
1296 case kIOMessageSystemWillPowerOff: debugf("PowerChanged kIOMessageSystemWillPowerOff"); mDNSCoreMachineSleep(m, true); break; // E0000250
1297 case kIOMessageSystemWillNotPowerOff: debugf("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
1298 case kIOMessageCanSystemSleep: debugf("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
1299 case kIOMessageSystemWillSleep: debugf("PowerChanged kIOMessageSystemWillSleep"); mDNSCoreMachineSleep(m, true); break; // E0000280
1300 case kIOMessageSystemWillNotSleep: debugf("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
1301 case kIOMessageSystemHasPoweredOn: debugf("PowerChanged kIOMessageSystemHasPoweredOn"); mDNSCoreMachineSleep(m, false); break; // E0000300
1302 default: debugf("PowerChanged unknown message %X", messageType); break;
1303 }
1304 IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
1305 }
1306
1307mDNSlocal mStatus WatchForPowerChanges(mDNS *const m)
1308 {
1309 IONotificationPortRef thePortRef;
1310 m->p->PowerConnection = IORegisterForSystemPower(m, &thePortRef, PowerChanged, &m->p->PowerNotifier);
1311 if (m->p->PowerConnection)
1312 {
1313 m->p->PowerRLS = IONotificationPortGetRunLoopSource(thePortRef);
1314 CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->PowerRLS, kCFRunLoopDefaultMode);
1315 return(mStatus_NoError);
1316 }
1317 return(-1);
1318 }
1319
1320CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
1321CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
1322CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
1323CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
1324
1325mDNSexport mDNSBool mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
1326 {
1327 int major = 0, minor = 0;
1328 char letter = 0, prodname[256]="Mac OS X", prodvers[256]="", buildver[256]="?";
1329 CFDictionaryRef vers = _CFCopySystemVersionDictionary();
1330 if (vers)
1331 {
1332 CFStringRef cfprodname = CFDictionaryGetValue(vers, _kCFSystemVersionProductNameKey);
1333 CFStringRef cfprodvers = CFDictionaryGetValue(vers, _kCFSystemVersionProductVersionKey);
1334 CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
1335 if (cfprodname) CFStringGetCString(cfprodname, prodname, sizeof(prodname), kCFStringEncodingUTF8);
1336 if (cfprodvers) CFStringGetCString(cfprodvers, prodvers, sizeof(prodvers), kCFStringEncodingUTF8);
1337 if (cfbuildver) CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8);
1338 sscanf(buildver, "%d%c%d", &major, &letter, &minor);
1339 CFRelease(vers);
1340 }
1341 if (HINFO_SWstring) mDNS_snprintf(HINFO_SWstring, 256, "%s %s (%s), %s", prodname, prodvers, buildver, mDNSResponderVersionString);
1342 return(major);
1343 }
1344
1345mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
1346 {
1347 mStatus err;
1348
1349 m->hostlabel.c[0] = 0;
1350
1351 char *HINFO_HWstring = "Macintosh";
1352 char HINFO_HWstring_buffer[256];
1353 int get_model[2] = { CTL_HW, HW_MODEL };
1354 size_t len_model = sizeof(HINFO_HWstring_buffer);
1355 if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0)
1356 HINFO_HWstring = HINFO_HWstring_buffer;
1357
1358 char HINFO_SWstring[256] = "";
1359 if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring) < 7) m->KnownBugs = mDNS_KnownBug_PhantomInterfaces;
1360
1361 mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
1362 mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
1363 if (hlen + slen < 254)
1364 {
1365 m->HIHardware.c[0] = hlen;
1366 m->HISoftware.c[0] = slen;
1367 mDNSPlatformMemCopy(HINFO_HWstring, &m->HIHardware.c[1], hlen);
1368 mDNSPlatformMemCopy(HINFO_SWstring, &m->HISoftware.c[1], slen);
1369 }
1370
1371 m->p->InterfaceList = mDNSNULL;
1372 m->p->userhostlabel.c[0] = 0;
1373 UpdateInterfaceList(m);
1374 SetupActiveInterfaces(m);
1375
1376 err = WatchForNetworkChanges(m);
1377 if (err) return(err);
1378
1379 err = WatchForPowerChanges(m);
1380 return(err);
1381 }
1382
1383mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
1384 {
1385 mStatus result = mDNSPlatformInit_setup(m);
1386 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
1387 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
1388 if (result == mStatus_NoError) mDNSCoreInitComplete(m, mStatus_NoError);
1389 return(result);
1390 }
1391
1392mDNSexport void mDNSPlatformClose(mDNS *const m)
1393 {
1394 if (m->p->PowerConnection)
1395 {
1396 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->PowerRLS, kCFRunLoopDefaultMode);
1397 CFRunLoopSourceInvalidate(m->p->PowerRLS);
1398 CFRelease(m->p->PowerRLS);
1399 IODeregisterForSystemPower(&m->p->PowerNotifier);
1400 m->p->PowerConnection = NULL;
1401 m->p->PowerNotifier = NULL;
1402 m->p->PowerRLS = NULL;
1403 }
1404
1405 if (m->p->Store)
1406 {
1407 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
1408 CFRunLoopSourceInvalidate(m->p->StoreRLS);
1409 CFRelease(m->p->StoreRLS);
1410 CFRelease(m->p->Store);
1411 m->p->Store = NULL;
1412 m->p->StoreRLS = NULL;
1413 }
1414
1415 MarkAllInterfacesInactive(m);
1416 ClearInactiveInterfaces(m);
1417 }
1418
1419mDNSexport mDNSs32 mDNSPlatformOneSecond = 1000;
1420
1421mDNSexport mStatus mDNSPlatformTimeInit(mDNSs32 *timenow)
1422 {
1423 // Notes: Typical values for mach_timebase_info:
1424 // tbi.numer = 1000 million
1425 // tbi.denom = 33 million
1426 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
1427 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
1428 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
1429 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
1430 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
1431 //
1432 // Arithmetic notes:
1433 // tbi.denom is at least 1, and not more than 2^32-1.
1434 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
1435 // tbi.denom is at least 1, and not more than 2^32-1.
1436 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
1437 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
1438 // which is unlikely on any current or future Macintosh.
1439 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
1440 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
1441 struct mach_timebase_info tbi;
1442 kern_return_t result = mach_timebase_info(&tbi);
1443 if (result != KERN_SUCCESS) return(result);
1444 clockdivisor = ((uint64_t)tbi.denom * 1000000) / tbi.numer;
1445 *timenow = mDNSPlatformTimeNow();
1446 return(mStatus_NoError);
1447 }
1448
1449mDNSexport mDNSs32 mDNSPlatformTimeNow(void)
1450 {
1451 if (clockdivisor == 0) { LogMsg("mDNSPlatformTimeNow called before mDNSPlatformTimeInit"); return(0); }
1452 return((mDNSs32)(mach_absolute_time() / clockdivisor));
1453 }
1454
1455// Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
1456mDNSexport void mDNSPlatformLock (const mDNS *const m) { (void)m; }
1457mDNSexport void mDNSPlatformUnlock (const mDNS *const m) { (void)m; }
1458mDNSexport void mDNSPlatformStrCopy(const void *src, void *dst) { strcpy((char *)dst, (char *)src); }
1459mDNSexport mDNSu32 mDNSPlatformStrLen (const void *src) { return(strlen((char*)src)); }
1460mDNSexport void mDNSPlatformMemCopy(const void *src, void *dst, mDNSu32 len) { memcpy(dst, src, len); }
1461mDNSexport mDNSBool mDNSPlatformMemSame(const void *src, const void *dst, mDNSu32 len) { return(memcmp(dst, src, len) == 0); }
1462mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len) { bzero(dst, len); }
1463mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
1464mDNSexport void mDNSPlatformMemFree (void *mem) { freeL("mDNSPlatformMemFree", mem); }