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