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