1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
24 Change History (most recent first):
26 $Log: mDNSMacOSX.c,v $
27 Revision 1.258 2004/12/14 00:18:05 cheshire
28 Don't log dns_configuration_copy() failures in the first three minutes after boot
30 Revision 1.257 2004/12/10 19:45:46 cheshire
31 <rdar://problem/3915074> Reduce egregious stack space usage
32 Reduced myCFSocketCallBack() stack frame from 9K to 512 bytes
34 Revision 1.256 2004/12/10 04:35:43 cheshire
35 <rdar://problem/3907233> Show "Note: Compiled without Apple-specific split DNS support" only once
37 Revision 1.255 2004/12/10 04:12:54 ksekar
38 <rdar://problem/3890764> Need new DefaultBrowseDomain key
40 Revision 1.254 2004/12/10 01:55:31 ksekar
41 <rdar://problem/3899067> Keychain lookups should be in lower case.
43 Revision 1.253 2004/12/09 03:15:41 ksekar
44 <rdar://problem/3806610> use _legacy instead of _default to find "empty string" browse domains
46 Revision 1.252 2004/12/07 01:32:42 cheshire
47 Don't log dns_configuration_copy() failure when running on 10.3
49 Revision 1.251 2004/12/06 22:30:31 cheshire
50 Added debugging log message
52 Revision 1.250 2004/12/06 06:59:08 ksekar
53 RegisterSplitDNS should return Unsupported error when compiled on Panther
55 Revision 1.249 2004/12/04 00:29:46 cheshire
56 Add "#ifdef MAC_OS_X_VERSION_10_4" around split-DNS code that can't be compiled on 10.3 systems
57 (When compiled on 10.3, code will not include split-DNS support.)
59 Revision 1.248 2004/12/01 20:57:20 ksekar
60 <rdar://problem/3873921> Wide Area Rendezvous must be split-DNS aware
62 Revision 1.247 2004/12/01 03:26:58 cheshire
63 Remove unused variables
65 Revision 1.246 2004/12/01 01:51:34 cheshire
66 Move ReadDDNSSettingsFromConfFile() from mDNSMacOSX.c to PlatformCommon.c
68 Revision 1.245 2004/11/30 03:24:04 cheshire
69 <rdar://problem/3854544> Defer processing network configuration changes until configuration has stabilized
71 Revision 1.244 2004/11/30 02:59:35 cheshire
72 For debugging diagnostics, added identifying strings in SCDynamicStoreCreate() calls
74 Revision 1.243 2004/11/29 19:17:29 ksekar
75 <rdar://problem/3878195> Unnecessary GetUserSpecifiedDDNSConfig log messages
77 Revision 1.242 2004/11/29 18:37:38 ksekar
78 <rdar://problem/3889341> Buffer overflow in GetConfigOption
80 Revision 1.241 2004/11/25 01:37:04 ksekar
81 <rdar://problem/3894854> Config file and SCPreferences don't play well together
83 Revision 1.240 2004/11/25 01:29:42 ksekar
84 Remove unnecessary log messages
86 Revision 1.239 2004/11/25 01:27:19 ksekar
87 <rdar://problem/3885859> Don't try to advertise link-local IP addresses via dynamic update
89 Revision 1.238 2004/11/24 22:00:59 cheshire
90 Move definition of mDNSAddressIsAllDNSLinkGroup() from mDNSMacOSX.c to mDNSEmbeddedAPI.h
92 Revision 1.237 2004/11/24 21:54:44 cheshire
93 <rdar://problem/3894475> mDNSCore not receiving unicast responses properly
95 Revision 1.236 2004/11/23 03:39:46 cheshire
96 Let interface name/index mapping capability live directly in JNISupport.c,
97 instead of having to call through to the daemon via IPC to get this information.
99 Revision 1.235 2004/11/17 01:45:35 cheshire
100 <rdar://problem/3847435> Rendezvous buddy list frequently becomes empty if you let the machine sleep
101 Refresh our interface list on receiving kIOMessageSystemHasPoweredOn,
102 in case we get no System Configuration Framework "network changed" event.
104 Revision 1.234 2004/11/17 00:32:56 ksekar
105 <rdar://problem/3880773> mDNSResponder will not discover zones contained both in Search Domains and DHCP Domain option
107 Revision 1.233 2004/11/12 03:16:45 rpantos
108 rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
110 Revision 1.232 2004/11/10 20:40:54 ksekar
111 <rdar://problem/3868216> LLQ mobility fragile on non-primary interface
113 Revision 1.231 2004/11/06 00:59:33 ksekar
114 Don't log ENETDOWN errors for unicast destinations (pollutes log on
117 Revision 1.230 2004/11/05 01:04:10 ksekar
118 <rdar://problem/3774577> LegacyNATDestroy() called too enthusiastically
120 Revision 1.229 2004/11/03 03:45:16 cheshire
121 <rdar://problem/3863627> mDNSResponder does not inform user of Computer Name collisions
123 Revision 1.228 2004/11/02 23:47:32 cheshire
124 <rdar://problem/3863214> Default hostname and Computer Name should be unique
126 Revision 1.227 2004/11/02 04:23:03 cheshire
127 Change to more informative name "GetUserSpecifiedLocalHostName()"
129 Revision 1.226 2004/11/01 20:36:19 ksekar
130 <rdar://problem/3802395> mDNSResponder should not receive Keychain Notifications
132 Revision 1.225 2004/10/28 19:03:04 cheshire
133 Remove \n from LogMsg() calls
135 Revision 1.224 2004/10/28 17:47:34 cheshire
136 Oops. Forgot the %d in the log message.
138 Revision 1.223 2004/10/28 17:24:28 cheshire
139 Updated "bad ifa_netmask" log message to give more information
141 Revision 1.222 2004/10/28 03:36:34 cheshire
142 <rdar://problem/3856535> Share the same port for both multicast and unicast receiving
144 Revision 1.221 2004/10/28 03:24:41 cheshire
145 Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
147 Revision 1.220 2004/10/28 00:53:57 cheshire
148 Export mDNSMacOSXNetworkChanged() so it's callable from outside this mDNSMacOSX.c;
149 Add LogOperation() call to record when we get network change events
151 Revision 1.219 2004/10/27 20:42:20 cheshire
152 Clean up debugging messages
154 Revision 1.218 2004/10/27 02:03:59 cheshire
155 Update debugging messages
157 Revision 1.217 2004/10/26 20:48:21 cheshire
158 Improve logging messages
160 Revision 1.216 2004/10/26 01:02:37 cheshire
163 Revision 1.215 2004/10/25 20:09:00 ksekar
164 Cleaned up config file parsing.
166 Revision 1.214 2004/10/25 19:30:53 ksekar
167 <rdar://problem/3827956> Simplify dynamic host name structures
169 Revision 1.213 2004/10/23 01:16:01 cheshire
170 <rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
172 Revision 1.212 2004/10/22 20:52:08 ksekar
173 <rdar://problem/3799260> Create NAT port mappings for Long Lived Queries
175 Revision 1.211 2004/10/22 01:07:11 cheshire
176 <rdar://problem/3375328> select() says data is waiting; recvfrom() says there is no data
177 Log error message if socket() ever returns file descriptors 0, 1 or 2 (stdin/stdout/stderr).
178 These are all supposed to be remapped to /dev/null
180 Revision 1.210 2004/10/20 02:19:54 cheshire
181 Eliminate "SetupAddr invalid sa_family" warning from RegisterSearchDomains()
183 Revision 1.209 2004/10/16 00:17:00 cheshire
184 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
186 Revision 1.208 2004/10/15 23:00:18 ksekar
187 <rdar://problem/3799242> Need to update LLQs on location changes
189 Revision 1.207 2004/10/13 22:45:23 cheshire
190 <rdar://problem/3438392> Ten-second delay before kIOMessageSystemHasPoweredOn message
192 Revision 1.206 2004/10/13 22:11:46 cheshire
193 Update debugging messages
195 Revision 1.205 2004/10/12 21:10:11 cheshire
196 <rdar://problem/3438376> mach_absolute_time() not monotonically increasing
197 Do a NotifyOfElusiveBug() if we see mach_absolute_time() go backwards
199 Revision 1.204 2004/10/12 03:20:52 ksekar
200 <rdar://problem/3835614> Incorrect LogMsg produces garbage on errors
202 Revision 1.203 2004/10/08 04:29:25 ksekar
203 <rdar://problem/3831842> Allow default search domains to be set via hint from DHCP
205 Revision 1.202 2004/10/04 05:56:04 cheshire
206 <rdar://problem/3824730> mDNSResponder doesn't respond to certain AirPort changes
208 Revision 1.201 2004/09/30 00:24:59 ksekar
209 <rdar://problem/3695802> Dynamically update default registration domains on config change
211 Revision 1.200 2004/09/26 23:20:35 ksekar
212 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
214 Revision 1.199 2004/09/24 23:54:55 cheshire
215 <rdar://problem/3787102> Don't use kCFSocketCloseOnInvalidate
217 Revision 1.198 2004/09/24 23:47:49 cheshire
218 Correct comment and error message
220 Revision 1.197 2004/09/24 23:39:27 cheshire
221 <rdar://problem/3733705> Only IPv6 loopback address advertised on laptop w/no networking
223 Revision 1.196 2004/09/24 20:53:04 cheshire
224 Revise error message to say "Setsockopt SO_REUSEPORT failed" instead of "Flaw in Kernel"
226 Revision 1.195 2004/09/24 19:21:45 cheshire
227 <rdar://problem/3671626> Report "Address already in use" errors
229 Revision 1.194 2004/09/24 19:16:54 cheshire
230 Remove "mDNS *const m" parameter from NotifyOfElusiveBug();
231 Refine error message to say "Flaw in Kernel (select/recvfrom mismatch)"
233 Revision 1.193 2004/09/22 00:41:59 cheshire
234 Move tcp connection status codes into the legal range allocated for mDNS use
236 Revision 1.192 2004/09/21 21:02:55 cheshire
237 Set up ifname before calling mDNS_RegisterInterface()
239 Revision 1.191 2004/09/21 19:19:36 cheshire
240 <rdar://problem/3760923> Combine WatchForDynDNSChanges() into WatchForNetworkChanges()
242 Revision 1.190 2004/09/21 19:04:45 cheshire
243 Strip trailing white space from the ends of lines
245 Revision 1.189 2004/09/21 00:13:28 cheshire
246 Fix build failure (io_connect_t and io_object_t are integers, not pointers)
248 Revision 1.188 2004/09/20 23:52:02 cheshire
249 CFSocket{Puma}.c renamed to mDNSMacOSX{Puma}.c
251 Revision 1.187 2004/09/18 01:37:01 cheshire
254 Revision 1.186 2004/09/18 01:11:57 ksekar
255 <rdar://problem/3806734> Add a user's default domain to empty-string browse list
257 Revision 1.185 2004/09/17 01:08:52 cheshire
258 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
259 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
260 declared in that file are ONLY appropriate to single-address-space embedded applications.
261 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
263 Revision 1.184 2004/09/17 00:19:10 cheshire
264 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
266 Revision 1.183 2004/09/17 00:15:56 cheshire
267 Rename mDNSPlatformInit_ReceiveUnicast to mDNSPlatformInit_CanReceiveUnicast
269 Revision 1.182 2004/09/16 21:36:36 cheshire
270 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
271 Changes to add necessary locking calls around unicast DNS operations
273 Revision 1.181 2004/09/16 02:03:42 cheshire
274 <rdar://problem/3802944> Change address to notify user of kernel flaw
276 Revision 1.180 2004/09/16 01:58:22 cheshire
277 Fix compiler warnings
279 Revision 1.179 2004/09/16 00:24:49 cheshire
280 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
282 Revision 1.178 2004/09/15 21:51:34 cheshire
283 <rdar://problem/3387020> mDNSResponder should notify user of kernel flaw
284 Calling CFUserNotificationDisplayNotice too early in the boot process seems to kill
285 the machine, so make sure we don't do this until at least three minutes after boot.
287 Revision 1.177 2004/09/15 01:16:29 cheshire
288 <rdar://problem/3387020> mDNSResponder should notify user of kernel flaw
290 Revision 1.176 2004/09/14 23:42:36 cheshire
291 <rdar://problem/3801296> Need to seed random number generator from platform-layer data
293 Revision 1.175 2004/09/14 21:35:46 cheshire
294 Minor code tidying, and added comments about CFRetainCounts
296 Revision 1.174 2004/09/14 19:14:57 ksekar
297 <rdar://problem/3192531> DynDNS: Discovery of DynDNS Zones via Reverse-Map PTR
299 Revision 1.173 2004/08/25 23:35:22 ksekar
300 <rdar://problem/3770615>: Error converting shared secret from base-64 to binary
302 Revision 1.172 2004/08/25 02:01:45 cheshire
303 <rdar://problem/3774777> Need to be able to get status of Dynamic DNS Host Name Update
305 Revision 1.171 2004/08/25 01:04:42 cheshire
306 Don't need to CFRelease name and array
308 Revision 1.170 2004/08/25 00:37:28 ksekar
309 <rdar://problem/3774635>: Cleanup DynDNS hostname registration code
311 Revision 1.169 2004/08/18 17:35:41 ksekar
312 <rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
314 Revision 1.168 2004/08/17 03:16:24 ksekar
315 Fixed checkin 1.166 - enumeration type changed for wrong invocation of mDNS_GetDomains
317 Revision 1.167 2004/08/17 00:52:43 ksekar
318 Fix config file parse error, make semantics match SCPreferences
321 Revision 1.166 2004/08/16 19:55:07 ksekar
322 Change enumeration type to BrowseDefault to construct empty-string
323 browse list as result of checking 1.161.
325 Revision 1.165 2004/08/16 19:52:40 ksekar
326 Pass computer name + zone for FQDN after keychain notification,
327 setting global default service registration domain to the zone.
329 Revision 1.164 2004/08/16 16:52:37 ksekar
330 Pass in zone read from keychain to mDNS_SetFQDNs.
332 Revision 1.163 2004/08/14 03:22:42 cheshire
333 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
334 Add GetUserSpecifiedDDNSName() routine
335 Convert ServiceRegDomain to domainname instead of C string
336 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
338 Revision 1.162 2004/08/12 22:34:00 cheshire
339 All strings should be read as kCFStringEncodingUTF8, not kCFStringEncodingASCII
341 Revision 1.161 2004/08/11 00:17:46 ksekar
342 <rdar://problem/3757662>: 8A227: Need Lighthouse configred machines to
343 set default bit for their domains
345 Revision 1.160 2004/07/29 19:27:16 ksekar
346 NATPMP Support - minor fixes and cleanup
348 Revision 1.159 2004/07/26 22:49:31 ksekar
349 <rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
351 Revision 1.158 2004/07/13 21:24:24 rpantos
352 Fix for <rdar://problem/3701120>.
354 Revision 1.157 2004/06/08 18:54:48 ksekar
355 <rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
357 Revision 1.156 2004/06/05 00:04:26 cheshire
358 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
360 Revision 1.155 2004/06/04 08:58:30 ksekar
361 <rdar://problem/3668624>: Keychain integration for secure dynamic update
363 Revision 1.154 2004/05/31 22:22:28 ksekar
364 <rdar://problem/3668639>: wide-area domains should be returned in
365 reg. domain enumeration
367 Revision 1.153 2004/05/26 17:06:33 cheshire
368 <rdar://problem/3668515>: Don't rely on CFSocketInvalidate() to remove RunLoopSource
370 Revision 1.152 2004/05/18 23:51:26 cheshire
371 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
373 Revision 1.151 2004/05/17 21:46:34 cheshire
374 <rdar://problem/3616426>: When interface is turned off, browse "remove" events are delivered with interface index zero
375 Take care to correctly update InterfaceIDs when a dormant interface comes back to life
377 Revision 1.150 2004/05/13 04:54:20 ksekar
378 Unified list copy/free code. Added symetric list for
380 Revision 1.149 2004/05/13 03:55:14 ksekar
381 Fixed list traversal bug in FoundDefSearchDomain.
383 Revision 1.148 2004/05/12 22:03:08 ksekar
384 Made GetSearchDomainList a true platform-layer call (declaration moved
385 from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
386 only on non-OSX platforms. Changed call to return a copy of the list
387 to avoid shared memory issues. Added a routine to free the list.
389 Revision 1.147 2004/05/12 02:03:25 ksekar
390 Non-local domains will only be browsed by default, and show up in
391 _browse domain enumeration, if they contain an _browse._dns-sd ptr record.
393 Revision 1.146 2004/04/27 02:49:15 cheshire
394 <rdar://problem/3634655>: mDNSResponder leaks sockets on bind() error
396 Revision 1.145 2004/04/21 03:08:03 cheshire
397 Rename 'alias' to more descriptive name 'primary'
399 Revision 1.144 2004/04/21 03:04:35 cheshire
400 Minor cleanup for clarity
402 Revision 1.143 2004/04/21 03:03:30 cheshire
403 Preparation work: AddInterfaceToList() should return pointer to structure it creates
405 Revision 1.142 2004/04/21 02:49:11 cheshire
406 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
408 Revision 1.141 2004/04/21 02:20:47 cheshire
409 Rename interface field 'CurrentlyActive' to more descriptive 'Exists'
411 Revision 1.140 2004/04/14 23:09:29 ksekar
412 Support for TSIG signed dynamic updates.
414 Revision 1.139 2004/04/09 17:40:26 cheshire
415 Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
417 Revision 1.138 2004/04/09 16:37:16 cheshire
418 Suggestion from Bob Bradley:
419 Move NumCacheRecordsForInterfaceID() to DNSCommon.c so it's available to all platform layers
421 Revision 1.137 2004/04/08 00:59:55 cheshire
422 <rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
423 Unify use of the InterfaceID field, and make code that walks the list respect the 'Exists' flag
425 Revision 1.136 2004/04/07 01:08:57 cheshire
426 <rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
428 Revision 1.135 2004/03/19 01:01:03 ksekar
429 Fixed config file parsing to chop newline
431 Revision 1.134 2004/03/13 01:57:34 ksekar
432 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
434 Revision 1.133 2004/02/02 22:46:56 cheshire
435 Move "CFRelease(dict);" inside the "if (dict)" check
437 Revision 1.132 2004/01/28 02:30:08 ksekar
438 Added default Search Domains to unicast browsing, controlled via
439 Networking sharing prefs pane. Stopped sending unicast messages on
440 every interface. Fixed unicast resolving via mach-port API.
442 Revision 1.131 2004/01/27 22:57:48 cheshire
443 <rdar://problem/3534352>: Need separate socket for issuing unicast queries
445 Revision 1.130 2004/01/27 22:28:40 cheshire
446 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
447 Additional lingering port 53 code deleted
449 Revision 1.129 2004/01/27 20:15:23 cheshire
450 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
452 Revision 1.128 2004/01/24 23:58:17 cheshire
453 Change to use mDNSVal16() instead of shifting and ORing
455 Revision 1.127 2004/01/24 04:59:16 cheshire
456 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
458 Revision 1.126 2004/01/23 23:23:15 ksekar
459 Added TCP support for truncated unicast messages.
461 Revision 1.125 2004/01/22 03:43:09 cheshire
462 Export constants like mDNSInterface_LocalOnly so that the client layers can use them
464 Revision 1.124 2004/01/21 21:53:19 cheshire
465 <rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port
467 Revision 1.123 2004/01/20 03:18:25 cheshire
468 Removed "LogMsg("Hey There!");" that evidently got checked in my mistake
470 Revision 1.122 2003/12/17 20:43:59 cheshire
471 <rdar://problem/3496728>: Syslog messages saying "sendto failed"
473 Revision 1.121 2003/12/13 03:05:28 ksekar
474 <rdar://problem/3192548>: DynDNS: Unicast query of service records
476 Revision 1.120 2003/12/08 21:00:46 rpantos
477 Changes to support mDNSResponder on Linux.
479 Revision 1.119 2003/12/03 02:35:15 cheshire
480 Also report value of m->timenow when logging sendto() failure
482 Revision 1.118 2003/11/14 20:59:09 cheshire
483 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
484 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
486 Revision 1.117 2003/11/08 22:18:29 cheshire
487 <rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
489 Revision 1.116 2003/09/23 16:39:49 cheshire
490 When LogAllOperations is set, also report registration and deregistration of interfaces
492 Revision 1.115 2003/09/10 00:45:55 cheshire
493 <rdar://problem/3412328> Don't log "sendto failed" errors during the first two minutes of startup
495 Revision 1.114 2003/08/27 02:55:13 cheshire
496 <rdar://problem/3387910>: Bug: Don't report mDNSPlatformSendUDP sendto errno 64 (Host is down)
498 Revision 1.113 2003/08/19 22:20:00 cheshire
499 <rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
500 More minor refinements
502 Revision 1.112 2003/08/19 03:04:43 cheshire
503 <rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
505 Revision 1.111 2003/08/18 22:53:37 cheshire
506 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
508 Revision 1.110 2003/08/16 03:39:00 cheshire
509 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
511 Revision 1.109 2003/08/15 02:19:49 cheshire
512 <rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
513 Also limit number of messages to at most 100
515 Revision 1.108 2003/08/12 22:24:52 cheshire
516 <rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
517 This message indicates a kernel bug, but still we don't want to flood syslog.
518 Do a sleep(1) after writing this log message, to limit the rate.
520 Revision 1.107 2003/08/12 19:56:25 cheshire
523 Revision 1.106 2003/08/12 13:48:32 cheshire
524 Add comment explaining clockdivisor calculation
526 Revision 1.105 2003/08/12 13:44:14 cheshire
527 <rdar://problem/3370229> mDNSResponder *VERY* unhappy if time goes backwards
528 Use mach_absolute_time() (which is guaranteed to always go forwards, resetting only on reboot)
529 instead of gettimeofday() (which can jump back if the user manually changes their time/date)
531 Revision 1.104 2003/08/12 13:12:07 cheshire
532 Textual search/replace: Indicate local functions using "mDNSlocal" instead of "static"
534 Revision 1.103 2003/08/08 18:36:04 cheshire
535 <rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
537 Revision 1.102 2003/08/06 00:14:52 cheshire
538 <rdar://problem/3330324> Need to check IP TTL on responses
539 Also add corresponding checks in the IPv6 code path
541 Revision 1.101 2003/08/05 22:20:16 cheshire
542 <rdar://problem/3330324> Need to check IP TTL on responses
544 Revision 1.100 2003/08/05 21:18:50 cheshire
545 <rdar://problem/3363185> mDNSResponder should ignore 6to4
546 Only use interfaces that are marked as multicast-capable (IFF_MULTICAST)
548 Revision 1.99 2003/08/05 20:13:52 cheshire
549 <rdar://problem/3294080> mDNSResponder using IPv6 interfaces before they are ready
550 Ignore interfaces with the IN6_IFF_NOTREADY flag set
552 Revision 1.98 2003/07/20 03:38:51 ksekar
553 <rdar://problem/3320722>
554 Completed support for Unix-domain socket based API.
556 Revision 1.97 2003/07/19 03:15:16 cheshire
557 Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
558 and add the obvious trivial implementations to each platform support layer
560 Revision 1.96 2003/07/18 00:30:00 cheshire
561 <rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
563 Revision 1.95 2003/07/12 03:15:20 cheshire
564 <rdar://problem/3324848> After SCDynamicStore notification, mDNSResponder updates
565 m->hostlabel even if user hasn't actually actually changed their dot-local hostname
567 Revision 1.94 2003/07/03 00:51:54 cheshire
568 <rdar://problem/3287213> When select() and recvmgs() disagree, get more info from kernel about the socket state
570 Revision 1.93 2003/07/03 00:09:14 cheshire
571 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
572 Additional refinement suggested by Josh: Use info->scope_id instead of if_nametoindex(info->ifa_name);
574 Revision 1.92 2003/07/02 21:19:51 cheshire
575 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
577 Revision 1.91 2003/06/24 01:53:51 cheshire
578 Minor update to comments
580 Revision 1.90 2003/06/24 01:51:47 cheshire
581 <rdar://problem/3303118> Oops: Double-dispose of sockets
582 Don't need to close sockets: CFSocketInvalidate() does that for us
584 Revision 1.89 2003/06/21 18:12:47 cheshire
585 <rdar://problem/3296061> mDNSResponder cannot handle interfaces whose total name is >3 chars
586 One-line change: should say "IF_NAMESIZE", not sizeof(ifname)
588 Revision 1.88 2003/06/12 23:38:37 cheshire
589 <rdar://problem/3291162> mDNSResponder doesn't detect some configuration changes
590 Also check that scope_id matches before concluding that two interfaces are the same
592 Revision 1.87 2003/06/10 01:14:11 cheshire
593 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
595 Revision 1.86 2003/05/28 02:41:52 cheshire
596 <rdar://problem/3034346> Time to remove Mac OS 9 UDP Port 53 legacy support
598 Revision 1.85 2003/05/28 02:39:47 cheshire
599 Minor change to debugging messages
601 Revision 1.84 2003/05/27 22:29:40 cheshire
602 Remove out-dated comment
604 Revision 1.83 2003/05/26 03:21:29 cheshire
605 Tidy up address structure naming:
606 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
607 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
608 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
610 Revision 1.82 2003/05/26 03:01:27 cheshire
611 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
613 Revision 1.81 2003/05/24 02:06:42 cheshire
614 <rdar://problem/3268480> IPv6 Multicast Loopback doesn't work
615 Tried setting IPV6_MULTICAST_LOOP; it doesn't help.
616 However, it is probably wise to have the code explicitly set this socket
617 option anyway, in case the default changes in later versions of Unix.
619 Revision 1.80 2003/05/24 02:02:24 cheshire
620 <rdar://problem/3221880> if_indextoname consumes a lot of CPU
621 Fix error in myIfIndexToName; was returning prematurely
623 Revision 1.79 2003/05/23 23:07:44 cheshire
624 <rdar://problem/3268199> Must not write to stderr when running as daemon
626 Revision 1.78 2003/05/23 01:19:04 cheshire
627 <rdar://problem/3267085> mDNSResponder needs to signal type of service to AirPort
628 Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
630 Revision 1.77 2003/05/23 01:12:05 cheshire
633 Revision 1.76 2003/05/22 01:26:01 cheshire
636 Revision 1.75 2003/05/22 00:07:09 cheshire
637 <rdar://problem/3264366> myCFSocketCallBack recvfrom(5) error 1, errno 35
638 Extra logging to determine whether there is a bug in CFSocket
640 Revision 1.74 2003/05/21 20:20:12 cheshire
641 Fix warnings (mainly printf format string warnings, like using "%d" where
642 it should say "%lu", etc.) and improve error logging (use strerror()
643 to include textual error message as well as numeric error in log messages).
645 Revision 1.73 2003/05/21 17:56:29 ksekar
646 <rdar://problem/3191277>: mDNSResponder doesn't watch for IPv6 address changes
648 Revision 1.72 2003/05/14 18:48:41 cheshire
649 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
650 More minor refinements:
651 mDNSMacOSX.c needs to do *all* its mDNS_DeregisterInterface calls before freeing memory
652 mDNS_DeregisterInterface revalidates cache record when *any* representative of an interface goes away
654 Revision 1.71 2003/05/14 07:08:37 cheshire
655 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
656 Previously, when there was any network configuration change, mDNSResponder
657 would tear down the entire list of active interfaces and start again.
658 That was very disruptive, and caused the entire cache to be flushed,
659 and caused lots of extra network traffic. Now it only removes interfaces
660 that have really gone, and only adds new ones that weren't there before.
662 Revision 1.70 2003/05/07 18:30:24 cheshire
663 Fix signed/unsigned comparison warning
665 Revision 1.69 2003/05/06 20:14:44 cheshire
668 Revision 1.68 2003/05/06 00:00:49 cheshire
669 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
671 Revision 1.67 2003/04/29 00:43:44 cheshire
672 Fix compiler warnings
674 Revision 1.66 2003/04/26 02:41:58 cheshire
675 <rdar://problem/3241281> Change timenow from a local variable to a structure member
677 Revision 1.65 2003/04/26 02:34:01 cheshire
678 Add missing mDNSexport
680 Revision 1.64 2003/04/15 16:48:06 jgraessl
681 <rdar://problem/3228833>
682 Modified code in CFSocket notifier function to read all packets on the socket
683 instead of reading only one packet every time the notifier was called.
685 Revision 1.63 2003/04/15 16:33:50 jgraessl
686 <rdar://problem/3221880>
687 Switched to our own copy of if_indextoname to improve performance.
689 Revision 1.62 2003/03/28 01:55:44 cheshire
690 Minor improvements to debugging messages
692 Revision 1.61 2003/03/27 03:30:56 cheshire
693 <rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
694 Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
696 1. Make mDNS_DeregisterInterface() safe to call from a callback
697 2. Make HostNameCallback() use mDNS_DeadvertiseInterface() instead
698 (it never really needed to deregister the interface at all)
700 Revision 1.60 2003/03/15 04:40:38 cheshire
701 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
703 Revision 1.59 2003/03/11 01:23:26 cheshire
704 <rdar://problem/3194246> mDNSResponder socket problems
706 Revision 1.58 2003/03/06 01:43:04 cheshire
707 <rdar://problem/3189097> Additional debugging code in mDNSResponder
708 Improve "LIST_ALL_INTERFACES" output
710 Revision 1.57 2003/03/05 22:36:27 cheshire
711 <rdar://problem/3186338> Loopback doesn't work with mDNSResponder-27
712 Temporary workaround: Skip loopback interface *only* if we found at least one v4 interface to use
714 Revision 1.56 2003/03/05 01:50:38 cheshire
715 <rdar://problem/3189097> Additional debugging code in mDNSResponder
717 Revision 1.55 2003/02/21 01:54:09 cheshire
718 <rdar://problem/3099194> mDNSResponder needs performance improvements
719 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
721 Revision 1.54 2003/02/20 06:48:35 cheshire
722 <rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
723 Reviewed by: Josh Graessley, Bob Bradley
725 Revision 1.53 2003/01/29 02:21:23 cheshire
726 Return mStatus_Invalid if can't send packet because socket not available
728 Revision 1.52 2003/01/28 19:39:43 jgraessl
729 Enabling AAAA over IPv4 support.
731 Revision 1.51 2003/01/28 05:11:23 cheshire
732 Fixed backwards comparison in SearchForInterfaceByName
734 Revision 1.50 2003/01/13 23:49:44 jgraessl
735 Merged changes for the following fixes in to top of tree:
736 <rdar://problem/3086540> computer name changes not handled properly
737 <rdar://problem/3124348> service name changes are not properly handled
738 <rdar://problem/3124352> announcements sent in pairs, failing chattiness test
740 Revision 1.49 2002/12/23 22:13:30 jgraessl
741 Reviewed by: Stuart Cheshire
742 Initial IPv6 support for mDNSResponder.
744 Revision 1.48 2002/11/22 01:37:52 cheshire
745 <rdar://problem/3108426> mDNSResponder is monitoring ServiceEntities instead of InterfaceEntities
747 Revision 1.47 2002/09/21 20:44:51 zarzycki
750 Revision 1.46 2002/09/19 21:25:35 cheshire
751 mDNS_snprintf() doesn't need to be in a separate file
753 Revision 1.45 2002/09/17 01:45:13 cheshire
754 Add LIST_ALL_INTERFACES symbol for debugging
756 Revision 1.44 2002/09/17 01:36:23 cheshire
757 Move Puma support to mDNSMacOSXPuma.c
759 Revision 1.43 2002/09/17 01:05:28 cheshire
760 Change mDNS_AdvertiseLocalAddresses to be an Init parameter instead of a global
762 Revision 1.42 2002/09/16 23:13:50 cheshire
767 // ***************************************************************************
769 // Supporting routines to run mDNS on a CFRunLoop platform
770 // ***************************************************************************
772 // For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
773 // including ones that mDNSResponder chooses not to use.
774 #define LIST_ALL_INTERFACES 0
776 // For enabling AAAA records over IPv4. Setting this to 0 sends only
777 // A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both
778 // AAAA and A records over both IPv4 and IPv6.
779 #define AAAA_OVER_V4 1
781 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
782 #include "DNSCommon.h"
783 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
784 #include "../mDNSShared/uds_daemon.h" // Defines communication interface from platform layer up to UDS daemon
785 #include "PlatformCommon.h"
788 #include <stdarg.h> // For va_list support
790 #include <net/if_types.h> // For IFT_ETHER
791 #include <net/if_dl.h>
793 #include <sys/param.h>
794 #include <sys/socket.h>
795 #include <sys/sysctl.h>
797 #include <sys/ioctl.h>
798 #include <time.h> // platform support for UTC time
799 #include <arpa/inet.h> // for inet_aton
801 #include <netinet/in.h> // For IP_RECVTTL
803 #define IP_RECVTTL 24 // bool; receive reception TTL w/dgram
806 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
807 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
808 #include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
810 #include <Security/Security.h>
812 #include <AvailabilityMacros.h>
813 #ifdef MAC_OS_X_VERSION_10_4
817 // Code contributed by Dave Heller:
818 // Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
819 // work on Mac OS X 10.1, which does not have the getifaddrs call.
820 #define RUN_ON_PUMA_WITHOUT_IFADDRS 0
821 #if RUN_ON_PUMA_WITHOUT_IFADDRS
822 #include "mDNSMacOSXPuma.c"
827 #include <IOKit/IOKitLib.h>
828 #include <IOKit/IOMessage.h>
829 #include <mach/mach_time.h>
831 typedef struct SearchListElem
833 struct SearchListElem
*next
;
837 DNSQuestion DefBrowseQ
;
838 DNSQuestion LegacyBrowseQ
;
839 DNSQuestion RegisterQ
;
840 DNSQuestion DefRegisterQ
;
841 ARListElem
*AuthRecs
;
845 // ***************************************************************************
848 static mDNSu32 clockdivisor
= 0;
850 // for domain enumeration and default browsing/registration
851 static SearchListElem
*SearchList
= NULL
; // where we search for _browse domains
852 static DNSQuestion LegacyBrowseDomainQ
; // our local enumeration query for _legacy._browse domains
853 static DNameListElem
*DefBrowseList
= NULL
; // cache of answers to above query (where we search for empty string browses)
854 static DNameListElem
*DefRegList
= NULL
; // manually generated list of domains where we register for empty string registrations
855 static ARListElem
*SCPrefBrowseDomains
= NULL
; // manually generated local-only PTR records for browse domains we get from SCPreferences
857 static domainname DynDNSRegDomain
; // Default wide-area zone for service registration
858 static domainname DynDNSBrowseDomain
; // Default wide-area zone for legacy ("empty string") browses
859 static domainname DynDNSHostname
;
861 #define CONFIG_FILE "/etc/mDNSResponder.conf"
862 #define DYNDNS_KEYCHAIN_SERVICE "DynDNS Shared Secret"
863 #define SYS_KEYCHAIN_PATH "/Library/Keychains/System.keychain"
865 // Function Prototypes
866 mDNSlocal
void SetSCPrefsBrowseDomain(mDNS
*m
, const domainname
*d
, mDNSBool add
);
868 // ***************************************************************************
871 // routines to allow access to default domain lists from daemon layer
873 mDNSexport DNameListElem
*mDNSPlatformGetSearchDomainList(void)
875 return mDNS_CopyDNameList(DefBrowseList
);
878 mDNSexport DNameListElem
*mDNSPlatformGetRegDomainList(void)
880 return mDNS_CopyDNameList(DefRegList
);
883 // utility routines to manage registration domain lists
885 mDNSlocal
void AddDefRegDomain(domainname
*d
)
887 DNameListElem
*newelem
= NULL
, *ptr
;
889 // make sure name not already in list
890 for (ptr
= DefRegList
; ptr
; ptr
= ptr
->next
)
892 if (SameDomainName(&ptr
->name
, d
))
893 { debugf("duplicate addition of default reg domain %##s", d
->c
); return; }
896 newelem
= mallocL("DNameListElem", sizeof(*newelem
));
897 if (!newelem
) { LogMsg("Error - malloc"); return; }
898 AssignDomainName(newelem
->name
, *d
);
899 newelem
->next
= DefRegList
;
900 DefRegList
= newelem
;
902 DefaultRegDomainChanged(d
, mDNStrue
);
903 udsserver_default_reg_domain_changed(d
, mDNStrue
);
906 mDNSlocal
void RemoveDefRegDomain(domainname
*d
)
908 DNameListElem
*ptr
= DefRegList
, *prev
= NULL
;
912 if (SameDomainName(&ptr
->name
, d
))
914 if (prev
) prev
->next
= ptr
->next
;
915 else DefRegList
= ptr
->next
;
916 freeL("DNameListElem", ptr
);
917 DefaultRegDomainChanged(d
, mDNSfalse
);
918 udsserver_default_reg_domain_changed(d
, mDNSfalse
);
924 debugf("Requested removal of default registration domain %##s not in contained in list", d
->c
);
927 mDNSlocal
void NotifyOfElusiveBug(const char *title
, mDNSu32 radarid
, const char *msg
)
929 extern mDNS mDNSStorage
;
930 NetworkInterfaceInfoOSX
*i
;
931 static int notifyCount
= 0;
932 if (notifyCount
) return;
934 // If we display our alert early in the boot process, then it vanishes once the desktop appears.
935 // To avoid this, we don't try to display alerts in the first three minutes after boot.
936 if ((mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return;
938 // Determine if we're at Apple (17.*.*.*)
939 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
940 if (i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
&& i
->ifinfo
.ip
.ip
.v4
.b
[0] == 17)
942 if (!i
) return; // If not at Apple, don't show the alert
944 // Send a notification to the user to contact coreos-networking
946 CFStringRef alertHeader
= CFStringCreateWithCString(NULL
, title
, kCFStringEncodingUTF8
);
947 CFStringRef alertFormat
= CFSTR("Congratulations, you've reproduced an elusive bug. Please contact the owner of <rdar://problem/%d>. %s");
948 CFStringRef alertMessage
= CFStringCreateWithFormat(NULL
, NULL
, alertFormat
, radarid
, msg
);
949 CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel
, NULL
, NULL
, NULL
, alertHeader
, alertMessage
, NULL
);
952 mDNSlocal
struct ifaddrs
* myGetIfAddrs(int refresh
)
954 static struct ifaddrs
*ifa
= NULL
;
962 if (ifa
== NULL
) getifaddrs(&ifa
);
967 mDNSlocal NetworkInterfaceInfoOSX
*SearchForInterfaceByName(mDNS
*const m
, const char *ifname
, int type
)
969 NetworkInterfaceInfoOSX
*i
;
970 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
971 if (i
->Exists
&& !strcmp(i
->ifa_name
, ifname
) &&
973 (type
== AF_INET
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) ||
974 (type
== AF_INET6
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
) )) return(i
);
978 mDNSlocal
int myIfIndexToName(u_short index
, char* name
)
981 for (ifa
= myGetIfAddrs(0); ifa
; ifa
= ifa
->ifa_next
)
982 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
983 if (((struct sockaddr_dl
*)ifa
->ifa_addr
)->sdl_index
== index
)
984 { strncpy(name
, ifa
->ifa_name
, IF_NAMESIZE
); return 0; }
988 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS
*const m
, mDNSu32 index
)
990 NetworkInterfaceInfoOSX
*i
;
991 if (index
== (uint32_t)~0) return(mDNSInterface_LocalOnly
);
993 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
994 // Don't get tricked by inactive interfaces with no InterfaceID set
995 if (i
->ifinfo
.InterfaceID
&& i
->scope_id
== index
) return(i
->ifinfo
.InterfaceID
);
999 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS
*const m
, mDNSInterfaceID id
)
1001 NetworkInterfaceInfoOSX
*i
;
1002 if (id
== mDNSInterface_LocalOnly
) return((mDNSu32
)~0);
1004 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1005 // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces, which have no InterfaceID set
1006 if ((mDNSInterfaceID
)i
== id
) return(i
->scope_id
);
1010 // NOTE: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
1011 // NOTE: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
1012 // OR send via our primary v4 unicast socket
1013 mDNSexport mStatus
mDNSPlatformSendUDP(const mDNS
*const m
, const void *const msg
, const mDNSu8
*const end
,
1014 mDNSInterfaceID InterfaceID
, const mDNSAddr
*dst
, mDNSIPPort dstPort
)
1018 // Note: For this platform we've adopted the convention that InterfaceIDs are secretly pointers
1019 // to the NetworkInterfaceInfoOSX structure that holds the active sockets. The mDNSCore code
1020 // doesn't know that and doesn't need to know that -- it just treats InterfaceIDs as opaque identifiers.
1021 NetworkInterfaceInfoOSX
*info
= (NetworkInterfaceInfoOSX
*)InterfaceID
;
1022 char *ifa_name
= info
? info
->ifa_name
: "unicast";
1023 struct sockaddr_storage to
;
1026 // Sanity check: Make sure that if we're sending a query via unicast, we're sending it using our
1027 // anonymous socket created for this purpose, so that we'll receive the response.
1028 // If we use one of the many multicast sockets bound to port 5353 then we may not receive responses reliably.
1029 if (info
&& !mDNSAddrIsDNSMulticast(dst
))
1031 const DNSMessage
*const m
= (DNSMessage
*)msg
;
1032 if ((m
->h
.flags
.b
[0] & kDNSFlag0_QR_Mask
) == kDNSFlag0_QR_Query
)
1033 LogMsg("mDNSPlatformSendUDP: ERROR: Sending query OP from mDNS port to non-mDNS destination %#a:%d", dst
, mDNSVal16(dstPort
));
1036 if (dst
->type
== mDNSAddrType_IPv4
)
1038 struct sockaddr_in
*sin_to
= (struct sockaddr_in
*)&to
;
1039 sin_to
->sin_len
= sizeof(*sin_to
);
1040 sin_to
->sin_family
= AF_INET
;
1041 sin_to
->sin_port
= dstPort
.NotAnInteger
;
1042 sin_to
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
1043 s
= info
? info
->ss
.sktv4
: m
->p
->unicastsockets
.sktv4
;
1045 else if (dst
->type
== mDNSAddrType_IPv6
)
1047 struct sockaddr_in6
*sin6_to
= (struct sockaddr_in6
*)&to
;
1048 sin6_to
->sin6_len
= sizeof(*sin6_to
);
1049 sin6_to
->sin6_family
= AF_INET6
;
1050 sin6_to
->sin6_port
= dstPort
.NotAnInteger
;
1051 sin6_to
->sin6_flowinfo
= 0;
1052 sin6_to
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
1053 sin6_to
->sin6_scope_id
= info
? info
->scope_id
: 0;
1054 s
= info
? info
->ss
.sktv6
: m
->p
->unicastsockets
.sktv6
;
1058 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
1059 return mStatus_BadParamErr
;
1063 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
1064 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
);
1066 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
1067 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
));
1069 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
1070 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
1071 if (s
< 0) return(mStatus_Invalid
);
1073 err
= sendto(s
, msg
, (UInt8
*)end
- (UInt8
*)msg
, 0, (struct sockaddr
*)&to
, to
.ss_len
);
1076 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
1077 if (!mDNSAddressIsAllDNSLinkGroup(dst
) && (errno
== EHOSTDOWN
|| errno
== ENETDOWN
|| errno
== EHOSTUNREACH
)) return(err
);
1078 // Don't report EHOSTUNREACH in the first three minutes after boot
1079 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
1080 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
1081 if (errno
== EHOSTUNREACH
&& (mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return(err
);
1082 LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %5s/%ld to %#a:%d skt %d error %d errno %d (%s) %lu",
1083 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
, err
, errno
, strerror(errno
), (mDNSu32
)(m
->timenow
));
1087 return(mStatus_NoError
);
1090 mDNSlocal ssize_t
myrecvfrom(const int s
, void *const buffer
, const size_t max
,
1091 struct sockaddr
*const from
, size_t *const fromlen
, mDNSAddr
*dstaddr
, char ifname
[IF_NAMESIZE
], mDNSu8
*ttl
)
1093 static unsigned int numLogMessages
= 0;
1094 struct iovec databuffers
= { (char *)buffer
, max
};
1097 struct cmsghdr
*cmPtr
;
1098 char ancillary
[1024];
1100 *ttl
= 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
1102 // Set up the message
1103 msg
.msg_name
= (caddr_t
)from
;
1104 msg
.msg_namelen
= *fromlen
;
1105 msg
.msg_iov
= &databuffers
;
1107 msg
.msg_control
= (caddr_t
)&ancillary
;
1108 msg
.msg_controllen
= sizeof(ancillary
);
1112 n
= recvmsg(s
, &msg
, 0);
1115 if (errno
!= EWOULDBLOCK
&& numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s
, n
, errno
);
1118 if (msg
.msg_controllen
< (int)sizeof(struct cmsghdr
))
1120 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
1121 s
, msg
.msg_controllen
, sizeof(struct cmsghdr
));
1124 if (msg
.msg_flags
& MSG_CTRUNC
)
1126 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s
);
1130 *fromlen
= msg
.msg_namelen
;
1132 // Parse each option out of the ancillary data.
1133 for (cmPtr
= CMSG_FIRSTHDR(&msg
); cmPtr
; cmPtr
= CMSG_NXTHDR(&msg
, cmPtr
))
1135 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
1136 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVDSTADDR
)
1138 dstaddr
->type
= mDNSAddrType_IPv4
;
1139 dstaddr
->ip
.v4
.NotAnInteger
= *(u_int32_t
*)CMSG_DATA(cmPtr
);
1141 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVIF
)
1143 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)CMSG_DATA(cmPtr
);
1144 if (sdl
->sdl_nlen
< IF_NAMESIZE
)
1146 mDNSPlatformMemCopy(sdl
->sdl_data
, ifname
, sdl
->sdl_nlen
);
1147 ifname
[sdl
->sdl_nlen
] = 0;
1148 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
1151 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVTTL
)
1153 *ttl
= *(u_char
*)CMSG_DATA(cmPtr
);
1155 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_PKTINFO
)
1157 struct in6_pktinfo
*ip6_info
= (struct in6_pktinfo
*)CMSG_DATA(cmPtr
);
1158 dstaddr
->type
= mDNSAddrType_IPv6
;
1159 dstaddr
->ip
.v6
= *(mDNSv6Addr
*)&ip6_info
->ipi6_addr
;
1160 myIfIndexToName(ip6_info
->ipi6_ifindex
, ifname
);
1162 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_HOPLIMIT
)
1164 *ttl
= *(int*)CMSG_DATA(cmPtr
);
1171 // On entry, context points to our CFSocketSet
1172 // If ss->info is NULL, we received this packet on our anonymous unicast socket
1173 // If ss->info is non-NULL, we received this packet on port 5353 on the indicated interface
1174 mDNSlocal
void myCFSocketCallBack(CFSocketRef cfs
, CFSocketCallBackType CallBackType
, CFDataRef address
, const void *data
, void *context
)
1176 mDNSAddr senderAddr
, destAddr
;
1177 mDNSIPPort senderPort
, destPort
= MulticastDNSPort
;
1178 const CFSocketSet
*ss
= (const CFSocketSet
*)context
;
1179 mDNS
*const m
= ss
->m
;
1180 mDNSInterfaceID InterfaceID
= ss
->info
? ss
->info
->ifinfo
.InterfaceID
: mDNSNULL
;
1181 struct sockaddr_storage from
;
1182 size_t fromlen
= sizeof(from
);
1183 char packetifname
[IF_NAMESIZE
] = "";
1184 int err
, s1
= -1, skt
= CFSocketGetNative(cfs
);
1187 (void)address
; // Parameter not used
1188 (void)data
; // Parameter not used
1190 if (CallBackType
!= kCFSocketReadCallBack
)
1191 LogMsg("myCFSocketCallBack: Why is CallBackType %d not kCFSocketReadCallBack?", CallBackType
);
1193 if (cfs
== ss
->cfsv4
) s1
= ss
->sktv4
;
1194 else if (cfs
== ss
->cfsv6
) s1
= ss
->sktv6
;
1196 if (s1
< 0 || s1
!= skt
)
1198 LogMsg("myCFSocketCallBack: s1 %d native socket %d, cfs %p", s1
, skt
, cfs
);
1199 LogMsg("myCFSocketCallBack: cfsv4 %p, sktv4 %d", ss
->cfsv4
, ss
->sktv4
);
1200 LogMsg("myCFSocketCallBack: cfsv6 %p, sktv6 %d", ss
->cfsv6
, ss
->sktv6
);
1204 while ((err
= myrecvfrom(s1
, &m
->imsg
, sizeof(m
->imsg
), (struct sockaddr
*)&from
, &fromlen
, &destAddr
, packetifname
, &ttl
)) >= 0)
1207 if (from
.ss_family
== AF_INET
)
1209 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&from
;
1210 senderAddr
.type
= mDNSAddrType_IPv4
;
1211 senderAddr
.ip
.v4
.NotAnInteger
= sin
->sin_addr
.s_addr
;
1212 senderPort
.NotAnInteger
= sin
->sin_port
;
1214 else if (from
.ss_family
== AF_INET6
)
1216 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&from
;
1217 senderAddr
.type
= mDNSAddrType_IPv6
;
1218 senderAddr
.ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
1219 senderPort
.NotAnInteger
= sin6
->sin6_port
;
1223 LogMsg("myCFSocketCallBack from is unknown address family %d", from
.ss_family
);
1227 if (mDNSAddrIsDNSMulticast(&destAddr
))
1229 // Even though we indicated a specific interface in the IP_ADD_MEMBERSHIP call, a weirdness of the
1230 // sockets API means that even though this socket has only officially joined the multicast group
1231 // on one specific interface, the kernel will still deliver multicast packets to it no matter which
1232 // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
1233 // To work around this weirdness, we use the IP_RECVIF option to find the name of the interface
1234 // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
1237 verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on unicast socket (Ignored)", &senderAddr
, &destAddr
);
1240 else if (!strcmp(ss
->info
->ifa_name
, packetifname
))
1241 verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on interface %#a/%s",
1242 &senderAddr
, &destAddr
, &ss
->info
->ifinfo
.ip
, ss
->info
->ifa_name
);
1245 verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on interface %#a/%s (Ignored -- really arrived on interface %s)",
1246 &senderAddr
, &destAddr
, &ss
->info
->ifinfo
.ip
, ss
->info
->ifa_name
, packetifname
);
1252 // Note: For unicast packets, try to find the matching mDNSCore interface object
1253 // (though we may not be able to, for unicast packets received over something like a PPP link)
1254 NetworkInterfaceInfo
*intf
= m
->HostInterfaces
;
1255 while (intf
&& strcmp(intf
->ifname
, packetifname
)) intf
= intf
->next
;
1256 if (intf
) InterfaceID
= intf
->InterfaceID
;
1259 mDNSCoreReceive(m
, &m
->imsg
, (unsigned char*)&m
->imsg
+ err
, &senderAddr
, senderPort
, &destAddr
, destPort
, InterfaceID
);
1262 if (err
< 0 && (errno
!= EWOULDBLOCK
|| count
== 0))
1264 // Something is busted here.
1265 // CFSocket says there is a packet, but myrecvfrom says there is not.
1266 // Try calling select() to get another opinion.
1267 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
1268 // All of this is racy, as data may have arrived after the call to select()
1269 int save_errno
= errno
;
1273 int solen
= sizeof(int);
1276 FD_SET(s1
, &readfds
);
1277 struct timeval timeout
;
1279 timeout
.tv_usec
= 0;
1280 int selectresult
= select(s1
+1, &readfds
, NULL
, NULL
, &timeout
);
1281 if (getsockopt(s1
, SOL_SOCKET
, SO_ERROR
, &so_error
, &solen
) == -1)
1282 LogMsg("myCFSocketCallBack getsockopt(SO_ERROR) error %d", errno
);
1283 if (getsockopt(s1
, SOL_SOCKET
, SO_NREAD
, &so_nread
, &solen
) == -1)
1284 LogMsg("myCFSocketCallBack getsockopt(SO_NREAD) error %d", errno
);
1285 if (ioctl(s1
, FIONREAD
, &fionread
) == -1)
1286 LogMsg("myCFSocketCallBack ioctl(FIONREAD) error %d", errno
);
1287 static unsigned int numLogMessages
= 0;
1288 if (numLogMessages
++ < 100)
1289 LogMsg("myCFSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
1290 s1
, err
, save_errno
, strerror(save_errno
), selectresult
, FD_ISSET(s1
, &readfds
) ? "" : "*NO* ", so_error
, so_nread
, fionread
, count
);
1291 if (numLogMessages
> 5)
1292 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)", 3375328,
1293 "Alternatively, you can send email to radar-3387020@group.apple.com. "
1294 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1296 sleep(1); // After logging this error, rate limit so we don't flood syslog
1300 // TCP socket support for unicast DNS and Dynamic DNS Update
1304 TCPConnectionCallback callback
;
1309 mDNSlocal
void tcpCFSocketCallback(CFSocketRef cfs
, CFSocketCallBackType CallbackType
, CFDataRef address
,
1310 const void *data
, void *context
)
1312 #pragma unused(CallbackType, address, data)
1313 mDNSBool connect
= mDNSfalse
;
1315 tcpInfo_t
*info
= context
;
1316 if (!info
->connected
)
1319 info
->connected
= mDNStrue
; // prevent connected flag from being set in future callbacks
1321 info
->callback(CFSocketGetNative(cfs
), info
->context
, connect
);
1322 // NOTE: the callback may call CloseConnection here, which frees the context structure!
1325 mDNSexport mStatus
mDNSPlatformTCPConnect(const mDNSAddr
*dst
, mDNSOpaque16 dstport
, mDNSInterfaceID InterfaceID
,
1326 TCPConnectionCallback callback
, void *context
, int *descriptor
)
1328 int sd
, on
= 1; // "on" for setsockopt
1329 struct sockaddr_in saddr
;
1330 CFSocketContext cfContext
= { 0, NULL
, 0, 0, 0 };
1333 CFRunLoopSourceRef rls
;
1335 (void)InterfaceID
; //!!!KRS use this if non-zero!!!
1338 if (dst
->type
!= mDNSAddrType_IPv4
)
1340 LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: opperation not supported");
1341 return mStatus_UnknownErr
;
1344 sd
= socket(AF_INET
, SOCK_STREAM
, 0);
1345 if (sd
< 3) { LogMsg("mDNSPlatformTCPConnect: socket error %d errno %d (%s)", sd
, errno
, strerror(errno
)); return mStatus_UnknownErr
; }
1348 if (fcntl(sd
, F_SETFL
, O_NONBLOCK
) < 0)
1350 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno
));
1351 return mStatus_UnknownErr
;
1354 // receive interface identifiers
1355 if (setsockopt(sd
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
)) < 0)
1357 LogMsg("setsockopt IP_RECVIF - %s", strerror(errno
));
1358 return mStatus_UnknownErr
;
1360 // set up CF wrapper, add to Run Loop
1361 info
= mallocL("mDNSPlatformTCPConnect", sizeof(tcpInfo_t
));
1362 info
->callback
= callback
;
1363 info
->context
= context
;
1364 cfContext
.info
= info
;
1365 sr
= CFSocketCreateWithNative(kCFAllocatorDefault
, sd
, kCFSocketReadCallBack
| kCFSocketConnectCallBack
,
1366 tcpCFSocketCallback
, &cfContext
);
1369 LogMsg("ERROR: mDNSPlatformTCPConnect - CFSocketRefCreateWithNative failed");
1370 freeL("mDNSPlatformTCPConnect", info
);
1371 return mStatus_UnknownErr
;
1374 rls
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, sr
, 0);
1377 LogMsg("ERROR: mDNSPlatformTCPConnect - CFSocketCreateRunLoopSource failed");
1378 freeL("mDNSPlatformTCPConnect", info
);
1379 return mStatus_UnknownErr
;
1382 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
1385 // initiate connection wth peer
1386 bzero(&saddr
, sizeof(saddr
));
1387 saddr
.sin_family
= AF_INET
;
1388 saddr
.sin_port
= dstport
.NotAnInteger
;
1389 memcpy(&saddr
.sin_addr
, &dst
->ip
.v4
.NotAnInteger
, sizeof(saddr
.sin_addr
));
1390 if (connect(sd
, (struct sockaddr
*)&saddr
, sizeof(saddr
)) < 0)
1392 if (errno
== EINPROGRESS
)
1394 info
->connected
= 0;
1396 return mStatus_ConnPending
;
1398 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: %s", strerror(errno
));
1399 freeL("mDNSPlatformTCPConnect", info
);
1400 CFSocketInvalidate(sr
);
1401 return mStatus_ConnFailed
;
1403 info
->connected
= 1;
1405 return mStatus_ConnEstablished
;
1408 mDNSexport
void mDNSPlatformTCPCloseConnection(int sd
)
1410 CFSocketContext cfContext
;
1414 if (sd
< 3) LogMsg("mDNSPlatformTCPCloseConnection: ERROR sd %d < 3", sd
);
1416 // Get the CFSocket for the descriptor
1417 sr
= CFSocketCreateWithNative(kCFAllocatorDefault
, sd
, kCFSocketNoCallBack
, NULL
, NULL
);
1418 if (!sr
) { LogMsg("ERROR: mDNSPlatformTCPCloseConnection - CFSocketCreateWithNative returned NULL"); return; }
1420 CFSocketGetContext(sr
, &cfContext
);
1421 if (!cfContext
.info
)
1423 LogMsg("ERROR: mDNSPlatformTCPCloseConnection - could not retreive tcpInfo from socket context");
1427 CFRelease(sr
); // this only releases the copy we allocated with CreateWithNative above
1429 info
= cfContext
.info
;
1431 // Note: MUST NOT close the underlying native BSD socket.
1432 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately,
1433 // because it first has to unhook the sockets from its select() call, before it can safely close them.
1434 CFSocketInvalidate(sr
);
1436 freeL("mDNSPlatformTCPCloseConnection", info
);
1439 mDNSexport
int mDNSPlatformReadTCP(int sd
, void *buf
, int buflen
)
1441 int nread
= recv(sd
, buf
, buflen
, 0);
1444 if (errno
== EAGAIN
) return 0; // no data available (call would block)
1445 LogMsg("ERROR: mDNSPlatformReadTCP - recv: %s", strerror(errno
));
1451 mDNSexport
int mDNSPlatformWriteTCP(int sd
, const char *msg
, int len
)
1453 int nsent
= send(sd
, msg
, len
, 0);
1457 if (errno
== EAGAIN
) return 0; // blocked
1458 LogMsg("ERROR: mDNSPlatformWriteTCP - sendL %s", strerror(errno
));
1464 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
1465 mDNSlocal
void GetUserSpecifiedFriendlyComputerName(domainlabel
*const namelabel
)
1467 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
1468 CFStringRef cfs
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
1471 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
1476 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
1477 mDNSlocal
void GetUserSpecifiedLocalHostName(domainlabel
*const namelabel
)
1479 CFStringRef cfs
= SCDynamicStoreCopyLocalHostName(NULL
);
1482 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
1487 mDNSlocal
void GetUserSpecifiedDDNSConfig(domainname
*const fqdn
, domainname
*const regDomain
, domainname
*const browseDomain
)
1489 char buf
[MAX_ESCAPED_DOMAIN_NAME
];
1492 regDomain
->c
[0] = 0;
1493 browseDomain
->c
[0] = 0;
1496 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetUserSpecifiedDDNSConfig"), NULL
, NULL
);
1499 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, CFSTR("Setup:/Network/DynamicDNS"));
1502 CFArrayRef fqdnArray
= CFDictionaryGetValue(dict
, CFSTR("FQDN"));
1503 CFArrayRef regArray
= CFDictionaryGetValue(dict
, CFSTR("DefaultRegistrationDomain"));
1504 CFArrayRef browseArray
= CFDictionaryGetValue(dict
, CFSTR("DefaultBrowseDomain"));
1507 CFStringRef name
= CFArrayGetValueAtIndex(fqdnArray
, 0);
1510 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
1511 !MakeDomainNameFromDNSNameString(fqdn
, buf
) || !fqdn
->c
[0])
1512 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf
[0] ? buf
: "(unknown)");
1513 else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf
);
1518 CFStringRef name
= CFArrayGetValueAtIndex(regArray
, 0);
1521 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
1522 !MakeDomainNameFromDNSNameString(regDomain
, buf
) || !regDomain
->c
[0])
1523 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf
[0] ? buf
: "(unknown)");
1524 else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration zone: %s", buf
);
1529 CFStringRef name
= CFArrayGetValueAtIndex(browseArray
, 0);
1532 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
1533 !MakeDomainNameFromDNSNameString(browseDomain
, buf
) || !browseDomain
->c
[0])
1534 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browse domain: %s", buf
[0] ? buf
: "(unknown)");
1535 else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browse zone: %s", buf
);
1544 mDNSlocal
void SetDDNSNameStatus(domainname
*const dname
, mStatus status
)
1546 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:SetDDNSNameStatus"), NULL
, NULL
);
1549 char uname
[MAX_ESCAPED_DOMAIN_NAME
];
1550 ConvertDomainNameToCString(dname
, uname
);
1552 while (*p
) { *p
= tolower(*p
); p
++; }
1553 const void *n1
= CFStringCreateWithCString(NULL
, uname
, kCFStringEncodingUTF8
); // CFStringRef
1554 const void *v1
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &status
); // CFNumberRef
1555 const void *n2
= CFSTR("FQDN"); // CFStringRef
1556 const void *v2
= CFDictionaryCreate(NULL
, &n1
, &v1
, 1, NULL
, NULL
); // CFDictionaryRef
1557 CFDictionaryRef dict
= CFDictionaryCreate(NULL
, &n2
, &v2
, 1, NULL
, NULL
);
1558 SCDynamicStoreSetValue(store
, CFSTR("State:/Network/DynamicDNS"), dict
);
1568 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
1569 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
1570 mDNSlocal mStatus
SetupSocket(mDNS
*const m
, CFSocketSet
*cp
, mDNSBool mcast
, const mDNSAddr
*ifaddr
, u_short sa_family
)
1572 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
1573 CFSocketRef
*c
= (sa_family
== AF_INET
) ? &cp
->cfsv4
: &cp
->cfsv6
;
1574 CFRunLoopSourceRef
*r
= (sa_family
== AF_INET
) ? &cp
->rlsv4
: &cp
->rlsv6
;
1576 const int twofivefive
= 255;
1577 mStatus err
= mStatus_NoError
;
1578 char *errstr
= mDNSNULL
;
1580 mDNSIPPort port
= (mcast
| m
->CanReceiveUnicastOn5353
) ? MulticastDNSPort
: zeroIPPort
;
1582 if (*s
>= 0) { LogMsg("SetupSocket ERROR: socket %d is already set", *s
); return(-1); }
1583 if (*c
) { LogMsg("SetupSocket ERROR: CFSocketRef %p is already set", *c
); return(-1); }
1585 // Open the socket...
1586 int skt
= socket(sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
1587 if (skt
< 3) { LogMsg("SetupSocket: socket error %d errno %d (%s)", skt
, errno
, strerror(errno
)); return(skt
); }
1589 // ... with a shared UDP port, if it's for multicast receiving
1590 if (port
.NotAnInteger
) err
= setsockopt(skt
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
1591 if (err
< 0) { errstr
= "setsockopt - SO_REUSEPORT"; goto fail
; }
1593 if (sa_family
== AF_INET
)
1595 // We want to receive destination addresses
1596 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVDSTADDR
, &on
, sizeof(on
));
1597 if (err
< 0) { errstr
= "setsockopt - IP_RECVDSTADDR"; goto fail
; }
1599 // We want to receive interface identifiers
1600 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
1601 if (err
< 0) { errstr
= "setsockopt - IP_RECVIF"; goto fail
; }
1603 // We want to receive packet TTL value so we can check it
1604 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVTTL
, &on
, sizeof(on
));
1605 // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
1607 // Add multicast group membership on this interface, if it's for multicast receiving
1610 struct in_addr addr
= { ifaddr
->ip
.v4
.NotAnInteger
};
1612 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroupv4
.NotAnInteger
;
1613 imr
.imr_interface
= addr
;
1614 err
= setsockopt(skt
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &imr
, sizeof(imr
));
1615 if (err
< 0) { errstr
= "setsockopt - IP_ADD_MEMBERSHIP"; goto fail
; }
1617 // Specify outgoing interface too
1618 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_IF
, &addr
, sizeof(addr
));
1619 if (err
< 0) { errstr
= "setsockopt - IP_MULTICAST_IF"; goto fail
; }
1622 // Send unicast packets with TTL 255
1623 err
= setsockopt(skt
, IPPROTO_IP
, IP_TTL
, &twofivefive
, sizeof(twofivefive
));
1624 if (err
< 0) { errstr
= "setsockopt - IP_TTL"; goto fail
; }
1626 // And multicast packets with TTL 255 too
1627 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_TTL
, &twofivefive
, sizeof(twofivefive
));
1628 if (err
< 0) { errstr
= "setsockopt - IP_MULTICAST_TTL"; goto fail
; }
1630 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
1631 const int ip_tosbits
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
;
1632 err
= setsockopt(skt
, IPPROTO_IP
, IP_TOS
, &ip_tosbits
, sizeof(ip_tosbits
));
1633 if (err
< 0) { errstr
= "setsockopt - IP_TOS"; goto fail
; }
1635 // And start listening for packets
1636 struct sockaddr_in listening_sockaddr
;
1637 listening_sockaddr
.sin_family
= AF_INET
;
1638 listening_sockaddr
.sin_port
= port
.NotAnInteger
;
1639 listening_sockaddr
.sin_addr
.s_addr
= 0; // Want to receive multicasts AND unicasts on this socket
1640 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr
, sizeof(listening_sockaddr
));
1641 if (err
) { errstr
= "bind"; goto fail
; }
1643 else if (sa_family
== AF_INET6
)
1645 // We want to receive destination addresses and receive interface identifiers
1646 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_PKTINFO
, &on
, sizeof(on
));
1647 if (err
< 0) { errstr
= "setsockopt - IPV6_PKTINFO"; goto fail
; }
1649 // We want to receive packet hop count value so we can check it
1650 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_HOPLIMIT
, &on
, sizeof(on
));
1651 if (err
< 0) { errstr
= "setsockopt - IPV6_HOPLIMIT"; goto fail
; }
1653 // We want to receive only IPv6 packets, without this option, we may
1654 // get IPv4 addresses as mapped addresses.
1655 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
));
1656 if (err
< 0) { errstr
= "setsockopt - IPV6_V6ONLY"; goto fail
; }
1660 // Add multicast group membership on this interface, if it's for multicast receiving
1661 int interface_id
= if_nametoindex(cp
->info
->ifa_name
);
1662 struct ipv6_mreq i6mr
;
1663 i6mr
.ipv6mr_interface
= interface_id
;
1664 i6mr
.ipv6mr_multiaddr
= *(struct in6_addr
*)&AllDNSLinkGroupv6
;
1665 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &i6mr
, sizeof(i6mr
));
1666 if (err
< 0) { errstr
= "setsockopt - IPV6_JOIN_GROUP"; goto fail
; }
1668 // Specify outgoing interface too
1669 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &interface_id
, sizeof(interface_id
));
1670 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_IF"; goto fail
; }
1673 // Send unicast packets with TTL 255
1674 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
1675 if (err
< 0) { errstr
= "setsockopt - IPV6_UNICAST_HOPS"; goto fail
; }
1677 // And multicast packets with TTL 255 too
1678 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
1679 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_HOPS"; goto fail
; }
1681 // Note: IPV6_TCLASS appears not to be implemented on OS X right now (or indeed on ANY version of Unix?)
1683 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
1684 int tclass
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
; // This may not be right (since tclass is not implemented on OS X, I can't test it)
1685 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_TCLASS
, &tclass
, sizeof(tclass
));
1686 if (err
< 0) { errstr
= "setsockopt - IPV6_TCLASS"; goto fail
; }
1689 // Want to receive our own packets
1690 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &on
, sizeof(on
));
1691 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_LOOP"; goto fail
; }
1693 // And start listening for packets
1694 struct sockaddr_in6 listening_sockaddr6
;
1695 bzero(&listening_sockaddr6
, sizeof(listening_sockaddr6
));
1696 listening_sockaddr6
.sin6_len
= sizeof(listening_sockaddr6
);
1697 listening_sockaddr6
.sin6_family
= AF_INET6
;
1698 listening_sockaddr6
.sin6_port
= port
.NotAnInteger
;
1699 listening_sockaddr6
.sin6_flowinfo
= 0;
1700 // listening_sockaddr6.sin6_addr = IN6ADDR_ANY_INIT; // Want to receive multicasts AND unicasts on this socket
1701 listening_sockaddr6
.sin6_scope_id
= 0;
1702 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr6
, sizeof(listening_sockaddr6
));
1703 if (err
) { errstr
= "bind"; goto fail
; }
1706 fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
1708 CFSocketContext myCFSocketContext
= { 0, cp
, NULL
, NULL
, NULL
};
1709 *c
= CFSocketCreateWithNative(kCFAllocatorDefault
, *s
, kCFSocketReadCallBack
, myCFSocketCallBack
, &myCFSocketContext
);
1710 *r
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, *c
, 0);
1711 CFRunLoopAddSource(CFRunLoopGetCurrent(), *r
, kCFRunLoopDefaultMode
);
1716 LogMsg("%s error %ld errno %d (%s)", errstr
, err
, errno
, strerror(errno
));
1717 if (!strcmp(errstr
, "bind") && errno
== EADDRINUSE
)
1718 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed", 3814904,
1719 "Alternatively, you can send email to radar-3387020@group.apple.com. "
1720 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1725 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
)
1727 if (!sa
) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid
); }
1729 if (sa
->sa_family
== AF_INET
)
1731 struct sockaddr_in
*ifa_addr
= (struct sockaddr_in
*)sa
;
1732 ip
->type
= mDNSAddrType_IPv4
;
1733 ip
->ip
.v4
.NotAnInteger
= ifa_addr
->sin_addr
.s_addr
;
1734 return(mStatus_NoError
);
1737 if (sa
->sa_family
== AF_INET6
)
1739 struct sockaddr_in6
*ifa_addr
= (struct sockaddr_in6
*)sa
;
1740 ip
->type
= mDNSAddrType_IPv6
;
1741 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr
->sin6_addr
)) ifa_addr
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
1742 ip
->ip
.v6
= *(mDNSv6Addr
*)&ifa_addr
->sin6_addr
;
1743 return(mStatus_NoError
);
1746 LogMsg("SetupAddr invalid sa_family %d", sa
->sa_family
);
1747 return(mStatus_Invalid
);
1750 mDNSlocal mDNSEthAddr
GetBSSID(char *ifa_name
)
1752 mDNSEthAddr eth
= zeroEthAddr
;
1753 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetBSSID"), NULL
, NULL
);
1756 CFStringRef entityname
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name
);
1759 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, entityname
);
1762 CFRange range
= { 0, 6 }; // Offset, length
1763 CFDataRef data
= CFDictionaryGetValue(dict
, CFSTR("BSSID"));
1764 if (data
&& CFDataGetLength(data
) == 6) CFDataGetBytes(data
, range
, eth
.b
);
1767 CFRelease(entityname
);
1774 mDNSlocal NetworkInterfaceInfoOSX
*AddInterfaceToList(mDNS
*const m
, struct ifaddrs
*ifa
)
1776 mDNSu32 scope_id
= if_nametoindex(ifa
->ifa_name
);
1777 mDNSEthAddr bssid
= GetBSSID(ifa
->ifa_name
);
1780 if (SetupAddr(&ip
, ifa
->ifa_addr
) != mStatus_NoError
) return(NULL
);
1781 if (SetupAddr(&mask
, ifa
->ifa_netmask
) != mStatus_NoError
) return(NULL
);
1783 NetworkInterfaceInfoOSX
**p
;
1784 for (p
= &m
->p
->InterfaceList
; *p
; p
= &(*p
)->next
)
1785 if (scope_id
== (*p
)->scope_id
&& mDNSSameAddress(&ip
, &(*p
)->ifinfo
.ip
) && mDNSSameEthAddress(&bssid
, &(*p
)->BSSID
))
1787 debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p", scope_id
, &bssid
, &ip
, *p
);
1788 (*p
)->Exists
= mDNStrue
;
1792 NetworkInterfaceInfoOSX
*i
= (NetworkInterfaceInfoOSX
*)mallocL("NetworkInterfaceInfoOSX", sizeof(*i
));
1793 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id
, &bssid
, &ip
, i
);
1794 if (!i
) return(mDNSNULL
);
1795 bzero(i
, sizeof(NetworkInterfaceInfoOSX
));
1796 i
->ifa_name
= (char *)mallocL("NetworkInterfaceInfoOSX name", strlen(ifa
->ifa_name
) + 1);
1797 if (!i
->ifa_name
) { freeL("NetworkInterfaceInfoOSX", i
); return(mDNSNULL
); }
1798 strcpy(i
->ifa_name
, ifa
->ifa_name
);
1800 i
->ifinfo
.InterfaceID
= mDNSNULL
;
1802 i
->ifinfo
.mask
= mask
;
1803 strncpy(i
->ifinfo
.ifname
, ifa
->ifa_name
, sizeof(i
->ifinfo
.ifname
));
1804 i
->ifinfo
.ifname
[sizeof(i
->ifinfo
.ifname
)-1] = 0;
1805 i
->ifinfo
.Advertise
= m
->AdvertiseLocalAddresses
;
1806 i
->ifinfo
.McastTxRx
= mDNSfalse
; // For now; will be set up later at the end of UpdateInterfaceList
1809 i
->Exists
= mDNStrue
;
1810 i
->scope_id
= scope_id
;
1812 i
->sa_family
= ifa
->ifa_addr
->sa_family
;
1813 i
->Multicast
= (ifa
->ifa_flags
& IFF_MULTICAST
) && !(ifa
->ifa_flags
& IFF_POINTOPOINT
);
1817 i
->ss
.sktv4
= i
->ss
.sktv6
= -1;
1818 i
->ss
.cfsv4
= i
->ss
.cfsv6
= NULL
;
1819 i
->ss
.rlsv4
= i
->ss
.rlsv6
= NULL
;
1825 mDNSlocal NetworkInterfaceInfoOSX
*FindRoutableIPv4(mDNS
*const m
, mDNSu32 scope_id
)
1827 NetworkInterfaceInfoOSX
*i
;
1828 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1829 if (i
->Exists
&& i
->scope_id
== scope_id
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
1830 if (!(i
->ifinfo
.ip
.ip
.v4
.b
[0] == 169 && i
->ifinfo
.ip
.ip
.v4
.b
[1] == 254))
1835 mDNSlocal mStatus
UpdateInterfaceList(mDNS
*const m
)
1837 mDNSBool foundav4
= mDNSfalse
;
1838 mDNSBool foundav6
= mDNSfalse
;
1839 struct ifaddrs
*ifa
= myGetIfAddrs(1);
1840 struct ifaddrs
*v4Loopback
= NULL
;
1841 struct ifaddrs
*v6Loopback
= NULL
;
1842 mDNSEthAddr PrimaryMAC
= zeroEthAddr
;
1843 char defaultname
[32];
1844 int InfoSocket
= socket(AF_INET6
, SOCK_DGRAM
, 0);
1845 if (InfoSocket
< 3) LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket
, errno
, strerror(errno
));
1846 if (m
->SleepState
) ifa
= NULL
;
1850 #if LIST_ALL_INTERFACES
1851 if (ifa
->ifa_addr
->sa_family
== AF_APPLETALK
)
1852 debugf("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
1853 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1854 else if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
1855 debugf("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
1856 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1857 else if (ifa
->ifa_addr
->sa_family
!= AF_INET
&& ifa
->ifa_addr
->sa_family
!= AF_INET6
)
1858 debugf("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
1859 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1860 if (!(ifa
->ifa_flags
& IFF_UP
))
1861 debugf("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
1862 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1863 if (!(ifa
->ifa_flags
& IFF_MULTICAST
))
1864 debugf("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
1865 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1866 if (ifa
->ifa_flags
& IFF_POINTOPOINT
)
1867 debugf("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
1868 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1869 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
1870 debugf("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
1871 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
1874 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
1876 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
;
1877 if (sdl
->sdl_type
== IFT_ETHER
&& sdl
->sdl_alen
== sizeof(PrimaryMAC
) && mDNSSameEthAddress(&PrimaryMAC
, &zeroEthAddr
))
1878 mDNSPlatformMemCopy(sdl
->sdl_data
+ sdl
->sdl_nlen
, PrimaryMAC
.b
, 6);
1881 if (ifa
->ifa_flags
& IFF_UP
&& ifa
->ifa_addr
)
1882 if (ifa
->ifa_addr
->sa_family
== AF_INET
|| ifa
->ifa_addr
->sa_family
== AF_INET6
)
1884 if (!ifa
->ifa_netmask
)
1887 SetupAddr(&ip
, ifa
->ifa_addr
);
1888 LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
1889 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
);
1891 else if (ifa
->ifa_addr
->sa_family
!= ifa
->ifa_netmask
->sa_family
)
1894 SetupAddr(&ip
, ifa
->ifa_addr
);
1895 LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
1896 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
, ifa
->ifa_netmask
->sa_family
);
1900 int ifru_flags6
= 0;
1901 if (ifa
->ifa_addr
->sa_family
== AF_INET6
&& InfoSocket
>= 0)
1903 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
1904 struct in6_ifreq ifr6
;
1905 bzero((char *)&ifr6
, sizeof(ifr6
));
1906 strncpy(ifr6
.ifr_name
, ifa
->ifa_name
, sizeof(ifr6
.ifr_name
));
1907 ifr6
.ifr_addr
= *sin6
;
1908 if (ioctl(InfoSocket
, SIOCGIFAFLAG_IN6
, &ifr6
) != -1)
1909 ifru_flags6
= ifr6
.ifr_ifru
.ifru_flags6
;
1910 verbosedebugf("%s %.16a %04X %04X", ifa
->ifa_name
, &sin6
->sin6_addr
, ifa
->ifa_flags
, ifru_flags6
);
1912 if (!(ifru_flags6
& (IN6_IFF_NOTREADY
| IN6_IFF_DETACHED
| IN6_IFF_DEPRECATED
| IN6_IFF_TEMPORARY
)))
1914 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
1915 if (ifa
->ifa_addr
->sa_family
== AF_INET
) v4Loopback
= ifa
;
1916 else v6Loopback
= ifa
;
1919 AddInterfaceToList(m
, ifa
);
1920 if (ifa
->ifa_addr
->sa_family
== AF_INET
) foundav4
= mDNStrue
;
1921 else foundav6
= mDNStrue
;
1926 ifa
= ifa
->ifa_next
;
1929 // For efficiency, we don't register a loopback interface when other interfaces of that family are available
1930 if (!foundav4
&& v4Loopback
) AddInterfaceToList(m
, v4Loopback
);
1931 if (!foundav6
&& v6Loopback
) AddInterfaceToList(m
, v6Loopback
);
1933 // Now the list is complete, set the McastTxRx setting for each interface.
1934 // We always send and receive using IPv4.
1935 // To reduce traffic, we send and receive using IPv6 only on interfaces that have no routable IPv4 address.
1936 // Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
1937 // which means there's a good chance that most or all the other devices on that network should also have v4.
1938 // 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.
1939 // At this time, reducing the packet rate is more important than v6-only devices on a large configured network,
1940 // so we are willing to make that sacrifice.
1941 NetworkInterfaceInfoOSX
*i
;
1942 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1945 mDNSBool txrx
= i
->Multicast
&& ((i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) || !FindRoutableIPv4(m
, i
->scope_id
));
1946 if (i
->ifinfo
.McastTxRx
!= txrx
)
1948 i
->ifinfo
.McastTxRx
= txrx
;
1949 i
->Exists
= 2; // State change; need to deregister and reregister this interface
1952 if (InfoSocket
>= 0) close(InfoSocket
);
1954 mDNS_snprintf(defaultname
, sizeof(defaultname
), "Macintosh-%02X%02X%02X%02X%02X%02X",
1955 PrimaryMAC
.b
[0], PrimaryMAC
.b
[1], PrimaryMAC
.b
[2], PrimaryMAC
.b
[3], PrimaryMAC
.b
[4], PrimaryMAC
.b
[5]);
1957 // Set up the nice label
1958 domainlabel nicelabel
;
1960 GetUserSpecifiedFriendlyComputerName(&nicelabel
);
1961 if (nicelabel
.c
[0] == 0) MakeDomainLabelFromLiteralString(&nicelabel
, defaultname
);
1963 // Set up the RFC 1034-compliant label
1964 domainlabel hostlabel
;
1966 GetUserSpecifiedLocalHostName(&hostlabel
);
1967 if (hostlabel
.c
[0] == 0) MakeDomainLabelFromLiteralString(&hostlabel
, defaultname
);
1969 if (SameDomainLabel(m
->p
->usernicelabel
.c
, nicelabel
.c
))
1970 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m
->p
->usernicelabel
.c
, m
->nicelabel
.c
);
1973 debugf("Updating m->nicelabel to %#s", nicelabel
.c
);
1974 m
->p
->usernicelabel
= m
->nicelabel
= nicelabel
;
1977 if (SameDomainLabel(m
->p
->userhostlabel
.c
, hostlabel
.c
))
1978 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
1981 debugf("Updating m->hostlabel to %#s", hostlabel
.c
);
1982 m
->p
->userhostlabel
= m
->hostlabel
= hostlabel
;
1986 return(mStatus_NoError
);
1989 // returns count of non-link local V4 addresses registered
1990 mDNSlocal
int SetupActiveInterfaces(mDNS
*const m
)
1992 NetworkInterfaceInfoOSX
*i
;
1994 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1997 NetworkInterfaceInfo
*n
= &i
->ifinfo
;
1998 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(m
, i
->ifa_name
, i
->sa_family
);
1999 if (!primary
) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i
->ifa_name
);
2001 if (n
->InterfaceID
&& n
->InterfaceID
!= (mDNSInterfaceID
)primary
) // Sanity check
2003 LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != primary %p", n
->InterfaceID
, primary
);
2004 n
->InterfaceID
= mDNSNULL
;
2007 if (!n
->InterfaceID
)
2009 // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
2010 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
2011 // If n->InterfaceID is NOT set, then we haven't registered it and we should not try to deregister it
2012 n
->InterfaceID
= (mDNSInterfaceID
)primary
;
2013 mDNS_RegisterInterface(m
, n
);
2014 if (i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
&& (i
->ifinfo
.ip
.ip
.v4
.b
[0] != 169 || i
->ifinfo
.ip
.ip
.v4
.b
[1] != 254)) count
++;
2015 LogOperation("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p %#a/%#a%s",
2016 i
->ifa_name
, i
->scope_id
, &i
->BSSID
, primary
, &n
->ip
, &n
->mask
, n
->InterfaceActive
? " (Primary)" : "");
2020 debugf("SetupActiveInterfaces: No Tx/Rx on %5s(%lu) %.6a InterfaceID %p %#a", i
->ifa_name
, i
->scope_id
, &i
->BSSID
, primary
, &n
->ip
);
2023 if (i
->sa_family
== AF_INET
&& primary
->ss
.sktv4
== -1)
2025 mStatus err
= SetupSocket(m
, &primary
->ss
, mDNStrue
, &i
->ifinfo
.ip
, AF_INET
);
2026 if (err
== 0) debugf("SetupActiveInterfaces: v4 socket%2d %5s(%lu) %.6a InterfaceID %p %#a", primary
->ss
.sktv4
, i
->ifa_name
, i
->scope_id
, &i
->BSSID
, n
->InterfaceID
, &n
->ip
);
2027 else LogMsg("SetupActiveInterfaces: v4 socket%2d %5s(%lu) %.6a InterfaceID %p %#a FAILED", primary
->ss
.sktv4
, i
->ifa_name
, i
->scope_id
, &i
->BSSID
, n
->InterfaceID
, &n
->ip
);
2030 if (i
->sa_family
== AF_INET6
&& primary
->ss
.sktv6
== -1)
2032 mStatus err
= SetupSocket(m
, &primary
->ss
, mDNStrue
, &i
->ifinfo
.ip
, AF_INET6
);
2033 if (err
== 0) debugf("SetupActiveInterfaces: v6 socket%2d %5s(%lu) %.6a InterfaceID %p %#a", primary
->ss
.sktv6
, i
->ifa_name
, i
->scope_id
, &i
->BSSID
, n
->InterfaceID
, &n
->ip
);
2034 else LogMsg("SetupActiveInterfaces: v6 socket%2d %5s(%lu) %.6a InterfaceID %p %#a FAILED", primary
->ss
.sktv6
, i
->ifa_name
, i
->scope_id
, &i
->BSSID
, n
->InterfaceID
, &n
->ip
);
2041 mDNSlocal
void MarkAllInterfacesInactive(mDNS
*const m
)
2043 NetworkInterfaceInfoOSX
*i
;
2044 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2045 i
->Exists
= mDNSfalse
;
2048 mDNSlocal
void CloseRunLoopSourceSocket(CFRunLoopSourceRef rls
, CFSocketRef cfs
)
2050 // Comments show retain counts (obtained via CFGetRetainCount()) after each call. rls 3 cfs 3
2051 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
); // rls 2 cfs 3
2052 CFRelease(rls
); // rls ? cfs 3
2053 CFSocketInvalidate(cfs
); // rls ? cfs 1
2054 CFRelease(cfs
); // rls ? cfs ?
2057 mDNSlocal
void CloseSocketSet(CFSocketSet
*ss
)
2059 // Note: MUST NOT close the underlying native BSD sockets.
2060 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately,
2061 // because it first has to unhook the sockets from its select() call, before it can safely close them.
2062 if (ss
->cfsv4
) CloseRunLoopSourceSocket(ss
->rlsv4
, ss
->cfsv4
);
2063 if (ss
->cfsv6
) CloseRunLoopSourceSocket(ss
->rlsv6
, ss
->cfsv6
);
2064 ss
->sktv4
= ss
->sktv6
= -1;
2065 ss
->cfsv4
= ss
->cfsv6
= NULL
;
2066 ss
->rlsv4
= ss
->rlsv6
= NULL
;
2069 // returns count of non-link local V4 addresses deregistered
2070 mDNSlocal
int ClearInactiveInterfaces(mDNS
*const m
)
2073 // If an interface is going away, then deregister this from the mDNSCore.
2074 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
2075 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
2076 // it refers to has gone away we'll crash.
2077 // Don't actually close the sockets or free the memory yet: When the last representative of an interface goes away
2078 // mDNSCore may want to send goodbye packets on that interface. (Not yet implemented, but a good idea anyway.)
2079 NetworkInterfaceInfoOSX
*i
;
2081 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2083 // 1. If this interface is no longer active, or its InterfaceID is changing, deregister it
2084 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(m
, i
->ifa_name
, i
->sa_family
);
2085 if (i
->ifinfo
.InterfaceID
)
2086 if (i
->Exists
== 0 || i
->Exists
== 2 || i
->ifinfo
.InterfaceID
!= (mDNSInterfaceID
)primary
)
2088 LogOperation("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p %#a%s",
2089 i
->ifa_name
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
, &i
->ifinfo
.ip
, i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
2090 mDNS_DeregisterInterface(m
, &i
->ifinfo
);
2091 if (i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
&& (i
->ifinfo
.ip
.ip
.v4
.b
[0] != 169 || i
->ifinfo
.ip
.ip
.v4
.b
[1] != 254)) count
++;
2092 i
->ifinfo
.InterfaceID
= mDNSNULL
;
2093 // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
2094 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
2095 // If n->InterfaceID is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
2100 // Now that everything that's going to deregister has done so, we can close sockets and free the memory
2101 NetworkInterfaceInfoOSX
**p
= &m
->p
->InterfaceList
;
2105 // 2. Close all our CFSockets. We'll recreate them later as necessary.
2106 // (We may have previously had both v4 and v6, and we may not need both any more.)
2107 CloseSocketSet(&i
->ss
);
2108 // 3. If no longer active, delete interface from list and free memory
2109 if (!i
->Exists
&& NumCacheRecordsForInterfaceID(m
, (mDNSInterfaceID
)i
) == 0)
2111 debugf("ClearInactiveInterfaces: Deleting %#a", &i
->ifinfo
.ip
);
2113 if (i
->ifa_name
) freeL("NetworkInterfaceInfoOSX name", i
->ifa_name
);
2114 freeL("NetworkInterfaceInfoOSX", i
);
2122 mDNSlocal mStatus
RegisterSplitDNS(mDNS
*m
)
2124 #ifndef MAC_OS_X_VERSION_10_4
2125 static int MessageShown
= 0;
2127 if (!MessageShown
) { MessageShown
= 1; LogMsg("Note: Compiled without Apple-specific split DNS support"); }
2128 return mStatus_UnsupportedErr
;
2131 dns_config_t
*config
= dns_configuration_copy();
2135 // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
2136 if (mDNSMacOSXSystemBuildNumber(NULL
) < 8) return mStatus_UnsupportedErr
;
2138 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
2139 // Apparently this is expected behaviour -- "not a bug".
2140 // Accordingly, we suppress syslog messages for the first three minutes after boot.
2141 // If we are still getting failures after three minutes, then we log them.
2142 if ((mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return mStatus_UnknownErr
;
2144 LogMsg("RegisterSplitDNS: Error: dns_configuration_copy returned NULL");
2145 return mStatus_UnknownErr
;
2147 mDNS_DeleteDNSServers(m
);
2149 LogOperation("RegisterSplitDNS: Registering %d resolvers", config
->n_resolver
);
2150 for (i
= 0; i
< config
->n_resolver
; i
++)
2154 dns_resolver_t
*r
= config
->resolver
[i
];
2155 if (r
->port
== MulticastDNSPort
.NotAnInteger
) continue; // ignore configurations for .local
2156 if (r
->search_order
== DEFAULT_SEARCH_ORDER
|| !r
->domain
|| !*r
->domain
) d
.c
[0] = 0; // we ignore domain for "default" resolver
2157 else if (!MakeDomainNameFromDNSNameString(&d
, r
->domain
)) { LogMsg("RegisterSplitDNS: bad domain %s", r
->domain
); continue; }
2159 // check if this is the lowest-weighted server for the domain
2160 for (j
= 0; j
< config
->n_resolver
; j
++)
2162 dns_resolver_t
*p
= config
->resolver
[j
];
2163 if (p
->port
== MulticastDNSPort
.NotAnInteger
) continue;
2164 if (p
->search_order
<= r
->search_order
)
2167 if (p
->search_order
== DEFAULT_SEARCH_ORDER
|| !p
->domain
|| !*p
->domain
) tmp
.c
[0] = '\0';
2168 else if (!MakeDomainNameFromDNSNameString(&tmp
, p
->domain
)) { LogMsg("RegisterSplitDNS: bad domain %s", p
->domain
); continue; }
2169 if (SameDomainName(&d
, &tmp
))
2170 if (p
->search_order
< r
->search_order
|| j
< i
) break; // if equal weights, pick first in list, otherwise pick lower-weight (p)
2173 if (j
< config
->n_resolver
) // found a lower-weighted resolver for this domain
2174 { debugf("Rejecting DNS server in slot %d domain %##s (slot %d outranks)", i
, d
.c
, j
); continue; }
2175 // we're using this resolver - find the first IPv4 address
2176 for (n
= 0; n
< r
->n_nameserver
; n
++)
2178 if (r
->nameserver
[n
]->sa_family
== AF_INET
)
2181 if (SetupAddr(&saddr
, r
->nameserver
[n
])) { LogMsg("RegisterSplitDNS: bad IP address"); continue; }
2182 debugf("Adding dns server from slot %d %d.%d.%d.%d for domain %##s", i
, saddr
.ip
.v4
.b
[0], saddr
.ip
.v4
.b
[1], saddr
.ip
.v4
.b
[2], saddr
.ip
.v4
.b
[3], d
.c
);
2183 mDNS_AddDNSServer(m
, &saddr
, &d
);
2184 break; // !!!KRS if we ever support round-robin servers, don't break here
2188 dns_configuration_free(config
);
2189 return mStatus_NoError
;
2193 mDNSlocal mStatus
RegisterNameServers(mDNS
*const m
, CFDictionaryRef dict
)
2198 mDNSAddr saddr
= { mDNSAddrType_IPv4
, { { { 0 } } } };
2201 mDNS_DeleteDNSServers(m
); // deregister orig list
2202 values
= CFDictionaryGetValue(dict
, kSCPropNetDNSServerAddresses
);
2203 if (!values
) return mStatus_NoError
;
2205 count
= CFArrayGetCount(values
);
2206 for (i
= 0; i
< count
; i
++)
2208 s
= CFArrayGetValueAtIndex(values
, i
);
2209 if (!s
) { LogMsg("ERROR: RegisterNameServers - CFArrayGetValueAtIndex"); break; }
2210 if (!CFStringGetCString(s
, buf
, 256, kCFStringEncodingUTF8
))
2212 LogMsg("ERROR: RegisterNameServers - CFStringGetCString");
2215 if (!inet_aton(buf
, (struct in_addr
*)saddr
.ip
.v4
.b
))
2217 LogMsg("ERROR: RegisterNameServers - invalid address string %s", buf
);
2220 LogOperation("RegisterNameServers: Adding %#a", &saddr
);
2221 mDNS_AddDNSServer(m
, &saddr
, NULL
);
2223 return mStatus_NoError
;
2226 mDNSlocal
void FreeARElemCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
2229 ARListElem
*elem
= rr
->RecordContext
;
2230 if (result
== mStatus_MemFree
) freeL("FreeARElemCallback", elem
);
2233 mDNSlocal
void FoundDomain(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
2235 SearchListElem
*slElem
= question
->QuestionContext
;
2236 ARListElem
*arElem
, *ptr
, *prev
;
2243 arElem
= mallocL("FoundDomain - arElem", sizeof(ARListElem
));
2244 if (!arElem
) { LogMsg("ERROR: malloc"); return; }
2245 mDNS_SetupResourceRecord(&arElem
->ar
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, 7200, kDNSRecordTypeShared
, FreeARElemCallback
, arElem
);
2246 if (question
== &slElem
->BrowseQ
) name
= "_browse._dns-sd._udp.local.";
2247 else if (question
== &slElem
->DefBrowseQ
) name
= "_default._browse._dns-sd._udp.local.";
2248 else if (question
== &slElem
->LegacyBrowseQ
) name
= "_legacy._browse._dns-sd._udp.local.";
2249 else if (question
== &slElem
->RegisterQ
) name
= "_register._dns-sd._udp.local.";
2250 else if (question
== &slElem
->DefRegisterQ
) name
= "_default._register._dns-sd._udp.local.";
2251 else { LogMsg("FoundDomain - unknown question"); return; }
2253 MakeDomainNameFromDNSNameString(&arElem
->ar
.resrec
.name
, name
);
2254 AssignDomainName(arElem
->ar
.resrec
.rdata
->u
.name
, answer
->rdata
->u
.name
);
2255 err
= mDNS_Register(m
, &arElem
->ar
);
2258 LogMsg("ERROR: FoundDomain - mDNS_Register returned %d", err
);
2259 freeL("FoundDomain - arElem", arElem
);
2262 arElem
->next
= slElem
->AuthRecs
;
2263 slElem
->AuthRecs
= arElem
;
2267 ptr
= slElem
->AuthRecs
;
2271 if (SameDomainName(&ptr
->ar
.resrec
.rdata
->u
.name
, &answer
->rdata
->u
.name
))
2273 debugf("Deregistering PTR %s -> %s", ptr
->ar
.resrec
.name
.c
, ptr
->ar
.resrec
.rdata
->u
.name
.c
);
2275 if (prev
) prev
->next
= ptr
->next
;
2276 else slElem
->AuthRecs
= ptr
->next
;
2278 err
= mDNS_Deregister(m
, dereg
);
2279 if (err
) LogMsg("ERROR: FoundDomain - mDNS_Deregister returned %d", err
);
2290 mDNSlocal
void MarkSearchListElem(domainname
*domain
)
2292 SearchListElem
*new, *ptr
;
2294 // if domain is in list, mark as pre-existent (0)
2295 for (ptr
= SearchList
; ptr
; ptr
= ptr
->next
)
2296 if (SameDomainName(&ptr
->domain
, domain
))
2298 if (ptr
->flag
!= 1) ptr
->flag
= 0; // gracefully handle duplicates - if it is already marked as add, don't bump down to preexistent
2302 // if domain not in list, add to list, mark as add (1)
2305 new = mallocL("MarkSearchListElem - SearchListElem", sizeof(SearchListElem
));
2306 if (!new) { LogMsg("ERROR: MarkSearchListElem - malloc"); return; }
2307 bzero(new, sizeof(SearchListElem
));
2308 AssignDomainName(new->domain
, *domain
);
2309 new->flag
= 1; // add
2310 new->next
= SearchList
;
2315 mDNSlocal mStatus
RegisterSearchDomains(mDNS
*const m
, CFDictionaryRef dict
)
2317 struct ifaddrs
*ifa
= NULL
;
2320 char buf
[MAX_ESCAPED_DOMAIN_NAME
];
2322 SearchListElem
*ptr
, *prev
, *freeSLPtr
;
2326 // step 1: mark each elem for removal (-1), unless we aren't passed a dictionary in which case we mark as preexistent
2327 for (ptr
= SearchList
; ptr
; ptr
= ptr
->next
) ptr
->flag
= dict
? -1 : 0;
2329 // get all the domains from "Search Domains" field of sharing prefs
2332 CFArrayRef searchdomains
= CFDictionaryGetValue(dict
, kSCPropNetDNSSearchDomains
);
2335 count
= CFArrayGetCount(searchdomains
);
2336 for (i
= 0; i
< count
; i
++)
2338 s
= CFArrayGetValueAtIndex(searchdomains
, i
);
2339 if (!s
) { LogMsg("ERROR: RegisterSearchDomains - CFArrayGetValueAtIndex"); break; }
2340 if (!CFStringGetCString(s
, buf
, MAX_ESCAPED_DOMAIN_NAME
, kCFStringEncodingUTF8
))
2342 LogMsg("ERROR: RegisterSearchDomains - CFStringGetCString");
2345 if (!MakeDomainNameFromDNSNameString(&domain
, buf
))
2347 LogMsg("ERROR: RegisterSearchDomains - invalid search domain %s", buf
);
2350 MarkSearchListElem(&domain
);
2353 CFStringRef dname
= CFDictionaryGetValue(dict
, kSCPropNetDNSDomainName
);
2356 if (CFStringGetCString(dname
, buf
, MAX_ESCAPED_DOMAIN_NAME
, kCFStringEncodingUTF8
))
2358 if (MakeDomainNameFromDNSNameString(&domain
, buf
)) MarkSearchListElem(&domain
);
2359 else LogMsg("ERROR: RegisterSearchDomains - invalid domain %s", buf
);
2361 else LogMsg("ERROR: RegisterSearchDomains - CFStringGetCString");
2365 // Construct reverse-map search domains
2366 ifa
= myGetIfAddrs(1);
2370 if (ifa
->ifa_addr
->sa_family
== AF_INET
&& !SetupAddr(&addr
, ifa
->ifa_addr
) && !IsPrivateV4Addr(&addr
) && !(ifa
->ifa_flags
& IFF_LOOPBACK
) && ifa
->ifa_netmask
)
2374 if (!SetupAddr(&netmask
, ifa
->ifa_netmask
))
2376 sprintf(buffer
, "%d.%d.%d.%d.in-addr.arpa.", addr
.ip
.v4
.b
[3] & netmask
.ip
.v4
.b
[3],
2377 addr
.ip
.v4
.b
[2] & netmask
.ip
.v4
.b
[2],
2378 addr
.ip
.v4
.b
[1] & netmask
.ip
.v4
.b
[1],
2379 addr
.ip
.v4
.b
[0] & netmask
.ip
.v4
.b
[0]);
2380 MakeDomainNameFromDNSNameString(&domain
, buffer
);
2381 MarkSearchListElem(&domain
);
2384 ifa
= ifa
->ifa_next
;
2387 if (DynDNSRegDomain
.c
[0]) MarkSearchListElem(&DynDNSRegDomain
); // implicitly browse reg domain too (no-op if same as BrowseDomain)
2389 // delete elems marked for removal, do queries for elems marked add
2394 if (ptr
->flag
== -1) // remove
2396 mDNS_StopQuery(m
, &ptr
->BrowseQ
);
2397 mDNS_StopQuery(m
, &ptr
->RegisterQ
);
2398 mDNS_StopQuery(m
, &ptr
->DefBrowseQ
);
2399 mDNS_StopQuery(m
, &ptr
->DefRegisterQ
);
2400 mDNS_StopQuery(m
, &ptr
->LegacyBrowseQ
);
2402 // deregister records generated from answers to the query
2403 arList
= ptr
->AuthRecs
;
2404 ptr
->AuthRecs
= NULL
;
2407 AuthRecord
*dereg
= &arList
->ar
;
2408 arList
= arList
->next
;
2409 debugf("Deregistering PTR %s -> %s", dereg
->resrec
.name
.c
, dereg
->resrec
.rdata
->u
.name
.c
);
2410 err
= mDNS_Deregister(m
, dereg
);
2411 if (err
) LogMsg("ERROR: RegisterSearchDomains mDNS_Deregister returned %d", err
);
2414 // remove elem from list, delete
2415 if (prev
) prev
->next
= ptr
->next
;
2416 else SearchList
= ptr
->next
;
2419 freeL("RegisterSearchDomains - freeSLPtr", freeSLPtr
);
2423 if (ptr
->flag
== 1) // add
2425 mStatus err1
, err2
, err3
, err4
, err5
;
2426 err1
= mDNS_GetDomains(m
, &ptr
->BrowseQ
, mDNS_DomainTypeBrowse
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
2427 err2
= mDNS_GetDomains(m
, &ptr
->DefBrowseQ
, mDNS_DomainTypeBrowseDefault
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
2428 err3
= mDNS_GetDomains(m
, &ptr
->RegisterQ
, mDNS_DomainTypeRegistration
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
2429 err4
= mDNS_GetDomains(m
, &ptr
->DefRegisterQ
, mDNS_DomainTypeRegistrationDefault
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
2430 err5
= mDNS_GetDomains(m
, &ptr
->LegacyBrowseQ
, mDNS_DomainTypeBrowseLegacy
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
2431 if (err1
|| err2
|| err3
|| err4
|| err5
)
2432 LogMsg("GetDomains for domain %##s returned error(s):\n"
2433 "%d (mDNS_DomainTypeBrowse)\n"
2434 "%d (mDNS_DomainTypeBrowseDefault)\n"
2435 "%d (mDNS_DomainTypeRegistration)\n"
2436 "%d (mDNS_DomainTypeRegistrationDefault)"
2437 "%d (mDNS_DomainTypeBrowseLegacy)\n",
2438 ptr
->domain
.c
, err1
, err2
, err3
, err4
, err5
);
2442 if (ptr
->flag
) { LogMsg("RegisterSearchDomains - unknown flag %d. Skipping.", ptr
->flag
); }
2448 return mStatus_NoError
;
2451 //!!!KRS here is where we will give success/failure notification to the UI
2452 mDNSlocal
void SCPrefsDynDNSCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
2455 debugf("SCPrefsDynDNSCallback: result %d for registration of name %##s", result
, rr
->resrec
.name
.c
);
2456 SetDDNSNameStatus(&rr
->resrec
.name
, result
);
2459 mDNSlocal
void SetSecretForDomain(mDNS
*m
, const domainname
*domain
)
2462 SecKeychainRef SysKeychain
= NULL
;
2463 SecKeychainItemRef KeychainItem
;
2464 char dstring
[MAX_ESCAPED_DOMAIN_NAME
];
2466 void *secret
= NULL
;
2467 domainname
*d
, canon
;
2470 // canonicalize name by converting to lower case (keychain and some name servers are case sensitive)
2471 ConvertDomainNameToCString(domain
, dstring
);
2472 dlen
= strlen(dstring
);
2473 for (i
= 0; i
< dlen
; i
++) dstring
[i
] = tolower(dstring
[i
]); // canonicalize -> lower case
2474 MakeDomainNameFromDNSNameString(&canon
, dstring
);
2477 err
= SecKeychainOpen(SYS_KEYCHAIN_PATH
, &SysKeychain
);
2478 if (err
) { LogMsg("SetSecretForDomain: couldn't open system keychain (error %d)", err
); return; }
2479 // find longest-match key ("account") name, excluding last label (e.g. excluding ".com")
2480 while (d
->c
[0] && *(d
->c
+ d
->c
[0] + 1))
2482 if (!ConvertDomainNameToCString(d
, dstring
)) { LogMsg("SetSecretForDomain: bad domain %##s", d
->c
); return; }
2483 dlen
= strlen(dstring
);
2484 if (dstring
[dlen
-1] == '.') { dstring
[dlen
-1] = '\0'; dlen
--; } // chop trailing dot
2485 err
= SecKeychainFindGenericPassword(SysKeychain
, strlen(DYNDNS_KEYCHAIN_SERVICE
), DYNDNS_KEYCHAIN_SERVICE
, dlen
, dstring
, &secretlen
, &secret
, &KeychainItem
);
2488 debugf("Setting shared secret for zone %s with key %##s", dstring
, d
->c
);
2489 mDNS_SetSecretForZone(m
, d
, d
, secret
, secretlen
, mDNStrue
);
2493 if (err
== errSecItemNotFound
) d
= (domainname
*)(d
->c
+ d
->c
[0] + 1);
2496 if (err
== errSecNoSuchKeychain
) debugf("SetSecretForDomain: keychain not found");
2497 else LogMsg("SetSecretForDomain: SecKeychainFindGenericPassword returned error %d", err
);
2503 mDNSlocal
void DynDNSConfigChanged(mDNS
*const m
)
2505 static mDNSBool LegacyNATInitialized
= mDNSfalse
;
2506 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
2507 CFDictionaryRef dict
;
2509 domainname BrowseDomain
, RegDomain
, fqdn
;
2511 // get fqdn, zone from SCPrefs
2512 GetUserSpecifiedDDNSConfig(&fqdn
, &RegDomain
, &BrowseDomain
);
2513 if (!fqdn
.c
[0] && !RegDomain
.c
[0]) ReadDDNSSettingsFromConfFile(m
, CONFIG_FILE
, &fqdn
, &RegDomain
);
2515 if (!SameDomainName(&BrowseDomain
, &DynDNSBrowseDomain
))
2517 if (DynDNSBrowseDomain
.c
[0]) SetSCPrefsBrowseDomain(m
, &DynDNSBrowseDomain
, mDNSfalse
);
2518 AssignDomainName(DynDNSBrowseDomain
, BrowseDomain
);
2519 if (DynDNSBrowseDomain
.c
[0]) SetSCPrefsBrowseDomain(m
, &DynDNSBrowseDomain
, mDNStrue
);
2522 if (!SameDomainName(&RegDomain
, &DynDNSRegDomain
))
2524 if (DynDNSRegDomain
.c
[0]) RemoveDefRegDomain(&DynDNSRegDomain
);
2525 AssignDomainName(DynDNSRegDomain
, RegDomain
);
2526 if (DynDNSRegDomain
.c
[0]) { SetSecretForDomain(m
, &DynDNSRegDomain
); AddDefRegDomain(&DynDNSRegDomain
); }
2529 if (!SameDomainName(&fqdn
, &DynDNSHostname
))
2531 if (DynDNSHostname
.c
[0]) mDNS_RemoveDynDNSHostName(m
, &DynDNSHostname
);
2532 AssignDomainName(DynDNSHostname
, fqdn
);
2533 if (DynDNSHostname
.c
[0])
2535 SetSecretForDomain(m
, &fqdn
); // no-op if "zone" secret, above, is to be used for hostname
2536 mDNS_AddDynDNSHostName(m
, &DynDNSHostname
, SCPrefsDynDNSCallback
, NULL
);
2537 SetDDNSNameStatus(&DynDNSHostname
, 1);
2542 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:DynDNSConfigChanged"), NULL
, NULL
);
2545 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetDNS
);
2546 if (!key
) { LogMsg("ERROR: DNSConfigChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store
); return; }
2547 dict
= SCDynamicStoreCopyValue(store
, key
);
2550 // handle any changes to search domains and DNS server addresses
2551 if (RegisterSplitDNS(m
) != mStatus_NoError
)
2552 if (dict
) RegisterNameServers(m
, dict
); // fall back to non-split DNS aware configuration on failure
2553 RegisterSearchDomains(m
, dict
); // note that we register name servers *before* search domains
2554 if (dict
) CFRelease(dict
);
2556 // get IPv4 settings
2557 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
2558 if (!key
) { LogMsg("ERROR: RouterChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store
); return; }
2559 dict
= SCDynamicStoreCopyValue(store
, key
);
2563 { mDNS_SetPrimaryInterfaceInfo(m
, NULL
, NULL
); return; } // lost v4
2565 // handle router changes
2568 r
.type
= mDNSAddrType_IPv4
;
2569 r
.ip
.v4
.NotAnInteger
= 0;
2570 CFStringRef router
= CFDictionaryGetValue(dict
, kSCPropNetIPv4Router
);
2573 if (!CFStringGetCString(router
, buf
, 256, kCFStringEncodingUTF8
))
2574 LogMsg("Could not convert router to CString");
2575 else inet_aton(buf
, (struct in_addr
*)&r
.ip
.v4
);
2578 // handle primary interface changes
2579 CFStringRef primary
= CFDictionaryGetValue(dict
, kSCDynamicStorePropNetPrimaryInterface
);
2582 struct ifaddrs
*ifa
= myGetIfAddrs(1);
2584 if (!CFStringGetCString(primary
, buf
, 256, kCFStringEncodingUTF8
))
2585 { LogMsg("Could not convert router to CString"); goto error
; }
2587 // find primary interface in list
2590 if (ifa
->ifa_addr
->sa_family
== AF_INET
&& !strcmp(buf
, ifa
->ifa_name
))
2593 SetupAddr(&ip
, ifa
->ifa_addr
);
2594 if (ip
.ip
.v4
.b
[0] == 169 && ip
.ip
.v4
.b
[1] == 254)
2595 { mDNS_SetPrimaryInterfaceInfo(m
, NULL
, NULL
); break; } // primary IP is link-local
2596 if (ip
.ip
.v4
.NotAnInteger
!= u
->PrimaryIP
.ip
.v4
.NotAnInteger
||
2597 r
.ip
.v4
.NotAnInteger
!= u
->Router
.ip
.v4
.NotAnInteger
)
2599 if (LegacyNATInitialized
) { LegacyNATDestroy(); LegacyNATInitialized
= mDNSfalse
; }
2600 if (IsPrivateV4Addr(&ip
))
2602 mStatus err
= LegacyNATInit();
2603 if (err
) LogMsg("ERROR: LegacyNATInit");
2604 else LegacyNATInitialized
= mDNStrue
;
2606 mDNS_SetPrimaryInterfaceInfo(m
, &ip
, r
.ip
.v4
.NotAnInteger
? &r
: NULL
);
2610 ifa
= ifa
->ifa_next
;
2618 mDNSexport
void mDNSMacOSXNetworkChanged(mDNS
*const m
)
2620 LogOperation("*** Network Configuration Change ***");
2621 MarkAllInterfacesInactive(m
);
2622 UpdateInterfaceList(m
);
2623 int nDeletions
= ClearInactiveInterfaces(m
);
2624 int nAdditions
= SetupActiveInterfaces(m
);
2625 if (nDeletions
|| nAdditions
) mDNS_UpdateLLQs(m
);
2626 DynDNSConfigChanged(m
);
2628 if (m
->MainCallback
)
2629 m
->MainCallback(m
, mStatus_ConfigChanged
);
2632 mDNSlocal
void NetworkChanged(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *context
)
2634 (void)store
; // Parameter not used
2635 (void)changedKeys
; // Parameter not used
2636 LogOperation("*** NetworkChanged ***");
2637 mDNS
*const m
= (mDNS
*const)context
;
2639 m
->p
->NetworkChanged
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 2);
2640 if (!m
->SuppressSending
||
2641 m
->SuppressSending
- m
->p
->NetworkChanged
< 0)
2642 m
->SuppressSending
= m
->p
->NetworkChanged
;
2646 mDNSlocal mStatus
WatchForNetworkChanges(mDNS
*const m
)
2649 SCDynamicStoreContext context
= { 0, m
, NULL
, NULL
, NULL
};
2650 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged
, &context
);
2651 CFStringRef key1
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
2652 CFStringRef key2
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv6
);
2653 CFStringRef key3
= SCDynamicStoreKeyCreateComputerName(NULL
);
2654 CFStringRef key4
= SCDynamicStoreKeyCreateHostNames(NULL
);
2655 CFStringRef key5
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetDNS
);
2656 CFStringRef pattern1
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv4
);
2657 CFStringRef pattern2
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv6
);
2659 CFMutableArrayRef keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2660 CFMutableArrayRef patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2662 if (!store
) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error
; }
2663 if (!key1
|| !key2
|| !key3
|| !key4
|| !keys
|| !pattern1
|| !pattern2
|| !patterns
) goto error
;
2665 CFArrayAppendValue(keys
, key1
);
2666 CFArrayAppendValue(keys
, key2
);
2667 CFArrayAppendValue(keys
, key3
);
2668 CFArrayAppendValue(keys
, key4
);
2669 CFArrayAppendValue(keys
, key5
);
2670 CFArrayAppendValue(keys
, CFSTR("Setup:/Network/DynamicDNS"));
2671 CFArrayAppendValue(patterns
, pattern1
);
2672 CFArrayAppendValue(patterns
, pattern2
);
2673 CFArrayAppendValue(patterns
, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
2674 if (!SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
2675 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error
; }
2677 m
->p
->StoreRLS
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
2678 if (!m
->p
->StoreRLS
) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error
; }
2680 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
2681 m
->p
->Store
= store
;
2686 if (store
) CFRelease(store
);
2689 if (key1
) CFRelease(key1
);
2690 if (key2
) CFRelease(key2
);
2691 if (key3
) CFRelease(key3
);
2692 if (key4
) CFRelease(key4
);
2693 if (key5
) CFRelease(key5
);
2694 if (pattern1
) CFRelease(pattern1
);
2695 if (pattern2
) CFRelease(pattern2
);
2696 if (keys
) CFRelease(keys
);
2697 if (patterns
) CFRelease(patterns
);
2702 mDNSlocal
void PowerChanged(void *refcon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
2704 mDNS
*const m
= (mDNS
*const)refcon
;
2705 (void)service
; // Parameter not used
2708 case kIOMessageCanSystemPowerOff
: debugf("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
2709 case kIOMessageSystemWillPowerOff
: debugf("PowerChanged kIOMessageSystemWillPowerOff"); mDNSCoreMachineSleep(m
, true); break; // E0000250
2710 case kIOMessageSystemWillNotPowerOff
: debugf("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
2711 case kIOMessageCanSystemSleep
: debugf("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
2712 case kIOMessageSystemWillSleep
: debugf("PowerChanged kIOMessageSystemWillSleep"); mDNSCoreMachineSleep(m
, true); break; // E0000280
2713 case kIOMessageSystemWillNotSleep
: debugf("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
2714 case kIOMessageSystemHasPoweredOn
: debugf("PowerChanged kIOMessageSystemHasPoweredOn");
2715 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
2716 if (m
->SleepState
) mDNSCoreMachineSleep(m
, false);
2717 // Just to be safe, also make sure our interface list is fully up to date, in case we
2718 // haven't yet received the System Configuration Framework "network changed" event that
2719 // we expect to receive some time shortly after the kIOMessageSystemWillPowerOn message
2720 mDNSMacOSXNetworkChanged(m
); break; // E0000300
2721 case kIOMessageSystemWillRestart
: debugf("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
2722 case kIOMessageSystemWillPowerOn
: debugf("PowerChanged kIOMessageSystemWillPowerOn");
2723 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
2724 mDNSMacOSXNetworkChanged(m
); mDNSCoreMachineSleep(m
, false); break; // E0000320
2725 default: debugf("PowerChanged unknown message %X", messageType
); break;
2727 IOAllowPowerChange(m
->p
->PowerConnection
, (long)messageArgument
);
2730 mDNSlocal mStatus
WatchForPowerChanges(mDNS
*const m
)
2732 IONotificationPortRef thePortRef
;
2733 m
->p
->PowerConnection
= IORegisterForSystemPower(m
, &thePortRef
, PowerChanged
, &m
->p
->PowerNotifier
);
2734 if (m
->p
->PowerConnection
)
2736 m
->p
->PowerRLS
= IONotificationPortGetRunLoopSource(thePortRef
);
2737 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->PowerRLS
, kCFRunLoopDefaultMode
);
2738 return(mStatus_NoError
);
2743 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
2744 CF_EXPORT
const CFStringRef _kCFSystemVersionProductNameKey
;
2745 CF_EXPORT
const CFStringRef _kCFSystemVersionProductVersionKey
;
2746 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
2748 mDNSexport
int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring
)
2750 int major
= 0, minor
= 0;
2751 char letter
= 0, prodname
[256]="Mac OS X", prodvers
[256]="", buildver
[256]="?";
2752 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
2755 CFStringRef cfprodname
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductNameKey
);
2756 CFStringRef cfprodvers
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductVersionKey
);
2757 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
2758 if (cfprodname
) CFStringGetCString(cfprodname
, prodname
, sizeof(prodname
), kCFStringEncodingUTF8
);
2759 if (cfprodvers
) CFStringGetCString(cfprodvers
, prodvers
, sizeof(prodvers
), kCFStringEncodingUTF8
);
2760 if (cfbuildver
) CFStringGetCString(cfbuildver
, buildver
, sizeof(buildver
), kCFStringEncodingUTF8
);
2761 sscanf(buildver
, "%d%c%d", &major
, &letter
, &minor
);
2764 if (HINFO_SWstring
) mDNS_snprintf(HINFO_SWstring
, 256, "%s %s (%s), %s", prodname
, prodvers
, buildver
, mDNSResponderVersionString
);
2768 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
2769 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
2770 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
2771 mDNSlocal mDNSBool
mDNSPlatformInit_CanReceiveUnicast(void)
2774 int s
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
2776 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s
, errno
, strerror(errno
));
2779 struct sockaddr_in s5353
;
2780 s5353
.sin_family
= AF_INET
;
2781 s5353
.sin_port
= MulticastDNSPort
.NotAnInteger
;
2782 s5353
.sin_addr
.s_addr
= 0;
2783 err
= bind(s
, (struct sockaddr
*)&s5353
, sizeof(s5353
));
2787 if (err
) LogMsg("No unicast UDP responses");
2788 else debugf("Unicast UDP responses okay");
2792 // Callback for the _legacy._browse queries - add answer to list of domains to search for empty-string browses
2793 mDNSlocal
void FoundDefBrowseDomain(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
2795 DNameListElem
*ptr
, *prev
, *new;
2797 (void)question
; // unused
2801 new = mallocL("FoundDefBrowseDomain", sizeof(DNameListElem
));
2802 if (!new) { LogMsg("ERROR: malloc"); return; }
2803 AssignDomainName(new->name
, answer
->rdata
->u
.name
);
2804 new->next
= DefBrowseList
;
2805 DefBrowseList
= new;
2806 DefaultBrowseDomainChanged(&new->name
, mDNStrue
);
2807 udsserver_default_browse_domain_changed(&new->name
, mDNStrue
);
2812 ptr
= DefBrowseList
;
2816 if (SameDomainName(&ptr
->name
, &answer
->rdata
->u
.name
))
2818 DefaultBrowseDomainChanged(&ptr
->name
, mDNSfalse
);
2819 udsserver_default_browse_domain_changed(&ptr
->name
, mDNSfalse
);
2820 if (prev
) prev
->next
= ptr
->next
;
2821 else DefBrowseList
= ptr
->next
;
2822 freeL("FoundDefBrowseDomain", ptr
);
2828 LogMsg("FoundDefBrowseDomain: Got remove event for domain %s not in list", answer
->rdata
->u
.name
.c
);
2832 // Add or remove a user-specified domain to the list of empty-string browse domains
2833 // Also register a non-legacy _browse PTR record so that the domain appears in enumeration lists
2834 mDNSlocal
void SetSCPrefsBrowseDomain(mDNS
*m
, const domainname
*d
, mDNSBool add
)
2838 // Create dummy record pointing to the domain to be added/removed
2839 mDNS_SetupResourceRecord(&rec
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, 7200, kDNSRecordTypeShared
, mDNSNULL
, mDNSNULL
);
2840 AssignDomainName(rec
.resrec
.rdata
->u
.name
, *d
);
2842 // add/remove the "_legacy" entry
2843 MakeDomainNameFromDNSNameString(&rec
.resrec
.name
, "_legacy._browse._dns-sd._udp.local.");
2844 FoundDefBrowseDomain(m
, &LegacyBrowseDomainQ
, &rec
.resrec
, add
);
2848 // allocate/register a non-legacy _browse PTR record
2849 ARListElem
*ptr
= mallocL("ARListElem", sizeof(*ptr
));
2850 mDNS_SetupResourceRecord(&ptr
->ar
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, 7200, kDNSRecordTypeShared
, FreeARElemCallback
, ptr
);
2851 MakeDomainNameFromDNSNameString(&ptr
->ar
.resrec
.name
, "_browse._dns-sd._udp.local.");
2852 AssignDomainName(ptr
->ar
.resrec
.rdata
->u
.name
, *d
);
2853 mStatus err
= mDNS_Register(m
, &ptr
->ar
);
2856 LogMsg("SetSCPrefsBrowseDomain: mDNS_Register returned error %d", err
);
2857 freeL("ARListElem", ptr
);
2861 ptr
->next
= SCPrefBrowseDomains
;
2862 SCPrefBrowseDomains
= ptr
;
2867 ARListElem
**remove
= &SCPrefBrowseDomains
;
2868 while (*remove
&& !SameDomainName(&(*remove
)->ar
.resrec
.rdata
->u
.name
, d
)) remove
= &(*remove
)->next
;
2869 if (!*remove
) { LogMsg("SetSCPrefsBrowseDomain (remove) - domain %##s not found!", d
->c
); return; }
2870 mDNS_Deregister(m
, &(*remove
)->ar
);
2871 *remove
= (*remove
)->next
;
2876 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
2877 // 1) query for _browse._dns-sd._udp.local on LocalOnly interface
2878 // (.local manually generated via explicit callback)
2879 // 2) for each search domain (from prefs pane), query for _browse._dns-sd._udp.<searchdomain>.
2880 // 3) for each result from (2), register LocalOnly PTR record_browse._dns-sd._udp.local. -> <result>
2881 // 4) result above should generate a callback from question in (1). result added to global list
2882 // 5) global list delivered to client via GetSearchDomainList()
2883 // 6) client calls to enumerate domains now go over LocalOnly interface
2884 // (!!!KRS may add outgoing interface in addition)
2886 mDNSlocal mStatus
InitDNSConfig(mDNS
*const m
)
2890 // start query for domains to be used in default (empty string domain) browses
2891 err
= mDNS_GetDomains(m
, &LegacyBrowseDomainQ
, mDNS_DomainTypeBrowseLegacy
, NULL
, mDNSInterface_LocalOnly
, FoundDefBrowseDomain
, NULL
);
2893 // provide .local automatically
2894 SetSCPrefsBrowseDomain(m
, &localdomain
, mDNStrue
);
2895 return mStatus_NoError
;
2898 mDNSlocal mStatus
mDNSPlatformInit_setup(mDNS
*const m
)
2902 m
->hostlabel
.c
[0] = 0;
2904 char *HINFO_HWstring
= "Macintosh";
2905 char HINFO_HWstring_buffer
[256];
2906 int get_model
[2] = { CTL_HW
, HW_MODEL
};
2907 size_t len_model
= sizeof(HINFO_HWstring_buffer
);
2908 if (sysctl(get_model
, 2, HINFO_HWstring_buffer
, &len_model
, NULL
, 0) == 0)
2909 HINFO_HWstring
= HINFO_HWstring_buffer
;
2911 char HINFO_SWstring
[256] = "";
2912 if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring
) < 7) m
->KnownBugs
|= mDNS_KnownBug_PhantomInterfaces
;
2913 if (mDNSPlatformInit_CanReceiveUnicast()) m
->CanReceiveUnicastOn5353
= mDNStrue
;
2915 mDNSu32 hlen
= mDNSPlatformStrLen(HINFO_HWstring
);
2916 mDNSu32 slen
= mDNSPlatformStrLen(HINFO_SWstring
);
2917 if (hlen
+ slen
< 254)
2919 m
->HIHardware
.c
[0] = hlen
;
2920 m
->HISoftware
.c
[0] = slen
;
2921 mDNSPlatformMemCopy(HINFO_HWstring
, &m
->HIHardware
.c
[1], hlen
);
2922 mDNSPlatformMemCopy(HINFO_SWstring
, &m
->HISoftware
.c
[1], slen
);
2925 m
->p
->unicastsockets
.m
= m
;
2926 m
->p
->unicastsockets
.info
= NULL
;
2927 m
->p
->unicastsockets
.sktv4
= m
->p
->unicastsockets
.sktv6
= -1;
2928 m
->p
->unicastsockets
.cfsv4
= m
->p
->unicastsockets
.cfsv6
= NULL
;
2929 m
->p
->unicastsockets
.rlsv4
= m
->p
->unicastsockets
.rlsv6
= NULL
;
2931 err
= SetupSocket(m
, &m
->p
->unicastsockets
, mDNSfalse
, &zeroAddr
, AF_INET
);
2932 err
= SetupSocket(m
, &m
->p
->unicastsockets
, mDNSfalse
, &zeroAddr
, AF_INET6
);
2934 struct sockaddr_in s4
;
2935 struct sockaddr_in6 s6
;
2936 int n4
= sizeof(s4
);
2937 int n6
= sizeof(s6
);
2938 if (getsockname(m
->p
->unicastsockets
.sktv4
, (struct sockaddr
*)&s4
, &n4
) < 0) LogMsg("getsockname v4 error %d (%s)", errno
, strerror(errno
));
2939 else m
->UnicastPort4
.NotAnInteger
= s4
.sin_port
;
2940 if (getsockname(m
->p
->unicastsockets
.sktv6
, (struct sockaddr
*)&s6
, &n6
) < 0) LogMsg("getsockname v6 error %d (%s)", errno
, strerror(errno
));
2941 else m
->UnicastPort6
.NotAnInteger
= s6
.sin6_port
;
2943 m
->p
->InterfaceList
= mDNSNULL
;
2944 m
->p
->userhostlabel
.c
[0] = 0;
2945 m
->p
->usernicelabel
.c
[0] = 0;
2946 m
->p
->NotifyUser
= 0;
2947 UpdateInterfaceList(m
);
2948 SetupActiveInterfaces(m
);
2950 err
= WatchForNetworkChanges(m
);
2951 if (err
) return(err
);
2953 err
= WatchForPowerChanges(m
);
2954 if (err
) return err
;
2956 DynDNSRegDomain
.c
[0] = '\0';
2957 DynDNSBrowseDomain
.c
[0] = '\0';
2958 DynDNSConfigChanged(m
); // Get initial DNS configuration
2964 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
2966 mStatus result
= mDNSPlatformInit_setup(m
);
2968 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
2969 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
2970 if (result
== mStatus_NoError
) mDNSCoreInitComplete(m
, mStatus_NoError
);
2974 mDNSexport
void mDNSPlatformClose(mDNS
*const m
)
2976 if (m
->p
->PowerConnection
)
2978 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->PowerRLS
, kCFRunLoopDefaultMode
);
2979 CFRunLoopSourceInvalidate(m
->p
->PowerRLS
);
2980 CFRelease(m
->p
->PowerRLS
);
2981 IODeregisterForSystemPower(&m
->p
->PowerNotifier
);
2982 m
->p
->PowerConnection
= 0;
2983 m
->p
->PowerNotifier
= 0;
2984 m
->p
->PowerRLS
= NULL
;
2989 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
2990 CFRunLoopSourceInvalidate(m
->p
->StoreRLS
);
2991 CFRelease(m
->p
->StoreRLS
);
2992 CFRelease(m
->p
->Store
);
2994 m
->p
->StoreRLS
= NULL
;
2997 MarkAllInterfacesInactive(m
);
2998 ClearInactiveInterfaces(m
);
2999 CloseSocketSet(&m
->p
->unicastsockets
);
3002 mDNSexport mDNSu32
mDNSPlatformRandomSeed(void)
3004 return(mach_absolute_time());
3007 mDNSexport mDNSs32 mDNSPlatformOneSecond
= 1000;
3009 mDNSexport mStatus
mDNSPlatformTimeInit(void)
3011 // Notes: Typical values for mach_timebase_info:
3012 // tbi.numer = 1000 million
3013 // tbi.denom = 33 million
3014 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
3015 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
3016 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
3017 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
3018 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
3020 // Arithmetic notes:
3021 // tbi.denom is at least 1, and not more than 2^32-1.
3022 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
3023 // tbi.denom is at least 1, and not more than 2^32-1.
3024 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
3025 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
3026 // which is unlikely on any current or future Macintosh.
3027 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
3028 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
3029 struct mach_timebase_info tbi
;
3030 kern_return_t result
= mach_timebase_info(&tbi
);
3031 if (result
== KERN_SUCCESS
) clockdivisor
= ((uint64_t)tbi
.denom
* 1000000) / tbi
.numer
;
3035 mDNSexport mDNSs32
mDNSPlatformRawTime(void)
3037 if (clockdivisor
== 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
3039 static uint64_t last_mach_absolute_time
= 0;
3040 uint64_t this_mach_absolute_time
= mach_absolute_time();
3041 if ((int64_t)this_mach_absolute_time
- (int64_t)last_mach_absolute_time
< 0)
3043 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time
);
3044 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time
);
3045 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
3046 last_mach_absolute_time
= this_mach_absolute_time
;
3047 NotifyOfElusiveBug("mach_absolute_time went backwards!", 3438376, "");
3049 last_mach_absolute_time
= this_mach_absolute_time
;
3051 return((mDNSs32
)(this_mach_absolute_time
/ clockdivisor
));
3054 mDNSexport mDNSs32
mDNSPlatformUTC(void)
3059 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
3060 mDNSexport
void mDNSPlatformLock (const mDNS
*const m
) { (void)m
; }
3061 mDNSexport
void mDNSPlatformUnlock (const mDNS
*const m
) { (void)m
; }
3062 mDNSexport
void mDNSPlatformStrCopy(const void *src
, void *dst
) { strcpy((char *)dst
, (char *)src
); }
3063 mDNSexport mDNSu32
mDNSPlatformStrLen (const void *src
) { return(strlen((char*)src
)); }
3064 mDNSexport
void mDNSPlatformMemCopy(const void *src
, void *dst
, mDNSu32 len
) { memcpy(dst
, src
, len
); }
3065 mDNSexport mDNSBool
mDNSPlatformMemSame(const void *src
, const void *dst
, mDNSu32 len
) { return(memcmp(dst
, src
, len
) == 0); }
3066 mDNSexport
void mDNSPlatformMemZero( void *dst
, mDNSu32 len
) { bzero(dst
, len
); }
3067 mDNSexport
void * mDNSPlatformMemAllocate(mDNSu32 len
) { return(mallocL("mDNSPlatformMemAllocate", len
)); }
3068 mDNSexport
void mDNSPlatformMemFree (void *mem
) { freeL("mDNSPlatformMemFree", mem
); }