2 * Copright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 Change History (most recent first):
28 Revision 1.157 2004/06/08 18:54:48 ksekar
29 <rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
31 Revision 1.156 2004/06/05 00:04:26 cheshire
32 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
34 Revision 1.155 2004/06/04 08:58:30 ksekar
35 <rdar://problem/3668624>: Keychain integration for secure dynamic update
37 Revision 1.154 2004/05/31 22:22:28 ksekar
38 <rdar://problem/3668639>: wide-area domains should be returned in
39 reg. domain enumeration
41 Revision 1.153 2004/05/26 17:06:33 cheshire
42 <rdar://problem/3668515>: Don't rely on CFSocketInvalidate() to remove RunLoopSource
44 Revision 1.152 2004/05/18 23:51:26 cheshire
45 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
47 Revision 1.151 2004/05/17 21:46:34 cheshire
48 <rdar://problem/3616426>: When interface is turned off, browse "remove" events are delivered with interface index zero
49 Take care to correctly update InterfaceIDs when a dormant interface comes back to life
51 Revision 1.150 2004/05/13 04:54:20 ksekar
52 Unified list copy/free code. Added symetric list for
54 Revision 1.149 2004/05/13 03:55:14 ksekar
55 Fixed list traversal bug in FoundDefSearchDomain.
57 Revision 1.148 2004/05/12 22:03:08 ksekar
58 Made GetSearchDomainList a true platform-layer call (declaration moved
59 from mDNSMacOSX.h to mDNSClientAPI.h), impelemted to return "local"
60 only on non-OSX platforms. Changed call to return a copy of the list
61 to avoid shared memory issues. Added a routine to free the list.
63 Revision 1.147 2004/05/12 02:03:25 ksekar
64 Non-local domains will only be browsed by default, and show up in
65 _browse domain enumeration, if they contain an _browse._dns-sd ptr record.
67 Revision 1.146 2004/04/27 02:49:15 cheshire
68 <rdar://problem/3634655>: mDNSResponder leaks sockets on bind() error
70 Revision 1.145 2004/04/21 03:08:03 cheshire
71 Rename 'alias' to more descriptive name 'primary'
73 Revision 1.144 2004/04/21 03:04:35 cheshire
74 Minor cleanup for clarity
76 Revision 1.143 2004/04/21 03:03:30 cheshire
77 Preparation work: AddInterfaceToList() should return pointer to structure it creates
79 Revision 1.142 2004/04/21 02:49:11 cheshire
80 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
82 Revision 1.141 2004/04/21 02:20:47 cheshire
83 Rename interface field 'CurrentlyActive' to more descriptive 'Exists'
85 Revision 1.140 2004/04/14 23:09:29 ksekar
86 Support for TSIG signed dynamic updates.
88 Revision 1.139 2004/04/09 17:40:26 cheshire
89 Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
91 Revision 1.138 2004/04/09 16:37:16 cheshire
92 Suggestion from Bob Bradley:
93 Move NumCacheRecordsForInterfaceID() to DNSCommon.c so it's available to all platform layers
95 Revision 1.137 2004/04/08 00:59:55 cheshire
96 <rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
97 Unify use of the InterfaceID field, and make code that walks the list respect the 'Exists' flag
99 Revision 1.136 2004/04/07 01:08:57 cheshire
100 <rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
102 Revision 1.135 2004/03/19 01:01:03 ksekar
103 Fixed config file parsing to chop newline
105 Revision 1.134 2004/03/13 01:57:34 ksekar
106 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
108 Revision 1.133 2004/02/02 22:46:56 cheshire
109 Move "CFRelease(dict);" inside the "if (dict)" check
111 Revision 1.132 2004/01/28 02:30:08 ksekar
112 Added default Search Domains to unicast browsing, controlled via
113 Networking sharing prefs pane. Stopped sending unicast messages on
114 every interface. Fixed unicast resolving via mach-port API.
116 Revision 1.131 2004/01/27 22:57:48 cheshire
117 <rdar://problem/3534352>: Need separate socket for issuing unicast queries
119 Revision 1.130 2004/01/27 22:28:40 cheshire
120 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
121 Additional lingering port 53 code deleted
123 Revision 1.129 2004/01/27 20:15:23 cheshire
124 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
126 Revision 1.128 2004/01/24 23:58:17 cheshire
127 Change to use mDNSVal16() instead of shifting and ORing
129 Revision 1.127 2004/01/24 04:59:16 cheshire
130 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
132 Revision 1.126 2004/01/23 23:23:15 ksekar
133 Added TCP support for truncated unicast messages.
135 Revision 1.125 2004/01/22 03:43:09 cheshire
136 Export constants like mDNSInterface_LocalOnly so that the client layers can use them
138 Revision 1.124 2004/01/21 21:53:19 cheshire
139 <rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port
141 Revision 1.123 2004/01/20 03:18:25 cheshire
142 Removed "LogMsg("Hey There!");" that evidently got checked in my mistake
144 Revision 1.122 2003/12/17 20:43:59 cheshire
145 <rdar://problem/3496728>: Syslog messages saying "sendto failed"
147 Revision 1.121 2003/12/13 03:05:28 ksekar
148 <rdar://problem/3192548>: DynDNS: Unicast query of service records
150 Revision 1.120 2003/12/08 21:00:46 rpantos
151 Changes to support mDNSResponder on Linux.
153 Revision 1.119 2003/12/03 02:35:15 cheshire
154 Also report value of m->timenow when logging sendto() failure
156 Revision 1.118 2003/11/14 20:59:09 cheshire
157 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
158 Best solution is just to combine mDNSClientAPI.h and mDNSPlatformFunctions.h into a single file.
160 Revision 1.117 2003/11/08 22:18:29 cheshire
161 <rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
163 Revision 1.116 2003/09/23 16:39:49 cheshire
164 When LogAllOperations is set, also report registration and deregistration of interfaces
166 Revision 1.115 2003/09/10 00:45:55 cheshire
167 <rdar://problem/3412328> Don't log "sendto failed" errors during the first two minutes of startup
169 Revision 1.114 2003/08/27 02:55:13 cheshire
170 <rdar://problem/3387910>: Bug: Don't report mDNSPlatformSendUDP sendto errno 64 (Host is down)
172 Revision 1.113 2003/08/19 22:20:00 cheshire
173 <rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
174 More minor refinements
176 Revision 1.112 2003/08/19 03:04:43 cheshire
177 <rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
179 Revision 1.111 2003/08/18 22:53:37 cheshire
180 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformTimeNow()
182 Revision 1.110 2003/08/16 03:39:00 cheshire
183 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
185 Revision 1.109 2003/08/15 02:19:49 cheshire
186 <rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
187 Also limit number of messages to at most 100
189 Revision 1.108 2003/08/12 22:24:52 cheshire
190 <rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
191 This message indicates a kernel bug, but still we don't want to flood syslog.
192 Do a sleep(1) after writing this log message, to limit the rate.
194 Revision 1.107 2003/08/12 19:56:25 cheshire
197 Revision 1.106 2003/08/12 13:48:32 cheshire
198 Add comment explaining clockdivisor calculation
200 Revision 1.105 2003/08/12 13:44:14 cheshire
201 <rdar://problem/3370229> mDNSResponder *VERY* unhappy if time goes backwards
202 Use mach_absolute_time() (which is guaranteed to always go forwards, resetting only on reboot)
203 instead of gettimeofday() (which can jump back if the user manually changes their time/date)
205 Revision 1.104 2003/08/12 13:12:07 cheshire
206 Textual search/replace: Indicate local functions using "mDNSlocal" instead of "static"
208 Revision 1.103 2003/08/08 18:36:04 cheshire
209 <rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
211 Revision 1.102 2003/08/06 00:14:52 cheshire
212 <rdar://problem/3330324> Need to check IP TTL on responses
213 Also add corresponding checks in the IPv6 code path
215 Revision 1.101 2003/08/05 22:20:16 cheshire
216 <rdar://problem/3330324> Need to check IP TTL on responses
218 Revision 1.100 2003/08/05 21:18:50 cheshire
219 <rdar://problem/3363185> mDNSResponder should ignore 6to4
220 Only use interfaces that are marked as multicast-capable (IFF_MULTICAST)
222 Revision 1.99 2003/08/05 20:13:52 cheshire
223 <rdar://problem/3294080> mDNSResponder using IPv6 interfaces before they are ready
224 Ignore interfaces with the IN6_IFF_NOTREADY flag set
226 Revision 1.98 2003/07/20 03:38:51 ksekar
227 <rdar://problem/3320722>
228 Completed support for Unix-domain socket based API.
230 Revision 1.97 2003/07/19 03:15:16 cheshire
231 Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
232 and add the obvious trivial implementations to each platform support layer
234 Revision 1.96 2003/07/18 00:30:00 cheshire
235 <rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
237 Revision 1.95 2003/07/12 03:15:20 cheshire
238 <rdar://problem/3324848> After SCDynamicStore notification, mDNSResponder updates
239 m->hostlabel even if user hasn't actually actually changed their dot-local hostname
241 Revision 1.94 2003/07/03 00:51:54 cheshire
242 <rdar://problem/3287213> When select() and recvmgs() disagree, get more info from kernel about the socket state
244 Revision 1.93 2003/07/03 00:09:14 cheshire
245 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
246 Additional refinement suggested by Josh: Use info->scope_id instead of if_nametoindex(info->ifa_name);
248 Revision 1.92 2003/07/02 21:19:51 cheshire
249 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
251 Revision 1.91 2003/06/24 01:53:51 cheshire
252 Minor update to comments
254 Revision 1.90 2003/06/24 01:51:47 cheshire
255 <rdar://problem/3303118> Oops: Double-dispose of sockets
256 Don't need to close sockets: CFSocketInvalidate() does that for us
258 Revision 1.89 2003/06/21 18:12:47 cheshire
259 <rdar://problem/3296061> Rendezvous cannot handle interfaces whose total name is >3 chars
260 One-line change: should say "IF_NAMESIZE", not sizeof(ifname)
262 Revision 1.88 2003/06/12 23:38:37 cheshire
263 <rdar://problem/3291162> mDNSResponder doesn't detect some configuration changes
264 Also check that scope_id matches before concluding that two interfaces are the same
266 Revision 1.87 2003/06/10 01:14:11 cheshire
267 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
269 Revision 1.86 2003/05/28 02:41:52 cheshire
270 <rdar://problem/3034346> Time to remove Mac OS 9 UDP Port 53 legacy support
272 Revision 1.85 2003/05/28 02:39:47 cheshire
273 Minor change to debugging messages
275 Revision 1.84 2003/05/27 22:29:40 cheshire
276 Remove out-dated comment
278 Revision 1.83 2003/05/26 03:21:29 cheshire
279 Tidy up address structure naming:
280 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
281 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
282 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
284 Revision 1.82 2003/05/26 03:01:27 cheshire
285 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
287 Revision 1.81 2003/05/24 02:06:42 cheshire
288 <rdar://problem/3268480> IPv6 Multicast Loopback doesn't work
289 Tried setting IPV6_MULTICAST_LOOP; it doesn't help.
290 However, it is probably wise to have the code explicitly set this socket
291 option anyway, in case the default changes in later versions of Unix.
293 Revision 1.80 2003/05/24 02:02:24 cheshire
294 <rdar://problem/3221880> if_indextoname consumes a lot of CPU
295 Fix error in myIfIndexToName; was returning prematurely
297 Revision 1.79 2003/05/23 23:07:44 cheshire
298 <rdar://problem/3268199> Must not write to stderr when running as daemon
300 Revision 1.78 2003/05/23 01:19:04 cheshire
301 <rdar://problem/3267085> mDNSResponder needs to signal type of service to AirPort
302 Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
304 Revision 1.77 2003/05/23 01:12:05 cheshire
307 Revision 1.76 2003/05/22 01:26:01 cheshire
310 Revision 1.75 2003/05/22 00:07:09 cheshire
311 <rdar://problem/3264366> myCFSocketCallBack recvfrom(5) error 1, errno 35
312 Extra logging to determine whether there is a bug in CFSocket
314 Revision 1.74 2003/05/21 20:20:12 cheshire
315 Fix warnings (mainly printf format string warnings, like using "%d" where
316 it should say "%lu", etc.) and improve error logging (use strerror()
317 to include textual error message as well as numeric error in log messages).
319 Revision 1.73 2003/05/21 17:56:29 ksekar
320 <rdar://problem/3191277>: mDNSResponder doesn't watch for IPv6 address changes
322 Revision 1.72 2003/05/14 18:48:41 cheshire
323 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
324 More minor refinements:
325 CFSocket.c needs to do *all* its mDNS_DeregisterInterface calls before freeing memory
326 mDNS_DeregisterInterface revalidates cache record when *any* representative of an interface goes away
328 Revision 1.71 2003/05/14 07:08:37 cheshire
329 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
330 Previously, when there was any network configuration change, mDNSResponder
331 would tear down the entire list of active interfaces and start again.
332 That was very disruptive, and caused the entire cache to be flushed,
333 and caused lots of extra network traffic. Now it only removes interfaces
334 that have really gone, and only adds new ones that weren't there before.
336 Revision 1.70 2003/05/07 18:30:24 cheshire
337 Fix signed/unsigned comparison warning
339 Revision 1.69 2003/05/06 20:14:44 cheshire
342 Revision 1.68 2003/05/06 00:00:49 cheshire
343 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
345 Revision 1.67 2003/04/29 00:43:44 cheshire
346 Fix compiler warnings
348 Revision 1.66 2003/04/26 02:41:58 cheshire
349 <rdar://problem/3241281> Change timenow from a local variable to a structure member
351 Revision 1.65 2003/04/26 02:34:01 cheshire
352 Add missing mDNSexport
354 Revision 1.64 2003/04/15 16:48:06 jgraessl
355 <rdar://problem/3228833>
356 Modified code in CFSocket notifier function to read all packets on the socket
357 instead of reading only one packet every time the notifier was called.
359 Revision 1.63 2003/04/15 16:33:50 jgraessl
360 <rdar://problem/3221880>
361 Switched to our own copy of if_indextoname to improve performance.
363 Revision 1.62 2003/03/28 01:55:44 cheshire
364 Minor improvements to debugging messages
366 Revision 1.61 2003/03/27 03:30:56 cheshire
367 <rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
368 Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
370 1. Make mDNS_DeregisterInterface() safe to call from a callback
371 2. Make HostNameCallback() use mDNS_DeadvertiseInterface() instead
372 (it never really needed to deregister the interface at all)
374 Revision 1.60 2003/03/15 04:40:38 cheshire
375 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
377 Revision 1.59 2003/03/11 01:23:26 cheshire
378 <rdar://problem/3194246> mDNSResponder socket problems
380 Revision 1.58 2003/03/06 01:43:04 cheshire
381 <rdar://problem/3189097> Additional debugging code in mDNSResponder
382 Improve "LIST_ALL_INTERFACES" output
384 Revision 1.57 2003/03/05 22:36:27 cheshire
385 <rdar://problem/3186338> Loopback doesn't work with mDNSResponder-27
386 Temporary workaround: Skip loopback interface *only* if we found at least one v4 interface to use
388 Revision 1.56 2003/03/05 01:50:38 cheshire
389 <rdar://problem/3189097> Additional debugging code in mDNSResponder
391 Revision 1.55 2003/02/21 01:54:09 cheshire
392 <rdar://problem/3099194> mDNSResponder needs performance improvements
393 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
395 Revision 1.54 2003/02/20 06:48:35 cheshire
396 <rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
397 Reviewed by: Josh Graessley, Bob Bradley
399 Revision 1.53 2003/01/29 02:21:23 cheshire
400 Return mStatus_Invalid if can't send packet because socket not available
402 Revision 1.52 2003/01/28 19:39:43 jgraessl
403 Enabling AAAA over IPv4 support.
405 Revision 1.51 2003/01/28 05:11:23 cheshire
406 Fixed backwards comparison in SearchForInterfaceByName
408 Revision 1.50 2003/01/13 23:49:44 jgraessl
409 Merged changes for the following fixes in to top of tree:
410 <rdar://problem/3086540> computer name changes not handled properly
411 <rdar://problem/3124348> service name changes are not properly handled
412 <rdar://problem/3124352> announcements sent in pairs, failing chattiness test
414 Revision 1.49 2002/12/23 22:13:30 jgraessl
415 Reviewed by: Stuart Cheshire
416 Initial IPv6 support for mDNSResponder.
418 Revision 1.48 2002/11/22 01:37:52 cheshire
419 <rdar://problem/3108426> mDNSResponder is monitoring ServiceEntities instead of InterfaceEntities
421 Revision 1.47 2002/09/21 20:44:51 zarzycki
424 Revision 1.46 2002/09/19 21:25:35 cheshire
425 mDNS_snprintf() doesn't need to be in a separate file
427 Revision 1.45 2002/09/17 01:45:13 cheshire
428 Add LIST_ALL_INTERFACES symbol for debugging
430 Revision 1.44 2002/09/17 01:36:23 cheshire
431 Move Puma support to CFSocketPuma.c
433 Revision 1.43 2002/09/17 01:05:28 cheshire
434 Change mDNS_AdvertiseLocalAddresses to be an Init parameter instead of a global
436 Revision 1.42 2002/09/16 23:13:50 cheshire
441 // ***************************************************************************
443 // Supporting routines to run mDNS on a CFRunLoop platform
444 // ***************************************************************************
446 // For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
447 // including ones that mDNSResponder chooses not to use.
448 #define LIST_ALL_INTERFACES 0
450 // For enabling AAAA records over IPv4. Setting this to 0 sends only
451 // A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both
452 // AAAA and A records over both IPv4 and IPv6.
453 #define AAAA_OVER_V4 1
455 #include "mDNSClientAPI.h" // Defines the interface provided to the client layer above
456 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
459 #include <unistd.h> // For select() and close()
460 #include <stdarg.h> // For va_list support
462 #include <net/if_dl.h>
464 #include <sys/param.h>
465 #include <sys/socket.h>
466 #include <sys/sysctl.h>
468 #include <sys/ioctl.h>
469 #include <time.h> // platform support for UTC time
470 #include <arpa/inet.h> // for inet_aton
472 #include <netinet/in.h> // For IP_RECVTTL
474 #define IP_RECVTTL 24 // bool; receive reception TTL w/dgram
477 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
478 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
479 #include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
481 #include <Security/Security.h>
483 // Code contributed by Dave Heller:
484 // Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
485 // work on Mac OS X 10.1, which does not have the getifaddrs call.
486 #define RUN_ON_PUMA_WITHOUT_IFADDRS 0
487 #if RUN_ON_PUMA_WITHOUT_IFADDRS
488 #include "CFSocketPuma.c"
493 #include <IOKit/IOKitLib.h>
494 #include <IOKit/IOMessage.h>
495 #include <mach/mach_time.h>
497 typedef struct AuthRecordListElem
499 struct AuthRecordListElem
*next
;
501 } AuthRecordListElem
;
503 typedef struct SearchListElem
505 struct SearchListElem
*next
;
509 DNSQuestion registerQ
;
510 AuthRecordListElem
*AuthRecs
;
514 // ***************************************************************************
517 static mDNSu32 clockdivisor
= 0;
518 static mDNSBool DNSConfigInitialized
= mDNSfalse
;
519 #define MAX_SEARCH_DOMAINS 32
521 // for domain enumeration and default browsing
522 static SearchListElem
*SearchList
= NULL
; // where we search for _browse domains
523 static DNSQuestion DefBrowseDomainQ
; // our local enumeration query for _browse domains
524 static DNameListElem
*DefBrowseList
= NULL
; // cache of answers to above query (where we search for empty string browses)
526 #define CONFIG_FILE "/etc/mDNSResponder.conf"
527 #define LH_KEYCHAIN_DESC "Lighthouse Shared Secret"
528 #define LH_KEYCHAIN_SERVICE "Lighthouse"
529 #define SYS_KEYCHAIN_PATH "/Library/Keychains/System.keychain"
530 #define LH_SUFFIX "members.mac.com."
532 // ***************************************************************************
535 #define mDNSSameIPv4Address(A,B) ((A).NotAnInteger == (B).NotAnInteger)
536 #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])
538 #define mDNSAddressIsAllDNSLinkGroup(X) ( \
539 ((X)->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address((X)->ip.v4, AllDNSLinkGroup )) || \
540 ((X)->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address((X)->ip.v6, AllDNSLinkGroupv6)) )
542 // ***************************************************************************
545 mDNSlocal
struct ifaddrs
* myGetIfAddrs(int refresh
)
547 static struct ifaddrs
*ifa
= NULL
;
555 if (ifa
== NULL
) getifaddrs(&ifa
);
560 mDNSlocal
int myIfIndexToName(u_short index
, char* name
)
563 for (ifa
= myGetIfAddrs(0); ifa
; ifa
= ifa
->ifa_next
)
564 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
565 if (((struct sockaddr_dl
*)ifa
->ifa_addr
)->sdl_index
== index
)
566 { strncpy(name
, ifa
->ifa_name
, IF_NAMESIZE
); return 0; }
570 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS
*const m
, mDNSu32 index
)
572 NetworkInterfaceInfoOSX
*i
;
573 if (index
== (uint32_t)~0) return(mDNSInterface_LocalOnly
);
575 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
576 // Don't get tricked by inactive interfaces with no InterfaceID set
577 if (i
->ifinfo
.InterfaceID
&& i
->scope_id
== index
) return(i
->ifinfo
.InterfaceID
);
581 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS
*const m
, mDNSInterfaceID id
)
583 NetworkInterfaceInfoOSX
*i
;
584 if (id
== mDNSInterface_LocalOnly
) return((mDNSu32
)~0);
586 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
587 // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces, which have no InterfaceID set
588 if ((mDNSInterfaceID
)i
== id
) return(i
->scope_id
);
592 // NOTE: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
593 // NOTE: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
594 mDNSexport mStatus
mDNSPlatformSendUDP(const mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
,
595 mDNSInterfaceID InterfaceID
, const mDNSAddr
*dst
, mDNSIPPort dstPort
)
599 // Note: For this platform we've adopted the convention that InterfaceIDs are secretly pointers
600 // to the NetworkInterfaceInfoOSX structure that holds the active sockets. The mDNSCore code
601 // doesn't know that and doesn't need to know that -- it just treats InterfaceIDs as opaque identifiers.
602 NetworkInterfaceInfoOSX
*info
= (NetworkInterfaceInfoOSX
*)InterfaceID
;
603 char *ifa_name
= info
? info
->ifa_name
: "unicast";
604 struct sockaddr_storage to
;
607 if (dst
->type
== mDNSAddrType_IPv4
)
609 struct sockaddr_in
*sin_to
= (struct sockaddr_in
*)&to
;
610 sin_to
->sin_len
= sizeof(*sin_to
);
611 sin_to
->sin_family
= AF_INET
;
612 sin_to
->sin_port
= dstPort
.NotAnInteger
;
613 sin_to
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
614 s
= info
? info
->ss
.sktv4
: m
->p
->unicastsockets
.sktv4
;
616 else if (dst
->type
== mDNSAddrType_IPv6
)
618 struct sockaddr_in6
*sin6_to
= (struct sockaddr_in6
*)&to
;
619 sin6_to
->sin6_len
= sizeof(*sin6_to
);
620 sin6_to
->sin6_family
= AF_INET6
;
621 sin6_to
->sin6_port
= dstPort
.NotAnInteger
;
622 sin6_to
->sin6_flowinfo
= 0;
623 sin6_to
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
624 sin6_to
->sin6_scope_id
= info
? info
->scope_id
: 0;
625 s
= info
? info
->ss
.sktv6
: m
->p
->unicastsockets
.sktv6
;
629 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!\n");
630 return mStatus_BadParamErr
;
634 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %X %s/%d to %#a:%d skt %d",
635 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
);
637 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %X %s/%d (socket of this type not available)",
638 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
));
640 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
641 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
642 if (s
< 0) return(mStatus_Invalid
);
644 err
= sendto(s
, msg
, (UInt8
*)end
- (UInt8
*)msg
, 0, (struct sockaddr
*)&to
, to
.ss_len
);
647 // Don't report EHOSTDOWN (i.e. ARP failure) to unicast destinations
648 if (errno
== EHOSTDOWN
&& !mDNSAddressIsAllDNSLinkGroup(dst
)) return(err
);
649 // Don't report EHOSTUNREACH in the first three minutes after boot
650 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
651 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
652 if (errno
== EHOSTUNREACH
&& (mDNSu32
)(m
->timenow
) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return(err
);
653 LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %s/%ld to %#a:%d skt %d error %d errno %d (%s) %lu",
654 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
, err
, errno
, strerror(errno
), (mDNSu32
)(m
->timenow
));
658 return(mStatus_NoError
);
661 mDNSlocal ssize_t
myrecvfrom(const int s
, void *const buffer
, const size_t max
,
662 struct sockaddr
*const from
, size_t *const fromlen
, mDNSAddr
*dstaddr
, char ifname
[IF_NAMESIZE
], mDNSu8
*ttl
)
664 static unsigned int numLogMessages
= 0;
665 struct iovec databuffers
= { (char *)buffer
, max
};
668 struct cmsghdr
*cmPtr
;
669 char ancillary
[1024];
671 *ttl
= 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
673 // Set up the message
674 msg
.msg_name
= (caddr_t
)from
;
675 msg
.msg_namelen
= *fromlen
;
676 msg
.msg_iov
= &databuffers
;
678 msg
.msg_control
= (caddr_t
)&ancillary
;
679 msg
.msg_controllen
= sizeof(ancillary
);
683 n
= recvmsg(s
, &msg
, 0);
686 if (errno
!= EWOULDBLOCK
&& numLogMessages
++ < 100) LogMsg("CFSocket.c: recvmsg(%d) returned error %d errno %d", s
, n
, errno
);
689 if (msg
.msg_controllen
< (int)sizeof(struct cmsghdr
))
691 if (numLogMessages
++ < 100) LogMsg("CFSocket.c: recvmsg(%d) msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
692 s
, msg
.msg_controllen
, sizeof(struct cmsghdr
));
695 if (msg
.msg_flags
& MSG_CTRUNC
)
697 if (numLogMessages
++ < 100) LogMsg("CFSocket.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s
);
701 *fromlen
= msg
.msg_namelen
;
703 // Parse each option out of the ancillary data.
704 for (cmPtr
= CMSG_FIRSTHDR(&msg
); cmPtr
; cmPtr
= CMSG_NXTHDR(&msg
, cmPtr
))
706 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
707 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVDSTADDR
)
709 dstaddr
->type
= mDNSAddrType_IPv4
;
710 dstaddr
->ip
.v4
.NotAnInteger
= *(u_int32_t
*)CMSG_DATA(cmPtr
);
712 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVIF
)
714 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)CMSG_DATA(cmPtr
);
715 if (sdl
->sdl_nlen
< IF_NAMESIZE
)
717 mDNSPlatformMemCopy(sdl
->sdl_data
, ifname
, sdl
->sdl_nlen
);
718 ifname
[sdl
->sdl_nlen
] = 0;
719 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
722 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVTTL
)
724 *ttl
= *(u_char
*)CMSG_DATA(cmPtr
);
726 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_PKTINFO
)
728 struct in6_pktinfo
*ip6_info
= (struct in6_pktinfo
*)CMSG_DATA(cmPtr
);
729 dstaddr
->type
= mDNSAddrType_IPv6
;
730 dstaddr
->ip
.v6
= *(mDNSv6Addr
*)&ip6_info
->ipi6_addr
;
731 myIfIndexToName(ip6_info
->ipi6_ifindex
, ifname
);
733 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_HOPLIMIT
)
735 *ttl
= *(int*)CMSG_DATA(cmPtr
);
742 // On entry, context points to our CFSocketSet
743 // If ss->info is NULL, we received this packet on our anonymous unicast socket
744 // If ss->info is non-NULL, we received this packet on port 5353 on the indicated interface
745 mDNSlocal
void myCFSocketCallBack(CFSocketRef cfs
, CFSocketCallBackType CallBackType
, CFDataRef address
, const void *data
, void *context
)
747 mDNSAddr senderAddr
, destAddr
;
748 mDNSIPPort senderPort
, destPort
= MulticastDNSPort
;
749 const CFSocketSet
*ss
= (const CFSocketSet
*)context
;
750 mDNS
*const m
= ss
->m
;
751 const mDNSInterfaceID InterfaceID
= ss
->info
? ss
->info
->ifinfo
.InterfaceID
: mDNSNULL
;
753 struct sockaddr_storage from
;
754 size_t fromlen
= sizeof(from
);
755 char packetifname
[IF_NAMESIZE
] = "";
756 int err
, s1
= -1, skt
= CFSocketGetNative(cfs
);
759 (void)address
; // Parameter not used
760 (void)data
; // Parameter not used
762 if (CallBackType
!= kCFSocketReadCallBack
)
763 LogMsg("myCFSocketCallBack: Why is CallBackType %d not kCFSocketReadCallBack?", CallBackType
);
765 if (cfs
== ss
->cfsv4
) s1
= ss
->sktv4
;
766 else if (cfs
== ss
->cfsv6
) s1
= ss
->sktv6
;
768 if (s1
< 0 || s1
!= skt
)
770 LogMsg("myCFSocketCallBack: s1 %d native socket %d, cfs %p", s1
, skt
, cfs
);
771 LogMsg("myCFSocketCallBack: cfsv4 %p, sktv4 %d", ss
->cfsv4
, ss
->sktv4
);
772 LogMsg("myCFSocketCallBack: cfsv6 %p, sktv6 %d", ss
->cfsv6
, ss
->sktv6
);
776 while ((err
= myrecvfrom(s1
, &packet
, sizeof(packet
), (struct sockaddr
*)&from
, &fromlen
, &destAddr
, packetifname
, &ttl
)) >= 0)
779 if (from
.ss_family
== AF_INET
)
781 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&from
;
782 senderAddr
.type
= mDNSAddrType_IPv4
;
783 senderAddr
.ip
.v4
.NotAnInteger
= sin
->sin_addr
.s_addr
;
784 senderPort
.NotAnInteger
= sin
->sin_port
;
786 else if (from
.ss_family
== AF_INET6
)
788 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&from
;
789 senderAddr
.type
= mDNSAddrType_IPv6
;
790 senderAddr
.ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
791 senderPort
.NotAnInteger
= sin6
->sin6_port
;
795 LogMsg("myCFSocketCallBack from is unknown address family %d", from
.ss_family
);
799 // Even though we indicated a specific interface in the IP_ADD_MEMBERSHIP call, a weirdness of the
800 // sockets API means that even though this socket has only officially joined the multicast group
801 // on one specific interface, the kernel will still deliver multicast packets to it no matter which
802 // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
803 // To work around this weirdness, we use the IP_RECVIF option to find the name of the interface
804 // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
806 verbosedebugf("myCFSocketCallBack got a packet from %#a to %#a on unicast socket", &senderAddr
, &destAddr
);
807 else if (!strcmp(ss
->info
->ifa_name
, packetifname
))
808 verbosedebugf("myCFSocketCallBack got a packet from %#a to %#a on interface %#a/%s",
809 &senderAddr
, &destAddr
, &ss
->info
->ifinfo
.ip
, ss
->info
->ifa_name
);
812 verbosedebugf("myCFSocketCallBack got a packet from %#a to %#a on interface %#a/%s (Ignored -- really arrived on interface %s)",
813 &senderAddr
, &destAddr
, &ss
->info
->ifinfo
.ip
, ss
->info
->ifa_name
, packetifname
);
817 if (err
< (int)sizeof(DNSMessageHeader
)) { debugf("myCFSocketCallBack packet length (%d) too short", err
); return; }
819 mDNSCoreReceive(m
, &packet
, (unsigned char*)&packet
+ err
, &senderAddr
, senderPort
, &destAddr
, destPort
, InterfaceID
, ttl
);
822 if (err
< 0 && (errno
!= EWOULDBLOCK
|| count
== 0))
824 // Something is busted here.
825 // CFSocket says there is a packet, but myrecvfrom says there is not.
826 // Try calling select() to get another opinion.
827 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
828 // All of this is racy, as data may have arrived after the call to select()
829 int save_errno
= errno
;
833 int solen
= sizeof(int);
836 FD_SET(s1
, &readfds
);
837 struct timeval timeout
;
840 int selectresult
= select(s1
+1, &readfds
, NULL
, NULL
, &timeout
);
841 if (getsockopt(s1
, SOL_SOCKET
, SO_ERROR
, &so_error
, &solen
) == -1)
842 LogMsg("myCFSocketCallBack getsockopt(SO_ERROR) error %d", errno
);
843 if (getsockopt(s1
, SOL_SOCKET
, SO_NREAD
, &so_nread
, &solen
) == -1)
844 LogMsg("myCFSocketCallBack getsockopt(SO_NREAD) error %d", errno
);
845 if (ioctl(s1
, FIONREAD
, &fionread
) == -1)
846 LogMsg("myCFSocketCallBack ioctl(FIONREAD) error %d", errno
);
847 static unsigned int numLogMessages
= 0;
848 if (numLogMessages
++ < 100)
849 LogMsg("myCFSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
850 s1
, err
, save_errno
, strerror(save_errno
), selectresult
, FD_ISSET(s1
, &readfds
) ? "" : "*NO* ", so_error
, so_nread
, fionread
, count
);
851 sleep(1); // After logging this error, rate limit so we don't flood syslog
855 // TCP socket support for unicast DNS and Dynamic DNS Update
859 TCPConnectionCallback callback
;
864 mDNSlocal
void tcpCFSocketCallback(CFSocketRef cfs
, CFSocketCallBackType CallbackType
, CFDataRef address
,
865 const void *data
, void *context
)
867 #pragma unused(CallbackType, address, data)
868 mDNSBool connect
= mDNSfalse
;
870 tcpInfo_t
*info
= context
;
871 if (!info
->connected
)
874 info
->connected
= mDNStrue
; // prevent connected flag from being set in future callbacks
876 info
->callback(CFSocketGetNative(cfs
), info
->context
, connect
);
877 // NOTE: the callback may call CloseConnection here, which frees the context structure!
880 mDNSexport mStatus
mDNSPlatformTCPConnect(const mDNSAddr
*dst
, mDNSOpaque16 dstport
, mDNSInterfaceID InterfaceID
,
881 TCPConnectionCallback callback
, void *context
, int *descriptor
)
883 int sd
, on
= 1; // "on" for setsockopt
884 struct sockaddr_in saddr
;
885 CFSocketContext cfContext
= { 0, NULL
, 0, 0, 0 };
888 CFRunLoopSourceRef rls
;
889 CFOptionFlags srFlags
;
891 (void)InterfaceID
; //!!!KRS use this if non-zero!!!
894 if (dst
->type
!= mDNSAddrType_IPv4
)
896 LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: opperation not supported");
897 return mStatus_UnknownErr
;
900 sd
= socket(AF_INET
, SOCK_STREAM
, 0);
903 LogMsg("ERROR: socket; %s", strerror(errno
));
904 return mStatus_UnknownErr
;
907 if (fcntl(sd
, F_SETFL
, O_NONBLOCK
) < 0)
909 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno
));
910 return mStatus_UnknownErr
;
913 // receive interface identifiers
914 if (setsockopt(sd
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
)) < 0)
916 LogMsg("setsockopt IP_RECVIF - %s", strerror(errno
));
917 return mStatus_UnknownErr
;
919 // set up CF wrapper, add to Run Loop
920 info
= mallocL("mDNSPlatformTCPConnect", sizeof(tcpInfo_t
));
921 info
->callback
= callback
;
922 info
->context
= context
;
923 cfContext
.info
= info
;
924 sr
= CFSocketCreateWithNative(kCFAllocatorDefault
, sd
, kCFSocketReadCallBack
| kCFSocketConnectCallBack
,
925 tcpCFSocketCallback
, &cfContext
);
928 LogMsg("ERROR: mDNSPlatformTCPConnect - CFSocketRefCreateWithNative failed");
929 freeL("mDNSPlatformTCPConnect", info
);
930 return mStatus_UnknownErr
;
933 // prevent closing of native socket
934 srFlags
= CFSocketGetSocketFlags(sr
);
935 CFSocketSetSocketFlags(sr
, srFlags
& (~kCFSocketCloseOnInvalidate
));
937 rls
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, sr
, 0);
940 LogMsg("ERROR: mDNSPlatformTCPConnect - CFSocketCreateRunLoopSource failed");
941 freeL("mDNSPlatformTCPConnect", info
);
942 return mStatus_UnknownErr
;
945 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
948 // initiate connection wth peer
949 bzero(&saddr
, sizeof(saddr
));
950 saddr
.sin_family
= AF_INET
;
951 saddr
.sin_port
= dstport
.NotAnInteger
;
952 memcpy(&saddr
.sin_addr
, &dst
->ip
.v4
.NotAnInteger
, sizeof(saddr
.sin_addr
));
953 if (connect(sd
, (struct sockaddr
*)&saddr
, sizeof(saddr
)) < 0)
955 if (errno
== EINPROGRESS
)
959 return mStatus_ConnectionPending
;
961 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: %s", strerror(errno
));
962 freeL("mDNSPlatformTCPConnect", info
);
963 CFSocketInvalidate(sr
);
964 return mStatus_ConnectionFailed
;
968 return mStatus_ConnectionEstablished
;
971 mDNSexport
void mDNSPlatformTCPCloseConnection(int sd
)
973 CFSocketContext cfContext
;
977 // get the CFSocket for the descriptor, if it exists
978 sr
= CFSocketCreateWithNative(kCFAllocatorDefault
, sd
, NULL
, NULL
, NULL
);
981 LogMsg("ERROR: mDNSPlatformTCPCloseConnection - attempt to close a socket that was not properly created");
984 CFSocketGetContext(sr
, &cfContext
);
987 LogMsg("ERROR: mDNSPlatformTCPCloseConnection - could not retreive tcpInfo from socket context");
991 CFRelease(sr
); // this only releases the copy we allocated with CreateWithNative above
993 info
= cfContext
.info
;
994 CFSocketInvalidate(sr
);
997 freeL("mDNSPlatformTCPCloseConnection", info
);
1000 mDNSexport
int mDNSPlatformReadTCP(int sd
, void *buf
, int buflen
)
1002 int nread
= recv(sd
, buf
, buflen
, 0);
1005 if (errno
== EAGAIN
) return 0; // no data available (call would block)
1006 LogMsg("ERROR: mDNSPlatformReadTCP - recv: %s", strerror(errno
));
1012 mDNSexport
int mDNSPlatformWriteTCP(int sd
, const char *msg
, int len
)
1014 int nsent
= send(sd
, msg
, len
, 0);
1018 if (errno
== EAGAIN
) return 0; // blocked
1019 LogMsg("ERROR: mDNSPlatformWriteTCP - sendL %s", strerror(errno
));
1025 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
1026 mDNSlocal
void GetUserSpecifiedFriendlyComputerName(domainlabel
*const namelabel
)
1028 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
1029 CFStringRef cfs
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
1032 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
1037 // This gets the text of the field currently labelled "Rendezvous Name" in the Sharing Prefs Control Panel
1038 mDNSlocal
void GetUserSpecifiedRFC1034ComputerName(domainlabel
*const namelabel
)
1040 CFStringRef cfs
= SCDynamicStoreCopyLocalHostName(NULL
);
1043 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
1048 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
1049 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
1050 mDNSlocal mStatus
SetupSocket(CFSocketSet
*cp
, mDNSIPPort port
, const mDNSAddr
*ifaddr
, u_short sa_family
)
1052 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
1053 CFSocketRef
*c
= (sa_family
== AF_INET
) ? &cp
->cfsv4
: &cp
->cfsv6
;
1054 CFRunLoopSourceRef
*r
= (sa_family
== AF_INET
) ? &cp
->rlsv4
: &cp
->rlsv6
;
1056 const int twofivefive
= 255;
1057 mStatus err
= mStatus_NoError
;
1058 char *errstr
= mDNSNULL
;
1060 if (*s
>= 0) { LogMsg("SetupSocket ERROR: socket %d is already set", *s
); return(-1); }
1061 if (*c
) { LogMsg("SetupSocket ERROR: CFSocketRef %p is already set", *c
); return(-1); }
1063 // Open the socket...
1064 int skt
= socket(sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
1065 if (skt
< 0) { LogMsg("socket error %d errno %d (%s)", skt
, errno
, strerror(errno
)); return(skt
); }
1067 // ... with a shared UDP port, if it's for multicast receiving
1068 if (port
.NotAnInteger
) err
= setsockopt(skt
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
1069 if (err
< 0) { errstr
= "setsockopt - SO_REUSEPORT"; goto fail
; }
1071 if (sa_family
== AF_INET
)
1073 // We want to receive destination addresses
1074 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVDSTADDR
, &on
, sizeof(on
));
1075 if (err
< 0) { errstr
= "setsockopt - IP_RECVDSTADDR"; goto fail
; }
1077 // We want to receive interface identifiers
1078 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
1079 if (err
< 0) { errstr
= "setsockopt - IP_RECVIF"; goto fail
; }
1081 // We want to receive packet TTL value so we can check it
1082 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVTTL
, &on
, sizeof(on
));
1083 // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
1085 // Add multicast group membership on this interface, if it's for multicast receiving
1086 if (port
.NotAnInteger
)
1088 struct in_addr addr
= { ifaddr
->ip
.v4
.NotAnInteger
};
1090 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroup
.NotAnInteger
;
1091 imr
.imr_interface
= addr
;
1092 err
= setsockopt(skt
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &imr
, sizeof(imr
));
1093 if (err
< 0) { errstr
= "setsockopt - IP_ADD_MEMBERSHIP"; goto fail
; }
1095 // Specify outgoing interface too
1096 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_IF
, &addr
, sizeof(addr
));
1097 if (err
< 0) { errstr
= "setsockopt - IP_MULTICAST_IF"; goto fail
; }
1100 // Send unicast packets with TTL 255
1101 err
= setsockopt(skt
, IPPROTO_IP
, IP_TTL
, &twofivefive
, sizeof(twofivefive
));
1102 if (err
< 0) { errstr
= "setsockopt - IP_TTL"; goto fail
; }
1104 // And multicast packets with TTL 255 too
1105 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_TTL
, &twofivefive
, sizeof(twofivefive
));
1106 if (err
< 0) { errstr
= "setsockopt - IP_MULTICAST_TTL"; goto fail
; }
1108 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
1109 const int ip_tosbits
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
;
1110 err
= setsockopt(skt
, IPPROTO_IP
, IP_TOS
, &ip_tosbits
, sizeof(ip_tosbits
));
1111 if (err
< 0) { errstr
= "setsockopt - IP_TOS"; goto fail
; }
1113 // And start listening for packets
1114 struct sockaddr_in listening_sockaddr
;
1115 listening_sockaddr
.sin_family
= AF_INET
;
1116 listening_sockaddr
.sin_port
= port
.NotAnInteger
;
1117 listening_sockaddr
.sin_addr
.s_addr
= 0; // Want to receive multicasts AND unicasts on this socket
1118 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr
, sizeof(listening_sockaddr
));
1119 if (err
) { errstr
= "bind"; goto fail
; }
1121 else if (sa_family
== AF_INET6
)
1123 // We want to receive destination addresses and receive interface identifiers
1124 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_PKTINFO
, &on
, sizeof(on
));
1125 if (err
< 0) { errstr
= "setsockopt - IPV6_PKTINFO"; goto fail
; }
1127 // We want to receive packet hop count value so we can check it
1128 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_HOPLIMIT
, &on
, sizeof(on
));
1129 if (err
< 0) { errstr
= "setsockopt - IPV6_HOPLIMIT"; goto fail
; }
1131 // We want to receive only IPv6 packets, without this option, we may
1132 // get IPv4 addresses as mapped addresses.
1133 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
));
1134 if (err
< 0) { errstr
= "setsockopt - IPV6_V6ONLY"; goto fail
; }
1136 if (port
.NotAnInteger
)
1138 // Add multicast group membership on this interface, if it's for multicast receiving
1139 int interface_id
= if_nametoindex(cp
->info
->ifa_name
);
1140 struct ipv6_mreq i6mr
;
1141 i6mr
.ipv6mr_interface
= interface_id
;
1142 i6mr
.ipv6mr_multiaddr
= *(struct in6_addr
*)&AllDNSLinkGroupv6
;
1143 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &i6mr
, sizeof(i6mr
));
1144 if (err
< 0) { errstr
= "setsockopt - IPV6_JOIN_GROUP"; goto fail
; }
1146 // Specify outgoing interface too
1147 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &interface_id
, sizeof(interface_id
));
1148 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_IF"; goto fail
; }
1151 // Send unicast packets with TTL 255
1152 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
1153 if (err
< 0) { errstr
= "setsockopt - IPV6_UNICAST_HOPS"; goto fail
; }
1155 // And multicast packets with TTL 255 too
1156 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
1157 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_HOPS"; goto fail
; }
1159 // Note: IPV6_TCLASS appears not to be implemented on OS X right now (or indeed on ANY version of Unix?)
1161 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
1162 int tclass
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
; // This may not be right (since tclass is not implemented on OS X, I can't test it)
1163 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_TCLASS
, &tclass
, sizeof(tclass
));
1164 if (err
< 0) { errstr
= "setsockopt - IPV6_TCLASS"; goto fail
; }
1167 // Want to receive our own packets
1168 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &on
, sizeof(on
));
1169 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_LOOP"; goto fail
; }
1171 // And start listening for packets
1172 struct sockaddr_in6 listening_sockaddr6
;
1173 bzero(&listening_sockaddr6
, sizeof(listening_sockaddr6
));
1174 listening_sockaddr6
.sin6_len
= sizeof(listening_sockaddr6
);
1175 listening_sockaddr6
.sin6_family
= AF_INET6
;
1176 listening_sockaddr6
.sin6_port
= port
.NotAnInteger
;
1177 listening_sockaddr6
.sin6_flowinfo
= 0;
1178 // listening_sockaddr6.sin6_addr = IN6ADDR_ANY_INIT; // Want to receive multicasts AND unicasts on this socket
1179 listening_sockaddr6
.sin6_scope_id
= 0;
1180 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr6
, sizeof(listening_sockaddr6
));
1181 if (err
) { errstr
= "bind"; goto fail
; }
1184 fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
1186 CFSocketContext myCFSocketContext
= { 0, cp
, NULL
, NULL
, NULL
};
1187 *c
= CFSocketCreateWithNative(kCFAllocatorDefault
, *s
, kCFSocketReadCallBack
, myCFSocketCallBack
, &myCFSocketContext
);
1188 *r
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, *c
, 0);
1189 CFRunLoopAddSource(CFRunLoopGetCurrent(), *r
, kCFRunLoopDefaultMode
);
1194 LogMsg("%s error %ld errno %d (%s)", errstr
, err
, errno
, strerror(errno
));
1199 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
)
1201 if (sa
->sa_family
== AF_INET
)
1203 struct sockaddr_in
*ifa_addr
= (struct sockaddr_in
*)sa
;
1204 ip
->type
= mDNSAddrType_IPv4
;
1205 ip
->ip
.v4
.NotAnInteger
= ifa_addr
->sin_addr
.s_addr
;
1208 else if (sa
->sa_family
== AF_INET6
)
1210 struct sockaddr_in6
*ifa_addr
= (struct sockaddr_in6
*)sa
;
1211 ip
->type
= mDNSAddrType_IPv6
;
1212 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr
->sin6_addr
)) ifa_addr
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
1213 ip
->ip
.v6
= *(mDNSv6Addr
*)&ifa_addr
->sin6_addr
;
1218 LogMsg("SetupAddr invalid sa_family %d", sa
->sa_family
);
1223 mDNSlocal NetworkInterfaceInfoOSX
*AddInterfaceToList(mDNS
*const m
, struct ifaddrs
*ifa
)
1225 mDNSu32 scope_id
= if_nametoindex(ifa
->ifa_name
);
1227 SetupAddr(&ip
, ifa
->ifa_addr
);
1228 NetworkInterfaceInfoOSX
**p
;
1229 for (p
= &m
->p
->InterfaceList
; *p
; p
= &(*p
)->next
)
1230 if (scope_id
== (*p
)->scope_id
&& mDNSSameAddress(&ip
, &(*p
)->ifinfo
.ip
))
1232 debugf("AddInterfaceToList: Found existing interface %u with address %#a", scope_id
, &ip
);
1233 (*p
)->Exists
= mDNStrue
;
1237 debugf("AddInterfaceToList: Making new interface %u with address %#a", scope_id
, &ip
);
1238 NetworkInterfaceInfoOSX
*i
= (NetworkInterfaceInfoOSX
*)mallocL("NetworkInterfaceInfoOSX", sizeof(*i
));
1239 if (!i
) return(mDNSNULL
);
1240 i
->ifa_name
= (char *)mallocL("NetworkInterfaceInfoOSX name", strlen(ifa
->ifa_name
) + 1);
1241 if (!i
->ifa_name
) { freeL("NetworkInterfaceInfoOSX", i
); return(mDNSNULL
); }
1242 strcpy(i
->ifa_name
, ifa
->ifa_name
);
1244 bzero(&i
->ifinfo
.uDNS_info
, sizeof(uDNS_NetworkInterfaceInfo
));
1245 i
->ifinfo
.InterfaceID
= mDNSNULL
;
1247 i
->ifinfo
.Advertise
= m
->AdvertiseLocalAddresses
;
1248 i
->ifinfo
.McastTxRx
= mDNSfalse
; // For now; will be set up later at the end of UpdateInterfaceList
1251 i
->Exists
= mDNStrue
;
1252 i
->scope_id
= scope_id
;
1253 i
->sa_family
= ifa
->ifa_addr
->sa_family
;
1254 i
->Multicast
= (ifa
->ifa_flags
& IFF_MULTICAST
) && !(ifa
->ifa_flags
& IFF_POINTOPOINT
);
1258 i
->ss
.sktv4
= i
->ss
.sktv6
= -1;
1259 i
->ss
.cfsv4
= i
->ss
.cfsv6
= NULL
;
1260 i
->ss
.rlsv4
= i
->ss
.rlsv6
= NULL
;
1266 mDNSlocal NetworkInterfaceInfoOSX
*FindRoutableIPv4(mDNS
*const m
, mDNSu32 scope_id
)
1268 NetworkInterfaceInfoOSX
*i
;
1269 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1270 if (i
->Exists
&& i
->scope_id
== scope_id
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
1271 if (!(i
->ifinfo
.ip
.ip
.v4
.b
[0] == 169 && i
->ifinfo
.ip
.ip
.v4
.b
[1] == 254))
1276 mDNSlocal mStatus
UpdateInterfaceList(mDNS
*const m
)
1278 mDNSBool foundav4
= mDNSfalse
;
1279 struct ifaddrs
*ifa
= myGetIfAddrs(1);
1280 struct ifaddrs
*theLoopback
= NULL
;
1281 int err
= (ifa
!= NULL
) ? 0 : (errno
!= 0 ? errno
: -1);
1282 int InfoSocket
= err
? -1 : socket(AF_INET6
, SOCK_DGRAM
, 0);
1283 if (err
) return(err
);
1285 // Set up the nice label
1286 m
->nicelabel
.c
[0] = 0;
1287 GetUserSpecifiedFriendlyComputerName(&m
->nicelabel
);
1288 if (m
->nicelabel
.c
[0] == 0) MakeDomainLabelFromLiteralString(&m
->nicelabel
, "Macintosh");
1290 // Set up the RFC 1034-compliant label
1291 domainlabel hostlabel
;
1293 GetUserSpecifiedRFC1034ComputerName(&hostlabel
);
1294 if (hostlabel
.c
[0] == 0) MakeDomainLabelFromLiteralString(&hostlabel
, "Macintosh");
1295 // If the user has changed their dot-local host name since the last time we checked, then update our local copy.
1296 // If the user has not changed their dot-local host name, then leave ours alone (m->hostlabel may have gone through
1297 // repeated conflict resolution to get to its current value, and if we reset it, we'll have to go through all that again.)
1298 if (SameDomainLabel(m
->p
->userhostlabel
.c
, hostlabel
.c
))
1299 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
1302 debugf("Updating m->hostlabel to %#s", hostlabel
.c
);
1303 m
->p
->userhostlabel
= m
->hostlabel
= hostlabel
;
1304 mDNS_GenerateFQDN(m
);
1305 if (mDNS_DNSRegistered(m
)) mDNS_GenerateGlobalFQDN(m
);
1310 #if LIST_ALL_INTERFACES
1311 if (ifa
->ifa_addr
->sa_family
== AF_APPLETALK
)
1312 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d is AF_APPLETALK",
1313 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1314 else if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
1315 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d is AF_LINK",
1316 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1317 else if (ifa
->ifa_addr
->sa_family
!= AF_INET
&& ifa
->ifa_addr
->sa_family
!= AF_INET6
)
1318 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
1319 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1320 if (!(ifa
->ifa_flags
& IFF_UP
))
1321 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d Interface not IFF_UP",
1322 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1323 if (!(ifa
->ifa_flags
& IFF_MULTICAST
))
1324 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
1325 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1326 if (ifa
->ifa_flags
& IFF_POINTOPOINT
)
1327 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
1328 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1329 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
1330 debugf("UpdateInterfaceList: %4s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
1331 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1333 if (ifa
->ifa_flags
& IFF_UP
)
1334 if (ifa
->ifa_addr
->sa_family
== AF_INET
|| ifa
->ifa_addr
->sa_family
== AF_INET6
)
1336 int ifru_flags6
= 0;
1337 if (ifa
->ifa_addr
->sa_family
== AF_INET6
&& InfoSocket
>= 0)
1339 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
1340 struct in6_ifreq ifr6
;
1341 bzero((char *)&ifr6
, sizeof(ifr6
));
1342 strncpy(ifr6
.ifr_name
, ifa
->ifa_name
, sizeof(ifr6
.ifr_name
));
1343 ifr6
.ifr_addr
= *sin6
;
1344 if (ioctl(InfoSocket
, SIOCGIFAFLAG_IN6
, &ifr6
) != -1)
1345 ifru_flags6
= ifr6
.ifr_ifru
.ifru_flags6
;
1346 verbosedebugf("%s %.16a %04X %04X", ifa
->ifa_name
, &sin6
->sin6_addr
, ifa
->ifa_flags
, ifru_flags6
);
1348 if (!(ifru_flags6
& (IN6_IFF_NOTREADY
| IN6_IFF_DETACHED
| IN6_IFF_DEPRECATED
| IN6_IFF_TEMPORARY
)))
1350 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
1354 AddInterfaceToList(m
, ifa
);
1355 if (ifa
->ifa_addr
->sa_family
== AF_INET
)
1356 foundav4
= mDNStrue
;
1360 ifa
= ifa
->ifa_next
;
1363 // Temporary workaround: Multicast loopback on IPv6 interfaces appears not to work.
1364 // In the interim, we skip loopback interface only if we found at least one v4 interface to use
1365 if (!foundav4
&& theLoopback
)
1366 AddInterfaceToList(m
, theLoopback
);
1368 // Now the list is complete, set the McastTxRx setting for each interface.
1369 // We always send and receive using IPv4.
1370 // To reduce traffic, we send and receive using IPv6 only on interfaces that have no routable IPv4 address.
1371 // Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
1372 // which means there's a good chance that most or all the other devices on that network should also have v4.
1373 // 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.
1374 // At this time, reducing the packet rate is more important than v6-only devices on a large configured network,
1375 // so we are willing to make that sacrifice.
1376 NetworkInterfaceInfoOSX
*i
;
1377 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1380 mDNSBool txrx
= i
->Multicast
&& ((i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) || !FindRoutableIPv4(m
, i
->scope_id
));
1381 if (i
->ifinfo
.McastTxRx
!= txrx
)
1383 i
->ifinfo
.McastTxRx
= txrx
;
1384 i
->Exists
= 2; // State change; need to deregister and reregister this interface
1388 if (InfoSocket
>= 0) close(InfoSocket
);
1392 mDNSlocal NetworkInterfaceInfoOSX
*SearchForInterfaceByName(mDNS
*const m
, char *ifname
, int type
)
1394 NetworkInterfaceInfoOSX
*i
;
1395 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1396 if (i
->Exists
&& !strcmp(i
->ifa_name
, ifname
) &&
1398 (type
== AF_INET
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) ||
1399 (type
== AF_INET6
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
) )) return(i
);
1403 mDNSlocal
void SetupActiveInterfaces(mDNS
*const m
)
1405 NetworkInterfaceInfoOSX
*i
;
1406 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1409 NetworkInterfaceInfo
*n
= &i
->ifinfo
;
1410 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(m
, i
->ifa_name
, i
->sa_family
);
1411 if (!primary
) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i
->ifa_name
);
1413 if (n
->InterfaceID
&& n
->InterfaceID
!= (mDNSInterfaceID
)primary
) // Sanity check
1415 LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != primary %p", n
->InterfaceID
, primary
);
1416 n
->InterfaceID
= mDNSNULL
;
1419 if (!n
->InterfaceID
)
1421 // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
1422 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
1423 // If n->InterfaceID is NOT set, then we haven't registered it and we should not try to deregister it
1424 n
->InterfaceID
= (mDNSInterfaceID
)primary
;
1425 mDNS_RegisterInterface(m
, n
);
1426 LogOperation("SetupActiveInterfaces: Registered %s(%lu) InterfaceID %p %#a%s",
1427 i
->ifa_name
, i
->scope_id
, primary
, &n
->ip
, n
->InterfaceActive
? " (Primary)" : "");
1431 debugf("SetupActiveInterfaces: No Tx/Rx on %s(%lu) InterfaceID %p %#a", i
->ifa_name
, i
->scope_id
, primary
, &n
->ip
);
1434 if (i
->sa_family
== AF_INET
&& primary
->ss
.sktv4
== -1)
1436 mStatus err
= SetupSocket(&primary
->ss
, MulticastDNSPort
, &i
->ifinfo
.ip
, AF_INET
);
1437 if (err
== 0) debugf("SetupActiveInterfaces: v4 socket%2d %s(%lu) InterfaceID %p %#a", primary
->ss
.sktv4
, i
->ifa_name
, i
->scope_id
, n
->InterfaceID
, &n
->ip
);
1438 else LogMsg("SetupActiveInterfaces: v4 socket%2d %s(%lu) InterfaceID %p %#a FAILED", primary
->ss
.sktv4
, i
->ifa_name
, i
->scope_id
, n
->InterfaceID
, &n
->ip
);
1441 if (i
->sa_family
== AF_INET6
&& primary
->ss
.sktv6
== -1)
1443 mStatus err
= SetupSocket(&primary
->ss
, MulticastDNSPort
, &i
->ifinfo
.ip
, AF_INET6
);
1444 if (err
== 0) debugf("SetupActiveInterfaces: v6 socket%2d %s(%lu) InterfaceID %p %#a", primary
->ss
.sktv6
, i
->ifa_name
, i
->scope_id
, n
->InterfaceID
, &n
->ip
);
1445 else LogMsg("SetupActiveInterfaces: v6 socket%2d %s(%lu) InterfaceID %p %#a FAILED", primary
->ss
.sktv6
, i
->ifa_name
, i
->scope_id
, n
->InterfaceID
, &n
->ip
);
1451 mDNSlocal
void MarkAllInterfacesInactive(mDNS
*const m
)
1453 NetworkInterfaceInfoOSX
*i
;
1454 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1455 i
->Exists
= mDNSfalse
;
1458 mDNSlocal
void CloseSocketSet(CFSocketSet
*ss
)
1460 // Note: MUST NOT close the underlying native BSD sockets.
1461 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately,
1462 // because it first has to unhook the sockets from its select() call, before it can safely close them.
1463 if (ss
->cfsv4
) { CFRunLoopRemoveSource(CFRunLoopGetCurrent(), ss
->rlsv4
, kCFRunLoopDefaultMode
); CFRelease(ss
->rlsv4
); CFSocketInvalidate(ss
->cfsv4
); CFRelease(ss
->cfsv4
); }
1464 if (ss
->cfsv6
) { CFRunLoopRemoveSource(CFRunLoopGetCurrent(), ss
->rlsv6
, kCFRunLoopDefaultMode
); CFRelease(ss
->rlsv6
); CFSocketInvalidate(ss
->cfsv6
); CFRelease(ss
->cfsv6
); }
1465 ss
->sktv4
= ss
->sktv6
= -1;
1466 ss
->cfsv4
= ss
->cfsv6
= NULL
;
1467 ss
->rlsv4
= ss
->rlsv6
= NULL
;
1470 mDNSlocal
void ClearInactiveInterfaces(mDNS
*const m
)
1473 // If an interface is going away, then deregister this from the mDNSCore.
1474 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
1475 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
1476 // it refers to has gone away we'll crash.
1477 // Don't actually close the sockets or free the memory yet: When the last representative of an interface goes away
1478 // mDNSCore may want to send goodbye packets on that interface. (Not yet implemented, but a good idea anyway.)
1479 NetworkInterfaceInfoOSX
*i
;
1480 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1482 // 1. If this interface is no longer active, or its InterfaceID is changing, deregister it
1483 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(m
, i
->ifa_name
, i
->sa_family
);
1484 if (i
->ifinfo
.InterfaceID
)
1485 if (i
->Exists
== 0 || i
->Exists
== 2 || i
->ifinfo
.InterfaceID
!= (mDNSInterfaceID
)primary
)
1487 LogOperation("ClearInactiveInterfaces: Deregistering %s(%lu) InterfaceID %p %#a%s",
1488 i
->ifa_name
, i
->scope_id
, i
->ifinfo
.InterfaceID
, &i
->ifinfo
.ip
, i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
1489 mDNS_DeregisterInterface(m
, &i
->ifinfo
);
1490 i
->ifinfo
.InterfaceID
= mDNSNULL
;
1491 // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
1492 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
1493 // If n->InterfaceID is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
1498 // Now that everything that's going to deregister has done so, we can close sockets and free the memory
1499 NetworkInterfaceInfoOSX
**p
= &m
->p
->InterfaceList
;
1503 // 2. Close all our CFSockets. We'll recreate them later as necessary.
1504 // (We may have previously had both v4 and v6, and we may not need both any more.)
1505 CloseSocketSet(&i
->ss
);
1506 // 3. If no longer active, delete interface from list and free memory
1507 if (!i
->Exists
&& NumCacheRecordsForInterfaceID(m
, (mDNSInterfaceID
)i
) == 0)
1509 debugf("ClearInactiveInterfaces: Deleting %#a", &i
->ifinfo
.ip
);
1511 if (i
->ifa_name
) freeL("NetworkInterfaceInfoOSX name", i
->ifa_name
);
1512 freeL("NetworkInterfaceInfoOSX", i
);
1520 mDNSlocal mStatus
RegisterNameServers(mDNS
*const m
, CFDictionaryRef dict
)
1529 mDNS_DeregisterDNSList(m
); // deregister orig list
1530 values
= CFDictionaryGetValue(dict
, kSCPropNetDNSServerAddresses
);
1531 if (!values
) return mStatus_NoError
;
1533 count
= CFArrayGetCount(values
);
1534 for (i
= 0; i
< count
; i
++)
1536 s
= CFArrayGetValueAtIndex(values
, i
);
1537 if (!s
) { LogMsg("ERROR: RegisterNameServers - CFArrayGetValueAtIndex"); break; }
1538 if (!CFStringGetCString(s
, buf
, 256, kCFStringEncodingASCII
))
1540 LogMsg("ERROR: RegisterNameServers - CFStringGetCString");
1543 if (!inet_aton(buf
, (struct in_addr
*)saddr
.b
))
1545 LogMsg("ERROR: RegisterNameServers - invalid address string %s", buf
);
1548 mDNS_RegisterDNS(m
, &saddr
);
1550 return mStatus_NoError
;
1553 mDNSlocal
void FreeARElemCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
1556 AuthRecordListElem
*elem
= rr
->RecordContext
;
1557 if (result
== mStatus_MemFree
) freeL("FreeARElemCallback", elem
);
1560 mDNSlocal
void FoundDomain(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1562 SearchListElem
*slElem
= question
->QuestionContext
;
1563 AuthRecordListElem
*arElem
, *ptr
, *prev
;
1570 arElem
= mallocL("FoundDomain - arElem", sizeof(AuthRecordListElem
));
1571 if (!arElem
) { LogMsg("ERROR: malloc"); return; }
1572 mDNS_SetupResourceRecord(&arElem
->ar
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, 7200, kDNSRecordTypeShared
, FreeARElemCallback
, arElem
);
1573 if (question
== &slElem
->browseQ
) name
= "_browse._dns-sd._udp.local.";
1574 else name
= "_register._dns-sd._udp.local.";
1575 MakeDomainNameFromDNSNameString(&arElem
->ar
.resrec
.name
, name
);
1576 strcpy(arElem
->ar
.resrec
.rdata
->u
.name
.c
, answer
->rdata
->u
.name
.c
);
1577 err
= mDNS_Register(m
, &arElem
->ar
);
1580 LogMsg("ERROR: FoundDomain - mDNS_Register returned %d", err
);
1581 freeL("FoundDomain - arElem", arElem
);
1584 arElem
->next
= slElem
->AuthRecs
;
1585 slElem
->AuthRecs
= arElem
;
1589 ptr
= slElem
->AuthRecs
;
1593 if (SameDomainName(&ptr
->ar
.resrec
.name
, &answer
->name
) && SameDomainName(&ptr
->ar
.resrec
.rdata
->u
.name
, &answer
->rdata
->u
.name
))
1595 debugf("Deregistering PTR %s -> %s", ptr
->ar
.resrec
.name
.c
, ptr
->ar
.resrec
.rdata
->u
.name
.c
);
1597 if (prev
) prev
->next
= ptr
->next
;
1598 else slElem
->AuthRecs
= ptr
->next
;
1600 err
= mDNS_Deregister(m
, dereg
);
1601 if (err
) LogMsg("ERROR: FoundDomain - mDNS_Deregister returned %d", err
);
1612 mDNSlocal mStatus
RegisterSearchDomains(mDNS
*const m
, CFDictionaryRef dict
)
1617 char buf
[MAX_ESCAPED_DOMAIN_NAME
];
1619 SearchListElem
*new, *ptr
, *prev
, *freeSLPtr
;
1620 AuthRecordListElem
*arList
;
1623 // step 1: mark each elem for removal (-1)
1624 for (ptr
= SearchList
; ptr
; ptr
= ptr
->next
) ptr
->flag
= -1;
1626 values
= CFDictionaryGetValue(dict
, kSCPropNetDNSSearchDomains
);
1629 count
= CFArrayGetCount(values
);
1630 for (i
= 0; i
< count
; i
++)
1632 s
= CFArrayGetValueAtIndex(values
, i
);
1633 if (!s
) { LogMsg("ERROR: RegisterNameServers - CFArrayGetValueAtIndex"); break; }
1634 if (!CFStringGetCString(s
, buf
, MAX_ESCAPED_DOMAIN_NAME
, kCFStringEncodingASCII
))
1636 LogMsg("ERROR: RegisterNameServers - CFStringGetCString");
1639 if (!MakeDomainNameFromDNSNameString(&domain
, buf
))
1641 LogMsg("ERROR: RegisterNameServers - invalid search domain %s", buf
);
1644 // if domain is in list, mark as pre-existent (0)
1645 for (ptr
= SearchList
; ptr
; ptr
= ptr
->next
)
1646 if (SameDomainName(&ptr
->domain
, &domain
)) { ptr
->flag
= 0; break; }
1648 // if domain not in list, add to list, mark as add (1)
1651 new = mallocL("RegisterSearchDomains - SearchListElem", sizeof(SearchListElem
));
1652 if (!new) { LogMsg("ERROR: RegisterSearchDomains - malloc"); return mStatus_UnknownErr
; }
1653 bzero(new, sizeof(SearchListElem
));
1654 strcpy(new->domain
.c
, domain
.c
);
1655 new->flag
= 1; // add
1656 new->next
= SearchList
;
1661 // delete elems marked for removal, do queries for elems marked add
1666 if (ptr
->flag
== -1) // remove
1668 mDNS_StopQuery(m
, &ptr
->browseQ
);
1669 mDNS_StopQuery(m
, &ptr
->registerQ
);
1670 // deregister records generated from answers to the query
1671 arList
= ptr
->AuthRecs
;
1672 ptr
->AuthRecs
= NULL
;
1675 AuthRecord
*dereg
= &arList
->ar
;
1676 arList
= arList
->next
;
1677 debugf("Deregistering PTR %s -> %s", dereg
->resrec
.name
.c
, dereg
->resrec
.rdata
->u
.name
.c
);
1678 err
= mDNS_Deregister(m
, dereg
);
1679 if (err
) LogMsg("ERROR: RegisterSearchDomains mDNS_Deregister returned %d", err
);
1682 // remove elem from list, delete
1683 if (prev
) prev
->next
= ptr
->next
;
1684 else SearchList
= ptr
->next
;
1687 freeL("RegisterNameServers - freeSLPtr", freeSLPtr
);
1691 if (ptr
->flag
== 1) // add
1693 err
= mDNS_GetDomains(m
, &ptr
->browseQ
, mDNS_DomainTypeBrowse
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
1694 if (err
) LogMsg("ERROR: RegisterNameServers - mDNS_DomainTypeBrowse, %d", err
);
1696 err
= mDNS_GetDomains(m
, &ptr
->registerQ
, mDNS_DomainTypeRegistration
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
1697 if (err
) LogMsg("ERROR: RegisterNameServers - mDNS_DomainTypeRegistration, %d", err
);
1701 if (ptr
->flag
) { LogMsg("RegisterNameServers - unknown flag %d. Skipping.", ptr
->flag
); }
1707 return mStatus_NoError
;
1710 // key must be kSCPropNetDNSServerAddresses or kSCPropNetDNSSearchDomains
1711 mDNSlocal mStatus
RegisterDNSConfig(mDNS
*const m
, CFDictionaryRef dict
, const CFStringRef key
)
1713 if (key
== kSCPropNetDNSSearchDomains
) return RegisterSearchDomains(m
, dict
);
1714 if (key
== kSCPropNetDNSServerAddresses
) return RegisterNameServers(m
, dict
);
1715 LogMsg("ERROR: RegisterDNSConfig - bad key"); return mStatus_UnknownErr
;
1719 mDNSlocal
void DNSConfigChanged(SCDynamicStoreRef session
, CFArrayRef changes
, void *context
)
1722 CFDictionaryRef dict
;
1725 if (DNSConfigInitialized
&& (!changes
|| CFArrayGetCount(changes
) == 0)) return;
1727 //!!!KRS fixme - we need a list of registerd servers. this wholesale
1728 // dereg doesn't work if there's an error and we bail out before registering the new list
1730 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetDNS
);
1731 if (!key
) { LogMsg("ERROR: DNSConfigChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); return; }
1732 dict
= SCDynamicStoreCopyValue(session
, key
);
1736 RegisterDNSConfig(m
, dict
, kSCPropNetDNSServerAddresses
);
1737 RegisterDNSConfig(m
, dict
, kSCPropNetDNSSearchDomains
);
1740 if (mDNS_DNSRegistered(m
)) mDNS_GenerateGlobalFQDN(m
);
1741 // no-op if label & domain are unchanged
1744 mDNSlocal mStatus
WatchForDNSChanges(mDNS
*const m
)
1747 CFMutableArrayRef keyList
;
1748 CFRunLoopSourceRef rls
;
1749 SCDynamicStoreRef session
;
1750 SCDynamicStoreContext context
= { 0, m
, NULL
, NULL
, NULL
};
1752 session
= SCDynamicStoreCreate(NULL
, CFSTR("trackDNS"), DNSConfigChanged
, &context
);
1753 if (!session
) { LogMsg("ERROR: WatchForDNSChanges - SCDynamicStoreCreate"); return mStatus_UnknownErr
; }
1755 keyList
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1756 if (!keyList
) { LogMsg("ERROR: WatchForDNSChanges - CFArrayCreateMutable"); return mStatus_UnknownErr
; }
1758 // create a pattern that matches the global DNS dictionary key
1759 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetDNS
);
1760 if (!key
) { LogMsg("ERROR: WatchForDNSChanges - SCDynamicStoreKeyCreateNetworkGlobalEntity"); return mStatus_UnknownErr
; }
1762 CFArrayAppendValue(keyList
, key
);
1765 // set the keys for our DynamicStore session
1766 SCDynamicStoreSetNotificationKeys(session
, keyList
, NULL
);
1769 // create a CFRunLoopSource for our DynamicStore session
1770 rls
= SCDynamicStoreCreateRunLoopSource(NULL
, session
, 0);
1771 if (!rls
) { LogMsg("ERROR: WatchForDNSChanges - SCDynamicStoreCreateRunLoopSource"); return mStatus_UnknownErr
; }
1773 // add the run loop source to our current run loop
1774 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
1777 // get initial configuration
1778 DNSConfigChanged(session
, NULL
, m
);
1779 return mStatus_NoError
;
1782 mDNSlocal
void NetworkChanged(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *context
)
1784 (void)store
; // Parameter not used
1785 (void)changedKeys
; // Parameter not used
1786 debugf("*** Network Configuration Change ***");
1788 mDNS
*const m
= (mDNS
*const)context
;
1789 MarkAllInterfacesInactive(m
);
1790 UpdateInterfaceList(m
);
1791 ClearInactiveInterfaces(m
);
1792 SetupActiveInterfaces(m
);
1794 if (m
->MainCallback
)
1795 m
->MainCallback(m
, mStatus_ConfigChanged
);
1798 mDNSlocal mStatus
WatchForNetworkChanges(mDNS
*const m
)
1801 SCDynamicStoreContext context
= { 0, m
, NULL
, NULL
, NULL
};
1802 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder"), NetworkChanged
, &context
);
1803 CFStringRef key1
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
1804 CFStringRef key2
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv6
);
1805 CFStringRef key3
= SCDynamicStoreKeyCreateComputerName(NULL
);
1806 CFStringRef key4
= SCDynamicStoreKeyCreateHostNames(NULL
);
1807 CFStringRef pattern1
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv4
);
1808 CFStringRef pattern2
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv6
);
1810 CFMutableArrayRef keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1811 CFMutableArrayRef patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1813 if (!store
) { LogMsg("SCDynamicStoreCreate failed: %s\n", SCErrorString(SCError())); goto error
; }
1814 if (!key1
|| !key2
|| !key3
|| !key4
|| !keys
|| !pattern1
|| !pattern2
|| !patterns
) goto error
;
1816 CFArrayAppendValue(keys
, key1
);
1817 CFArrayAppendValue(keys
, key2
);
1818 CFArrayAppendValue(keys
, key3
);
1819 CFArrayAppendValue(keys
, key4
);
1820 CFArrayAppendValue(patterns
, pattern1
);
1821 CFArrayAppendValue(patterns
, pattern2
);
1822 if (!SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
1823 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s\n", SCErrorString(SCError())); goto error
; }
1825 m
->p
->StoreRLS
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
1826 if (!m
->p
->StoreRLS
) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s\n", SCErrorString(SCError())); goto error
; }
1828 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
1829 m
->p
->Store
= store
;
1834 if (store
) CFRelease(store
);
1837 if (key1
) CFRelease(key1
);
1838 if (key2
) CFRelease(key2
);
1839 if (key3
) CFRelease(key3
);
1840 if (key4
) CFRelease(key4
);
1841 if (pattern1
) CFRelease(pattern1
);
1842 if (pattern2
) CFRelease(pattern2
);
1843 if (keys
) CFRelease(keys
);
1844 if (patterns
) CFRelease(patterns
);
1849 mDNSlocal
void PowerChanged(void *refcon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
1851 mDNS
*const m
= (mDNS
*const)refcon
;
1852 (void)service
; // Parameter not used
1855 case kIOMessageCanSystemPowerOff
: debugf("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
1856 case kIOMessageSystemWillPowerOff
: debugf("PowerChanged kIOMessageSystemWillPowerOff"); mDNSCoreMachineSleep(m
, true); break; // E0000250
1857 case kIOMessageSystemWillNotPowerOff
: debugf("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
1858 case kIOMessageCanSystemSleep
: debugf("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
1859 case kIOMessageSystemWillSleep
: debugf("PowerChanged kIOMessageSystemWillSleep"); mDNSCoreMachineSleep(m
, true); break; // E0000280
1860 case kIOMessageSystemWillNotSleep
: debugf("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
1861 case kIOMessageSystemHasPoweredOn
: debugf("PowerChanged kIOMessageSystemHasPoweredOn"); mDNSCoreMachineSleep(m
, false); break; // E0000300
1862 default: debugf("PowerChanged unknown message %X", messageType
); break;
1864 IOAllowPowerChange(m
->p
->PowerConnection
, (long)messageArgument
);
1867 mDNSlocal mStatus
WatchForPowerChanges(mDNS
*const m
)
1869 IONotificationPortRef thePortRef
;
1870 m
->p
->PowerConnection
= IORegisterForSystemPower(m
, &thePortRef
, PowerChanged
, &m
->p
->PowerNotifier
);
1871 if (m
->p
->PowerConnection
)
1873 m
->p
->PowerRLS
= IONotificationPortGetRunLoopSource(thePortRef
);
1874 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->PowerRLS
, kCFRunLoopDefaultMode
);
1875 return(mStatus_NoError
);
1880 mDNSexport mDNSBool haveSecInfo
= mDNSfalse
; // this must go away once we have full keychain integration
1881 mDNSlocal
void GetAuthInfoFromKeychainItem(mDNS
*m
, SecKeychainItemRef item
)
1884 mDNSu32 infoTag
= kSecAccountItemAttr
;
1885 mDNSu32 infoFmt
= 0; // string
1886 SecKeychainAttributeInfo info
;
1887 SecKeychainAttributeList
*authAttrList
= NULL
;
1892 char accountName
[MAX_ESCAPED_DOMAIN_NAME
];
1894 AuthRecord
*rrReg
, *rrBrowse
;
1897 info
.tag
= &infoTag
;
1898 info
.format
= &infoFmt
;
1900 err
= SecKeychainItemCopyAttributesAndData(item
, &info
, NULL
, &authAttrList
, &dataLen
, &data
);
1901 if (err
) { LogMsg("SecKeychainItemCopyAttributesAndData returned error %d", err
); return; }
1903 // copy account name
1904 if (!authAttrList
->count
|| authAttrList
->attr
->tag
!= kSecAccountItemAttr
)
1905 { LogMsg("Received bad authAttrList"); return; }
1907 if (authAttrList
->attr
->length
+ strlen(LH_SUFFIX
) > MAX_ESCAPED_DOMAIN_NAME
)
1908 { LogMsg("Account name too long (%d bytes)", authAttrList
->attr
->length
); return; }
1909 memcpy(accountName
, authAttrList
->attr
->data
, authAttrList
->attr
->length
);
1910 accountName
[authAttrList
->attr
->length
] = '\0';
1913 if (!AppendLiteralLabelString(&zone
, accountName
) ||
1914 !AppendDNSNameString(&zone
, LH_SUFFIX
))
1915 { LogMsg("InitAuthInfo - bad account name"); return; }
1917 mDNS_UpdateDomainRequiresAuthentication(m
, &zone
, &zone
, data
, dataLen
, mDNStrue
);
1918 if(m
->uDNS_info
.NameRegDomain
) { debugf("Overwriting config file options with KeyChain values"); }
1920 if (!ConvertDomainNameToCString(&zone
, m
->uDNS_info
.NameRegDomain
) ||
1921 !ConvertDomainNameToCString(&zone
, m
->uDNS_info
.ServiceRegDomain
))
1922 { LogMsg("Couldn't set keychain username in uDNS global info"); }
1924 mDNS_GenerateGlobalFQDN(m
);
1925 // normally we'd query the zone for _register/_browse domains, but to reduce server load we manually generate the records
1927 haveSecInfo
= mDNStrue
;
1928 //!!!KRS need to do better bookkeeping once we support multiple users
1929 rrReg
= mallocL("AuthRecord", sizeof(AuthRecord
));
1930 rrBrowse
= mallocL("AuthRecord", sizeof(AuthRecord
));
1931 if (!rrReg
|| !rrBrowse
) { LogMsg("ERROR: Malloc"); return; }
1934 mDNS_SetupResourceRecord(rrBrowse
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, 7200, kDNSRecordTypeShared
, mDNSNULL
, mDNSNULL
);
1935 MakeDomainNameFromDNSNameString(&rrBrowse
->resrec
.name
, "_browse._dns-sd._udp.local.");
1936 strcpy(rrBrowse
->resrec
.rdata
->u
.name
.c
, zone
.c
);
1939 mDNS_SetupResourceRecord(rrReg
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, 7200, kDNSRecordTypeShared
, mDNSNULL
, mDNSNULL
);
1940 MakeDomainNameFromDNSNameString(&rrReg
->resrec
.name
, "_register._dns-sd._udp.local.");
1941 strcpy(rrReg
->resrec
.rdata
->u
.name
.c
, zone
.c
);
1943 regErr
= mDNS_Register(m
, rrReg
);
1944 if (regErr
) LogMsg("Registration of local-only reg domain %s failed", zone
.c
);
1946 regErr
= mDNS_Register(m
, rrBrowse
);
1947 if (regErr
) LogMsg("Registration of local-only browse domain %s failed", zone
.c
);
1948 SecKeychainItemFreeContent(authAttrList
, data
);
1951 mDNSlocal
void InitAuthInfo(mDNS
*m
);
1953 mDNSlocal OSStatus
KeychainCallback(SecKeychainEvent event
, SecKeychainCallbackInfo
*info
, void *context
)
1959 debugf("SecKeychainAddCallback received event %d", event
);
1960 InitAuthInfo((mDNS
*)context
); // keychain events happen rarely - just rebuild the list
1964 mDNSexport
void InitAuthInfo(mDNS
*m
)
1968 SecKeychainSearchRef searchRef
= NULL
;
1969 SecKeychainRef sysKeychain
= NULL
;
1970 SecKeychainAttribute searchAttrs
[] = { { kSecDescriptionItemAttr
, strlen(LH_KEYCHAIN_DESC
), LH_KEYCHAIN_DESC
},
1971 { kSecServiceItemAttr
, strlen(LH_KEYCHAIN_SERVICE
), LH_KEYCHAIN_SERVICE
} };
1972 SecKeychainAttributeList searchList
= { sizeof(searchAttrs
) / sizeof(*searchAttrs
), searchAttrs
};
1973 SecKeychainItemRef item
;
1975 // clear any previous entries
1976 mDNS_ClearAuthenticationList(m
);
1978 err
= SecKeychainOpen(SYS_KEYCHAIN_PATH
, &sysKeychain
);
1979 if (err
) { LogMsg("ERROR: InitAuthInfo - couldn't open system keychain - %d", err
); goto release_refs
; }
1980 err
= SecKeychainSetDomainDefault(kSecPreferencesDomainSystem
, sysKeychain
);
1981 if (err
) { LogMsg("ERROR: InitAuthInfo - couldn't set domain default for system keychain - %d", err
); goto release_refs
; }
1983 err
= SecKeychainSearchCreateFromAttributes(sysKeychain
, kSecGenericPasswordItemClass
, &searchList
, &searchRef
);
1984 if (err
) { LogMsg("ERROR: InitAuthInfo - SecKeychainSearchCreateFromAttributes %d", err
); goto release_refs
; }
1986 while (!SecKeychainSearchCopyNext(searchRef
, &item
))
1988 GetAuthInfoFromKeychainItem(m
, item
);
1991 err
= SecKeychainAddCallback(KeychainCallback
, kSecAddEventMask
| kSecDeleteEventMask
| kSecUpdateEventMask
| kSecPasswordChangedEventMask
, m
);
1992 if (err
&& err
!= errSecDuplicateCallback
) { LogMsg("SecKeychainAddCallback returned error %d", err
); }
1996 if (searchRef
) CFRelease(searchRef
);
1997 if (sysKeychain
) CFRelease(sysKeychain
);
2000 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
2001 CF_EXPORT
const CFStringRef _kCFSystemVersionProductNameKey
;
2002 CF_EXPORT
const CFStringRef _kCFSystemVersionProductVersionKey
;
2003 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
2005 mDNSexport mDNSBool
mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring
)
2007 int major
= 0, minor
= 0;
2008 char letter
= 0, prodname
[256]="Mac OS X", prodvers
[256]="", buildver
[256]="?";
2009 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
2012 CFStringRef cfprodname
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductNameKey
);
2013 CFStringRef cfprodvers
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductVersionKey
);
2014 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
2015 if (cfprodname
) CFStringGetCString(cfprodname
, prodname
, sizeof(prodname
), kCFStringEncodingUTF8
);
2016 if (cfprodvers
) CFStringGetCString(cfprodvers
, prodvers
, sizeof(prodvers
), kCFStringEncodingUTF8
);
2017 if (cfbuildver
) CFStringGetCString(cfbuildver
, buildver
, sizeof(buildver
), kCFStringEncodingUTF8
);
2018 sscanf(buildver
, "%d%c%d", &major
, &letter
, &minor
);
2021 if (HINFO_SWstring
) mDNS_snprintf(HINFO_SWstring
, 256, "%s %s (%s), %s", prodname
, prodvers
, buildver
, mDNSResponderVersionString
);
2025 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
2026 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
2027 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
2028 mDNSlocal mDNSBool
mDNSPlatformInit_ReceiveUnicast(void)
2031 int s
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
2032 struct sockaddr_in s5353
;
2033 s5353
.sin_family
= AF_INET
;
2034 s5353
.sin_port
= MulticastDNSPort
.NotAnInteger
;
2035 s5353
.sin_addr
.s_addr
= 0;
2036 err
= bind(s
, (struct sockaddr
*)&s5353
, sizeof(s5353
));
2038 if (err
) debugf("No unicast UDP responses");
2039 else debugf("Unicast UDP responses okay");
2044 //!!!KRS this should be less order-dependent as we support more configuration options
2045 mDNSlocal mDNSBool
GetConfigOption(char *dst
, const char *option
, FILE *f
)
2050 if (!fgets(buf
, 1024, f
)) { LogMsg("Option %s not set", option
); return mDNSfalse
; }
2051 len
= strlen(option
);
2052 if (!strncmp(buf
, option
, len
))
2054 strcpy(dst
, buf
+ len
+ 1);
2056 if ( len
&& dst
[len
-1] == '\n') dst
[len
-1] = '\0'; // chop newline
2059 LogMsg("Malformatted config file - %s not set", option
);
2065 mDNSlocal
void ReadRegDomainFromConfig(mDNS
*const m
)
2068 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;;
2069 char key
[MAX_ESCAPED_DOMAIN_NAME
];
2070 domainname key_d
, name_d
, service_d
;
2075 // read registration domain (for dynamic updates) from config file
2076 // !!!KRS these must go away once we can learn the reg domain from the network or prefs
2077 if (m
->uDNS_info
.NameRegDomain
[0] || m
->uDNS_info
.ServiceRegDomain
[0])
2078 { debugf("Options from config already set via keychain. Ignoring config file."); return; }
2080 f
= fopen(CONFIG_FILE
, "r");
2083 if (errno
!= ENOENT
) LogMsg("ERROR: Config file exists, but cannot be opened.");
2087 if (!GetConfigOption(u
->NameRegDomain
, "name-reg", f
)) goto end
;
2088 if (!GetConfigOption(u
->ServiceRegDomain
, "service-reg", f
)) goto end
;
2089 if (!GetConfigOption(key
, "key-name", f
)) goto end
;
2090 if (!GetConfigOption(secret
, "secret-64", f
)) { LogMsg("ERROR: config file contains key without secret"); goto end
; }
2092 // we don't actually need this in domain-name format - just convert it to error check
2093 if (!MakeDomainNameFromDNSNameString(&service_d
, u
->ServiceRegDomain
))
2094 { LogMsg("ERROR: config file contains bad service reg domain %s", u
->ServiceRegDomain
); u
->ServiceRegDomain
[0] = '\0'; }
2096 if (!MakeDomainNameFromDNSNameString(&name_d
, u
->NameRegDomain
))
2097 { LogMsg("ERROR: config file contains bad name reg domain %s", u
->NameRegDomain
); u
->NameRegDomain
[0] = '\0'; }
2099 if (!MakeDomainNameFromDNSNameString(&key_d
, key
))
2100 { LogMsg("ERROR: config file contains bad key %s", key
); key
[0] = '\0'; }
2104 slen
= strlen(secret
);
2105 if (u
->ServiceRegDomain
[0])
2107 err
= mDNS_UpdateDomainRequiresAuthentication(m
, &service_d
, &key_d
, secret
, slen
, mDNStrue
);
2108 if (err
) LogMsg("ERROR: mDNS_UpdateDomainRequiresAuthentication returned %d for domain ", err
, u
->ServiceRegDomain
);
2110 if (u
->NameRegDomain
[0])
2112 err
= mDNS_UpdateDomainRequiresAuthentication(m
, &name_d
, &key_d
, secret
, slen
, mDNStrue
);
2113 if (err
) LogMsg("ERROR: mDNS_UpdateDomainRequiresAuthentication returned %d for domain ", err
, u
->NameRegDomain
);
2121 mDNSexport DNameListElem
*mDNSPlatformGetSearchDomainList(void)
2123 return mDNS_CopyDNameList(DefBrowseList
);
2126 mDNSexport DNameListElem
*mDNSPlatformGetRegDomainList(void)
2128 static DNameListElem tmp
;
2129 static mDNSBool init
= mDNSfalse
;
2133 MakeDomainNameFromDNSNameString(&tmp
.name
, "local.");
2137 return mDNS_CopyDNameList(&tmp
);
2141 mDNSlocal
void FoundDefBrowseDomain(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
2143 DNameListElem
*ptr
, *prev
, *new;
2145 (void)question
; // unused
2149 new = mallocL("FoundDefBrowseDomain", sizeof(DNameListElem
));
2150 if (!new) { LogMsg("ERROR: malloc"); return; }
2151 strcpy(new->name
.c
, answer
->rdata
->u
.name
.c
);
2152 new->next
= DefBrowseList
;
2153 DefBrowseList
= new;
2158 ptr
= DefBrowseList
;
2162 if (SameDomainName(&ptr
->name
, &answer
->rdata
->u
.name
))
2164 if (prev
) prev
->next
= ptr
->next
;
2165 else DefBrowseList
= ptr
->next
;
2166 freeL("FoundDefBrowseDomain", ptr
);
2172 LogMsg("FoundDefBrowseDomain: Got remove event for domain %s not in list", answer
->rdata
->u
.name
.c
);
2176 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
2177 // 1) query for _browse._dns-sd._udp.local on LocalOnly interface
2178 // (.local manually generated via explicit callback)
2179 // 2) for each search domain (from prefs pane), query for _browse._dns-sd._udp.<searchdomain>.
2180 // 3) for each result from (2), register LocalOnly PTR record_browse._dns-sd._udp.local. -> <result>
2181 // 4) result above should generate a callback from question in (1). result added to global list
2182 // 5) global list delivered to client via GetSearchDomainList()
2183 // 6) client calls to enumerate domains now go over LocalOnly interface
2184 // (!!!KRS may add outgoing interface in addition)
2186 mDNSlocal mStatus
InitDNSConfig(mDNS
*const m
)
2190 DNSConfigInitialized
= mDNStrue
;
2192 // start query for domains to be used in default (empty string domain) browses
2193 err
= mDNS_GetDomains(m
, &DefBrowseDomainQ
, mDNS_DomainTypeBrowse
, NULL
, mDNSInterface_LocalOnly
, FoundDefBrowseDomain
, NULL
);
2195 // provide .local automatically
2196 mDNS_SetupResourceRecord(&local
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, 7200, kDNSRecordTypeShared
, mDNSNULL
, mDNSNULL
);
2197 MakeDomainNameFromDNSNameString(&local
.resrec
.name
, "_browse._dns-sd._udp.local.");
2198 MakeDomainNameFromDNSNameString(&local
.resrec
.rdata
->u
.name
, "local.");
2199 // other fields ignored
2200 FoundDefBrowseDomain(m
, &DefBrowseDomainQ
, &local
.resrec
, 1);
2202 return mStatus_NoError
;
2205 mDNSlocal mStatus
mDNSPlatformInit_setup(mDNS
*const m
)
2209 m
->hostlabel
.c
[0] = 0;
2211 char *HINFO_HWstring
= "Macintosh";
2212 char HINFO_HWstring_buffer
[256];
2213 int get_model
[2] = { CTL_HW
, HW_MODEL
};
2214 size_t len_model
= sizeof(HINFO_HWstring_buffer
);
2215 if (sysctl(get_model
, 2, HINFO_HWstring_buffer
, &len_model
, NULL
, 0) == 0)
2216 HINFO_HWstring
= HINFO_HWstring_buffer
;
2218 char HINFO_SWstring
[256] = "";
2219 if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring
) < 7) m
->KnownBugs
|= mDNS_KnownBug_PhantomInterfaces
;
2220 if (mDNSPlatformInit_ReceiveUnicast()) m
->CanReceiveUnicast
= mDNStrue
;
2222 mDNSu32 hlen
= mDNSPlatformStrLen(HINFO_HWstring
);
2223 mDNSu32 slen
= mDNSPlatformStrLen(HINFO_SWstring
);
2224 if (hlen
+ slen
< 254)
2226 m
->HIHardware
.c
[0] = hlen
;
2227 m
->HISoftware
.c
[0] = slen
;
2228 mDNSPlatformMemCopy(HINFO_HWstring
, &m
->HIHardware
.c
[1], hlen
);
2229 mDNSPlatformMemCopy(HINFO_SWstring
, &m
->HISoftware
.c
[1], slen
);
2232 m
->p
->unicastsockets
.m
= m
;
2233 m
->p
->unicastsockets
.info
= NULL
;
2234 m
->p
->unicastsockets
.sktv4
= m
->p
->unicastsockets
.sktv6
= -1;
2235 m
->p
->unicastsockets
.cfsv4
= m
->p
->unicastsockets
.cfsv6
= NULL
;
2236 m
->p
->unicastsockets
.rlsv4
= m
->p
->unicastsockets
.rlsv6
= NULL
;
2238 err
= SetupSocket(&m
->p
->unicastsockets
, zeroIPPort
, &zeroAddr
, AF_INET
);
2239 err
= SetupSocket(&m
->p
->unicastsockets
, zeroIPPort
, &zeroAddr
, AF_INET6
);
2241 m
->p
->InterfaceList
= mDNSNULL
;
2242 m
->p
->userhostlabel
.c
[0] = 0;
2243 UpdateInterfaceList(m
);
2244 SetupActiveInterfaces(m
);
2246 err
= WatchForNetworkChanges(m
);
2247 if (err
) return(err
);
2249 err
= WatchForPowerChanges(m
);
2250 if (err
) return err
;
2252 err
= WatchForDNSChanges(m
);
2256 m
->uDNS_info
.ServiceRegDomain
[0] = '\0';
2257 m
->uDNS_info
.NameRegDomain
[0] = '\0';
2259 ReadRegDomainFromConfig(m
);
2264 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
2266 mStatus result
= mDNSPlatformInit_setup(m
);
2268 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
2269 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
2270 if (result
== mStatus_NoError
) mDNSCoreInitComplete(m
, mStatus_NoError
);
2274 mDNSexport
void mDNSPlatformClose(mDNS
*const m
)
2276 if (m
->p
->PowerConnection
)
2278 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->PowerRLS
, kCFRunLoopDefaultMode
);
2279 CFRunLoopSourceInvalidate(m
->p
->PowerRLS
);
2280 CFRelease(m
->p
->PowerRLS
);
2281 IODeregisterForSystemPower(&m
->p
->PowerNotifier
);
2282 m
->p
->PowerConnection
= NULL
;
2283 m
->p
->PowerNotifier
= NULL
;
2284 m
->p
->PowerRLS
= NULL
;
2289 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
2290 CFRunLoopSourceInvalidate(m
->p
->StoreRLS
);
2291 CFRelease(m
->p
->StoreRLS
);
2292 CFRelease(m
->p
->Store
);
2294 m
->p
->StoreRLS
= NULL
;
2297 MarkAllInterfacesInactive(m
);
2298 ClearInactiveInterfaces(m
);
2299 CloseSocketSet(&m
->p
->unicastsockets
);
2302 mDNSexport mDNSs32 mDNSPlatformOneSecond
= 1000;
2304 mDNSexport mStatus
mDNSPlatformTimeInit(mDNSs32
*timenow
)
2306 // Notes: Typical values for mach_timebase_info:
2307 // tbi.numer = 1000 million
2308 // tbi.denom = 33 million
2309 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
2310 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
2311 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
2312 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
2313 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
2315 // Arithmetic notes:
2316 // tbi.denom is at least 1, and not more than 2^32-1.
2317 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
2318 // tbi.denom is at least 1, and not more than 2^32-1.
2319 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
2320 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
2321 // which is unlikely on any current or future Macintosh.
2322 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
2323 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
2324 struct mach_timebase_info tbi
;
2325 kern_return_t result
= mach_timebase_info(&tbi
);
2326 if (result
!= KERN_SUCCESS
) return(result
);
2327 clockdivisor
= ((uint64_t)tbi
.denom
* 1000000) / tbi
.numer
;
2328 *timenow
= mDNSPlatformTimeNow();
2329 return(mStatus_NoError
);
2332 mDNSexport mDNSs32
mDNSPlatformTimeNow(void)
2334 if (clockdivisor
== 0) { LogMsg("mDNSPlatformTimeNow called before mDNSPlatformTimeInit"); return(0); }
2335 return((mDNSs32
)(mach_absolute_time() / clockdivisor
));
2338 mDNSexport mDNSs32
mDNSPlatformUTC(void)
2343 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
2344 mDNSexport
void mDNSPlatformLock (const mDNS
*const m
) { (void)m
; }
2345 mDNSexport
void mDNSPlatformUnlock (const mDNS
*const m
) { (void)m
; }
2346 mDNSexport
void mDNSPlatformStrCopy(const void *src
, void *dst
) { strcpy((char *)dst
, (char *)src
); }
2347 mDNSexport mDNSu32
mDNSPlatformStrLen (const void *src
) { return(strlen((char*)src
)); }
2348 mDNSexport
void mDNSPlatformMemCopy(const void *src
, void *dst
, mDNSu32 len
) { memcpy(dst
, src
, len
); }
2349 mDNSexport mDNSBool
mDNSPlatformMemSame(const void *src
, const void *dst
, mDNSu32 len
) { return(memcmp(dst
, src
, len
) == 0); }
2350 mDNSexport
void mDNSPlatformMemZero( void *dst
, mDNSu32 len
) { bzero(dst
, len
); }
2351 mDNSexport
void * mDNSPlatformMemAllocate(mDNSu32 len
) { return(mallocL("mDNSPlatformMemAllocate", len
)); }
2352 mDNSexport
void mDNSPlatformMemFree (void *mem
) { freeL("mDNSPlatformMemFree", mem
); }