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