]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/mDNSMacOSX.c
a1987412c20b3dfb54e7ac32b9b6a96e309a4566
[apple/mdnsresponder.git] / mDNSMacOSX / mDNSMacOSX.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16
17 Change History (most recent first):
18
19 $Log: mDNSMacOSX.c,v $
20 Revision 1.521 2007/12/14 00:58:28 cheshire
21 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
22 Additional fixes: When going to sleep, mDNSResponder needs to postpone sleep
23 until TLS/TCP deregistrations have completed (up to five seconds maximum)
24
25 Revision 1.520 2007/12/10 23:01:01 cheshire
26 Remove some unnecessary log messages
27
28 Revision 1.519 2007/12/06 00:22:27 mcguire
29 <rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
30
31 Revision 1.518 2007/12/05 01:52:30 cheshire
32 <rdar://problem/5624763> BTMM: getaddrinfo_async_start returns EAI_NONAME when resolving BTMM hostname
33 Delay returning IPv4 address ("A") results for autotunnel names until after we've set up the tunnel (or tried to)
34
35 Revision 1.517 2007/12/03 18:37:26 cheshire
36 Moved mDNSPlatformWriteLogMsg & mDNSPlatformWriteDebugMsg
37 from mDNSMacOSX.c to PlatformCommon.c, so that Posix build can use them
38
39 Revision 1.516 2007/12/01 01:21:27 jgraessley
40 <rdar://problem/5623140> mDNSResponder unicast DNS improvements
41
42 Revision 1.515 2007/12/01 00:40:00 cheshire
43 Add mDNSPlatformWriteLogMsg & mDNSPlatformWriteDebugMsg abstractions, to facilitate EFI conversion
44
45 Revision 1.514 2007/12/01 00:38:32 cheshire
46 Fixed compile warning: declaration of 'index' shadows a global declaration
47
48 Revision 1.513 2007/11/27 00:08:49 jgraessley
49 <rdar://problem/5613538> Interface-specific resolvers not setup correctly
50
51 Revision 1.512 2007/11/16 22:09:26 cheshire
52 Added missing type information in mDNSPlatformTCPCloseConnection debugging log message
53
54 Revision 1.511 2007/11/14 23:06:13 cheshire
55 <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
56
57 Revision 1.510 2007/11/14 22:29:19 cheshire
58 Updated comments and debugging log messages
59
60 Revision 1.509 2007/11/14 01:07:53 cheshire
61 Updated comments
62
63 Revision 1.508 2007/11/02 21:59:37 cheshire
64 Added comment about locking
65
66 Revision 1.507 2007/11/02 20:18:13 cheshire
67 <rdar://problem/5575583> BTMM: Work around keychain notification bug <rdar://problem/5124399>
68
69 Revision 1.506 2007/10/30 20:46:45 cheshire
70 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
71
72 Revision 1.505 2007/10/29 23:55:10 cheshire
73 <rdar://problem/5526791> BTMM: Changing Local Hostname doesn't update Back to My Mac registered records
74 Don't need to manually fake another AutoTunnelNATCallback if it has not yet received its first callback
75 (and indeed should not, since the result fields will not yet be set up correctly in this case)
76
77 Revision 1.504 2007/10/26 00:50:37 cheshire
78 <rdar://problem/5526791> BTMM: Changing Local Hostname doesn't update Back to My Mac registered records
79
80 Revision 1.503 2007/10/25 23:11:42 cheshire
81 Ignore IPv6 ULA addresses configured on lo0 loopback interface
82
83 Revision 1.502 2007/10/22 20:07:07 cheshire
84 Moved mDNSPlatformSourceAddrForDest from mDNSMacOSX.c to PlatformCommon.c so
85 Posix build can share the code (better than just pasting it into mDNSPosix.c)
86
87 Revision 1.501 2007/10/22 19:40:30 cheshire
88 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
89 Made subroutine mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAddr *const dst)
90
91 Revision 1.500 2007/10/17 22:49:55 cheshire
92 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
93
94 Revision 1.499 2007/10/17 19:47:54 cheshire
95 Improved debugging messages
96
97 Revision 1.498 2007/10/17 18:42:06 cheshire
98 Export SetDomainSecrets so its callable from other files
99
100 Revision 1.497 2007/10/16 17:03:07 cheshire
101 <rdar://problem/3557903> Performance: Core code will not work on platforms with small stacks
102 Cut SetDomainSecrets stack from 3792 to 1760 bytes
103
104 Revision 1.496 2007/10/04 20:33:05 mcguire
105 <rdar://problem/5518845> BTMM: Racoon configuration removed when network changes
106
107 Revision 1.495 2007/10/02 05:03:38 cheshire
108 Fix bogus indentation in mDNSPlatformDynDNSHostNameStatusChanged
109
110 Revision 1.494 2007/09/29 20:40:19 cheshire
111 <rdar://problem/5513378> Crash in ReissueBlockedQuestions
112
113 Revision 1.493 2007/09/29 03:16:45 cheshire
114 <rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
115 When AutoTunnel information changes, wait for record deregistrations to complete before registering new data
116
117 Revision 1.492 2007/09/28 23:58:35 mcguire
118 <rdar://problem/5505280> BTMM: v6 address and security policies being setup too soon
119 Fix locking issue.
120
121 Revision 1.491 2007/09/27 23:28:53 mcguire
122 <rdar://problem/5508042> BTMM: Anonymous racoon configuration not always cleaned up correctly
123
124 Revision 1.490 2007/09/26 23:01:21 mcguire
125 <rdar://problem/5505280> BTMM: v6 address and security policies being setup too soon
126
127 Revision 1.489 2007/09/26 22:58:16 mcguire
128 <rdar://problem/5505092> BTMM: Client tunnels being created to ::0 via 0.0.0.0
129
130 Revision 1.488 2007/09/26 00:32:45 cheshire
131 Rearrange struct TCPSocket_struct so "TCPSocketFlags flags" comes first (needed for debug logging)
132
133 Revision 1.487 2007/09/21 17:07:41 mcguire
134 <rdar://problem/5487354> BTMM: Need to modify IPSec tunnel setup files when shared secret changes (server-role)
135
136 Revision 1.486 2007/09/19 23:17:38 cheshire
137 <rdar://problem/5482131> BTMM: Crash when switching .Mac accounts
138
139 Revision 1.485 2007/09/19 21:44:29 cheshire
140 Improved "mDNSKeychainGetSecrets failed" error message
141
142 Revision 1.484 2007/09/18 21:44:55 cheshire
143 <rdar://problem/5469006> Crash in GetAuthInfoForName_internal
144 Code was using n->ExtPort (now n->RequestedPort) when it should have been using n->ExternalPort
145
146 Revision 1.483 2007/09/17 22:19:39 mcguire
147 <rdar://problem/5482519> BTMM: Tunnel is getting configured too much which causes long delays
148 No need to configure a tunnel again if all the parameters are the same -- just remove the older duplicate tunnel from the list.
149
150 Revision 1.482 2007/09/14 21:16:03 cheshire
151 <rdar://problem/5413170> mDNSResponder using 100% CPU spinning in tlsReadSock
152
153 Revision 1.481 2007/09/14 21:14:56 mcguire
154 <rdar://problem/5481318> BTMM: Need to modify IPSec tunnel setup files when shared secret changes
155
156 Revision 1.480 2007/09/13 00:16:42 cheshire
157 <rdar://problem/5468706> Miscellaneous NAT Traversal improvements
158
159 Revision 1.479 2007/09/12 19:22:20 cheshire
160 Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
161 Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
162
163 Revision 1.478 2007/09/07 22:21:45 vazquez
164 <rdar://problem/5460830> BTMM: Connection stops working after connecting VPN
165
166 Revision 1.477 2007/09/07 21:22:30 cheshire
167 <rdar://problem/5460210> BTMM: SetupSocket 5351 failed; Can't allocate UDP multicast socket spew on wake from sleep with internet sharing on
168 Don't log failures binding to port 5351
169
170 Revision 1.476 2007/09/06 20:38:08 cheshire
171 <rdar://problem/5439021> Only call SetDomainSecrets() for Keychain changes that are relevant to mDNSResponder
172
173 Revision 1.475 2007/09/05 02:24:28 cheshire
174 <rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
175 In ReissueBlockedQuestions, only restart questions marked NoAnswer_Suspended, not those marked NoAnswer_Fail
176
177 Revision 1.474 2007/09/04 22:32:58 mcguire
178 <rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
179
180 Revision 1.473 2007/08/31 19:53:15 cheshire
181 <rdar://problem/5431151> BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup
182 If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist
183
184 Revision 1.472 2007/08/31 18:49:49 vazquez
185 <rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM
186
187 Revision 1.471 2007/08/31 02:05:46 cheshire
188 Need to hold mDNS_Lock when calling mDNS_AddDynDNSHostName
189
190 Revision 1.470 2007/08/30 22:50:04 mcguire
191 <rdar://problem/5430628> BTMM: Tunneled services are registered when autotunnel can't be setup
192
193 Revision 1.469 2007/08/30 19:40:51 cheshire
194 Added syslog messages to report various initialization failures
195
196 Revision 1.468 2007/08/30 00:12:20 cheshire
197 Check error codes and log failures during AutoTunnel setup
198
199 Revision 1.467 2007/08/28 00:33:04 jgraessley
200 <rdar://problem/5423932> Selective compilation options
201
202 Revision 1.466 2007/08/24 23:25:55 cheshire
203 Debugging messages to help track down duplicate items being read from system keychain
204
205 Revision 1.465 2007/08/24 00:39:12 cheshire
206 Added comment explaining why we set info->AutoTunnelService.resrec.RecordType to kDNSRecordTypeUnregistered
207
208 Revision 1.464 2007/08/24 00:15:21 cheshire
209 Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
210
211 Revision 1.463 2007/08/23 21:02:35 cheshire
212 SecKeychainSetPreferenceDomain() call should be in platform-support layer, not daemon.c
213
214 Revision 1.462 2007/08/18 01:02:03 mcguire
215 <rdar://problem/5415593> No Bonjour services are getting registered at boot
216
217 Revision 1.461 2007/08/10 22:25:57 mkrochma
218 <rdar://problem/5396302> mDNSResponder continually complains about slow UDP packet reception -- about 400 msecs
219
220 Revision 1.460 2007/08/08 22:34:59 mcguire
221 <rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
222
223 Revision 1.459 2007/08/08 21:07:48 vazquez
224 <rdar://problem/5244687> BTMM: Need to advertise model information via wide-area bonjour
225
226 Revision 1.458 2007/08/03 02:18:41 mcguire
227 <rdar://problem/5381687> BTMM: Use port numbers in IPsec policies & configuration files
228
229 Revision 1.457 2007/08/02 16:48:45 mcguire
230 <rdar://problem/5329526> BTMM: Don't try to create tunnel back to same machine
231
232 Revision 1.456 2007/08/02 03:28:30 vazquez
233 Make ExternalAddress and err unused to fix build warnings
234
235 Revision 1.455 2007/08/01 03:09:22 cheshire
236 <rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port
237
238 Revision 1.454 2007/07/31 23:08:34 mcguire
239 <rdar://problem/5329542> BTMM: Make AutoTunnel mode work with multihoming
240
241 Revision 1.453 2007/07/31 19:13:58 mkrochma
242 No longer need to include "btmm" in hostname to avoid name conflicts
243
244 Revision 1.452 2007/07/27 19:30:41 cheshire
245 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
246 to properly reflect tri-state nature of the possible responses
247
248 Revision 1.451 2007/07/25 22:25:45 cheshire
249 <rdar://problem/5360853> BTMM: Code not cleaning up old racoon files
250
251 Revision 1.450 2007/07/25 21:19:10 cheshire
252 <rdar://problem/5359507> Fails to build with NO_SECURITYFRAMEWORK: 'IsTunnelModeDomain' defined but not used
253
254 Revision 1.449 2007/07/25 01:36:09 mcguire
255 <rdar://problem/5345290> BTMM: Replace popen() `setkey` calls to setup/teardown ipsec policies
256
257 Revision 1.448 2007/07/24 21:30:09 cheshire
258 Added "AutoTunnel server listening for connections..." diagnostic message
259
260 Revision 1.447 2007/07/24 20:24:18 cheshire
261 Only remove AutoTunnel address if we have created it.
262 Otherwise, we get "errno 49 (Can't assign requested address)" errors on exit.
263
264 Revision 1.446 2007/07/24 03:00:09 cheshire
265 SetDomainSecrets() should call SetupLocalAutoTunnelInterface_internal(), not SetupLocalAutoTunnelInterface()
266
267 Revision 1.445 2007/07/23 20:26:26 cheshire
268 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
269 Move code that reads "Setup:/Network/BackToMyMac" preferences outside the check
270 for existence of "Setup:/Network/DynamicDNS" settings
271
272 Revision 1.444 2007/07/21 00:54:49 cheshire
273 <rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured
274
275 Revision 1.443 2007/07/20 23:23:11 cheshire
276 Rename out-of-date name "atq" (was AutoTunnelQuery) to simpler "tun"
277
278 Revision 1.442 2007/07/20 20:23:24 cheshire
279 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
280 Fixed errors reading the Setup:/Network/BackToMyMac preferences
281
282 Revision 1.441 2007/07/20 16:46:45 mcguire
283 <rdar://problem/5345233> BTMM: Replace system() `route` calls to setup/teardown routes
284
285 Revision 1.440 2007/07/20 16:22:07 mcguire
286 <rdar://problem/5344584> BTMM: Replace system() `ifconfig` calls to setup/teardown IPv6 address
287
288 Revision 1.439 2007/07/20 01:14:56 cheshire
289 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
290 Cleaned up log messages
291
292 Revision 1.438 2007/07/20 00:54:21 cheshire
293 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
294
295 Revision 1.437 2007/07/19 22:01:27 cheshire
296 Added "#pragma mark" sections headings to divide code into related function groups
297
298 Revision 1.436 2007/07/18 03:25:25 cheshire
299 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
300 Bring up server-side tunnel on demand, when necessary
301
302 Revision 1.435 2007/07/18 01:05:08 cheshire
303 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
304 Add list of client tunnels so we can automatically reconfigure when local address changes
305
306 Revision 1.434 2007/07/16 20:16:00 vazquez
307 <rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
308 Remove unnecessary LNT init code
309
310 Revision 1.433 2007/07/14 00:36:07 cheshire
311 Remove temporary IPv4LL tunneling mode now that IPv6-over-IPv4 is working
312
313 Revision 1.432 2007/07/12 23:55:11 cheshire
314 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
315 Don't need two separate DNSQuestion structures when looking up tunnel endpoint
316
317 Revision 1.431 2007/07/12 23:34:48 cheshire
318 Removed 'LogOperation' message to reduce verbosity in syslog
319
320 Revision 1.430 2007/07/12 22:16:46 cheshire
321 Improved "could not convert shared secret from base64" log message so it doesn't reveal key data in syslog
322
323 Revision 1.429 2007/07/12 02:51:28 cheshire
324 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
325
326 Revision 1.428 2007/07/11 23:17:31 cheshire
327 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
328 Improve log message to indicate if we're starting or restarting racoon
329
330 Revision 1.427 2007/07/11 22:50:30 cheshire
331 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
332 Write /etc/racoon/remote/anonymous.conf configuration file and start up /usr/sbin/racoon
333
334 Revision 1.426 2007/07/11 20:40:49 cheshire
335 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
336 In mDNSPlatformGetPrimaryInterface(), prefer routable IPv4 address to IPv4LL
337
338 Revision 1.425 2007/07/11 19:24:19 cheshire
339 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services
340 Configure internal AutoTunnel address
341 (For temporary testing we're faking up an IPv4LL address instead of IPv6 ULA, and we're
342 assigning it with "system(commandstring);" which probably isn't the most efficient way to do it)
343
344 Revision 1.424 2007/07/11 19:00:27 cheshire
345 Only need to set up m->AutoTunnelHostAddr first time through UpdateInterfaceList()
346
347 Revision 1.423 2007/07/11 03:00:59 cheshire
348 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
349 Add AutoTunnel parameter to mDNS_SetSecretForDomain; Generate IPv6 ULA address for tunnel endpoint
350
351 Revision 1.422 2007/07/10 01:21:20 cheshire
352 Added (commented out) line for displaying key data for debugging
353
354 Revision 1.421 2007/06/25 20:58:11 cheshire
355 <rdar://problem/5234463> Write the Multicast DNS domains to the DynamicStore
356 Additional refinement: Add mDNS domain list new new DynamicStore entity "State:/Network/MulticastDNS"
357
358 Revision 1.420 2007/06/22 21:52:14 cheshire
359 <rdar://problem/5234463> Write the Multicast DNS domains to the DynamicStore
360
361 Revision 1.419 2007/06/22 21:32:00 cheshire
362 <rdar://problem/5239020> Use SecKeychainCopyDefault instead of SecKeychainOpen
363
364 Revision 1.418 2007/06/21 16:37:43 jgraessley
365 Bug #: 5280520
366 Reviewed by: Stuart Cheshire
367 Additional changes to get this compiling on the embedded platform.
368
369 Revision 1.417 2007/06/20 01:44:00 cheshire
370 More information in "Network Configuration Change" message
371
372 Revision 1.416 2007/06/20 01:10:12 cheshire
373 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
374
375 Revision 1.415 2007/06/15 19:23:38 cheshire
376 <rdar://problem/5254053> mDNSResponder renames my host without asking
377 Improve log messages, to distinguish user-initiated renames from automatic (name conflict) renames
378
379 Revision 1.414 2007/05/17 22:00:59 cheshire
380 <rdar://problem/5210966> Lower network change delay from two seconds to one second
381
382 Revision 1.413 2007/05/16 16:43:27 cheshire
383 Only log "bind" failures for our shared mDNS port and for binding to zero
384 -- other attempts to bind to a particular port may legitimately fail
385
386 Revision 1.412 2007/05/15 21:49:21 cheshire
387 Get rid of "#pragma unused"
388
389 Revision 1.411 2007/05/14 23:54:55 cheshire
390 Instead of sprintf, use safer length-limited mDNS_snprintf
391
392 Revision 1.410 2007/05/12 01:05:00 cheshire
393 Updated debugging messages
394
395 Revision 1.409 2007/05/10 22:39:48 cheshire
396 <rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
397 Only define CountMaskBits for builds with debugging messages
398
399 Revision 1.408 2007/05/10 22:19:00 cheshire
400 <rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
401 Don't deliver multicast packets for which we can't find an associated InterfaceID
402
403 Revision 1.407 2007/05/10 21:40:28 cheshire
404 Don't log unnecessary "Address already in use" errors when joining multicast groups
405
406 Revision 1.406 2007/05/08 00:56:17 cheshire
407 <rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
408
409 Revision 1.405 2007/05/04 20:21:39 cheshire
410 Improve "connect failed" error message
411
412 Revision 1.404 2007/05/02 19:41:53 cheshire
413 No need to alarm people with "Connection reset by peer" syslog message
414
415 Revision 1.403 2007/04/28 01:31:59 cheshire
416 Improve debugging support for catching memory corruption problems
417
418 Revision 1.402 2007/04/26 22:54:57 cheshire
419 Debugging messages to help track down <rdar://problem/5164206> mDNSResponder takes 50%+ CPU
420
421 Revision 1.401 2007/04/26 00:35:16 cheshire
422 <rdar://problem/5140339> uDNS: Domain discovery not working over VPN
423 Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
424 inside the firewall may give answers where a public one gives none, and vice versa.)
425
426 Revision 1.400 2007/04/24 21:50:27 cheshire
427 Debugging: Show list of changedKeys in NetworkChanged callback
428
429 Revision 1.399 2007/04/23 22:28:47 cheshire
430 Allan Nathanson informs us we should only be looking at the search list for resolver[0], not all of them
431
432 Revision 1.398 2007/04/23 04:57:00 cheshire
433 Log messages for debugging <rdar://problem/4570952> IPv6 multicast not working properly
434
435 Revision 1.397 2007/04/22 06:02:03 cheshire
436 <rdar://problem/4615977> Query should immediately return failure when no server
437
438 Revision 1.396 2007/04/21 21:47:47 cheshire
439 <rdar://problem/4376383> Daemon: Add watchdog timer
440
441 Revision 1.395 2007/04/18 20:58:34 cheshire
442 <rdar://problem/5140339> Domain discovery not working over VPN
443 Needed different code to handle the case where there's only a single search domain
444
445 Revision 1.394 2007/04/17 23:05:50 cheshire
446 <rdar://problem/3957358> Shouldn't send domain queries when we have 169.254 or loopback address
447
448 Revision 1.393 2007/04/17 19:21:29 cheshire
449 <rdar://problem/5140339> Domain discovery not working over VPN
450
451 Revision 1.392 2007/04/17 17:15:09 cheshire
452 Change NO_CFUSERNOTIFICATION code so it still logs to syslog
453
454 Revision 1.391 2007/04/07 01:01:48 cheshire
455 <rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
456
457 Revision 1.390 2007/04/06 18:45:02 cheshire
458 Fix SetupActiveInterfaces() -- accidentally changed SetupSocket parameter
459
460 Revision 1.389 2007/04/05 21:39:49 cheshire
461 Debugging messages to help diagnose <rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
462
463 Revision 1.388 2007/04/05 21:09:52 cheshire
464 Condense sprawling code
465
466 Revision 1.387 2007/04/05 20:40:37 cheshire
467 Remove unused mDNSPlatformTCPGetFlags()
468
469 Revision 1.386 2007/04/05 19:50:56 cheshire
470 Fixed memory leak: GetCertChain() was not releasing cert returned by SecIdentityCopyCertificate()
471
472 Revision 1.385 2007/04/03 19:39:19 cheshire
473 Fixed intel byte order bug in mDNSPlatformSetDNSServers()
474
475 Revision 1.384 2007/03/31 01:10:53 cheshire
476 Add debugging
477
478 Revision 1.383 2007/03/31 00:13:48 cheshire
479 Remove LogMsg
480
481 Revision 1.382 2007/03/28 21:01:29 cheshire
482 <rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
483
484 Revision 1.381 2007/03/28 15:56:37 cheshire
485 <rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
486
487 Revision 1.380 2007/03/26 22:54:46 cheshire
488 Fix compile error
489
490 Revision 1.379 2007/03/22 18:31:48 cheshire
491 Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
492
493 Revision 1.378 2007/03/22 00:49:20 cheshire
494 <rdar://problem/4848295> Advertise model information via Bonjour
495
496 Revision 1.377 2007/03/21 00:30:05 cheshire
497 <rdar://problem/4789455> Multiple errors in DNameList-related code
498
499 Revision 1.376 2007/03/20 17:07:15 cheshire
500 Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
501
502 Revision 1.375 2007/03/20 00:50:57 cheshire
503 <rdar://problem/4530644> Remove logic to disable IPv6 discovery on interfaces which have a routable IPv4 address
504
505 Revision 1.374 2007/03/06 23:29:50 cheshire
506 <rdar://problem/4331696> Need to call IONotificationPortDestroy on shutdown
507
508 Revision 1.373 2007/02/28 01:51:20 cheshire
509 Added comment about reverse-order IP address
510
511 Revision 1.372 2007/02/28 01:06:48 cheshire
512 Use %#a format code instead of %d.%d.%d.%d
513
514 Revision 1.371 2007/02/08 21:12:28 cheshire
515 <rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
516
517 Revision 1.370 2007/01/16 22:59:58 cheshire
518 Error code ioErr is from wrong conceptual namespace; use errSSLClosedAbort instead
519
520 Revision 1.369 2007/01/10 02:09:32 cheshire
521 Better LogOperation record of keys read from System Keychain
522
523 Revision 1.368 2007/01/10 01:25:31 cheshire
524 Use symbol kDNSServiceCompPrivateDNS instead of fixed string "State:/Network/PrivateDNS"
525
526 Revision 1.367 2007/01/10 01:22:01 cheshire
527 Make sure c1, c2, c3 are initialized
528
529 Revision 1.366 2007/01/09 22:37:20 cheshire
530 Provide ten-second grace period for deleted keys, to give mDNSResponder
531 time to delete host name before it gives up access to the required key.
532
533 Revision 1.365 2007/01/09 21:09:20 cheshire
534 Need locking in KeychainChanged()
535
536 Revision 1.364 2007/01/09 20:17:04 cheshire
537 mDNSPlatformGetDNSConfig() needs to initialize fields even when no "Setup:/Network/DynamicDNS" entity exists
538
539 Revision 1.363 2007/01/09 02:41:18 cheshire
540 uDNS_SetupDNSConfig() shouldn't be called from mDNSMacOSX.c (platform support layer);
541 moved it to mDNS_Init() in mDNS.c (core code)
542
543 Revision 1.362 2007/01/08 23:54:01 cheshire
544 Made mDNSPlatformGetDNSConfig() more selective -- only reads prefs for non-null parameters
545
546 Revision 1.361 2007/01/05 08:30:48 cheshire
547 Trim excessive "$Log" checkin history from before 2006
548 (checkin history still available via "cvs log ..." of course)
549
550 Revision 1.360 2007/01/04 00:12:24 cheshire
551 <rdar://problem/4742742> Read *all* DNS keys from keychain,
552 not just key for the system-wide default registration domain
553
554 Revision 1.359 2006/12/22 21:14:37 cheshire
555 Added comment explaining why we allow both "ddns" and "sndd" as valid item types
556 The Keychain APIs on Intel appear to store the four-character item type backwards (at least some of the time)
557
558 Revision 1.358 2006/12/22 20:59:50 cheshire
559 <rdar://problem/4742742> Read *all* DNS keys from keychain,
560 not just key for the system-wide default registration domain
561
562 Revision 1.357 2006/12/21 00:09:45 cheshire
563 Use mDNSPlatformMemZero instead of bzero
564
565 Revision 1.356 2006/12/20 23:15:53 mkrochma
566 Fix the private domain list code so that it actually works
567
568 Revision 1.355 2006/12/20 23:04:36 mkrochma
569 Fix crash when adding private domain list to Dynamic Store
570
571 Revision 1.354 2006/12/19 22:43:55 cheshire
572 Fix compiler warnings
573
574 Revision 1.353 2006/12/14 22:08:29 cheshire
575 Fixed memory leak: need to call SecKeychainItemFreeAttributesAndData()
576 to release data allocated by SecKeychainItemCopyAttributesAndData()
577
578 Revision 1.352 2006/12/14 02:33:26 cheshire
579 <rdar://problem/4841422> uDNS: Wide-area registrations sometimes fail
580
581 Revision 1.351 2006/11/28 21:37:51 mkrochma
582 Tweak where the private DNS data is written
583
584 Revision 1.350 2006/11/28 07:55:02 herscher
585 <rdar://problem/4742743> dnsextd has a slow memory leak
586
587 Revision 1.349 2006/11/28 07:45:58 herscher
588 <rdar://problem/4787010> Daemon: Need to write list of private domain names to the DynamicStore
589
590 Revision 1.348 2006/11/16 21:47:20 mkrochma
591 <rdar://problem/4841422> uDNS: Wide-area registrations sometimes fail
592
593 Revision 1.347 2006/11/10 00:54:16 cheshire
594 <rdar://problem/4816598> Changing case of Computer Name doesn't work
595
596 Revision 1.346 2006/10/31 02:34:58 cheshire
597 <rdar://problem/4692130> Stop creating HINFO records
598
599 Revision 1.345 2006/09/21 20:04:38 mkrochma
600 Accidently changed function name while checking in previous fix
601
602 Revision 1.344 2006/09/21 19:04:13 mkrochma
603 <rdar://problem/4733803> uDNS: Update keychain format of DNS key to include prefix
604
605 Revision 1.343 2006/09/15 21:20:16 cheshire
606 Remove uDNS_info substructure from mDNS_struct
607
608 Revision 1.342 2006/08/16 00:31:50 mkrochma
609 <rdar://problem/4386944> Get rid of NotAnInteger references
610
611 Revision 1.341 2006/08/14 23:24:40 cheshire
612 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
613
614 Revision 1.340 2006/07/29 19:11:13 mkrochma
615 Change GetUserSpecifiedDDNSConfig LogMsg to debugf
616
617 Revision 1.339 2006/07/27 03:24:35 cheshire
618 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
619 Further refinement: Declare KQueueEntry parameter "const"
620
621 Revision 1.338 2006/07/27 02:59:25 cheshire
622 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
623 Further refinements: CFRunLoop thread needs to explicitly wake the kqueue thread
624 after releasing BigMutex, in case actions it took have resulted in new work for the
625 kqueue thread (e.g. NetworkChanged events may result in the kqueue thread having to
626 add new active interfaces to its list, and consequently schedule queries to be sent).
627
628 Revision 1.337 2006/07/22 06:11:37 cheshire
629 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
630
631 Revision 1.336 2006/07/15 02:01:32 cheshire
632 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
633 Fix broken "empty string" browsing
634
635 Revision 1.335 2006/07/14 05:25:11 cheshire
636 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
637 Fixed crash in mDNSPlatformGetDNSConfig() reading BrowseDomains array
638
639 Revision 1.334 2006/07/05 23:42:00 cheshire
640 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
641
642 Revision 1.333 2006/06/29 05:33:30 cheshire
643 <rdar://problem/4607043> mDNSResponder conditional compilation options
644
645 Revision 1.332 2006/06/28 09:10:36 cheshire
646 Extra debugging messages
647
648 Revision 1.331 2006/06/21 22:29:42 cheshire
649 Make _CFCopySystemVersionDictionary() call more defensive on systems that have no build information set
650
651 Revision 1.330 2006/06/20 23:06:00 cheshire
652 Fix some keychain API type mismatches (was mDNSu32 instead of UInt32)
653
654 Revision 1.329 2006/06/08 23:22:33 cheshire
655 Comment changes
656
657 Revision 1.328 2006/03/19 03:27:49 cheshire
658 <rdar://problem/4118624> Suppress "interface flapping" logic for loopback
659
660 Revision 1.327 2006/03/19 02:00:09 cheshire
661 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
662
663 Revision 1.326 2006/03/08 22:42:23 cheshire
664 Fix spelling mistake: LocalReverseMapomain -> LocalReverseMapDomain
665
666 Revision 1.325 2006/01/10 00:39:17 cheshire
667 Add comments explaining how IPv6 link-local addresses sometimes have an embedded scope_id
668
669 Revision 1.324 2006/01/09 19:28:59 cheshire
670 <rdar://problem/4403128> Cap number of "sendto failed" messages we allow mDNSResponder to log
671
672 Revision 1.323 2006/01/05 21:45:27 cheshire
673 <rdar://problem/4400118> Fix uninitialized structure member in IPv6 code
674
675 Revision 1.322 2006/01/05 21:41:50 cheshire
676 <rdar://problem/4108164> Reword "mach_absolute_time went backwards" dialog
677
678 Revision 1.321 2006/01/05 21:35:06 cheshire
679 Add (commented out) trigger value for testing "mach_absolute_time went backwards" notice
680
681 */
682
683 // ***************************************************************************
684 // mDNSMacOSX.c:
685 // Supporting routines to run mDNS on a CFRunLoop platform
686 // ***************************************************************************
687
688 // For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
689 // including ones that mDNSResponder chooses not to use.
690 #define LIST_ALL_INTERFACES 0
691
692 // For enabling AAAA records over IPv4. Setting this to 0 sends only
693 // A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both
694 // AAAA and A records over both IPv4 and IPv6.
695 #define AAAA_OVER_V4 1
696
697 // In Mac OS X 10.4 and earlier, to reduce traffic, we would send and receive using IPv6 only on interfaces that had no routable
698 // IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
699 // which means there's a good chance that most or all the other devices on that network should also have IPv4.
700 // By doing this we lost the ability to talk to true IPv6-only devices on that link, but we cut the packet rate in half.
701 // At that time, reducing the packet rate was more important than v6-only devices on a large configured network,
702 // so were willing to make that sacrifice.
703 // In Mac OS X 10.5, in 2007, two things have changed:
704 // 1. IPv6-only devices are starting to become more common, so we can't ignore them.
705 // 2. Other efficiency improvements in the code mean that crude hacks like this should no longer be necessary.
706
707 #define USE_V6_ONLY_WHEN_NO_ROUTABLE_V4 0
708
709 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
710 #include "DNSCommon.h"
711 #include "uDNS.h"
712 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
713 #include "../mDNSShared/uds_daemon.h" // Defines communication interface from platform layer up to UDS daemon
714 #include "PlatformCommon.h"
715
716 #include <stdio.h>
717 #include <stdarg.h> // For va_list support
718 #include <net/if.h>
719 #include <net/if_types.h> // For IFT_ETHER
720 #include <net/if_dl.h>
721 #include <sys/uio.h>
722 #include <sys/param.h>
723 #include <sys/socket.h>
724 #include <sys/sysctl.h>
725 #include <sys/event.h>
726 #include <fcntl.h>
727 #include <sys/ioctl.h>
728 #include <time.h> // platform support for UTC time
729 #include <arpa/inet.h> // for inet_aton
730 #include <pthread.h>
731
732 #include <netinet/in.h> // For IP_RECVTTL
733 #ifndef IP_RECVTTL
734 #define IP_RECVTTL 24 // bool; receive reception TTL w/dgram
735 #endif
736
737 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
738 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
739 #include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
740 #include <netinet6/nd6.h> // For ND6_INFINITE_LIFETIME etc.
741
742 #if TARGET_OS_EMBEDDED
743 #define NO_SECURITYFRAMEWORK 1
744 #define NO_CFUSERNOTIFICATION 1
745 #endif
746
747 #ifndef NO_SECURITYFRAMEWORK
748 #include <Security/SecureTransport.h>
749 #include <Security/Security.h>
750 #endif /* NO_SECURITYFRAMEWORK */
751
752 #include <DebugServices.h>
753 #include "dnsinfo.h"
754
755 // Code contributed by Dave Heller:
756 // Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
757 // work on Mac OS X 10.1, which does not have the getifaddrs call.
758 #define RUN_ON_PUMA_WITHOUT_IFADDRS 0
759 #if RUN_ON_PUMA_WITHOUT_IFADDRS
760 #include "mDNSMacOSXPuma.c"
761 #else
762 #include <ifaddrs.h>
763 #endif
764
765 #include <IOKit/IOKitLib.h>
766 #include <IOKit/IOMessage.h>
767 #include <mach/mach_error.h>
768 #include <mach/mach_port.h>
769 #include <mach/mach_time.h>
770 #include "helper.h"
771
772 #define kInterfaceSpecificOption "interface="
773
774 // ***************************************************************************
775 // Globals
776
777 #if COMPILER_LIKES_PRAGMA_MARK
778 #pragma mark - Globals
779 #endif
780
781 static mDNSu32 clockdivisor = 0;
782
783 mDNSexport int KQueueFD;
784
785 #ifndef NO_SECURITYFRAMEWORK
786 static CFArrayRef ServerCerts;
787 #endif /* NO_SECURITYFRAMEWORK */
788
789 #define DYNDNS_KEYCHAIN_SERVICE "DynDNS Shared Secret"
790
791 CFStringRef NetworkChangedKey_IPv4;
792 CFStringRef NetworkChangedKey_IPv6;
793 CFStringRef NetworkChangedKey_Hostnames;
794 CFStringRef NetworkChangedKey_Computername;
795 CFStringRef NetworkChangedKey_DNS;
796 CFStringRef NetworkChangedKey_DynamicDNS = CFSTR("Setup:/Network/DynamicDNS");
797 CFStringRef NetworkChangedKey_BackToMyMac = CFSTR("Setup:/Network/BackToMyMac");
798
799 // ***************************************************************************
800 // Functions
801
802 #if COMPILER_LIKES_PRAGMA_MARK
803 #pragma mark -
804 #pragma mark - Utility Functions
805 #endif
806
807 // We only attempt to send and receive multicast packets on interfaces that are
808 // (a) flagged as multicast-capable
809 // (b) *not* flagged as point-to-point (e.g. modem)
810 // Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
811 // to run up the user's bill sending multicast traffic over a link where there's only a single device at the
812 // other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
813 #define MulticastInterface(i) ((i->ifa_flags & IFF_MULTICAST) && !(i->ifa_flags & IFF_POINTOPOINT))
814
815 mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both strings are UTF-8 text
816 {
817 static int notifyCount = 0;
818 if (notifyCount) return;
819
820 // If we display our alert early in the boot process, then it vanishes once the desktop appears.
821 // To avoid this, we don't try to display alerts in the first three minutes after boot.
822 if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return;
823
824 // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
825 #if !ForceAlerts
826 {
827 // Determine if we're at Apple (17.*.*.*)
828 extern mDNS mDNSStorage;
829 NetworkInterfaceInfoOSX *i;
830 for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
831 if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && i->ifinfo.ip.ip.v4.b[0] == 17)
832 break;
833 if (!i) return; // If not at Apple, don't show the alert
834 }
835 #endif
836
837 LogMsg("%s", title);
838 LogMsg("%s", msg);
839 // Display a notification to the user
840 notifyCount++;
841
842 #ifndef NO_CFUSERNOTIFICATION
843 static const char footer[] = "(Note: This message only appears on machines with 17.x.x.x IP addresses — i.e. at Apple — not on customer machines.)";
844 CFStringRef alertHeader = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8);
845 CFStringRef alertBody = CFStringCreateWithCString(NULL, msg, kCFStringEncodingUTF8);
846 CFStringRef alertFooter = CFStringCreateWithCString(NULL, footer, kCFStringEncodingUTF8);
847 CFStringRef alertMessage = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@\r\r%@"), alertBody, alertFooter);
848 CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL, alertHeader, alertMessage, NULL);
849 #endif /* NO_CFUSERNOTIFICATION */
850 }
851
852 mDNSlocal struct ifaddrs *myGetIfAddrs(int refresh)
853 {
854 static struct ifaddrs *ifa = NULL;
855
856 if (refresh && ifa)
857 {
858 freeifaddrs(ifa);
859 ifa = NULL;
860 }
861
862 if (ifa == NULL) getifaddrs(&ifa);
863
864 return ifa;
865 }
866
867 // To match *either* a v4 or v6 instance of this interface name, pass AF_UNSPEC for type
868 mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, const char *ifname, int type)
869 {
870 NetworkInterfaceInfoOSX *i;
871 for (i = m->p->InterfaceList; i; i = i->next)
872 if (i->Exists && !strcmp(i->ifa_name, ifname) &&
873 ((type == AF_UNSPEC ) ||
874 (type == AF_INET && i->ifinfo.ip.type == mDNSAddrType_IPv4) ||
875 (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6))) return(i);
876 return(NULL);
877 }
878
879 mDNSlocal int myIfIndexToName(u_short ifindex, char *name)
880 {
881 struct ifaddrs *ifa;
882 for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
883 if (ifa->ifa_addr->sa_family == AF_LINK)
884 if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == ifindex)
885 { strlcpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; }
886 return -1;
887 }
888
889 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex)
890 {
891 NetworkInterfaceInfoOSX *i;
892 if (ifindex == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
893 if (ifindex == kDNSServiceInterfaceIndexAny ) return(mDNSNULL);
894
895 // Don't get tricked by inactive interfaces with no InterfaceID set
896 for (i = m->p->InterfaceList; i; i = i->next)
897 if (i->ifinfo.InterfaceID && i->scope_id == ifindex) return(i->ifinfo.InterfaceID);
898
899 // Not found. Make sure our interface list is up to date, then try again.
900 LogOperation("InterfaceID for interface index %d not found; Updating interface list", ifindex);
901 mDNSMacOSXNetworkChanged(m);
902 for (i = m->p->InterfaceList; i; i = i->next)
903 if (i->ifinfo.InterfaceID && i->scope_id == ifindex) return(i->ifinfo.InterfaceID);
904
905 return(mDNSNULL);
906 }
907
908 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id)
909 {
910 NetworkInterfaceInfoOSX *i;
911 if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
912 if (id == mDNSInterface_Any ) return(0);
913
914 // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces, which have no InterfaceID set
915 for (i = m->p->InterfaceList; i; i = i->next)
916 if ((mDNSInterfaceID)i == id) return(i->scope_id);
917
918 // Not found. Make sure our interface list is up to date, then try again.
919 LogOperation("Interface index for InterfaceID %p not found; Updating interface list", id);
920 mDNSMacOSXNetworkChanged(m);
921 for (i = m->p->InterfaceList; i; i = i->next)
922 if ((mDNSInterfaceID)i == id) return(i->scope_id);
923
924 return(0);
925 }
926
927 #if COMPILER_LIKES_PRAGMA_MARK
928 #pragma mark -
929 #pragma mark - UDP & TCP send & receive
930 #endif
931
932 mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr)
933 {
934 mDNSBool result = mDNSfalse;
935 SCNetworkConnectionFlags flags;
936 SCNetworkReachabilityRef ReachRef = NULL;
937
938 ReachRef = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, addr);
939 if (!ReachRef) { LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithAddress"); goto end; }
940 if (!SCNetworkReachabilityGetFlags(ReachRef, &flags)) { LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags"); goto end; }
941 result = flags & kSCNetworkFlagsConnectionRequired;
942
943 end:
944 if (ReachRef) CFRelease(ReachRef);
945 return result;
946 }
947
948 struct UDPSocket_struct
949 {
950 mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCore expects every UDPSocket_struct to begin with mDNSIPPort port
951 KQSocketSet ss;
952 };
953
954 // NOTE: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
955 // NOTE: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
956 // OR send via our primary v4 unicast socket
957 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
958 mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstPort)
959 {
960 // Note: For this platform we've adopted the convention that InterfaceIDs are secretly pointers
961 // to the NetworkInterfaceInfoOSX structure that holds the active sockets. The mDNSCore code
962 // doesn't know that and doesn't need to know that -- it just treats InterfaceIDs as opaque identifiers.
963 NetworkInterfaceInfoOSX *info = (NetworkInterfaceInfoOSX *)InterfaceID;
964 char *ifa_name = info ? info->ifa_name : "unicast";
965 struct sockaddr_storage to;
966 int s = -1, err;
967 mStatus result = mStatus_NoError;
968
969 // Sanity check: Make sure that if we're sending a query via unicast, we're sending it using our
970 // anonymous socket created for this purpose, so that we'll receive the response.
971 // If we use one of the many multicast sockets bound to port 5353 then we may not receive responses reliably.
972 if (InterfaceID && !mDNSAddrIsDNSMulticast(dst))
973 if ((((DNSMessage *)msg)->h.flags.b[0] & kDNSFlag0_QR_Mask) == kDNSFlag0_QR_Query)
974 LogMsg("mDNSPlatformSendUDP: ERROR: Sending query OP from mDNS port to non-mDNS destination %#a:%d", dst, mDNSVal16(dstPort));
975
976 if (dst->type == mDNSAddrType_IPv4)
977 {
978 struct sockaddr_in *sin_to = (struct sockaddr_in*)&to;
979 sin_to->sin_len = sizeof(*sin_to);
980 sin_to->sin_family = AF_INET;
981 sin_to->sin_port = dstPort.NotAnInteger;
982 sin_to->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
983 s = m->p->permanentsockets.sktv4;
984
985 #ifdef _LEGACY_NAT_TRAVERSAL_
986 if (m->SSDPSocket && mDNSSameIPPort(dstPort, SSDPPort))
987 s = m->SSDPSocket->ss.sktv4;
988 #endif _LEGACY_NAT_TRAVERSAL_
989
990 if (info) // Specify outgoing interface
991 {
992 if (!mDNSAddrIsDNSMulticast(dst))
993 {
994 #ifdef IP_FORCE_OUT_IFP
995 setsockopt(s, IPPROTO_IP, IP_FORCE_OUT_IFP, ifa_name, strlen(ifa_name) + 1);
996 #else
997 {
998 static int displayed = 0;
999 if (!displayed)
1000 {
1001 displayed = 1;
1002 LogOperation("IP_FORCE_OUT_IFP Socket option not defined -- cannot specify interface for unicast packets");
1003 }
1004 }
1005 #endif
1006 }
1007 else
1008 {
1009 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
1010 if (err < 0) LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %ld errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
1011 }
1012 }
1013 }
1014 else if (dst->type == mDNSAddrType_IPv6)
1015 {
1016 struct sockaddr_in6 *sin6_to = (struct sockaddr_in6*)&to;
1017 sin6_to->sin6_len = sizeof(*sin6_to);
1018 sin6_to->sin6_family = AF_INET6;
1019 sin6_to->sin6_port = dstPort.NotAnInteger;
1020 sin6_to->sin6_flowinfo = 0;
1021 sin6_to->sin6_addr = *(struct in6_addr*)&dst->ip.v6;
1022 sin6_to->sin6_scope_id = info ? info->scope_id : 0;
1023 s = m->p->permanentsockets.sktv6;
1024 if (info && mDNSAddrIsDNSMulticast(dst)) // Specify outgoing interface
1025 {
1026 err = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &info->scope_id, sizeof(info->scope_id));
1027 if (err < 0) LogMsg("setsockopt - IPV6_MULTICAST_IF error %ld errno %d (%s)", err, errno, strerror(errno));
1028 }
1029 }
1030 else
1031 {
1032 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
1033 #if ForceAlerts
1034 *(long*)0 = 0;
1035 #endif
1036 return mStatus_BadParamErr;
1037 }
1038
1039 // Don't send if it would cause dial-on-demand connection initiation.
1040 // As an optimization, don't bother consulting reachability API / routing
1041 // table when sending Multicast DNS since we ignore PPP interfaces for mDNS traffic.
1042 if (!info && !mDNSAddrIsDNSMulticast(dst) && AddrRequiresPPPConnection((struct sockaddr *)&to))
1043 {
1044 debugf("mDNSPlatformSendUDP: Surpressing sending to avoid dial-on-demand connection");
1045 return mStatus_NoError;
1046 }
1047
1048 if (s >= 0)
1049 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
1050 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s);
1051 else
1052 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
1053 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort));
1054
1055 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
1056 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
1057 if (s < 0) return(mStatus_Invalid);
1058
1059 err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len);
1060 if (err < 0)
1061 {
1062 static int MessageCount = 0;
1063 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
1064 if (!mDNSAddressIsAllDNSLinkGroup(dst))
1065 if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr);
1066 // Don't report EHOSTUNREACH in the first three minutes after boot
1067 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
1068 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
1069 if (errno == EHOSTUNREACH && (mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(mStatus_TransientErr);
1070 // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
1071 if (errno == EADDRNOTAVAIL && m->p->NetworkChanged) return(mStatus_TransientErr);
1072 if (MessageCount < 1000)
1073 {
1074 MessageCount++;
1075 LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %5s/%ld to %#a:%d skt %d error %d errno %d (%s) %lu",
1076 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
1077 }
1078 result = mStatus_UnknownErr;
1079 }
1080
1081 #ifdef IP_FORCE_OUT_IFP
1082 if (dst->type == mDNSAddrType_IPv4 && info && !mDNSAddrIsDNSMulticast(dst))
1083 setsockopt(s, IPPROTO_IP, IP_FORCE_OUT_IFP, "", 1);
1084 #endif
1085
1086 return(result);
1087 }
1088
1089 mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
1090 struct sockaddr *const from, size_t *const fromlen, mDNSAddr *dstaddr, char ifname[IF_NAMESIZE], mDNSu8 *ttl)
1091 {
1092 static unsigned int numLogMessages = 0;
1093 struct iovec databuffers = { (char *)buffer, max };
1094 struct msghdr msg;
1095 ssize_t n;
1096 struct cmsghdr *cmPtr;
1097 char ancillary[1024];
1098
1099 *ttl = 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
1100
1101 // Set up the message
1102 msg.msg_name = (caddr_t)from;
1103 msg.msg_namelen = *fromlen;
1104 msg.msg_iov = &databuffers;
1105 msg.msg_iovlen = 1;
1106 msg.msg_control = (caddr_t)&ancillary;
1107 msg.msg_controllen = sizeof(ancillary);
1108 msg.msg_flags = 0;
1109
1110 // Receive the data
1111 n = recvmsg(s, &msg, 0);
1112 if (n<0)
1113 {
1114 if (errno != EWOULDBLOCK && numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s, n, errno);
1115 return(-1);
1116 }
1117 if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
1118 {
1119 if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
1120 s, n, msg.msg_controllen, sizeof(struct cmsghdr));
1121 return(-1);
1122 }
1123 if (msg.msg_flags & MSG_CTRUNC)
1124 {
1125 if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
1126 return(-1);
1127 }
1128
1129 *fromlen = msg.msg_namelen;
1130
1131 // Parse each option out of the ancillary data.
1132 for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
1133 {
1134 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
1135 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVDSTADDR)
1136 {
1137 dstaddr->type = mDNSAddrType_IPv4;
1138 dstaddr->ip.v4 = *(mDNSv4Addr*)CMSG_DATA(cmPtr);
1139 //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
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(ifname, sdl->sdl_data, 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 *ttl = *(u_char*)CMSG_DATA(cmPtr);
1153 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_PKTINFO)
1154 {
1155 struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmPtr);
1156 dstaddr->type = mDNSAddrType_IPv6;
1157 dstaddr->ip.v6 = *(mDNSv6Addr*)&ip6_info->ipi6_addr;
1158 myIfIndexToName(ip6_info->ipi6_ifindex, ifname);
1159 }
1160 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT)
1161 *ttl = *(int*)CMSG_DATA(cmPtr);
1162 }
1163
1164 return(n);
1165 }
1166
1167 mDNSlocal void myKQSocketCallBack(int s1, short filter, void *context)
1168 {
1169 const KQSocketSet *const ss = (const KQSocketSet *)context;
1170 mDNS *const m = ss->m;
1171 int err, count = 0;
1172
1173 if (filter != EVFILT_READ)
1174 LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter, EVFILT_READ);
1175
1176 if (s1 != ss->sktv4 && s1 != ss->sktv6)
1177 {
1178 LogMsg("myKQSocketCallBack: native socket %d", s1);
1179 LogMsg("myKQSocketCallBack: sktv4 %d", ss->sktv4);
1180 LogMsg("myKQSocketCallBack: sktv6 %d", ss->sktv6);
1181 }
1182
1183 while (1)
1184 {
1185 mDNSAddr senderAddr, destAddr;
1186 mDNSIPPort senderPort, destPort = (m->SSDPSocket && ss == &m->SSDPSocket->ss ? m->SSDPSocket->port : MulticastDNSPort);
1187 struct sockaddr_storage from;
1188 size_t fromlen = sizeof(from);
1189 char packetifname[IF_NAMESIZE] = "";
1190 mDNSu8 ttl;
1191 err = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl);
1192 if (err < 0) break;
1193
1194 count++;
1195 if (from.ss_family == AF_INET)
1196 {
1197 struct sockaddr_in *s = (struct sockaddr_in*)&from;
1198 senderAddr.type = mDNSAddrType_IPv4;
1199 senderAddr.ip.v4.NotAnInteger = s->sin_addr.s_addr;
1200 senderPort.NotAnInteger = s->sin_port;
1201 //LogOperation("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1202 }
1203 else if (from.ss_family == AF_INET6)
1204 {
1205 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&from;
1206 senderAddr.type = mDNSAddrType_IPv6;
1207 senderAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
1208 senderPort.NotAnInteger = sin6->sin6_port;
1209 //LogOperation("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1210 }
1211 else
1212 {
1213 LogMsg("myKQSocketCallBack from is unknown address family %d", from.ss_family);
1214 return;
1215 }
1216
1217 // NOTE: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
1218 mDNSInterfaceID InterfaceID = mDNSNULL;
1219 NetworkInterfaceInfo *intf = m->HostInterfaces;
1220 while (intf && strcmp(intf->ifname, packetifname)) intf = intf->next;
1221 // When going to sleep we deregister all our interfaces, but if the machine
1222 // takes a few seconds to sleep we may continue to receive multicasts
1223 // during that time, which would confuse mDNSCoreReceive, because as far
1224 // as it's concerned, we should have no active interfaces any more.
1225 // Hence we ignore multicasts for which we can find no matching InterfaceID.
1226 if (intf) InterfaceID = intf->InterfaceID;
1227 else if (mDNSAddrIsDNSMulticast(&destAddr)) continue;
1228
1229 // LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
1230 // &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifa_name);
1231
1232 mDNSCoreReceive(m, &m->imsg, (unsigned char*)&m->imsg + err, &senderAddr, senderPort, &destAddr, destPort, InterfaceID);
1233 }
1234
1235 if (err < 0 && (errno != EWOULDBLOCK || count == 0))
1236 {
1237 // Something is busted here.
1238 // kqueue says there is a packet, but myrecvfrom says there is not.
1239 // Try calling select() to get another opinion.
1240 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
1241 // All of this is racy, as data may have arrived after the call to select()
1242 static unsigned int numLogMessages = 0;
1243 int save_errno = errno;
1244 int so_error = -1;
1245 int so_nread = -1;
1246 int fionread = -1;
1247 socklen_t solen = sizeof(int);
1248 fd_set readfds;
1249 struct timeval timeout;
1250 int selectresult;
1251 FD_ZERO(&readfds);
1252 FD_SET(s1, &readfds);
1253 timeout.tv_sec = 0;
1254 timeout.tv_usec = 0;
1255 selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
1256 if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1)
1257 LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno);
1258 if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1)
1259 LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno);
1260 if (ioctl(s1, FIONREAD, &fionread) == -1)
1261 LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno);
1262 if (numLogMessages++ < 100)
1263 LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
1264 s1, err, save_errno, strerror(save_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
1265 if (numLogMessages > 5)
1266 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
1267 "Congratulations, you've reproduced an elusive bug.\r"
1268 "Please contact the current assignee of <rdar://problem/3375328>.\r"
1269 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
1270 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1271
1272 sleep(1); // After logging this error, rate limit so we don't flood syslog
1273 }
1274 }
1275
1276 // TCP socket support
1277
1278 struct TCPSocket_struct
1279 {
1280 TCPSocketFlags flags; // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
1281 TCPConnectionCallback callback;
1282 int fd;
1283 KQueueEntry kqEntry;
1284 #ifndef NO_SECURITYFRAMEWORK
1285 SSLContextRef tlsContext;
1286 #endif /* NO_SECURITYFRAMEWORK */
1287 void *context;
1288 mDNSBool setup;
1289 mDNSBool handshakecomplete;
1290 mDNSBool connected;
1291 };
1292
1293 #ifndef NO_SECURITYFRAMEWORK
1294
1295 mDNSlocal OSStatus tlsWriteSock(SSLConnectionRef connection, const void *data, size_t *dataLength)
1296 {
1297 int ret = send(((TCPSocket *)connection)->fd, data, *dataLength, 0);
1298 if (ret >= 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
1299 if (ret >= 0) { *dataLength = ret; return(noErr); }
1300 *dataLength = 0;
1301 if (errno == EAGAIN ) return(errSSLWouldBlock);
1302 if (errno == ENOENT ) return(errSSLClosedGraceful);
1303 if (errno == EPIPE || errno == ECONNRESET) return(errSSLClosedAbort);
1304 LogMsg("ERROR: tlsWriteSock: error %d %s\n", errno, strerror(errno));
1305 return(errSSLClosedAbort);
1306 }
1307
1308 mDNSlocal OSStatus tlsReadSock(SSLConnectionRef connection, void *data, size_t *dataLength)
1309 {
1310 int ret = recv(((TCPSocket *)connection)->fd, data, *dataLength, 0);
1311 if (ret > 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
1312 if (ret > 0) { *dataLength = ret; return(noErr); }
1313 *dataLength = 0;
1314 if (ret == 0 || errno == ENOENT ) return(errSSLClosedGraceful);
1315 if ( errno == EAGAIN ) return(errSSLWouldBlock);
1316 if ( errno == ECONNRESET) return(errSSLClosedAbort);
1317 LogMsg("ERROR: tlsSockRead: error %d %s\n", errno, strerror(errno));
1318 return(errSSLClosedAbort);
1319 }
1320
1321 mDNSlocal OSStatus tlsSetupSock(TCPSocket *sock, mDNSBool server)
1322 {
1323 mStatus err = SSLNewContext(server, &sock->tlsContext);
1324 if (err) { LogMsg("ERROR: tlsSetupSock: SSLNewContext failed with error code: %d", err); return(err); }
1325
1326 err = SSLSetIOFuncs(sock->tlsContext, tlsReadSock, tlsWriteSock);
1327 if (err) { LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err); return(err); }
1328
1329 err = SSLSetConnection(sock->tlsContext, (SSLConnectionRef) sock);
1330 if (err) { LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err); return(err); }
1331
1332 return(err);
1333 }
1334
1335 mDNSlocal mDNSBool IsTunnelModeDomain(const domainname *d)
1336 {
1337 static const domainname *mmc = (const domainname*) "\x7" "members" "\x3" "mac" "\x3" "com";
1338 const domainname *d1 = mDNSNULL; // TLD
1339 const domainname *d2 = mDNSNULL; // SLD
1340 const domainname *d3 = mDNSNULL;
1341 while (d->c[0]) { d3 = d2; d2 = d1; d1 = d; d = (const domainname*)(d->c + 1 + d->c[0]); }
1342 return(d3 && SameDomainName(d3, mmc));
1343 }
1344
1345 #endif /* NO_SECURITYFRAMEWORK */
1346
1347 mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context)
1348 {
1349 TCPSocket *sock = context;
1350 mStatus err = mStatus_NoError;
1351
1352 //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
1353 //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
1354 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
1355 if (filter == EVFILT_WRITE) KQueueSet(sock->fd, EV_DELETE, EVFILT_WRITE, &sock->kqEntry);
1356
1357 if (sock->flags & kTCPSocketFlags_UseTLS)
1358 {
1359 #ifndef NO_SECURITYFRAMEWORK
1360 if (!sock->setup) { sock->setup = mDNStrue; tlsSetupSock(sock, mDNSfalse); }
1361 if (!sock->handshakecomplete)
1362 {
1363 //LogMsg("tcpKQSocketCallback Starting SSLHandshake");
1364 err = SSLHandshake(sock->tlsContext);
1365 //if (!err) LogMsg("tcpKQSocketCallback SSLHandshake complete");
1366 if (!err) sock->handshakecomplete = mDNStrue;
1367 else if (err == errSSLWouldBlock) return;
1368 else { LogMsg("KQ SSLHandshake failed: %d", err); SSLDisposeContext(sock->tlsContext); sock->tlsContext = NULL; }
1369 }
1370 #else
1371 err = mStatus_UnsupportedErr;
1372 #endif /* NO_SECURITYFRAMEWORK */
1373 }
1374
1375 mDNSBool c = !sock->connected;
1376 sock->connected = mDNStrue;
1377 sock->callback(sock, sock->context, c, err);
1378 // NOTE: the callback may call CloseConnection here, which frees the context structure!
1379 }
1380
1381 mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef)
1382 {
1383 struct kevent new_event;
1384 EV_SET(&new_event, fd, filter, flags, 0, 0, (void*)entryRef);
1385 return (kevent(KQueueFD, &new_event, 1, NULL, 0, NULL) < 0) ? errno : 0;
1386 }
1387
1388 mDNSexport void KQueueLock(mDNS *const m)
1389 {
1390 pthread_mutex_lock(&m->p->BigMutex);
1391 m->p->BigMutexStartTime = mDNSPlatformRawTime();
1392 }
1393
1394 mDNSexport void KQueueUnlock(mDNS *const m, const char const *task)
1395 {
1396 mDNSs32 end = mDNSPlatformRawTime();
1397 (void)task;
1398 if (end - m->p->BigMutexStartTime >= WatchDogReportingThreshold)
1399 LogOperation("WARNING: %s took %dms to complete", task, end - m->p->BigMutexStartTime);
1400
1401 pthread_mutex_unlock(&m->p->BigMutex);
1402
1403 char wake = 1;
1404 if (send(m->p->WakeKQueueLoopFD, &wake, sizeof(wake), 0) == -1)
1405 LogMsg("ERROR: KQueueWake: send failed with error code: %d - %s", errno, strerror(errno));
1406 }
1407
1408 mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port)
1409 {
1410 (void) m;
1411
1412 TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket));
1413 if (!sock) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL); }
1414
1415 mDNSPlatformMemZero(sock, sizeof(TCPSocket));
1416 sock->callback = mDNSNULL;
1417 sock->fd = socket(AF_INET, SOCK_STREAM, 0);
1418 sock->kqEntry.KQcallback= tcpKQSocketCallback;
1419 sock->kqEntry.KQcontext = sock;
1420 sock->kqEntry.KQtask = "mDNSPlatformTCPSocket";
1421 sock->flags = flags;
1422 sock->context = mDNSNULL;
1423 sock->setup = mDNSfalse;
1424 sock->handshakecomplete = mDNSfalse;
1425 sock->connected = mDNSfalse;
1426
1427 if (sock->fd == -1)
1428 {
1429 LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock->fd, errno, strerror(errno));
1430 freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
1431 return(mDNSNULL);
1432 }
1433
1434 // Bind it
1435 struct sockaddr_in addr;
1436 memset(&addr, 0, sizeof(addr));
1437 addr.sin_family = AF_INET;
1438 addr.sin_addr.s_addr = htonl(INADDR_ANY);
1439 addr.sin_port = port->NotAnInteger;
1440 if (bind(sock->fd, (struct sockaddr*) &addr, sizeof(addr)) < 0)
1441 { LogMsg("ERROR: bind %s", strerror(errno)); goto error; }
1442
1443 // Receive interface identifiers
1444 const int on = 1; // "on" for setsockopt
1445 if (setsockopt(sock->fd, IPPROTO_IP, IP_RECVIF, &on, sizeof(on)) < 0)
1446 { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); goto error; }
1447
1448 memset(&addr, 0, sizeof(addr));
1449 socklen_t len = sizeof(addr);
1450 if (getsockname(sock->fd, (struct sockaddr*) &addr, &len) < 0)
1451 { LogMsg("getsockname - %s", strerror(errno)); goto error; }
1452
1453 port->NotAnInteger = addr.sin_port;
1454 return sock;
1455
1456 error:
1457 close(sock->fd);
1458 freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
1459 return(mDNSNULL);
1460 }
1461
1462 mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
1463 TCPConnectionCallback callback, void *context)
1464 {
1465 struct sockaddr_in saddr;
1466 mStatus err = mStatus_NoError;
1467
1468 sock->callback = callback;
1469 sock->context = context;
1470 sock->setup = mDNSfalse;
1471 sock->handshakecomplete = mDNSfalse;
1472 sock->connected = mDNSfalse;
1473
1474 (void) InterfaceID; //!!!KRS use this if non-zero!!!
1475
1476 if (dst->type != mDNSAddrType_IPv4)
1477 {
1478 LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: opperation not supported");
1479 return mStatus_UnknownErr;
1480 }
1481
1482 mDNSPlatformMemZero(&saddr, sizeof(saddr));
1483 saddr.sin_family = AF_INET;
1484 saddr.sin_port = dstport.NotAnInteger;
1485 saddr.sin_len = sizeof(saddr);
1486 saddr.sin_addr.s_addr = dst->ip.v4.NotAnInteger;
1487
1488 // Don't send if it would cause dial-on-demand connection initiation.
1489 if (AddrRequiresPPPConnection((struct sockaddr *)&saddr))
1490 {
1491 debugf("mDNSPlatformTCPConnect: Surpressing sending to avoid dial-on-demand connection");
1492 return mStatus_UnknownErr;
1493 }
1494
1495 sock->kqEntry.KQcallback = tcpKQSocketCallback;
1496 sock->kqEntry.KQcontext = sock;
1497 sock->kqEntry.KQtask = "Outgoing TCP";
1498
1499 // Watch for connect complete (write is ready)
1500 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
1501 if (KQueueSet(sock->fd, EV_ADD /* | EV_ONESHOT */, EVFILT_WRITE, &sock->kqEntry))
1502 {
1503 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1504 close(sock->fd);
1505 return errno;
1506 }
1507
1508 // Watch for incoming data
1509 if (KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry))
1510 {
1511 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1512 close(sock->fd); // Closing the descriptor removes all filters from the kqueue
1513 return errno;
1514 }
1515
1516 if (fcntl(sock->fd, F_SETFL, fcntl(sock->fd, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
1517 {
1518 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno));
1519 return mStatus_UnknownErr;
1520 }
1521
1522 // initiate connection wth peer
1523 if (connect(sock->fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
1524 {
1525 if (errno == EINPROGRESS) return mStatus_ConnPending;
1526 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d %s", sock->fd, errno, strerror(errno));
1527 close(sock->fd);
1528 return mStatus_ConnFailed;
1529 }
1530
1531 LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
1532 // kQueue should notify us, but this LogMsg is to help track down if it doesn't
1533 return err;
1534 }
1535
1536 // Why doesn't mDNSPlatformTCPAccept actually call accept() ?
1537 mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
1538 {
1539 mStatus err = mStatus_NoError;
1540
1541 TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket));
1542 if (!sock) return(mDNSNULL);
1543
1544 memset(sock, 0, sizeof(*sock));
1545 sock->fd = fd;
1546 sock->flags = flags;
1547
1548 if (flags & kTCPSocketFlags_UseTLS)
1549 {
1550 #ifndef NO_SECURITYFRAMEWORK
1551 if (!ServerCerts) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err = mStatus_UnknownErr; goto exit; }
1552
1553 err = tlsSetupSock(sock, mDNStrue);
1554 if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err); goto exit; }
1555
1556 err = SSLSetCertificate(sock->tlsContext, ServerCerts);
1557 if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err); goto exit; }
1558 #else
1559 err = mStatus_UnsupportedErr;
1560 #endif /* NO_SECURITYFRAMEWORK */
1561 }
1562 #ifndef NO_SECURITYFRAMEWORK
1563 exit:
1564 #endif
1565
1566 if (err) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock); return(mDNSNULL); }
1567 return(sock);
1568 }
1569
1570 mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
1571 {
1572 if (sock)
1573 {
1574 #ifndef NO_SECURITYFRAMEWORK
1575 if (sock->tlsContext)
1576 {
1577 SSLClose(sock->tlsContext);
1578 SSLDisposeContext(sock->tlsContext);
1579 sock->tlsContext = NULL;
1580 }
1581 #endif /* NO_SECURITYFRAMEWORK */
1582 if (sock->fd != -1)
1583 {
1584 shutdown(sock->fd, 2);
1585 close(sock->fd);
1586 sock->fd = -1;
1587 }
1588
1589 freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock);
1590 }
1591 }
1592
1593 mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed)
1594 {
1595 long nread = 0;
1596 *closed = mDNSfalse;
1597
1598 if (sock->flags & kTCPSocketFlags_UseTLS)
1599 {
1600 #ifndef NO_SECURITYFRAMEWORK
1601 if (!sock->handshakecomplete)
1602 {
1603 //LogMsg("mDNSPlatformReadTCP Starting SSLHandshake");
1604 mStatus err = SSLHandshake(sock->tlsContext);
1605 //if (!err) LogMsg("mDNSPlatformReadTCP SSLHandshake complete");
1606 if (!err) sock->handshakecomplete = mDNStrue;
1607 else if (err == errSSLWouldBlock) return(0);
1608 else { LogMsg("Read SSLHandshake failed: %d", err); SSLDisposeContext(sock->tlsContext); sock->tlsContext = NULL; }
1609 }
1610
1611 //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
1612 mStatus err = SSLRead(sock->tlsContext, buf, buflen, (size_t*)&nread);
1613 //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
1614 if (err == errSSLClosedGraceful) { nread = 0; *closed = mDNStrue; }
1615 else if (err && err != errSSLWouldBlock)
1616 { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err); nread = -1; *closed = mDNStrue; }
1617 #else
1618 nread = -1;
1619 *closed = mDNStrue;
1620 #endif /* NO_SECURITYFRAMEWORK */
1621 }
1622 else
1623 {
1624 static int CLOSEDcount = 0;
1625 static int EAGAINcount = 0;
1626 nread = recv(sock->fd, buf, buflen, 0);
1627
1628 if (nread > 0) { CLOSEDcount = 0; EAGAINcount = 0; } // On success, clear our error counters
1629 else if (nread == 0)
1630 {
1631 *closed = mDNStrue;
1632 if ((++CLOSEDcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock->fd, CLOSEDcount); sleep(1); }
1633 }
1634 // else nread is negative -- see what kind of error we got
1635 else if (errno == ECONNRESET) { nread = 0; *closed = mDNStrue; }
1636 else if (errno != EAGAIN) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d %s", errno, strerror(errno)); nread = -1; }
1637 else // errno is EAGAIN (EWOULDBLOCK) -- no data available
1638 {
1639 nread = 0;
1640 if ((++EAGAINcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock->fd, EAGAINcount); sleep(1); }
1641 }
1642 }
1643
1644 return nread;
1645 }
1646
1647 mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
1648 {
1649 int nsent;
1650
1651 if (sock->flags & kTCPSocketFlags_UseTLS)
1652 {
1653 #ifndef NO_SECURITYFRAMEWORK
1654 size_t processed;
1655 mStatus err = SSLWrite(sock->tlsContext, msg, len, &processed);
1656
1657 if (!err) nsent = (int) processed;
1658 else if (err == errSSLWouldBlock) nsent = 0;
1659 else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err); nsent = -1; }
1660 #else
1661 nsent = -1;
1662 #endif /* NO_SECURITYFRAMEWORK */
1663 }
1664 else
1665 {
1666 nsent = send(sock->fd, msg, len, 0);
1667 if (nsent < 0)
1668 {
1669 if (errno == EAGAIN) nsent = 0;
1670 else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno)); nsent = -1; }
1671 }
1672 }
1673
1674 return nsent;
1675 }
1676
1677 mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
1678 {
1679 return sock->fd;
1680 }
1681
1682 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
1683 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
1684 mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family, mDNSIPPort *const outport)
1685 {
1686 const int ip_tosbits = IPTOS_LOWDELAY | IPTOS_THROUGHPUT;
1687 int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
1688 KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
1689 const int on = 1;
1690 const int twofivefive = 255;
1691 mStatus err = mStatus_NoError;
1692 char *errstr = mDNSNULL;
1693
1694 int skt = socket(sa_family, SOCK_DGRAM, IPPROTO_UDP);
1695 if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno)); return(skt); }
1696
1697 // ... with a shared UDP port, if it's for multicast receiving
1698 if (mDNSSameIPPort(port, MulticastDNSPort)) err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
1699 if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; }
1700
1701 if (sa_family == AF_INET)
1702 {
1703 // We want to receive destination addresses
1704 err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
1705 if (err < 0) { errstr = "setsockopt - IP_RECVDSTADDR"; goto fail; }
1706
1707 // We want to receive interface identifiers
1708 err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
1709 if (err < 0) { errstr = "setsockopt - IP_RECVIF"; goto fail; }
1710
1711 // We want to receive packet TTL value so we can check it
1712 err = setsockopt(skt, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on));
1713 // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
1714
1715 // Send unicast packets with TTL 255
1716 err = setsockopt(skt, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive));
1717 if (err < 0) { errstr = "setsockopt - IP_TTL"; goto fail; }
1718
1719 // And multicast packets with TTL 255 too
1720 err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive));
1721 if (err < 0) { errstr = "setsockopt - IP_MULTICAST_TTL"; goto fail; }
1722
1723 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
1724 err = setsockopt(skt, IPPROTO_IP, IP_TOS, &ip_tosbits, sizeof(ip_tosbits));
1725 if (err < 0) { errstr = "setsockopt - IP_TOS"; goto fail; }
1726
1727 // And start listening for packets
1728 struct sockaddr_in listening_sockaddr;
1729 listening_sockaddr.sin_family = AF_INET;
1730 listening_sockaddr.sin_port = port.NotAnInteger;
1731 listening_sockaddr.sin_addr.s_addr = 0; // Want to receive multicasts AND unicasts on this socket
1732 err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr));
1733 if (err) { errstr = "bind"; goto fail; }
1734 if (outport) outport->NotAnInteger = listening_sockaddr.sin_port;
1735 }
1736 else if (sa_family == AF_INET6)
1737 {
1738 // We want to receive destination addresses and receive interface identifiers
1739 err = setsockopt(skt, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on));
1740 if (err < 0) { errstr = "setsockopt - IPV6_PKTINFO"; goto fail; }
1741
1742 // We want to receive packet hop count value so we can check it
1743 err = setsockopt(skt, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof(on));
1744 if (err < 0) { errstr = "setsockopt - IPV6_HOPLIMIT"; goto fail; }
1745
1746 // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
1747 // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
1748 err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
1749 if (err < 0) { errstr = "setsockopt - IPV6_V6ONLY"; goto fail; }
1750
1751 // Send unicast packets with TTL 255
1752 err = setsockopt(skt, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &twofivefive, sizeof(twofivefive));
1753 if (err < 0) { errstr = "setsockopt - IPV6_UNICAST_HOPS"; goto fail; }
1754
1755 // And multicast packets with TTL 255 too
1756 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive));
1757 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_HOPS"; goto fail; }
1758
1759 // Note: IPV6_TCLASS appears not to be implemented on OS X right now (or indeed on ANY version of Unix?)
1760 #ifdef IPV6_TCLASS
1761 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
1762 int tclass = IPTOS_LOWDELAY | IPTOS_THROUGHPUT; // This may not be right (since tclass is not implemented on OS X, I can't test it)
1763 err = setsockopt(skt, IPPROTO_IPV6, IPV6_TCLASS, &tclass, sizeof(tclass));
1764 if (err < 0) { errstr = "setsockopt - IPV6_TCLASS"; goto fail; }
1765 #endif
1766
1767 // Want to receive our own packets
1768 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on));
1769 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_LOOP"; goto fail; }
1770
1771 // And start listening for packets
1772 struct sockaddr_in6 listening_sockaddr6;
1773 mDNSPlatformMemZero(&listening_sockaddr6, sizeof(listening_sockaddr6));
1774 listening_sockaddr6.sin6_len = sizeof(listening_sockaddr6);
1775 listening_sockaddr6.sin6_family = AF_INET6;
1776 listening_sockaddr6.sin6_port = port.NotAnInteger;
1777 listening_sockaddr6.sin6_flowinfo = 0;
1778 listening_sockaddr6.sin6_addr = in6addr_any; // Want to receive multicasts AND unicasts on this socket
1779 listening_sockaddr6.sin6_scope_id = 0;
1780 err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6));
1781 if (err) { errstr = "bind"; goto fail; }
1782 if (outport) outport->NotAnInteger = listening_sockaddr6.sin6_port;
1783 }
1784
1785 fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
1786 fcntl(skt, F_SETFD, 1); // set close-on-exec
1787 *s = skt;
1788 k->KQcallback = myKQSocketCallBack;
1789 k->KQcontext = cp;
1790 k->KQtask = "UDP packet reception";
1791 KQueueSet(*s, EV_ADD, EVFILT_READ, k);
1792
1793 return(err);
1794
1795 fail:
1796 // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
1797 if (strcmp(errstr, "bind") || mDNSSameIPPort(port, MulticastDNSPort) || mDNSIPPortIsZero(port))
1798 LogMsg("%s error %ld errno %d (%s)", errstr, err, errno, strerror(errno));
1799
1800 // If we got a "bind" failure with an EADDRINUSE error for our shared mDNS port, display error alert
1801 if (!strcmp(errstr, "bind") && mDNSSameIPPort(port, MulticastDNSPort) && errno == EADDRINUSE)
1802 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
1803 "Congratulations, you've reproduced an elusive bug.\r"
1804 "Please contact the current assignee of <rdar://problem/3814904>.\r"
1805 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
1806 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1807
1808 close(skt);
1809 return(err);
1810 }
1811
1812 mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort port)
1813 {
1814 mStatus err;
1815 UDPSocket *p = mallocL("UDPSocket", sizeof(UDPSocket));
1816 if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); }
1817 memset(p, 0, sizeof(UDPSocket));
1818 p->ss.m = m;
1819 p->ss.sktv4 = -1;
1820 p->ss.sktv6 = -1;
1821 p->port = zeroIPPort;
1822 err = SetupSocket(&p->ss, port, AF_INET, &p->port);
1823 if (err)
1824 {
1825 // In customer builds we don't want to log failures with port 5351, because this is a known issue
1826 // of failing to bind to this port when Internet Sharing has already bound to it
1827 if (mDNSSameIPPort(port, NATPMPPort))
1828 LogOperation("mDNSPlatformUDPSocket: SetupSocket %d failed", mDNSVal16(port));
1829 else LogMsg ("mDNSPlatformUDPSocket: SetupSocket %d failed", mDNSVal16(port));
1830 freeL("UDPSocket", p);
1831 return(mDNSNULL);
1832 }
1833 return(p);
1834 }
1835
1836 mDNSlocal void CloseSocketSet(KQSocketSet *ss)
1837 {
1838 if (ss->sktv4 != -1)
1839 {
1840 close(ss->sktv4);
1841 ss->sktv4 = -1;
1842 }
1843 if (ss->sktv6 != -1)
1844 {
1845 close(ss->sktv6);
1846 ss->sktv6 = -1;
1847 }
1848 }
1849
1850 mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
1851 {
1852 CloseSocketSet(&sock->ss);
1853 freeL("UDPSocket", sock);
1854 }
1855
1856 #if COMPILER_LIKES_PRAGMA_MARK
1857 #pragma mark -
1858 #pragma mark - Key Management
1859 #endif
1860
1861 #ifndef NO_SECURITYFRAMEWORK
1862 mDNSlocal CFArrayRef GetCertChain(SecIdentityRef identity)
1863 {
1864 CFMutableArrayRef certChain = NULL;
1865 if (!identity) { LogMsg("getCertChain: identity is NULL"); return(NULL); }
1866 SecCertificateRef cert;
1867 OSStatus err = SecIdentityCopyCertificate(identity, &cert);
1868 if (err || !cert) LogMsg("getCertChain: SecIdentityCopyCertificate() returned %d", (int) err);
1869 else
1870 {
1871 SecPolicySearchRef searchRef;
1872 err = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef);
1873 if (err || !searchRef) LogMsg("getCertChain: SecPolicySearchCreate() returned %d", (int) err);
1874 else
1875 {
1876 SecPolicyRef policy;
1877 err = SecPolicySearchCopyNext(searchRef, &policy);
1878 if (err || !policy) LogMsg("getCertChain: SecPolicySearchCopyNext() returned %d", (int) err);
1879 else
1880 {
1881 CFArrayRef wrappedCert = CFArrayCreate(NULL, (const void**) &cert, 1, &kCFTypeArrayCallBacks);
1882 if (!wrappedCert) LogMsg("getCertChain: wrappedCert is NULL");
1883 else
1884 {
1885 SecTrustRef trust;
1886 err = SecTrustCreateWithCertificates(wrappedCert, policy, &trust);
1887 if (err || !trust) LogMsg("getCertChain: SecTrustCreateWithCertificates() returned %d", (int) err);
1888 else
1889 {
1890 err = SecTrustEvaluate(trust, NULL);
1891 if (err) LogMsg("getCertChain: SecTrustEvaluate() returned %d", (int) err);
1892 else
1893 {
1894 CFArrayRef rawCertChain;
1895 CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
1896 err = SecTrustGetResult(trust, NULL, &rawCertChain, &statusChain);
1897 if (err || !rawCertChain || !statusChain) LogMsg("getCertChain: SecTrustGetResult() returned %d", (int) err);
1898 else
1899 {
1900 certChain = CFArrayCreateMutableCopy(NULL, 0, rawCertChain);
1901 if (!certChain) LogMsg("getCertChain: certChain is NULL");
1902 else
1903 {
1904 // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
1905 // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
1906 CFArraySetValueAtIndex(certChain, 0, identity);
1907 // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
1908 if (CFArrayGetCount(certChain) > 1) CFArrayRemoveValueAtIndex(certChain, CFArrayGetCount(certChain) - 1);
1909 }
1910 CFRelease(rawCertChain);
1911 // Do not free statusChain:
1912 // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
1913 // certChain: Call the CFRelease function to release this object when you are finished with it.
1914 // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
1915 }
1916 }
1917 CFRelease(trust);
1918 }
1919 CFRelease(wrappedCert);
1920 }
1921 CFRelease(policy);
1922 }
1923 CFRelease(searchRef);
1924 }
1925 CFRelease(cert);
1926 }
1927 return certChain;
1928 }
1929 #endif /* NO_SECURITYFRAMEWORK */
1930
1931 mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
1932 {
1933 #ifdef NO_SECURITYFRAMEWORK
1934 return mStatus_UnsupportedErr;
1935 #else
1936 SecIdentityRef identity = nil;
1937 SecIdentitySearchRef srchRef = nil;
1938 OSStatus err;
1939
1940 // search for "any" identity matching specified key use
1941 // In this app, we expect there to be exactly one
1942 err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_DECRYPT, &srchRef);
1943 if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err); return err; }
1944
1945 err = SecIdentitySearchCopyNext(srchRef, &identity);
1946 if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err); return err; }
1947
1948 if (CFGetTypeID(identity) != SecIdentityGetTypeID())
1949 { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr; }
1950
1951 // Found one. Call getCertChain to create the correct certificate chain.
1952 ServerCerts = GetCertChain(identity);
1953 if (ServerCerts == nil) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: getCertChain error"); return mStatus_UnknownErr; }
1954
1955 return mStatus_NoError;
1956 #endif /* NO_SECURITYFRAMEWORK */
1957 }
1958
1959 mDNSexport void mDNSPlatformTLSTearDownCerts(void)
1960 {
1961 #ifndef NO_SECURITYFRAMEWORK
1962 if (ServerCerts) { CFRelease(ServerCerts); ServerCerts = NULL; }
1963 #endif /* NO_SECURITYFRAMEWORK */
1964 }
1965
1966 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
1967 mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
1968 {
1969 CFStringEncoding encoding = kCFStringEncodingUTF8;
1970 CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
1971 if (cfs)
1972 {
1973 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
1974 CFRelease(cfs);
1975 }
1976 }
1977
1978 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
1979 mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel)
1980 {
1981 CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
1982 if (cfs)
1983 {
1984 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
1985 CFRelease(cfs);
1986 }
1987 }
1988
1989 mDNSlocal mDNSBool DDNSSettingEnabled(CFDictionaryRef dict)
1990 {
1991 mDNSs32 val;
1992 CFNumberRef state = CFDictionaryGetValue(dict, CFSTR("Enabled"));
1993 if (!state) return mDNSfalse;
1994 if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val)) { LogMsg("ERROR: DDNSSettingEnabled - CFNumberGetValue"); return mDNSfalse; }
1995 return val ? mDNStrue : mDNSfalse;
1996 }
1997
1998 mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
1999 {
2000 if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
2001
2002 if (sa->sa_family == AF_INET)
2003 {
2004 struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
2005 ip->type = mDNSAddrType_IPv4;
2006 ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
2007 return(mStatus_NoError);
2008 }
2009
2010 if (sa->sa_family == AF_INET6)
2011 {
2012 struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
2013 // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
2014 // value into the second word of the IPv6 link-local address, so they can just
2015 // pass around IPv6 address structures instead of full sockaddr_in6 structures.
2016 // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
2017 // To work around this we always whack the second word of any IPv6 link-local address back to zero.
2018 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
2019 ip->type = mDNSAddrType_IPv6;
2020 ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
2021 return(mStatus_NoError);
2022 }
2023
2024 LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
2025 return(mStatus_Invalid);
2026 }
2027
2028 mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name)
2029 {
2030 mDNSEthAddr eth = zeroEthAddr;
2031 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetBSSID"), NULL, NULL);
2032 if (store)
2033 {
2034 CFStringRef entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name);
2035 if (entityname)
2036 {
2037 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, entityname);
2038 if (dict)
2039 {
2040 CFRange range = { 0, 6 }; // Offset, length
2041 CFDataRef data = CFDictionaryGetValue(dict, CFSTR("BSSID"));
2042 if (data && CFDataGetLength(data) == 6) CFDataGetBytes(data, range, eth.b);
2043 CFRelease(dict);
2044 }
2045 CFRelease(entityname);
2046 }
2047 CFRelease(store);
2048 }
2049 return(eth);
2050 }
2051
2052 // Returns pointer to newly created NetworkInterfaceInfoOSX object, or
2053 // pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
2054 // may return NULL if out of memory (unlikely) or parameters are invalid for some reason
2055 // (e.g. sa_family not AF_INET or AF_INET6)
2056 mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa, mDNSs32 utc)
2057 {
2058 mDNSu32 scope_id = if_nametoindex(ifa->ifa_name);
2059 mDNSEthAddr bssid = GetBSSID(ifa->ifa_name);
2060
2061 mDNSAddr ip, mask;
2062 if (SetupAddr(&ip, ifa->ifa_addr ) != mStatus_NoError) return(NULL);
2063 if (SetupAddr(&mask, ifa->ifa_netmask) != mStatus_NoError) return(NULL);
2064
2065 NetworkInterfaceInfoOSX **p;
2066 for (p = &m->p->InterfaceList; *p; p = &(*p)->next)
2067 if (scope_id == (*p)->scope_id && mDNSSameAddress(&ip, &(*p)->ifinfo.ip) && mDNSSameEthAddress(&bssid, &(*p)->BSSID))
2068 {
2069 debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, *p);
2070 (*p)->Exists = mDNStrue;
2071 // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
2072 if ((*p)->LastSeen != utc) (*p)->AppearanceTime = utc;
2073 return(*p);
2074 }
2075
2076 NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
2077 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i);
2078 if (!i) return(mDNSNULL);
2079 mDNSPlatformMemZero(i, sizeof(NetworkInterfaceInfoOSX));
2080 i->ifa_name = (char *)mallocL("NetworkInterfaceInfoOSX name", strlen(ifa->ifa_name) + 1);
2081 if (!i->ifa_name) { freeL("NetworkInterfaceInfoOSX", i); return(mDNSNULL); }
2082 strcpy(i->ifa_name, ifa->ifa_name); // This is safe because we know we allocated i->ifa_name with sufficient space
2083
2084 i->ifinfo.InterfaceID = mDNSNULL;
2085 i->ifinfo.ip = ip;
2086 i->ifinfo.mask = mask;
2087 strlcpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname));
2088 i->ifinfo.ifname[sizeof(i->ifinfo.ifname)-1] = 0;
2089 i->ifinfo.Advertise = m->AdvertiseLocalAddresses;
2090 i->ifinfo.McastTxRx = mDNSfalse; // For now; will be set up later at the end of UpdateInterfaceList
2091
2092 i->next = mDNSNULL;
2093 i->Exists = mDNStrue;
2094 i->AppearanceTime = utc; // Brand new interface; AppearanceTime is now
2095 i->LastSeen = utc;
2096 i->Flashing = mDNSfalse;
2097 i->Occulting = mDNSfalse;
2098 i->scope_id = scope_id;
2099 i->BSSID = bssid;
2100 i->sa_family = ifa->ifa_addr->sa_family;
2101 i->ifa_flags = ifa->ifa_flags;
2102
2103 *p = i;
2104 return(i);
2105 }
2106
2107 #if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
2108 mDNSlocal NetworkInterfaceInfoOSX *FindRoutableIPv4(mDNS *const m, mDNSu32 scope_id)
2109 {
2110 NetworkInterfaceInfoOSX *i;
2111 for (i = m->p->InterfaceList; i; i = i->next)
2112 if (i->Exists && i->scope_id == scope_id && i->ifinfo.ip.type == mDNSAddrType_IPv4)
2113 if (!mDNSv4AddressIsLinkLocal(&i->ifinfo.ip.ip.v4))
2114 return(i);
2115 return(mDNSNULL);
2116 }
2117 #endif
2118
2119 #if APPLE_OSX_mDNSResponder
2120
2121 #if COMPILER_LIKES_PRAGMA_MARK
2122 #pragma mark -
2123 #pragma mark - AutoTunnel
2124 #endif
2125
2126 #define kRacoonPort 4500
2127
2128 static mDNSBool AnonymousRacoonConfig = mDNSfalse;
2129
2130 // MUST be called with lock held
2131 mDNSlocal mDNSBool TunnelServers(mDNS *const m)
2132 {
2133 ServiceRecordSet *p;
2134 for (p = m->ServiceRegistrations; p; p = p->uDNS_next)
2135 {
2136 DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, p->RR_SRV.resrec.name);
2137 if (AuthInfo && AuthInfo->AutoTunnel && !AuthInfo->deltime) return(mDNStrue);
2138 }
2139 return(mDNSfalse);
2140 }
2141
2142 // MUST be called with lock held
2143 mDNSlocal mDNSBool TunnelClients(mDNS *const m)
2144 {
2145 ClientTunnel *p;
2146 for (p = m->TunnelClients; p; p = p->next)
2147 if (p->q.ThisQInterval < 0)
2148 return(mDNStrue);
2149 return(mDNSfalse);
2150 }
2151
2152 mDNSlocal void RegisterAutoTunnelRecords(mDNS *m, DomainAuthInfo *info)
2153 {
2154 if (info->AutoTunnelNAT.clientContext && !info->AutoTunnelNAT.Result && !mDNSIPPortIsZero(info->AutoTunnelNAT.ExternalPort) && AutoTunnelUnregistered(info))
2155 {
2156 mStatus err;
2157 LogOperation("RegisterAutoTunnelRecords %##s (%#s)", info->domain.c, m->hostlabel.c);
2158
2159 // 1. Set up our address record for the internal tunnel address
2160 // (User-visible user-friendly host name, used as target in AutoTunnel SRV records)
2161 info->AutoTunnelHostRecord.namestorage.c[0] = 0;
2162 AppendDomainLabel(&info->AutoTunnelHostRecord.namestorage, &m->hostlabel);
2163 AppendDomainName (&info->AutoTunnelHostRecord.namestorage, &info->domain);
2164 info->AutoTunnelHostRecord.resrec.rdata->u.ipv6 = m->AutoTunnelHostAddr;
2165 info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeKnownUnique;
2166 err = mDNS_Register(m, &info->AutoTunnelHostRecord);
2167 if (err) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelHostRecord %##s", err, info->AutoTunnelHostRecord.namestorage.c);
2168
2169 // 2. Set up device info record
2170 ConstructServiceName(&info->AutoTunnelDeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &info->domain);
2171 mDNSu8 len = m->HIHardware.c[0] < 255 - 6 ? m->HIHardware.c[0] : 255 - 6;
2172 mDNSPlatformMemCopy(info->AutoTunnelDeviceInfo.resrec.rdata->u.data + 1, "model=", 6);
2173 mDNSPlatformMemCopy(info->AutoTunnelDeviceInfo.resrec.rdata->u.data + 7, m->HIHardware.c + 1, len);
2174 info->AutoTunnelDeviceInfo.resrec.rdata->u.data[0] = 6 + len; // "model=" plus the device string
2175 info->AutoTunnelDeviceInfo.resrec.rdlength = 7 + len; // One extra for the length byte at the start of the string
2176 info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeKnownUnique;
2177 err = mDNS_Register(m, &info->AutoTunnelDeviceInfo);
2178 if (err) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelDeviceInfo %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
2179
2180 // 3. Set up our address record for the external tunnel address
2181 // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
2182 info->AutoTunnelTarget.namestorage.c[0] = 0;
2183 AppendDomainLabel(&info->AutoTunnelTarget.namestorage, &m->AutoTunnelLabel);
2184 AppendDomainName (&info->AutoTunnelTarget.namestorage, &info->domain);
2185 info->AutoTunnelTarget.resrec.RecordType = kDNSRecordTypeKnownUnique;
2186
2187 mDNS_Lock(m);
2188 mDNS_AddDynDNSHostName(m, &info->AutoTunnelTarget.namestorage, mDNSNULL, info);
2189 mDNS_Unlock(m);
2190
2191 // 4. Set up IKE tunnel's SRV record: "AutoTunnelHostRecord SRV 0 0 port AutoTunnelTarget"
2192 AssignDomainName (&info->AutoTunnelService.namestorage, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
2193 AppendDomainLabel(&info->AutoTunnelService.namestorage, &m->hostlabel);
2194 AppendDomainName (&info->AutoTunnelService.namestorage, &info->domain);
2195 info->AutoTunnelService.resrec.rdata->u.srv.priority = 0;
2196 info->AutoTunnelService.resrec.rdata->u.srv.weight = 0;
2197 info->AutoTunnelService.resrec.rdata->u.srv.port = info->AutoTunnelNAT.ExternalPort;
2198 AssignDomainName(&info->AutoTunnelService.resrec.rdata->u.srv.target, &info->AutoTunnelTarget.namestorage);
2199 info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeKnownUnique;
2200 err = mDNS_Register(m, &info->AutoTunnelService);
2201 if (err) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelService %##s", err, info->AutoTunnelService.namestorage.c);
2202
2203 LogOperation("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
2204 info->AutoTunnelTarget.namestorage.c, &m->AdvertisedV4.ip.v4, mDNSVal16(info->AutoTunnelNAT.IntPort),
2205 info->AutoTunnelHostRecord.namestorage.c, &m->AutoTunnelHostAddr);
2206 }
2207 }
2208
2209 mDNSlocal void DeregisterAutoTunnelRecords(mDNS *m, DomainAuthInfo *info)
2210 {
2211 LogOperation("DeregisterAutoTunnelRecords %##s", info->domain.c);
2212 if (info->AutoTunnelService.resrec.RecordType > kDNSRecordTypeDeregistering)
2213 {
2214 mStatus err = mDNS_Deregister(m, &info->AutoTunnelService);
2215 if (err)
2216 {
2217 info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeUnregistered;
2218 LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelService %##s", err, info->AutoTunnelService.namestorage.c);
2219 }
2220
2221 mDNS_Lock(m);
2222 mDNS_RemoveDynDNSHostName(m, &info->AutoTunnelTarget.namestorage);
2223 mDNS_Unlock(m);
2224 }
2225
2226 if (info->AutoTunnelHostRecord.resrec.RecordType > kDNSRecordTypeDeregistering)
2227 {
2228 mStatus err = mDNS_Deregister(m, &info->AutoTunnelHostRecord);
2229 if (err)
2230 {
2231 info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeUnregistered;
2232 LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelHostRecord %##s", err, info->AutoTunnelHostRecord.namestorage.c);
2233 }
2234 }
2235
2236 if (info->AutoTunnelDeviceInfo.resrec.RecordType > kDNSRecordTypeDeregistering)
2237 {
2238 mStatus err = mDNS_Deregister(m, &info->AutoTunnelDeviceInfo);
2239 if (err)
2240 {
2241 info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeUnregistered;
2242 LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelDeviceInfo %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
2243 }
2244 }
2245 }
2246
2247 mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
2248 {
2249 DomainAuthInfo *info = (DomainAuthInfo *)rr->RecordContext;
2250 if (result == mStatus_MemFree)
2251 {
2252 LogOperation("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m, rr));
2253 RegisterAutoTunnelRecords(m,info);
2254 }
2255 }
2256
2257 mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n)
2258 {
2259 DomainAuthInfo *info = (DomainAuthInfo *)n->clientContext;
2260 LogOperation("AutoTunnelNATCallback Result %d %.4a Internal %d External %d %#s.%##s",
2261 n->Result, &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort), m->hostlabel.c, info->domain.c);
2262
2263 m->NextSRVUpdate = NonZeroTime(m->timenow);
2264 DeregisterAutoTunnelRecords(m,info);
2265 RegisterAutoTunnelRecords(m,info);
2266
2267 // Determine whether we need racoon to accept incoming connections
2268 for (info = m->AuthInfoList; info; info = info->next)
2269 if (info->AutoTunnel && !info->deltime && !mDNSIPPortIsZero(info->AutoTunnelNAT.ExternalPort))
2270 break;
2271 mDNSBool needRacoonConfig = info != mDNSNULL;
2272 if (needRacoonConfig != AnonymousRacoonConfig)
2273 {
2274 AnonymousRacoonConfig = needRacoonConfig;
2275 // Create or revert configuration file, and start (or SIGHUP) Racoon
2276 (void)mDNSConfigureServer(AnonymousRacoonConfig ? kmDNSUp : kmDNSDown, info ? info->b64keydata : "");
2277 }
2278 }
2279
2280 mDNSlocal void AbortDeregistration(mDNS *const m, AuthRecord *rr)
2281 {
2282 if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
2283 {
2284 LogOperation("Aborting deregistration of %s", ARDisplayString(m, rr));
2285 CompleteDeregistration(m, rr);
2286 }
2287 else if (rr->resrec.RecordType != kDNSRecordTypeUnregistered)
2288 LogMsg("AbortDeregistration ERROR RecordType %02X for %s", ARDisplayString(m, rr));
2289 }
2290
2291 // Before SetupLocalAutoTunnelInterface_internal is called,
2292 // m->AutoTunnelHostAddr.b[0] must be non-zero, and there must be at least one TunnelClient or TunnelServer
2293 // Must be called with the lock held
2294 mDNSexport void SetupLocalAutoTunnelInterface_internal(mDNS *const m)
2295 {
2296 LogOperation("SetupLocalAutoTunnelInterface");
2297
2298 // 1. Configure the local IPv6 address
2299 if (!m->AutoTunnelHostAddrActive)
2300 {
2301 m->AutoTunnelHostAddrActive = mDNStrue;
2302 LogOperation("Setting up AutoTunnel address %.16a", &m->AutoTunnelHostAddr);
2303 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSUp, m->AutoTunnelHostAddr.b);
2304 }
2305
2306 // 2. If we have at least one server (pending) listening, publish our records
2307 if (TunnelServers(m))
2308 {
2309 DomainAuthInfo *info;
2310 for (info = m->AuthInfoList; info; info = info->next)
2311 {
2312 if (info->AutoTunnel && !info->deltime && !info->AutoTunnelNAT.clientContext)
2313 {
2314 // If we just resurrected a DomainAuthInfo that is still deregistering, we need to abort the deregistration process before re-using the AuthRecord memory
2315 AbortDeregistration(m, &info->AutoTunnelHostRecord);
2316 AbortDeregistration(m, &info->AutoTunnelDeviceInfo);
2317 AbortDeregistration(m, &info->AutoTunnelService);
2318
2319 mDNS_SetupResourceRecord(&info->AutoTunnelHostRecord, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
2320 mDNS_SetupResourceRecord(&info->AutoTunnelDeviceInfo, mDNSNULL, mDNSInterface_Any, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
2321 mDNS_SetupResourceRecord(&info->AutoTunnelTarget, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
2322 mDNS_SetupResourceRecord(&info->AutoTunnelService, mDNSNULL, mDNSInterface_Any, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
2323
2324 // Try to get a NAT port mapping for the AutoTunnelService
2325 info->AutoTunnelNAT.clientCallback = AutoTunnelNATCallback;
2326 info->AutoTunnelNAT.clientContext = info;
2327 info->AutoTunnelNAT.Protocol = NATOp_MapUDP;
2328 info->AutoTunnelNAT.IntPort = mDNSOpaque16fromIntVal(kRacoonPort);
2329 info->AutoTunnelNAT.RequestedPort = mDNSOpaque16fromIntVal(kRacoonPort);
2330 info->AutoTunnelNAT.NATLease = 0;
2331 mStatus err = mDNS_StartNATOperation_internal(m, &info->AutoTunnelNAT);
2332 if (err) LogMsg("SetupLocalAutoTunnelInterface_internal error %d starting NAT mapping", err);
2333 }
2334 }
2335 }
2336 }
2337
2338 mDNSlocal mStatus AutoTunnelSetKeys(ClientTunnel *tun, mDNSBool AddNew)
2339 {
2340 return(mDNSAutoTunnelSetKeys(AddNew ? kmDNSAutoTunnelSetKeysReplace : kmDNSAutoTunnelSetKeysDelete, tun->loc_inner.b, tun->loc_outer.b, kRacoonPort, tun->rmt_inner.b, tun->rmt_outer.b, mDNSVal16(tun->rmt_outer_port), tun->b64keydata));
2341 }
2342
2343 // If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
2344 #define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
2345
2346 mDNSlocal void ReissueBlockedQuestionWithType(mDNS *const m, domainname *d, mDNSBool success, mDNSu16 qtype)
2347 {
2348 DNSQuestion *q = m->Questions;
2349 while (q)
2350 {
2351 if (q->NoAnswer == NoAnswer_Suspended && q->qtype == qtype && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d))
2352 {
2353 LogOperation("Restart %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
2354 mDNSQuestionCallback *tmp = q->QuestionCallback;
2355 q->QuestionCallback = AutoTunnelCallback; // Set QuestionCallback to suppress another call back to AddNewClientTunnel
2356 mDNS_StopQuery(m, q);
2357 mDNS_StartQuery(m, q);
2358 q->QuestionCallback = tmp; // Restore QuestionCallback back to the real value
2359 if (!success) q->NoAnswer = NoAnswer_Fail;
2360 // When we call mDNS_StopQuery, it's possible for other subbordinate questions like the GetZoneData query to be cancelled too.
2361 // In general we have to assume that the question list might have changed in arbitrary ways.
2362 // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
2363 // already in use. The safest solution is just to go back to the start of the list and start again.
2364 // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
2365 // just one suspended question, so it's really a 2n algorithm.
2366 q = m->Questions;
2367 }
2368 else
2369 q = q->next;
2370 }
2371 }
2372
2373 mDNSlocal void ReissueBlockedQuestions(mDNS *const m, domainname *d, mDNSBool success)
2374 {
2375 // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has
2376 // a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN.
2377 // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller --
2378 // even if the name does have a valid AAAA record, we don't want clients trying to connect to it without a properly encrypted tunnel.
2379 // 3. For A queries we never fabricate failures -- if a BTTM service is really using raw IPv4, then it doesn't need the IPv6 tunnel.
2380 ReissueBlockedQuestionWithType(m, d, success, kDNSType_AAAA);
2381 ReissueBlockedQuestionWithType(m, d, mDNStrue, kDNSType_A);
2382 }
2383
2384 mDNSlocal void UnlinkAndReissueBlockedQuestions(mDNS *const m, ClientTunnel *tun, mDNSBool success)
2385 {
2386 ClientTunnel **p = &m->TunnelClients;
2387 while (*p != tun && *p) p = &(*p)->next;
2388 if (*p) *p = tun->next;
2389 ReissueBlockedQuestions(m, &tun->dstname, success);
2390 LogOperation("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun);
2391 freeL("ClientTunnel", tun);
2392 }
2393
2394 mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
2395 {
2396 ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
2397 LogOperation("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun, AddRecord, answer->rdlength, question->qtype);
2398
2399 if (!AddRecord) return;
2400 mDNS_StopQuery(m, question);
2401
2402 if (!answer->rdlength)
2403 {
2404 LogOperation("AutoTunnelCallback NXDOMAIN %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
2405 UnlinkAndReissueBlockedQuestions(m, tun, mDNSfalse);
2406 return;
2407 }
2408
2409 if (question->qtype == kDNSType_AAAA)
2410 {
2411 if (mDNSSameIPv6Address(answer->rdata->u.ipv6, m->AutoTunnelHostAddr))
2412 {
2413 LogOperation("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer->rdata->u.ipv6);
2414 UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
2415 return;
2416 }
2417
2418 tun->rmt_inner = answer->rdata->u.ipv6;
2419 LogOperation("AutoTunnelCallback: dst host %.16a", &tun->rmt_inner);
2420 AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
2421 AppendDomainName(&question->qname, &tun->dstname);
2422 question->qtype = kDNSType_SRV;
2423 mDNS_StartQuery(m, &tun->q);
2424 }
2425 else if (question->qtype == kDNSType_SRV)
2426 {
2427 LogOperation("AutoTunnelCallback: SRV target name %##s", answer->rdata->u.srv.target.c);
2428 AssignDomainName(&tun->q.qname, &answer->rdata->u.srv.target);
2429 tun->rmt_outer_port = answer->rdata->u.srv.port;
2430 question->qtype = kDNSType_A;
2431 mDNS_StartQuery(m, &tun->q);
2432 }
2433 else if (question->qtype == kDNSType_A)
2434 {
2435 ClientTunnel *old = mDNSNULL;
2436 LogOperation("AutoTunnelCallback: SRV target addr %.4a", &answer->rdata->u.ipv4);
2437 question->ThisQInterval = -1; // So we know this tunnel setup has completed
2438 tun->rmt_outer = answer->rdata->u.ipv4;
2439 tun->loc_inner = m->AutoTunnelHostAddr;
2440 mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
2441 tmpDst.ip.v4 = tun->rmt_outer;
2442 mDNSAddr tmpSrc = zeroAddr;
2443 mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
2444 if (tmpSrc.type == mDNSAddrType_IPv4) tun->loc_outer = tmpSrc.ip.v4;
2445 else tun->loc_outer = m->AdvertisedV4.ip.v4;
2446
2447 ClientTunnel **p = &tun->next;
2448 mDNSBool needSetKeys = mDNStrue;
2449 while (*p)
2450 {
2451 if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
2452 else
2453 {
2454 LogOperation("Found existing AutoTunnel for %##s %.16a", tun->dstname.c, &tun->rmt_inner);
2455 old = *p;
2456 *p = old->next;
2457 if (old->q.ThisQInterval >= 0) mDNS_StopQuery(m, &old->q);
2458 else if (!mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
2459 !mDNSSameIPv4Address(old->loc_outer, tun->loc_outer) ||
2460 !mDNSSameIPv6Address(old->rmt_inner, tun->rmt_inner) ||
2461 !mDNSSameIPv4Address(old->rmt_outer, tun->rmt_outer) ||
2462 !mDNSSameIPPort(old->rmt_outer_port, tun->rmt_outer_port))
2463 {
2464 LogOperation("Deleting existing AutoTunnel for %##s %.16a", tun->dstname.c, &tun->rmt_inner);
2465 AutoTunnelSetKeys(old, mDNSfalse);
2466 }
2467 else needSetKeys = mDNSfalse;
2468
2469 LogOperation("AutoTunnelCallback: Disposing ClientTunnel %p", tun);
2470 freeL("ClientTunnel", old);
2471 }
2472 }
2473
2474 if (needSetKeys) LogOperation("New AutoTunnel for %##s %.16a", tun->dstname.c, &tun->rmt_inner);
2475
2476 if (m->AutoTunnelHostAddr.b[0]) { mDNS_Lock(m); SetupLocalAutoTunnelInterface_internal(m); mDNS_Unlock(m); };
2477
2478 mStatus result = needSetKeys ? AutoTunnelSetKeys(tun, mDNStrue) : mStatus_NoError;
2479 // Kick off any questions that were held pending this tunnel setup
2480 ReissueBlockedQuestions(m, &tun->dstname, (result == mStatus_NoError) ? mDNStrue : mDNSfalse);
2481 }
2482 else
2483 LogMsg("AutoTunnelCallback: Unknown question %p", question);
2484 }
2485
2486 // Must be called with the lock held
2487 mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q)
2488 {
2489 ClientTunnel *p = mallocL("ClientTunnel", sizeof(ClientTunnel));
2490 if (!p) return;
2491 AssignDomainName(&p->dstname, &q->qname);
2492 p->MarkedForDeletion = mDNSfalse;
2493 p->loc_inner = zerov6Addr;
2494 p->loc_outer = zerov4Addr;
2495 p->rmt_inner = zerov6Addr;
2496 p->rmt_outer = zerov4Addr;
2497 p->rmt_outer_port = zeroIPPort;
2498 mDNS_snprintf(p->b64keydata, sizeof(p->b64keydata), "%s", q->AuthInfo->b64keydata);
2499 p->next = m->TunnelClients;
2500 m->TunnelClients = p; // We intentionally build list in reverse order
2501
2502 p->q.InterfaceID = mDNSInterface_Any;
2503 p->q.Target = zeroAddr;
2504 AssignDomainName(&p->q.qname, &q->qname);
2505 p->q.qtype = kDNSType_AAAA;
2506 p->q.qclass = kDNSClass_IN;
2507 p->q.LongLived = mDNSfalse;
2508 p->q.ExpectUnique = mDNStrue;
2509 p->q.ForceMCast = mDNSfalse;
2510 p->q.ReturnIntermed = mDNStrue;
2511 p->q.QuestionCallback = AutoTunnelCallback;
2512 p->q.QuestionContext = p;
2513
2514 LogOperation("AddNewClientTunnel start tun %p %##s (%s)%s", p, &q->qname.c, DNSTypeName(q->qtype), q->LongLived ? " LongLived" : "");
2515 mDNS_StartQuery_internal(m, &p->q);
2516 }
2517
2518 #endif // APPLE_OSX_mDNSResponder
2519
2520 #if COMPILER_LIKES_PRAGMA_MARK
2521 #pragma mark -
2522 #pragma mark - Power State & Configuration Change Management
2523 #endif
2524
2525 mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
2526 {
2527 mDNSBool foundav4 = mDNSfalse;
2528 mDNSBool foundav6 = mDNSfalse;
2529 struct ifaddrs *ifa = myGetIfAddrs(1);
2530 struct ifaddrs *v4Loopback = NULL;
2531 struct ifaddrs *v6Loopback = NULL;
2532 mDNSEthAddr PrimaryMAC = zeroEthAddr;
2533 char defaultname[32];
2534 #ifndef NO_IPV6
2535 int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
2536 if (InfoSocket < 3 && errno != EAFNOSUPPORT) LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno));
2537 #endif
2538 if (m->SleepState) ifa = NULL;
2539
2540 while (ifa)
2541 {
2542 #if LIST_ALL_INTERFACES
2543 if (ifa->ifa_addr->sa_family == AF_APPLETALK)
2544 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
2545 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
2546 else if (ifa->ifa_addr->sa_family == AF_LINK)
2547 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
2548 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
2549 else if (ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6)
2550 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
2551 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
2552 if (!(ifa->ifa_flags & IFF_UP))
2553 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
2554 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
2555 if (!(ifa->ifa_flags & IFF_MULTICAST))
2556 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
2557 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
2558 if (ifa->ifa_flags & IFF_POINTOPOINT)
2559 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
2560 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
2561 if (ifa->ifa_flags & IFF_LOOPBACK)
2562 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
2563 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
2564 #endif
2565
2566 if (ifa->ifa_addr->sa_family == AF_LINK)
2567 {
2568 struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
2569 if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == sizeof(PrimaryMAC) && mDNSSameEthAddress(&PrimaryMAC, &zeroEthAddr))
2570 mDNSPlatformMemCopy(PrimaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6);
2571 }
2572
2573 if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr)
2574 if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6)
2575 {
2576 if (!ifa->ifa_netmask)
2577 {
2578 mDNSAddr ip;
2579 SetupAddr(&ip, ifa->ifa_addr);
2580 LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
2581 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip);
2582 }
2583 else if (ifa->ifa_addr->sa_family != ifa->ifa_netmask->sa_family)
2584 {
2585 mDNSAddr ip;
2586 SetupAddr(&ip, ifa->ifa_addr);
2587 LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
2588 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip, ifa->ifa_netmask->sa_family);
2589 }
2590 else
2591 {
2592 int ifru_flags6 = 0;
2593 #ifndef NO_IPV6
2594 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
2595 if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
2596 {
2597 struct in6_ifreq ifr6;
2598 mDNSPlatformMemZero((char *)&ifr6, sizeof(ifr6));
2599 strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
2600 ifr6.ifr_addr = *sin6;
2601 if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
2602 ifru_flags6 = ifr6.ifr_ifru.ifru_flags6;
2603 verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6);
2604 }
2605 #endif
2606 if (!(ifru_flags6 & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
2607 {
2608 if (ifa->ifa_flags & IFF_LOOPBACK)
2609 {
2610 if (ifa->ifa_addr->sa_family == AF_INET) v4Loopback = ifa;
2611 #ifndef NO_IPV6
2612 else if (sin6->sin6_addr.s6_addr[0] != 0xFD) v6Loopback = ifa;
2613 #endif
2614 }
2615 else
2616 {
2617 NetworkInterfaceInfoOSX *i = AddInterfaceToList(m, ifa, utc);
2618 if (i && MulticastInterface(i))
2619 {
2620 if (ifa->ifa_addr->sa_family == AF_INET) foundav4 = mDNStrue;
2621 else foundav6 = mDNStrue;
2622 }
2623 }
2624 }
2625 }
2626 }
2627 ifa = ifa->ifa_next;
2628 }
2629
2630 // For efficiency, we don't register a loopback interface when other interfaces of that family are available
2631 if (!foundav4 && v4Loopback) AddInterfaceToList(m, v4Loopback, utc);
2632 if (!foundav6 && v6Loopback) AddInterfaceToList(m, v6Loopback, utc);
2633
2634 // Now the list is complete, set the McastTxRx setting for each interface.
2635 NetworkInterfaceInfoOSX *i;
2636 for (i = m->p->InterfaceList; i; i = i->next)
2637 if (i->Exists)
2638 {
2639 mDNSBool txrx = MulticastInterface(i);
2640 #if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
2641 txrx = txrx && ((i->ifinfo.ip.type == mDNSAddrType_IPv4) || !FindRoutableIPv4(m, i->scope_id));
2642 #endif
2643 if (i->ifinfo.McastTxRx != txrx)
2644 {
2645 i->ifinfo.McastTxRx = txrx;
2646 i->Exists = 2; // State change; need to deregister and reregister this interface
2647 }
2648 }
2649
2650 #ifndef NO_IPV6
2651 if (InfoSocket >= 0) close(InfoSocket);
2652 #endif
2653
2654 // If we haven't set up AutoTunnelHostAddr yet, do it now
2655 if (!mDNSSameEthAddress(&PrimaryMAC, &zeroEthAddr) && m->AutoTunnelHostAddr.b[0] == 0)
2656 {
2657 m->AutoTunnelHostAddr.b[0x0] = 0xFD; // Required prefix for "locally assigned" ULA (See RFC 4193)
2658 m->AutoTunnelHostAddr.b[0x1] = mDNSRandom(255);
2659 m->AutoTunnelHostAddr.b[0x2] = mDNSRandom(255);
2660 m->AutoTunnelHostAddr.b[0x3] = mDNSRandom(255);
2661 m->AutoTunnelHostAddr.b[0x4] = mDNSRandom(255);
2662 m->AutoTunnelHostAddr.b[0x5] = mDNSRandom(255);
2663 m->AutoTunnelHostAddr.b[0x6] = mDNSRandom(255);
2664 m->AutoTunnelHostAddr.b[0x7] = mDNSRandom(255);
2665 m->AutoTunnelHostAddr.b[0x8] = PrimaryMAC.b[0] ^ 0x02; // See RFC 3513, Appendix A for explanation
2666 m->AutoTunnelHostAddr.b[0x9] = PrimaryMAC.b[1];
2667 m->AutoTunnelHostAddr.b[0xA] = PrimaryMAC.b[2];
2668 m->AutoTunnelHostAddr.b[0xB] = 0xFF;
2669 m->AutoTunnelHostAddr.b[0xC] = 0xFE;
2670 m->AutoTunnelHostAddr.b[0xD] = PrimaryMAC.b[3];
2671 m->AutoTunnelHostAddr.b[0xE] = PrimaryMAC.b[4];
2672 m->AutoTunnelHostAddr.b[0xF] = PrimaryMAC.b[5];
2673 m->AutoTunnelLabel.c[0] = mDNS_snprintf((char*)m->AutoTunnelLabel.c+1, 254, "AutoTunnel-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X",
2674 m->AutoTunnelHostAddr.b[0x8], m->AutoTunnelHostAddr.b[0x9], m->AutoTunnelHostAddr.b[0xA], m->AutoTunnelHostAddr.b[0xB],
2675 m->AutoTunnelHostAddr.b[0xC], m->AutoTunnelHostAddr.b[0xD], m->AutoTunnelHostAddr.b[0xE], m->AutoTunnelHostAddr.b[0xF]);
2676 LogOperation("m->AutoTunnelLabel %#s", m->AutoTunnelLabel.c);
2677 }
2678
2679 #ifndef kDefaultLocalHostNamePrefix
2680 #define kDefaultLocalHostNamePrefix "Macintosh"
2681 #endif
2682 mDNS_snprintf(defaultname, sizeof(defaultname), kDefaultLocalHostNamePrefix "-%02X%02X%02X%02X%02X%02X",
2683 PrimaryMAC.b[0], PrimaryMAC.b[1], PrimaryMAC.b[2], PrimaryMAC.b[3], PrimaryMAC.b[4], PrimaryMAC.b[5]);
2684
2685 // Set up the nice label
2686 domainlabel nicelabel;
2687 nicelabel.c[0] = 0;
2688 GetUserSpecifiedFriendlyComputerName(&nicelabel);
2689 if (nicelabel.c[0] == 0)
2690 {
2691 LogMsg("Couldn't read user-specified Computer Name; using default “%s” instead", defaultname);
2692 MakeDomainLabelFromLiteralString(&nicelabel, defaultname);
2693 }
2694
2695 // Set up the RFC 1034-compliant label
2696 domainlabel hostlabel;
2697 hostlabel.c[0] = 0;
2698 GetUserSpecifiedLocalHostName(&hostlabel);
2699 if (hostlabel.c[0] == 0)
2700 {
2701 LogMsg("Couldn't read user-specified local hostname; using default “%s.local” instead", defaultname);
2702 MakeDomainLabelFromLiteralString(&hostlabel, defaultname);
2703 }
2704
2705 mDNSBool namechange = mDNSfalse;
2706
2707 // We use a case-sensitive comparison here because even though changing the capitalization
2708 // of the name alone is not significant to DNS, it's still a change from the user's point of view
2709 if (SameDomainLabelCS(m->p->usernicelabel.c, nicelabel.c))
2710 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m->p->usernicelabel.c, m->nicelabel.c);
2711 else
2712 {
2713 if (m->p->usernicelabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
2714 LogMsg("User updated Computer Name from %#s to %#s", m->p->usernicelabel.c, nicelabel.c);
2715 m->p->usernicelabel = m->nicelabel = nicelabel;
2716 namechange = mDNStrue;
2717 }
2718
2719 if (SameDomainLabelCS(m->p->userhostlabel.c, hostlabel.c))
2720 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m->p->userhostlabel.c, m->hostlabel.c);
2721 else
2722 {
2723 if (m->p->userhostlabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
2724 LogMsg("User updated Local Hostname from %#s to %#s", m->p->userhostlabel.c, hostlabel.c);
2725 m->p->userhostlabel = m->hostlabel = hostlabel;
2726 mDNS_SetFQDN(m);
2727 namechange = mDNStrue;
2728 }
2729
2730 #if APPLE_OSX_mDNSResponder
2731 if (namechange) // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records
2732 {
2733 DomainAuthInfo *info;
2734 for (info = m->AuthInfoList; info; info = info->next)
2735 if (info->AutoTunnelNAT.clientContext && !mDNSIPv4AddressIsOnes(info->AutoTunnelNAT.ExternalAddress))
2736 AutoTunnelNATCallback(m, &info->AutoTunnelNAT);
2737 }
2738 #endif
2739
2740 return(mStatus_NoError);
2741 }
2742
2743 #if LogAllOperations || MDNS_DEBUGMSGS
2744 // Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
2745 // Returns -1 if all the one-bits are not contiguous
2746 mDNSlocal int CountMaskBits(mDNSAddr *mask)
2747 {
2748 int i = 0, bits = 0;
2749 int bytes = mask->type == mDNSAddrType_IPv4 ? 4 : mask->type == mDNSAddrType_IPv6 ? 16 : 0;
2750 while (i < bytes)
2751 {
2752 mDNSu8 b = mask->ip.v6.b[i++];
2753 while (b & 0x80) { bits++; b <<= 1; }
2754 if (b) return(-1);
2755 }
2756 while (i < bytes) if (mask->ip.v6.b[i++]) return(-1);
2757 return(bits);
2758 }
2759 #endif
2760
2761 // returns count of non-link local V4 addresses registered
2762 mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
2763 {
2764 NetworkInterfaceInfoOSX *i;
2765 int count = 0;
2766 for (i = m->p->InterfaceList; i; i = i->next)
2767 if (i->Exists)
2768 {
2769 NetworkInterfaceInfo *const n = &i->ifinfo;
2770 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, AAAA_OVER_V4 ? AF_UNSPEC : i->sa_family);
2771 if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifa_name);
2772
2773 if (n->InterfaceID && n->InterfaceID != (mDNSInterfaceID)primary) // Sanity check
2774 {
2775 LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != primary %p", n->InterfaceID, primary);
2776 n->InterfaceID = mDNSNULL;
2777 }
2778
2779 if (!n->InterfaceID)
2780 {
2781 // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
2782 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
2783 // If n->InterfaceID is NOT set, then we haven't registered it and we should not try to deregister it
2784 n->InterfaceID = (mDNSInterfaceID)primary;
2785
2786 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
2787 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
2788 // If the interface is an old one that went away and came back in less than a minute, then we're in a flapping scenario.
2789 i->Occulting = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->LastSeen > 0 && utc - i->LastSeen < 60);
2790
2791 mDNS_RegisterInterface(m, n, i->Flashing && i->Occulting);
2792 if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++;
2793 LogOperation("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s",
2794 i->ifa_name, i->scope_id, &i->BSSID, primary, &n->ip, CountMaskBits(&n->mask),
2795 i->Flashing ? " (Flashing)" : "",
2796 i->Occulting ? " (Occulting)" : "",
2797 n->InterfaceActive ? " (Primary)" : "");
2798
2799 if (!n->McastTxRx)
2800 debugf("SetupActiveInterfaces: No Tx/Rx on %5s(%lu) %.6a InterfaceID %p %#a", i->ifa_name, i->scope_id, &i->BSSID, primary, &n->ip);
2801 else
2802 {
2803 if (i->sa_family == AF_INET)
2804 {
2805 struct ip_mreq imr;
2806 primary->ifa_v4addr.s_addr = i->ifinfo.ip.ip.v4.NotAnInteger;
2807 imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
2808 imr.imr_interface = primary->ifa_v4addr;
2809
2810 // If this is our *first* IPv4 instance for this interface name, we need to do a IP_DROP_MEMBERSHIP first,
2811 // before trying to join the group, to clear out stale kernel state which may be lingering.
2812 // In particular, this happens with removable network interfaces like USB Ethernet adapters -- the kernel has stale state
2813 // from the last time the USB Ethernet adapter was connected, and part of the kernel thinks we've already joined the group
2814 // on that interface (so we get EADDRINUSE when we try to join again) but a different part of the kernel thinks we haven't
2815 // joined the group (so we receive no multicasts). Doing an IP_DROP_MEMBERSHIP before joining seems to flush the stale state.
2816 // Also, trying to make the code leave the group when the adapter is removed doesn't work either,
2817 // because by the time we get the configuration change notification, the interface is already gone,
2818 // so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address").
2819 // <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
2820 if (SearchForInterfaceByName(m, i->ifa_name, AF_INET) == i)
2821 {
2822 LogOperation("SetupActiveInterfaces: %5s(%lu) Doing precautionary IP_DROP_MEMBERSHIP for %.4a on %.4a", i->ifa_name, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
2823 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(imr));
2824 if (err < 0 && (errno != EADDRNOTAVAIL || LogAllOperations))
2825 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %ld errno %d (%s)", err, errno, strerror(errno));
2826 }
2827
2828 LogOperation("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i->ifa_name, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
2829 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
2830 // Joining same group twice can give "Address already in use" error -- no need to report that
2831 if (err < 0 && (errno != EADDRINUSE || LogAllOperations))
2832 LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %ld errno %d (%s) group %.4a on %.4a", err, errno, strerror(errno), &imr.imr_multiaddr, &imr.imr_interface);
2833 }
2834 #ifndef NO_IPV6
2835 if (i->sa_family == AF_INET6)
2836 {
2837 struct ipv6_mreq i6mr;
2838 i6mr.ipv6mr_interface = primary->scope_id;
2839 i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
2840
2841 if (SearchForInterfaceByName(m, i->ifa_name, AF_INET6) == i)
2842 {
2843 LogOperation("SetupActiveInterfaces: %5s(%lu) Doing precautionary IPV6_LEAVE_GROUP for %.16a on %u", i->ifa_name, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
2844 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
2845 if (err < 0 && (errno != EADDRNOTAVAIL || LogAllOperations))
2846 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %ld errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
2847 }
2848
2849 LogOperation("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i->ifa_name, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
2850 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
2851 // Joining same group twice can give "Address already in use" error -- no need to report that
2852 if (err < 0 && (errno != EADDRINUSE || LogAllOperations))
2853 LogMsg("setsockopt - IPV6_JOIN_GROUP error %ld errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
2854 }
2855 #endif
2856 }
2857 }
2858 }
2859 return count;
2860 }
2861
2862 mDNSlocal void MarkAllInterfacesInactive(mDNS *const m, mDNSs32 utc)
2863 {
2864 NetworkInterfaceInfoOSX *i;
2865 for (i = m->p->InterfaceList; i; i = i->next)
2866 {
2867 if (i->Exists) i->LastSeen = utc;
2868 i->Exists = mDNSfalse;
2869 }
2870 }
2871
2872 // returns count of non-link local V4 addresses deregistered
2873 mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc)
2874 {
2875 // First pass:
2876 // If an interface is going away, then deregister this from the mDNSCore.
2877 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
2878 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
2879 // it refers to has gone away we'll crash.
2880 NetworkInterfaceInfoOSX *i;
2881 int count = 0;
2882 for (i = m->p->InterfaceList; i; i = i->next)
2883 {
2884 // If this interface is no longer active, or its InterfaceID is changing, deregister it
2885 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, AAAA_OVER_V4 ? AF_UNSPEC : i->sa_family);
2886 if (i->ifinfo.InterfaceID)
2887 if (i->Exists == 0 || i->Exists == 2 || i->ifinfo.InterfaceID != (mDNSInterfaceID)primary)
2888 {
2889 i->Flashing = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->AppearanceTime < 60);
2890 LogOperation("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s",
2891 i->ifa_name, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID,
2892 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask),
2893 i->Flashing ? " (Flashing)" : "",
2894 i->Occulting ? " (Occulting)" : "",
2895 i->ifinfo.InterfaceActive ? " (Primary)" : "");
2896 mDNS_DeregisterInterface(m, &i->ifinfo, i->Flashing && i->Occulting);
2897 if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++;
2898 i->ifinfo.InterfaceID = mDNSNULL;
2899 // NOTE: If i->ifinfo.InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
2900 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
2901 // If i->ifinfo.InterfaceID is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
2902
2903 // Caution: If we ever decide to add code here to leave the multicast group, we need to make sure that this
2904 // is the LAST representative of this physical interface, or we'll unsubscribe from the group prematurely.
2905 }
2906 }
2907
2908 // Second pass:
2909 // Now that everything that's going to deregister has done so, we can clean up and free the memory
2910 NetworkInterfaceInfoOSX **p = &m->p->InterfaceList;
2911 while (*p)
2912 {
2913 i = *p;
2914 // If no longer active, delete interface from list and free memory
2915 if (!i->Exists)
2916 {
2917 if (i->LastSeen == utc) i->LastSeen = utc - 1;
2918 mDNSBool delete = (NumCacheRecordsForInterfaceID(m, (mDNSInterfaceID)i) == 0) && (utc - i->LastSeen >= 60);
2919 LogOperation("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
2920 i->ifa_name, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID,
2921 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), utc - i->LastSeen,
2922 i->ifinfo.InterfaceActive ? " (Primary)" : "");
2923 if (delete)
2924 {
2925 *p = i->next;
2926 if (i->ifa_name) freeL("NetworkInterfaceInfoOSX name", i->ifa_name);
2927 freeL("NetworkInterfaceInfoOSX", i);
2928 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
2929 }
2930 }
2931 p = &i->next;
2932 }
2933 return count;
2934 }
2935
2936 mDNSlocal void AppendDNameListElem(DNameListElem ***List, mDNSu32 uid, domainname *name)
2937 {
2938 DNameListElem *dnle = (DNameListElem*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem));
2939 if (!dnle) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
2940 else
2941 {
2942 dnle->next = mDNSNULL;
2943 dnle->uid = uid;
2944 AssignDomainName(&dnle->name, name);
2945 **List = dnle;
2946 *List = &dnle->next;
2947 }
2948 }
2949
2950 mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains)
2951 {
2952 int i;
2953 char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
2954 domainname d;
2955
2956 // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
2957 if (fqdn) fqdn->c[0] = 0;
2958 if (RegDomains ) *RegDomains = NULL;
2959 if (BrowseDomains) *BrowseDomains = NULL;
2960
2961 LogOperation("mDNSPlatformSetDNSConfig%s%s%s%s%s",
2962 setservers ? " setservers" : "",
2963 setsearch ? " setsearch" : "",
2964 fqdn ? " fqdn" : "",
2965 RegDomains ? " RegDomains" : "",
2966 BrowseDomains ? " BrowseDomains" : "");
2967
2968 // Add the inferred address-based configuration discovery domains
2969 // (should really be in core code I think, not platform-specific)
2970 if (setsearch)
2971 {
2972 struct ifaddrs *ifa = myGetIfAddrs(1);
2973 while (ifa)
2974 {
2975 mDNSAddr a, n;
2976 if (ifa->ifa_addr->sa_family == AF_INET &&
2977 ifa->ifa_netmask &&
2978 !(ifa->ifa_flags & IFF_LOOPBACK) &&
2979 !SetupAddr(&a, ifa->ifa_addr) &&
2980 !SetupAddr(&n, ifa->ifa_netmask) &&
2981 !mDNSv4AddressIsLinkLocal(&a.ip.v4) )
2982 {
2983 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
2984 mDNS_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa.", a.ip.v4.b[3] & n.ip.v4.b[3],
2985 a.ip.v4.b[2] & n.ip.v4.b[2],
2986 a.ip.v4.b[1] & n.ip.v4.b[1],
2987 a.ip.v4.b[0] & n.ip.v4.b[0]);
2988 mDNS_AddSearchDomain_CString(buf);
2989 }
2990 ifa = ifa->ifa_next;
2991 }
2992 }
2993
2994 #ifndef MDNS_NO_DNSINFO
2995 if (setservers || setsearch)
2996 {
2997 dns_config_t *config = dns_configuration_copy();
2998 if (!config)
2999 {
3000 // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
3001 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
3002 // Apparently this is expected behaviour -- "not a bug".
3003 // Accordingly, we suppress syslog messages for the first three minutes after boot.
3004 // If we are still getting failures after three minutes, then we log them.
3005 if (mDNSMacOSXSystemBuildNumber(NULL) > 7 && (mDNSu32)mDNSPlatformRawTime() > (mDNSu32)(mDNSPlatformOneSecond * 180))
3006 LogMsg("GetDNSConfig: Error: dns_configuration_copy returned NULL");
3007 }
3008 else
3009 {
3010 LogOperation("mDNSPlatformSetDNSConfig: config->n_resolver = %d", config->n_resolver);
3011 if (setservers)
3012 {
3013 for (i = 0; i < config->n_resolver; i++)
3014 {
3015 int j, n;
3016 dns_resolver_t *r = config->resolver[i];
3017 // Ignore dnsinfo entries for mDNS domains (indicated by the fact that the resolver port is 5353, the mDNS port)
3018 // Note: Unlike the BSD Sockets APIs (where TCP and UDP port numbers are universally in network byte order)
3019 // in Apple's "dnsinfo.h" API the port number is declared to be a "uint16_t in host byte order"
3020 if (r->port == 5353) continue;
3021 if (r->search_order == DEFAULT_SEARCH_ORDER || !r->domain || !*r->domain) d.c[0] = 0; // we ignore domain for "default" resolver
3022 else if (!MakeDomainNameFromDNSNameString(&d, r->domain)) { LogMsg("RegisterSplitDNS: bad domain %s", r->domain); continue; }
3023
3024 for (j = 0; j < config->n_resolver; j++) // check if this is the lowest-weighted server for the domain
3025 {
3026 dns_resolver_t *p = config->resolver[j];
3027 if (p->port == 5353) continue; // Note: dns_resolver_t port is defined to be "uint16_t in host byte order"
3028 if (p->search_order <= r->search_order)
3029 {
3030 domainname tmp;
3031 if (p->search_order == DEFAULT_SEARCH_ORDER || !p->domain || !*p->domain) tmp.c[0] = '\0';
3032 else if (!MakeDomainNameFromDNSNameString(&tmp, p->domain)) { LogMsg("RegisterSplitDNS: bad domain %s", p->domain); continue; }
3033 if (SameDomainName(&d, &tmp))
3034 if (p->search_order < r->search_order || j < i) break; // if equal weights, pick first in list, otherwise pick lower-weight (p)
3035 }
3036 }
3037 if (j < config->n_resolver) // found a lower-weighted resolver for this domain
3038 debugf("Rejecting DNS server in slot %d domain %##s (slot %d outranks)", i, d.c, j);
3039 else
3040 {
3041 mDNSInterfaceID interface = mDNSInterface_Any;
3042 int disabled = 0;
3043
3044 // DNS server option parsing
3045 if (r->options != NULL)
3046 {
3047 char *nextOption = r->options;
3048 char *currentOption = NULL;
3049 while ((currentOption = strsep(&nextOption, " ")) != NULL && currentOption[0] != 0)
3050 {
3051 // The option may be in the form of interface=xxx where xxx is an interface name.
3052 if (strncmp(currentOption, kInterfaceSpecificOption, sizeof(kInterfaceSpecificOption) - 1) == 0)
3053 {
3054 NetworkInterfaceInfoOSX *ni;
3055 char ifname[IF_NAMESIZE+1];
3056 mDNSu32 ifindex = 0;
3057 // If something goes wrong finding the interface, create the server entry anyhow but mark it as disabled.
3058 // This allows us to block these special queries from going out on the wire.
3059 strlcpy(ifname, currentOption + sizeof(kInterfaceSpecificOption)-1, sizeof(ifname));
3060 ifindex = if_nametoindex(ifname);
3061 if (ifindex == 0) { disabled = 1; LogMsg("RegisterSplitDNS: interfaceSpecific - interface %s not found", ifname); continue; }
3062 LogOperation("%s: Interface-specific entry: %s on %s (%d)", __FUNCTION__, r->domain, ifname, ifindex);
3063 // Find the interface, can't use mDNSPlatformInterfaceIDFromInterfaceIndex
3064 // because that will call mDNSMacOSXNetworkChanged if the interface doesn't exist
3065 for (ni = m->p->InterfaceList; ni; ni = ni->next)
3066 if (ni->ifinfo.InterfaceID && ni->scope_id == ifindex) break;
3067 if (ni != NULL) interface = ni->ifinfo.InterfaceID;
3068 if (interface == mDNSNULL) { disabled = 1; LogMsg("RegisterSplitDNS: interfaceSpecific - index %d (%s) not found", ifindex, ifname); continue; }
3069 }
3070 }
3071 }
3072 for (n = 0; n < r->n_nameserver; n++)
3073 if (r->nameserver[n]->sa_family == AF_INET && (interface || disabled || !AddrRequiresPPPConnection(r->nameserver[n])))
3074 {
3075 mDNSAddr saddr;
3076 // mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 192, 168, 1, 1 } } } }; // for testing
3077 debugf("Adding dns server from slot %d %#a for domain %##s", i, &saddr, d.c);
3078 if (SetupAddr(&saddr, r->nameserver[n])) LogMsg("RegisterSplitDNS: bad IP address");
3079 else
3080 {
3081 DNSServer *s = mDNS_AddDNSServer(m, &d, interface, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort);
3082 if (s && disabled) s->teststate = DNSServer_Disabled;
3083 }
3084 }
3085 }
3086 }
3087 }
3088 if (setsearch)
3089 {
3090 // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
3091 // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
3092 // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
3093 // instead use the search domain list as the sole authority for what domains to search and in what order
3094 // (and the domain from the "domain" field will also appear somewhere in that list).
3095 // Also, all search domains get added to the search list for resolver[0], so the domains and/or
3096 // search lists for other resolvers in the list need to be ignored.
3097 if (config->resolver[0]->n_search == 0) mDNS_AddSearchDomain_CString(config->resolver[0]->domain);
3098 else for (i = 0; i < config->resolver[0]->n_search; i++) mDNS_AddSearchDomain_CString(config->resolver[0]->search[i]);
3099 }
3100 dns_configuration_free(config);
3101 setservers = mDNSfalse; // Done these now -- no need to fetch the same data from SCDynamicStore
3102 setsearch = mDNSfalse;
3103 }
3104 }
3105 #endif // MDNS_NO_DNSINFO
3106
3107 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformSetDNSConfig"), NULL, NULL);
3108 if (store)
3109 {
3110 CFDictionaryRef ddnsdict = SCDynamicStoreCopyValue(store, NetworkChangedKey_DynamicDNS);
3111 if (ddnsdict)
3112 {
3113 if (fqdn)
3114 {
3115 CFArrayRef fqdnArray = CFDictionaryGetValue(ddnsdict, CFSTR("HostNames"));
3116 if (fqdnArray && CFArrayGetCount(fqdnArray) > 0)
3117 {
3118 // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
3119 CFDictionaryRef fqdnDict = CFArrayGetValueAtIndex(fqdnArray, 0);
3120 if (fqdnDict && DDNSSettingEnabled(fqdnDict))
3121 {
3122 CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain"));
3123 if (name)
3124 {
3125 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
3126 !MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0])
3127 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)");
3128 else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf);
3129 }
3130 }
3131 }
3132 }
3133
3134 if (RegDomains)
3135 {
3136 CFArrayRef regArray = CFDictionaryGetValue(ddnsdict, CFSTR("RegistrationDomains"));
3137 if (regArray && CFArrayGetCount(regArray) > 0)
3138 {
3139 CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0);
3140 if (regDict && DDNSSettingEnabled(regDict))
3141 {
3142 CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain"));
3143 if (name)
3144 {
3145 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
3146 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
3147 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)");
3148 else
3149 {
3150 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf);
3151 AppendDNameListElem(&RegDomains, 0, &d);
3152 }
3153 }
3154 }
3155 }
3156 }
3157
3158 if (BrowseDomains)
3159 {
3160 CFArrayRef browseArray = CFDictionaryGetValue(ddnsdict, CFSTR("BrowseDomains"));
3161 if (browseArray)
3162 {
3163 for (i = 0; i < CFArrayGetCount(browseArray); i++)
3164 {
3165 CFDictionaryRef browseDict = CFArrayGetValueAtIndex(browseArray, i);
3166 if (browseDict && DDNSSettingEnabled(browseDict))
3167 {
3168 CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain"));
3169 if (name)
3170 {
3171 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
3172 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
3173 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf[0] ? buf : "(unknown)");
3174 else
3175 {
3176 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf);
3177 AppendDNameListElem(&BrowseDomains, 0, &d);
3178 }
3179 }
3180 }
3181 }
3182 }
3183 }
3184 CFRelease(ddnsdict);
3185 }
3186
3187 if (RegDomains)
3188 {
3189 CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
3190 if (btmm)
3191 {
3192 CFIndex size = CFDictionaryGetCount(btmm);
3193 const void *key[size];
3194 const void *val[size];
3195 CFDictionaryGetKeysAndValues(btmm, key, val);
3196 for (i = 0; i < size; i++)
3197 {
3198 LogOperation("BackToMyMac %d", i);
3199 if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
3200 LogMsg("Can't read BackToMyMac %d key %s", i, buf);
3201 else
3202 {
3203 mDNSu32 uid = atoi(buf);
3204 if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
3205 LogMsg("Can't read BackToMyMac %d val %s", i, buf);
3206 else if (MakeDomainNameFromDNSNameString(&d, buf) && d.c[0])
3207 {
3208 LogOperation("BackToMyMac %d %d %##s", i, uid, d.c);
3209 AppendDNameListElem(&RegDomains, uid, &d);
3210 }
3211 }
3212 }
3213 CFRelease(btmm);
3214 }
3215 }
3216
3217 if (setservers || setsearch)
3218 {
3219 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_DNS);
3220 if (dict)
3221 {
3222 if (setservers)
3223 {
3224 CFArrayRef values = CFDictionaryGetValue(dict, kSCPropNetDNSServerAddresses);
3225 if (values)
3226 {
3227 for (i = 0; i < CFArrayGetCount(values); i++)
3228 {
3229 CFStringRef s = CFArrayGetValueAtIndex(values, i);
3230 mDNSAddr addr = { mDNSAddrType_IPv4, { { { 0 } } } };
3231 if (s && CFStringGetCString(s, buf, 256, kCFStringEncodingUTF8) &&
3232 inet_aton(buf, (struct in_addr *) &addr.ip.v4))
3233 mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, &addr, UnicastDNSPort);
3234 }
3235 }
3236 }
3237 if (setsearch)
3238 {
3239 // Add the manual and/or DHCP-dicovered search domains
3240 CFArrayRef searchDomains = CFDictionaryGetValue(dict, kSCPropNetDNSSearchDomains);
3241 if (searchDomains)
3242 {
3243 for (i = 0; i < CFArrayGetCount(searchDomains); i++)
3244 {
3245 CFStringRef s = CFArrayGetValueAtIndex(searchDomains, i);
3246 if (s && CFStringGetCString(s, buf, sizeof(buf), kCFStringEncodingUTF8))
3247 mDNS_AddSearchDomain_CString(buf);
3248 }
3249 }
3250 else // No kSCPropNetDNSSearchDomains, so use kSCPropNetDNSDomainName
3251 {
3252 // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
3253 // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
3254 // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
3255 // instead use the search domain list as the sole authority for what domains to search and in what order
3256 // (and the domain from the "domain" field will also appear somewhere in that list).
3257 CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetDNSDomainName);
3258 if (string && CFStringGetCString(string, buf, sizeof(buf), kCFStringEncodingUTF8))
3259 mDNS_AddSearchDomain_CString(buf);
3260 }
3261 }
3262 CFRelease(dict);
3263 }
3264 }
3265 CFRelease(store);
3266 }
3267 }
3268
3269 mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *r)
3270 {
3271 char buf[256];
3272 mStatus err = 0;
3273 (void)m; // Unused
3274
3275 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL, NULL);
3276 if (!store) LogMsg("mDNSPlatformGetPrimaryInterface: SCDynamicStoreCreate failed");
3277 else
3278 {
3279 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_IPv4);
3280 if (dict)
3281 {
3282 r->type = mDNSAddrType_IPv4;
3283 r->ip.v4 = zerov4Addr;
3284 CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
3285 if (string)
3286 {
3287 if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8))
3288 LogMsg("Could not convert router to CString");
3289 else
3290 {
3291 struct sockaddr_in saddr;
3292 saddr.sin_len = sizeof(saddr);
3293 saddr.sin_family = AF_INET;
3294 saddr.sin_port = 0;
3295 inet_aton(buf, &saddr.sin_addr);
3296
3297 if (AddrRequiresPPPConnection((struct sockaddr *)&saddr)) debugf("Ignoring router %s (requires PPP connection)", buf);
3298 else *(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr;
3299 }
3300 }
3301
3302 string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
3303 if (string)
3304 {
3305 mDNSBool HavePrimaryGlobalv6 = mDNSfalse; // does the primary interface have a global v6 address?
3306 struct ifaddrs *ifa = myGetIfAddrs(1);
3307
3308 *v4 = *v6 = zeroAddr;
3309
3310 if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8)) { LogMsg("Could not convert router to CString"); goto exit; }
3311
3312 // find primary interface in list
3313 while (ifa && (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4) || !HavePrimaryGlobalv6))
3314 {
3315 mDNSAddr tmp6 = zeroAddr;
3316 if (!strcmp(buf, ifa->ifa_name))
3317 {
3318 if (ifa->ifa_addr->sa_family == AF_INET)
3319 {
3320 if (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4)) SetupAddr(v4, ifa->ifa_addr);
3321 }
3322 else if (ifa->ifa_addr->sa_family == AF_INET6)
3323 {
3324 SetupAddr(&tmp6, ifa->ifa_addr);
3325 if (tmp6.ip.v6.b[0] >> 5 == 1) // global prefix: 001
3326 { HavePrimaryGlobalv6 = mDNStrue; *v6 = tmp6; }
3327 }
3328 }
3329 else
3330 {
3331 // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
3332 if (!HavePrimaryGlobalv6 && ifa->ifa_addr->sa_family == AF_INET6 && !v6->ip.v6.b[0])
3333 {
3334 SetupAddr(&tmp6, ifa->ifa_addr);
3335 if (tmp6.ip.v6.b[0] >> 5 == 1) *v6 = tmp6;
3336 }
3337 }
3338 ifa = ifa->ifa_next;
3339 }
3340
3341 // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
3342 // V4 to communicate w/ our DNS server
3343 }
3344
3345 exit:
3346 CFRelease(dict);
3347 }
3348 CFRelease(store);
3349 }
3350 return err;
3351 }
3352
3353 mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
3354 {
3355 LogOperation("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status, dname->c);
3356 char uname[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
3357 ConvertDomainNameToCString(dname, uname);
3358
3359 char *p = uname;
3360 while (*p)
3361 {
3362 *p = tolower(*p);
3363 if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
3364 p++;
3365 }
3366
3367 // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
3368 // That single entity is a CFDictionary with name "HostNames".
3369 // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
3370 // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
3371 // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
3372 // The CFDictionary for each FQDN holds (at present) a single name/value pair,
3373 // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
3374
3375 const CFStringRef StateKeys [1] = { CFSTR("HostNames") };
3376 const CFStringRef HostKeys [1] = { CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8) };
3377 const CFStringRef StatusKeys[1] = { CFSTR("Status") };
3378 if (!HostKeys[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname);
3379 else
3380 {
3381 const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) };
3382 if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%ld) failed", status);
3383 else
3384 {
3385 const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, NULL, NULL) };
3386 if (HostVals[0])
3387 {
3388 const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, NULL, NULL) };
3389 if (StateVals[0])
3390 {
3391 CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, NULL, NULL);
3392 if (StateDict)
3393 {
3394 mDNSDynamicStoreSetConfig(kmDNSDynamicConfig, StateDict);
3395 CFRelease(StateDict);
3396 }
3397 CFRelease(StateVals[0]);
3398 }
3399 CFRelease(HostVals[0]);
3400 }
3401 CFRelease(StatusVals[0]);
3402 }
3403 CFRelease(HostKeys[0]);
3404 }
3405 }
3406
3407 // MUST be called holding the lock -- this routine calls SetupLocalAutoTunnelInterface_internal()
3408 mDNSexport void SetDomainSecrets(mDNS *m)
3409 {
3410 #ifdef NO_SECURITYFRAMEWORK
3411 (void)m;
3412 LogMsg("Note: SetDomainSecrets: no keychain support");
3413 #else
3414 mDNSBool haveAutoTunnels = mDNSfalse;
3415
3416 LogOperation("SetDomainSecrets");
3417
3418 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
3419 // In the case where the user simultaneously removes their DDNS host name and the key
3420 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
3421 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
3422 // address records behind that we no longer have permission to delete.
3423 DomainAuthInfo *ptr;
3424 for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
3425 ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10);
3426
3427 #if APPLE_OSX_mDNSResponder
3428 {
3429 // Mark all TunnelClients for deletion
3430 ClientTunnel *client;
3431 for (client = m->TunnelClients; client; client = client->next)
3432 {
3433 LogOperation("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c);
3434 client->MarkedForDeletion = mDNStrue;
3435 }
3436 }
3437 #endif APPLE_OSX_mDNSResponder
3438
3439 // String Array used to write list of private domains to Dynamic Store
3440 CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
3441 if (!sa) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
3442 CFIndex i;
3443 CFDataRef data = NULL;
3444 const int itemsPerEntry = 3; // domain name, key name, key value
3445 CFArrayRef secrets = NULL;
3446 int err = mDNSKeychainGetSecrets(&secrets);
3447 if (err || !secrets)
3448 LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err, secrets);
3449 else
3450 {
3451 CFIndex ArrayCount = CFArrayGetCount(secrets);
3452 // Iterate through the secrets
3453 for (i = 0; i < ArrayCount; ++i)
3454 {
3455 int j;
3456 CFArrayRef entry = CFArrayGetValueAtIndex(secrets, i);
3457 if (CFArrayGetTypeID() != CFGetTypeID(entry) || itemsPerEntry != CFArrayGetCount(entry))
3458 { LogMsg("SetDomainSecrets: malformed entry"); continue; }
3459 for (j = 0; j < CFArrayGetCount(entry); ++j)
3460 if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry, j)))
3461 { LogMsg("SetDomainSecrets: malformed entry item"); continue; }
3462
3463 // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
3464
3465 // Get DNS domain this key is for
3466 char stringbuf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal domainname as C-string, including terminating NUL
3467 data = CFArrayGetValueAtIndex(entry, 0);
3468 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
3469 { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data)); continue; }
3470 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
3471 stringbuf[CFDataGetLength(data)] = '\0';
3472
3473 domainname domain;
3474 if (!MakeDomainNameFromDNSNameString(&domain, stringbuf)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf); continue; }
3475
3476 // Get key name
3477 data = CFArrayGetValueAtIndex(entry, 1);
3478 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
3479 { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data)); continue; }
3480 CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)stringbuf);
3481 stringbuf[CFDataGetLength(data)] = '\0';
3482
3483 domainname keyname;
3484 if (!MakeDomainNameFromDNSNameString(&keyname, stringbuf)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf); continue; }
3485
3486 // Get key data
3487 data = CFArrayGetValueAtIndex(entry, 2);
3488 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
3489 { LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data)); continue; }
3490 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
3491 stringbuf[CFDataGetLength(data)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key
3492
3493 DomainAuthInfo *FoundInList;
3494 for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
3495 if (SameDomainName(&FoundInList->domain, &domain)) break;
3496
3497 #if APPLE_OSX_mDNSResponder
3498 if (FoundInList)
3499 {
3500 // If any client tunnel destination is in this domain, set deletion flag to false
3501 ClientTunnel *client;
3502 for (client = m->TunnelClients; client; client = client->next)
3503 if (FoundInList == GetAuthInfoForName_internal(m, &client->dstname))
3504 {
3505 LogOperation("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client->dstname.c);
3506 client->MarkedForDeletion = mDNSfalse;
3507 // If the key has changed, reconfigure the tunnel
3508 if (strncmp(stringbuf, client->b64keydata, sizeof(client->b64keydata)))
3509 {
3510 mDNSBool queryNotInProgress = client->q.ThisQInterval < 0;
3511 LogOperation("SetDomainSecrets: secret changed for tunnel %##s %s", client->dstname.c, queryNotInProgress ? "reconfiguring" : "query in progress");
3512 if (queryNotInProgress) AutoTunnelSetKeys(client, mDNSfalse);
3513 mDNS_snprintf(client->b64keydata, sizeof(client->b64keydata), "%s", stringbuf);
3514 if (queryNotInProgress) AutoTunnelSetKeys(client, mDNStrue);
3515 }
3516 }
3517 }
3518
3519 mDNSBool keyChanged = FoundInList && FoundInList->AutoTunnel ? strncmp(stringbuf, FoundInList->b64keydata, sizeof(FoundInList->b64keydata)) : mDNSfalse;
3520
3521 #endif APPLE_OSX_mDNSResponder
3522
3523 // Uncomment the line below to view the keys as they're read out of the system keychain
3524 // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
3525 //LogOperation("SetDomainSecrets: %##s %##s %s", &domain.c, &keyname.c, stringbuf);
3526
3527 // If didn't find desired domain in the list, make a new entry
3528 ptr = FoundInList;
3529 if (FoundInList && FoundInList->AutoTunnel && haveAutoTunnels == mDNSfalse) haveAutoTunnels = mDNStrue;
3530 if (!FoundInList)
3531 {
3532 ptr = (DomainAuthInfo*)mallocL("DomainAuthInfo", sizeof(*ptr));
3533 if (!ptr) { LogMsg("SetDomainSecrets: No memory"); continue; }
3534 }
3535
3536 LogOperation("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain);
3537 if (mDNS_SetSecretForDomain(m, ptr, &domain, &keyname, stringbuf, IsTunnelModeDomain(&domain)) == mStatus_BadParamErr)
3538 {
3539 if (!FoundInList) mDNSPlatformMemFree(ptr); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
3540 continue;
3541 }
3542
3543 #if APPLE_OSX_mDNSResponder
3544 if (keyChanged && AnonymousRacoonConfig)
3545 {
3546 LogOperation("SetDomainSecrets: secret changed for %##s", &domain);
3547 (void)mDNSConfigureServer(kmDNSUp, stringbuf);
3548 }
3549 #endif APPLE_OSX_mDNSResponder
3550
3551 ConvertDomainNameToCString(&domain, stringbuf);
3552 CFStringRef cfs = CFStringCreateWithCString(NULL, stringbuf, kCFStringEncodingUTF8);
3553 if (cfs) { CFArrayAppendValue(sa, cfs); CFRelease(cfs); }
3554 }
3555 CFRelease(secrets);
3556 }
3557 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, sa);
3558 CFRelease(sa);
3559
3560 #if APPLE_OSX_mDNSResponder
3561 {
3562 // clean up ClientTunnels
3563 ClientTunnel **pp = &m->TunnelClients;
3564 while (*pp)
3565 {
3566 if ((*pp)->MarkedForDeletion)
3567 {
3568 ClientTunnel *cur = *pp;
3569 LogOperation("SetDomainSecrets: removing client %p %##s from list", cur, cur->dstname.c);
3570 if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
3571 AutoTunnelSetKeys(cur, mDNSfalse);
3572 *pp = cur->next;
3573 freeL("ClientTunnel", cur);
3574 }
3575 else
3576 pp = &(*pp)->next;
3577 }
3578
3579 DomainAuthInfo *info = m->AuthInfoList;
3580 while (info)
3581 {
3582 if (info->AutoTunnel && info->deltime && info->AutoTunnelNAT.clientContext)
3583 {
3584 // stop the NAT operation
3585 mDNS_StopNATOperation_internal(m, &info->AutoTunnelNAT);
3586 if (info->AutoTunnelNAT.clientCallback)
3587 {
3588 // Reset port and let the AutoTunnelNATCallback handle cleanup
3589 info->AutoTunnelNAT.ExternalAddress = m->ExternalAddress;
3590 info->AutoTunnelNAT.ExternalPort = zeroIPPort;
3591 info->AutoTunnelNAT.Lifetime = 0;
3592 info->AutoTunnelNAT.Result = mStatus_NoError;
3593 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
3594 info->AutoTunnelNAT.clientCallback(m, &info->AutoTunnelNAT);
3595 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
3596 }
3597 info->AutoTunnelNAT.clientContext = mDNSNULL;
3598 }
3599 info = info->next;
3600 }
3601
3602 if (!haveAutoTunnels && !m->TunnelClients && m->AutoTunnelHostAddrActive)
3603 {
3604 // remove interface if no autotunnel servers and no more client tunnels
3605 LogOperation("SetDomainSecrets: Bringing tunnel interface DOWN");
3606 m->AutoTunnelHostAddrActive = mDNSfalse;
3607 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown, m->AutoTunnelHostAddr.b);
3608 memset(m->AutoTunnelHostAddr.b, 0, sizeof(m->AutoTunnelHostAddr.b));
3609 }
3610
3611 if (!haveAutoTunnels && AnonymousRacoonConfig)
3612 {
3613 LogMsg("SetDomainSecrets: Resetting AnonymousRacoonConfig to false");
3614 AnonymousRacoonConfig = mDNSfalse;
3615 (void)mDNSConfigureServer(kmDNSDown, "");
3616 }
3617
3618 if (m->AutoTunnelHostAddr.b[0])
3619 if (TunnelClients(m) || TunnelServers(m))
3620 SetupLocalAutoTunnelInterface_internal(m);
3621 }
3622 #endif APPLE_OSX_mDNSResponder
3623
3624 #endif /* NO_SECURITYFRAMEWORK */
3625 }
3626
3627 mDNSlocal void SetLocalDomains(void)
3628 {
3629 CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
3630 if (!sa) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
3631
3632 CFArrayAppendValue(sa, CFSTR("local"));
3633 CFArrayAppendValue(sa, CFSTR("254.169.in-addr.arpa"));
3634 CFArrayAppendValue(sa, CFSTR("8.e.f.ip6.arpa"));
3635 CFArrayAppendValue(sa, CFSTR("9.e.f.ip6.arpa"));
3636 CFArrayAppendValue(sa, CFSTR("a.e.f.ip6.arpa"));
3637 CFArrayAppendValue(sa, CFSTR("b.e.f.ip6.arpa"));
3638
3639 mDNSDynamicStoreSetConfig(kmDNSMulticastConfig, sa);
3640 CFRelease(sa);
3641 }
3642
3643 mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
3644 {
3645 LogOperation("*** Network Configuration Change *** (%d)%s",
3646 m->p->NetworkChanged ? mDNS_TimeNow(m) - m->p->NetworkChanged : 0,
3647 m->p->NetworkChanged ? "" : " (no scheduled configuration change)");
3648 m->p->NetworkChanged = 0; // If we received a network change event and deferred processing, we're now dealing with it
3649 mDNSs32 utc = mDNSPlatformUTC();
3650 MarkAllInterfacesInactive(m, utc);
3651 UpdateInterfaceList(m, utc);
3652 ClearInactiveInterfaces(m, utc);
3653 SetupActiveInterfaces(m, utc);
3654
3655 #if APPLE_OSX_mDNSResponder
3656 {
3657 if (m->AutoTunnelHostAddr.b[0])
3658 {
3659 mDNS_Lock(m);
3660 if (TunnelClients(m) || TunnelServers(m))
3661 SetupLocalAutoTunnelInterface_internal(m);
3662 mDNS_Unlock(m);
3663 }
3664
3665 // Scan to find client tunnels whose questions have completed,
3666 // but whose local inner/outer addresses have changed since the tunnel was set up
3667 ClientTunnel *p;
3668 for (p = m->TunnelClients; p; p = p->next)
3669 if (p->q.ThisQInterval < 0)
3670 {
3671 mDNSAddr tmpSrc = zeroAddr;
3672 mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
3673 tmpDst.ip.v4 = p->rmt_outer;
3674 mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
3675 if (!mDNSSameIPv6Address(p->loc_inner, m->AutoTunnelHostAddr) ||
3676 !mDNSSameIPv4Address(p->loc_outer, tmpSrc.ip.v4))
3677 {
3678 AutoTunnelSetKeys(p, mDNSfalse);
3679 p->loc_inner = m->AutoTunnelHostAddr;
3680 p->loc_outer = tmpSrc.ip.v4;
3681 AutoTunnelSetKeys(p, mDNStrue);
3682 }
3683 }
3684 }
3685 #endif APPLE_OSX_mDNSResponder
3686
3687 uDNS_SetupDNSConfig(m);
3688
3689 if (m->MainCallback)
3690 m->MainCallback(m, mStatus_ConfigChanged);
3691 }
3692
3693 mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
3694 {
3695 (void)store; // Parameter not used
3696 (void)changedKeys; // Parameter not used
3697 mDNS *const m = (mDNS *const)context;
3698 KQueueLock(m);
3699 mDNS_Lock(m);
3700
3701 mDNSs32 delay = mDNSPlatformOneSecond; // Start off assuming a one-second delay
3702
3703 int c = CFArrayGetCount(changedKeys); // Count changes
3704 CFRange range = { 0, c };
3705 int c1 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Hostnames ) != 0);
3706 int c2 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Computername) != 0);
3707 int c3 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DynamicDNS ) != 0);
3708 if (c && c - c1 - c2 - c3 == 0) delay = mDNSPlatformOneSecond/20; // If these were the only changes, shorten delay
3709
3710 #if LogAllOperations
3711 int i;
3712 for (i=0; i<c; i++)
3713 {
3714 char buf[256];
3715 if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys, i), buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
3716 LogOperation("*** NetworkChanged SC key: %s", buf);
3717 }
3718 LogOperation("*** NetworkChanged *** %d change%s %s%s%sdelay %d",
3719 c, c>1?"s":"",
3720 c1 ? "(Local Hostname) " : "",
3721 c2 ? "(Computer Name) " : "",
3722 c3 ? "(DynamicDNS) " : "",
3723 delay);
3724 #endif
3725
3726 if (!m->p->NetworkChanged ||
3727 m->p->NetworkChanged - NonZeroTime(m->timenow + delay) < 0)
3728 m->p->NetworkChanged = NonZeroTime(m->timenow + delay);
3729
3730 // If we have a global DNS change, then disregard delay and reconfigure immediately
3731 if (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DNS) != 0) m->p->NetworkChanged = NonZeroTime(m->timenow);
3732
3733 // KeyChain frequently fails to notify clients of change events. To work around this
3734 // we set a timer and periodically poll to detect if any changes have occurred.
3735 // Without this Back To My Mac just does't work for a large number of users.
3736 // See <rdar://problem/5124399> Not getting Keychain Changed events when enabling BTMM
3737 if (c3 || CFArrayContainsValue(changedKeys, range, NetworkChangedKey_BackToMyMac))
3738 {
3739 LogOperation("*** NetworkChanged *** starting KeyChainBugTimer");
3740 m->p->KeyChainBugTimer = NonZeroTime(m->timenow + delay);
3741 m->p->KeyChainBugInterval = mDNSPlatformOneSecond;
3742 }
3743
3744 if (!m->SuppressSending ||
3745 m->SuppressSending - m->p->NetworkChanged < 0)
3746 m->SuppressSending = m->p->NetworkChanged;
3747
3748 mDNS_Unlock(m);
3749 KQueueUnlock(m, "NetworkChanged");
3750 }
3751
3752 mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
3753 {
3754 mStatus err = -1;
3755 SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
3756 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged, &context);
3757 CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
3758 CFStringRef pattern1 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
3759 CFStringRef pattern2 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
3760 CFMutableArrayRef patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
3761
3762 if (!store) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error; }
3763 if (!keys || !pattern1 || !pattern2 || !patterns) goto error;
3764
3765 CFArrayAppendValue(keys, NetworkChangedKey_IPv4);
3766 CFArrayAppendValue(keys, NetworkChangedKey_IPv6);
3767 CFArrayAppendValue(keys, NetworkChangedKey_Hostnames);
3768 CFArrayAppendValue(keys, NetworkChangedKey_Computername);
3769 CFArrayAppendValue(keys, NetworkChangedKey_DNS);
3770 CFArrayAppendValue(keys, NetworkChangedKey_DynamicDNS);
3771 CFArrayAppendValue(keys, NetworkChangedKey_BackToMyMac);
3772 CFArrayAppendValue(patterns, pattern1);
3773 CFArrayAppendValue(patterns, pattern2);
3774 CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
3775 if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns))
3776 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error; }
3777
3778 m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
3779 if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
3780
3781 CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
3782 m->p->Store = store;
3783 err = 0;
3784 goto exit;
3785
3786 error:
3787 if (store) CFRelease(store);
3788
3789 exit:
3790 if (patterns) CFRelease(patterns);
3791 if (pattern2) CFRelease(pattern2);
3792 if (pattern1) CFRelease(pattern1);
3793 if (keys) CFRelease(keys);
3794
3795 return(err);
3796 }
3797
3798 #ifndef NO_SECURITYFRAMEWORK
3799 mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCallbackInfo *info, void *context)
3800 {
3801 LogOperation("*** Keychain Changed ***");
3802 mDNS *const m = (mDNS *const)context;
3803 SecKeychainRef skc;
3804 OSStatus err = SecKeychainCopyDefault(&skc);
3805 if (!err)
3806 {
3807 if (info->keychain == skc)
3808 {
3809 // For delete events, attempt to verify what item was deleted fail because the item is already gone, so we just assume they may be relevant
3810 mDNSBool relevant = (keychainEvent == kSecDeleteEvent);
3811 if (!relevant)
3812 {
3813 UInt32 tags[3] = { kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr };
3814 SecKeychainAttributeInfo attrInfo = { 3, tags, NULL }; // Count, array of tags, array of formats
3815 SecKeychainAttributeList *a = NULL;
3816 err = SecKeychainItemCopyAttributesAndData(info->item, &attrInfo, NULL, &a, NULL, NULL);
3817 if (!err)
3818 {
3819 relevant = ((a->attr[0].length == 4 && (!strncasecmp(a->attr[0].data, "ddns", 4) || !strncasecmp(a->attr[0].data, "sndd", 4))) ||
3820 (a->attr[1].length >= 4 && (!strncasecmp(a->attr[1].data, "dns:", 4))));
3821 SecKeychainItemFreeAttributesAndData(a, NULL);
3822 }
3823 }
3824 if (relevant)
3825 {
3826 LogMsg("*** Keychain Changed *** KeychainEvent=%d %s",
3827 keychainEvent,
3828 keychainEvent == kSecAddEvent ? "kSecAddEvent" :
3829 keychainEvent == kSecDeleteEvent ? "kSecDeleteEvent" :
3830 keychainEvent == kSecUpdateEvent ? "kSecUpdateEvent" : "<Unknown>");
3831 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
3832 KQueueLock(m);
3833 mDNS_Lock(m);
3834 SetDomainSecrets(m);
3835 mDNS_Unlock(m);
3836 KQueueUnlock(m, "KeychainChanged");
3837 }
3838 }
3839 CFRelease(skc);
3840 }
3841
3842 return 0;
3843 }
3844 #endif
3845
3846 #ifndef NO_IOPOWER
3847 mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
3848 {
3849 mDNS *const m = (mDNS *const)refcon;
3850 KQueueLock(m);
3851 (void)service; // Parameter not used
3852 LogOperation("PowerChanged %X %lX", messageType, messageArgument);
3853 switch(messageType)
3854 {
3855 case kIOMessageCanSystemPowerOff: debugf ("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
3856 case kIOMessageSystemWillPowerOff: LogOperation("PowerChanged kIOMessageSystemWillPowerOff");
3857 mDNSCoreMachineSleep(m, true); mDNSMacOSXNetworkChanged(m); break; // E0000250
3858 case kIOMessageSystemWillNotPowerOff: debugf ("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
3859 case kIOMessageCanSystemSleep: debugf ("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
3860 case kIOMessageSystemWillSleep: LogOperation("PowerChanged kIOMessageSystemWillSleep");
3861 mDNSCoreMachineSleep(m, true); mDNSMacOSXNetworkChanged(m); break; // E0000280
3862 case kIOMessageSystemWillNotSleep: debugf ("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
3863 case kIOMessageSystemHasPoweredOn: LogOperation("PowerChanged kIOMessageSystemHasPoweredOn");
3864 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
3865 if (m->SleepState) mDNSCoreMachineSleep(m, false);
3866 // Just to be safe, also make sure our interface list is fully up to date, in case we
3867 // haven't yet received the System Configuration Framework "network changed" event that
3868 // we expect to receive some time shortly after the kIOMessageSystemWillPowerOn message
3869 mDNSMacOSXNetworkChanged(m); break; // E0000300
3870 case kIOMessageSystemWillRestart: debugf ("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
3871 case kIOMessageSystemWillPowerOn: LogOperation("PowerChanged kIOMessageSystemWillPowerOn");
3872 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
3873 mDNSMacOSXNetworkChanged(m); mDNSCoreMachineSleep(m, false); break; // E0000320
3874 default: LogOperation("PowerChanged unknown message %X", messageType); break;
3875 }
3876
3877 if (!m->p->SleepLimit && messageType == kIOMessageSystemWillSleep)
3878 {
3879 m->p->SleepLimit = NonZeroTime(mDNS_TimeNow(m) + mDNSPlatformOneSecond * 5);
3880 m->p->SleepCookie = (long)messageArgument;
3881 }
3882 else
3883 IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
3884
3885 KQueueUnlock(m, "Sleep/Wake");
3886 }
3887 #endif /* NO_IOPOWER */
3888
3889 #if COMPILER_LIKES_PRAGMA_MARK
3890 #pragma mark -
3891 #pragma mark - Initialization & Teardown
3892 #endif
3893
3894 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
3895 CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
3896 CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
3897 CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
3898
3899 // Major version 6 is 10.2.x (Jaguar)
3900 // Major version 7 is 10.3.x (Panther)
3901 // Major version 8 is 10.4.x (Tiger)
3902 mDNSexport int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
3903 {
3904 int major = 0, minor = 0;
3905 char letter = 0, prodname[256]="<Unknown>", prodvers[256]="<Unknown>", buildver[256]="<Unknown>";
3906 CFDictionaryRef vers = _CFCopySystemVersionDictionary();
3907 if (vers)
3908 {
3909 CFStringRef cfprodname = CFDictionaryGetValue(vers, _kCFSystemVersionProductNameKey);
3910 CFStringRef cfprodvers = CFDictionaryGetValue(vers, _kCFSystemVersionProductVersionKey);
3911 CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
3912 if (cfprodname) CFStringGetCString(cfprodname, prodname, sizeof(prodname), kCFStringEncodingUTF8);
3913 if (cfprodvers) CFStringGetCString(cfprodvers, prodvers, sizeof(prodvers), kCFStringEncodingUTF8);
3914 if (cfbuildver) CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8);
3915 sscanf(buildver, "%d%c%d", &major, &letter, &minor);
3916 CFRelease(vers);
3917 }
3918 if (!major) { major=8; LogMsg("Note: No Major Build Version number found; assuming 8"); }
3919 if (HINFO_SWstring) mDNS_snprintf(HINFO_SWstring, 256, "%s %s (%s), %s", prodname, prodvers, buildver, mDNSResponderVersionString);
3920 return(major);
3921 }
3922
3923 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
3924 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
3925 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
3926 mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
3927 {
3928 int err = -1;
3929 int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
3930 if (s < 3)
3931 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s, errno, strerror(errno));
3932 else
3933 {
3934 struct sockaddr_in s5353;
3935 s5353.sin_family = AF_INET;
3936 s5353.sin_port = MulticastDNSPort.NotAnInteger;
3937 s5353.sin_addr.s_addr = 0;
3938 err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
3939 close(s);
3940 }
3941
3942 if (err) LogMsg("No unicast UDP responses");
3943 else debugf("Unicast UDP responses okay");
3944 return(err == 0);
3945 }
3946
3947 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
3948 // 1) query for b._dns-sd._udp.local on LocalOnly interface
3949 // (.local manually generated via explicit callback)
3950 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
3951 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
3952 // 4) result above should generate a callback from question in (1). result added to global list
3953 // 5) global list delivered to client via GetSearchDomainList()
3954 // 6) client calls to enumerate domains now go over LocalOnly interface
3955 // (!!!KRS may add outgoing interface in addition)
3956
3957 mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
3958 {
3959 mStatus err;
3960
3961 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
3962 // If we can't read the user's preferences, then we sleep a bit and try again, for up to five seconds before we give up.
3963 int i;
3964 for (i=0; i<100; i++)
3965 {
3966 domainlabel testlabel;
3967 testlabel.c[0] = 0;
3968 GetUserSpecifiedLocalHostName(&testlabel);
3969 if (testlabel.c[0]) break;
3970 usleep(50000);
3971 }
3972
3973 m->hostlabel.c[0] = 0;
3974
3975 char *HINFO_HWstring = "Macintosh";
3976 char HINFO_HWstring_buffer[256];
3977 int get_model[2] = { CTL_HW, HW_MODEL };
3978 size_t len_model = sizeof(HINFO_HWstring_buffer);
3979 if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0)
3980 HINFO_HWstring = HINFO_HWstring_buffer;
3981
3982 char HINFO_SWstring[256] = "";
3983 if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring) < 7) m->KnownBugs |= mDNS_KnownBug_PhantomInterfaces;
3984 if (mDNSPlatformInit_CanReceiveUnicast()) m->CanReceiveUnicastOn5353 = mDNStrue;
3985
3986 mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
3987 mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
3988 if (hlen + slen < 254)
3989 {
3990 m->HIHardware.c[0] = hlen;
3991 m->HISoftware.c[0] = slen;
3992 mDNSPlatformMemCopy(&m->HIHardware.c[1], HINFO_HWstring, hlen);
3993 mDNSPlatformMemCopy(&m->HISoftware.c[1], HINFO_SWstring, slen);
3994 }
3995
3996 m->p->permanentsockets.m = m;
3997 m->p->permanentsockets.sktv4 = m->p->permanentsockets.sktv6 = -1;
3998 m->p->permanentsockets.kqsv4.KQcallback = m->p->permanentsockets.kqsv6.KQcallback = myKQSocketCallBack;
3999 m->p->permanentsockets.kqsv4.KQcontext = m->p->permanentsockets.kqsv6.KQcontext = &m->p->permanentsockets;
4000 m->p->permanentsockets.kqsv4.KQtask = m->p->permanentsockets.kqsv6.KQtask = "UDP packet reception";
4001
4002 err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET, mDNSNULL);
4003 #ifndef NO_IPV6
4004 err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET6, mDNSNULL);
4005 #endif
4006
4007 struct sockaddr_in s4;
4008 socklen_t n4 = sizeof(s4);
4009 if (getsockname(m->p->permanentsockets.sktv4, (struct sockaddr *)&s4, &n4) < 0) LogMsg("getsockname v4 error %d (%s)", errno, strerror(errno));
4010 else m->UnicastPort4.NotAnInteger = s4.sin_port;
4011 #ifndef NO_IPV6
4012 if (m->p->permanentsockets.sktv6 >= 0)
4013 {
4014 struct sockaddr_in6 s6;
4015 socklen_t n6 = sizeof(s6);
4016 if (getsockname(m->p->permanentsockets.sktv6, (struct sockaddr *)&s6, &n6) < 0) LogMsg("getsockname v6 error %d (%s)", errno, strerror(errno));
4017 else m->UnicastPort6.NotAnInteger = s6.sin6_port;
4018 }
4019 #endif
4020
4021 m->p->InterfaceList = mDNSNULL;
4022 m->p->userhostlabel.c[0] = 0;
4023 m->p->usernicelabel.c[0] = 0;
4024 m->p->NotifyUser = 0;
4025 m->p->KeyChainBugTimer = 0;
4026 m->p->SleepLimit = 0;
4027
4028 m->AutoTunnelHostAddr.b[0] = 0; // Zero out AutoTunnelHostAddr so UpdateInterfaceList() know it has to set it up
4029
4030 mDNSs32 utc = mDNSPlatformUTC();
4031 UpdateInterfaceList(m, utc);
4032 SetupActiveInterfaces(m, utc);
4033
4034 NetworkChangedKey_IPv4 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
4035 NetworkChangedKey_IPv6 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
4036 NetworkChangedKey_Hostnames = SCDynamicStoreKeyCreateHostNames(NULL);
4037 NetworkChangedKey_Computername = SCDynamicStoreKeyCreateComputerName(NULL);
4038 NetworkChangedKey_DNS = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
4039 if (!NetworkChangedKey_IPv4 || !NetworkChangedKey_IPv6 || !NetworkChangedKey_Hostnames || !NetworkChangedKey_Computername || !NetworkChangedKey_DNS)
4040 { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr); }
4041
4042 err = WatchForNetworkChanges(m);
4043 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err); return(err); }
4044
4045 // Explicitly ensure that our Keychain operations utilize the system domain.
4046 #ifndef NO_SECURITYFRAMEWORK
4047 SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
4048 #endif
4049
4050 mDNS_Lock(m);
4051 SetDomainSecrets(m);
4052 SetLocalDomains();
4053 mDNS_Unlock(m);
4054
4055 #ifndef NO_SECURITYFRAMEWORK
4056 err = SecKeychainAddCallback(KeychainChanged, kSecAddEventMask|kSecDeleteEventMask|kSecUpdateEventMask, m);
4057 if (err) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err); return(err); }
4058 #endif
4059
4060 #ifndef NO_IOPOWER
4061 m->p->PowerConnection = IORegisterForSystemPower(m, &m->p->PowerPortRef, PowerChanged, &m->p->PowerNotifier);
4062 if (!m->p->PowerConnection) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
4063 else CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
4064 #endif /* NO_IOPOWER */
4065
4066 return(mStatus_NoError);
4067 }
4068
4069 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
4070 {
4071 #if MDNS_NO_DNSINFO
4072 LogMsg("Note: Compiled without Apple-specific Split-DNS support");
4073 #endif
4074
4075 mStatus result = mDNSPlatformInit_setup(m);
4076
4077 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
4078 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
4079 if (result == mStatus_NoError) mDNSCoreInitComplete(m, mStatus_NoError);
4080 return(result);
4081 }
4082
4083 mDNSexport void mDNSPlatformClose(mDNS *const m)
4084 {
4085 if (m->p->PowerConnection)
4086 {
4087 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
4088 #ifndef NO_IOPOWER
4089 // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
4090 // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
4091 IODeregisterForSystemPower(&m->p->PowerNotifier);
4092 IOServiceClose ( m->p->PowerConnection);
4093 IONotificationPortDestroy ( m->p->PowerPortRef);
4094 #endif /* NO_IOPOWER */
4095 m->p->PowerConnection = 0;
4096 }
4097
4098 if (m->p->Store)
4099 {
4100 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
4101 CFRunLoopSourceInvalidate(m->p->StoreRLS);
4102 CFRelease(m->p->StoreRLS);
4103 CFRelease(m->p->Store);
4104 m->p->Store = NULL;
4105 m->p->StoreRLS = NULL;
4106 }
4107
4108 mDNSs32 utc = mDNSPlatformUTC();
4109 MarkAllInterfacesInactive(m, utc);
4110 ClearInactiveInterfaces(m, utc);
4111 CloseSocketSet(&m->p->permanentsockets);
4112
4113 #if APPLE_OSX_mDNSResponder
4114 if (m->AutoTunnelHostAddrActive && m->AutoTunnelHostAddr.b[0])
4115 {
4116 m->AutoTunnelHostAddrActive = mDNSfalse;
4117 LogMsg("Removing AutoTunnel address %.16a", &m->AutoTunnelHostAddr);
4118 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown, m->AutoTunnelHostAddr.b);
4119 }
4120 #endif // APPLE_OSX_mDNSResponder
4121 }
4122
4123 #if COMPILER_LIKES_PRAGMA_MARK
4124 #pragma mark -
4125 #pragma mark - General Platform Support Layer functions
4126 #endif
4127
4128 mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
4129 {
4130 return(mach_absolute_time());
4131 }
4132
4133 mDNSexport mDNSs32 mDNSPlatformOneSecond = 1000;
4134
4135 mDNSexport mStatus mDNSPlatformTimeInit(void)
4136 {
4137 // Notes: Typical values for mach_timebase_info:
4138 // tbi.numer = 1000 million
4139 // tbi.denom = 33 million
4140 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
4141 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
4142 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
4143 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
4144 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
4145 //
4146 // Arithmetic notes:
4147 // tbi.denom is at least 1, and not more than 2^32-1.
4148 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
4149 // tbi.denom is at least 1, and not more than 2^32-1.
4150 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
4151 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
4152 // which is unlikely on any current or future Macintosh.
4153 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
4154 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
4155 struct mach_timebase_info tbi;
4156 kern_return_t result = mach_timebase_info(&tbi);
4157 if (result == KERN_SUCCESS) clockdivisor = ((uint64_t)tbi.denom * 1000000) / tbi.numer;
4158 return(result);
4159 }
4160
4161 mDNSexport mDNSs32 mDNSPlatformRawTime(void)
4162 {
4163 if (clockdivisor == 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
4164
4165 static uint64_t last_mach_absolute_time = 0;
4166 //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
4167 uint64_t this_mach_absolute_time = mach_absolute_time();
4168 if ((int64_t)this_mach_absolute_time - (int64_t)last_mach_absolute_time < 0)
4169 {
4170 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time);
4171 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time);
4172 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
4173 last_mach_absolute_time = this_mach_absolute_time;
4174 // Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xyyy) or later.
4175 // (This bug happens all the time on 10.3, and we know that's not going to be fixed.)
4176 if (mDNSMacOSXSystemBuildNumber(NULL) >= 8)
4177 NotifyOfElusiveBug("mach_absolute_time went backwards!",
4178 "This error occurs from time to time, often on newly released hardware, "
4179 "and usually the exact cause is different in each instance.\r\r"
4180 "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
4181 "and assign it to Radar Component “Kernel” Version “X”.");
4182 }
4183 last_mach_absolute_time = this_mach_absolute_time;
4184
4185 return((mDNSs32)(this_mach_absolute_time / clockdivisor));
4186 }
4187
4188 mDNSexport mDNSs32 mDNSPlatformUTC(void)
4189 {
4190 return time(NULL);
4191 }
4192
4193 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
4194 mDNSexport void mDNSPlatformLock (const mDNS *const m) { (void)m; }
4195 mDNSexport void mDNSPlatformUnlock (const mDNS *const m) { (void)m; }
4196 mDNSexport void mDNSPlatformStrCopy( void *dst, const void *src) { strcpy((char *)dst, (char *)src); }
4197 mDNSexport mDNSu32 mDNSPlatformStrLen ( const void *src) { return(strlen((char*)src)); }
4198 mDNSexport void mDNSPlatformMemCopy( void *dst, const void *src, mDNSu32 len) { memcpy(dst, src, len); }
4199 mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len) == 0); }
4200 mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len) { bzero(dst, len); }
4201 #if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
4202 mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
4203 #endif
4204 mDNSexport void mDNSPlatformMemFree (void *mem) { freeL("mDNSPlatformMemFree", mem); }