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