]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/mDNSMacOSX.c
mDNSResponder-98.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / mDNSMacOSX.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
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
12 * file.
13 *
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.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23
24 Change History (most recent first):
25
26 $Log: mDNSMacOSX.c,v $
27 Revision 1.294 2005/01/27 21:30:23 cheshire
28 <rdar://problem/3952067> "Can't assign requested address" message after AirPort turned off
29 Don't write syslog messages for EADDRNOTAVAIL if we know network configuration changes are happening
30
31 Revision 1.293 2005/01/27 19:15:41 cheshire
32 Remove extraneous LogMsg() call
33
34 Revision 1.292 2005/01/27 17:48:38 cheshire
35 Added comment about CFSocketInvalidate closing the underlying socket
36
37 Revision 1.291 2005/01/27 00:10:58 cheshire
38 <rdar://problem/3967867> Name change log messages every time machine boots
39
40 Revision 1.290 2005/01/25 23:18:30 ksekar
41 fix for <rdar://problem/3971467> requires that local-only ".local" registration record be created
42
43 Revision 1.289 2005/01/25 18:08:31 ksekar
44 Removed redundant debug output
45
46 Revision 1.288 2005/01/25 17:42:26 ksekar
47 Renamed FoundDefBrowseDomain -> FoundLegacyBrowseDomain,
48 cleaned up duplicate log messages when adding/removing browse domains
49
50 Revision 1.287 2005/01/25 16:59:23 ksekar
51 <rdar://problem/3971138> sa_len not set checking reachability for TCP connections
52
53 Revision 1.286 2005/01/25 02:02:37 cheshire
54 <rdar://problem/3970673> mDNSResponder leaks
55 GetSearchDomains() was not calling dns_configuration_free().
56
57 Revision 1.285 2005/01/22 00:07:54 ksekar
58 <rdar://problem/3960546> mDNSResponder should look at all browse domains in SCPreferences
59
60 Revision 1.284 2005/01/21 23:07:17 ksekar
61 <rdar://problem/3960795> mDNSResponder causes Dial on Demand
62
63 Revision 1.283 2005/01/19 21:16:16 cheshire
64 Make sure when we set NetworkChanged that we don't set it to zero
65
66 Revision 1.282 2005/01/19 19:19:21 ksekar
67 <rdar://problem/3960191> Need a way to turn off domain discovery
68
69 Revision 1.281 2005/01/18 18:10:55 ksekar
70 <rdar://problem/3954575> Use 10.4 resolver API to get search domains
71
72 Revision 1.280 2005/01/17 22:48:52 ksekar
73 No longer need to call MarkSearchListElem for registration domain
74
75 Revision 1.279 2005/01/17 20:40:34 ksekar
76 SCPreferences changes should remove exactly one browse and one legacy browse domain for each remove event
77
78 Revision 1.278 2005/01/17 19:53:34 ksekar
79 Refinement to previous fix - register _legacy._browse records for SCPreference domains to achieve correct reference counting
80
81 Revision 1.277 2005/01/12 00:17:50 ksekar
82 <rdar://problem/3933573> Update LLQs *after* setting DNS
83
84 Revision 1.276 2005/01/10 17:39:10 ksekar
85 Refinement to 1.272 - avoid spurious warnings when registration and browse domains are set to same value and toggled on/off
86
87 Revision 1.275 2005/01/10 04:02:22 ksekar
88 Refinement to <rdar://problem/3891628> - strip trailing dot before writing hostname status to dynamic store
89
90 Revision 1.274 2005/01/10 03:41:36 ksekar
91 Correction to checkin 1.272 - check that registration domain is set
92 before trying to remove it as an implicit browse domain
93
94 Revision 1.273 2005/01/08 00:42:18 ksekar
95 <rdar://problem/3922758> Clean up syslog messages
96
97 Revision 1.272 2005/01/07 23:21:42 ksekar
98 <rdar://problem/3891628> Clean up SCPreferences format
99
100 Revision 1.271 2004/12/20 23:18:12 cheshire
101 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
102 One more refinement: When an interface with a v6LL address gets a v4 address too, that's not a flap
103
104 Revision 1.270 2004/12/20 21:28:14 cheshire
105 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
106 Additional refinements to handle sleep/wake better
107
108 Revision 1.269 2004/12/20 20:48:11 cheshire
109 Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xxx) or later
110
111 Revision 1.268 2004/12/18 03:19:04 cheshire
112 Show netmask in error log
113
114 Revision 1.267 2004/12/18 00:51:52 cheshire
115 Use symbolic constant kDNSServiceInterfaceIndexLocalOnly instead of (mDNSu32) ~0
116
117 Revision 1.266 2004/12/17 23:49:38 cheshire
118 <rdar://problem/3922754> Computer Name change is slow
119 Also treat changes to "Setup:/Network/DynamicDNS" the same way
120
121 Revision 1.265 2004/12/17 23:37:47 cheshire
122 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
123 (and other repetitive configuration changes)
124
125 Revision 1.264 2004/12/17 19:03:05 cheshire
126 Update debugging messages to show netmask a simple CIDR-style numeric value (0-128)
127
128 Revision 1.263 2004/12/17 05:25:46 cheshire
129 <rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
130
131 Revision 1.262 2004/12/17 04:48:32 cheshire
132 <rdar://problem/3922754> Computer Name change is slow
133
134 Revision 1.261 2004/12/17 02:40:08 cheshire
135 Undo last change -- it was too strict
136
137 Revision 1.260 2004/12/16 22:17:16 cheshire
138 Only accept multicast packets on interfaces that have McastTxRx set
139
140 Revision 1.259 2004/12/16 20:13:01 cheshire
141 <rdar://problem/3324626> Cache memory management improvements
142
143 Revision 1.258 2004/12/14 00:18:05 cheshire
144 Don't log dns_configuration_copy() failures in the first three minutes after boot
145
146 Revision 1.257 2004/12/10 19:45:46 cheshire
147 <rdar://problem/3915074> Reduce egregious stack space usage
148 Reduced myCFSocketCallBack() stack frame from 9K to 512 bytes
149
150 Revision 1.256 2004/12/10 04:35:43 cheshire
151 <rdar://problem/3907233> Show "Note: Compiled without Apple-specific split DNS support" only once
152
153 Revision 1.255 2004/12/10 04:12:54 ksekar
154 <rdar://problem/3890764> Need new DefaultBrowseDomain key
155
156 Revision 1.254 2004/12/10 01:55:31 ksekar
157 <rdar://problem/3899067> Keychain lookups should be in lower case.
158
159 Revision 1.253 2004/12/09 03:15:41 ksekar
160 <rdar://problem/3806610> use _legacy instead of _default to find "empty string" browse domains
161
162 Revision 1.252 2004/12/07 01:32:42 cheshire
163 Don't log dns_configuration_copy() failure when running on 10.3
164
165 Revision 1.251 2004/12/06 22:30:31 cheshire
166 Added debugging log message
167
168 Revision 1.250 2004/12/06 06:59:08 ksekar
169 RegisterSplitDNS should return Unsupported error when compiled on Panther
170
171 Revision 1.249 2004/12/04 00:29:46 cheshire
172 Add "#ifdef MAC_OS_X_VERSION_10_4" around split-DNS code that can't be compiled on 10.3 systems
173 (When compiled on 10.3, code will not include split-DNS support.)
174
175 Revision 1.248 2004/12/01 20:57:20 ksekar
176 <rdar://problem/3873921> Wide Area Rendezvous must be split-DNS aware
177
178 Revision 1.247 2004/12/01 03:26:58 cheshire
179 Remove unused variables
180
181 Revision 1.246 2004/12/01 01:51:34 cheshire
182 Move ReadDDNSSettingsFromConfFile() from mDNSMacOSX.c to PlatformCommon.c
183
184 Revision 1.245 2004/11/30 03:24:04 cheshire
185 <rdar://problem/3854544> Defer processing network configuration changes until configuration has stabilized
186
187 Revision 1.244 2004/11/30 02:59:35 cheshire
188 For debugging diagnostics, added identifying strings in SCDynamicStoreCreate() calls
189
190 Revision 1.243 2004/11/29 19:17:29 ksekar
191 <rdar://problem/3878195> Unnecessary GetUserSpecifiedDDNSConfig log messages
192
193 Revision 1.242 2004/11/29 18:37:38 ksekar
194 <rdar://problem/3889341> Buffer overflow in GetConfigOption
195
196 Revision 1.241 2004/11/25 01:37:04 ksekar
197 <rdar://problem/3894854> Config file and SCPreferences don't play well together
198
199 Revision 1.240 2004/11/25 01:29:42 ksekar
200 Remove unnecessary log messages
201
202 Revision 1.239 2004/11/25 01:27:19 ksekar
203 <rdar://problem/3885859> Don't try to advertise link-local IP addresses via dynamic update
204
205 Revision 1.238 2004/11/24 22:00:59 cheshire
206 Move definition of mDNSAddressIsAllDNSLinkGroup() from mDNSMacOSX.c to mDNSEmbeddedAPI.h
207
208 Revision 1.237 2004/11/24 21:54:44 cheshire
209 <rdar://problem/3894475> mDNSCore not receiving unicast responses properly
210
211 Revision 1.236 2004/11/23 03:39:46 cheshire
212 Let interface name/index mapping capability live directly in JNISupport.c,
213 instead of having to call through to the daemon via IPC to get this information.
214
215 Revision 1.235 2004/11/17 01:45:35 cheshire
216 <rdar://problem/3847435> Rendezvous buddy list frequently becomes empty if you let the machine sleep
217 Refresh our interface list on receiving kIOMessageSystemHasPoweredOn,
218 in case we get no System Configuration Framework "network changed" event.
219
220 Revision 1.234 2004/11/17 00:32:56 ksekar
221 <rdar://problem/3880773> mDNSResponder will not discover zones contained both in Search Domains and DHCP Domain option
222
223 Revision 1.233 2004/11/12 03:16:45 rpantos
224 rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
225
226 Revision 1.232 2004/11/10 20:40:54 ksekar
227 <rdar://problem/3868216> LLQ mobility fragile on non-primary interface
228
229 Revision 1.231 2004/11/06 00:59:33 ksekar
230 Don't log ENETDOWN errors for unicast destinations (pollutes log on
231 wake from sleep)
232
233 Revision 1.230 2004/11/05 01:04:10 ksekar
234 <rdar://problem/3774577> LegacyNATDestroy() called too enthusiastically
235
236 Revision 1.229 2004/11/03 03:45:16 cheshire
237 <rdar://problem/3863627> mDNSResponder does not inform user of Computer Name collisions
238
239 Revision 1.228 2004/11/02 23:47:32 cheshire
240 <rdar://problem/3863214> Default hostname and Computer Name should be unique
241
242 Revision 1.227 2004/11/02 04:23:03 cheshire
243 Change to more informative name "GetUserSpecifiedLocalHostName()"
244
245 Revision 1.226 2004/11/01 20:36:19 ksekar
246 <rdar://problem/3802395> mDNSResponder should not receive Keychain Notifications
247
248 Revision 1.225 2004/10/28 19:03:04 cheshire
249 Remove \n from LogMsg() calls
250
251 Revision 1.224 2004/10/28 17:47:34 cheshire
252 Oops. Forgot the %d in the log message.
253
254 Revision 1.223 2004/10/28 17:24:28 cheshire
255 Updated "bad ifa_netmask" log message to give more information
256
257 Revision 1.222 2004/10/28 03:36:34 cheshire
258 <rdar://problem/3856535> Share the same port for both multicast and unicast receiving
259
260 Revision 1.221 2004/10/28 03:24:41 cheshire
261 Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
262
263 Revision 1.220 2004/10/28 00:53:57 cheshire
264 Export mDNSMacOSXNetworkChanged() so it's callable from outside this mDNSMacOSX.c;
265 Add LogOperation() call to record when we get network change events
266
267 Revision 1.219 2004/10/27 20:42:20 cheshire
268 Clean up debugging messages
269
270 Revision 1.218 2004/10/27 02:03:59 cheshire
271 Update debugging messages
272
273 Revision 1.217 2004/10/26 20:48:21 cheshire
274 Improve logging messages
275
276 Revision 1.216 2004/10/26 01:02:37 cheshire
277 Update comment
278
279 Revision 1.215 2004/10/25 20:09:00 ksekar
280 Cleaned up config file parsing.
281
282 Revision 1.214 2004/10/25 19:30:53 ksekar
283 <rdar://problem/3827956> Simplify dynamic host name structures
284
285 Revision 1.213 2004/10/23 01:16:01 cheshire
286 <rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
287
288 Revision 1.212 2004/10/22 20:52:08 ksekar
289 <rdar://problem/3799260> Create NAT port mappings for Long Lived Queries
290
291 Revision 1.211 2004/10/22 01:07:11 cheshire
292 <rdar://problem/3375328> select() says data is waiting; recvfrom() says there is no data
293 Log error message if socket() ever returns file descriptors 0, 1 or 2 (stdin/stdout/stderr).
294 These are all supposed to be remapped to /dev/null
295
296 Revision 1.210 2004/10/20 02:19:54 cheshire
297 Eliminate "SetupAddr invalid sa_family" warning from RegisterSearchDomains()
298
299 Revision 1.209 2004/10/16 00:17:00 cheshire
300 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
301
302 Revision 1.208 2004/10/15 23:00:18 ksekar
303 <rdar://problem/3799242> Need to update LLQs on location changes
304
305 Revision 1.207 2004/10/13 22:45:23 cheshire
306 <rdar://problem/3438392> Ten-second delay before kIOMessageSystemHasPoweredOn message
307
308 Revision 1.206 2004/10/13 22:11:46 cheshire
309 Update debugging messages
310
311 Revision 1.205 2004/10/12 21:10:11 cheshire
312 <rdar://problem/3438376> mach_absolute_time() not monotonically increasing
313 Do a NotifyOfElusiveBug() if we see mach_absolute_time() go backwards
314
315 Revision 1.204 2004/10/12 03:20:52 ksekar
316 <rdar://problem/3835614> Incorrect LogMsg produces garbage on errors
317
318 Revision 1.203 2004/10/08 04:29:25 ksekar
319 <rdar://problem/3831842> Allow default search domains to be set via hint from DHCP
320
321 Revision 1.202 2004/10/04 05:56:04 cheshire
322 <rdar://problem/3824730> mDNSResponder doesn't respond to certain AirPort changes
323
324 Revision 1.201 2004/09/30 00:24:59 ksekar
325 <rdar://problem/3695802> Dynamically update default registration domains on config change
326
327 Revision 1.200 2004/09/26 23:20:35 ksekar
328 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
329
330 Revision 1.199 2004/09/24 23:54:55 cheshire
331 <rdar://problem/3787102> Don't use kCFSocketCloseOnInvalidate
332
333 Revision 1.198 2004/09/24 23:47:49 cheshire
334 Correct comment and error message
335
336 Revision 1.197 2004/09/24 23:39:27 cheshire
337 <rdar://problem/3733705> Only IPv6 loopback address advertised on laptop w/no networking
338
339 Revision 1.196 2004/09/24 20:53:04 cheshire
340 Revise error message to say "Setsockopt SO_REUSEPORT failed" instead of "Flaw in Kernel"
341
342 Revision 1.195 2004/09/24 19:21:45 cheshire
343 <rdar://problem/3671626> Report "Address already in use" errors
344
345 Revision 1.194 2004/09/24 19:16:54 cheshire
346 Remove "mDNS *const m" parameter from NotifyOfElusiveBug();
347 Refine error message to say "Flaw in Kernel (select/recvfrom mismatch)"
348
349 Revision 1.193 2004/09/22 00:41:59 cheshire
350 Move tcp connection status codes into the legal range allocated for mDNS use
351
352 Revision 1.192 2004/09/21 21:02:55 cheshire
353 Set up ifname before calling mDNS_RegisterInterface()
354
355 Revision 1.191 2004/09/21 19:19:36 cheshire
356 <rdar://problem/3760923> Combine WatchForDynDNSChanges() into WatchForNetworkChanges()
357
358 Revision 1.190 2004/09/21 19:04:45 cheshire
359 Strip trailing white space from the ends of lines
360
361 Revision 1.189 2004/09/21 00:13:28 cheshire
362 Fix build failure (io_connect_t and io_object_t are integers, not pointers)
363
364 Revision 1.188 2004/09/20 23:52:02 cheshire
365 CFSocket{Puma}.c renamed to mDNSMacOSX{Puma}.c
366
367 Revision 1.187 2004/09/18 01:37:01 cheshire
368 Update comment
369
370 Revision 1.186 2004/09/18 01:11:57 ksekar
371 <rdar://problem/3806734> Add a user's default domain to empty-string browse list
372
373 Revision 1.185 2004/09/17 01:08:52 cheshire
374 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
375 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
376 declared in that file are ONLY appropriate to single-address-space embedded applications.
377 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
378
379 Revision 1.184 2004/09/17 00:19:10 cheshire
380 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
381
382 Revision 1.183 2004/09/17 00:15:56 cheshire
383 Rename mDNSPlatformInit_ReceiveUnicast to mDNSPlatformInit_CanReceiveUnicast
384
385 Revision 1.182 2004/09/16 21:36:36 cheshire
386 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
387 Changes to add necessary locking calls around unicast DNS operations
388
389 Revision 1.181 2004/09/16 02:03:42 cheshire
390 <rdar://problem/3802944> Change address to notify user of kernel flaw
391
392 Revision 1.180 2004/09/16 01:58:22 cheshire
393 Fix compiler warnings
394
395 Revision 1.179 2004/09/16 00:24:49 cheshire
396 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
397
398 Revision 1.178 2004/09/15 21:51:34 cheshire
399 <rdar://problem/3387020> mDNSResponder should notify user of kernel flaw
400 Calling CFUserNotificationDisplayNotice too early in the boot process seems to kill
401 the machine, so make sure we don't do this until at least three minutes after boot.
402
403 Revision 1.177 2004/09/15 01:16:29 cheshire
404 <rdar://problem/3387020> mDNSResponder should notify user of kernel flaw
405
406 Revision 1.176 2004/09/14 23:42:36 cheshire
407 <rdar://problem/3801296> Need to seed random number generator from platform-layer data
408
409 Revision 1.175 2004/09/14 21:35:46 cheshire
410 Minor code tidying, and added comments about CFRetainCounts
411
412 Revision 1.174 2004/09/14 19:14:57 ksekar
413 <rdar://problem/3192531> DynDNS: Discovery of DynDNS Zones via Reverse-Map PTR
414
415 Revision 1.173 2004/08/25 23:35:22 ksekar
416 <rdar://problem/3770615>: Error converting shared secret from base-64 to binary
417
418 Revision 1.172 2004/08/25 02:01:45 cheshire
419 <rdar://problem/3774777> Need to be able to get status of Dynamic DNS Host Name Update
420
421 Revision 1.171 2004/08/25 01:04:42 cheshire
422 Don't need to CFRelease name and array
423
424 Revision 1.170 2004/08/25 00:37:28 ksekar
425 <rdar://problem/3774635>: Cleanup DynDNS hostname registration code
426
427 Revision 1.169 2004/08/18 17:35:41 ksekar
428 <rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
429
430 Revision 1.168 2004/08/17 03:16:24 ksekar
431 Fixed checkin 1.166 - enumeration type changed for wrong invocation of mDNS_GetDomains
432
433 Revision 1.167 2004/08/17 00:52:43 ksekar
434 Fix config file parse error, make semantics match SCPreferences
435 configuration input.
436
437 Revision 1.166 2004/08/16 19:55:07 ksekar
438 Change enumeration type to BrowseDefault to construct empty-string
439 browse list as result of checking 1.161.
440
441 Revision 1.165 2004/08/16 19:52:40 ksekar
442 Pass computer name + zone for FQDN after keychain notification,
443 setting global default service registration domain to the zone.
444
445 Revision 1.164 2004/08/16 16:52:37 ksekar
446 Pass in zone read from keychain to mDNS_SetFQDNs.
447
448 Revision 1.163 2004/08/14 03:22:42 cheshire
449 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
450 Add GetUserSpecifiedDDNSName() routine
451 Convert ServiceRegDomain to domainname instead of C string
452 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
453
454 Revision 1.162 2004/08/12 22:34:00 cheshire
455 All strings should be read as kCFStringEncodingUTF8, not kCFStringEncodingASCII
456
457 Revision 1.161 2004/08/11 00:17:46 ksekar
458 <rdar://problem/3757662>: 8A227: Need Lighthouse configred machines to
459 set default bit for their domains
460
461 Revision 1.160 2004/07/29 19:27:16 ksekar
462 NATPMP Support - minor fixes and cleanup
463
464 Revision 1.159 2004/07/26 22:49:31 ksekar
465 <rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
466
467 Revision 1.158 2004/07/13 21:24:24 rpantos
468 Fix for <rdar://problem/3701120>.
469
470 Revision 1.157 2004/06/08 18:54:48 ksekar
471 <rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
472
473 Revision 1.156 2004/06/05 00:04:26 cheshire
474 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
475
476 Revision 1.155 2004/06/04 08:58:30 ksekar
477 <rdar://problem/3668624>: Keychain integration for secure dynamic update
478
479 Revision 1.154 2004/05/31 22:22:28 ksekar
480 <rdar://problem/3668639>: wide-area domains should be returned in
481 reg. domain enumeration
482
483 Revision 1.153 2004/05/26 17:06:33 cheshire
484 <rdar://problem/3668515>: Don't rely on CFSocketInvalidate() to remove RunLoopSource
485
486 Revision 1.152 2004/05/18 23:51:26 cheshire
487 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
488
489 Revision 1.151 2004/05/17 21:46:34 cheshire
490 <rdar://problem/3616426>: When interface is turned off, browse "remove" events are delivered with interface index zero
491 Take care to correctly update InterfaceIDs when a dormant interface comes back to life
492
493 Revision 1.150 2004/05/13 04:54:20 ksekar
494 Unified list copy/free code. Added symetric list for
495
496 Revision 1.149 2004/05/13 03:55:14 ksekar
497 Fixed list traversal bug in FoundDefSearchDomain.
498
499 Revision 1.148 2004/05/12 22:03:08 ksekar
500 Made GetSearchDomainList a true platform-layer call (declaration moved
501 from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
502 only on non-OSX platforms. Changed call to return a copy of the list
503 to avoid shared memory issues. Added a routine to free the list.
504
505 Revision 1.147 2004/05/12 02:03:25 ksekar
506 Non-local domains will only be browsed by default, and show up in
507 _browse domain enumeration, if they contain an _browse._dns-sd ptr record.
508
509 Revision 1.146 2004/04/27 02:49:15 cheshire
510 <rdar://problem/3634655>: mDNSResponder leaks sockets on bind() error
511
512 Revision 1.145 2004/04/21 03:08:03 cheshire
513 Rename 'alias' to more descriptive name 'primary'
514
515 Revision 1.144 2004/04/21 03:04:35 cheshire
516 Minor cleanup for clarity
517
518 Revision 1.143 2004/04/21 03:03:30 cheshire
519 Preparation work: AddInterfaceToList() should return pointer to structure it creates
520
521 Revision 1.142 2004/04/21 02:49:11 cheshire
522 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
523
524 Revision 1.141 2004/04/21 02:20:47 cheshire
525 Rename interface field 'CurrentlyActive' to more descriptive 'Exists'
526
527 Revision 1.140 2004/04/14 23:09:29 ksekar
528 Support for TSIG signed dynamic updates.
529
530 Revision 1.139 2004/04/09 17:40:26 cheshire
531 Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
532
533 Revision 1.138 2004/04/09 16:37:16 cheshire
534 Suggestion from Bob Bradley:
535 Move NumCacheRecordsForInterfaceID() to DNSCommon.c so it's available to all platform layers
536
537 Revision 1.137 2004/04/08 00:59:55 cheshire
538 <rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
539 Unify use of the InterfaceID field, and make code that walks the list respect the 'Exists' flag
540
541 Revision 1.136 2004/04/07 01:08:57 cheshire
542 <rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
543
544 Revision 1.135 2004/03/19 01:01:03 ksekar
545 Fixed config file parsing to chop newline
546
547 Revision 1.134 2004/03/13 01:57:34 ksekar
548 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
549
550 Revision 1.133 2004/02/02 22:46:56 cheshire
551 Move "CFRelease(dict);" inside the "if (dict)" check
552
553 Revision 1.132 2004/01/28 02:30:08 ksekar
554 Added default Search Domains to unicast browsing, controlled via
555 Networking sharing prefs pane. Stopped sending unicast messages on
556 every interface. Fixed unicast resolving via mach-port API.
557
558 Revision 1.131 2004/01/27 22:57:48 cheshire
559 <rdar://problem/3534352>: Need separate socket for issuing unicast queries
560
561 Revision 1.130 2004/01/27 22:28:40 cheshire
562 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
563 Additional lingering port 53 code deleted
564
565 Revision 1.129 2004/01/27 20:15:23 cheshire
566 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
567
568 Revision 1.128 2004/01/24 23:58:17 cheshire
569 Change to use mDNSVal16() instead of shifting and ORing
570
571 Revision 1.127 2004/01/24 04:59:16 cheshire
572 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
573
574 Revision 1.126 2004/01/23 23:23:15 ksekar
575 Added TCP support for truncated unicast messages.
576
577 Revision 1.125 2004/01/22 03:43:09 cheshire
578 Export constants like mDNSInterface_LocalOnly so that the client layers can use them
579
580 Revision 1.124 2004/01/21 21:53:19 cheshire
581 <rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port
582
583 Revision 1.123 2004/01/20 03:18:25 cheshire
584 Removed "LogMsg("Hey There!");" that evidently got checked in my mistake
585
586 Revision 1.122 2003/12/17 20:43:59 cheshire
587 <rdar://problem/3496728>: Syslog messages saying "sendto failed"
588
589 Revision 1.121 2003/12/13 03:05:28 ksekar
590 <rdar://problem/3192548>: DynDNS: Unicast query of service records
591
592 Revision 1.120 2003/12/08 21:00:46 rpantos
593 Changes to support mDNSResponder on Linux.
594
595 Revision 1.119 2003/12/03 02:35:15 cheshire
596 Also report value of m->timenow when logging sendto() failure
597
598 Revision 1.118 2003/11/14 20:59:09 cheshire
599 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
600 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
601
602 Revision 1.117 2003/11/08 22:18:29 cheshire
603 <rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
604
605 Revision 1.116 2003/09/23 16:39:49 cheshire
606 When LogAllOperations is set, also report registration and deregistration of interfaces
607
608 Revision 1.115 2003/09/10 00:45:55 cheshire
609 <rdar://problem/3412328> Don't log "sendto failed" errors during the first two minutes of startup
610
611 Revision 1.114 2003/08/27 02:55:13 cheshire
612 <rdar://problem/3387910>: Bug: Don't report mDNSPlatformSendUDP sendto errno 64 (Host is down)
613
614 Revision 1.113 2003/08/19 22:20:00 cheshire
615 <rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
616 More minor refinements
617
618 Revision 1.112 2003/08/19 03:04:43 cheshire
619 <rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
620
621 Revision 1.111 2003/08/18 22:53:37 cheshire
622 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
623
624 Revision 1.110 2003/08/16 03:39:00 cheshire
625 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
626
627 Revision 1.109 2003/08/15 02:19:49 cheshire
628 <rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
629 Also limit number of messages to at most 100
630
631 Revision 1.108 2003/08/12 22:24:52 cheshire
632 <rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
633 This message indicates a kernel bug, but still we don't want to flood syslog.
634 Do a sleep(1) after writing this log message, to limit the rate.
635
636 Revision 1.107 2003/08/12 19:56:25 cheshire
637 Update to APSL 2.0
638
639 Revision 1.106 2003/08/12 13:48:32 cheshire
640 Add comment explaining clockdivisor calculation
641
642 Revision 1.105 2003/08/12 13:44:14 cheshire
643 <rdar://problem/3370229> mDNSResponder *VERY* unhappy if time goes backwards
644 Use mach_absolute_time() (which is guaranteed to always go forwards, resetting only on reboot)
645 instead of gettimeofday() (which can jump back if the user manually changes their time/date)
646
647 Revision 1.104 2003/08/12 13:12:07 cheshire
648 Textual search/replace: Indicate local functions using "mDNSlocal" instead of "static"
649
650 Revision 1.103 2003/08/08 18:36:04 cheshire
651 <rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
652
653 Revision 1.102 2003/08/06 00:14:52 cheshire
654 <rdar://problem/3330324> Need to check IP TTL on responses
655 Also add corresponding checks in the IPv6 code path
656
657 Revision 1.101 2003/08/05 22:20:16 cheshire
658 <rdar://problem/3330324> Need to check IP TTL on responses
659
660 Revision 1.100 2003/08/05 21:18:50 cheshire
661 <rdar://problem/3363185> mDNSResponder should ignore 6to4
662 Only use interfaces that are marked as multicast-capable (IFF_MULTICAST)
663
664 Revision 1.99 2003/08/05 20:13:52 cheshire
665 <rdar://problem/3294080> mDNSResponder using IPv6 interfaces before they are ready
666 Ignore interfaces with the IN6_IFF_NOTREADY flag set
667
668 Revision 1.98 2003/07/20 03:38:51 ksekar
669 <rdar://problem/3320722>
670 Completed support for Unix-domain socket based API.
671
672 Revision 1.97 2003/07/19 03:15:16 cheshire
673 Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
674 and add the obvious trivial implementations to each platform support layer
675
676 Revision 1.96 2003/07/18 00:30:00 cheshire
677 <rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
678
679 Revision 1.95 2003/07/12 03:15:20 cheshire
680 <rdar://problem/3324848> After SCDynamicStore notification, mDNSResponder updates
681 m->hostlabel even if user hasn't actually actually changed their dot-local hostname
682
683 Revision 1.94 2003/07/03 00:51:54 cheshire
684 <rdar://problem/3287213> When select() and recvmgs() disagree, get more info from kernel about the socket state
685
686 Revision 1.93 2003/07/03 00:09:14 cheshire
687 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
688 Additional refinement suggested by Josh: Use info->scope_id instead of if_nametoindex(info->ifa_name);
689
690 Revision 1.92 2003/07/02 21:19:51 cheshire
691 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
692
693 Revision 1.91 2003/06/24 01:53:51 cheshire
694 Minor update to comments
695
696 Revision 1.90 2003/06/24 01:51:47 cheshire
697 <rdar://problem/3303118> Oops: Double-dispose of sockets
698 Don't need to close sockets: CFSocketInvalidate() does that for us
699
700 Revision 1.89 2003/06/21 18:12:47 cheshire
701 <rdar://problem/3296061> mDNSResponder cannot handle interfaces whose total name is >3 chars
702 One-line change: should say "IF_NAMESIZE", not sizeof(ifname)
703
704 Revision 1.88 2003/06/12 23:38:37 cheshire
705 <rdar://problem/3291162> mDNSResponder doesn't detect some configuration changes
706 Also check that scope_id matches before concluding that two interfaces are the same
707
708 Revision 1.87 2003/06/10 01:14:11 cheshire
709 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
710
711 Revision 1.86 2003/05/28 02:41:52 cheshire
712 <rdar://problem/3034346> Time to remove Mac OS 9 UDP Port 53 legacy support
713
714 Revision 1.85 2003/05/28 02:39:47 cheshire
715 Minor change to debugging messages
716
717 Revision 1.84 2003/05/27 22:29:40 cheshire
718 Remove out-dated comment
719
720 Revision 1.83 2003/05/26 03:21:29 cheshire
721 Tidy up address structure naming:
722 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
723 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
724 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
725
726 Revision 1.82 2003/05/26 03:01:27 cheshire
727 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
728
729 Revision 1.81 2003/05/24 02:06:42 cheshire
730 <rdar://problem/3268480> IPv6 Multicast Loopback doesn't work
731 Tried setting IPV6_MULTICAST_LOOP; it doesn't help.
732 However, it is probably wise to have the code explicitly set this socket
733 option anyway, in case the default changes in later versions of Unix.
734
735 Revision 1.80 2003/05/24 02:02:24 cheshire
736 <rdar://problem/3221880> if_indextoname consumes a lot of CPU
737 Fix error in myIfIndexToName; was returning prematurely
738
739 Revision 1.79 2003/05/23 23:07:44 cheshire
740 <rdar://problem/3268199> Must not write to stderr when running as daemon
741
742 Revision 1.78 2003/05/23 01:19:04 cheshire
743 <rdar://problem/3267085> mDNSResponder needs to signal type of service to AirPort
744 Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
745
746 Revision 1.77 2003/05/23 01:12:05 cheshire
747 Minor code tidying
748
749 Revision 1.76 2003/05/22 01:26:01 cheshire
750 Tidy up log messages
751
752 Revision 1.75 2003/05/22 00:07:09 cheshire
753 <rdar://problem/3264366> myCFSocketCallBack recvfrom(5) error 1, errno 35
754 Extra logging to determine whether there is a bug in CFSocket
755
756 Revision 1.74 2003/05/21 20:20:12 cheshire
757 Fix warnings (mainly printf format string warnings, like using "%d" where
758 it should say "%lu", etc.) and improve error logging (use strerror()
759 to include textual error message as well as numeric error in log messages).
760
761 Revision 1.73 2003/05/21 17:56:29 ksekar
762 <rdar://problem/3191277>: mDNSResponder doesn't watch for IPv6 address changes
763
764 Revision 1.72 2003/05/14 18:48:41 cheshire
765 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
766 More minor refinements:
767 mDNSMacOSX.c needs to do *all* its mDNS_DeregisterInterface calls before freeing memory
768 mDNS_DeregisterInterface revalidates cache record when *any* representative of an interface goes away
769
770 Revision 1.71 2003/05/14 07:08:37 cheshire
771 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
772 Previously, when there was any network configuration change, mDNSResponder
773 would tear down the entire list of active interfaces and start again.
774 That was very disruptive, and caused the entire cache to be flushed,
775 and caused lots of extra network traffic. Now it only removes interfaces
776 that have really gone, and only adds new ones that weren't there before.
777
778 Revision 1.70 2003/05/07 18:30:24 cheshire
779 Fix signed/unsigned comparison warning
780
781 Revision 1.69 2003/05/06 20:14:44 cheshire
782 Change "tp" to "tv"
783
784 Revision 1.68 2003/05/06 00:00:49 cheshire
785 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
786
787 Revision 1.67 2003/04/29 00:43:44 cheshire
788 Fix compiler warnings
789
790 Revision 1.66 2003/04/26 02:41:58 cheshire
791 <rdar://problem/3241281> Change timenow from a local variable to a structure member
792
793 Revision 1.65 2003/04/26 02:34:01 cheshire
794 Add missing mDNSexport
795
796 Revision 1.64 2003/04/15 16:48:06 jgraessl
797 <rdar://problem/3228833>
798 Modified code in CFSocket notifier function to read all packets on the socket
799 instead of reading only one packet every time the notifier was called.
800
801 Revision 1.63 2003/04/15 16:33:50 jgraessl
802 <rdar://problem/3221880>
803 Switched to our own copy of if_indextoname to improve performance.
804
805 Revision 1.62 2003/03/28 01:55:44 cheshire
806 Minor improvements to debugging messages
807
808 Revision 1.61 2003/03/27 03:30:56 cheshire
809 <rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
810 Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
811 Fixes:
812 1. Make mDNS_DeregisterInterface() safe to call from a callback
813 2. Make HostNameCallback() use mDNS_DeadvertiseInterface() instead
814 (it never really needed to deregister the interface at all)
815
816 Revision 1.60 2003/03/15 04:40:38 cheshire
817 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
818
819 Revision 1.59 2003/03/11 01:23:26 cheshire
820 <rdar://problem/3194246> mDNSResponder socket problems
821
822 Revision 1.58 2003/03/06 01:43:04 cheshire
823 <rdar://problem/3189097> Additional debugging code in mDNSResponder
824 Improve "LIST_ALL_INTERFACES" output
825
826 Revision 1.57 2003/03/05 22:36:27 cheshire
827 <rdar://problem/3186338> Loopback doesn't work with mDNSResponder-27
828 Temporary workaround: Skip loopback interface *only* if we found at least one v4 interface to use
829
830 Revision 1.56 2003/03/05 01:50:38 cheshire
831 <rdar://problem/3189097> Additional debugging code in mDNSResponder
832
833 Revision 1.55 2003/02/21 01:54:09 cheshire
834 <rdar://problem/3099194> mDNSResponder needs performance improvements
835 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
836
837 Revision 1.54 2003/02/20 06:48:35 cheshire
838 <rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
839 Reviewed by: Josh Graessley, Bob Bradley
840
841 Revision 1.53 2003/01/29 02:21:23 cheshire
842 Return mStatus_Invalid if can't send packet because socket not available
843
844 Revision 1.52 2003/01/28 19:39:43 jgraessl
845 Enabling AAAA over IPv4 support.
846
847 Revision 1.51 2003/01/28 05:11:23 cheshire
848 Fixed backwards comparison in SearchForInterfaceByName
849
850 Revision 1.50 2003/01/13 23:49:44 jgraessl
851 Merged changes for the following fixes in to top of tree:
852 <rdar://problem/3086540> computer name changes not handled properly
853 <rdar://problem/3124348> service name changes are not properly handled
854 <rdar://problem/3124352> announcements sent in pairs, failing chattiness test
855
856 Revision 1.49 2002/12/23 22:13:30 jgraessl
857 Reviewed by: Stuart Cheshire
858 Initial IPv6 support for mDNSResponder.
859
860 Revision 1.48 2002/11/22 01:37:52 cheshire
861 <rdar://problem/3108426> mDNSResponder is monitoring ServiceEntities instead of InterfaceEntities
862
863 Revision 1.47 2002/09/21 20:44:51 zarzycki
864 Added APSL info
865
866 Revision 1.46 2002/09/19 21:25:35 cheshire
867 mDNS_snprintf() doesn't need to be in a separate file
868
869 Revision 1.45 2002/09/17 01:45:13 cheshire
870 Add LIST_ALL_INTERFACES symbol for debugging
871
872 Revision 1.44 2002/09/17 01:36:23 cheshire
873 Move Puma support to mDNSMacOSXPuma.c
874
875 Revision 1.43 2002/09/17 01:05:28 cheshire
876 Change mDNS_AdvertiseLocalAddresses to be an Init parameter instead of a global
877
878 Revision 1.42 2002/09/16 23:13:50 cheshire
879 Minor code tidying
880
881 */
882
883 // ***************************************************************************
884 // mDNSMacOSX.c:
885 // Supporting routines to run mDNS on a CFRunLoop platform
886 // ***************************************************************************
887
888 // For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
889 // including ones that mDNSResponder chooses not to use.
890 #define LIST_ALL_INTERFACES 0
891
892 // For enabling AAAA records over IPv4. Setting this to 0 sends only
893 // A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both
894 // AAAA and A records over both IPv4 and IPv6.
895 #define AAAA_OVER_V4 1
896
897 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
898 #include "DNSCommon.h"
899 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
900 #include "../mDNSShared/uds_daemon.h" // Defines communication interface from platform layer up to UDS daemon
901 #include "PlatformCommon.h"
902
903 #include <stdio.h>
904 #include <stdarg.h> // For va_list support
905 #include <net/if.h>
906 #include <net/if_types.h> // For IFT_ETHER
907 #include <net/if_dl.h>
908 #include <sys/uio.h>
909 #include <sys/param.h>
910 #include <sys/socket.h>
911 #include <sys/sysctl.h>
912 #include <fcntl.h>
913 #include <sys/ioctl.h>
914 #include <time.h> // platform support for UTC time
915 #include <arpa/inet.h> // for inet_aton
916
917 #include <netinet/in.h> // For IP_RECVTTL
918 #ifndef IP_RECVTTL
919 #define IP_RECVTTL 24 // bool; receive reception TTL w/dgram
920 #endif
921
922 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
923 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
924 #include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
925
926 #include <Security/Security.h>
927
928 #include <AvailabilityMacros.h>
929 #ifdef MAC_OS_X_VERSION_10_4
930 #include <dnsinfo.h>
931 #endif
932
933 // Code contributed by Dave Heller:
934 // Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
935 // work on Mac OS X 10.1, which does not have the getifaddrs call.
936 #define RUN_ON_PUMA_WITHOUT_IFADDRS 0
937 #if RUN_ON_PUMA_WITHOUT_IFADDRS
938 #include "mDNSMacOSXPuma.c"
939 #else
940 #include <ifaddrs.h>
941 #endif
942
943 #include <IOKit/IOKitLib.h>
944 #include <IOKit/IOMessage.h>
945 #include <mach/mach_time.h>
946
947 typedef struct SearchListElem
948 {
949 struct SearchListElem *next;
950 domainname domain;
951 int flag;
952 DNSQuestion BrowseQ;
953 DNSQuestion DefBrowseQ;
954 DNSQuestion LegacyBrowseQ;
955 DNSQuestion RegisterQ;
956 DNSQuestion DefRegisterQ;
957 ARListElem *AuthRecs;
958 } SearchListElem;
959
960
961 // ***************************************************************************
962 // Globals
963
964 static mDNSu32 clockdivisor = 0;
965
966 // for domain enumeration and default browsing/registration
967 static SearchListElem *SearchList = NULL; // where we search for _browse domains
968 static DNSQuestion LegacyBrowseDomainQ; // our local enumeration query for _legacy._browse domains
969 static DNameListElem *DefBrowseList = NULL; // cache of answers to above query (where we search for empty string browses)
970 static DNameListElem *DefRegList = NULL; // manually generated list of domains where we register for empty string registrations
971 static ARListElem *SCPrefBrowseDomains = NULL; // manually generated local-only PTR records for browse domains we get from SCPreferences
972
973 static domainname DynDNSRegDomain; // Default wide-area zone for service registration
974 static CFArrayRef DynDNSBrowseDomains = NULL; // Default wide-area zones for legacy ("empty string") browses
975 static domainname DynDNSHostname;
976
977 static mDNSBool DomainDiscoveryDisabled = mDNSfalse;
978
979 #define CONFIG_FILE "/etc/mDNSResponder.conf"
980 #define DYNDNS_KEYCHAIN_SERVICE "DynDNS Shared Secret"
981 #define SYS_KEYCHAIN_PATH "/Library/Keychains/System.keychain"
982
983 // Function Prototypes
984 mDNSlocal void SetSCPrefsBrowseDomain(mDNS *m, const domainname *d, mDNSBool add);
985
986 // ***************************************************************************
987 // Functions
988
989 // routines to allow access to default domain lists from daemon layer
990
991 mDNSexport DNameListElem *mDNSPlatformGetSearchDomainList(void)
992 {
993 return mDNS_CopyDNameList(DefBrowseList);
994 }
995
996 mDNSexport DNameListElem *mDNSPlatformGetRegDomainList(void)
997 {
998 return mDNS_CopyDNameList(DefRegList);
999 }
1000
1001 // utility routines to manage registration domain lists
1002
1003 mDNSlocal void AddDefRegDomain(domainname *d)
1004 {
1005 DNameListElem *newelem = NULL, *ptr;
1006
1007 // make sure name not already in list
1008 for (ptr = DefRegList; ptr; ptr = ptr->next)
1009 {
1010 if (SameDomainName(&ptr->name, d))
1011 { debugf("duplicate addition of default reg domain %##s", d->c); return; }
1012 }
1013
1014 newelem = mallocL("DNameListElem", sizeof(*newelem));
1015 if (!newelem) { LogMsg("Error - malloc"); return; }
1016 AssignDomainName(&newelem->name, d);
1017 newelem->next = DefRegList;
1018 DefRegList = newelem;
1019
1020 DefaultRegDomainChanged(d, mDNStrue);
1021 udsserver_default_reg_domain_changed(d, mDNStrue);
1022 }
1023
1024 mDNSlocal void RemoveDefRegDomain(domainname *d)
1025 {
1026 DNameListElem *ptr = DefRegList, *prev = NULL;
1027
1028 while (ptr)
1029 {
1030 if (SameDomainName(&ptr->name, d))
1031 {
1032 if (prev) prev->next = ptr->next;
1033 else DefRegList = ptr->next;
1034 freeL("DNameListElem", ptr);
1035 DefaultRegDomainChanged(d, mDNSfalse);
1036 udsserver_default_reg_domain_changed(d, mDNSfalse);
1037 return;
1038 }
1039 prev = ptr;
1040 ptr = ptr->next;
1041 }
1042 debugf("Requested removal of default registration domain %##s not in contained in list", d->c);
1043 }
1044
1045 mDNSlocal void NotifyOfElusiveBug(const char *title, mDNSu32 radarid, const char *msg)
1046 {
1047 extern mDNS mDNSStorage;
1048 NetworkInterfaceInfoOSX *i;
1049 static int notifyCount = 0;
1050 if (notifyCount) return;
1051
1052 // If we display our alert early in the boot process, then it vanishes once the desktop appears.
1053 // To avoid this, we don't try to display alerts in the first three minutes after boot.
1054 if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return;
1055
1056 // Determine if we're at Apple (17.*.*.*)
1057 for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
1058 if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && i->ifinfo.ip.ip.v4.b[0] == 17)
1059 break;
1060 if (!i) return; // If not at Apple, don't show the alert
1061
1062 // Send a notification to the user to contact coreos-networking
1063 notifyCount++;
1064 CFStringRef alertHeader = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8);
1065 CFStringRef alertFormat = CFSTR("Congratulations, you've reproduced an elusive bug. Please contact the owner of <rdar://problem/%d>. %s");
1066 CFStringRef alertMessage = CFStringCreateWithFormat(NULL, NULL, alertFormat, radarid, msg);
1067 CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL, alertHeader, alertMessage, NULL);
1068 }
1069
1070 mDNSlocal struct ifaddrs* myGetIfAddrs(int refresh)
1071 {
1072 static struct ifaddrs *ifa = NULL;
1073
1074 if (refresh && ifa)
1075 {
1076 freeifaddrs(ifa);
1077 ifa = NULL;
1078 }
1079
1080 if (ifa == NULL) getifaddrs(&ifa);
1081
1082 return ifa;
1083 }
1084
1085 mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, const char *ifname, int type)
1086 {
1087 NetworkInterfaceInfoOSX *i;
1088 for (i = m->p->InterfaceList; i; i = i->next)
1089 if (i->Exists && !strcmp(i->ifa_name, ifname) &&
1090 ((AAAA_OVER_V4 ) ||
1091 (type == AF_INET && i->ifinfo.ip.type == mDNSAddrType_IPv4) ||
1092 (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6) )) return(i);
1093 return(NULL);
1094 }
1095
1096 mDNSlocal int myIfIndexToName(u_short index, char* name)
1097 {
1098 struct ifaddrs *ifa;
1099 for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
1100 if (ifa->ifa_addr->sa_family == AF_LINK)
1101 if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == index)
1102 { strncpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; }
1103 return -1;
1104 }
1105
1106 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS *const m, mDNSu32 index)
1107 {
1108 NetworkInterfaceInfoOSX *i;
1109 if (index == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
1110 if (index)
1111 for (i = m->p->InterfaceList; i; i = i->next)
1112 // Don't get tricked by inactive interfaces with no InterfaceID set
1113 if (i->ifinfo.InterfaceID && i->scope_id == index) return(i->ifinfo.InterfaceID);
1114 return(mDNSNULL);
1115 }
1116
1117 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m, mDNSInterfaceID id)
1118 {
1119 NetworkInterfaceInfoOSX *i;
1120 if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
1121 if (id)
1122 for (i = m->p->InterfaceList; i; i = i->next)
1123 // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces, which have no InterfaceID set
1124 if ((mDNSInterfaceID)i == id) return(i->scope_id);
1125 return 0;
1126 }
1127
1128 mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr)
1129 {
1130 mDNSBool result = mDNSfalse;
1131 SCNetworkConnectionFlags flags;
1132 SCNetworkReachabilityRef ReachRef = NULL;
1133
1134 ReachRef = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, addr);
1135 if (!ReachRef) { LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithAddress"); goto end; }
1136 if (!SCNetworkReachabilityGetFlags(ReachRef, &flags)) { LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags"); goto end; }
1137 result = flags & kSCNetworkFlagsConnectionRequired;
1138
1139 end:
1140 if (ReachRef) CFRelease(ReachRef);
1141 return result;
1142 }
1143
1144 // NOTE: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
1145 // NOTE: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
1146 // OR send via our primary v4 unicast socket
1147 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
1148 mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstPort)
1149 {
1150 #pragma unused(m)
1151
1152 // Note: For this platform we've adopted the convention that InterfaceIDs are secretly pointers
1153 // to the NetworkInterfaceInfoOSX structure that holds the active sockets. The mDNSCore code
1154 // doesn't know that and doesn't need to know that -- it just treats InterfaceIDs as opaque identifiers.
1155 NetworkInterfaceInfoOSX *info = (NetworkInterfaceInfoOSX *)InterfaceID;
1156 char *ifa_name = info ? info->ifa_name : "unicast";
1157 struct sockaddr_storage to;
1158 int s = -1, err;
1159
1160 // Sanity check: Make sure that if we're sending a query via unicast, we're sending it using our
1161 // anonymous socket created for this purpose, so that we'll receive the response.
1162 // If we use one of the many multicast sockets bound to port 5353 then we may not receive responses reliably.
1163 if (info && !mDNSAddrIsDNSMulticast(dst))
1164 {
1165 const DNSMessage *const m = (DNSMessage *)msg;
1166 if ((m->h.flags.b[0] & kDNSFlag0_QR_Mask) == kDNSFlag0_QR_Query)
1167 LogMsg("mDNSPlatformSendUDP: ERROR: Sending query OP from mDNS port to non-mDNS destination %#a:%d", dst, mDNSVal16(dstPort));
1168 }
1169
1170 if (dst->type == mDNSAddrType_IPv4)
1171 {
1172 struct sockaddr_in *sin_to = (struct sockaddr_in*)&to;
1173 sin_to->sin_len = sizeof(*sin_to);
1174 sin_to->sin_family = AF_INET;
1175 sin_to->sin_port = dstPort.NotAnInteger;
1176 sin_to->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
1177 s = info ? info->ss.sktv4 : m->p->unicastsockets.sktv4;
1178 }
1179 else if (dst->type == mDNSAddrType_IPv6)
1180 {
1181 struct sockaddr_in6 *sin6_to = (struct sockaddr_in6*)&to;
1182 sin6_to->sin6_len = sizeof(*sin6_to);
1183 sin6_to->sin6_family = AF_INET6;
1184 sin6_to->sin6_port = dstPort.NotAnInteger;
1185 sin6_to->sin6_flowinfo = 0;
1186 sin6_to->sin6_addr = *(struct in6_addr*)&dst->ip.v6;
1187 sin6_to->sin6_scope_id = info ? info->scope_id : 0;
1188 s = info ? info->ss.sktv6 : m->p->unicastsockets.sktv6;
1189 }
1190 else
1191 {
1192 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
1193 return mStatus_BadParamErr;
1194 }
1195
1196 // Don't send if it would cause dial on demand connection initiation. As an optimization,
1197 // don't bother consulting reachability API / routing table when sending Multicast DNS
1198 // since we ignore PPP interfaces for mDNS traffic
1199 if (!mDNSAddrIsDNSMulticast(dst) && AddrRequiresPPPConnection((struct sockaddr *)&to))
1200 {
1201 debugf("mDNSPlatformSendUDP: Surpressing sending to avoid dial-on-demand connection");
1202 return mStatus_NoError;
1203 }
1204
1205 if (s >= 0)
1206 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
1207 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s);
1208 else
1209 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
1210 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort));
1211
1212 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
1213 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
1214 if (s < 0) return(mStatus_Invalid);
1215
1216 err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len);
1217 if (err < 0)
1218 {
1219 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
1220 if (!mDNSAddressIsAllDNSLinkGroup(dst) && (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH)) return(err);
1221 // Don't report EHOSTUNREACH in the first three minutes after boot
1222 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
1223 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
1224 if (errno == EHOSTUNREACH && (mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(err);
1225 // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
1226 if (errno == EADDRNOTAVAIL && m->p->NetworkChanged) return(err);
1227 LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %5s/%ld to %#a:%d skt %d error %d errno %d (%s) %lu",
1228 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
1229 return(err);
1230 }
1231
1232 return(mStatus_NoError);
1233 }
1234
1235 mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
1236 struct sockaddr *const from, size_t *const fromlen, mDNSAddr *dstaddr, char ifname[IF_NAMESIZE], mDNSu8 *ttl)
1237 {
1238 static unsigned int numLogMessages = 0;
1239 struct iovec databuffers = { (char *)buffer, max };
1240 struct msghdr msg;
1241 ssize_t n;
1242 struct cmsghdr *cmPtr;
1243 char ancillary[1024];
1244
1245 *ttl = 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
1246
1247 // Set up the message
1248 msg.msg_name = (caddr_t)from;
1249 msg.msg_namelen = *fromlen;
1250 msg.msg_iov = &databuffers;
1251 msg.msg_iovlen = 1;
1252 msg.msg_control = (caddr_t)&ancillary;
1253 msg.msg_controllen = sizeof(ancillary);
1254 msg.msg_flags = 0;
1255
1256 // Receive the data
1257 n = recvmsg(s, &msg, 0);
1258 if (n<0)
1259 {
1260 if (errno != EWOULDBLOCK && numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s, n, errno);
1261 return(-1);
1262 }
1263 if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
1264 {
1265 if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
1266 s, msg.msg_controllen, sizeof(struct cmsghdr));
1267 return(-1);
1268 }
1269 if (msg.msg_flags & MSG_CTRUNC)
1270 {
1271 if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
1272 return(-1);
1273 }
1274
1275 *fromlen = msg.msg_namelen;
1276
1277 // Parse each option out of the ancillary data.
1278 for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
1279 {
1280 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
1281 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVDSTADDR)
1282 {
1283 dstaddr->type = mDNSAddrType_IPv4;
1284 dstaddr->ip.v4.NotAnInteger = *(u_int32_t*)CMSG_DATA(cmPtr);
1285 }
1286 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF)
1287 {
1288 struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr);
1289 if (sdl->sdl_nlen < IF_NAMESIZE)
1290 {
1291 mDNSPlatformMemCopy(sdl->sdl_data, ifname, sdl->sdl_nlen);
1292 ifname[sdl->sdl_nlen] = 0;
1293 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
1294 }
1295 }
1296 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVTTL)
1297 {
1298 *ttl = *(u_char*)CMSG_DATA(cmPtr);
1299 }
1300 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_PKTINFO)
1301 {
1302 struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmPtr);
1303 dstaddr->type = mDNSAddrType_IPv6;
1304 dstaddr->ip.v6 = *(mDNSv6Addr*)&ip6_info->ipi6_addr;
1305 myIfIndexToName(ip6_info->ipi6_ifindex, ifname);
1306 }
1307 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT)
1308 {
1309 *ttl = *(int*)CMSG_DATA(cmPtr);
1310 }
1311 }
1312
1313 return(n);
1314 }
1315
1316 // On entry, context points to our CFSocketSet
1317 // If ss->info is NULL, we received this packet on our anonymous unicast socket
1318 // If ss->info is non-NULL, we received this packet on port 5353 on the indicated interface
1319 mDNSlocal void myCFSocketCallBack(CFSocketRef cfs, CFSocketCallBackType CallBackType, CFDataRef address, const void *data, void *context)
1320 {
1321 mDNSAddr senderAddr, destAddr;
1322 mDNSIPPort senderPort, destPort = MulticastDNSPort;
1323 const CFSocketSet *ss = (const CFSocketSet *)context;
1324 mDNS *const m = ss->m;
1325 mDNSInterfaceID InterfaceID = ss->info ? ss->info->ifinfo.InterfaceID : mDNSNULL;
1326 struct sockaddr_storage from;
1327 size_t fromlen = sizeof(from);
1328 char packetifname[IF_NAMESIZE] = "";
1329 int err, s1 = -1, skt = CFSocketGetNative(cfs);
1330 int count = 0;
1331
1332 (void)address; // Parameter not used
1333 (void)data; // Parameter not used
1334
1335 if (CallBackType != kCFSocketReadCallBack)
1336 LogMsg("myCFSocketCallBack: Why is CallBackType %d not kCFSocketReadCallBack?", CallBackType);
1337
1338 if (cfs == ss->cfsv4) s1 = ss->sktv4;
1339 else if (cfs == ss->cfsv6) s1 = ss->sktv6;
1340
1341 if (s1 < 0 || s1 != skt)
1342 {
1343 LogMsg("myCFSocketCallBack: s1 %d native socket %d, cfs %p", s1, skt, cfs);
1344 LogMsg("myCFSocketCallBack: cfsv4 %p, sktv4 %d", ss->cfsv4, ss->sktv4);
1345 LogMsg("myCFSocketCallBack: cfsv6 %p, sktv6 %d", ss->cfsv6, ss->sktv6);
1346 }
1347
1348 mDNSu8 ttl;
1349 while ((err = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl)) >= 0)
1350 {
1351 count++;
1352 if (from.ss_family == AF_INET)
1353 {
1354 struct sockaddr_in *sin = (struct sockaddr_in*)&from;
1355 senderAddr.type = mDNSAddrType_IPv4;
1356 senderAddr.ip.v4.NotAnInteger = sin->sin_addr.s_addr;
1357 senderPort.NotAnInteger = sin->sin_port;
1358 }
1359 else if (from.ss_family == AF_INET6)
1360 {
1361 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&from;
1362 senderAddr.type = mDNSAddrType_IPv6;
1363 senderAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
1364 senderPort.NotAnInteger = sin6->sin6_port;
1365 }
1366 else
1367 {
1368 LogMsg("myCFSocketCallBack from is unknown address family %d", from.ss_family);
1369 return;
1370 }
1371
1372 if (mDNSAddrIsDNSMulticast(&destAddr))
1373 {
1374 // Even though we indicated a specific interface in the IP_ADD_MEMBERSHIP call, a weirdness of the
1375 // sockets API means that even though this socket has only officially joined the multicast group
1376 // on one specific interface, the kernel will still deliver multicast packets to it no matter which
1377 // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
1378 // To work around this weirdness, we use the IP_RECVIF option to find the name of the interface
1379 // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
1380 if (!ss->info || !ss->info->Exists)
1381 {
1382 verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on unicast socket (Ignored)", &senderAddr, &destAddr);
1383 return;
1384 }
1385 else if (!strcmp(ss->info->ifa_name, packetifname))
1386 verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on interface %#a/%s",
1387 &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifa_name);
1388 else
1389 {
1390 verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on interface %#a/%s (Ignored -- really arrived on interface %s)",
1391 &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifa_name, packetifname);
1392 return;
1393 }
1394 }
1395 else
1396 {
1397 // Note: For unicast packets, try to find the matching mDNSCore interface object
1398 // (though we may not be able to, for unicast packets received over something like a PPP link)
1399 NetworkInterfaceInfo *intf = m->HostInterfaces;
1400 while (intf && strcmp(intf->ifname, packetifname)) intf = intf->next;
1401 if (intf) InterfaceID = intf->InterfaceID;
1402 }
1403
1404 mDNSCoreReceive(m, &m->imsg, (unsigned char*)&m->imsg + err, &senderAddr, senderPort, &destAddr, destPort, InterfaceID);
1405 }
1406
1407 if (err < 0 && (errno != EWOULDBLOCK || count == 0))
1408 {
1409 // Something is busted here.
1410 // CFSocket says there is a packet, but myrecvfrom says there is not.
1411 // Try calling select() to get another opinion.
1412 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
1413 // All of this is racy, as data may have arrived after the call to select()
1414 int save_errno = errno;
1415 int so_error = -1;
1416 int so_nread = -1;
1417 int fionread = -1;
1418 int solen = sizeof(int);
1419 fd_set readfds;
1420 FD_ZERO(&readfds);
1421 FD_SET(s1, &readfds);
1422 struct timeval timeout;
1423 timeout.tv_sec = 0;
1424 timeout.tv_usec = 0;
1425 int selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
1426 if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1)
1427 LogMsg("myCFSocketCallBack getsockopt(SO_ERROR) error %d", errno);
1428 if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1)
1429 LogMsg("myCFSocketCallBack getsockopt(SO_NREAD) error %d", errno);
1430 if (ioctl(s1, FIONREAD, &fionread) == -1)
1431 LogMsg("myCFSocketCallBack ioctl(FIONREAD) error %d", errno);
1432 static unsigned int numLogMessages = 0;
1433 if (numLogMessages++ < 100)
1434 LogMsg("myCFSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
1435 s1, err, save_errno, strerror(save_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
1436 if (numLogMessages > 5)
1437 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)", 3375328,
1438 "Alternatively, you can send email to radar-3387020@group.apple.com. "
1439 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1440
1441 sleep(1); // After logging this error, rate limit so we don't flood syslog
1442 }
1443 }
1444
1445 // TCP socket support for unicast DNS and Dynamic DNS Update
1446
1447 typedef struct
1448 {
1449 TCPConnectionCallback callback;
1450 void *context;
1451 int connected;
1452 } tcpInfo_t;
1453
1454 mDNSlocal void tcpCFSocketCallback(CFSocketRef cfs, CFSocketCallBackType CallbackType, CFDataRef address,
1455 const void *data, void *context)
1456 {
1457 #pragma unused(CallbackType, address, data)
1458 mDNSBool connect = mDNSfalse;
1459
1460 tcpInfo_t *info = context;
1461 if (!info->connected)
1462 {
1463 connect = mDNStrue;
1464 info->connected = mDNStrue; // prevent connected flag from being set in future callbacks
1465 }
1466 info->callback(CFSocketGetNative(cfs), info->context, connect);
1467 // NOTE: the callback may call CloseConnection here, which frees the context structure!
1468 }
1469
1470 mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
1471 TCPConnectionCallback callback, void *context, int *descriptor)
1472 {
1473 int sd, on = 1; // "on" for setsockopt
1474 struct sockaddr_in saddr;
1475 CFSocketContext cfContext = { 0, NULL, 0, 0, 0 };
1476 tcpInfo_t *info;
1477 CFSocketRef sr;
1478 CFRunLoopSourceRef rls;
1479
1480 (void)InterfaceID; //!!!KRS use this if non-zero!!!
1481
1482 *descriptor = 0;
1483 if (dst->type != mDNSAddrType_IPv4)
1484 {
1485 LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: opperation not supported");
1486 return mStatus_UnknownErr;
1487 }
1488
1489 bzero(&saddr, sizeof(saddr));
1490 saddr.sin_family = AF_INET;
1491 saddr.sin_port = dstport.NotAnInteger;
1492 saddr.sin_len = sizeof(saddr);
1493 memcpy(&saddr.sin_addr, &dst->ip.v4.NotAnInteger, sizeof(saddr.sin_addr));
1494
1495 // Don't send if it would cause dial on demand connection initiation.
1496 if (AddrRequiresPPPConnection((struct sockaddr *)&saddr))
1497 {
1498 debugf("mDNSPlatformTCPConnect: Surpressing sending to avoid dial-on-demand connection");
1499 return mStatus_UnknownErr;
1500 }
1501
1502 sd = socket(AF_INET, SOCK_STREAM, 0);
1503 if (sd < 3) { LogMsg("mDNSPlatformTCPConnect: socket error %d errno %d (%s)", sd, errno, strerror(errno)); return mStatus_UnknownErr; }
1504
1505 // set non-blocking
1506 if (fcntl(sd, F_SETFL, O_NONBLOCK) < 0)
1507 {
1508 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno));
1509 return mStatus_UnknownErr;
1510 }
1511
1512 // receive interface identifiers
1513 if (setsockopt(sd, IPPROTO_IP, IP_RECVIF, &on, sizeof(on)) < 0)
1514 {
1515 LogMsg("setsockopt IP_RECVIF - %s", strerror(errno));
1516 return mStatus_UnknownErr;
1517 }
1518 // set up CF wrapper, add to Run Loop
1519 info = mallocL("mDNSPlatformTCPConnect", sizeof(tcpInfo_t));
1520 info->callback = callback;
1521 info->context = context;
1522 cfContext.info = info;
1523 sr = CFSocketCreateWithNative(kCFAllocatorDefault, sd, kCFSocketReadCallBack | kCFSocketConnectCallBack,
1524 tcpCFSocketCallback, &cfContext);
1525 if (!sr)
1526 {
1527 LogMsg("ERROR: mDNSPlatformTCPConnect - CFSocketRefCreateWithNative failed");
1528 freeL("mDNSPlatformTCPConnect", info);
1529 return mStatus_UnknownErr;
1530 }
1531
1532 rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sr, 0);
1533 if (!rls)
1534 {
1535 LogMsg("ERROR: mDNSPlatformTCPConnect - CFSocketCreateRunLoopSource failed");
1536 freeL("mDNSPlatformTCPConnect", info);
1537 return mStatus_UnknownErr;
1538 }
1539
1540 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
1541 CFRelease(rls);
1542
1543 // initiate connection wth peer
1544 if (connect(sd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
1545 {
1546 if (errno == EINPROGRESS)
1547 {
1548 info->connected = 0;
1549 *descriptor= sd;
1550 return mStatus_ConnPending;
1551 }
1552 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: %s", strerror(errno));
1553 freeL("mDNSPlatformTCPConnect", info);
1554 CFSocketInvalidate(sr); // Note: Also closes the underlying socket
1555 return mStatus_ConnFailed;
1556 }
1557 info->connected = 1;
1558 *descriptor = sd;
1559 return mStatus_ConnEstablished;
1560 }
1561
1562 mDNSexport void mDNSPlatformTCPCloseConnection(int sd)
1563 {
1564 CFSocketContext cfContext;
1565 tcpInfo_t *info;
1566 CFSocketRef sr;
1567
1568 if (sd < 3) LogMsg("mDNSPlatformTCPCloseConnection: ERROR sd %d < 3", sd);
1569
1570 // Get the CFSocket for the descriptor
1571 sr = CFSocketCreateWithNative(kCFAllocatorDefault, sd, kCFSocketNoCallBack, NULL, NULL);
1572 if (!sr) { LogMsg("ERROR: mDNSPlatformTCPCloseConnection - CFSocketCreateWithNative returned NULL"); return; }
1573
1574 CFSocketGetContext(sr, &cfContext);
1575 if (!cfContext.info)
1576 {
1577 LogMsg("ERROR: mDNSPlatformTCPCloseConnection - could not retreive tcpInfo from socket context");
1578 CFRelease(sr);
1579 return;
1580 }
1581 CFRelease(sr); // this only releases the copy we allocated with CreateWithNative above
1582
1583 info = cfContext.info;
1584
1585 // Note: MUST NOT close the underlying native BSD socket.
1586 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately,
1587 // because it first has to unhook the sockets from its select() call, before it can safely close them.
1588 CFSocketInvalidate(sr);
1589 CFRelease(sr);
1590 freeL("mDNSPlatformTCPCloseConnection", info);
1591 }
1592
1593 mDNSexport int mDNSPlatformReadTCP(int sd, void *buf, int buflen)
1594 {
1595 int nread = recv(sd, buf, buflen, 0);
1596 if (nread < 0)
1597 {
1598 if (errno == EAGAIN) return 0; // no data available (call would block)
1599 LogMsg("ERROR: mDNSPlatformReadTCP - recv: %s", strerror(errno));
1600 return -1;
1601 }
1602 return nread;
1603 }
1604
1605 mDNSexport int mDNSPlatformWriteTCP(int sd, const char *msg, int len)
1606 {
1607 int nsent = send(sd, msg, len, 0);
1608
1609 if (nsent < 0)
1610 {
1611 if (errno == EAGAIN) return 0; // blocked
1612 LogMsg("ERROR: mDNSPlatformWriteTCP - sendL %s", strerror(errno));
1613 return -1;
1614 }
1615 return nsent;
1616 }
1617
1618 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
1619 mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
1620 {
1621 CFStringEncoding encoding = kCFStringEncodingUTF8;
1622 CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
1623 if (cfs)
1624 {
1625 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
1626 CFRelease(cfs);
1627 }
1628 }
1629
1630 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
1631 mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel)
1632 {
1633 CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
1634 if (cfs)
1635 {
1636 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
1637 CFRelease(cfs);
1638 }
1639 }
1640
1641 mDNSlocal mDNSBool DDNSSettingEnabled(CFDictionaryRef dict)
1642 {
1643 mDNSs32 val;
1644 CFNumberRef state = CFDictionaryGetValue(dict, CFSTR("Enabled"));
1645 if (!state) return mDNSfalse;
1646 if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val)) { LogMsg("ERROR: DDNSSettingEnabled - CFNumberGetValue"); return mDNSfalse; }
1647 return val ? mDNStrue : mDNSfalse;
1648 }
1649
1650 mDNSlocal void GetUserSpecifiedDDNSConfig(domainname *const fqdn, domainname *const regDomain, CFArrayRef *const browseDomains)
1651 {
1652 char buf[MAX_ESCAPED_DOMAIN_NAME];
1653
1654 fqdn->c[0] = 0;
1655 regDomain->c[0] = 0;
1656 buf[0] = 0;
1657 *browseDomains = NULL;
1658
1659 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetUserSpecifiedDDNSConfig"), NULL, NULL);
1660 if (store)
1661 {
1662 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, CFSTR("Setup:/Network/DynamicDNS"));
1663 if (dict)
1664 {
1665 CFArrayRef fqdnArray = CFDictionaryGetValue(dict, CFSTR("HostNames"));
1666 if (fqdnArray)
1667 {
1668 CFDictionaryRef fqdnDict = CFArrayGetValueAtIndex(fqdnArray, 0); // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
1669 if (fqdnDict && DDNSSettingEnabled(fqdnDict))
1670 {
1671 CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain"));
1672 if (name)
1673 {
1674 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
1675 !MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0])
1676 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)");
1677 else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf);
1678 }
1679 }
1680 }
1681
1682 CFArrayRef regArray = CFDictionaryGetValue(dict, CFSTR("RegistrationDomains"));
1683 if (regArray)
1684 {
1685 CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0);
1686 if (regDict && DDNSSettingEnabled(regDict))
1687 {
1688 CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain"));
1689 if (name)
1690 {
1691 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
1692 !MakeDomainNameFromDNSNameString(regDomain, buf) || !regDomain->c[0])
1693 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)");
1694 else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration zone: %s", buf);
1695 }
1696 }
1697 }
1698 CFArrayRef browseArray = CFDictionaryGetValue(dict, CFSTR("BrowseDomains"));
1699 if (browseArray)
1700 {
1701 CFRetain(browseArray);
1702 *browseDomains = browseArray;
1703 }
1704 CFRelease(dict);
1705 }
1706 CFRelease(store);
1707 }
1708 }
1709
1710 mDNSlocal void SetDDNSNameStatus(domainname *const dname, mStatus status)
1711 {
1712 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:SetDDNSNameStatus"), NULL, NULL);
1713 if (store)
1714 {
1715 char uname[MAX_ESCAPED_DOMAIN_NAME];
1716 ConvertDomainNameToCString(dname, uname);
1717 char *p = uname;
1718
1719 while (*p)
1720 {
1721 *p = tolower(*p);
1722 if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
1723 p++;
1724 }
1725
1726 const void *StatusKey = CFSTR("Status");
1727 const void *StatusVal = CFNumberCreate(NULL, kCFNumberSInt32Type, &status); // CFNumberRef
1728 const void *StatusDict = CFDictionaryCreate(NULL, &StatusKey, &StatusVal, 1, NULL, NULL);
1729
1730 const void *HostKey = CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8);
1731 const void *HostDict = CFDictionaryCreate(NULL, &HostKey, &StatusDict, 1, NULL, NULL);
1732
1733 const void *StateKey = CFSTR("HostNames"); // CFStringRef
1734 CFDictionaryRef StateDict = CFDictionaryCreate(NULL, &StateKey, &HostDict, 1, NULL, NULL);
1735 SCDynamicStoreSetValue(store, CFSTR("State:/Network/DynamicDNS"), StateDict);
1736
1737 CFRelease(StateDict);
1738 CFRelease(StateKey);
1739 CFRelease(HostDict);
1740 CFRelease(HostKey);
1741 CFRelease(StatusDict);
1742 CFRelease(StatusVal);
1743 CFRelease(StatusKey);
1744 CFRelease(store);
1745 }
1746 }
1747
1748 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
1749 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
1750 mDNSlocal mStatus SetupSocket(mDNS *const m, CFSocketSet *cp, mDNSBool mcast, const mDNSAddr *ifaddr, u_short sa_family)
1751 {
1752 int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
1753 CFSocketRef *c = (sa_family == AF_INET) ? &cp->cfsv4 : &cp->cfsv6;
1754 CFRunLoopSourceRef *r = (sa_family == AF_INET) ? &cp->rlsv4 : &cp->rlsv6;
1755 const int on = 1;
1756 const int twofivefive = 255;
1757 mStatus err = mStatus_NoError;
1758 char *errstr = mDNSNULL;
1759
1760 mDNSIPPort port = (mcast | m->CanReceiveUnicastOn5353) ? MulticastDNSPort : zeroIPPort;
1761
1762 if (*s >= 0) { LogMsg("SetupSocket ERROR: socket %d is already set", *s); return(-1); }
1763 if (*c) { LogMsg("SetupSocket ERROR: CFSocketRef %p is already set", *c); return(-1); }
1764
1765 // Open the socket...
1766 int skt = socket(sa_family, SOCK_DGRAM, IPPROTO_UDP);
1767 if (skt < 3) { LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno)); return(skt); }
1768
1769 // ... with a shared UDP port, if it's for multicast receiving
1770 if (port.NotAnInteger) err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
1771 if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; }
1772
1773 if (sa_family == AF_INET)
1774 {
1775 // We want to receive destination addresses
1776 err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
1777 if (err < 0) { errstr = "setsockopt - IP_RECVDSTADDR"; goto fail; }
1778
1779 // We want to receive interface identifiers
1780 err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
1781 if (err < 0) { errstr = "setsockopt - IP_RECVIF"; goto fail; }
1782
1783 // We want to receive packet TTL value so we can check it
1784 err = setsockopt(skt, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on));
1785 // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
1786
1787 // Add multicast group membership on this interface, if it's for multicast receiving
1788 if (mcast)
1789 {
1790 struct in_addr addr = { ifaddr->ip.v4.NotAnInteger };
1791 struct ip_mreq imr;
1792 imr.imr_multiaddr.s_addr = AllDNSLinkGroupv4.NotAnInteger;
1793 imr.imr_interface = addr;
1794 err = setsockopt(skt, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
1795 if (err < 0) { errstr = "setsockopt - IP_ADD_MEMBERSHIP"; goto fail; }
1796
1797 // Specify outgoing interface too
1798 err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_IF, &addr, sizeof(addr));
1799 if (err < 0) { errstr = "setsockopt - IP_MULTICAST_IF"; goto fail; }
1800 }
1801
1802 // Send unicast packets with TTL 255
1803 err = setsockopt(skt, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive));
1804 if (err < 0) { errstr = "setsockopt - IP_TTL"; goto fail; }
1805
1806 // And multicast packets with TTL 255 too
1807 err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive));
1808 if (err < 0) { errstr = "setsockopt - IP_MULTICAST_TTL"; goto fail; }
1809
1810 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
1811 const int ip_tosbits = IPTOS_LOWDELAY | IPTOS_THROUGHPUT;
1812 err = setsockopt(skt, IPPROTO_IP, IP_TOS, &ip_tosbits, sizeof(ip_tosbits));
1813 if (err < 0) { errstr = "setsockopt - IP_TOS"; goto fail; }
1814
1815 // And start listening for packets
1816 struct sockaddr_in listening_sockaddr;
1817 listening_sockaddr.sin_family = AF_INET;
1818 listening_sockaddr.sin_port = port.NotAnInteger;
1819 listening_sockaddr.sin_addr.s_addr = 0; // Want to receive multicasts AND unicasts on this socket
1820 err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr));
1821 if (err) { errstr = "bind"; goto fail; }
1822 }
1823 else if (sa_family == AF_INET6)
1824 {
1825 // We want to receive destination addresses and receive interface identifiers
1826 err = setsockopt(skt, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on));
1827 if (err < 0) { errstr = "setsockopt - IPV6_PKTINFO"; goto fail; }
1828
1829 // We want to receive packet hop count value so we can check it
1830 err = setsockopt(skt, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof(on));
1831 if (err < 0) { errstr = "setsockopt - IPV6_HOPLIMIT"; goto fail; }
1832
1833 // We want to receive only IPv6 packets, without this option, we may
1834 // get IPv4 addresses as mapped addresses.
1835 err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
1836 if (err < 0) { errstr = "setsockopt - IPV6_V6ONLY"; goto fail; }
1837
1838 if (mcast)
1839 {
1840 // Add multicast group membership on this interface, if it's for multicast receiving
1841 int interface_id = if_nametoindex(cp->info->ifa_name);
1842 struct ipv6_mreq i6mr;
1843 i6mr.ipv6mr_interface = interface_id;
1844 i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroupv6;
1845 err = setsockopt(skt, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
1846 if (err < 0) { errstr = "setsockopt - IPV6_JOIN_GROUP"; goto fail; }
1847
1848 // Specify outgoing interface too
1849 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_IF, &interface_id, sizeof(interface_id));
1850 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_IF"; goto fail; }
1851 }
1852
1853 // Send unicast packets with TTL 255
1854 err = setsockopt(skt, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &twofivefive, sizeof(twofivefive));
1855 if (err < 0) { errstr = "setsockopt - IPV6_UNICAST_HOPS"; goto fail; }
1856
1857 // And multicast packets with TTL 255 too
1858 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive));
1859 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_HOPS"; goto fail; }
1860
1861 // Note: IPV6_TCLASS appears not to be implemented on OS X right now (or indeed on ANY version of Unix?)
1862 #ifdef IPV6_TCLASS
1863 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
1864 int tclass = IPTOS_LOWDELAY | IPTOS_THROUGHPUT; // This may not be right (since tclass is not implemented on OS X, I can't test it)
1865 err = setsockopt(skt, IPPROTO_IPV6, IPV6_TCLASS, &tclass, sizeof(tclass));
1866 if (err < 0) { errstr = "setsockopt - IPV6_TCLASS"; goto fail; }
1867 #endif
1868
1869 // Want to receive our own packets
1870 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on));
1871 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_LOOP"; goto fail; }
1872
1873 // And start listening for packets
1874 struct sockaddr_in6 listening_sockaddr6;
1875 bzero(&listening_sockaddr6, sizeof(listening_sockaddr6));
1876 listening_sockaddr6.sin6_len = sizeof(listening_sockaddr6);
1877 listening_sockaddr6.sin6_family = AF_INET6;
1878 listening_sockaddr6.sin6_port = port.NotAnInteger;
1879 listening_sockaddr6.sin6_flowinfo = 0;
1880 // listening_sockaddr6.sin6_addr = IN6ADDR_ANY_INIT; // Want to receive multicasts AND unicasts on this socket
1881 listening_sockaddr6.sin6_scope_id = 0;
1882 err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6));
1883 if (err) { errstr = "bind"; goto fail; }
1884 }
1885
1886 fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
1887 *s = skt;
1888 CFSocketContext myCFSocketContext = { 0, cp, NULL, NULL, NULL };
1889 *c = CFSocketCreateWithNative(kCFAllocatorDefault, *s, kCFSocketReadCallBack, myCFSocketCallBack, &myCFSocketContext);
1890 *r = CFSocketCreateRunLoopSource(kCFAllocatorDefault, *c, 0);
1891 CFRunLoopAddSource(CFRunLoopGetCurrent(), *r, kCFRunLoopDefaultMode);
1892
1893 return(err);
1894
1895 fail:
1896 LogMsg("%s error %ld errno %d (%s)", errstr, err, errno, strerror(errno));
1897 if (!strcmp(errstr, "bind") && errno == EADDRINUSE)
1898 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed", 3814904,
1899 "Alternatively, you can send email to radar-3387020@group.apple.com. "
1900 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1901 close(skt);
1902 return(err);
1903 }
1904
1905 mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
1906 {
1907 if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
1908
1909 if (sa->sa_family == AF_INET)
1910 {
1911 struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
1912 ip->type = mDNSAddrType_IPv4;
1913 ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
1914 return(mStatus_NoError);
1915 }
1916
1917 if (sa->sa_family == AF_INET6)
1918 {
1919 struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
1920 ip->type = mDNSAddrType_IPv6;
1921 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
1922 ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
1923 return(mStatus_NoError);
1924 }
1925
1926 LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
1927 return(mStatus_Invalid);
1928 }
1929
1930 mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name)
1931 {
1932 mDNSEthAddr eth = zeroEthAddr;
1933 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetBSSID"), NULL, NULL);
1934 if (store)
1935 {
1936 CFStringRef entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name);
1937 if (entityname)
1938 {
1939 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, entityname);
1940 if (dict)
1941 {
1942 CFRange range = { 0, 6 }; // Offset, length
1943 CFDataRef data = CFDictionaryGetValue(dict, CFSTR("BSSID"));
1944 if (data && CFDataGetLength(data) == 6) CFDataGetBytes(data, range, eth.b);
1945 CFRelease(dict);
1946 }
1947 CFRelease(entityname);
1948 }
1949 CFRelease(store);
1950 }
1951 return(eth);
1952 }
1953
1954 mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa, mDNSs32 utc)
1955 {
1956 mDNSu32 scope_id = if_nametoindex(ifa->ifa_name);
1957 mDNSEthAddr bssid = GetBSSID(ifa->ifa_name);
1958
1959 mDNSAddr ip, mask;
1960 if (SetupAddr(&ip, ifa->ifa_addr ) != mStatus_NoError) return(NULL);
1961 if (SetupAddr(&mask, ifa->ifa_netmask) != mStatus_NoError) return(NULL);
1962
1963 NetworkInterfaceInfoOSX **p;
1964 for (p = &m->p->InterfaceList; *p; p = &(*p)->next)
1965 if (scope_id == (*p)->scope_id && mDNSSameAddress(&ip, &(*p)->ifinfo.ip) && mDNSSameEthAddress(&bssid, &(*p)->BSSID))
1966 {
1967 debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, *p);
1968 (*p)->Exists = mDNStrue;
1969 return(*p);
1970 }
1971
1972 NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
1973 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i);
1974 if (!i) return(mDNSNULL);
1975 bzero(i, sizeof(NetworkInterfaceInfoOSX));
1976 i->ifa_name = (char *)mallocL("NetworkInterfaceInfoOSX name", strlen(ifa->ifa_name) + 1);
1977 if (!i->ifa_name) { freeL("NetworkInterfaceInfoOSX", i); return(mDNSNULL); }
1978 strcpy(i->ifa_name, ifa->ifa_name);
1979
1980 i->ifinfo.InterfaceID = mDNSNULL;
1981 i->ifinfo.ip = ip;
1982 i->ifinfo.mask = mask;
1983 strncpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname));
1984 i->ifinfo.ifname[sizeof(i->ifinfo.ifname)-1] = 0;
1985 i->ifinfo.Advertise = m->AdvertiseLocalAddresses;
1986 i->ifinfo.McastTxRx = mDNSfalse; // For now; will be set up later at the end of UpdateInterfaceList
1987
1988 i->next = mDNSNULL;
1989 i->Exists = mDNStrue;
1990 i->LastSeen = utc;
1991 i->scope_id = scope_id;
1992 i->BSSID = bssid;
1993 i->sa_family = ifa->ifa_addr->sa_family;
1994 i->Multicast = (ifa->ifa_flags & IFF_MULTICAST) && !(ifa->ifa_flags & IFF_POINTOPOINT);
1995
1996 i->ss.m = m;
1997 i->ss.info = i;
1998 i->ss.sktv4 = i->ss.sktv6 = -1;
1999 i->ss.cfsv4 = i->ss.cfsv6 = NULL;
2000 i->ss.rlsv4 = i->ss.rlsv6 = NULL;
2001
2002 *p = i;
2003 return(i);
2004 }
2005
2006 mDNSlocal NetworkInterfaceInfoOSX *FindRoutableIPv4(mDNS *const m, mDNSu32 scope_id)
2007 {
2008 NetworkInterfaceInfoOSX *i;
2009 for (i = m->p->InterfaceList; i; i = i->next)
2010 if (i->Exists && i->scope_id == scope_id && i->ifinfo.ip.type == mDNSAddrType_IPv4)
2011 if (!(i->ifinfo.ip.ip.v4.b[0] == 169 && i->ifinfo.ip.ip.v4.b[1] == 254))
2012 return(i);
2013 return(mDNSNULL);
2014 }
2015
2016 mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
2017 {
2018 mDNSBool foundav4 = mDNSfalse;
2019 mDNSBool foundav6 = mDNSfalse;
2020 struct ifaddrs *ifa = myGetIfAddrs(1);
2021 struct ifaddrs *v4Loopback = NULL;
2022 struct ifaddrs *v6Loopback = NULL;
2023 mDNSEthAddr PrimaryMAC = zeroEthAddr;
2024 char defaultname[32];
2025 int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
2026 if (InfoSocket < 3) LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno));
2027 if (m->SleepState) ifa = NULL;
2028
2029 while (ifa)
2030 {
2031 #if LIST_ALL_INTERFACES
2032 if (ifa->ifa_addr->sa_family == AF_APPLETALK)
2033 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
2034 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
2035 else if (ifa->ifa_addr->sa_family == AF_LINK)
2036 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
2037 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
2038 else if (ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6)
2039 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
2040 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
2041 if (!(ifa->ifa_flags & IFF_UP))
2042 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
2043 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
2044 if (!(ifa->ifa_flags & IFF_MULTICAST))
2045 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
2046 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
2047 if (ifa->ifa_flags & IFF_POINTOPOINT)
2048 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
2049 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
2050 if (ifa->ifa_flags & IFF_LOOPBACK)
2051 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
2052 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
2053 #endif
2054
2055 if (ifa->ifa_addr->sa_family == AF_LINK)
2056 {
2057 struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
2058 if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == sizeof(PrimaryMAC) && mDNSSameEthAddress(&PrimaryMAC, &zeroEthAddr))
2059 mDNSPlatformMemCopy(sdl->sdl_data + sdl->sdl_nlen, PrimaryMAC.b, 6);
2060 }
2061
2062 if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr)
2063 if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6)
2064 {
2065 if (!ifa->ifa_netmask)
2066 {
2067 mDNSAddr ip;
2068 SetupAddr(&ip, ifa->ifa_addr);
2069 LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
2070 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip);
2071 }
2072 else if (ifa->ifa_addr->sa_family != ifa->ifa_netmask->sa_family)
2073 {
2074 mDNSAddr ip;
2075 SetupAddr(&ip, ifa->ifa_addr);
2076 LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
2077 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip, ifa->ifa_netmask->sa_family);
2078 }
2079 else
2080 {
2081 int ifru_flags6 = 0;
2082 if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
2083 {
2084 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
2085 struct in6_ifreq ifr6;
2086 bzero((char *)&ifr6, sizeof(ifr6));
2087 strncpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
2088 ifr6.ifr_addr = *sin6;
2089 if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
2090 ifru_flags6 = ifr6.ifr_ifru.ifru_flags6;
2091 verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6);
2092 }
2093 if (!(ifru_flags6 & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
2094 {
2095 if (ifa->ifa_flags & IFF_LOOPBACK)
2096 if (ifa->ifa_addr->sa_family == AF_INET) v4Loopback = ifa;
2097 else v6Loopback = ifa;
2098 else
2099 {
2100 AddInterfaceToList(m, ifa, utc);
2101 if (ifa->ifa_addr->sa_family == AF_INET) foundav4 = mDNStrue;
2102 else foundav6 = mDNStrue;
2103 }
2104 }
2105 }
2106 }
2107 ifa = ifa->ifa_next;
2108 }
2109
2110 // For efficiency, we don't register a loopback interface when other interfaces of that family are available
2111 if (!foundav4 && v4Loopback) AddInterfaceToList(m, v4Loopback, utc);
2112 if (!foundav6 && v6Loopback) AddInterfaceToList(m, v6Loopback, utc);
2113
2114 // Now the list is complete, set the McastTxRx setting for each interface.
2115 // We always send and receive using IPv4.
2116 // To reduce traffic, we send and receive using IPv6 only on interfaces that have no routable IPv4 address.
2117 // Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
2118 // which means there's a good chance that most or all the other devices on that network should also have v4.
2119 // 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.
2120 // At this time, reducing the packet rate is more important than v6-only devices on a large configured network,
2121 // so we are willing to make that sacrifice.
2122 NetworkInterfaceInfoOSX *i;
2123 for (i = m->p->InterfaceList; i; i = i->next)
2124 if (i->Exists)
2125 {
2126 mDNSBool txrx = i->Multicast && ((i->ifinfo.ip.type == mDNSAddrType_IPv4) || !FindRoutableIPv4(m, i->scope_id));
2127 if (i->ifinfo.McastTxRx != txrx)
2128 {
2129 i->ifinfo.McastTxRx = txrx;
2130 i->Exists = 2; // State change; need to deregister and reregister this interface
2131 }
2132 }
2133 if (InfoSocket >= 0) close(InfoSocket);
2134
2135 mDNS_snprintf(defaultname, sizeof(defaultname), "Macintosh-%02X%02X%02X%02X%02X%02X",
2136 PrimaryMAC.b[0], PrimaryMAC.b[1], PrimaryMAC.b[2], PrimaryMAC.b[3], PrimaryMAC.b[4], PrimaryMAC.b[5]);
2137
2138 // Set up the nice label
2139 domainlabel nicelabel;
2140 nicelabel.c[0] = 0;
2141 GetUserSpecifiedFriendlyComputerName(&nicelabel);
2142 if (nicelabel.c[0] == 0)
2143 {
2144 LogMsg("Couldn't read user-specified Computer Name; using default “%s” instead", defaultname);
2145 MakeDomainLabelFromLiteralString(&nicelabel, defaultname);
2146 }
2147
2148 // Set up the RFC 1034-compliant label
2149 domainlabel hostlabel;
2150 hostlabel.c[0] = 0;
2151 GetUserSpecifiedLocalHostName(&hostlabel);
2152 if (hostlabel.c[0] == 0)
2153 {
2154 LogMsg("Couldn't read user-specified local hostname; using default “%s.local” instead", defaultname);
2155 MakeDomainLabelFromLiteralString(&hostlabel, defaultname);
2156 }
2157
2158 if (SameDomainLabel(m->p->usernicelabel.c, nicelabel.c))
2159 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m->p->usernicelabel.c, m->nicelabel.c);
2160 else
2161 {
2162 debugf("Updating m->nicelabel to %#s", nicelabel.c);
2163 m->p->usernicelabel = m->nicelabel = nicelabel;
2164 }
2165
2166 if (SameDomainLabel(m->p->userhostlabel.c, hostlabel.c))
2167 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m->p->userhostlabel.c, m->hostlabel.c);
2168 else
2169 {
2170 debugf("Updating m->hostlabel to %#s", hostlabel.c);
2171 m->p->userhostlabel = m->hostlabel = hostlabel;
2172 mDNS_SetFQDN(m);
2173 }
2174
2175 return(mStatus_NoError);
2176 }
2177
2178 mDNSlocal int CountMaskBits(mDNSAddr *mask)
2179 {
2180 int i = 0, bits = 0;
2181 int bytes = mask->type == mDNSAddrType_IPv4 ? 4 : mask->type == mDNSAddrType_IPv6 ? 16 : 0;
2182 while (i < bytes)
2183 {
2184 mDNSu8 b = mask->ip.v6.b[i++];
2185 while (b & 0x80) { bits++; b <<= 1; }
2186 if (b) return(-1);
2187 }
2188 while (i < bytes) if (mask->ip.v6.b[i++]) return(-1);
2189 return(bits);
2190 }
2191
2192 // returns count of non-link local V4 addresses registered
2193 mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
2194 {
2195 NetworkInterfaceInfoOSX *i;
2196 int count = 0;
2197 for (i = m->p->InterfaceList; i; i = i->next)
2198 if (i->Exists)
2199 {
2200 NetworkInterfaceInfo *n = &i->ifinfo;
2201 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, i->sa_family);
2202 if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifa_name);
2203
2204 if (n->InterfaceID && n->InterfaceID != (mDNSInterfaceID)primary) // Sanity check
2205 {
2206 LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != primary %p", n->InterfaceID, primary);
2207 n->InterfaceID = mDNSNULL;
2208 }
2209
2210 if (!n->InterfaceID)
2211 {
2212 // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
2213 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
2214 // If n->InterfaceID is NOT set, then we haven't registered it and we should not try to deregister it
2215 n->InterfaceID = (mDNSInterfaceID)primary;
2216 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
2217 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
2218 // If the interface is an old one that went away and came back in less than a minute, then we're in a flapping scenario.
2219 mDNSBool flapping = (utc - i->LastSeen > 0 && utc - i->LastSeen < 60);
2220 mDNS_RegisterInterface(m, n, flapping ? mDNSPlatformOneSecond * 5 : 0);
2221 if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && (i->ifinfo.ip.ip.v4.b[0] != 169 || i->ifinfo.ip.ip.v4.b[1] != 254)) count++;
2222 LogOperation("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s",
2223 i->ifa_name, i->scope_id, &i->BSSID, primary, &n->ip, CountMaskBits(&n->mask),
2224 flapping ? " (Flapping)" : "", n->InterfaceActive ? " (Primary)" : "");
2225 }
2226
2227 if (!n->McastTxRx)
2228 debugf("SetupActiveInterfaces: No Tx/Rx on %5s(%lu) %.6a InterfaceID %p %#a", i->ifa_name, i->scope_id, &i->BSSID, primary, &n->ip);
2229 else
2230 {
2231 if (i->sa_family == AF_INET && primary->ss.sktv4 == -1)
2232 {
2233 mStatus err = SetupSocket(m, &primary->ss, mDNStrue, &i->ifinfo.ip, AF_INET);
2234 if (err == 0) debugf("SetupActiveInterfaces: v4 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d", primary->ss.sktv4, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip, CountMaskBits(&n->mask));
2235 else LogMsg("SetupActiveInterfaces: v4 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d FAILED", primary->ss.sktv4, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip, CountMaskBits(&n->mask));
2236 }
2237
2238 if (i->sa_family == AF_INET6 && primary->ss.sktv6 == -1)
2239 {
2240 mStatus err = SetupSocket(m, &primary->ss, mDNStrue, &i->ifinfo.ip, AF_INET6);
2241 if (err == 0) debugf("SetupActiveInterfaces: v6 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d", primary->ss.sktv6, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip, CountMaskBits(&n->mask));
2242 else LogMsg("SetupActiveInterfaces: v6 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d FAILED", primary->ss.sktv6, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip, CountMaskBits(&n->mask));
2243 }
2244 }
2245 }
2246 return count;
2247 }
2248
2249 mDNSlocal void MarkAllInterfacesInactive(mDNS *const m, mDNSs32 utc)
2250 {
2251 NetworkInterfaceInfoOSX *i;
2252 for (i = m->p->InterfaceList; i; i = i->next)
2253 {
2254 if (i->Exists) i->LastSeen = utc;
2255 i->Exists = mDNSfalse;
2256 }
2257 }
2258
2259 mDNSlocal void CloseRunLoopSourceSocket(CFRunLoopSourceRef rls, CFSocketRef cfs)
2260 {
2261 // Note: CFSocketInvalidate also closes the underlying socket for us
2262 // Comments show retain counts (obtained via CFGetRetainCount()) after each call. rls 3 cfs 3
2263 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); // rls 2 cfs 3
2264 CFRelease(rls); // rls ? cfs 3
2265 CFSocketInvalidate(cfs); // rls ? cfs 1
2266 CFRelease(cfs); // rls ? cfs ?
2267 }
2268
2269 mDNSlocal void CloseSocketSet(CFSocketSet *ss)
2270 {
2271 // Note: MUST NOT close the underlying native BSD sockets.
2272 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately,
2273 // because it first has to unhook the sockets from its select() call, before it can safely close them.
2274 if (ss->cfsv4) CloseRunLoopSourceSocket(ss->rlsv4, ss->cfsv4);
2275 if (ss->cfsv6) CloseRunLoopSourceSocket(ss->rlsv6, ss->cfsv6);
2276 ss->sktv4 = ss->sktv6 = -1;
2277 ss->cfsv4 = ss->cfsv6 = NULL;
2278 ss->rlsv4 = ss->rlsv6 = NULL;
2279 }
2280
2281 // returns count of non-link local V4 addresses deregistered
2282 mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc)
2283 {
2284 // First pass:
2285 // If an interface is going away, then deregister this from the mDNSCore.
2286 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
2287 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
2288 // it refers to has gone away we'll crash.
2289 // Don't actually close the sockets or free the memory yet: When the last representative of an interface goes away
2290 // mDNSCore may want to send goodbye packets on that interface. (Not yet implemented, but a good idea anyway.)
2291 NetworkInterfaceInfoOSX *i;
2292 int count = 0;
2293 for (i = m->p->InterfaceList; i; i = i->next)
2294 {
2295 // 1. If this interface is no longer active, or its InterfaceID is changing, deregister it
2296 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, i->sa_family);
2297 if (i->ifinfo.InterfaceID)
2298 if (i->Exists == 0 || i->Exists == 2 || i->ifinfo.InterfaceID != (mDNSInterfaceID)primary)
2299 {
2300 LogOperation("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p %#a/%d%s",
2301 i->ifa_name, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID,
2302 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), i->ifinfo.InterfaceActive ? " (Primary)" : "");
2303 mDNS_DeregisterInterface(m, &i->ifinfo);
2304 if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && (i->ifinfo.ip.ip.v4.b[0] != 169 || i->ifinfo.ip.ip.v4.b[1] != 254)) count++;
2305 i->ifinfo.InterfaceID = mDNSNULL;
2306 // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
2307 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
2308 // If n->InterfaceID is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
2309 }
2310 }
2311
2312 // Second pass:
2313 // Now that everything that's going to deregister has done so, we can close sockets and free the memory
2314 NetworkInterfaceInfoOSX **p = &m->p->InterfaceList;
2315 while (*p)
2316 {
2317 i = *p;
2318 // 2. Close all our CFSockets. We'll recreate them later as necessary.
2319 // (We may have previously had both v4 and v6, and we may not need both any more.)
2320 CloseSocketSet(&i->ss);
2321 // 3. If no longer active, delete interface from list and free memory
2322 if (!i->Exists)
2323 {
2324 if (i->LastSeen == utc) i->LastSeen = utc - 1;
2325 mDNSBool delete = (NumCacheRecordsForInterfaceID(m, (mDNSInterfaceID)i) == 0) && (utc - i->LastSeen >= 60);
2326 LogOperation("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
2327 i->ifa_name, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID,
2328 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), utc - i->LastSeen,
2329 i->ifinfo.InterfaceActive ? " (Primary)" : "");
2330 if (delete)
2331 {
2332 *p = i->next;
2333 if (i->ifa_name) freeL("NetworkInterfaceInfoOSX name", i->ifa_name);
2334 freeL("NetworkInterfaceInfoOSX", i);
2335 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
2336 }
2337 }
2338 p = &i->next;
2339 }
2340 return count;
2341 }
2342
2343 mDNSlocal mStatus GetDNSConfig(void **result)
2344 {
2345 #ifndef MAC_OS_X_VERSION_10_4
2346 static int MessageShown = 0;
2347 if (!MessageShown) { MessageShown = 1; LogMsg("Note: Compiled without Apple-specific split DNS support"); }
2348 *result = NULL;
2349 return mStatus_UnsupportedErr;
2350 #else
2351
2352 *result = dns_configuration_copy();
2353
2354 if (!*result)
2355 {
2356 // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
2357 if (mDNSMacOSXSystemBuildNumber(NULL) < 8) return mStatus_UnsupportedErr;
2358
2359 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
2360 // Apparently this is expected behaviour -- "not a bug".
2361 // Accordingly, we suppress syslog messages for the first three minutes after boot.
2362 // If we are still getting failures after three minutes, then we log them.
2363 if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return mStatus_NoError;
2364
2365 LogMsg("GetDNSConfig: Error: dns_configuration_copy returned NULL");
2366 return mStatus_UnknownErr;
2367 }
2368 return mStatus_NoError;
2369 #endif // MAC_OS_X_VERSION_10_4
2370 }
2371
2372 mDNSlocal mStatus RegisterSplitDNS(mDNS *m)
2373 {
2374 (void)m; // unused on 10.3 systems
2375 void *v;
2376 mStatus err = GetDNSConfig(&v);
2377 if (!err && v)
2378 {
2379 #ifdef MAC_OS_X_VERSION_10_4
2380 int i;
2381 dns_config_t *config = v; // use void * to allow compilation on 10.3 systems
2382 mDNS_DeleteDNSServers(m);
2383
2384 LogOperation("RegisterSplitDNS: Registering %d resolvers", config->n_resolver);
2385 for (i = 0; i < config->n_resolver; i++)
2386 {
2387 int j, n;
2388 domainname d;
2389 dns_resolver_t *r = config->resolver[i];
2390 if (r->port == MulticastDNSPort.NotAnInteger) continue; // ignore configurations for .local
2391 if (r->search_order == DEFAULT_SEARCH_ORDER || !r->domain || !*r->domain) d.c[0] = 0; // we ignore domain for "default" resolver
2392 else if (!MakeDomainNameFromDNSNameString(&d, r->domain)) { LogMsg("RegisterSplitDNS: bad domain %s", r->domain); continue; }
2393
2394 // check if this is the lowest-weighted server for the domain
2395 for (j = 0; j < config->n_resolver; j++)
2396 {
2397 dns_resolver_t *p = config->resolver[j];
2398 if (p->port == MulticastDNSPort.NotAnInteger) continue;
2399 if (p->search_order <= r->search_order)
2400 {
2401 domainname tmp;
2402 if (p->search_order == DEFAULT_SEARCH_ORDER || !p->domain || !*p->domain) tmp.c[0] = '\0';
2403 else if (!MakeDomainNameFromDNSNameString(&tmp, p->domain)) { LogMsg("RegisterSplitDNS: bad domain %s", p->domain); continue; }
2404 if (SameDomainName(&d, &tmp))
2405 if (p->search_order < r->search_order || j < i) break; // if equal weights, pick first in list, otherwise pick lower-weight (p)
2406 }
2407 }
2408 if (j < config->n_resolver) // found a lower-weighted resolver for this domain
2409 { debugf("Rejecting DNS server in slot %d domain %##s (slot %d outranks)", i, d.c, j); continue; }
2410 // we're using this resolver - find the first IPv4 address
2411 for (n = 0; n < r->n_nameserver; n++)
2412 {
2413 if (r->nameserver[n]->sa_family == AF_INET && !AddrRequiresPPPConnection(r->nameserver[n]))
2414 {
2415 mDNSAddr saddr;
2416 if (SetupAddr(&saddr, r->nameserver[n])) { LogMsg("RegisterSplitDNS: bad IP address"); continue; }
2417 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);
2418 mDNS_AddDNSServer(m, &saddr, &d);
2419 break; // !!!KRS if we ever support round-robin servers, don't break here
2420 }
2421 }
2422 }
2423 dns_configuration_free(config);
2424 #endif
2425 }
2426 return err;
2427 }
2428
2429 mDNSlocal mStatus RegisterNameServers(mDNS *const m, CFDictionaryRef dict)
2430 {
2431 int i, count;
2432 CFArrayRef values;
2433 char buf[256];
2434 mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 0 } } } };
2435 CFStringRef s;
2436
2437 mDNS_DeleteDNSServers(m); // deregister orig list
2438 values = CFDictionaryGetValue(dict, kSCPropNetDNSServerAddresses);
2439 if (!values) return mStatus_NoError;
2440
2441 count = CFArrayGetCount(values);
2442 for (i = 0; i < count; i++)
2443 {
2444 s = CFArrayGetValueAtIndex(values, i);
2445 if (!s) { LogMsg("ERROR: RegisterNameServers - CFArrayGetValueAtIndex"); break; }
2446 if (!CFStringGetCString(s, buf, 256, kCFStringEncodingUTF8))
2447 {
2448 LogMsg("ERROR: RegisterNameServers - CFStringGetCString");
2449 continue;
2450 }
2451 if (!inet_aton(buf, (struct in_addr *)saddr.ip.v4.b))
2452 {
2453 LogMsg("ERROR: RegisterNameServers - invalid address string %s", buf);
2454 continue;
2455 }
2456 LogOperation("RegisterNameServers: Adding %#a", &saddr);
2457 mDNS_AddDNSServer(m, &saddr, NULL);
2458 }
2459 return mStatus_NoError;
2460 }
2461
2462 mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
2463 {
2464 (void)m; // unused
2465 ARListElem *elem = rr->RecordContext;
2466 if (result == mStatus_MemFree) freeL("FreeARElemCallback", elem);
2467 }
2468
2469 mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
2470 {
2471 SearchListElem *slElem = question->QuestionContext;
2472 ARListElem *arElem, *ptr, *prev;
2473 AuthRecord *dereg;
2474 const char *name;
2475 mStatus err;
2476
2477 if (AddRecord)
2478 {
2479 arElem = mallocL("FoundDomain - arElem", sizeof(ARListElem));
2480 if (!arElem) { LogMsg("ERROR: malloc"); return; }
2481 mDNS_SetupResourceRecord(&arElem->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, FreeARElemCallback, arElem);
2482 if (question == &slElem->BrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowse];
2483 else if (question == &slElem->DefBrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseDefault];
2484 else if (question == &slElem->LegacyBrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseLegacy];
2485 else if (question == &slElem->RegisterQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistration];
2486 else if (question == &slElem->DefRegisterQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistrationDefault];
2487 else { LogMsg("FoundDomain - unknown question"); return; }
2488
2489 MakeDomainNameFromDNSNameString(arElem->ar.resrec.name, name);
2490 AppendDNSNameString (arElem->ar.resrec.name, "local");
2491 AssignDomainName(&arElem->ar.resrec.rdata->u.name, &answer->rdata->u.name);
2492 err = mDNS_Register(m, &arElem->ar);
2493 if (err)
2494 {
2495 LogMsg("ERROR: FoundDomain - mDNS_Register returned %d", err);
2496 freeL("FoundDomain - arElem", arElem);
2497 return;
2498 }
2499 arElem->next = slElem->AuthRecs;
2500 slElem->AuthRecs = arElem;
2501 }
2502 else
2503 {
2504 ptr = slElem->AuthRecs;
2505 prev = NULL;
2506 while (ptr)
2507 {
2508 if (SameDomainName(&ptr->ar.resrec.rdata->u.name, &answer->rdata->u.name))
2509 {
2510 debugf("Deregistering PTR %s -> %s", ptr->ar.resrec.name->c, ptr->ar.resrec.rdata->u.name.c);
2511 dereg = &ptr->ar;
2512 if (prev) prev->next = ptr->next;
2513 else slElem->AuthRecs = ptr->next;
2514 ptr = ptr->next;
2515 err = mDNS_Deregister(m, dereg);
2516 if (err) LogMsg("ERROR: FoundDomain - mDNS_Deregister returned %d", err);
2517 }
2518 else
2519 {
2520 prev = ptr;
2521 ptr = ptr->next;
2522 }
2523 }
2524 }
2525 }
2526
2527 mDNSlocal void MarkSearchListElem(const char *d)
2528 {
2529 SearchListElem *new, *ptr;
2530 domainname domain;
2531
2532 if (!MakeDomainNameFromDNSNameString(&domain, d))
2533 { LogMsg("ERROR: MarkSearchListElem - bad domain %##s", d); return; }
2534
2535 if (SameDomainName(&domain, &localdomain) || SameDomainName(&domain, &LocalReverseMapomain))
2536 { debugf("MarkSearchListElem - ignoring local domain %##s", domain.c); return; }
2537
2538 // if domain is in list, mark as pre-existent (0)
2539 for (ptr = SearchList; ptr; ptr = ptr->next)
2540 if (SameDomainName(&ptr->domain, &domain))
2541 {
2542 if (ptr->flag != 1) ptr->flag = 0; // gracefully handle duplicates - if it is already marked as add, don't bump down to preexistent
2543 break;
2544 }
2545
2546 // if domain not in list, add to list, mark as add (1)
2547 if (!ptr)
2548 {
2549 new = mallocL("MarkSearchListElem - SearchListElem", sizeof(SearchListElem));
2550 if (!new) { LogMsg("ERROR: MarkSearchListElem - malloc"); return; }
2551 bzero(new, sizeof(SearchListElem));
2552 AssignDomainName(&new->domain, &domain);
2553 new->flag = 1; // add
2554 new->next = SearchList;
2555 SearchList = new;
2556 }
2557 }
2558
2559 // Get the search domains via OS X resolver routines. Returns mStatus_UnsupporterErr if compiled or run on 10.3 systems
2560 mDNSlocal mStatus GetSearchDomains(void)
2561 {
2562 void *v;
2563 mStatus err = GetDNSConfig(&v);
2564 if (!err && v)
2565 {
2566 #ifdef MAC_OS_X_VERSION_10_4
2567 int i;
2568 dns_config_t *config = v;
2569 if (!config->n_resolver) return err;
2570 dns_resolver_t *resolv = config->resolver[0]; // use the first slot for search domains
2571
2572 for (i = 0; i < resolv->n_search; i++) MarkSearchListElem(resolv->search[i]);
2573 if (resolv->domain) MarkSearchListElem(resolv->domain);
2574 dns_configuration_free(config);
2575 #endif
2576 }
2577 return err;
2578 }
2579
2580 // Get search domains from dynamic store - used as a fallback mechanism on 10.3 systems, if GetSearchDomains (above) fails.
2581 mDNSlocal void GetDSSearchDomains(CFDictionaryRef dict)
2582 {
2583 char buf[MAX_ESCAPED_DOMAIN_NAME];
2584 int i, count;
2585
2586 CFStringRef s;
2587
2588 // get all the domains from "Search Domains" field of sharing prefs
2589 if (dict)
2590 {
2591 CFArrayRef searchdomains = CFDictionaryGetValue(dict, kSCPropNetDNSSearchDomains);
2592 if (searchdomains)
2593 {
2594 count = CFArrayGetCount(searchdomains);
2595 for (i = 0; i < count; i++)
2596 {
2597 s = CFArrayGetValueAtIndex(searchdomains, i);
2598 if (!s) { LogMsg("ERROR: GetDSSearchDomains - CFArrayGetValueAtIndex"); break; }
2599 if (!CFStringGetCString(s, buf, MAX_ESCAPED_DOMAIN_NAME, kCFStringEncodingUTF8))
2600 {
2601 LogMsg("ERROR: GetDSSearchDomains - CFStringGetCString");
2602 continue;
2603 }
2604 MarkSearchListElem(buf);
2605 }
2606 }
2607
2608 // get DHCP domain field
2609 CFStringRef dname = CFDictionaryGetValue(dict, kSCPropNetDNSDomainName);
2610 if (dname)
2611 {
2612 if (CFStringGetCString(dname, buf, MAX_ESCAPED_DOMAIN_NAME, kCFStringEncodingUTF8))
2613 MarkSearchListElem(buf);
2614 else LogMsg("ERROR: GetDSSearchDomains - CFStringGetCString");
2615 }
2616 }
2617 }
2618
2619 mDNSlocal mStatus RegisterSearchDomains(mDNS *const m, CFDictionaryRef dict)
2620 {
2621 struct ifaddrs *ifa = NULL;
2622 SearchListElem *ptr, *prev, *freeSLPtr;
2623 ARListElem *arList;
2624 mStatus err;
2625
2626 if (DomainDiscoveryDisabled) return mStatus_NoError;
2627
2628 // step 1: mark each elem for removal (-1), unless we aren't passed a dictionary in which case we mark as preexistent
2629 for (ptr = SearchList; ptr; ptr = ptr->next) ptr->flag = dict ? -1 : 0;
2630
2631 // Get search domains from resolver library (available in OS X 10.4 and later), reverting to dynamic store on 10.3 systems
2632 if (GetSearchDomains() == mStatus_UnsupportedErr) GetDSSearchDomains(dict);
2633
2634 // Construct reverse-map search domains
2635 ifa = myGetIfAddrs(1);
2636 while (ifa)
2637 {
2638 mDNSAddr addr;
2639 if (ifa->ifa_addr->sa_family == AF_INET && !SetupAddr(&addr, ifa->ifa_addr) && !IsPrivateV4Addr(&addr) && !(ifa->ifa_flags & IFF_LOOPBACK) && ifa->ifa_netmask)
2640 {
2641 mDNSAddr netmask;
2642 char buffer[256];
2643 if (!SetupAddr(&netmask, ifa->ifa_netmask))
2644 {
2645 sprintf(buffer, "%d.%d.%d.%d.in-addr.arpa.", addr.ip.v4.b[3] & netmask.ip.v4.b[3],
2646 addr.ip.v4.b[2] & netmask.ip.v4.b[2],
2647 addr.ip.v4.b[1] & netmask.ip.v4.b[1],
2648 addr.ip.v4.b[0] & netmask.ip.v4.b[0]);
2649 MarkSearchListElem(buffer);
2650 }
2651 }
2652 ifa = ifa->ifa_next;
2653 }
2654
2655 // delete elems marked for removal, do queries for elems marked add
2656 prev = NULL;
2657 ptr = SearchList;
2658 while (ptr)
2659 {
2660 if (ptr->flag == -1) // remove
2661 {
2662 mDNS_StopQuery(m, &ptr->BrowseQ);
2663 mDNS_StopQuery(m, &ptr->RegisterQ);
2664 mDNS_StopQuery(m, &ptr->DefBrowseQ);
2665 mDNS_StopQuery(m, &ptr->DefRegisterQ);
2666 mDNS_StopQuery(m, &ptr->LegacyBrowseQ);
2667
2668 // deregister records generated from answers to the query
2669 arList = ptr->AuthRecs;
2670 ptr->AuthRecs = NULL;
2671 while (arList)
2672 {
2673 AuthRecord *dereg = &arList->ar;
2674 arList = arList->next;
2675 debugf("Deregistering PTR %s -> %s", dereg->resrec.name->c, dereg->resrec.rdata->u.name.c);
2676 err = mDNS_Deregister(m, dereg);
2677 if (err) LogMsg("ERROR: RegisterSearchDomains mDNS_Deregister returned %d", err);
2678 }
2679
2680 // remove elem from list, delete
2681 if (prev) prev->next = ptr->next;
2682 else SearchList = ptr->next;
2683 freeSLPtr = ptr;
2684 ptr = ptr->next;
2685 freeL("RegisterSearchDomains - freeSLPtr", freeSLPtr);
2686 continue;
2687 }
2688
2689 if (ptr->flag == 1) // add
2690 {
2691 mStatus err1, err2, err3, err4, err5;
2692 err1 = mDNS_GetDomains(m, &ptr->BrowseQ, mDNS_DomainTypeBrowse, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
2693 err2 = mDNS_GetDomains(m, &ptr->DefBrowseQ, mDNS_DomainTypeBrowseDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
2694 err3 = mDNS_GetDomains(m, &ptr->RegisterQ, mDNS_DomainTypeRegistration, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
2695 err4 = mDNS_GetDomains(m, &ptr->DefRegisterQ, mDNS_DomainTypeRegistrationDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
2696 err5 = mDNS_GetDomains(m, &ptr->LegacyBrowseQ, mDNS_DomainTypeBrowseLegacy, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
2697 if (err1 || err2 || err3 || err4 || err5)
2698 LogMsg("GetDomains for domain %##s returned error(s):\n"
2699 "%d (mDNS_DomainTypeBrowse)\n"
2700 "%d (mDNS_DomainTypeBrowseDefault)\n"
2701 "%d (mDNS_DomainTypeRegistration)\n"
2702 "%d (mDNS_DomainTypeRegistrationDefault)"
2703 "%d (mDNS_DomainTypeBrowseLegacy)\n",
2704 ptr->domain.c, err1, err2, err3, err4, err5);
2705 ptr->flag = 0;
2706 }
2707
2708 if (ptr->flag) { LogMsg("RegisterSearchDomains - unknown flag %d. Skipping.", ptr->flag); }
2709
2710 prev = ptr;
2711 ptr = ptr->next;
2712 }
2713
2714 return mStatus_NoError;
2715 }
2716
2717 //!!!KRS here is where we will give success/failure notification to the UI
2718 mDNSlocal void SCPrefsDynDNSCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
2719 {
2720 (void)m; // unused
2721 debugf("SCPrefsDynDNSCallback: result %d for registration of name %##s", result, rr->resrec.name->c);
2722 SetDDNSNameStatus(rr->resrec.name, result);
2723 }
2724
2725 mDNSlocal void SetSecretForDomain(mDNS *m, const domainname *domain)
2726 {
2727 OSStatus err = 0;
2728 SecKeychainRef SysKeychain = NULL;
2729 SecKeychainItemRef KeychainItem;
2730 char dstring[MAX_ESCAPED_DOMAIN_NAME];
2731 mDNSu32 secretlen;
2732 void *secret = NULL;
2733 domainname *d, canon;
2734 int i, dlen;
2735
2736 // canonicalize name by converting to lower case (keychain and some name servers are case sensitive)
2737 ConvertDomainNameToCString(domain, dstring);
2738 dlen = strlen(dstring);
2739 for (i = 0; i < dlen; i++) dstring[i] = tolower(dstring[i]); // canonicalize -> lower case
2740 MakeDomainNameFromDNSNameString(&canon, dstring);
2741 d = &canon;
2742
2743 err = SecKeychainOpen(SYS_KEYCHAIN_PATH, &SysKeychain);
2744 if (err) { LogMsg("SetSecretForDomain: couldn't open system keychain (error %d)", err); return; }
2745 // find longest-match key ("account") name, excluding last label (e.g. excluding ".com")
2746 while (d->c[0] && *(d->c + d->c[0] + 1))
2747 {
2748 if (!ConvertDomainNameToCString(d, dstring)) { LogMsg("SetSecretForDomain: bad domain %##s", d->c); return; }
2749 dlen = strlen(dstring);
2750 if (dstring[dlen-1] == '.') { dstring[dlen-1] = '\0'; dlen--; } // chop trailing dot
2751 err = SecKeychainFindGenericPassword(SysKeychain, strlen(DYNDNS_KEYCHAIN_SERVICE), DYNDNS_KEYCHAIN_SERVICE, dlen, dstring, &secretlen, &secret, &KeychainItem);
2752 if (!err)
2753 {
2754 debugf("Setting shared secret for zone %s with key %##s", dstring, d->c);
2755 mDNS_SetSecretForZone(m, d, d, secret, secretlen, mDNStrue);
2756 free(secret);
2757 return;
2758 }
2759 if (err == errSecItemNotFound) d = (domainname *)(d->c + d->c[0] + 1);
2760 else
2761 {
2762 if (err == errSecNoSuchKeychain) debugf("SetSecretForDomain: keychain not found");
2763 else LogMsg("SetSecretForDomain: SecKeychainFindGenericPassword returned error %d", err);
2764 return;
2765 }
2766 }
2767 }
2768
2769 mDNSlocal void SetSCPrefsBrowseDomainsFromCFArray(mDNS *m, CFArrayRef browseDomains, mDNSBool add)
2770 {
2771 if (browseDomains)
2772 {
2773 CFIndex count = CFArrayGetCount(browseDomains);
2774 CFDictionaryRef browseDict;
2775 char buf[MAX_ESCAPED_DOMAIN_NAME];
2776 int i;
2777
2778 for (i = 0; i < count; i++)
2779 {
2780 browseDict = (CFDictionaryRef)CFArrayGetValueAtIndex(browseDomains, i);
2781 if (browseDict && DDNSSettingEnabled(browseDict))
2782 {
2783 CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain"));
2784 if (name)
2785 {
2786 domainname BrowseDomain;
2787 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) || !MakeDomainNameFromDNSNameString(&BrowseDomain, buf) || !BrowseDomain.c[0])
2788 LogMsg("SetSCPrefsBrowseDomainsFromCFArray SCDynamicStore bad DDNS browse domain: %s", buf[0] ? buf : "(unknown)");
2789 else SetSCPrefsBrowseDomain(m, &BrowseDomain, add);
2790 }
2791 }
2792 }
2793 }
2794 }
2795
2796
2797 mDNSlocal void DynDNSConfigChanged(mDNS *const m)
2798 {
2799 static mDNSBool LegacyNATInitialized = mDNSfalse;
2800 uDNS_GlobalInfo *u = &m->uDNS_info;
2801 CFDictionaryRef dict;
2802 CFStringRef key;
2803 domainname RegDomain, fqdn;
2804 CFArrayRef NewBrowseDomains = NULL;
2805
2806 // get fqdn, zone from SCPrefs
2807 GetUserSpecifiedDDNSConfig(&fqdn, &RegDomain, &NewBrowseDomains);
2808 ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, fqdn.c[0] ? NULL : &fqdn, RegDomain.c[0] ? NULL : &RegDomain, &DomainDiscoveryDisabled);
2809
2810 if (!SameDomainName(&RegDomain, &DynDNSRegDomain))
2811 {
2812 if (DynDNSRegDomain.c[0])
2813 {
2814 RemoveDefRegDomain(&DynDNSRegDomain);
2815 SetSCPrefsBrowseDomain(m, &DynDNSRegDomain, mDNSfalse); // if we were automatically browsing in our registration domain, stop
2816 }
2817 AssignDomainName(&DynDNSRegDomain, &RegDomain);
2818 if (DynDNSRegDomain.c[0])
2819 {
2820 SetSecretForDomain(m, &DynDNSRegDomain);
2821 AddDefRegDomain(&DynDNSRegDomain);
2822 SetSCPrefsBrowseDomain(m, &DynDNSRegDomain, mDNStrue);
2823 }
2824 }
2825
2826 // Add new browse domains to internal list
2827 if (NewBrowseDomains) SetSCPrefsBrowseDomainsFromCFArray(m, NewBrowseDomains, mDNStrue);
2828
2829 // Remove old browse domains from internal list
2830 if (DynDNSBrowseDomains)
2831 {
2832 SetSCPrefsBrowseDomainsFromCFArray(m, DynDNSBrowseDomains, mDNSfalse);
2833 CFRelease(DynDNSBrowseDomains);
2834 }
2835
2836 // Replace the old browse domains array with the new array
2837 DynDNSBrowseDomains = NewBrowseDomains;
2838
2839 if (!SameDomainName(&fqdn, &DynDNSHostname))
2840 {
2841 if (DynDNSHostname.c[0]) mDNS_RemoveDynDNSHostName(m, &DynDNSHostname);
2842 AssignDomainName(&DynDNSHostname, &fqdn);
2843 if (DynDNSHostname.c[0])
2844 {
2845 SetSecretForDomain(m, &fqdn); // no-op if "zone" secret, above, is to be used for hostname
2846 mDNS_AddDynDNSHostName(m, &DynDNSHostname, SCPrefsDynDNSCallback, NULL);
2847 SetDDNSNameStatus(&DynDNSHostname, 1);
2848 }
2849 }
2850
2851 // get DNS settings
2852 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:DynDNSConfigChanged"), NULL, NULL);
2853 if (!store) return;
2854
2855 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
2856 if (!key) { LogMsg("ERROR: DNSConfigChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store); return; }
2857 dict = SCDynamicStoreCopyValue(store, key);
2858 CFRelease(key);
2859
2860 // handle any changes to search domains and DNS server addresses
2861 if (RegisterSplitDNS(m) != mStatus_NoError)
2862 if (dict) RegisterNameServers(m, dict); // fall back to non-split DNS aware configuration on failure
2863 RegisterSearchDomains(m, dict); // note that we register name servers *before* search domains
2864 if (dict) CFRelease(dict);
2865
2866 // get IPv4 settings
2867 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,kSCDynamicStoreDomainState, kSCEntNetIPv4);
2868 if (!key) { LogMsg("ERROR: RouterChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store); return; }
2869 dict = SCDynamicStoreCopyValue(store, key);
2870 CFRelease(key);
2871 CFRelease(store);
2872 if (!dict)
2873 { mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL); return; } // lost v4
2874
2875 // handle router changes
2876 mDNSAddr r;
2877 char buf[256];
2878 r.type = mDNSAddrType_IPv4;
2879 r.ip.v4.NotAnInteger = 0;
2880 CFStringRef router = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
2881 if (router)
2882 {
2883 struct sockaddr_in saddr;
2884
2885 if (!CFStringGetCString(router, buf, 256, kCFStringEncodingUTF8))
2886 LogMsg("Could not convert router to CString");
2887 else
2888 {
2889 saddr.sin_len = sizeof(saddr);
2890 saddr.sin_family = AF_INET;
2891 saddr.sin_port = 0;
2892 inet_aton(buf, &saddr.sin_addr);
2893 if (AddrRequiresPPPConnection((struct sockaddr *)&saddr)) { debugf("Ignoring router %s (requires PPP connection)", buf); }
2894 else *(in_addr_t *)&r.ip.v4 = saddr.sin_addr.s_addr;
2895 }
2896 }
2897
2898 // handle primary interface changes
2899 CFStringRef primary = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
2900 if (primary)
2901 {
2902 struct ifaddrs *ifa = myGetIfAddrs(1);
2903
2904 if (!CFStringGetCString(primary, buf, 256, kCFStringEncodingUTF8))
2905 { LogMsg("Could not convert router to CString"); goto error; }
2906
2907 // find primary interface in list
2908 while (ifa)
2909 {
2910 if (ifa->ifa_addr->sa_family == AF_INET && !strcmp(buf, ifa->ifa_name))
2911 {
2912 mDNSAddr ip;
2913 SetupAddr(&ip, ifa->ifa_addr);
2914 if (ip.ip.v4.b[0] == 169 && ip.ip.v4.b[1] == 254)
2915 { mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL); break; } // primary IP is link-local
2916 if (ip.ip.v4.NotAnInteger != u->PrimaryIP.ip.v4.NotAnInteger ||
2917 r.ip.v4.NotAnInteger != u->Router.ip.v4.NotAnInteger)
2918 {
2919 if (LegacyNATInitialized) { LegacyNATDestroy(); LegacyNATInitialized = mDNSfalse; }
2920 if (r.ip.v4.NotAnInteger && IsPrivateV4Addr(&ip))
2921 {
2922 mStatus err = LegacyNATInit();
2923 if (err) LogMsg("ERROR: LegacyNATInit");
2924 else LegacyNATInitialized = mDNStrue;
2925 }
2926 mDNS_SetPrimaryInterfaceInfo(m, &ip, r.ip.v4.NotAnInteger ? &r : NULL);
2927 break;
2928 }
2929 }
2930 ifa = ifa->ifa_next;
2931 }
2932 }
2933
2934 error:
2935 CFRelease(dict);
2936 }
2937
2938 mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
2939 {
2940 LogOperation("*** Network Configuration Change ***");
2941 mDNSs32 utc = mDNSPlatformUTC();
2942 MarkAllInterfacesInactive(m, utc);
2943 UpdateInterfaceList(m, utc);
2944 int nDeletions = ClearInactiveInterfaces(m, utc);
2945 int nAdditions = SetupActiveInterfaces(m, utc);
2946 DynDNSConfigChanged(m); // note - call DynDNSConfigChanged *before* mDNS_UpdateLLQs
2947 if (nDeletions || nAdditions) mDNS_UpdateLLQs(m); // so that LLQs are restarted against the up to date name servers
2948
2949 if (m->MainCallback)
2950 m->MainCallback(m, mStatus_ConfigChanged);
2951 }
2952
2953 mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
2954 {
2955 (void)store; // Parameter not used
2956 (void)changedKeys; // Parameter not used
2957 mDNS *const m = (mDNS *const)context;
2958 mDNS_Lock(m);
2959
2960 mDNSs32 delay = mDNSPlatformOneSecond * 2; // Start off assuming a two-second delay
2961
2962 int c = CFArrayGetCount(changedKeys); // Count changes
2963 CFRange range = { 0, c };
2964 CFStringRef k1 = SCDynamicStoreKeyCreateComputerName(NULL);
2965 CFStringRef k2 = SCDynamicStoreKeyCreateHostNames(NULL);
2966 if (k1 && k2)
2967 {
2968 int c1 = (CFArrayContainsValue(changedKeys, range, k1) != 0); // See if ComputerName changed
2969 int c2 = (CFArrayContainsValue(changedKeys, range, k2) != 0); // See if Local Hostname changed
2970 int c3 = (CFArrayContainsValue(changedKeys, range, CFSTR("Setup:/Network/DynamicDNS")) != 0);
2971 if (c && c - c1 - c2 - c3 == 0) delay = mDNSPlatformOneSecond/10; // If these were the only changes, shorten delay
2972 }
2973 if (k1) CFRelease(k1);
2974 if (k2) CFRelease(k2);
2975
2976 LogOperation("*** NetworkChanged *** %d change%s, delay %d", c, c>1?"s":"", delay);
2977
2978 if (!m->p->NetworkChanged ||
2979 m->p->NetworkChanged - NonZeroTime(m->timenow + delay) < 0)
2980 m->p->NetworkChanged = NonZeroTime(m->timenow + delay);
2981
2982 if (!m->SuppressSending ||
2983 m->SuppressSending - m->p->NetworkChanged < 0)
2984 m->SuppressSending = m->p->NetworkChanged;
2985 mDNS_Unlock(m);
2986 }
2987
2988 mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
2989 {
2990 mStatus err = -1;
2991 SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
2992 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged, &context);
2993 CFStringRef key1 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
2994 CFStringRef key2 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
2995 CFStringRef key3 = SCDynamicStoreKeyCreateComputerName(NULL);
2996 CFStringRef key4 = SCDynamicStoreKeyCreateHostNames(NULL);
2997 CFStringRef key5 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
2998 CFStringRef pattern1 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
2999 CFStringRef pattern2 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
3000
3001 CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
3002 CFMutableArrayRef patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
3003
3004 if (!store) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error; }
3005 if (!key1 || !key2 || !key3 || !key4 || !keys || !pattern1 || !pattern2 || !patterns) goto error;
3006
3007 CFArrayAppendValue(keys, key1);
3008 CFArrayAppendValue(keys, key2);
3009 CFArrayAppendValue(keys, key3);
3010 CFArrayAppendValue(keys, key4);
3011 CFArrayAppendValue(keys, key5);
3012 CFArrayAppendValue(keys, CFSTR("Setup:/Network/DynamicDNS"));
3013 CFArrayAppendValue(patterns, pattern1);
3014 CFArrayAppendValue(patterns, pattern2);
3015 CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
3016 if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns))
3017 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error; }
3018
3019 m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
3020 if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
3021
3022 CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
3023 m->p->Store = store;
3024 err = 0;
3025 goto exit;
3026
3027 error:
3028 if (store) CFRelease(store);
3029
3030 exit:
3031 if (key1) CFRelease(key1);
3032 if (key2) CFRelease(key2);
3033 if (key3) CFRelease(key3);
3034 if (key4) CFRelease(key4);
3035 if (key5) CFRelease(key5);
3036 if (pattern1) CFRelease(pattern1);
3037 if (pattern2) CFRelease(pattern2);
3038 if (keys) CFRelease(keys);
3039 if (patterns) CFRelease(patterns);
3040
3041 return(err);
3042 }
3043
3044 mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
3045 {
3046 mDNS *const m = (mDNS *const)refcon;
3047 (void)service; // Parameter not used
3048 switch(messageType)
3049 {
3050 case kIOMessageCanSystemPowerOff: debugf("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
3051 case kIOMessageSystemWillPowerOff: debugf("PowerChanged kIOMessageSystemWillPowerOff");
3052 mDNSCoreMachineSleep(m, true); mDNSMacOSXNetworkChanged(m); break; // E0000250
3053 case kIOMessageSystemWillNotPowerOff: debugf("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
3054 case kIOMessageCanSystemSleep: debugf("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
3055 case kIOMessageSystemWillSleep: debugf("PowerChanged kIOMessageSystemWillSleep");
3056 mDNSCoreMachineSleep(m, true); mDNSMacOSXNetworkChanged(m); break; // E0000280
3057 case kIOMessageSystemWillNotSleep: debugf("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
3058 case kIOMessageSystemHasPoweredOn: debugf("PowerChanged kIOMessageSystemHasPoweredOn");
3059 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
3060 if (m->SleepState) mDNSCoreMachineSleep(m, false);
3061 // Just to be safe, also make sure our interface list is fully up to date, in case we
3062 // haven't yet received the System Configuration Framework "network changed" event that
3063 // we expect to receive some time shortly after the kIOMessageSystemWillPowerOn message
3064 mDNSMacOSXNetworkChanged(m); break; // E0000300
3065 case kIOMessageSystemWillRestart: debugf("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
3066 case kIOMessageSystemWillPowerOn: debugf("PowerChanged kIOMessageSystemWillPowerOn");
3067 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
3068 mDNSMacOSXNetworkChanged(m); mDNSCoreMachineSleep(m, false); break; // E0000320
3069 default: debugf("PowerChanged unknown message %X", messageType); break;
3070 }
3071 IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
3072 }
3073
3074 mDNSlocal mStatus WatchForPowerChanges(mDNS *const m)
3075 {
3076 IONotificationPortRef thePortRef;
3077 m->p->PowerConnection = IORegisterForSystemPower(m, &thePortRef, PowerChanged, &m->p->PowerNotifier);
3078 if (m->p->PowerConnection)
3079 {
3080 m->p->PowerRLS = IONotificationPortGetRunLoopSource(thePortRef);
3081 CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->PowerRLS, kCFRunLoopDefaultMode);
3082 return(mStatus_NoError);
3083 }
3084 return(-1);
3085 }
3086
3087 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
3088 CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
3089 CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
3090 CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
3091
3092 mDNSexport int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
3093 {
3094 int major = 0, minor = 0;
3095 char letter = 0, prodname[256]="Mac OS X", prodvers[256]="", buildver[256]="?";
3096 CFDictionaryRef vers = _CFCopySystemVersionDictionary();
3097 if (vers)
3098 {
3099 CFStringRef cfprodname = CFDictionaryGetValue(vers, _kCFSystemVersionProductNameKey);
3100 CFStringRef cfprodvers = CFDictionaryGetValue(vers, _kCFSystemVersionProductVersionKey);
3101 CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
3102 if (cfprodname) CFStringGetCString(cfprodname, prodname, sizeof(prodname), kCFStringEncodingUTF8);
3103 if (cfprodvers) CFStringGetCString(cfprodvers, prodvers, sizeof(prodvers), kCFStringEncodingUTF8);
3104 if (cfbuildver) CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8);
3105 sscanf(buildver, "%d%c%d", &major, &letter, &minor);
3106 CFRelease(vers);
3107 }
3108 if (HINFO_SWstring) mDNS_snprintf(HINFO_SWstring, 256, "%s %s (%s), %s", prodname, prodvers, buildver, mDNSResponderVersionString);
3109 return(major);
3110 }
3111
3112 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
3113 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
3114 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
3115 mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
3116 {
3117 int err = -1;
3118 int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
3119 if (s < 3)
3120 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s, errno, strerror(errno));
3121 else
3122 {
3123 struct sockaddr_in s5353;
3124 s5353.sin_family = AF_INET;
3125 s5353.sin_port = MulticastDNSPort.NotAnInteger;
3126 s5353.sin_addr.s_addr = 0;
3127 err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
3128 close(s);
3129 }
3130
3131 if (err) LogMsg("No unicast UDP responses");
3132 else debugf("Unicast UDP responses okay");
3133 return(err == 0);
3134 }
3135
3136 // Callback for the _legacy._browse queries - add answer to list of domains to search for empty-string browses
3137 mDNSlocal void FoundLegacyBrowseDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
3138 {
3139 DNameListElem *ptr, *prev, *new;
3140 (void)m; // unused;
3141 (void)question; // unused
3142
3143 LogMsg("%s browse domain %##s", AddRecord ? "Adding" : "Removing", answer->rdata->u.name.c);
3144
3145 if (AddRecord)
3146 {
3147 new = mallocL("FoundLegacyBrowseDomain", sizeof(DNameListElem));
3148 if (!new) { LogMsg("ERROR: malloc"); return; }
3149 AssignDomainName(&new->name, &answer->rdata->u.name);
3150 new->next = DefBrowseList;
3151 DefBrowseList = new;
3152 DefaultBrowseDomainChanged(&new->name, mDNStrue);
3153 udsserver_default_browse_domain_changed(&new->name, mDNStrue);
3154 return;
3155 }
3156 else
3157 {
3158 ptr = DefBrowseList;
3159 prev = NULL;
3160 while (ptr)
3161 {
3162 if (SameDomainName(&ptr->name, &answer->rdata->u.name))
3163 {
3164 DefaultBrowseDomainChanged(&ptr->name, mDNSfalse);
3165 udsserver_default_browse_domain_changed(&ptr->name, mDNSfalse);
3166 if (prev) prev->next = ptr->next;
3167 else DefBrowseList = ptr->next;
3168 freeL("FoundLegacyBrowseDomain", ptr);
3169 return;
3170 }
3171 prev = ptr;
3172 ptr = ptr->next;
3173 }
3174 LogMsg("FoundLegacyBrowseDomain: Got remove event for domain %s not in list", answer->rdata->u.name.c);
3175 }
3176 }
3177
3178 mDNSlocal void RegisterBrowseDomainPTR(mDNS *m, const domainname *d, int type)
3179 {
3180 // allocate/register legacy and non-legacy _browse PTR record
3181 ARListElem *browse = mallocL("ARListElem", sizeof(*browse));
3182 mDNS_SetupResourceRecord(&browse->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, FreeARElemCallback, browse);
3183 MakeDomainNameFromDNSNameString(browse->ar.resrec.name, mDNS_DomainTypeNames[type]);
3184 AppendDNSNameString (browse->ar.resrec.name, "local");
3185 AssignDomainName(&browse->ar.resrec.rdata->u.name, d);
3186 mStatus err = mDNS_Register(m, &browse->ar);
3187 if (err)
3188 {
3189 LogMsg("SetSCPrefsBrowseDomain: mDNS_Register returned error %d", err);
3190 freeL("ARListElem", browse);
3191 }
3192 else
3193 {
3194 browse->next = SCPrefBrowseDomains;
3195 SCPrefBrowseDomains = browse;
3196 }
3197 }
3198
3199 mDNSlocal void DeregisterBrowseDomainPTR(mDNS *m, const domainname *d, int type)
3200 {
3201 ARListElem *remove, **ptr = &SCPrefBrowseDomains;
3202 domainname lhs; // left-hand side of PTR, for comparison
3203
3204 MakeDomainNameFromDNSNameString(&lhs, mDNS_DomainTypeNames[type]);
3205 AppendDNSNameString (&lhs, "local");
3206
3207 while (*ptr)
3208 {
3209 if (SameDomainName(&(*ptr)->ar.resrec.rdata->u.name, d) && SameDomainName((*ptr)->ar.resrec.name, &lhs))
3210 {
3211 remove = *ptr;
3212 *ptr = (*ptr)->next;
3213 mDNS_Deregister(m, &remove->ar);
3214 return;
3215 }
3216 else ptr = &(*ptr)->next;
3217 }
3218 }
3219
3220 // Add or remove a user-specified domain to the list of empty-string browse domains
3221 // Also register a non-legacy _browse PTR record so that the domain appears in enumeration lists
3222 mDNSlocal void SetSCPrefsBrowseDomain(mDNS *m, const domainname *d, mDNSBool add)
3223 {
3224 debugf("SetSCPrefsBrowseDomain: %s default browse domain %##s", add ? "Adding" : "Removing", d->c);
3225
3226 if (add)
3227 {
3228 RegisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowse);
3229 RegisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowseLegacy);
3230 }
3231 else
3232 {
3233 DeregisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowse);
3234 DeregisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowseLegacy);
3235 }
3236 }
3237
3238 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
3239 // 1) query for b._dns-sd._udp.local on LocalOnly interface
3240 // (.local manually generated via explicit callback)
3241 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
3242 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
3243 // 4) result above should generate a callback from question in (1). result added to global list
3244 // 5) global list delivered to client via GetSearchDomainList()
3245 // 6) client calls to enumerate domains now go over LocalOnly interface
3246 // (!!!KRS may add outgoing interface in addition)
3247
3248 mDNSlocal mStatus InitDNSConfig(mDNS *const m)
3249 {
3250 mStatus err;
3251 static AuthRecord LocalRegPTR;
3252
3253 // start query for domains to be used in default (empty string domain) browses
3254 err = mDNS_GetDomains(m, &LegacyBrowseDomainQ, mDNS_DomainTypeBrowseLegacy, NULL, mDNSInterface_LocalOnly, FoundLegacyBrowseDomain, NULL);
3255
3256 // provide browse domain "local" automatically
3257 SetSCPrefsBrowseDomain(m, &localdomain, mDNStrue);
3258
3259 // register registration domain "local"
3260 mDNS_SetupResourceRecord(&LocalRegPTR, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, NULL, NULL);
3261 MakeDomainNameFromDNSNameString(LocalRegPTR.resrec.name, mDNS_DomainTypeNames[mDNS_DomainTypeRegistration]);
3262 AppendDNSNameString (LocalRegPTR.resrec.name, "local");
3263 AssignDomainName(&LocalRegPTR.resrec.rdata->u.name, &localdomain);
3264 err = mDNS_Register(m, &LocalRegPTR);
3265 if (err) LogMsg("ERROR: InitDNSConfig - mDNS_Register returned error %d", err);
3266
3267 return mStatus_NoError;
3268 }
3269
3270 mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
3271 {
3272 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
3273 // If we can't read the user's preferences, then we sleep a bit and try again, for up to five seconds before we give up.
3274 int i;
3275 for (i=0; i<100; i++)
3276 {
3277 domainlabel testlabel;
3278 testlabel.c[0] = 0;
3279 GetUserSpecifiedLocalHostName(&testlabel);
3280 if (testlabel.c[0]) break;
3281 usleep(50000);
3282 }
3283
3284 mStatus err;
3285
3286 m->hostlabel.c[0] = 0;
3287
3288 char *HINFO_HWstring = "Macintosh";
3289 char HINFO_HWstring_buffer[256];
3290 int get_model[2] = { CTL_HW, HW_MODEL };
3291 size_t len_model = sizeof(HINFO_HWstring_buffer);
3292 if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0)
3293 HINFO_HWstring = HINFO_HWstring_buffer;
3294
3295 char HINFO_SWstring[256] = "";
3296 if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring) < 7) m->KnownBugs |= mDNS_KnownBug_PhantomInterfaces;
3297 if (mDNSPlatformInit_CanReceiveUnicast()) m->CanReceiveUnicastOn5353 = mDNStrue;
3298
3299 mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
3300 mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
3301 if (hlen + slen < 254)
3302 {
3303 m->HIHardware.c[0] = hlen;
3304 m->HISoftware.c[0] = slen;
3305 mDNSPlatformMemCopy(HINFO_HWstring, &m->HIHardware.c[1], hlen);
3306 mDNSPlatformMemCopy(HINFO_SWstring, &m->HISoftware.c[1], slen);
3307 }
3308
3309 m->p->unicastsockets.m = m;
3310 m->p->unicastsockets.info = NULL;
3311 m->p->unicastsockets.sktv4 = m->p->unicastsockets.sktv6 = -1;
3312 m->p->unicastsockets.cfsv4 = m->p->unicastsockets.cfsv6 = NULL;
3313 m->p->unicastsockets.rlsv4 = m->p->unicastsockets.rlsv6 = NULL;
3314
3315 err = SetupSocket(m, &m->p->unicastsockets, mDNSfalse, &zeroAddr, AF_INET);
3316 err = SetupSocket(m, &m->p->unicastsockets, mDNSfalse, &zeroAddr, AF_INET6);
3317
3318 struct sockaddr_in s4;
3319 struct sockaddr_in6 s6;
3320 int n4 = sizeof(s4);
3321 int n6 = sizeof(s6);
3322 if (getsockname(m->p->unicastsockets.sktv4, (struct sockaddr *)&s4, &n4) < 0) LogMsg("getsockname v4 error %d (%s)", errno, strerror(errno));
3323 else m->UnicastPort4.NotAnInteger = s4.sin_port;
3324 if (getsockname(m->p->unicastsockets.sktv6, (struct sockaddr *)&s6, &n6) < 0) LogMsg("getsockname v6 error %d (%s)", errno, strerror(errno));
3325 else m->UnicastPort6.NotAnInteger = s6.sin6_port;
3326
3327 m->p->InterfaceList = mDNSNULL;
3328 m->p->userhostlabel.c[0] = 0;
3329 m->p->usernicelabel.c[0] = 0;
3330 m->p->NotifyUser = 0;
3331 mDNSs32 utc = mDNSPlatformUTC();
3332 UpdateInterfaceList(m, utc);
3333 SetupActiveInterfaces(m, utc);
3334
3335 err = WatchForNetworkChanges(m);
3336 if (err) return(err);
3337
3338 err = WatchForPowerChanges(m);
3339 if (err) return err;
3340
3341 DynDNSRegDomain.c[0] = '\0';
3342 DynDNSConfigChanged(m); // Get initial DNS configuration
3343
3344 InitDNSConfig(m);
3345 return(err);
3346 }
3347
3348 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
3349 {
3350 mStatus result = mDNSPlatformInit_setup(m);
3351
3352 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
3353 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
3354 if (result == mStatus_NoError) mDNSCoreInitComplete(m, mStatus_NoError);
3355 return(result);
3356 }
3357
3358 mDNSexport void mDNSPlatformClose(mDNS *const m)
3359 {
3360 if (m->p->PowerConnection)
3361 {
3362 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->PowerRLS, kCFRunLoopDefaultMode);
3363 CFRunLoopSourceInvalidate(m->p->PowerRLS);
3364 CFRelease(m->p->PowerRLS);
3365 IODeregisterForSystemPower(&m->p->PowerNotifier);
3366 m->p->PowerConnection = 0;
3367 m->p->PowerNotifier = 0;
3368 m->p->PowerRLS = NULL;
3369 }
3370
3371 if (m->p->Store)
3372 {
3373 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
3374 CFRunLoopSourceInvalidate(m->p->StoreRLS);
3375 CFRelease(m->p->StoreRLS);
3376 CFRelease(m->p->Store);
3377 m->p->Store = NULL;
3378 m->p->StoreRLS = NULL;
3379 }
3380
3381 mDNSs32 utc = mDNSPlatformUTC();
3382 MarkAllInterfacesInactive(m, utc);
3383 ClearInactiveInterfaces(m, utc);
3384 CloseSocketSet(&m->p->unicastsockets);
3385 }
3386
3387 mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
3388 {
3389 return(mach_absolute_time());
3390 }
3391
3392 mDNSexport mDNSs32 mDNSPlatformOneSecond = 1000;
3393
3394 mDNSexport mStatus mDNSPlatformTimeInit(void)
3395 {
3396 // Notes: Typical values for mach_timebase_info:
3397 // tbi.numer = 1000 million
3398 // tbi.denom = 33 million
3399 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
3400 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
3401 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
3402 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
3403 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
3404 //
3405 // Arithmetic notes:
3406 // tbi.denom is at least 1, and not more than 2^32-1.
3407 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
3408 // tbi.denom is at least 1, and not more than 2^32-1.
3409 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
3410 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
3411 // which is unlikely on any current or future Macintosh.
3412 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
3413 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
3414 struct mach_timebase_info tbi;
3415 kern_return_t result = mach_timebase_info(&tbi);
3416 if (result == KERN_SUCCESS) clockdivisor = ((uint64_t)tbi.denom * 1000000) / tbi.numer;
3417 return(result);
3418 }
3419
3420 mDNSexport mDNSs32 mDNSPlatformRawTime(void)
3421 {
3422 if (clockdivisor == 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
3423
3424 static uint64_t last_mach_absolute_time = 0;
3425 uint64_t this_mach_absolute_time = mach_absolute_time();
3426 if ((int64_t)this_mach_absolute_time - (int64_t)last_mach_absolute_time < 0)
3427 {
3428 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time);
3429 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time);
3430 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
3431 last_mach_absolute_time = this_mach_absolute_time;
3432 // Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xxx) or later
3433 if (mDNSMacOSXSystemBuildNumber(NULL) >= 8)
3434 NotifyOfElusiveBug("mach_absolute_time went backwards!", 3438376, "");
3435 }
3436 last_mach_absolute_time = this_mach_absolute_time;
3437
3438 return((mDNSs32)(this_mach_absolute_time / clockdivisor));
3439 }
3440
3441 mDNSexport mDNSs32 mDNSPlatformUTC(void)
3442 {
3443 return time(NULL);
3444 }
3445
3446 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
3447 mDNSexport void mDNSPlatformLock (const mDNS *const m) { (void)m; }
3448 mDNSexport void mDNSPlatformUnlock (const mDNS *const m) { (void)m; }
3449 mDNSexport void mDNSPlatformStrCopy(const void *src, void *dst) { strcpy((char *)dst, (char *)src); }
3450 mDNSexport mDNSu32 mDNSPlatformStrLen (const void *src) { return(strlen((char*)src)); }
3451 mDNSexport void mDNSPlatformMemCopy(const void *src, void *dst, mDNSu32 len) { memcpy(dst, src, len); }
3452 mDNSexport mDNSBool mDNSPlatformMemSame(const void *src, const void *dst, mDNSu32 len) { return(memcmp(dst, src, len) == 0); }
3453 mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len) { bzero(dst, len); }
3454 mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
3455 mDNSexport void mDNSPlatformMemFree (void *mem) { freeL("mDNSPlatformMemFree", mem); }