]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/mDNSMacOSX.c
mDNSResponder-212.1.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / mDNSMacOSX.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16
17 Change History (most recent first):
18
19 $Log: mDNSMacOSX.c,v $
20 Revision 1.687 2009/06/30 21:16:09 cheshire
21 <rdar://problem/7020041> Plugging and unplugging the power cable shouldn't cause a network change event
22 Additional fix: Only start and stop NetWake browses for active interfaces that are currently registered with mDNSCore
23
24 Revision 1.686 2009/06/25 23:36:56 cheshire
25 To facilitate testing, added command-line switch "-OfferSleepProxyService"
26 to re-enable the previously-supported mode of operation where we offer
27 sleep proxy service on desktop Macs that are set to never sleep.
28
29 Revision 1.685 2009/06/25 23:15:12 cheshire
30 Don't try to use private header file "IOPowerSourcesPrivate.h"
31 (it prevents external developers from being able to compile the code)
32
33 Revision 1.684 2009/06/24 22:14:22 cheshire
34 <rdar://problem/6911445> Plugging and unplugging the power cable shouldn't cause a network change event
35
36 Revision 1.683 2009/06/08 22:31:03 cheshire
37 Fixed typo in comment: Portability > 35 means nominal weight < 3kg
38
39 Revision 1.682 2009/05/19 23:30:31 cheshire
40 Suppressed some unnecessary debugging messages; added AppleTV to list of recognized hardware
41
42 Revision 1.681 2009/05/12 23:23:15 cheshire
43 Removed unnecessary "mDNSPlatformTCPConnect - connect failed ... Error 50 (Network is down)" debugging message
44
45 Revision 1.680 2009/05/05 01:32:50 jessic2
46 <rdar://problem/6830541> regservice_callback: instance->request is NULL 0 -- Clean up spurious logs resulting from fixing this bug.
47
48 Revision 1.679 2009/05/01 23:48:46 jessic2
49 <rdar://problem/6830541> regservice_callback: instance->request is NULL 0
50
51 Revision 1.678 2009/04/24 23:32:28 cheshire
52 To facilitate testing, put back code to be a sleep proxy when set to never sleep, compiled out by compile-time switch
53
54 Revision 1.677 2009/04/24 20:50:16 mcguire
55 <rdar://problem/6791775> 4 second delay in DNS response
56
57 Revision 1.676 2009/04/24 02:17:58 mcguire
58 <rdar://problem/5264124> uDNS: Not always respecting preference order of DNS servers
59
60 Revision 1.675 2009/04/23 18:51:28 mcguire
61 <rdar://problem/6729406> uDNS: PPP doesn't automatically reconnect on wake from sleep (no name resolver)
62
63 Revision 1.674 2009/04/23 00:58:01 jessic2
64 <rdar://problem/6802117> uDNS: DNS stops working after configd crashes
65
66 Revision 1.673 2009/04/22 01:19:57 jessic2
67 <rdar://problem/6814585> Daemon: mDNSResponder is logging garbage for error codes because it's using %ld for int 32
68
69 Revision 1.672 2009/04/21 16:34:47 mcguire
70 <rdar://problem/6810663> null deref in mDNSPlatformSetDNSConfig
71
72 Revision 1.671 2009/04/15 01:14:07 mcguire
73 <rdar://problem/6791775> 4 second delay in DNS response
74
75 Revision 1.670 2009/04/15 01:10:39 jessic2
76 <rdar://problem/6466541> BTMM: Add support for setting kDNSServiceErr_NoSuchRecord in DynamicStore
77
78 Revision 1.669 2009/04/11 02:02:34 mcguire
79 <rdar://problem/6780046> crash in doSSLHandshake
80
81 Revision 1.668 2009/04/11 00:20:08 jessic2
82 <rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
83
84 Revision 1.667 2009/04/09 20:01:00 cheshire
85 <rdar://problem/6767122> IOPMCopyActivePMPreferences not available on Apple TV
86 At Rory's suggestion, removed unnecessary "Could not get Wake On LAN value" log message
87
88 Revision 1.666 2009/04/07 21:57:53 cheshire
89 <rdar://problem/6767122> IOPMCopyActivePMPreferences not available on Apple TV
90 Put previous code back
91
92 Revision 1.665 2009/04/03 21:48:44 mcguire
93 Back out checkin 1.664 (<rdar://problem/6755199> MessageTracer: prepend domain to make signature field unique)
94
95 Revision 1.663 2009/04/02 22:21:16 mcguire
96 <rdar://problem/6577409> Adopt IOPM APIs
97
98 Revision 1.662 2009/04/02 01:08:15 mcguire
99 <rdar://problem/6735635> Don't be a sleep proxy when set to sleep never
100
101 Revision 1.661 2009/04/01 17:50:14 mcguire
102 cleanup mDNSRandom
103
104 Revision 1.660 2009/04/01 01:13:10 mcguire
105 <rdar://problem/6744276> Sleep Proxy: Detect lid closed
106
107 Revision 1.659 2009/03/30 21:11:07 jessic2
108 <rdar://problem/6728725> Need to do some polish work on MessageTracer logging
109
110 Revision 1.658 2009/03/30 20:07:28 mcguire
111 <rdar://problem/6736133> BTMM: SSLHandshake threads are leaking Mach ports
112
113 Revision 1.657 2009/03/27 17:27:13 cheshire
114 <rdar://problem/6724859> Need to support querying IPv6 DNS servers
115
116 Revision 1.656 2009/03/26 05:02:48 mcguire
117 fix build error in dnsextd
118
119 Revision 1.655 2009/03/26 03:59:00 jessic2
120 Changes for <rdar://problem/6492552&6492593&6492609&6492613&6492628&6492640&6492699>
121
122 Revision 1.654 2009/03/20 20:53:26 cheshire
123 Added test code for testing with MacBook Air, using a USB dongle that doesn't actually support Wake-On-LAN
124
125 Revision 1.653 2009/03/20 20:52:22 cheshire
126 <rdar://problem/6703952> Support CFUserNotificationDisplayNotice in mDNSResponderHelper
127
128 Revision 1.652 2009/03/19 23:44:47 mcguire
129 <rdar://problem/6699216> Properly handle EADDRINUSE
130
131 Revision 1.651 2009/03/17 19:15:24 mcguire
132 <rdar://problem/6655415> SSLHandshake deadlock issues
133
134 Revision 1.650 2009/03/17 01:24:22 cheshire
135 Updated to new Sleep Proxy metric ranges: 100000-999999; 1000000 means "do not use"
136
137 Revision 1.649 2009/03/15 01:30:29 mcguire
138 fix log message
139
140 Revision 1.648 2009/03/15 01:16:08 mcguire
141 <rdar://problem/6655415> SSLHandshake deadlock issues
142
143 Revision 1.647 2009/03/14 01:42:56 mcguire
144 <rdar://problem/5457116> BTMM: Fix issues with multiple .Mac accounts on the same machine
145
146 Revision 1.646 2009/03/13 01:36:24 mcguire
147 <rdar://problem/6657640> Reachability fixes on DNS config change
148
149 Revision 1.645 2009/03/10 23:48:33 cheshire
150 <rdar://problem/6665739> Task scheduling failure when Sleep Proxy Server is active
151
152 Revision 1.644 2009/03/10 04:17:09 cheshire
153 Check for NULL answer in UpdateSPSStatus()
154
155 Revision 1.643 2009/03/10 01:15:55 cheshire
156 Sleep Proxies with invalid names (score 10000) need to be ignored
157
158 Revision 1.642 2009/03/08 04:46:51 mkrochma
159 Change Keychain LogMsg to LogInfo
160
161 Revision 1.641 2009/03/05 23:53:34 cheshire
162 Removed spurious "SnowLeopardPowerChanged: wake ERROR" syslog message
163
164 Revision 1.640 2009/03/05 21:57:13 cheshire
165 Don't close BPF fd until we have no more records we're proxying for on that interface
166
167 Revision 1.639 2009/03/04 01:45:01 cheshire
168 HW_MODEL information should be LogSPS, not LogMsg
169
170 Revision 1.638 2009/03/03 22:51:54 cheshire
171 <rdar://problem/6504236> Sleep Proxy: Waking on same network but different interface will cause conflicts
172
173 Revision 1.637 2009/02/26 22:58:47 cheshire
174 <rdar://problem/6616335> Crash in mDNSResponder at mDNSResponder • CloseBPF + 75
175 Fixed race condition between the kqueue thread and the CFRunLoop thread.
176
177 Revision 1.636 2009/02/21 01:38:39 cheshire
178 Added comment: mDNSCoreMachineSleep(m, false); // Will set m->SleepState = SleepState_Awake;
179
180 Revision 1.635 2009/02/17 23:29:03 cheshire
181 Throttle logging to a slower rate when running on SnowLeopard
182
183 Revision 1.634 2009/02/14 00:29:17 mcguire
184 fixed typo
185
186 Revision 1.633 2009/02/14 00:07:11 cheshire
187 Need to set up m->SystemWakeOnLANEnabled before calling UpdateInterfaceList(m, utc);
188
189 Revision 1.632 2009/02/13 19:40:07 cheshire
190 Improved alignment of LogSPS messages
191
192 Revision 1.631 2009/02/13 18:16:05 cheshire
193 Fixed some compile warnings
194
195 Revision 1.630 2009/02/13 06:32:43 cheshire
196 Converted LogOperation messages to LogInfo or LogSPS
197
198 Revision 1.629 2009/02/12 20:57:26 cheshire
199 Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch
200
201 Revision 1.628 2009/02/11 02:34:45 cheshire
202 m->p->SystemWakeForNetworkAccessEnabled renamed to m->SystemWakeOnLANEnabled
203
204 Revision 1.627 2009/02/10 00:19:17 cheshire
205 <rdar://problem/6107426> Sleep Proxy: Adopt SIOCGIFWAKEFLAGS ioctl to determine interface WOMP-ability
206
207 Revision 1.626 2009/02/10 00:15:38 cheshire
208 <rdar://problem/6551529> Sleep Proxy: "Unknown DNS packet type 8849" logs
209
210 Revision 1.625 2009/02/09 21:24:25 cheshire
211 Set correct bit in ifr.ifr_wake_flags (was coincidentally working because IF_WAKE_ON_MAGIC_PACKET happens to have the value 1)
212
213 Revision 1.624 2009/02/09 21:11:43 cheshire
214 Need to acknowledge kIOPMSystemPowerStateCapabilityCPU message
215
216 Revision 1.623 2009/02/09 06:20:42 cheshire
217 Upon receiving system power change notification, make sure our m->p->SystemWakeForNetworkAccessEnabled value
218 correctly reflects the current system setting
219
220 Revision 1.622 2009/02/07 02:57:32 cheshire
221 <rdar://problem/6084043> Sleep Proxy: Need to adopt IOPMConnection
222
223 Revision 1.621 2009/02/06 03:18:12 mcguire
224 <rdar://problem/6534643> BTMM: State not cleaned up on SIGTERM w/o reboot
225
226 Revision 1.620 2009/02/02 22:14:11 cheshire
227 Instead of repeatedly checking the Dynamic Store, use m->p->SystemWakeForNetworkAccessEnabled variable
228
229 Revision 1.619 2009/01/24 02:11:58 cheshire
230 Handle case where config->resolver[0]->nameserver[0] is NULL
231
232 Revision 1.618 2009/01/24 01:55:51 cheshire
233 Handle case where config->resolver[0]->domain is NULL
234
235 Revision 1.617 2009/01/24 01:48:42 cheshire
236 <rdar://problem/4786302> Implement logic to determine when to send dot-local lookups via Unicast
237
238 Revision 1.616 2009/01/24 00:28:43 cheshire
239 Updated comments
240
241 Revision 1.615 2009/01/22 02:14:26 cheshire
242 <rdar://problem/6515626> Sleep Proxy: Set correct target MAC address, instead of all zeroes
243
244 Revision 1.614 2009/01/21 03:43:57 mcguire
245 <rdar://problem/6511765> BTMM: Add support for setting kDNSServiceErr_NATPortMappingDisabled in DynamicStore
246
247 Revision 1.613 2009/01/20 02:38:41 mcguire
248 fix previous checkin comment
249
250 Revision 1.612 2009/01/20 02:35:15 mcguire
251 <rdar://problem/6508974> don't update BTMM & SleepProxyServers status at shutdown time
252
253 Revision 1.611 2009/01/17 04:15:40 cheshire
254 Updated "did sleep(5)" debugging message
255
256 Revision 1.610 2009/01/16 20:37:30 cheshire
257 Fixed incorrect value of EOPNOTSUPP
258
259 Revision 1.609 2009/01/16 03:08:13 cheshire
260 Use kernel event notifications to track KEV_DL_WAKEFLAGS_CHANGED
261 (indicates when SIOCGIFWAKEFLAGS changes for an interface, e.g. when AirPort
262 switches from a base-station that's WakeOnLAN-capable to one that isn't)
263
264 Revision 1.608 2009/01/16 01:27:03 cheshire
265 Initial work to adopt SIOCGIFWAKEFLAGS ioctl to determine whether an interface is WakeOnLAN-capable
266
267 Revision 1.607 2009/01/15 22:24:01 cheshire
268 Get rid of unnecessary ifa_name field in NetworkInterfaceInfoOSX (it just duplicates the content of ifinfo.ifname)
269 This also eliminates an unnecessary malloc, memory copy, and free
270
271 Revision 1.606 2009/01/15 00:22:49 mcguire
272 <rdar://problem/6437092> NAT-PMP: mDNSResponder needs to listen on 224.0.0.1:5350/UDP with REUSEPORT
273
274 Revision 1.605 2009/01/14 01:38:43 mcguire
275 <rdar://problem/6492710> Write out DynamicStore per-interface SleepProxyServer info
276
277 Revision 1.604 2009/01/13 05:31:34 mkrochma
278 <rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
279
280 Revision 1.603 2009/01/12 22:26:13 mkrochma
281 Change DynamicStore location from BonjourSleepProxy/DiscoveredServers to SleepProxyServers
282
283 Revision 1.602 2008/12/19 20:23:34 mcguire
284 <rdar://problem/6459269> Lots of duplicate log messages about failure to bind to NAT-PMP Announcement port
285
286 Revision 1.601 2008/12/15 19:51:56 mcguire
287 <rdar://problem/6443067> Retry UDP socket creation only when randomizing ports
288
289 Revision 1.600 2008/12/12 21:30:14 cheshire
290 Additional defensive coding -- make sure InterfaceID is found in our list before using it
291
292 Revision 1.599 2008/12/12 04:36:26 cheshire
293 Make sure we don't overflow our BPF filter buffer
294 Only add addresses for records where the InterfaceID matches
295
296 Revision 1.598 2008/12/12 00:57:51 cheshire
297 Updated BPF filter generation to explicitly match addresses we're proxying for,
298 rather than just matching any unknown IP address
299
300 Revision 1.597 2008/12/10 20:37:05 cheshire
301 Don't mark interfaces like PPP as being WakeonLAN-capable
302
303 Revision 1.596 2008/12/10 19:34:30 cheshire
304 Use symbolic OS version names instead of literal integers
305
306 Revision 1.595 2008/12/10 02:25:31 cheshire
307 Minor fixes to use of LogClientOperations symbol
308
309 Revision 1.594 2008/12/10 02:11:45 cheshire
310 ARMv5 compiler doesn't like uncommented stuff after #endif
311
312 Revision 1.593 2008/12/09 23:08:55 mcguire
313 <rdar://problem/6430877> should use IP_BOUND_IF
314 additional cleanup
315
316 Revision 1.592 2008/12/09 19:58:44 mcguire
317 <rdar://problem/6430877> should use IP_BOUND_IF
318
319 Revision 1.591 2008/12/09 15:39:05 cheshire
320 Workaround for bug on Leopard and earlier where Ethernet drivers report wrong link state immediately after wake from sleep
321
322 Revision 1.590 2008/12/09 05:21:54 cheshire
323 Should key sleep/wake handling off kIOMessageSystemWillPowerOn message -- the kIOMessageSystemHasPoweredOn
324 message is delayed by some seemingly-random amount in the range 0-15 seconds.
325
326 Revision 1.589 2008/12/05 02:35:25 mcguire
327 <rdar://problem/6107390> Write to the DynamicStore when a Sleep Proxy server is available on the network
328
329 Revision 1.588 2008/12/04 21:08:52 mcguire
330 <rdar://problem/6116863> mDNS: Provide mechanism to disable Multicast advertisements
331
332 Revision 1.587 2008/12/04 02:17:47 cheshire
333 Additional sleep/wake debugging messages
334
335 Revision 1.586 2008/11/26 20:34:55 cheshire
336 Changed some "LogOperation" debugging messages to "debugf"
337
338 Revision 1.585 2008/11/25 20:53:35 cheshire
339 Updated portability metrics; added Xserve and PowerBook to list
340
341 Revision 1.584 2008/11/25 05:07:16 cheshire
342 <rdar://problem/6374328> Advertise Sleep Proxy metrics in service name
343
344 Revision 1.583 2008/11/20 01:42:31 cheshire
345 For consistency with other parts of the code, changed code to only check
346 that the first 4 bytes of MAC address are zero, not the whole 6 bytes.
347
348 Revision 1.582 2008/11/14 22:59:09 cheshire
349 When on a network with more than one subnet overlayed on a single physical link, don't make local ARP
350 entries for hosts that are on our physical link but not on our logical subnet -- it confuses the kernel
351
352 Revision 1.581 2008/11/14 21:01:26 cheshire
353 Log a warning if we fail to get a MAC address for an interface
354
355 Revision 1.580 2008/11/14 02:16:15 cheshire
356 Clean up NetworkChanged handling
357
358 Revision 1.579 2008/11/12 23:15:37 cheshire
359 Updated log messages
360
361 Revision 1.578 2008/11/06 23:41:57 cheshire
362 Refinement: Only need to create local ARP entry when sending ARP packet to broadcast address or to ourselves
363
364 Revision 1.577 2008/11/06 01:15:47 mcguire
365 Fix compile error that occurs when LogOperation is disabled
366
367 Revision 1.576 2008/11/05 21:55:21 cheshire
368 Fixed mistake in BPF filter generation
369
370 Revision 1.575 2008/11/04 23:54:09 cheshire
371 Added routine mDNSSetARP(), used to replace an SPS client's entry in our ARP cache with
372 a dummy one, so that IP traffic to the SPS client initiated by the SPS machine can be
373 captured by our BPF filters, and used as a trigger to wake the sleeping machine.
374
375 Revision 1.574 2008/11/04 00:27:58 cheshire
376 Corrected some timing anomalies in sleep/wake causing spurious name self-conflicts
377
378 Revision 1.573 2008/11/03 01:12:42 mkrochma
379 Fix compile error that occurs when LogOperation is disabled
380
381 Revision 1.572 2008/10/31 23:36:13 cheshire
382 One wakeup clear any previous power requests
383
384 Revision 1.571 2008/10/31 23:05:30 cheshire
385 Move logic to decide when to at as Sleep Proxy Server from daemon.c to mDNSMacOSX.c
386
387 Revision 1.570 2008/10/30 01:08:19 cheshire
388 After waking for network maintenance operations go back to sleep again
389
390 Revision 1.569 2008/10/29 21:39:43 cheshire
391 Updated syslog messages; close BPF socket on read error
392
393 Revision 1.568 2008/10/28 20:37:28 cheshire
394 Changed code to create its own CFSocketCreateWithNative directly, instead of
395 relying on udsSupportAddFDToEventLoop/udsSupportRemoveFDFromEventLoop
396
397 Revision 1.567 2008/10/27 22:31:37 cheshire
398 Can't just close BPF_fd using "close(i->BPF_fd);" -- need to call
399 "udsSupportRemoveFDFromEventLoop(i->BPF_fd);" to remove it from our event source list
400
401 Revision 1.566 2008/10/23 22:33:23 cheshire
402 Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu
403
404 Revision 1.565 2008/10/22 23:23:55 cheshire
405 Moved definition of OSXVers from daemon.c into mDNSMacOSX.c
406
407 Revision 1.564 2008/10/22 22:08:46 cheshire
408 Take IP header length into account when determining how many bytes to return from BPF filter
409
410 Revision 1.563 2008/10/22 20:59:28 cheshire
411 BPF filter needs to capture a few more bytes so that we can examine TCP header fields
412
413 Revision 1.562 2008/10/22 19:48:29 cheshire
414 Improved syslog messages
415
416 Revision 1.561 2008/10/22 17:18:57 cheshire
417 Need to open and close BPF fds when turning Sleep Proxy Server on and off
418
419 Revision 1.560 2008/10/22 01:09:36 cheshire
420 Fixed build warning when not using LogClientOperations
421
422 Revision 1.559 2008/10/21 01:05:30 cheshire
423 Added code to receive raw packets using Berkeley Packet Filter (BPF)
424
425 Revision 1.558 2008/10/16 22:42:06 cheshire
426 Removed debugging messages
427
428 Revision 1.557 2008/10/09 22:33:14 cheshire
429 Fill in ifinfo.MAC field when fetching interface list
430
431 Revision 1.556 2008/10/09 21:15:23 cheshire
432 In mDNSPlatformUDPSocket(), need to create an IPv6 socket as well as IPv4
433
434 Revision 1.555 2008/10/09 19:05:57 cheshire
435 No longer want to inhibit all networking when going to sleep
436
437 Revision 1.554 2008/10/08 18:36:51 mkrochma
438 <rdar://problem/4371323> Supress Couldn't read user-specified Computer Name logs
439
440 Revision 1.553 2008/10/04 00:47:12 cheshire
441 If NetWake setting changes for an interface, treat it as a whole new interface (like BSSID changing)
442
443 Revision 1.552 2008/10/03 23:32:15 cheshire
444 Added definition of mDNSPlatformSendRawPacket
445
446 Revision 1.551 2008/10/03 18:25:16 cheshire
447 Instead of calling "m->MainCallback" function pointer directly, call mDNSCore routine "mDNS_ConfigChanged(m);"
448
449 Revision 1.550 2008/10/03 00:51:58 cheshire
450 Removed spurious "else" case that got left in by mistake
451
452 Revision 1.549 2008/10/03 00:50:13 cheshire
453 Minor code rearrangement; don't set up interface list until *after* we've started watching for network changes
454
455 Revision 1.548 2008/10/03 00:26:25 cheshire
456 Export DictionaryIsEnabled() so it's callable from other files
457
458 Revision 1.547 2008/10/02 23:50:07 mcguire
459 <rdar://problem/6136442> shutdown time issues
460 improve log messages when SCDynamicStoreCreate() fails
461
462 Revision 1.546 2008/10/02 22:26:21 cheshire
463 Moved declaration of BPF_fd from uds_daemon.c to mDNSMacOSX.c, where it really belongs
464
465 Revision 1.545 2008/10/01 22:01:40 cheshire
466 On Allan Nathanson's advice, add "State:/IOKit/PowerManagement/CurrentSettings"
467 to keys array instead of patterns array, for efficiency
468
469 Revision 1.544 2008/10/01 21:35:35 cheshire
470 Monitor "State:/IOKit/PowerManagement/CurrentSettings" to track state of "Wake for network access" setting
471
472 Revision 1.543 2008/09/26 23:05:56 mkrochma
473 Improve log messages by using good old UTF-8
474
475 Revision 1.542 2008/09/26 19:49:51 cheshire
476 Improved "failed to send packet" debugging message
477
478 Revision 1.541 2008/09/25 21:02:05 cheshire
479 <rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
480 In TunnelServers(), need to check main m->ResourceRecords list to see
481 if we have a non-zero number of advertised AutoTunnel services
482
483 Revision 1.540 2008/07/30 00:55:56 mcguire
484 <rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
485 Additional fixes so that we know when a socket has been closed while in a loop reading from it
486
487 Revision 1.539 2008/07/24 20:23:04 cheshire
488 <rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
489
490 Revision 1.538 2008/06/02 05:39:39 mkrochma
491 <rdar://problem/5932760> Don't set TOS bits anymore
492
493 Revision 1.537 2008/05/01 18:30:54 mkrochma
494 <rdar://problem/5895642> Make mDNSResponder and mDNSResponderHelper shutdown at regular time
495
496 Revision 1.536 2008/03/25 01:27:30 mcguire
497 <rdar://problem/5810718> Status sometimes wrong when link goes down
498
499 Revision 1.535 2008/03/14 22:52:51 mcguire
500 <rdar://problem/5321824> write status to the DS
501 Ignore duplicate queries, which don't get established (since they're duplicates)
502
503 Revision 1.534 2008/03/12 22:58:15 mcguire
504 <rdar://problem/5321824> write status to the DS
505 Fixes for NO_SECURITYFRAMEWORK
506
507 Revision 1.533 2008/03/07 00:48:54 mcguire
508 <rdar://problem/5321824> write status to the DS
509 cleanup strings
510
511 Revision 1.532 2008/03/06 23:44:39 mcguire
512 <rdar://problem/5321824> write status to the DS
513 cleanup function names & log messages
514 add external port numbers to dictionary
515 add defensive code in case CF*Create fails
516 don't output NAT statuses if zero
517
518 Revision 1.531 2008/03/06 21:27:47 cheshire
519 <rdar://problem/5500969> BTMM: Need ability to identify version of mDNSResponder client
520 To save network bandwidth, removed unnecessary redundant information from HINFO record
521
522 Revision 1.530 2008/03/06 03:15:48 mcguire
523 <rdar://problem/5321824> write status to the DS
524 use mStatus_* instead of kDNSServiceErr_*
525
526 Revision 1.529 2008/03/06 02:48:35 mcguire
527 <rdar://problem/5321824> write status to the DS
528
529 Revision 1.528 2008/02/29 01:33:57 mcguire
530 <rdar://problem/5611801> BTMM: Services stay registered after previously successful NAT Port mapping fails
531
532 Revision 1.527 2008/02/28 03:25:26 mcguire
533 <rdar://problem/5535772> config cleanup on shutdown/reboot
534
535 Revision 1.526 2008/02/26 21:43:54 cheshire
536 Renamed 'clockdivisor' to 'mDNSPlatformClockDivisor' (LogTimeStamps code needs to be able to access it)
537
538 Revision 1.525 2008/02/20 00:53:20 cheshire
539 <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
540 Removed overly alarming syslog message
541
542 Revision 1.524 2008/01/31 22:25:10 jgraessley
543 <rdar://problem/5715434> using default Macintosh-0016CBF62EFD.local
544 Use sysctlbyname to get hardware type for the default name.
545
546 Revision 1.523 2008/01/15 01:32:56 jgraessley
547 Bug #: 5595309
548 Reviewed by: Stuart Cheshire
549 Additional change to print warning message up to 1000 times to make it more visible
550
551 Revision 1.522 2008/01/15 01:14:02 mcguire
552 <rdar://problem/5674390> mDNSPlatformSendUDP should allow unicast queries on specific interfaces
553 removed check and log message, as they are no longer relevant
554
555 Revision 1.521 2007/12/14 00:58:28 cheshire
556 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
557 Additional fixes: When going to sleep, mDNSResponder needs to postpone sleep
558 until TLS/TCP deregistrations have completed (up to five seconds maximum)
559
560 Revision 1.520 2007/12/10 23:01:01 cheshire
561 Remove some unnecessary log messages
562
563 Revision 1.519 2007/12/06 00:22:27 mcguire
564 <rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
565
566 Revision 1.518 2007/12/05 01:52:30 cheshire
567 <rdar://problem/5624763> BTMM: getaddrinfo_async_start returns EAI_NONAME when resolving BTMM hostname
568 Delay returning IPv4 address ("A") results for autotunnel names until after we've set up the tunnel (or tried to)
569
570 Revision 1.517 2007/12/03 18:37:26 cheshire
571 Moved mDNSPlatformWriteLogMsg & mDNSPlatformWriteDebugMsg
572 from mDNSMacOSX.c to PlatformCommon.c, so that Posix build can use them
573
574 Revision 1.516 2007/12/01 01:21:27 jgraessley
575 <rdar://problem/5623140> mDNSResponder unicast DNS improvements
576
577 Revision 1.515 2007/12/01 00:40:00 cheshire
578 Add mDNSPlatformWriteLogMsg & mDNSPlatformWriteDebugMsg abstractions, to facilitate EFI conversion
579
580 Revision 1.514 2007/12/01 00:38:32 cheshire
581 Fixed compile warning: declaration of 'index' shadows a global declaration
582
583 Revision 1.513 2007/11/27 00:08:49 jgraessley
584 <rdar://problem/5613538> Interface-specific resolvers not setup correctly
585
586 Revision 1.512 2007/11/16 22:09:26 cheshire
587 Added missing type information in mDNSPlatformTCPCloseConnection debugging log message
588
589 Revision 1.511 2007/11/14 23:06:13 cheshire
590 <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
591
592 Revision 1.510 2007/11/14 22:29:19 cheshire
593 Updated comments and debugging log messages
594
595 Revision 1.509 2007/11/14 01:07:53 cheshire
596 Updated comments
597
598 Revision 1.508 2007/11/02 21:59:37 cheshire
599 Added comment about locking
600
601 Revision 1.507 2007/11/02 20:18:13 cheshire
602 <rdar://problem/5575583> BTMM: Work around keychain notification bug <rdar://problem/5124399>
603
604 Revision 1.506 2007/10/30 20:46:45 cheshire
605 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
606
607 Revision 1.505 2007/10/29 23:55:10 cheshire
608 <rdar://problem/5526791> BTMM: Changing Local Hostname doesn't update Back to My Mac registered records
609 Don't need to manually fake another AutoTunnelNATCallback if it has not yet received its first callback
610 (and indeed should not, since the result fields will not yet be set up correctly in this case)
611
612 Revision 1.504 2007/10/26 00:50:37 cheshire
613 <rdar://problem/5526791> BTMM: Changing Local Hostname doesn't update Back to My Mac registered records
614
615 Revision 1.503 2007/10/25 23:11:42 cheshire
616 Ignore IPv6 ULA addresses configured on lo0 loopback interface
617
618 Revision 1.502 2007/10/22 20:07:07 cheshire
619 Moved mDNSPlatformSourceAddrForDest from mDNSMacOSX.c to PlatformCommon.c so
620 Posix build can share the code (better than just pasting it into mDNSPosix.c)
621
622 Revision 1.501 2007/10/22 19:40:30 cheshire
623 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
624 Made subroutine mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAddr *const dst)
625
626 Revision 1.500 2007/10/17 22:49:55 cheshire
627 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
628
629 Revision 1.499 2007/10/17 19:47:54 cheshire
630 Improved debugging messages
631
632 Revision 1.498 2007/10/17 18:42:06 cheshire
633 Export SetDomainSecrets so its callable from other files
634
635 Revision 1.497 2007/10/16 17:03:07 cheshire
636 <rdar://problem/3557903> Performance: Core code will not work on platforms with small stacks
637 Cut SetDomainSecrets stack from 3792 to 1760 bytes
638
639 Revision 1.496 2007/10/04 20:33:05 mcguire
640 <rdar://problem/5518845> BTMM: Racoon configuration removed when network changes
641
642 Revision 1.495 2007/10/02 05:03:38 cheshire
643 Fix bogus indentation in mDNSPlatformDynDNSHostNameStatusChanged
644
645 Revision 1.494 2007/09/29 20:40:19 cheshire
646 <rdar://problem/5513378> Crash in ReissueBlockedQuestions
647
648 Revision 1.493 2007/09/29 03:16:45 cheshire
649 <rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
650 When AutoTunnel information changes, wait for record deregistrations to complete before registering new data
651
652 Revision 1.492 2007/09/28 23:58:35 mcguire
653 <rdar://problem/5505280> BTMM: v6 address and security policies being setup too soon
654 Fix locking issue.
655
656 Revision 1.491 2007/09/27 23:28:53 mcguire
657 <rdar://problem/5508042> BTMM: Anonymous racoon configuration not always cleaned up correctly
658
659 Revision 1.490 2007/09/26 23:01:21 mcguire
660 <rdar://problem/5505280> BTMM: v6 address and security policies being setup too soon
661
662 Revision 1.489 2007/09/26 22:58:16 mcguire
663 <rdar://problem/5505092> BTMM: Client tunnels being created to ::0 via 0.0.0.0
664
665 Revision 1.488 2007/09/26 00:32:45 cheshire
666 Rearrange struct TCPSocket_struct so "TCPSocketFlags flags" comes first (needed for debug logging)
667
668 Revision 1.487 2007/09/21 17:07:41 mcguire
669 <rdar://problem/5487354> BTMM: Need to modify IPSec tunnel setup files when shared secret changes (server-role)
670
671 Revision 1.486 2007/09/19 23:17:38 cheshire
672 <rdar://problem/5482131> BTMM: Crash when switching .Mac accounts
673
674 Revision 1.485 2007/09/19 21:44:29 cheshire
675 Improved "mDNSKeychainGetSecrets failed" error message
676
677 Revision 1.484 2007/09/18 21:44:55 cheshire
678 <rdar://problem/5469006> Crash in GetAuthInfoForName_internal
679 Code was using n->ExtPort (now n->RequestedPort) when it should have been using n->ExternalPort
680
681 Revision 1.483 2007/09/17 22:19:39 mcguire
682 <rdar://problem/5482519> BTMM: Tunnel is getting configured too much which causes long delays
683 No need to configure a tunnel again if all the parameters are the same -- just remove the older duplicate tunnel from the list.
684
685 Revision 1.482 2007/09/14 21:16:03 cheshire
686 <rdar://problem/5413170> mDNSResponder using 100% CPU spinning in tlsReadSock
687
688 Revision 1.481 2007/09/14 21:14:56 mcguire
689 <rdar://problem/5481318> BTMM: Need to modify IPSec tunnel setup files when shared secret changes
690
691 Revision 1.480 2007/09/13 00:16:42 cheshire
692 <rdar://problem/5468706> Miscellaneous NAT Traversal improvements
693
694 Revision 1.479 2007/09/12 19:22:20 cheshire
695 Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
696 Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
697
698 Revision 1.478 2007/09/07 22:21:45 vazquez
699 <rdar://problem/5460830> BTMM: Connection stops working after connecting VPN
700
701 Revision 1.477 2007/09/07 21:22:30 cheshire
702 <rdar://problem/5460210> BTMM: SetupSocket 5351 failed; Can't allocate UDP multicast socket spew on wake from sleep with internet sharing on
703 Don't log failures binding to port 5351
704
705 Revision 1.476 2007/09/06 20:38:08 cheshire
706 <rdar://problem/5439021> Only call SetDomainSecrets() for Keychain changes that are relevant to mDNSResponder
707
708 Revision 1.475 2007/09/05 02:24:28 cheshire
709 <rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
710 In ReissueBlockedQuestions, only restart questions marked NoAnswer_Suspended, not those marked NoAnswer_Fail
711
712 Revision 1.474 2007/09/04 22:32:58 mcguire
713 <rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
714
715 Revision 1.473 2007/08/31 19:53:15 cheshire
716 <rdar://problem/5431151> BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup
717 If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist
718
719 Revision 1.472 2007/08/31 18:49:49 vazquez
720 <rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM
721
722 Revision 1.471 2007/08/31 02:05:46 cheshire
723 Need to hold mDNS_Lock when calling mDNS_AddDynDNSHostName
724
725 Revision 1.470 2007/08/30 22:50:04 mcguire
726 <rdar://problem/5430628> BTMM: Tunneled services are registered when autotunnel can't be setup
727
728 Revision 1.469 2007/08/30 19:40:51 cheshire
729 Added syslog messages to report various initialization failures
730
731 Revision 1.468 2007/08/30 00:12:20 cheshire
732 Check error codes and log failures during AutoTunnel setup
733
734 Revision 1.467 2007/08/28 00:33:04 jgraessley
735 <rdar://problem/5423932> Selective compilation options
736
737 Revision 1.466 2007/08/24 23:25:55 cheshire
738 Debugging messages to help track down duplicate items being read from system keychain
739
740 Revision 1.465 2007/08/24 00:39:12 cheshire
741 Added comment explaining why we set info->AutoTunnelService.resrec.RecordType to kDNSRecordTypeUnregistered
742
743 Revision 1.464 2007/08/24 00:15:21 cheshire
744 Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
745
746 Revision 1.463 2007/08/23 21:02:35 cheshire
747 SecKeychainSetPreferenceDomain() call should be in platform-support layer, not daemon.c
748
749 Revision 1.462 2007/08/18 01:02:03 mcguire
750 <rdar://problem/5415593> No Bonjour services are getting registered at boot
751
752 Revision 1.461 2007/08/10 22:25:57 mkrochma
753 <rdar://problem/5396302> mDNSResponder continually complains about slow UDP packet reception -- about 400 msecs
754
755 Revision 1.460 2007/08/08 22:34:59 mcguire
756 <rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
757
758 Revision 1.459 2007/08/08 21:07:48 vazquez
759 <rdar://problem/5244687> BTMM: Need to advertise model information via wide-area bonjour
760
761 Revision 1.458 2007/08/03 02:18:41 mcguire
762 <rdar://problem/5381687> BTMM: Use port numbers in IPsec policies & configuration files
763
764 Revision 1.457 2007/08/02 16:48:45 mcguire
765 <rdar://problem/5329526> BTMM: Don't try to create tunnel back to same machine
766
767 Revision 1.456 2007/08/02 03:28:30 vazquez
768 Make ExternalAddress and err unused to fix build warnings
769
770 Revision 1.455 2007/08/01 03:09:22 cheshire
771 <rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port
772
773 Revision 1.454 2007/07/31 23:08:34 mcguire
774 <rdar://problem/5329542> BTMM: Make AutoTunnel mode work with multihoming
775
776 Revision 1.453 2007/07/31 19:13:58 mkrochma
777 No longer need to include "btmm" in hostname to avoid name conflicts
778
779 Revision 1.452 2007/07/27 19:30:41 cheshire
780 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
781 to properly reflect tri-state nature of the possible responses
782
783 Revision 1.451 2007/07/25 22:25:45 cheshire
784 <rdar://problem/5360853> BTMM: Code not cleaning up old racoon files
785
786 Revision 1.450 2007/07/25 21:19:10 cheshire
787 <rdar://problem/5359507> Fails to build with NO_SECURITYFRAMEWORK: 'IsTunnelModeDomain' defined but not used
788
789 Revision 1.449 2007/07/25 01:36:09 mcguire
790 <rdar://problem/5345290> BTMM: Replace popen() `setkey` calls to setup/teardown ipsec policies
791
792 Revision 1.448 2007/07/24 21:30:09 cheshire
793 Added "AutoTunnel server listening for connections..." diagnostic message
794
795 Revision 1.447 2007/07/24 20:24:18 cheshire
796 Only remove AutoTunnel address if we have created it.
797 Otherwise, we get "errno 49 (Can't assign requested address)" errors on exit.
798
799 Revision 1.446 2007/07/24 03:00:09 cheshire
800 SetDomainSecrets() should call SetupLocalAutoTunnelInterface_internal(), not SetupLocalAutoTunnelInterface()
801
802 Revision 1.445 2007/07/23 20:26:26 cheshire
803 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
804 Move code that reads "Setup:/Network/BackToMyMac" preferences outside the check
805 for existence of "Setup:/Network/DynamicDNS" settings
806
807 Revision 1.444 2007/07/21 00:54:49 cheshire
808 <rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured
809
810 Revision 1.443 2007/07/20 23:23:11 cheshire
811 Rename out-of-date name "atq" (was AutoTunnelQuery) to simpler "tun"
812
813 Revision 1.442 2007/07/20 20:23:24 cheshire
814 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
815 Fixed errors reading the Setup:/Network/BackToMyMac preferences
816
817 Revision 1.441 2007/07/20 16:46:45 mcguire
818 <rdar://problem/5345233> BTMM: Replace system() `route` calls to setup/teardown routes
819
820 Revision 1.440 2007/07/20 16:22:07 mcguire
821 <rdar://problem/5344584> BTMM: Replace system() `ifconfig` calls to setup/teardown IPv6 address
822
823 Revision 1.439 2007/07/20 01:14:56 cheshire
824 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
825 Cleaned up log messages
826
827 Revision 1.438 2007/07/20 00:54:21 cheshire
828 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
829
830 Revision 1.437 2007/07/19 22:01:27 cheshire
831 Added "#pragma mark" sections headings to divide code into related function groups
832
833 Revision 1.436 2007/07/18 03:25:25 cheshire
834 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
835 Bring up server-side tunnel on demand, when necessary
836
837 Revision 1.435 2007/07/18 01:05:08 cheshire
838 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
839 Add list of client tunnels so we can automatically reconfigure when local address changes
840
841 Revision 1.434 2007/07/16 20:16:00 vazquez
842 <rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
843 Remove unnecessary LNT init code
844
845 Revision 1.433 2007/07/14 00:36:07 cheshire
846 Remove temporary IPv4LL tunneling mode now that IPv6-over-IPv4 is working
847
848 Revision 1.432 2007/07/12 23:55:11 cheshire
849 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
850 Don't need two separate DNSQuestion structures when looking up tunnel endpoint
851
852 Revision 1.431 2007/07/12 23:34:48 cheshire
853 Removed 'LogOperation' message to reduce verbosity in syslog
854
855 Revision 1.430 2007/07/12 22:16:46 cheshire
856 Improved "could not convert shared secret from base64" log message so it doesn't reveal key data in syslog
857
858 Revision 1.429 2007/07/12 02:51:28 cheshire
859 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
860
861 Revision 1.428 2007/07/11 23:17:31 cheshire
862 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
863 Improve log message to indicate if we're starting or restarting racoon
864
865 Revision 1.427 2007/07/11 22:50:30 cheshire
866 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
867 Write /etc/racoon/remote/anonymous.conf configuration file and start up /usr/sbin/racoon
868
869 Revision 1.426 2007/07/11 20:40:49 cheshire
870 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
871 In mDNSPlatformGetPrimaryInterface(), prefer routable IPv4 address to IPv4LL
872
873 Revision 1.425 2007/07/11 19:24:19 cheshire
874 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services
875 Configure internal AutoTunnel address
876 (For temporary testing we're faking up an IPv4LL address instead of IPv6 ULA, and we're
877 assigning it with "system(commandstring);" which probably isn't the most efficient way to do it)
878
879 Revision 1.424 2007/07/11 19:00:27 cheshire
880 Only need to set up m->AutoTunnelHostAddr first time through UpdateInterfaceList()
881
882 Revision 1.423 2007/07/11 03:00:59 cheshire
883 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
884 Add AutoTunnel parameter to mDNS_SetSecretForDomain; Generate IPv6 ULA address for tunnel endpoint
885
886 Revision 1.422 2007/07/10 01:21:20 cheshire
887 Added (commented out) line for displaying key data for debugging
888
889 Revision 1.421 2007/06/25 20:58:11 cheshire
890 <rdar://problem/5234463> Write the Multicast DNS domains to the DynamicStore
891 Additional refinement: Add mDNS domain list new new DynamicStore entity "State:/Network/MulticastDNS"
892
893 Revision 1.420 2007/06/22 21:52:14 cheshire
894 <rdar://problem/5234463> Write the Multicast DNS domains to the DynamicStore
895
896 Revision 1.419 2007/06/22 21:32:00 cheshire
897 <rdar://problem/5239020> Use SecKeychainCopyDefault instead of SecKeychainOpen
898
899 Revision 1.418 2007/06/21 16:37:43 jgraessley
900 Bug #: 5280520
901 Reviewed by: Stuart Cheshire
902 Additional changes to get this compiling on the embedded platform.
903
904 Revision 1.417 2007/06/20 01:44:00 cheshire
905 More information in "Network Configuration Change" message
906
907 Revision 1.416 2007/06/20 01:10:12 cheshire
908 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
909
910 Revision 1.415 2007/06/15 19:23:38 cheshire
911 <rdar://problem/5254053> mDNSResponder renames my host without asking
912 Improve log messages, to distinguish user-initiated renames from automatic (name conflict) renames
913
914 Revision 1.414 2007/05/17 22:00:59 cheshire
915 <rdar://problem/5210966> Lower network change delay from two seconds to one second
916
917 Revision 1.413 2007/05/16 16:43:27 cheshire
918 Only log "bind" failures for our shared mDNS port and for binding to zero
919 -- other attempts to bind to a particular port may legitimately fail
920
921 Revision 1.412 2007/05/15 21:49:21 cheshire
922 Get rid of "#pragma unused"
923
924 Revision 1.411 2007/05/14 23:54:55 cheshire
925 Instead of sprintf, use safer length-limited mDNS_snprintf
926
927 Revision 1.410 2007/05/12 01:05:00 cheshire
928 Updated debugging messages
929
930 Revision 1.409 2007/05/10 22:39:48 cheshire
931 <rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
932 Only define CountMaskBits for builds with debugging messages
933
934 Revision 1.408 2007/05/10 22:19:00 cheshire
935 <rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
936 Don't deliver multicast packets for which we can't find an associated InterfaceID
937
938 Revision 1.407 2007/05/10 21:40:28 cheshire
939 Don't log unnecessary "Address already in use" errors when joining multicast groups
940
941 Revision 1.406 2007/05/08 00:56:17 cheshire
942 <rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
943
944 Revision 1.405 2007/05/04 20:21:39 cheshire
945 Improve "connect failed" error message
946
947 Revision 1.404 2007/05/02 19:41:53 cheshire
948 No need to alarm people with "Connection reset by peer" syslog message
949
950 Revision 1.403 2007/04/28 01:31:59 cheshire
951 Improve debugging support for catching memory corruption problems
952
953 Revision 1.402 2007/04/26 22:54:57 cheshire
954 Debugging messages to help track down <rdar://problem/5164206> mDNSResponder takes 50%+ CPU
955
956 Revision 1.401 2007/04/26 00:35:16 cheshire
957 <rdar://problem/5140339> uDNS: Domain discovery not working over VPN
958 Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
959 inside the firewall may give answers where a public one gives none, and vice versa.)
960
961 Revision 1.400 2007/04/24 21:50:27 cheshire
962 Debugging: Show list of changedKeys in NetworkChanged callback
963
964 Revision 1.399 2007/04/23 22:28:47 cheshire
965 Allan Nathanson informs us we should only be looking at the search list for resolver[0], not all of them
966
967 Revision 1.398 2007/04/23 04:57:00 cheshire
968 Log messages for debugging <rdar://problem/4570952> IPv6 multicast not working properly
969
970 Revision 1.397 2007/04/22 06:02:03 cheshire
971 <rdar://problem/4615977> Query should immediately return failure when no server
972
973 Revision 1.396 2007/04/21 21:47:47 cheshire
974 <rdar://problem/4376383> Daemon: Add watchdog timer
975
976 Revision 1.395 2007/04/18 20:58:34 cheshire
977 <rdar://problem/5140339> Domain discovery not working over VPN
978 Needed different code to handle the case where there's only a single search domain
979
980 Revision 1.394 2007/04/17 23:05:50 cheshire
981 <rdar://problem/3957358> Shouldn't send domain queries when we have 169.254 or loopback address
982
983 Revision 1.393 2007/04/17 19:21:29 cheshire
984 <rdar://problem/5140339> Domain discovery not working over VPN
985
986 Revision 1.392 2007/04/17 17:15:09 cheshire
987 Change NO_CFUSERNOTIFICATION code so it still logs to syslog
988
989 Revision 1.391 2007/04/07 01:01:48 cheshire
990 <rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
991
992 Revision 1.390 2007/04/06 18:45:02 cheshire
993 Fix SetupActiveInterfaces() -- accidentally changed SetupSocket parameter
994
995 Revision 1.389 2007/04/05 21:39:49 cheshire
996 Debugging messages to help diagnose <rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
997
998 Revision 1.388 2007/04/05 21:09:52 cheshire
999 Condense sprawling code
1000
1001 Revision 1.387 2007/04/05 20:40:37 cheshire
1002 Remove unused mDNSPlatformTCPGetFlags()
1003
1004 Revision 1.386 2007/04/05 19:50:56 cheshire
1005 Fixed memory leak: GetCertChain() was not releasing cert returned by SecIdentityCopyCertificate()
1006
1007 Revision 1.385 2007/04/03 19:39:19 cheshire
1008 Fixed intel byte order bug in mDNSPlatformSetDNSServers()
1009
1010 Revision 1.384 2007/03/31 01:10:53 cheshire
1011 Add debugging
1012
1013 Revision 1.383 2007/03/31 00:13:48 cheshire
1014 Remove LogMsg
1015
1016 Revision 1.382 2007/03/28 21:01:29 cheshire
1017 <rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
1018
1019 Revision 1.381 2007/03/28 15:56:37 cheshire
1020 <rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
1021
1022 Revision 1.380 2007/03/26 22:54:46 cheshire
1023 Fix compile error
1024
1025 Revision 1.379 2007/03/22 18:31:48 cheshire
1026 Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
1027
1028 Revision 1.378 2007/03/22 00:49:20 cheshire
1029 <rdar://problem/4848295> Advertise model information via Bonjour
1030
1031 Revision 1.377 2007/03/21 00:30:05 cheshire
1032 <rdar://problem/4789455> Multiple errors in DNameList-related code
1033
1034 Revision 1.376 2007/03/20 17:07:15 cheshire
1035 Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
1036
1037 Revision 1.375 2007/03/20 00:50:57 cheshire
1038 <rdar://problem/4530644> Remove logic to disable IPv6 discovery on interfaces which have a routable IPv4 address
1039
1040 Revision 1.374 2007/03/06 23:29:50 cheshire
1041 <rdar://problem/4331696> Need to call IONotificationPortDestroy on shutdown
1042
1043 Revision 1.373 2007/02/28 01:51:20 cheshire
1044 Added comment about reverse-order IP address
1045
1046 Revision 1.372 2007/02/28 01:06:48 cheshire
1047 Use %#a format code instead of %d.%d.%d.%d
1048
1049 Revision 1.371 2007/02/08 21:12:28 cheshire
1050 <rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
1051
1052 Revision 1.370 2007/01/16 22:59:58 cheshire
1053 Error code ioErr is from wrong conceptual namespace; use errSSLClosedAbort instead
1054
1055 Revision 1.369 2007/01/10 02:09:32 cheshire
1056 Better LogOperation record of keys read from System Keychain
1057
1058 Revision 1.368 2007/01/10 01:25:31 cheshire
1059 Use symbol kDNSServiceCompPrivateDNS instead of fixed string "State:/Network/PrivateDNS"
1060
1061 Revision 1.367 2007/01/10 01:22:01 cheshire
1062 Make sure c1, c2, c3 are initialized
1063
1064 Revision 1.366 2007/01/09 22:37:20 cheshire
1065 Provide ten-second grace period for deleted keys, to give mDNSResponder
1066 time to delete host name before it gives up access to the required key.
1067
1068 Revision 1.365 2007/01/09 21:09:20 cheshire
1069 Need locking in KeychainChanged()
1070
1071 Revision 1.364 2007/01/09 20:17:04 cheshire
1072 mDNSPlatformGetDNSConfig() needs to initialize fields even when no "Setup:/Network/DynamicDNS" entity exists
1073
1074 Revision 1.363 2007/01/09 02:41:18 cheshire
1075 uDNS_SetupDNSConfig() shouldn't be called from mDNSMacOSX.c (platform support layer);
1076 moved it to mDNS_Init() in mDNS.c (core code)
1077
1078 Revision 1.362 2007/01/08 23:54:01 cheshire
1079 Made mDNSPlatformGetDNSConfig() more selective -- only reads prefs for non-null parameters
1080
1081 Revision 1.361 2007/01/05 08:30:48 cheshire
1082 Trim excessive "$Log" checkin history from before 2006
1083 (checkin history still available via "cvs log ..." of course)
1084
1085 Revision 1.360 2007/01/04 00:12:24 cheshire
1086 <rdar://problem/4742742> Read *all* DNS keys from keychain,
1087 not just key for the system-wide default registration domain
1088
1089 Revision 1.359 2006/12/22 21:14:37 cheshire
1090 Added comment explaining why we allow both "ddns" and "sndd" as valid item types
1091 The Keychain APIs on Intel appear to store the four-character item type backwards (at least some of the time)
1092
1093 Revision 1.358 2006/12/22 20:59:50 cheshire
1094 <rdar://problem/4742742> Read *all* DNS keys from keychain,
1095 not just key for the system-wide default registration domain
1096
1097 Revision 1.357 2006/12/21 00:09:45 cheshire
1098 Use mDNSPlatformMemZero instead of bzero
1099
1100 Revision 1.356 2006/12/20 23:15:53 mkrochma
1101 Fix the private domain list code so that it actually works
1102
1103 Revision 1.355 2006/12/20 23:04:36 mkrochma
1104 Fix crash when adding private domain list to Dynamic Store
1105
1106 Revision 1.354 2006/12/19 22:43:55 cheshire
1107 Fix compiler warnings
1108
1109 Revision 1.353 2006/12/14 22:08:29 cheshire
1110 Fixed memory leak: need to call SecKeychainItemFreeAttributesAndData()
1111 to release data allocated by SecKeychainItemCopyAttributesAndData()
1112
1113 Revision 1.352 2006/12/14 02:33:26 cheshire
1114 <rdar://problem/4841422> uDNS: Wide-area registrations sometimes fail
1115
1116 Revision 1.351 2006/11/28 21:37:51 mkrochma
1117 Tweak where the private DNS data is written
1118
1119 Revision 1.350 2006/11/28 07:55:02 herscher
1120 <rdar://problem/4742743> dnsextd has a slow memory leak
1121
1122 Revision 1.349 2006/11/28 07:45:58 herscher
1123 <rdar://problem/4787010> Daemon: Need to write list of private domain names to the DynamicStore
1124
1125 Revision 1.348 2006/11/16 21:47:20 mkrochma
1126 <rdar://problem/4841422> uDNS: Wide-area registrations sometimes fail
1127
1128 Revision 1.347 2006/11/10 00:54:16 cheshire
1129 <rdar://problem/4816598> Changing case of Computer Name doesn't work
1130
1131 Revision 1.346 2006/10/31 02:34:58 cheshire
1132 <rdar://problem/4692130> Stop creating HINFO records
1133
1134 Revision 1.345 2006/09/21 20:04:38 mkrochma
1135 Accidently changed function name while checking in previous fix
1136
1137 Revision 1.344 2006/09/21 19:04:13 mkrochma
1138 <rdar://problem/4733803> uDNS: Update keychain format of DNS key to include prefix
1139
1140 Revision 1.343 2006/09/15 21:20:16 cheshire
1141 Remove uDNS_info substructure from mDNS_struct
1142
1143 Revision 1.342 2006/08/16 00:31:50 mkrochma
1144 <rdar://problem/4386944> Get rid of NotAnInteger references
1145
1146 Revision 1.341 2006/08/14 23:24:40 cheshire
1147 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
1148
1149 Revision 1.340 2006/07/29 19:11:13 mkrochma
1150 Change GetUserSpecifiedDDNSConfig LogMsg to debugf
1151
1152 Revision 1.339 2006/07/27 03:24:35 cheshire
1153 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
1154 Further refinement: Declare KQueueEntry parameter "const"
1155
1156 Revision 1.338 2006/07/27 02:59:25 cheshire
1157 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
1158 Further refinements: CFRunLoop thread needs to explicitly wake the kqueue thread
1159 after releasing BigMutex, in case actions it took have resulted in new work for the
1160 kqueue thread (e.g. NetworkChanged events may result in the kqueue thread having to
1161 add new active interfaces to its list, and consequently schedule queries to be sent).
1162
1163 Revision 1.337 2006/07/22 06:11:37 cheshire
1164 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
1165
1166 Revision 1.336 2006/07/15 02:01:32 cheshire
1167 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1168 Fix broken "empty string" browsing
1169
1170 Revision 1.335 2006/07/14 05:25:11 cheshire
1171 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1172 Fixed crash in mDNSPlatformGetDNSConfig() reading BrowseDomains array
1173
1174 Revision 1.334 2006/07/05 23:42:00 cheshire
1175 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1176
1177 Revision 1.333 2006/06/29 05:33:30 cheshire
1178 <rdar://problem/4607043> mDNSResponder conditional compilation options
1179
1180 Revision 1.332 2006/06/28 09:10:36 cheshire
1181 Extra debugging messages
1182
1183 Revision 1.331 2006/06/21 22:29:42 cheshire
1184 Make _CFCopySystemVersionDictionary() call more defensive on systems that have no build information set
1185
1186 Revision 1.330 2006/06/20 23:06:00 cheshire
1187 Fix some keychain API type mismatches (was mDNSu32 instead of UInt32)
1188
1189 Revision 1.329 2006/06/08 23:22:33 cheshire
1190 Comment changes
1191
1192 Revision 1.328 2006/03/19 03:27:49 cheshire
1193 <rdar://problem/4118624> Suppress "interface flapping" logic for loopback
1194
1195 Revision 1.327 2006/03/19 02:00:09 cheshire
1196 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
1197
1198 Revision 1.326 2006/03/08 22:42:23 cheshire
1199 Fix spelling mistake: LocalReverseMapomain -> LocalReverseMapDomain
1200
1201 Revision 1.325 2006/01/10 00:39:17 cheshire
1202 Add comments explaining how IPv6 link-local addresses sometimes have an embedded scope_id
1203
1204 Revision 1.324 2006/01/09 19:28:59 cheshire
1205 <rdar://problem/4403128> Cap number of "sendto failed" messages we allow mDNSResponder to log
1206
1207 Revision 1.323 2006/01/05 21:45:27 cheshire
1208 <rdar://problem/4400118> Fix uninitialized structure member in IPv6 code
1209
1210 Revision 1.322 2006/01/05 21:41:50 cheshire
1211 <rdar://problem/4108164> Reword "mach_absolute_time went backwards" dialog
1212
1213 Revision 1.321 2006/01/05 21:35:06 cheshire
1214 Add (commented out) trigger value for testing "mach_absolute_time went backwards" notice
1215
1216 */
1217
1218 // ***************************************************************************
1219 // mDNSMacOSX.c:
1220 // Supporting routines to run mDNS on a CFRunLoop platform
1221 // ***************************************************************************
1222
1223 // For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
1224 // including ones that mDNSResponder chooses not to use.
1225 #define LIST_ALL_INTERFACES 0
1226
1227 // For enabling AAAA records over IPv4. Setting this to 0 sends only
1228 // A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both
1229 // AAAA and A records over both IPv4 and IPv6.
1230 #define AAAA_OVER_V4 1
1231
1232 // 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
1233 // IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
1234 // which means there's a good chance that most or all the other devices on that network should also have IPv4.
1235 // 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.
1236 // At that time, reducing the packet rate was more important than v6-only devices on a large configured network,
1237 // so were willing to make that sacrifice.
1238 // In Mac OS X 10.5, in 2007, two things have changed:
1239 // 1. IPv6-only devices are starting to become more common, so we can't ignore them.
1240 // 2. Other efficiency improvements in the code mean that crude hacks like this should no longer be necessary.
1241
1242 #define USE_V6_ONLY_WHEN_NO_ROUTABLE_V4 0
1243
1244 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
1245 #include "DNSCommon.h"
1246 #include "uDNS.h"
1247 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
1248 #include "dns_sd.h" // For mDNSInterface_LocalOnly etc.
1249 #include "PlatformCommon.h"
1250
1251 #include <stdio.h>
1252 #include <stdarg.h> // For va_list support
1253 #include <stdlib.h> // For arc4random
1254 #include <net/if.h>
1255 #include <net/if_types.h> // For IFT_ETHER
1256 #include <net/if_dl.h>
1257 #include <net/bpf.h> // For BIOCSETIF etc.
1258 #include <sys/uio.h>
1259 #include <sys/param.h>
1260 #include <sys/socket.h>
1261 #include <sys/sysctl.h>
1262 #include <sys/event.h>
1263 #include <fcntl.h>
1264 #include <sys/ioctl.h>
1265 #include <time.h> // platform support for UTC time
1266 #include <arpa/inet.h> // for inet_aton
1267 #include <pthread.h>
1268
1269 #include <netinet/in.h> // For IP_RECVTTL
1270 #ifndef IP_RECVTTL
1271 #define IP_RECVTTL 24 // bool; receive reception TTL w/dgram
1272 #endif
1273
1274 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
1275 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
1276 #include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
1277 #include <netinet6/nd6.h> // For ND6_INFINITE_LIFETIME etc.
1278
1279 #if TARGET_OS_EMBEDDED
1280 #define NO_SECURITYFRAMEWORK 1
1281 #define NO_CFUSERNOTIFICATION 1
1282 #endif
1283
1284 #ifndef NO_SECURITYFRAMEWORK
1285 #include <Security/SecureTransport.h>
1286 #include <Security/Security.h>
1287 #endif /* NO_SECURITYFRAMEWORK */
1288
1289 #include <DebugServices.h>
1290 #include "dnsinfo.h"
1291
1292 // Code contributed by Dave Heller:
1293 // Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
1294 // work on Mac OS X 10.1, which does not have the getifaddrs call.
1295 #define RUN_ON_PUMA_WITHOUT_IFADDRS 0
1296 #if RUN_ON_PUMA_WITHOUT_IFADDRS
1297 #include "mDNSMacOSXPuma.c"
1298 #else
1299 #include <ifaddrs.h>
1300 #endif
1301
1302 #include <IOKit/IOKitLib.h>
1303 #include <IOKit/IOMessage.h>
1304
1305 #if USE_IOPMCOPYACTIVEPMPREFERENCES
1306 #include <IOKit/ps/IOPowerSources.h>
1307 #include <IOKit/ps/IOPowerSourcesPrivate.h>
1308 #endif
1309
1310 #include <mach/mach_error.h>
1311 #include <mach/mach_port.h>
1312 #include <mach/mach_time.h>
1313 #include "helper.h"
1314
1315 #include <asl.h>
1316
1317 #define kInterfaceSpecificOption "interface="
1318
1319 // ***************************************************************************
1320 // Globals
1321
1322 #if COMPILER_LIKES_PRAGMA_MARK
1323 #pragma mark - Globals
1324 #endif
1325
1326 // By default we don't offer sleep proxy service
1327 // If OfferSleepProxyService is set non-zero (typically via command-line switch),
1328 // then we'll offer sleep proxy service on desktop Macs that are set to never sleep.
1329 // We currently do not offer sleep proxy service on laptops, or on machines that are set to go to sleep.
1330 mDNSexport int OfferSleepProxyService = 0;
1331
1332 mDNSexport int OSXVers;
1333 mDNSexport int KQueueFD;
1334
1335 #ifndef NO_SECURITYFRAMEWORK
1336 static CFArrayRef ServerCerts;
1337 #endif /* NO_SECURITYFRAMEWORK */
1338
1339 static CFStringRef NetworkChangedKey_IPv4;
1340 static CFStringRef NetworkChangedKey_IPv6;
1341 static CFStringRef NetworkChangedKey_Hostnames;
1342 static CFStringRef NetworkChangedKey_Computername;
1343 static CFStringRef NetworkChangedKey_DNS;
1344 static CFStringRef NetworkChangedKey_DynamicDNS = CFSTR("Setup:/Network/DynamicDNS");
1345 static CFStringRef NetworkChangedKey_BackToMyMac = CFSTR("Setup:/Network/BackToMyMac");
1346
1347 static char HINFO_HWstring_buffer[32];
1348 static char *HINFO_HWstring = "Device";
1349 static int HINFO_HWstring_prefixlen = 6;
1350
1351 mDNSexport int WatchDogReportingThreshold = 250;
1352
1353 #if APPLE_OSX_mDNSResponder
1354 static mDNSu8 SPMetricPortability = 99;
1355 static mDNSu8 SPMetricMarginalPower = 99;
1356 static mDNSu8 SPMetricTotalPower = 99;
1357 mDNSexport domainname ActiveDirectoryPrimaryDomain;
1358 mDNSexport int ActiveDirectoryPrimaryDomainLabelCount;
1359 mDNSexport mDNSAddr ActiveDirectoryPrimaryDomainServer;
1360 #endif // APPLE_OSX_mDNSResponder
1361
1362 // ***************************************************************************
1363 // Functions
1364
1365 #if COMPILER_LIKES_PRAGMA_MARK
1366 #pragma mark -
1367 #pragma mark - Utility Functions
1368 #endif
1369
1370 // We only attempt to send and receive multicast packets on interfaces that are
1371 // (a) flagged as multicast-capable
1372 // (b) *not* flagged as point-to-point (e.g. modem)
1373 // Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
1374 // to run up the user's bill sending multicast traffic over a link where there's only a single device at the
1375 // other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
1376 #define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
1377
1378 mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both strings are UTF-8 text
1379 {
1380 static int notifyCount = 0;
1381 if (notifyCount) return;
1382
1383 // If we display our alert early in the boot process, then it vanishes once the desktop appears.
1384 // To avoid this, we don't try to display alerts in the first three minutes after boot.
1385 if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return;
1386
1387 // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
1388 #if !ForceAlerts
1389 {
1390 // Determine if we're at Apple (17.*.*.*)
1391 extern mDNS mDNSStorage;
1392 NetworkInterfaceInfoOSX *i;
1393 for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
1394 if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && i->ifinfo.ip.ip.v4.b[0] == 17)
1395 break;
1396 if (!i) return; // If not at Apple, don't show the alert
1397 }
1398 #endif
1399
1400 LogMsg("%s", title);
1401 LogMsg("%s", msg);
1402 // Display a notification to the user
1403 notifyCount++;
1404
1405 #ifndef NO_CFUSERNOTIFICATION
1406 mDNSNotify(title, msg);
1407 #endif /* NO_CFUSERNOTIFICATION */
1408 }
1409
1410 mDNSlocal struct ifaddrs *myGetIfAddrs(int refresh)
1411 {
1412 static struct ifaddrs *ifa = NULL;
1413
1414 if (refresh && ifa)
1415 {
1416 freeifaddrs(ifa);
1417 ifa = NULL;
1418 }
1419
1420 if (ifa == NULL) getifaddrs(&ifa);
1421
1422 return ifa;
1423 }
1424
1425 // To match *either* a v4 or v6 instance of this interface name, pass AF_UNSPEC for type
1426 mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, const char *ifname, int type)
1427 {
1428 NetworkInterfaceInfoOSX *i;
1429 for (i = m->p->InterfaceList; i; i = i->next)
1430 if (i->Exists && !strcmp(i->ifinfo.ifname, ifname) &&
1431 ((type == AF_UNSPEC ) ||
1432 (type == AF_INET && i->ifinfo.ip.type == mDNSAddrType_IPv4) ||
1433 (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6))) return(i);
1434 return(NULL);
1435 }
1436
1437 mDNSlocal int myIfIndexToName(u_short ifindex, char *name)
1438 {
1439 struct ifaddrs *ifa;
1440 for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
1441 if (ifa->ifa_addr->sa_family == AF_LINK)
1442 if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == ifindex)
1443 { strlcpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; }
1444 return -1;
1445 }
1446
1447 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex)
1448 {
1449 NetworkInterfaceInfoOSX *i;
1450 if (ifindex == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
1451 if (ifindex == kDNSServiceInterfaceIndexAny ) return(mDNSNULL);
1452
1453 // Don't get tricked by inactive interfaces with no InterfaceID set
1454 for (i = m->p->InterfaceList; i; i = i->next)
1455 if (i->ifinfo.InterfaceID && i->scope_id == ifindex) return(i->ifinfo.InterfaceID);
1456
1457 // Not found. Make sure our interface list is up to date, then try again.
1458 LogInfo("InterfaceID for interface index %d not found; Updating interface list", ifindex);
1459 mDNSMacOSXNetworkChanged(m);
1460 for (i = m->p->InterfaceList; i; i = i->next)
1461 if (i->ifinfo.InterfaceID && i->scope_id == ifindex) return(i->ifinfo.InterfaceID);
1462
1463 return(mDNSNULL);
1464 }
1465
1466 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id)
1467 {
1468 NetworkInterfaceInfoOSX *i;
1469 if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
1470 if (id == mDNSInterface_Any ) return(0);
1471
1472 // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces, which have no InterfaceID set
1473 for (i = m->p->InterfaceList; i; i = i->next)
1474 if ((mDNSInterfaceID)i == id) return(i->scope_id);
1475
1476 // Not found. Make sure our interface list is up to date, then try again.
1477 LogInfo("Interface index for InterfaceID %p not found; Updating interface list", id);
1478 mDNSMacOSXNetworkChanged(m);
1479 for (i = m->p->InterfaceList; i; i = i->next)
1480 if ((mDNSInterfaceID)i == id) return(i->scope_id);
1481
1482 return(0);
1483 }
1484
1485 #if APPLE_OSX_mDNSResponder
1486 mDNSexport void mDNSASLLog(uuid_t *uuid, const char *subdomain, const char *result, const char *signature, const char *fmt, ...)
1487 {
1488 if (OSXVers < OSXVers_10_6_SnowLeopard) return;
1489
1490 static char buffer[512];
1491 aslmsg asl_msg = asl_new(ASL_TYPE_MSG);
1492
1493 if (!asl_msg) { LogMsg("mDNSASLLog: asl_new failed"); return; }
1494 if (uuid)
1495 {
1496 char uuidStr[36];
1497 uuid_unparse(*uuid, uuidStr);
1498 asl_set (asl_msg, "com.apple.message.uuid", uuidStr);
1499 }
1500
1501 static char domainBase[] = "com.apple.mDNSResponder.%s";
1502 mDNS_snprintf (buffer, sizeof(buffer), domainBase, subdomain);
1503 asl_set (asl_msg, "com.apple.message.domain", buffer);
1504
1505 if (result) asl_set(asl_msg, "com.apple.message.result", result);
1506 if (signature) asl_set(asl_msg, "com.apple.message.signature", signature);
1507
1508 va_list ptr;
1509 va_start(ptr,fmt);
1510 mDNS_vsnprintf(buffer, sizeof(buffer), fmt, ptr);
1511 va_end(ptr);
1512
1513 int old_filter = asl_set_filter(NULL,ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
1514 asl_log(NULL, asl_msg, ASL_LEVEL_DEBUG, "%s", buffer);
1515 asl_set_filter(NULL, old_filter);
1516 asl_free(asl_msg);
1517 }
1518 #endif
1519
1520 #if COMPILER_LIKES_PRAGMA_MARK
1521 #pragma mark -
1522 #pragma mark - UDP & TCP send & receive
1523 #endif
1524
1525 mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr)
1526 {
1527 mDNSBool result = mDNSfalse;
1528 SCNetworkConnectionFlags flags;
1529 SCNetworkReachabilityRef ReachRef = NULL;
1530
1531 ReachRef = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, addr);
1532 if (!ReachRef) { LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithAddress"); goto end; }
1533 if (!SCNetworkReachabilityGetFlags(ReachRef, &flags)) { LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags"); goto end; }
1534 result = flags & kSCNetworkFlagsConnectionRequired;
1535
1536 end:
1537 if (ReachRef) CFRelease(ReachRef);
1538 return result;
1539 }
1540
1541 // Note: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
1542 // Note: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
1543 // OR send via our primary v4 unicast socket
1544 // UPDATE: The UDPSocket *src parameter now allows the caller to specify the source socket
1545 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
1546 mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, mDNSIPPort dstPort)
1547 {
1548 // Note: For this platform we've adopted the convention that InterfaceIDs are secretly pointers
1549 // to the NetworkInterfaceInfoOSX structure that holds the active sockets. The mDNSCore code
1550 // doesn't know that and doesn't need to know that -- it just treats InterfaceIDs as opaque identifiers.
1551 NetworkInterfaceInfoOSX *info = (NetworkInterfaceInfoOSX *)InterfaceID;
1552 char *ifa_name = info ? info->ifinfo.ifname : "unicast";
1553 struct sockaddr_storage to;
1554 int s = -1, err;
1555 mStatus result = mStatus_NoError;
1556
1557 if (dst->type == mDNSAddrType_IPv4)
1558 {
1559 struct sockaddr_in *sin_to = (struct sockaddr_in*)&to;
1560 sin_to->sin_len = sizeof(*sin_to);
1561 sin_to->sin_family = AF_INET;
1562 sin_to->sin_port = dstPort.NotAnInteger;
1563 sin_to->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
1564 s = (src ? src->ss : m->p->permanentsockets).sktv4;
1565
1566 if (info) // Specify outgoing interface
1567 {
1568 if (!mDNSAddrIsDNSMulticast(dst))
1569 {
1570 #ifdef IP_BOUND_IF
1571 if (info->scope_id == 0)
1572 LogInfo("IP_BOUND_IF socket option not set -- info %p (%s) scope_id is zero", info, ifa_name);
1573 else
1574 setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
1575 #else
1576 {
1577 static int displayed = 0;
1578 if (displayed < 1000)
1579 {
1580 displayed++;
1581 LogInfo("IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets");
1582 }
1583 }
1584 #endif
1585 }
1586 else
1587 {
1588 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
1589 if (err < 0 && !m->p->NetworkChanged)
1590 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
1591 }
1592 }
1593 }
1594 else if (dst->type == mDNSAddrType_IPv6)
1595 {
1596 struct sockaddr_in6 *sin6_to = (struct sockaddr_in6*)&to;
1597 sin6_to->sin6_len = sizeof(*sin6_to);
1598 sin6_to->sin6_family = AF_INET6;
1599 sin6_to->sin6_port = dstPort.NotAnInteger;
1600 sin6_to->sin6_flowinfo = 0;
1601 sin6_to->sin6_addr = *(struct in6_addr*)&dst->ip.v6;
1602 sin6_to->sin6_scope_id = info ? info->scope_id : 0;
1603 s = (src ? src->ss : m->p->permanentsockets).sktv6;
1604 if (info && mDNSAddrIsDNSMulticast(dst)) // Specify outgoing interface
1605 {
1606 err = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &info->scope_id, sizeof(info->scope_id));
1607 if (err < 0) LogMsg("setsockopt - IPV6_MULTICAST_IF error %d errno %d (%s)", err, errno, strerror(errno));
1608 }
1609 }
1610 else
1611 {
1612 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
1613 #if ForceAlerts
1614 *(long*)0 = 0;
1615 #endif
1616 return mStatus_BadParamErr;
1617 }
1618
1619 if (s >= 0)
1620 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
1621 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s);
1622 else
1623 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
1624 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort));
1625
1626 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
1627 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
1628 if (s < 0) return(mStatus_Invalid);
1629
1630 err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len);
1631 if (err < 0)
1632 {
1633 static int MessageCount = 0;
1634 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
1635 if (!mDNSAddressIsAllDNSLinkGroup(dst))
1636 if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr);
1637 // Don't report EHOSTUNREACH in the first three minutes after boot
1638 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
1639 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
1640 if (errno == EHOSTUNREACH && (mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(mStatus_TransientErr);
1641 // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
1642 if (errno == EADDRNOTAVAIL && m->p->NetworkChanged) return(mStatus_TransientErr);
1643 if (MessageCount < 1000)
1644 {
1645 MessageCount++;
1646 if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
1647 LogInfo("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
1648 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
1649 else
1650 LogMsg("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
1651 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
1652 }
1653 result = mStatus_UnknownErr;
1654 }
1655
1656 #ifdef IP_BOUND_IF
1657 if (dst->type == mDNSAddrType_IPv4 && info && !mDNSAddrIsDNSMulticast(dst))
1658 {
1659 static const mDNSu32 ifindex = 0;
1660 setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &ifindex, sizeof(ifindex));
1661 }
1662 #endif
1663
1664 return(result);
1665 }
1666
1667 mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
1668 struct sockaddr *const from, size_t *const fromlen, mDNSAddr *dstaddr, char ifname[IF_NAMESIZE], mDNSu8 *ttl)
1669 {
1670 static unsigned int numLogMessages = 0;
1671 struct iovec databuffers = { (char *)buffer, max };
1672 struct msghdr msg;
1673 ssize_t n;
1674 struct cmsghdr *cmPtr;
1675 char ancillary[1024];
1676
1677 *ttl = 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
1678
1679 // Set up the message
1680 msg.msg_name = (caddr_t)from;
1681 msg.msg_namelen = *fromlen;
1682 msg.msg_iov = &databuffers;
1683 msg.msg_iovlen = 1;
1684 msg.msg_control = (caddr_t)&ancillary;
1685 msg.msg_controllen = sizeof(ancillary);
1686 msg.msg_flags = 0;
1687
1688 // Receive the data
1689 n = recvmsg(s, &msg, 0);
1690 if (n<0)
1691 {
1692 if (errno != EWOULDBLOCK && numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s, n, errno);
1693 return(-1);
1694 }
1695 if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
1696 {
1697 if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
1698 s, n, msg.msg_controllen, sizeof(struct cmsghdr));
1699 return(-1);
1700 }
1701 if (msg.msg_flags & MSG_CTRUNC)
1702 {
1703 if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
1704 return(-1);
1705 }
1706
1707 *fromlen = msg.msg_namelen;
1708
1709 // Parse each option out of the ancillary data.
1710 for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
1711 {
1712 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
1713 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVDSTADDR)
1714 {
1715 dstaddr->type = mDNSAddrType_IPv4;
1716 dstaddr->ip.v4 = *(mDNSv4Addr*)CMSG_DATA(cmPtr);
1717 //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
1718 }
1719 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF)
1720 {
1721 struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr);
1722 if (sdl->sdl_nlen < IF_NAMESIZE)
1723 {
1724 mDNSPlatformMemCopy(ifname, sdl->sdl_data, sdl->sdl_nlen);
1725 ifname[sdl->sdl_nlen] = 0;
1726 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
1727 }
1728 }
1729 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVTTL)
1730 *ttl = *(u_char*)CMSG_DATA(cmPtr);
1731 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_PKTINFO)
1732 {
1733 struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmPtr);
1734 dstaddr->type = mDNSAddrType_IPv6;
1735 dstaddr->ip.v6 = *(mDNSv6Addr*)&ip6_info->ipi6_addr;
1736 myIfIndexToName(ip6_info->ipi6_ifindex, ifname);
1737 }
1738 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT)
1739 *ttl = *(int*)CMSG_DATA(cmPtr);
1740 }
1741
1742 return(n);
1743 }
1744
1745 mDNSlocal void myKQSocketCallBack(int s1, short filter, void *context)
1746 {
1747 KQSocketSet *const ss = (KQSocketSet *)context;
1748 mDNS *const m = ss->m;
1749 int err = 0, count = 0, closed = 0;
1750
1751 if (filter != EVFILT_READ)
1752 LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter, EVFILT_READ);
1753
1754 if (s1 != ss->sktv4 && s1 != ss->sktv6)
1755 {
1756 LogMsg("myKQSocketCallBack: native socket %d", s1);
1757 LogMsg("myKQSocketCallBack: sktv4 %d", ss->sktv4);
1758 LogMsg("myKQSocketCallBack: sktv6 %d", ss->sktv6);
1759 }
1760
1761 while (!closed)
1762 {
1763 mDNSAddr senderAddr, destAddr;
1764 mDNSIPPort senderPort;
1765 struct sockaddr_storage from;
1766 size_t fromlen = sizeof(from);
1767 char packetifname[IF_NAMESIZE] = "";
1768 mDNSu8 ttl;
1769 err = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl);
1770 if (err < 0) break;
1771
1772 count++;
1773 if (from.ss_family == AF_INET)
1774 {
1775 struct sockaddr_in *s = (struct sockaddr_in*)&from;
1776 senderAddr.type = mDNSAddrType_IPv4;
1777 senderAddr.ip.v4.NotAnInteger = s->sin_addr.s_addr;
1778 senderPort.NotAnInteger = s->sin_port;
1779 //LogInfo("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1780 }
1781 else if (from.ss_family == AF_INET6)
1782 {
1783 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&from;
1784 senderAddr.type = mDNSAddrType_IPv6;
1785 senderAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
1786 senderPort.NotAnInteger = sin6->sin6_port;
1787 //LogInfo("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1788 }
1789 else
1790 {
1791 LogMsg("myKQSocketCallBack from is unknown address family %d", from.ss_family);
1792 return;
1793 }
1794
1795 // Note: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
1796 mDNSInterfaceID InterfaceID = mDNSNULL;
1797 NetworkInterfaceInfo *intf = m->HostInterfaces;
1798 while (intf && strcmp(intf->ifname, packetifname)) intf = intf->next;
1799 // When going to sleep we deregister all our interfaces, but if the machine
1800 // takes a few seconds to sleep we may continue to receive multicasts
1801 // during that time, which would confuse mDNSCoreReceive, because as far
1802 // as it's concerned, we should have no active interfaces any more.
1803 // Hence we ignore multicasts for which we can find no matching InterfaceID.
1804 if (intf) InterfaceID = intf->InterfaceID;
1805 else if (mDNSAddrIsDNSMulticast(&destAddr)) continue;
1806
1807 // LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
1808 // &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
1809
1810 // mDNSCoreReceive may close the socket we're reading from. We must break out of our
1811 // loop when that happens, or we may try to read from an invalid FD. We do this by
1812 // setting the closeFlag pointer in the socketset, so CloseSocketSet can inform us
1813 // if it closes the socketset.
1814 ss->closeFlag = &closed;
1815
1816 mDNSCoreReceive(m, &m->imsg, (unsigned char*)&m->imsg + err, &senderAddr, senderPort, &destAddr, ss->port, InterfaceID);
1817
1818 // if we didn't close, we can safely dereference the socketset, and should to
1819 // reset the closeFlag, since it points to something on the stack
1820 if (!closed) ss->closeFlag = mDNSNULL;
1821 }
1822
1823 if (err < 0 && (errno != EWOULDBLOCK || count == 0))
1824 {
1825 // Something is busted here.
1826 // kqueue says there is a packet, but myrecvfrom says there is not.
1827 // Try calling select() to get another opinion.
1828 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
1829 // All of this is racy, as data may have arrived after the call to select()
1830 static unsigned int numLogMessages = 0;
1831 int save_errno = errno;
1832 int so_error = -1;
1833 int so_nread = -1;
1834 int fionread = -1;
1835 socklen_t solen = sizeof(int);
1836 fd_set readfds;
1837 struct timeval timeout;
1838 int selectresult;
1839 FD_ZERO(&readfds);
1840 FD_SET(s1, &readfds);
1841 timeout.tv_sec = 0;
1842 timeout.tv_usec = 0;
1843 selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
1844 if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1)
1845 LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno);
1846 if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1)
1847 LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno);
1848 if (ioctl(s1, FIONREAD, &fionread) == -1)
1849 LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno);
1850 if (numLogMessages++ < 100)
1851 LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
1852 s1, err, save_errno, strerror(save_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
1853 if (numLogMessages > 5)
1854 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
1855 "Congratulations, you've reproduced an elusive bug.\r"
1856 "Please contact the current assignee of <rdar://problem/3375328>.\r"
1857 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
1858 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1859
1860 sleep(1); // After logging this error, rate limit so we don't flood syslog
1861 }
1862 }
1863
1864 // TCP socket support
1865
1866 typedef enum
1867 {
1868 handshake_required,
1869 handshake_in_progress,
1870 handshake_completed,
1871 handshake_to_be_closed
1872 } handshakeStatus;
1873
1874 struct TCPSocket_struct
1875 {
1876 TCPSocketFlags flags; // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
1877 TCPConnectionCallback callback;
1878 int fd;
1879 KQueueEntry kqEntry;
1880 #ifndef NO_SECURITYFRAMEWORK
1881 SSLContextRef tlsContext;
1882 pthread_t handshake_thread;
1883 #endif /* NO_SECURITYFRAMEWORK */
1884 void *context;
1885 mDNSBool setup;
1886 mDNSBool connected;
1887 handshakeStatus handshake;
1888 mDNS *m; // So we can call KQueueLock from the SSLHandshake thread
1889 mStatus err;
1890 };
1891
1892 mDNSlocal void doTcpSocketCallback(TCPSocket *sock)
1893 {
1894 mDNSBool c = !sock->connected;
1895 sock->connected = mDNStrue;
1896 sock->callback(sock, sock->context, c, sock->err);
1897 // Note: the callback may call CloseConnection here, which frees the context structure!
1898 }
1899
1900 #ifndef NO_SECURITYFRAMEWORK
1901
1902 mDNSlocal OSStatus tlsWriteSock(SSLConnectionRef connection, const void *data, size_t *dataLength)
1903 {
1904 int ret = send(((TCPSocket *)connection)->fd, data, *dataLength, 0);
1905 if (ret >= 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
1906 if (ret >= 0) { *dataLength = ret; return(noErr); }
1907 *dataLength = 0;
1908 if (errno == EAGAIN ) return(errSSLWouldBlock);
1909 if (errno == ENOENT ) return(errSSLClosedGraceful);
1910 if (errno == EPIPE || errno == ECONNRESET) return(errSSLClosedAbort);
1911 LogMsg("ERROR: tlsWriteSock: %d error %d (%s)\n", ((TCPSocket *)connection)->fd, errno, strerror(errno));
1912 return(errSSLClosedAbort);
1913 }
1914
1915 mDNSlocal OSStatus tlsReadSock(SSLConnectionRef connection, void *data, size_t *dataLength)
1916 {
1917 int ret = recv(((TCPSocket *)connection)->fd, data, *dataLength, 0);
1918 if (ret > 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
1919 if (ret > 0) { *dataLength = ret; return(noErr); }
1920 *dataLength = 0;
1921 if (ret == 0 || errno == ENOENT ) return(errSSLClosedGraceful);
1922 if ( errno == EAGAIN ) return(errSSLWouldBlock);
1923 if ( errno == ECONNRESET) return(errSSLClosedAbort);
1924 LogMsg("ERROR: tlsSockRead: error %d (%s)\n", errno, strerror(errno));
1925 return(errSSLClosedAbort);
1926 }
1927
1928 mDNSlocal OSStatus tlsSetupSock(TCPSocket *sock, mDNSBool server)
1929 {
1930 mStatus err = SSLNewContext(server, &sock->tlsContext);
1931 if (err) { LogMsg("ERROR: tlsSetupSock: SSLNewContext failed with error code: %d", err); return(err); }
1932
1933 err = SSLSetIOFuncs(sock->tlsContext, tlsReadSock, tlsWriteSock);
1934 if (err) { LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err); return(err); }
1935
1936 err = SSLSetConnection(sock->tlsContext, (SSLConnectionRef) sock);
1937 if (err) { LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err); return(err); }
1938
1939 return(err);
1940 }
1941
1942 mDNSlocal void *doSSLHandshake(void *ctx)
1943 {
1944 // Warning: Touching sock without the kqueue lock!
1945 // We're protected because sock->handshake == handshake_in_progress
1946 TCPSocket *sock = (TCPSocket*)ctx;
1947 mDNS * const m = sock->m; // Get m now, as we may free sock if marked to be closed while we're waiting on SSLHandshake
1948 mStatus err = SSLHandshake(sock->tlsContext);
1949
1950 KQueueLock(m);
1951 LogInfo("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
1952
1953 if (sock->handshake == handshake_to_be_closed)
1954 {
1955 LogInfo("SSLHandshake completed after close");
1956 mDNSPlatformTCPCloseConnection(sock);
1957 }
1958 else
1959 {
1960 if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry);
1961 else LogMsg("doSSLHandshake: sock->fd is -1");
1962
1963 if (err == errSSLWouldBlock)
1964 sock->handshake = handshake_required;
1965 else
1966 {
1967 if (err)
1968 {
1969 LogMsg("SSLHandshake failed: %d", err);
1970 SSLDisposeContext(sock->tlsContext);
1971 sock->tlsContext = NULL;
1972 }
1973
1974 sock->err = err;
1975 sock->handshake = handshake_completed;
1976
1977 LogInfo("doSSLHandshake: %p calling doTcpSocketCallback", sock);
1978 doTcpSocketCallback(sock);
1979 }
1980 }
1981
1982 LogInfo("SSLHandshake %p: dropping lock", sock);
1983 KQueueUnlock(m, "doSSLHandshake");
1984 return NULL;
1985 }
1986
1987 mDNSlocal mStatus spawnSSLHandshake(TCPSocket* sock)
1988 {
1989 LogInfo("spawnSSLHandshake %p: entry", sock);
1990 if (sock->handshake != handshake_required) LogMsg("spawnSSLHandshake: handshake status not required: %d", sock->handshake);
1991 sock->handshake = handshake_in_progress;
1992 KQueueSet(sock->fd, EV_DELETE, EVFILT_READ, &sock->kqEntry);
1993 pthread_attr_t attr;
1994 pthread_attr_init(&attr);
1995 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1996 mStatus err = pthread_create(&sock->handshake_thread, &attr, doSSLHandshake, sock);
1997 pthread_attr_destroy(&attr);
1998 if (err)
1999 {
2000 LogMsg("Could not start SSLHandshake thread: (%d) %s", err, strerror(err));
2001 sock->handshake = handshake_completed;
2002 sock->err = err;
2003 KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry);
2004 }
2005 LogInfo("spawnSSLHandshake %p: done", sock);
2006 return err;
2007 }
2008
2009 mDNSlocal mDNSBool IsTunnelModeDomain(const domainname *d)
2010 {
2011 static const domainname *mmc = (const domainname*) "\x7" "members" "\x3" "mac" "\x3" "com";
2012 const domainname *d1 = mDNSNULL; // TLD
2013 const domainname *d2 = mDNSNULL; // SLD
2014 const domainname *d3 = mDNSNULL;
2015 while (d->c[0]) { d3 = d2; d2 = d1; d1 = d; d = (const domainname*)(d->c + 1 + d->c[0]); }
2016 return(d3 && SameDomainName(d3, mmc));
2017 }
2018
2019 #endif /* NO_SECURITYFRAMEWORK */
2020
2021 mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context)
2022 {
2023 TCPSocket *sock = context;
2024 sock->err = mStatus_NoError;
2025
2026 //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
2027 //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
2028 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
2029 if (filter == EVFILT_WRITE) KQueueSet(sock->fd, EV_DELETE, EVFILT_WRITE, &sock->kqEntry);
2030
2031 if (sock->flags & kTCPSocketFlags_UseTLS)
2032 {
2033 #ifndef NO_SECURITYFRAMEWORK
2034 if (!sock->setup) { sock->setup = mDNStrue; tlsSetupSock(sock, mDNSfalse); }
2035
2036 if (sock->handshake == handshake_required) { if (spawnSSLHandshake(sock) == 0) return; }
2037 else if (sock->handshake == handshake_in_progress || sock->handshake == handshake_to_be_closed) return;
2038 else if (sock->handshake != handshake_completed)
2039 {
2040 if (!sock->err) sock->err = mStatus_UnknownErr;
2041 LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock->handshake);
2042 }
2043 #else
2044 sock->err = mStatus_UnsupportedErr;
2045 #endif /* NO_SECURITYFRAMEWORK */
2046 }
2047
2048 doTcpSocketCallback(sock);
2049 }
2050
2051 mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef)
2052 {
2053 struct kevent new_event;
2054 EV_SET(&new_event, fd, filter, flags, 0, 0, (void*)entryRef);
2055 return (kevent(KQueueFD, &new_event, 1, NULL, 0, NULL) < 0) ? errno : 0;
2056 }
2057
2058 mDNSexport void KQueueLock(mDNS *const m)
2059 {
2060 pthread_mutex_lock(&m->p->BigMutex);
2061 m->p->BigMutexStartTime = mDNSPlatformRawTime();
2062 }
2063
2064 mDNSexport void KQueueUnlock(mDNS *const m, const char const *task)
2065 {
2066 mDNSs32 end = mDNSPlatformRawTime();
2067 (void)task;
2068 if (end - m->p->BigMutexStartTime >= WatchDogReportingThreshold)
2069 LogInfo("WARNING: %s took %dms to complete", task, end - m->p->BigMutexStartTime);
2070
2071 pthread_mutex_unlock(&m->p->BigMutex);
2072
2073 char wake = 1;
2074 if (send(m->p->WakeKQueueLoopFD, &wake, sizeof(wake), 0) == -1)
2075 LogMsg("ERROR: KQueueWake: send failed with error code: %d (%s)", errno, strerror(errno));
2076 }
2077
2078 mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port)
2079 {
2080 (void) m;
2081
2082 TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket));
2083 if (!sock) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL); }
2084
2085 mDNSPlatformMemZero(sock, sizeof(TCPSocket));
2086 sock->callback = mDNSNULL;
2087 sock->fd = socket(AF_INET, SOCK_STREAM, 0);
2088 sock->kqEntry.KQcallback= tcpKQSocketCallback;
2089 sock->kqEntry.KQcontext = sock;
2090 sock->kqEntry.KQtask = "mDNSPlatformTCPSocket";
2091 sock->flags = flags;
2092 sock->context = mDNSNULL;
2093 sock->setup = mDNSfalse;
2094 sock->connected = mDNSfalse;
2095 sock->handshake = handshake_required;
2096 sock->m = m;
2097 sock->err = mStatus_NoError;
2098
2099 if (sock->fd == -1)
2100 {
2101 LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock->fd, errno, strerror(errno));
2102 freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
2103 return(mDNSNULL);
2104 }
2105
2106 // Bind it
2107 struct sockaddr_in addr;
2108 mDNSPlatformMemZero(&addr, sizeof(addr));
2109 addr.sin_family = AF_INET;
2110 addr.sin_addr.s_addr = htonl(INADDR_ANY);
2111 addr.sin_port = port->NotAnInteger;
2112 if (bind(sock->fd, (struct sockaddr*) &addr, sizeof(addr)) < 0)
2113 { LogMsg("ERROR: bind %s", strerror(errno)); goto error; }
2114
2115 // Receive interface identifiers
2116 const int on = 1; // "on" for setsockopt
2117 if (setsockopt(sock->fd, IPPROTO_IP, IP_RECVIF, &on, sizeof(on)) < 0)
2118 { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); goto error; }
2119
2120 mDNSPlatformMemZero(&addr, sizeof(addr));
2121 socklen_t len = sizeof(addr);
2122 if (getsockname(sock->fd, (struct sockaddr*) &addr, &len) < 0)
2123 { LogMsg("getsockname - %s", strerror(errno)); goto error; }
2124
2125 port->NotAnInteger = addr.sin_port;
2126 return sock;
2127
2128 error:
2129 close(sock->fd);
2130 freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
2131 return(mDNSNULL);
2132 }
2133
2134 mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
2135 TCPConnectionCallback callback, void *context)
2136 {
2137 struct sockaddr_in saddr;
2138 mStatus err = mStatus_NoError;
2139
2140 sock->callback = callback;
2141 sock->context = context;
2142 sock->setup = mDNSfalse;
2143 sock->connected = mDNSfalse;
2144 sock->handshake = handshake_required;
2145 sock->err = mStatus_NoError;
2146
2147 (void) InterfaceID; //!!!KRS use this if non-zero!!!
2148
2149 if (dst->type != mDNSAddrType_IPv4)
2150 {
2151 LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: opperation not supported");
2152 return mStatus_UnknownErr;
2153 }
2154
2155 mDNSPlatformMemZero(&saddr, sizeof(saddr));
2156 saddr.sin_family = AF_INET;
2157 saddr.sin_port = dstport.NotAnInteger;
2158 saddr.sin_len = sizeof(saddr);
2159 saddr.sin_addr.s_addr = dst->ip.v4.NotAnInteger;
2160
2161 sock->kqEntry.KQcallback = tcpKQSocketCallback;
2162 sock->kqEntry.KQcontext = sock;
2163 sock->kqEntry.KQtask = "Outgoing TCP";
2164
2165 // Watch for connect complete (write is ready)
2166 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
2167 if (KQueueSet(sock->fd, EV_ADD /* | EV_ONESHOT */, EVFILT_WRITE, &sock->kqEntry))
2168 {
2169 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
2170 close(sock->fd);
2171 return errno;
2172 }
2173
2174 // Watch for incoming data
2175 if (KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry))
2176 {
2177 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
2178 close(sock->fd); // Closing the descriptor removes all filters from the kqueue
2179 return errno;
2180 }
2181
2182 if (fcntl(sock->fd, F_SETFL, fcntl(sock->fd, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
2183 {
2184 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno));
2185 return mStatus_UnknownErr;
2186 }
2187
2188 // initiate connection wth peer
2189 if (connect(sock->fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
2190 {
2191 if (errno == EINPROGRESS) return mStatus_ConnPending;
2192 if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
2193 LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock->fd, errno, strerror(errno));
2194 else
2195 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock->fd, errno, strerror(errno));
2196 close(sock->fd);
2197 return mStatus_ConnFailed;
2198 }
2199
2200 LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
2201 // kQueue should notify us, but this LogMsg is to help track down if it doesn't
2202 return err;
2203 }
2204
2205 // Why doesn't mDNSPlatformTCPAccept actually call accept() ?
2206 mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
2207 {
2208 mStatus err = mStatus_NoError;
2209
2210 TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket));
2211 if (!sock) return(mDNSNULL);
2212
2213 mDNSPlatformMemZero(sock, sizeof(*sock));
2214 sock->fd = fd;
2215 sock->flags = flags;
2216
2217 if (flags & kTCPSocketFlags_UseTLS)
2218 {
2219 #ifndef NO_SECURITYFRAMEWORK
2220 if (!ServerCerts) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err = mStatus_UnknownErr; goto exit; }
2221
2222 err = tlsSetupSock(sock, mDNStrue);
2223 if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err); goto exit; }
2224
2225 err = SSLSetCertificate(sock->tlsContext, ServerCerts);
2226 if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err); goto exit; }
2227 #else
2228 err = mStatus_UnsupportedErr;
2229 #endif /* NO_SECURITYFRAMEWORK */
2230 }
2231 #ifndef NO_SECURITYFRAMEWORK
2232 exit:
2233 #endif
2234
2235 if (err) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock); return(mDNSNULL); }
2236 return(sock);
2237 }
2238
2239 mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
2240 {
2241 if (sock)
2242 {
2243 #ifndef NO_SECURITYFRAMEWORK
2244 if (sock->tlsContext)
2245 {
2246 if (sock->handshake == handshake_in_progress) // SSLHandshake thread using this sock (esp. tlsContext)
2247 {
2248 LogInfo("mDNSPlatformTCPCloseConnection: called while handshake in progress");
2249 sock->handshake = handshake_to_be_closed;
2250 }
2251 if (sock->handshake == handshake_to_be_closed)
2252 return;
2253
2254 SSLClose(sock->tlsContext);
2255 SSLDisposeContext(sock->tlsContext);
2256 sock->tlsContext = NULL;
2257 }
2258 #endif /* NO_SECURITYFRAMEWORK */
2259 if (sock->fd != -1)
2260 {
2261 shutdown(sock->fd, 2);
2262 close(sock->fd);
2263 sock->fd = -1;
2264 }
2265
2266 freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock);
2267 }
2268 }
2269
2270 mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed)
2271 {
2272 long nread = 0;
2273 *closed = mDNSfalse;
2274
2275 if (sock->flags & kTCPSocketFlags_UseTLS)
2276 {
2277 #ifndef NO_SECURITYFRAMEWORK
2278 if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformReadTCP called while handshake required"); return 0; }
2279 else if (sock->handshake == handshake_in_progress) return 0;
2280 else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformReadTCP called with unexpected SSLHandshake status: %d", sock->handshake);
2281
2282 //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
2283 mStatus err = SSLRead(sock->tlsContext, buf, buflen, (size_t*)&nread);
2284 //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
2285 if (err == errSSLClosedGraceful) { nread = 0; *closed = mDNStrue; }
2286 else if (err && err != errSSLWouldBlock)
2287 { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err); nread = -1; *closed = mDNStrue; }
2288 #else
2289 nread = -1;
2290 *closed = mDNStrue;
2291 #endif /* NO_SECURITYFRAMEWORK */
2292 }
2293 else
2294 {
2295 static int CLOSEDcount = 0;
2296 static int EAGAINcount = 0;
2297 nread = recv(sock->fd, buf, buflen, 0);
2298
2299 if (nread > 0) { CLOSEDcount = 0; EAGAINcount = 0; } // On success, clear our error counters
2300 else if (nread == 0)
2301 {
2302 *closed = mDNStrue;
2303 if ((++CLOSEDcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock->fd, CLOSEDcount); sleep(1); }
2304 }
2305 // else nread is negative -- see what kind of error we got
2306 else if (errno == ECONNRESET) { nread = 0; *closed = mDNStrue; }
2307 else if (errno != EAGAIN) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d (%s)", errno, strerror(errno)); nread = -1; }
2308 else // errno is EAGAIN (EWOULDBLOCK) -- no data available
2309 {
2310 nread = 0;
2311 if ((++EAGAINcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock->fd, EAGAINcount); sleep(1); }
2312 }
2313 }
2314
2315 return nread;
2316 }
2317
2318 mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
2319 {
2320 int nsent;
2321
2322 if (sock->flags & kTCPSocketFlags_UseTLS)
2323 {
2324 #ifndef NO_SECURITYFRAMEWORK
2325 size_t processed;
2326 if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformWriteTCP called while handshake required"); return 0; }
2327 if (sock->handshake == handshake_in_progress) return 0;
2328 else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformWriteTCP called with unexpected SSLHandshake status: %d", sock->handshake);
2329
2330 mStatus err = SSLWrite(sock->tlsContext, msg, len, &processed);
2331
2332 if (!err) nsent = (int) processed;
2333 else if (err == errSSLWouldBlock) nsent = 0;
2334 else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err); nsent = -1; }
2335 #else
2336 nsent = -1;
2337 #endif /* NO_SECURITYFRAMEWORK */
2338 }
2339 else
2340 {
2341 nsent = send(sock->fd, msg, len, 0);
2342 if (nsent < 0)
2343 {
2344 if (errno == EAGAIN) nsent = 0;
2345 else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno)); nsent = -1; }
2346 }
2347 }
2348
2349 return nsent;
2350 }
2351
2352 mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
2353 {
2354 return sock->fd;
2355 }
2356
2357 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
2358 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
2359 mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family, mDNSIPPort *const outport)
2360 {
2361 int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
2362 KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
2363 const int on = 1;
2364 const int twofivefive = 255;
2365 mStatus err = mStatus_NoError;
2366 char *errstr = mDNSNULL;
2367
2368 cp->closeFlag = mDNSNULL;
2369
2370 int skt = socket(sa_family, SOCK_DGRAM, IPPROTO_UDP);
2371 if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno)); return(skt); }
2372
2373 // ... with a shared UDP port, if it's for multicast receiving
2374 if (mDNSSameIPPort(port, MulticastDNSPort) || mDNSSameIPPort(port, NATPMPAnnouncementPort)) err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
2375 if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; }
2376
2377 if (sa_family == AF_INET)
2378 {
2379 // We want to receive destination addresses
2380 err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
2381 if (err < 0) { errstr = "setsockopt - IP_RECVDSTADDR"; goto fail; }
2382
2383 // We want to receive interface identifiers
2384 err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
2385 if (err < 0) { errstr = "setsockopt - IP_RECVIF"; goto fail; }
2386
2387 // We want to receive packet TTL value so we can check it
2388 err = setsockopt(skt, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on));
2389 // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
2390
2391 // Send unicast packets with TTL 255
2392 err = setsockopt(skt, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive));
2393 if (err < 0) { errstr = "setsockopt - IP_TTL"; goto fail; }
2394
2395 // And multicast packets with TTL 255 too
2396 err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive));
2397 if (err < 0) { errstr = "setsockopt - IP_MULTICAST_TTL"; goto fail; }
2398
2399 // And start listening for packets
2400 struct sockaddr_in listening_sockaddr;
2401 listening_sockaddr.sin_family = AF_INET;
2402 listening_sockaddr.sin_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping
2403 listening_sockaddr.sin_addr.s_addr = mDNSSameIPPort(port, NATPMPAnnouncementPort) ? AllSystemsMcast.NotAnInteger : 0;
2404 err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr));
2405 if (err) { errstr = "bind"; goto fail; }
2406 if (outport) outport->NotAnInteger = listening_sockaddr.sin_port;
2407 }
2408 else if (sa_family == AF_INET6)
2409 {
2410 // NAT-PMP Announcements make no sense on IPv6, so bail early w/o error
2411 if (mDNSSameIPPort(port, NATPMPAnnouncementPort)) { if (outport) *outport = zeroIPPort; return mStatus_NoError; }
2412
2413 // We want to receive destination addresses and receive interface identifiers
2414 err = setsockopt(skt, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on));
2415 if (err < 0) { errstr = "setsockopt - IPV6_PKTINFO"; goto fail; }
2416
2417 // We want to receive packet hop count value so we can check it
2418 err = setsockopt(skt, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof(on));
2419 if (err < 0) { errstr = "setsockopt - IPV6_HOPLIMIT"; goto fail; }
2420
2421 // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
2422 // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
2423 err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
2424 if (err < 0) { errstr = "setsockopt - IPV6_V6ONLY"; goto fail; }
2425
2426 // Send unicast packets with TTL 255
2427 err = setsockopt(skt, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &twofivefive, sizeof(twofivefive));
2428 if (err < 0) { errstr = "setsockopt - IPV6_UNICAST_HOPS"; goto fail; }
2429
2430 // And multicast packets with TTL 255 too
2431 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive));
2432 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_HOPS"; goto fail; }
2433
2434 // Want to receive our own packets
2435 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on));
2436 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_LOOP"; goto fail; }
2437
2438 // And start listening for packets
2439 struct sockaddr_in6 listening_sockaddr6;
2440 mDNSPlatformMemZero(&listening_sockaddr6, sizeof(listening_sockaddr6));
2441 listening_sockaddr6.sin6_len = sizeof(listening_sockaddr6);
2442 listening_sockaddr6.sin6_family = AF_INET6;
2443 listening_sockaddr6.sin6_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping
2444 listening_sockaddr6.sin6_flowinfo = 0;
2445 listening_sockaddr6.sin6_addr = in6addr_any; // Want to receive multicasts AND unicasts on this socket
2446 listening_sockaddr6.sin6_scope_id = 0;
2447 err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6));
2448 if (err) { errstr = "bind"; goto fail; }
2449 if (outport) outport->NotAnInteger = listening_sockaddr6.sin6_port;
2450 }
2451
2452 fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
2453 fcntl(skt, F_SETFD, 1); // set close-on-exec
2454 *s = skt;
2455 k->KQcallback = myKQSocketCallBack;
2456 k->KQcontext = cp;
2457 k->KQtask = "UDP packet reception";
2458 KQueueSet(*s, EV_ADD, EVFILT_READ, k);
2459
2460 return(err);
2461
2462 fail:
2463 // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
2464 if (strcmp(errstr, "bind") || mDNSSameIPPort(port, MulticastDNSPort) || mDNSIPPortIsZero(port))
2465 LogMsg("%s skt %d port %d error %d errno %d (%s)", errstr, skt, mDNSVal16(port), err, errno, strerror(errno));
2466
2467 // If we got a "bind" failure of EADDRINUSE, inform the caller as it might need to try another random port
2468 if (!strcmp(errstr, "bind") && errno == EADDRINUSE)
2469 {
2470 err = EADDRINUSE;
2471 if (mDNSSameIPPort(port, MulticastDNSPort))
2472 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
2473 "Congratulations, you've reproduced an elusive bug.\r"
2474 "Please contact the current assignee of <rdar://problem/3814904>.\r"
2475 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
2476 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
2477 }
2478
2479 close(skt);
2480 return(err);
2481 }
2482
2483 mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport)
2484 {
2485 mStatus err;
2486 mDNSIPPort port = requestedport;
2487 mDNSBool randomizePort = mDNSIPPortIsZero(requestedport);
2488 int i = 10000; // Try at most 10000 times to get a unique random port
2489 UDPSocket *p = mallocL("UDPSocket", sizeof(UDPSocket));
2490 if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); }
2491 mDNSPlatformMemZero(p, sizeof(UDPSocket));
2492 p->ss.port = zeroIPPort;
2493 p->ss.m = m;
2494 p->ss.sktv4 = -1;
2495 p->ss.sktv6 = -1;
2496
2497 do
2498 {
2499 // The kernel doesn't do cryptographically strong random port allocation, so we do it ourselves here
2500 if (randomizePort) port = mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF));
2501 err = SetupSocket(&p->ss, port, AF_INET, &p->ss.port);
2502 if (!err)
2503 {
2504 err = SetupSocket(&p->ss, port, AF_INET6, &p->ss.port);
2505 if (err) { close(p->ss.sktv4); p->ss.sktv4 = -1; }
2506 }
2507 i--;
2508 } while (err == EADDRINUSE && randomizePort && i);
2509
2510 if (err)
2511 {
2512 // In customer builds we don't want to log failures with port 5351, because this is a known issue
2513 // of failing to bind to this port when Internet Sharing has already bound to it
2514 // We also don't want to log about port 5350, due to a known bug when some other
2515 // process is bound to it.
2516 if (mDNSSameIPPort(requestedport, NATPMPPort) || mDNSSameIPPort(requestedport, NATPMPAnnouncementPort))
2517 LogInfo("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
2518 else LogMsg("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
2519 freeL("UDPSocket", p);
2520 return(mDNSNULL);
2521 }
2522 return(p);
2523 }
2524
2525 mDNSlocal void CloseSocketSet(KQSocketSet *ss)
2526 {
2527 if (ss->sktv4 != -1)
2528 {
2529 close(ss->sktv4);
2530 ss->sktv4 = -1;
2531 }
2532 if (ss->sktv6 != -1)
2533 {
2534 close(ss->sktv6);
2535 ss->sktv6 = -1;
2536 }
2537 if (ss->closeFlag) *ss->closeFlag = 1;
2538 }
2539
2540 mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
2541 {
2542 CloseSocketSet(&sock->ss);
2543 freeL("UDPSocket", sock);
2544 }
2545
2546 #if COMPILER_LIKES_PRAGMA_MARK
2547 #pragma mark -
2548 #pragma mark - BPF Raw packet sending/receiving
2549 #endif
2550
2551 #if APPLE_OSX_mDNSResponder
2552
2553 mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
2554 {
2555 if (!InterfaceID) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; }
2556 NetworkInterfaceInfoOSX *info = (NetworkInterfaceInfoOSX *)InterfaceID;
2557 if (info->BPF_fd < 0)
2558 LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info->ifinfo.ifname, info->BPF_fd);
2559 else
2560 {
2561 //LogMsg("mDNSPlatformSendRawPacket %d bytes on %s", end - (mDNSu8 *)msg, info->ifinfo.ifname);
2562 if (write(info->BPF_fd, msg, end - (mDNSu8 *)msg) < 0)
2563 LogMsg("mDNSPlatformSendRawPacket: BPF write(%d) failed %d (%s)", info->BPF_fd, errno, strerror(errno));
2564 }
2565 }
2566
2567 mDNSexport void mDNSPlatformSetLocalARP(const mDNSv4Addr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
2568 {
2569 if (!InterfaceID) { LogMsg("mDNSPlatformSetLocalARP: No InterfaceID specified"); return; }
2570 NetworkInterfaceInfoOSX *info = (NetworkInterfaceInfoOSX *)InterfaceID;
2571 // Manually inject an entry into our local ARP cache.
2572 // (We can't do this by sending an ARP broadcast, because the kernel only pays attention to incoming ARP packets, not outgoing.)
2573 mDNSBool makearp = mDNSv4AddressIsLinkLocal(tpa);
2574 if (!makearp)
2575 {
2576 NetworkInterfaceInfoOSX *i;
2577 for (i = info->m->p->InterfaceList; i; i = i->next)
2578 if (i->Exists && i->ifinfo.InterfaceID == InterfaceID && i->ifinfo.ip.type == mDNSAddrType_IPv4)
2579 if (((i->ifinfo.ip.ip.v4.NotAnInteger ^ tpa->NotAnInteger) & i->ifinfo.mask.ip.v4.NotAnInteger) == 0)
2580 makearp = mDNStrue;
2581 }
2582 if (!makearp)
2583 LogInfo("Don't need ARP entry for %s %.4a %.6a", info->ifinfo.ifname, tpa, tha);
2584 else
2585 {
2586 int result = mDNSSetARP(info->scope_id, tpa->b, tha->b);
2587 if (result) LogMsg("Set local ARP entry for %s %.4a %.6a failed: %d", info->ifinfo.ifname, tpa, tha, result);
2588 else debugf ("Set local ARP entry for %s %.4a %.6a", info->ifinfo.ifname, tpa, tha);
2589 }
2590 }
2591
2592 mDNSlocal void CloseBPF(NetworkInterfaceInfoOSX *const i)
2593 {
2594 LogSPS("%s closing BPF fd %d", i->ifinfo.ifname, i->BPF_fd);
2595
2596 // Note: MUST NOT close() the underlying native BSD sockets.
2597 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, because
2598 // it first has to unhook the sockets from its select() call on its other thread, before it can safely close them.
2599 CFRunLoopRemoveSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode);
2600 CFRelease(i->BPF_rls);
2601 CFSocketInvalidate(i->BPF_cfs);
2602 CFRelease(i->BPF_cfs);
2603 i->BPF_fd = -1;
2604 }
2605
2606 mDNSlocal void bpf_callback(const CFSocketRef cfs, const CFSocketCallBackType CallBackType, const CFDataRef address, const void *const data, void *const context)
2607 {
2608 (void)cfs;
2609 (void)CallBackType;
2610 (void)address;
2611 (void)data;
2612
2613 NetworkInterfaceInfoOSX *const info = (NetworkInterfaceInfoOSX *)context;
2614 KQueueLock(info->m);
2615
2616 // Now we've got the lock, make sure the kqueue thread didn't close the fd out from under us (will not be a problem once the OS X
2617 // kernel has a mechanism for dispatching all events to a single thread, but for now we have to guard against this race condition).
2618 if (info->BPF_fd < 0) goto exit;
2619
2620 ssize_t n = read(info->BPF_fd, &info->m->imsg, info->BPF_len);
2621 const mDNSu8 *ptr = (const mDNSu8 *)&info->m->imsg;
2622 const mDNSu8 *end = (const mDNSu8 *)&info->m->imsg + n;
2623 debugf("%3d: bpf_callback got %d bytes on %s", info->BPF_fd, n, info->ifinfo.ifname);
2624
2625 if (n<0)
2626 {
2627 LogMsg("Closing %s BPF fd %d due to error %d (%s)", info->ifinfo.ifname, info->BPF_fd, errno, strerror(errno));
2628 CloseBPF(info);
2629 goto exit;
2630 }
2631
2632 while (ptr < end)
2633 {
2634 const struct bpf_hdr *bh = (const struct bpf_hdr *)ptr;
2635 debugf("%3d: bpf_callback bh_caplen %4d bh_datalen %4d remaining %4d", info->BPF_fd, bh->bh_caplen, bh->bh_datalen, end - (ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen)));
2636 mDNSCoreReceiveRawPacket(info->m, ptr + bh->bh_hdrlen, ptr + bh->bh_hdrlen + bh->bh_caplen, info->ifinfo.InterfaceID);
2637 ptr += BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen);
2638 }
2639 exit:
2640 KQueueUnlock(info->m, "bpf_callback");
2641 }
2642
2643 #define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from)
2644
2645 mDNSlocal int CountProxyTargets(mDNS *const m, NetworkInterfaceInfoOSX *x, int *p4, int *p6)
2646 {
2647 int numv4 = 0, numv6 = 0;
2648 AuthRecord *rr;
2649
2650 for (rr = m->ResourceRecords; rr; rr=rr->next)
2651 if (rr->resrec.InterfaceID == (mDNSInterfaceID)x && rr->AddressProxy.type == mDNSAddrType_IPv4)
2652 {
2653 if (p4) LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s IP%2d %.4a", x->BPF_fd, x->ifinfo.ifname, numv4, &rr->AddressProxy.ip.v4);
2654 numv4++;
2655 }
2656
2657 for (rr = m->ResourceRecords; rr; rr=rr->next)
2658 if (rr->resrec.InterfaceID == (mDNSInterfaceID)x && rr->AddressProxy.type == mDNSAddrType_IPv6)
2659 {
2660 if (p6) LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s IP%2d %.16a", x->BPF_fd, x->ifinfo.ifname, numv6, &rr->AddressProxy.ip.v6);
2661 numv6++;
2662 }
2663
2664 if (p4) *p4 = numv4;
2665 if (p6) *p6 = numv6;
2666 return(numv4 + numv6);
2667 }
2668
2669 mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
2670 {
2671 NetworkInterfaceInfoOSX *x;
2672 for (x = m->p->InterfaceList; x; x = x->next) if (x == (NetworkInterfaceInfoOSX *)InterfaceID) break;
2673 if (!x) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID); return; }
2674
2675 #define MAX_BPF_ADDRS 250
2676 int numv4 = 0, numv6 = 0;
2677
2678 if (CountProxyTargets(m, x, &numv4, &numv6) > MAX_BPF_ADDRS)
2679 {
2680 LogMsg("mDNSPlatformUpdateProxyList: ERROR Too many address proxy records v4 %d v6 %d", numv4, numv6);
2681 if (numv4 > MAX_BPF_ADDRS) numv4 = MAX_BPF_ADDRS;
2682 numv6 = MAX_BPF_ADDRS - numv4;
2683 }
2684
2685 LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s MAC %.6a %d v4 %d v6", x->BPF_fd, x->ifinfo.ifname, &x->ifinfo.MAC, numv4, numv6);
2686
2687 // Caution: This is a static structure, so we need to be careful that any modifications we make to it
2688 // are done in such a way that they work correctly when mDNSPlatformUpdateProxyList is called multiple times
2689 static struct bpf_insn filter[17 + MAX_BPF_ADDRS] =
2690 {
2691 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), // 0 Read Ethertype (bytes 12,13)
2692
2693 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0806, 0, 1), // 1 If Ethertype == ARP goto next, else 3
2694 BPF_STMT(BPF_RET + BPF_K, 42), // 2 Return 42-byte ARP
2695
2696 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0800, 4, 0), // 3 If Ethertype == IPv4 goto 8 (IPv4 address list check) else next
2697
2698 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x86DD, 0, 9), // 4 If Ethertype == IPv6 goto next, else exit
2699 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), // 5 Read Protocol and Hop Limit (bytes 20,21)
2700 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x3AFF, 0, 9), // 6 If (Prot,TTL) == (3A,FF) goto next, else IPv6 address list check
2701 BPF_STMT(BPF_RET + BPF_K, 78), // 7 Return 78-byte ND
2702
2703 // Is IPv4 packet; check if it's addressed to any IPv4 address we're proxying for
2704 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 30), // 8 Read IPv4 Dst (bytes 30,31,32,33)
2705 };
2706
2707 struct bpf_insn *pc = &filter[9];
2708 struct bpf_insn *chk6 = pc + numv4 + 1; // numv4 address checks, plus a "return 0"
2709 struct bpf_insn *fail = chk6 + 1 + numv6; // Get v6 Dst LSW, plus numv6 address checks
2710 struct bpf_insn *ret4 = fail + 1;
2711 struct bpf_insn *ret6 = ret4 + 4;
2712
2713 static const struct bpf_insn rf = BPF_STMT(BPF_RET + BPF_K, 0); // No match: Return nothing
2714
2715 static const struct bpf_insn g6 = BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 50); // Read IPv6 Dst LSW (bytes 50,51,52,53)
2716
2717 static const struct bpf_insn r4a = BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14); // Get IP Header length (normally 20)
2718 static const struct bpf_insn r4b = BPF_STMT(BPF_LD + BPF_IMM, 34); // A = 34 (14-byte Ethernet plus 20-byte TCP)
2719 static const struct bpf_insn r4c = BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0); // A += IP Header length
2720 static const struct bpf_insn r4d = BPF_STMT(BPF_RET + BPF_A, 0); // Success: Return Ethernet + IP + TCP
2721
2722 static const struct bpf_insn r6a = BPF_STMT(BPF_RET + BPF_K, 94); // Success: Return Eth + IPv6 + TCP + 20 bytes spare
2723
2724 BPF_SetOffset(&filter[4], jf, fail); // If Ethertype not ARP, IPv4, or IPv6, fail
2725 BPF_SetOffset(&filter[6], jf, chk6); // If IPv6 but not ICMPv6, go to IPv6 address list check
2726
2727 // BPF Byte-Order Note
2728 // The BPF API designers apparently thought that programmers would not be smart enough to use htons
2729 // and htonl correctly to convert numeric values to network byte order on little-endian machines,
2730 // so instead they chose to make the API implicitly byte-swap *ALL* values, even literal byte strings
2731 // that shouldn't be byte-swapped, like ASCII text, Ethernet addresses, IP addresses, etc.
2732 // As a result, if we put Ethernet addresses and IP addresses in the right byte order, the BPF API
2733 // will byte-swap and make them backwards, and then our filter won't work. So, we have to arrange
2734 // that on little-endian machines we deliberately put addresses in memory with the bytes backwards,
2735 // so that when the BPF API goes through and swaps them all, they end up back as they should be.
2736 // In summary, if we byte-swap all the non-numeric fields that shouldn't be swapped, and we *don't*
2737 // swap any of the numeric values that *should* be byte-swapped, then the filter will work correctly.
2738
2739 AuthRecord *rr;
2740 for (rr = m->ResourceRecords; rr; rr=rr->next)
2741 if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
2742 {
2743 mDNSv4Addr a = rr->AddressProxy.ip.v4;
2744 pc->code = BPF_JMP + BPF_JEQ + BPF_K;
2745 BPF_SetOffset(pc, jt, ret4);
2746 pc->jf = 0;
2747 pc->k = (bpf_u_int32)a.b[0] << 24 | (bpf_u_int32)a.b[1] << 16 | (bpf_u_int32)a.b[2] << 8 | (bpf_u_int32)a.b[3];
2748 pc++;
2749 }
2750 *pc++ = rf;
2751
2752 if (pc != chk6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc, chk6);
2753 *pc++ = g6; // chk6 points here
2754
2755 for (rr = m->ResourceRecords; rr; rr=rr->next)
2756 if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
2757 {
2758 mDNSv6Addr a = rr->AddressProxy.ip.v6;
2759 pc->code = BPF_JMP + BPF_JEQ + BPF_K;
2760 BPF_SetOffset(pc, jt, ret6);
2761 pc->jf = 0;
2762 pc->k = (bpf_u_int32)a.b[12] << 24 | (bpf_u_int32)a.b[13] << 16 | (bpf_u_int32)a.b[14] << 8 | (bpf_u_int32)a.b[15];
2763 pc++;
2764 }
2765
2766 if (pc != fail) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc, fail);
2767 *pc++ = rf; // fail points here
2768
2769 if (pc != ret4) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc, ret4);
2770 *pc++ = r4a; // ret4 points here
2771 *pc++ = r4b;
2772 *pc++ = r4c;
2773 *pc++ = r4d;
2774
2775 if (pc != ret6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc, ret6);
2776 *pc++ = r6a; // ret6 points here
2777
2778 struct bpf_program prog = { pc - filter, filter };
2779
2780 #if 0
2781 // For debugging BPF filter program
2782 unsigned int q;
2783 for (q=0; q<prog.bf_len; q++)
2784 LogSPS("mDNSPlatformUpdateProxyList: %2d { 0x%02x, %d, %d, 0x%08x },", q, prog.bf_insns[q].code, prog.bf_insns[q].jt, prog.bf_insns[q].jf, prog.bf_insns[q].k);
2785 #endif
2786
2787 if (!numv4 && !numv6)
2788 {
2789 LogSPS("mDNSPlatformUpdateProxyList: No need for filter");
2790 if (m->timenow == 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0");
2791 // Schedule check to see if we can close this BPF_fd now
2792 if (!m->p->NetworkChanged) m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
2793 // prog.bf_len = 0; This seems to panic the kernel
2794 }
2795
2796 if (ioctl(x->BPF_fd, BIOCSETF, &prog) < 0) LogMsg("mDNSPlatformUpdateProxyList: BIOCSETF(%d) failed %d (%s)", prog.bf_len, errno, strerror(errno));
2797 else LogSPS("mDNSPlatformUpdateProxyList: BIOCSETF(%d) successful", prog.bf_len);
2798 }
2799
2800 mDNSexport void mDNSPlatformReceiveBPF_fd(mDNS *const m, int fd)
2801 {
2802 mDNS_Lock(m);
2803
2804 NetworkInterfaceInfoOSX *i;
2805 for (i = m->p->InterfaceList; i; i = i->next) if (i->BPF_fd == -2) break;
2806 if (!i) { LogSPS("mDNSPlatformReceiveBPF_fd: No Interfaces awaiting BPF fd %d; closing", fd); close(fd); }
2807 else
2808 {
2809 LogSPS("%s using BPF fd %d", i->ifinfo.ifname, fd);
2810
2811 struct bpf_version v;
2812 if (ioctl(fd, BIOCVERSION, &v) < 0)
2813 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2814 else if (BPF_MAJOR_VERSION != v.bv_major || BPF_MINOR_VERSION != v.bv_minor)
2815 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION header %d.%d kernel %d.%d",
2816 fd, i->ifinfo.ifname, BPF_MAJOR_VERSION, BPF_MINOR_VERSION, v.bv_major, v.bv_minor);
2817
2818 if (ioctl(fd, BIOCGBLEN, &i->BPF_len) < 0)
2819 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCGBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2820
2821 if (i->BPF_len > sizeof(m->imsg))
2822 {
2823 i->BPF_len = sizeof(m->imsg);
2824 if (ioctl(fd, BIOCSBLEN, &i->BPF_len) < 0)
2825 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2826 else LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", i->BPF_len);
2827 }
2828
2829 static const u_int opt_immediate = 1;
2830 if (ioctl(fd, BIOCIMMEDIATE, &opt_immediate) < 0)
2831 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCIMMEDIATE failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
2832
2833 struct ifreq ifr;
2834 mDNSPlatformMemZero(&ifr, sizeof(ifr));
2835 strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
2836 if (ioctl(fd, BIOCSETIF, &ifr) < 0)
2837 { LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSETIF failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); i->BPF_fd = -3; }
2838 else
2839 {
2840 CFSocketContext myCFSocketContext = { 0, i, NULL, NULL, NULL };
2841 i->BPF_fd = fd;
2842 i->BPF_cfs = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack, bpf_callback, &myCFSocketContext);
2843 i->BPF_rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, i->BPF_cfs, 0);
2844 CFRunLoopAddSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode);
2845 mDNSPlatformUpdateProxyList(m, (mDNSInterfaceID)i);
2846 }
2847 }
2848
2849 mDNS_Unlock(m);
2850 }
2851
2852 #endif // APPLE_OSX_mDNSResponder
2853
2854 #if COMPILER_LIKES_PRAGMA_MARK
2855 #pragma mark -
2856 #pragma mark - Key Management
2857 #endif
2858
2859 #ifndef NO_SECURITYFRAMEWORK
2860 mDNSlocal CFArrayRef GetCertChain(SecIdentityRef identity)
2861 {
2862 CFMutableArrayRef certChain = NULL;
2863 if (!identity) { LogMsg("getCertChain: identity is NULL"); return(NULL); }
2864 SecCertificateRef cert;
2865 OSStatus err = SecIdentityCopyCertificate(identity, &cert);
2866 if (err || !cert) LogMsg("getCertChain: SecIdentityCopyCertificate() returned %d", (int) err);
2867 else
2868 {
2869 SecPolicySearchRef searchRef;
2870 err = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef);
2871 if (err || !searchRef) LogMsg("getCertChain: SecPolicySearchCreate() returned %d", (int) err);
2872 else
2873 {
2874 SecPolicyRef policy;
2875 err = SecPolicySearchCopyNext(searchRef, &policy);
2876 if (err || !policy) LogMsg("getCertChain: SecPolicySearchCopyNext() returned %d", (int) err);
2877 else
2878 {
2879 CFArrayRef wrappedCert = CFArrayCreate(NULL, (const void**) &cert, 1, &kCFTypeArrayCallBacks);
2880 if (!wrappedCert) LogMsg("getCertChain: wrappedCert is NULL");
2881 else
2882 {
2883 SecTrustRef trust;
2884 err = SecTrustCreateWithCertificates(wrappedCert, policy, &trust);
2885 if (err || !trust) LogMsg("getCertChain: SecTrustCreateWithCertificates() returned %d", (int) err);
2886 else
2887 {
2888 err = SecTrustEvaluate(trust, NULL);
2889 if (err) LogMsg("getCertChain: SecTrustEvaluate() returned %d", (int) err);
2890 else
2891 {
2892 CFArrayRef rawCertChain;
2893 CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
2894 err = SecTrustGetResult(trust, NULL, &rawCertChain, &statusChain);
2895 if (err || !rawCertChain || !statusChain) LogMsg("getCertChain: SecTrustGetResult() returned %d", (int) err);
2896 else
2897 {
2898 certChain = CFArrayCreateMutableCopy(NULL, 0, rawCertChain);
2899 if (!certChain) LogMsg("getCertChain: certChain is NULL");
2900 else
2901 {
2902 // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
2903 // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
2904 CFArraySetValueAtIndex(certChain, 0, identity);
2905 // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
2906 if (CFArrayGetCount(certChain) > 1) CFArrayRemoveValueAtIndex(certChain, CFArrayGetCount(certChain) - 1);
2907 }
2908 CFRelease(rawCertChain);
2909 // Do not free statusChain:
2910 // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
2911 // certChain: Call the CFRelease function to release this object when you are finished with it.
2912 // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
2913 }
2914 }
2915 CFRelease(trust);
2916 }
2917 CFRelease(wrappedCert);
2918 }
2919 CFRelease(policy);
2920 }
2921 CFRelease(searchRef);
2922 }
2923 CFRelease(cert);
2924 }
2925 return certChain;
2926 }
2927 #endif /* NO_SECURITYFRAMEWORK */
2928
2929 mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
2930 {
2931 #ifdef NO_SECURITYFRAMEWORK
2932 return mStatus_UnsupportedErr;
2933 #else
2934 SecIdentityRef identity = nil;
2935 SecIdentitySearchRef srchRef = nil;
2936 OSStatus err;
2937
2938 // search for "any" identity matching specified key use
2939 // In this app, we expect there to be exactly one
2940 err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_DECRYPT, &srchRef);
2941 if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err); return err; }
2942
2943 err = SecIdentitySearchCopyNext(srchRef, &identity);
2944 if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err); return err; }
2945
2946 if (CFGetTypeID(identity) != SecIdentityGetTypeID())
2947 { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr; }
2948
2949 // Found one. Call getCertChain to create the correct certificate chain.
2950 ServerCerts = GetCertChain(identity);
2951 if (ServerCerts == nil) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: getCertChain error"); return mStatus_UnknownErr; }
2952
2953 return mStatus_NoError;
2954 #endif /* NO_SECURITYFRAMEWORK */
2955 }
2956
2957 mDNSexport void mDNSPlatformTLSTearDownCerts(void)
2958 {
2959 #ifndef NO_SECURITYFRAMEWORK
2960 if (ServerCerts) { CFRelease(ServerCerts); ServerCerts = NULL; }
2961 #endif /* NO_SECURITYFRAMEWORK */
2962 }
2963
2964 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
2965 mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
2966 {
2967 CFStringEncoding encoding = kCFStringEncodingUTF8;
2968 CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
2969 if (cfs)
2970 {
2971 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
2972 CFRelease(cfs);
2973 }
2974 }
2975
2976 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
2977 mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel)
2978 {
2979 CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
2980 if (cfs)
2981 {
2982 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
2983 CFRelease(cfs);
2984 }
2985 }
2986
2987 mDNSexport mDNSBool DictionaryIsEnabled(CFDictionaryRef dict)
2988 {
2989 mDNSs32 val;
2990 CFNumberRef state = CFDictionaryGetValue(dict, CFSTR("Enabled"));
2991 if (!state) return mDNSfalse;
2992 if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val))
2993 { LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse; }
2994 return val ? mDNStrue : mDNSfalse;
2995 }
2996
2997 mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
2998 {
2999 if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
3000
3001 if (sa->sa_family == AF_INET)
3002 {
3003 struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
3004 ip->type = mDNSAddrType_IPv4;
3005 ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
3006 return(mStatus_NoError);
3007 }
3008
3009 if (sa->sa_family == AF_INET6)
3010 {
3011 struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
3012 // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
3013 // value into the second word of the IPv6 link-local address, so they can just
3014 // pass around IPv6 address structures instead of full sockaddr_in6 structures.
3015 // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
3016 // To work around this we always whack the second word of any IPv6 link-local address back to zero.
3017 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
3018 ip->type = mDNSAddrType_IPv6;
3019 ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
3020 return(mStatus_NoError);
3021 }
3022
3023 LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
3024 return(mStatus_Invalid);
3025 }
3026
3027 mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name)
3028 {
3029 mDNSEthAddr eth = zeroEthAddr;
3030 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetBSSID"), NULL, NULL);
3031 if (!store)
3032 LogMsg("GetBSSID: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
3033 else
3034 {
3035 CFStringRef entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name);
3036 if (entityname)
3037 {
3038 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, entityname);
3039 if (dict)
3040 {
3041 CFRange range = { 0, 6 }; // Offset, length
3042 CFDataRef data = CFDictionaryGetValue(dict, CFSTR("BSSID"));
3043 if (data && CFDataGetLength(data) == 6) CFDataGetBytes(data, range, eth.b);
3044 CFRelease(dict);
3045 }
3046 CFRelease(entityname);
3047 }
3048 CFRelease(store);
3049 }
3050 return(eth);
3051 }
3052
3053 mDNSlocal int GetMAC(mDNSEthAddr *eth, u_short ifindex)
3054 {
3055 struct ifaddrs *ifa;
3056 for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
3057 if (ifa->ifa_addr->sa_family == AF_LINK)
3058 {
3059 const struct sockaddr_dl *const sdl = (const struct sockaddr_dl *)ifa->ifa_addr;
3060 if (sdl->sdl_index == ifindex)
3061 { mDNSPlatformMemCopy(eth->b, sdl->sdl_data + sdl->sdl_nlen, 6); return 0; }
3062 }
3063 *eth = zeroEthAddr;
3064 return -1;
3065 }
3066
3067 #ifndef SIOCGIFWAKEFLAGS
3068 #define SIOCGIFWAKEFLAGS _IOWR('i', 136, struct ifreq) /* get interface wake property flags */
3069 #endif
3070
3071 #ifndef IF_WAKE_ON_MAGIC_PACKET
3072 #define IF_WAKE_ON_MAGIC_PACKET 0x01
3073 #endif
3074
3075 #ifndef ifr_wake_flags
3076 #define ifr_wake_flags ifr_ifru.ifru_intval
3077 #endif
3078
3079 mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i)
3080 {
3081 if (!MulticastInterface(i) ) return(mDNSfalse); // We only use Sleep Proxy Service on multicast-capable interfaces
3082 if (i->ifa_flags & IFF_LOOPBACK) return(mDNSfalse); // except loopback
3083
3084 int s = socket(AF_INET, SOCK_DGRAM, 0);
3085 if (s < 0) { LogMsg("NetWakeInterface %s socket failed %s errno %d (%s)", i->ifinfo.ifname, errno, strerror(errno)); return(mDNSfalse); }
3086
3087 struct ifreq ifr;
3088 strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
3089 if (ioctl(s, SIOCGIFWAKEFLAGS, &ifr) < 0)
3090 {
3091 // For some strange reason, in /usr/include/sys/errno.h, EOPNOTSUPP is defined to be
3092 // 102 when compiling kernel code, and 45 when compiling user-level code. Since this
3093 // error code is being returned from the kernel, we need to use the kernel version.
3094 #define KERNEL_EOPNOTSUPP 102
3095 if (errno != KERNEL_EOPNOTSUPP) // "Operation not supported on socket", the expected result on Leopard and earlier
3096 LogMsg("NetWakeInterface SIOCGIFWAKEFLAGS %s errno %d (%s)", i->ifinfo.ifname, errno, strerror(errno));
3097 // If on Leopard or earlier, we get EOPNOTSUPP, so in that case
3098 // we enable WOL if this interface is not AirPort and "Wake for Network access" is turned on.
3099 ifr.ifr_wake_flags = (errno == KERNEL_EOPNOTSUPP && !(i)->BSSID.l[0] && i->m->SystemWakeOnLANEnabled) ? IF_WAKE_ON_MAGIC_PACKET : 0;
3100 }
3101 #if ASSUME_SNOWLEOPARD_INCORRECTLY_REPORTS_AIRPORT_INCAPABLE_OF_WAKE_ON_LAN
3102 else
3103 {
3104 // Call succeeded.
3105 // However, on SnowLeopard, it currently indicates incorrectly that AirPort is incapable of Wake-on-LAN.
3106 // Therefore, for AirPort interfaces, we just track the system-wide Wake-on-LAN setting.
3107 if ((i)->BSSID.l[0]) ifr.ifr_wake_flags = i->m->SystemWakeOnLANEnabled ? IF_WAKE_ON_MAGIC_PACKET : 0;
3108 }
3109 #endif
3110
3111 close(s);
3112
3113 // ifr.ifr_wake_flags = IF_WAKE_ON_MAGIC_PACKET; // For testing with MacBook Air, using a USB dongle that doesn't actually support Wake-On-LAN
3114
3115 LogSPS("%-6s %#-14a %s WOMP", i->ifinfo.ifname, &i->ifinfo.ip, (ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) ? "supports" : "no");
3116
3117 return((ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) != 0);
3118 }
3119
3120 // Returns pointer to newly created NetworkInterfaceInfoOSX object, or
3121 // pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
3122 // may return NULL if out of memory (unlikely) or parameters are invalid for some reason
3123 // (e.g. sa_family not AF_INET or AF_INET6)
3124 mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa, mDNSs32 utc)
3125 {
3126 mDNSu32 scope_id = if_nametoindex(ifa->ifa_name);
3127 mDNSEthAddr bssid = GetBSSID(ifa->ifa_name);
3128
3129 mDNSAddr ip, mask;
3130 if (SetupAddr(&ip, ifa->ifa_addr ) != mStatus_NoError) return(NULL);
3131 if (SetupAddr(&mask, ifa->ifa_netmask) != mStatus_NoError) return(NULL);
3132
3133 NetworkInterfaceInfoOSX **p;
3134 for (p = &m->p->InterfaceList; *p; p = &(*p)->next)
3135 if (scope_id == (*p)->scope_id &&
3136 mDNSSameAddress(&ip, &(*p)->ifinfo.ip) &&
3137 mDNSSameEthAddress(&bssid, &(*p)->BSSID))
3138 {
3139 debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, *p);
3140 (*p)->Exists = mDNStrue;
3141 // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
3142 if ((*p)->LastSeen != utc) (*p)->AppearanceTime = utc;
3143
3144 // If Wake-on-LAN capability of this interface has changed (e.g. because power cable on laptop has been disconnected)
3145 // we may need to start or stop or sleep proxy browse operation
3146 const mDNSBool NetWake = NetWakeInterface(*p);
3147 if ((*p)->ifinfo.NetWake != NetWake)
3148 {
3149 (*p)->ifinfo.NetWake = NetWake;
3150 // If this interface is already registered with mDNSCore, then we need to start or stop its NetWake browse on-the-fly.
3151 // If this interface is not already registered (i.e. it's a dormant interface we had in our list
3152 // from when we previously saw it) then we mustn't do that, because mDNSCore doesn't know about it yet.
3153 // In this case, the mDNS_RegisterInterface() call will take care of starting the NetWake browse if necessary.
3154 if ((*p)->ifinfo.InterfaceID)
3155 {
3156 mDNS_Lock(m);
3157 if (NetWake) mDNS_ActivateNetWake_internal (m, &(*p)->ifinfo);
3158 else mDNS_DeactivateNetWake_internal(m, &(*p)->ifinfo);
3159 mDNS_Unlock(m);
3160 }
3161 }
3162
3163 return(*p);
3164 }
3165
3166 NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
3167 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i);
3168 if (!i) return(mDNSNULL);
3169 mDNSPlatformMemZero(i, sizeof(NetworkInterfaceInfoOSX));
3170 i->ifinfo.InterfaceID = mDNSNULL;
3171 i->ifinfo.ip = ip;
3172 i->ifinfo.mask = mask;
3173 strlcpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname));
3174 i->ifinfo.ifname[sizeof(i->ifinfo.ifname)-1] = 0;
3175 // We can be configured to disable multicast advertisement, but we want to to support
3176 // local-only services, which need a loopback address record.
3177 i->ifinfo.Advertise = m->DivertMulticastAdvertisements ? ((ifa->ifa_flags & IFF_LOOPBACK) ? mDNStrue : mDNSfalse) : m->AdvertiseLocalAddresses;
3178 i->ifinfo.McastTxRx = mDNSfalse; // For now; will be set up later at the end of UpdateInterfaceList
3179
3180 i->next = mDNSNULL;
3181 i->m = m;
3182 i->Exists = mDNStrue;
3183 i->Flashing = mDNSfalse;
3184 i->Occulting = mDNSfalse;
3185 i->AppearanceTime = utc; // Brand new interface; AppearanceTime is now
3186 i->LastSeen = utc;
3187 i->ifa_flags = ifa->ifa_flags;
3188 i->scope_id = scope_id;
3189 i->BSSID = bssid;
3190 i->sa_family = ifa->ifa_addr->sa_family;
3191 i->BPF_fd = -1;
3192 i->BPF_len = 0;
3193
3194 // Do this AFTER i->BSSID has been set up
3195 i->ifinfo.NetWake = NetWakeInterface(i);
3196 GetMAC(&i->ifinfo.MAC, scope_id);
3197 if (i->ifinfo.NetWake && !i->ifinfo.MAC.l[0])
3198 LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i->ifinfo.MAC, scope_id, i->ifinfo.ifname, &ip);
3199
3200 *p = i;
3201 return(i);
3202 }
3203
3204 #if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
3205 mDNSlocal NetworkInterfaceInfoOSX *FindRoutableIPv4(mDNS *const m, mDNSu32 scope_id)
3206 {
3207 NetworkInterfaceInfoOSX *i;
3208 for (i = m->p->InterfaceList; i; i = i->next)
3209 if (i->Exists && i->scope_id == scope_id && i->ifinfo.ip.type == mDNSAddrType_IPv4)
3210 if (!mDNSv4AddressIsLinkLocal(&i->ifinfo.ip.ip.v4))
3211 return(i);
3212 return(mDNSNULL);
3213 }
3214 #endif
3215
3216 #if APPLE_OSX_mDNSResponder
3217
3218 #if COMPILER_LIKES_PRAGMA_MARK
3219 #pragma mark -
3220 #pragma mark - AutoTunnel
3221 #endif
3222
3223 #define kRacoonPort 4500
3224
3225 static DomainAuthInfo* AnonymousRacoonConfig = mDNSNULL;
3226
3227 #ifndef NO_SECURITYFRAMEWORK
3228
3229 static CFMutableDictionaryRef domainStatusDict = NULL;
3230
3231 // MUST be called with lock held
3232 mDNSlocal void RemoveAutoTunnelDomainStatus(const mDNS *const m, const DomainAuthInfo *const info)
3233 {
3234 char buffer[1024];
3235 CFStringRef domain;
3236
3237 LogInfo("RemoveAutoTunnelDomainStatus: %##s", info->domain.c);
3238
3239 if (!domainStatusDict) { LogMsg("RemoveAutoTunnelDomainStatus: No domainStatusDict"); return; }
3240
3241 buffer[mDNS_snprintf(buffer, sizeof(buffer), "%##s", info->domain.c) - 1] = 0;
3242 domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3243 if (!domain) { LogMsg("RemoveAutoTunnelDomainStatus: Could not create CFString domain"); return; }
3244
3245 if (CFDictionaryContainsKey(domainStatusDict, domain))
3246 {
3247 CFDictionaryRemoveValue(domainStatusDict, domain);
3248 if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
3249 }
3250 CFRelease(domain);
3251 }
3252
3253 #endif // ndef NO_SECURITYFRAMEWORK
3254
3255 mDNSlocal mStatus CheckQuestionForStatus(const DNSQuestion *const q)
3256 {
3257 if (q->LongLived)
3258 {
3259 if (q->nta || (q->servAddr.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsOnes(q->servAddr.ip.v4)))
3260 return mStatus_NoSuchRecord;
3261 else if (q->state == LLQ_Poll)
3262 return mStatus_PollingMode;
3263 else if (q->state != LLQ_Established && !q->DuplicateOf)
3264 return mStatus_TransientErr;
3265 }
3266
3267 return mStatus_NoError;
3268 }
3269
3270 // MUST be called with lock held
3271 mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAuthInfo *const info)
3272 {
3273 #ifdef NO_SECURITYFRAMEWORK
3274 (void)m;
3275 (void)info;
3276 #else
3277 const NATTraversalInfo *const llq = m->LLQNAT.clientContext ? &m->LLQNAT : mDNSNULL;
3278 const NATTraversalInfo *const tun = info->AutoTunnelNAT.clientContext ? &info->AutoTunnelNAT : mDNSNULL;
3279 char buffer[1024];
3280 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
3281 CFStringRef domain = NULL;
3282 CFStringRef tmp = NULL;
3283 CFNumberRef num = NULL;
3284 mStatus status = mStatus_NoError;
3285
3286 if (!domainStatusDict)
3287 {
3288 domainStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
3289 if (!domainStatusDict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary domainStatusDict"); return; }
3290 }
3291
3292 if (!dict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary dict"); return; }
3293
3294 buffer[mDNS_snprintf(buffer, sizeof(buffer), "%##s", info->domain.c) - 1] = 0;
3295 domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3296 if (!domain) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString domain"); return; }
3297
3298 mDNS_snprintf(buffer, sizeof(buffer), "%#a", &m->Router);
3299 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3300 if (!tmp)
3301 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString RouterAddress");
3302 else
3303 {
3304 CFDictionarySetValue(dict, CFSTR("RouterAddress"), tmp);
3305 CFRelease(tmp);
3306 }
3307
3308 mDNS_snprintf(buffer, sizeof(buffer), "%.4a", &m->ExternalAddress);
3309 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3310 if (!tmp)
3311 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString ExternalAddress");
3312 else
3313 {
3314 CFDictionarySetValue(dict, CFSTR("ExternalAddress"), tmp);
3315 CFRelease(tmp);
3316 }
3317
3318 if (llq)
3319 {
3320 mDNSu32 port = mDNSVal16(llq->ExternalPort);
3321
3322 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
3323 if (!num)
3324 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQExternalPort");
3325 else
3326 {
3327 CFDictionarySetValue(dict, CFSTR("LLQExternalPort"), num);
3328 CFRelease(num);
3329 }
3330
3331 if (llq->Result)
3332 {
3333 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &llq->Result);
3334 if (!num)
3335 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQNPMStatus");
3336 else
3337 {
3338 CFDictionarySetValue(dict, CFSTR("LLQNPMStatus"), num);
3339 CFRelease(num);
3340 }
3341 }
3342 }
3343
3344 if (tun)
3345 {
3346 mDNSu32 port = mDNSVal16(tun->ExternalPort);
3347
3348 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
3349 if (!num)
3350 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelExternalPort");
3351 else
3352 {
3353 CFDictionarySetValue(dict, CFSTR("AutoTunnelExternalPort"), num);
3354 CFRelease(num);
3355 }
3356
3357 if (tun->Result)
3358 {
3359 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tun->Result);
3360 if (!num)
3361 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelNPMStatus");
3362 else
3363 {
3364 CFDictionarySetValue(dict, CFSTR("AutoTunnelNPMStatus"), num);
3365 CFRelease(num);
3366 }
3367 }
3368 }
3369 if (tun || llq)
3370 {
3371 mDNSu32 code = m->LastNATMapResultCode;
3372
3373 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &code);
3374 if (!num)
3375 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LastNATMapResultCode");
3376 else
3377 {
3378 CFDictionarySetValue(dict, CFSTR("LastNATMapResultCode"), num);
3379 CFRelease(num);
3380 }
3381 }
3382
3383 if (!llq && !tun)
3384 {
3385 status = mStatus_NotInitializedErr;
3386 mDNS_snprintf(buffer, sizeof(buffer), "Neither LLQ nor AutoTunnel NAT port mapping is currently active");
3387 }
3388 else if ((llq && llq->Result == mStatus_DoubleNAT) || (tun && tun->Result == mStatus_DoubleNAT))
3389 {
3390 status = mStatus_DoubleNAT;
3391 mDNS_snprintf(buffer, sizeof(buffer), "Double NAT: Router is reporting an external address");
3392 }
3393 else if ((llq && llq->Result == mStatus_NATPortMappingDisabled) || (tun && tun->Result == mStatus_NATPortMappingDisabled) ||
3394 (m->LastNATMapResultCode == NATErr_Refused && ((llq && !llq->Result && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && !tun->Result && mDNSIPPortIsZero(tun->ExternalPort)))))
3395 {
3396 status = mStatus_NATPortMappingDisabled;
3397 mDNS_snprintf(buffer, sizeof(buffer), "NAT-PMP is disabled on the router");
3398 }
3399 else if ((llq && llq->Result) || (tun && tun->Result))
3400 {
3401 status = mStatus_NATTraversal;
3402 mDNS_snprintf(buffer, sizeof(buffer), "Error obtaining NAT port mapping from router");
3403 }
3404 else if (m->Router.type == mDNSAddrType_None)
3405 {
3406 status = mStatus_NoRouter;
3407 mDNS_snprintf(buffer, sizeof(buffer), "No network connection - none");
3408 }
3409 else if (m->Router.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsZero(m->Router.ip.v4))
3410 {
3411 status = mStatus_NoRouter;
3412 mDNS_snprintf(buffer, sizeof(buffer), "No network connection - v4 zero");
3413 }
3414 else if ((llq && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && mDNSIPPortIsZero(tun->ExternalPort)))
3415 {
3416 status = mStatus_NATTraversal;
3417 mDNS_snprintf(buffer, sizeof(buffer), "Unable to obtain NAT port mapping from router");
3418 }
3419 else
3420 {
3421 DNSQuestion* q, *worst_q = mDNSNULL;
3422 for (q = m->Questions; q; q=q->next)
3423 if (q->AuthInfo == info)
3424 {
3425 mStatus newStatus = CheckQuestionForStatus(q);
3426 if (newStatus == mStatus_NoSuchRecord) { status = newStatus; worst_q = q; break; }
3427 else if (newStatus == mStatus_PollingMode) { status = newStatus; worst_q = q; }
3428 else if (newStatus == mStatus_TransientErr && status == mStatus_NoError) { status = newStatus; worst_q = q; }
3429 }
3430
3431 if (status == mStatus_NoError) mDNS_snprintf(buffer, sizeof(buffer), "Success");
3432 else if (status == mStatus_NoSuchRecord) mDNS_snprintf(buffer, sizeof(buffer), "GetZoneData %s: %##s", worst_q->nta ? "not yet complete" : "failed", worst_q->qname.c);
3433 else if (status == mStatus_PollingMode) mDNS_snprintf(buffer, sizeof(buffer), "Query polling %##s", worst_q->qname.c);
3434 else if (status == mStatus_TransientErr) mDNS_snprintf(buffer, sizeof(buffer), "Query not yet established %##s", worst_q->qname.c);
3435 }
3436
3437 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &status);
3438 if (!num)
3439 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber StatusCode");
3440 else
3441 {
3442 CFDictionarySetValue(dict, CFSTR("StatusCode"), num);
3443 CFRelease(num);
3444 }
3445
3446 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
3447 if (!tmp)
3448 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString StatusMessage");
3449 else
3450 {
3451 CFDictionarySetValue(dict, CFSTR("StatusMessage"), tmp);
3452 CFRelease(tmp);
3453 }
3454
3455 if (!CFDictionaryContainsKey(domainStatusDict, domain) ||
3456 !CFEqual(dict, (CFMutableDictionaryRef)CFDictionaryGetValue(domainStatusDict, domain)))
3457 {
3458 CFDictionarySetValue(domainStatusDict, domain, dict);
3459 if (!m->ShutdownTime)
3460 {
3461 static char statusBuf[16];
3462 mDNS_snprintf(statusBuf, sizeof(statusBuf), "%d", (int)status);
3463 mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.domainstatus", status ? "failure" : "success", statusBuf, "");
3464 mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
3465 }
3466 }
3467
3468 CFRelease(domain);
3469 CFRelease(dict);
3470
3471 debugf("UpdateAutoTunnelDomainStatus: %s", buffer);
3472 #endif // def NO_SECURITYFRAMEWORK
3473 }
3474
3475 // MUST be called with lock held
3476 mDNSexport void UpdateAutoTunnelDomainStatuses(const mDNS *const m)
3477 {
3478 #ifdef NO_SECURITYFRAMEWORK
3479 (void)m;
3480 #else
3481 DomainAuthInfo* info;
3482 for (info = m->AuthInfoList; info; info = info->next)
3483 if (info->AutoTunnel && !info->deltime)
3484 UpdateAutoTunnelDomainStatus(m, info);
3485 #endif // def NO_SECURITYFRAMEWORK
3486 }
3487
3488 // MUST be called with lock held
3489 mDNSlocal mDNSBool TunnelServers(mDNS *const m)
3490 {
3491 ServiceRecordSet *p;
3492 for (p = m->ServiceRegistrations; p; p = p->uDNS_next)
3493 {
3494 DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, p->RR_SRV.resrec.name);
3495 if (AuthInfo && AuthInfo->AutoTunnel && !AuthInfo->deltime) return(mDNStrue);
3496 }
3497
3498 AuthRecord *r;
3499 for (r = m->ResourceRecords; r; r = r->next)
3500 if (r->resrec.rrtype == kDNSType_SRV)
3501 {
3502 DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, r->resrec.name);
3503 if (AuthInfo && AuthInfo->AutoTunnel && !AuthInfo->deltime) return(mDNStrue);
3504 }
3505
3506 return(mDNSfalse);
3507 }
3508
3509 // MUST be called with lock held
3510 mDNSlocal mDNSBool TunnelClients(mDNS *const m)
3511 {
3512 ClientTunnel *p;
3513 for (p = m->TunnelClients; p; p = p->next)
3514 if (p->q.ThisQInterval < 0)
3515 return(mDNStrue);
3516 return(mDNSfalse);
3517 }
3518
3519 mDNSlocal void RegisterAutoTunnelRecords(mDNS *m, DomainAuthInfo *info)
3520 {
3521 if (info->AutoTunnelNAT.clientContext && !info->AutoTunnelNAT.Result && !mDNSIPPortIsZero(info->AutoTunnelNAT.ExternalPort) && AutoTunnelUnregistered(info))
3522 {
3523 mStatus err;
3524 LogInfo("RegisterAutoTunnelRecords %##s (%#s)", info->domain.c, m->hostlabel.c);
3525
3526 // 1. Set up our address record for the internal tunnel address
3527 // (User-visible user-friendly host name, used as target in AutoTunnel SRV records)
3528 info->AutoTunnelHostRecord.namestorage.c[0] = 0;
3529 AppendDomainLabel(&info->AutoTunnelHostRecord.namestorage, &m->hostlabel);
3530 AppendDomainName (&info->AutoTunnelHostRecord.namestorage, &info->domain);
3531 info->AutoTunnelHostRecord.resrec.rdata->u.ipv6 = m->AutoTunnelHostAddr;
3532 info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeKnownUnique;
3533 err = mDNS_Register(m, &info->AutoTunnelHostRecord);
3534 if (err) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelHostRecord %##s", err, info->AutoTunnelHostRecord.namestorage.c);
3535
3536 // 2. Set up device info record
3537 ConstructServiceName(&info->AutoTunnelDeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &info->domain);
3538 mDNSu8 len = m->HIHardware.c[0] < 255 - 6 ? m->HIHardware.c[0] : 255 - 6;
3539 mDNSPlatformMemCopy(info->AutoTunnelDeviceInfo.resrec.rdata->u.data + 1, "model=", 6);
3540 mDNSPlatformMemCopy(info->AutoTunnelDeviceInfo.resrec.rdata->u.data + 7, m->HIHardware.c + 1, len);
3541 info->AutoTunnelDeviceInfo.resrec.rdata->u.data[0] = 6 + len; // "model=" plus the device string
3542 info->AutoTunnelDeviceInfo.resrec.rdlength = 7 + len; // One extra for the length byte at the start of the string
3543 info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeKnownUnique;
3544 err = mDNS_Register(m, &info->AutoTunnelDeviceInfo);
3545 if (err) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelDeviceInfo %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
3546
3547 // 3. Set up our address record for the external tunnel address
3548 // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
3549 info->AutoTunnelTarget.namestorage.c[0] = 0;
3550 AppendDomainLabel(&info->AutoTunnelTarget.namestorage, &m->AutoTunnelLabel);
3551 AppendDomainName (&info->AutoTunnelTarget.namestorage, &info->domain);
3552 info->AutoTunnelTarget.resrec.RecordType = kDNSRecordTypeKnownUnique;
3553
3554 mDNS_Lock(m);
3555 mDNS_AddDynDNSHostName(m, &info->AutoTunnelTarget.namestorage, mDNSNULL, info);
3556 mDNS_Unlock(m);
3557
3558 // 4. Set up IKE tunnel's SRV record: "AutoTunnelHostRecord SRV 0 0 port AutoTunnelTarget"
3559 AssignDomainName (&info->AutoTunnelService.namestorage, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
3560 AppendDomainLabel(&info->AutoTunnelService.namestorage, &m->hostlabel);
3561 AppendDomainName (&info->AutoTunnelService.namestorage, &info->domain);
3562 info->AutoTunnelService.resrec.rdata->u.srv.priority = 0;
3563 info->AutoTunnelService.resrec.rdata->u.srv.weight = 0;
3564 info->AutoTunnelService.resrec.rdata->u.srv.port = info->AutoTunnelNAT.ExternalPort;
3565 AssignDomainName(&info->AutoTunnelService.resrec.rdata->u.srv.target, &info->AutoTunnelTarget.namestorage);
3566 info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeKnownUnique;
3567 err = mDNS_Register(m, &info->AutoTunnelService);
3568 if (err) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelService %##s", err, info->AutoTunnelService.namestorage.c);
3569
3570 LogInfo("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
3571 info->AutoTunnelTarget.namestorage.c, &m->AdvertisedV4.ip.v4, mDNSVal16(info->AutoTunnelNAT.IntPort),
3572 info->AutoTunnelHostRecord.namestorage.c, &m->AutoTunnelHostAddr);
3573 }
3574 }
3575
3576 mDNSlocal void DeregisterAutoTunnelRecords(mDNS *m, DomainAuthInfo *info)
3577 {
3578 LogInfo("DeregisterAutoTunnelRecords %##s", info->domain.c);
3579 if (info->AutoTunnelService.resrec.RecordType > kDNSRecordTypeDeregistering)
3580 {
3581 mStatus err = mDNS_Deregister(m, &info->AutoTunnelService);
3582 if (err)
3583 {
3584 info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeUnregistered;
3585 LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelService %##s", err, info->AutoTunnelService.namestorage.c);
3586 }
3587
3588 mDNS_Lock(m);
3589 mDNS_RemoveDynDNSHostName(m, &info->AutoTunnelTarget.namestorage);
3590 mDNS_Unlock(m);
3591 }
3592
3593 if (info->AutoTunnelHostRecord.resrec.RecordType > kDNSRecordTypeDeregistering)
3594 {
3595 mStatus err = mDNS_Deregister(m, &info->AutoTunnelHostRecord);
3596 if (err)
3597 {
3598 info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeUnregistered;
3599 LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelHostRecord %##s", err, info->AutoTunnelHostRecord.namestorage.c);
3600 }
3601 }
3602
3603 if (info->AutoTunnelDeviceInfo.resrec.RecordType > kDNSRecordTypeDeregistering)
3604 {
3605 mStatus err = mDNS_Deregister(m, &info->AutoTunnelDeviceInfo);
3606 if (err)
3607 {
3608 info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeUnregistered;
3609 LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelDeviceInfo %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
3610 }
3611 }
3612 }
3613
3614 mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
3615 {
3616 DomainAuthInfo *info = (DomainAuthInfo *)rr->RecordContext;
3617 if (result == mStatus_MemFree)
3618 {
3619 LogInfo("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m, rr));
3620 // Reset the host record namestorage to force high-level PTR/SRV/TXT to deregister
3621 if (rr == &info->AutoTunnelHostRecord)
3622 {
3623 rr->namestorage.c[0] = 0;
3624 m->NextSRVUpdate = NonZeroTime(m->timenow);
3625 }
3626 RegisterAutoTunnelRecords(m,info);
3627 }
3628 }
3629
3630 // Determine whether we need racoon to accept incoming connections
3631 mDNSlocal void UpdateConfigureServer(mDNS *m)
3632 {
3633 DomainAuthInfo *info;
3634
3635 for (info = m->AuthInfoList; info; info = info->next)
3636 if (info->AutoTunnel && !info->deltime && !mDNSIPPortIsZero(info->AutoTunnelNAT.ExternalPort))
3637 break;
3638
3639 if (info != AnonymousRacoonConfig)
3640 {
3641 AnonymousRacoonConfig = info;
3642 // Create or revert configuration file, and start (or SIGHUP) Racoon
3643 (void)mDNSConfigureServer(AnonymousRacoonConfig ? kmDNSUp : kmDNSDown, AnonymousRacoonConfig ? &AnonymousRacoonConfig->domain : mDNSNULL);
3644 }
3645 }
3646
3647 mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n)
3648 {
3649 DomainAuthInfo *info = (DomainAuthInfo *)n->clientContext;
3650 LogInfo("AutoTunnelNATCallback Result %d %.4a Internal %d External %d %#s.%##s",
3651 n->Result, &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort), m->hostlabel.c, info->domain.c);
3652
3653 m->NextSRVUpdate = NonZeroTime(m->timenow);
3654 DeregisterAutoTunnelRecords(m,info);
3655 RegisterAutoTunnelRecords(m,info);
3656
3657 UpdateConfigureServer(m);
3658
3659 UpdateAutoTunnelDomainStatus(m, (DomainAuthInfo *)n->clientContext);
3660 }
3661
3662 mDNSlocal void AbortDeregistration(mDNS *const m, AuthRecord *rr)
3663 {
3664 if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
3665 {
3666 LogInfo("Aborting deregistration of %s", ARDisplayString(m, rr));
3667 CompleteDeregistration(m, rr);
3668 }
3669 else if (rr->resrec.RecordType != kDNSRecordTypeUnregistered)
3670 LogMsg("AbortDeregistration ERROR RecordType %02X for %s", ARDisplayString(m, rr));
3671 }
3672
3673 // Before SetupLocalAutoTunnelInterface_internal is called,
3674 // m->AutoTunnelHostAddr.b[0] must be non-zero, and there must be at least one TunnelClient or TunnelServer
3675 // Must be called with the lock held
3676 mDNSexport void SetupLocalAutoTunnelInterface_internal(mDNS *const m)
3677 {
3678 LogInfo("SetupLocalAutoTunnelInterface");
3679
3680 // 1. Configure the local IPv6 address
3681 if (!m->AutoTunnelHostAddrActive)
3682 {
3683 m->AutoTunnelHostAddrActive = mDNStrue;
3684 LogInfo("Setting up AutoTunnel address %.16a", &m->AutoTunnelHostAddr);
3685 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSUp, m->AutoTunnelHostAddr.b);
3686 }
3687
3688 // 2. If we have at least one server (pending) listening, publish our records
3689 if (TunnelServers(m))
3690 {
3691 DomainAuthInfo *info;
3692 for (info = m->AuthInfoList; info; info = info->next)
3693 {
3694 if (info->AutoTunnel && !info->deltime && !info->AutoTunnelNAT.clientContext)
3695 {
3696 // If we just resurrected a DomainAuthInfo that is still deregistering, we need to abort the deregistration process before re-using the AuthRecord memory
3697 AbortDeregistration(m, &info->AutoTunnelHostRecord);
3698 AbortDeregistration(m, &info->AutoTunnelDeviceInfo);
3699 AbortDeregistration(m, &info->AutoTunnelService);
3700
3701 mDNS_SetupResourceRecord(&info->AutoTunnelHostRecord, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
3702 mDNS_SetupResourceRecord(&info->AutoTunnelDeviceInfo, mDNSNULL, mDNSInterface_Any, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
3703 mDNS_SetupResourceRecord(&info->AutoTunnelTarget, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
3704 mDNS_SetupResourceRecord(&info->AutoTunnelService, mDNSNULL, mDNSInterface_Any, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
3705
3706 // Try to get a NAT port mapping for the AutoTunnelService
3707 info->AutoTunnelNAT.clientCallback = AutoTunnelNATCallback;
3708 info->AutoTunnelNAT.clientContext = info;
3709 info->AutoTunnelNAT.Protocol = NATOp_MapUDP;
3710 info->AutoTunnelNAT.IntPort = mDNSOpaque16fromIntVal(kRacoonPort);
3711 info->AutoTunnelNAT.RequestedPort = mDNSOpaque16fromIntVal(kRacoonPort);
3712 info->AutoTunnelNAT.NATLease = 0;
3713 mStatus err = mDNS_StartNATOperation_internal(m, &info->AutoTunnelNAT);
3714 if (err) LogMsg("SetupLocalAutoTunnelInterface_internal error %d starting NAT mapping", err);
3715 }
3716 }
3717 }
3718 }
3719
3720 mDNSlocal mStatus AutoTunnelSetKeys(ClientTunnel *tun, mDNSBool AddNew)
3721 {
3722 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), SkipLeadingLabels(&tun->dstname, 1)));
3723 }
3724
3725 // If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
3726 #define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
3727
3728 mDNSlocal void ReissueBlockedQuestionWithType(mDNS *const m, domainname *d, mDNSBool success, mDNSu16 qtype)
3729 {
3730 DNSQuestion *q = m->Questions;
3731 while (q)
3732 {
3733 if (q->NoAnswer == NoAnswer_Suspended && q->qtype == qtype && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d))
3734 {
3735 LogInfo("Restart %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
3736 mDNSQuestionCallback *tmp = q->QuestionCallback;
3737 q->QuestionCallback = AutoTunnelCallback; // Set QuestionCallback to suppress another call back to AddNewClientTunnel
3738 mDNS_StopQuery(m, q);
3739 mDNS_StartQuery(m, q);
3740 q->QuestionCallback = tmp; // Restore QuestionCallback back to the real value
3741 if (!success) q->NoAnswer = NoAnswer_Fail;
3742 // When we call mDNS_StopQuery, it's possible for other subordinate questions like the GetZoneData query to be cancelled too.
3743 // In general we have to assume that the question list might have changed in arbitrary ways.
3744 // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
3745 // already in use. The safest solution is just to go back to the start of the list and start again.
3746 // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
3747 // just one suspended question, so it's really a 2n algorithm.
3748 q = m->Questions;
3749 }
3750 else
3751 q = q->next;
3752 }
3753 }
3754
3755 mDNSlocal void ReissueBlockedQuestions(mDNS *const m, domainname *d, mDNSBool success)
3756 {
3757 // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has
3758 // a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN.
3759 // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller --
3760 // 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.
3761 // 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.
3762 ReissueBlockedQuestionWithType(m, d, success, kDNSType_AAAA);
3763 ReissueBlockedQuestionWithType(m, d, mDNStrue, kDNSType_A);
3764 }
3765
3766 mDNSlocal void UnlinkAndReissueBlockedQuestions(mDNS *const m, ClientTunnel *tun, mDNSBool success)
3767 {
3768 ClientTunnel **p = &m->TunnelClients;
3769 while (*p != tun && *p) p = &(*p)->next;
3770 if (*p) *p = tun->next;
3771 ReissueBlockedQuestions(m, &tun->dstname, success);
3772 LogInfo("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun);
3773 freeL("ClientTunnel", tun);
3774 }
3775
3776 mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
3777 {
3778 ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
3779 LogInfo("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun, AddRecord, answer->rdlength, question->qtype);
3780
3781 if (!AddRecord) return;
3782 mDNS_StopQuery(m, question);
3783
3784 if (!answer->rdlength)
3785 {
3786 LogInfo("AutoTunnelCallback NXDOMAIN %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
3787 static char msgbuf[16];
3788 mDNS_snprintf(msgbuf, sizeof(msgbuf), "%s lookup", DNSTypeName(question->qtype));
3789 mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.config", "failure", msgbuf, "");
3790 UnlinkAndReissueBlockedQuestions(m, tun, mDNSfalse);
3791 return;
3792 }
3793
3794 if (question->qtype == kDNSType_AAAA)
3795 {
3796 if (mDNSSameIPv6Address(answer->rdata->u.ipv6, m->AutoTunnelHostAddr))
3797 {
3798 LogInfo("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer->rdata->u.ipv6);
3799 UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
3800 return;
3801 }
3802
3803 tun->rmt_inner = answer->rdata->u.ipv6;
3804 LogInfo("AutoTunnelCallback: dst host %.16a", &tun->rmt_inner);
3805 AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
3806 AppendDomainName(&question->qname, &tun->dstname);
3807 question->qtype = kDNSType_SRV;
3808 mDNS_StartQuery(m, &tun->q);
3809 }
3810 else if (question->qtype == kDNSType_SRV)
3811 {
3812 LogInfo("AutoTunnelCallback: SRV target name %##s", answer->rdata->u.srv.target.c);
3813 AssignDomainName(&tun->q.qname, &answer->rdata->u.srv.target);
3814 tun->rmt_outer_port = answer->rdata->u.srv.port;
3815 question->qtype = kDNSType_A;
3816 mDNS_StartQuery(m, &tun->q);
3817 }
3818 else if (question->qtype == kDNSType_A)
3819 {
3820 ClientTunnel *old = mDNSNULL;
3821 LogInfo("AutoTunnelCallback: SRV target addr %.4a", &answer->rdata->u.ipv4);
3822 question->ThisQInterval = -1; // So we know this tunnel setup has completed
3823 tun->rmt_outer = answer->rdata->u.ipv4;
3824 tun->loc_inner = m->AutoTunnelHostAddr;
3825 mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
3826 tmpDst.ip.v4 = tun->rmt_outer;
3827 mDNSAddr tmpSrc = zeroAddr;
3828 mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
3829 if (tmpSrc.type == mDNSAddrType_IPv4) tun->loc_outer = tmpSrc.ip.v4;
3830 else tun->loc_outer = m->AdvertisedV4.ip.v4;
3831
3832 ClientTunnel **p = &tun->next;
3833 mDNSBool needSetKeys = mDNStrue;
3834 while (*p)
3835 {
3836 if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
3837 else
3838 {
3839 LogInfo("Found existing AutoTunnel for %##s %.16a", tun->dstname.c, &tun->rmt_inner);
3840 old = *p;
3841 *p = old->next;
3842 if (old->q.ThisQInterval >= 0) mDNS_StopQuery(m, &old->q);
3843 else if (!mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
3844 !mDNSSameIPv4Address(old->loc_outer, tun->loc_outer) ||
3845 !mDNSSameIPv6Address(old->rmt_inner, tun->rmt_inner) ||
3846 !mDNSSameIPv4Address(old->rmt_outer, tun->rmt_outer) ||
3847 !mDNSSameIPPort(old->rmt_outer_port, tun->rmt_outer_port))
3848 {
3849 LogInfo("Deleting existing AutoTunnel for %##s %.16a", tun->dstname.c, &tun->rmt_inner);
3850 AutoTunnelSetKeys(old, mDNSfalse);
3851 }
3852 else needSetKeys = mDNSfalse;
3853
3854 LogInfo("AutoTunnelCallback: Disposing ClientTunnel %p", tun);
3855 freeL("ClientTunnel", old);
3856 }
3857 }
3858
3859 if (needSetKeys) LogInfo("New AutoTunnel for %##s %.16a", tun->dstname.c, &tun->rmt_inner);
3860
3861 if (m->AutoTunnelHostAddr.b[0]) { mDNS_Lock(m); SetupLocalAutoTunnelInterface_internal(m); mDNS_Unlock(m); };
3862
3863 mStatus result = needSetKeys ? AutoTunnelSetKeys(tun, mDNStrue) : mStatus_NoError;
3864 static char msgbuf[32];
3865 mDNS_snprintf(msgbuf, sizeof(msgbuf), "Tunnel setup - %d", result);
3866 mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.config", result ? "failure" : "success", msgbuf, "");
3867 // Kick off any questions that were held pending this tunnel setup
3868 ReissueBlockedQuestions(m, &tun->dstname, (result == mStatus_NoError) ? mDNStrue : mDNSfalse);
3869 }
3870 else
3871 LogMsg("AutoTunnelCallback: Unknown question %p", question);
3872 }
3873
3874 // Must be called with the lock held
3875 mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q)
3876 {
3877 ClientTunnel *p = mallocL("ClientTunnel", sizeof(ClientTunnel));
3878 if (!p) return;
3879 AssignDomainName(&p->dstname, &q->qname);
3880 p->MarkedForDeletion = mDNSfalse;
3881 p->loc_inner = zerov6Addr;
3882 p->loc_outer = zerov4Addr;
3883 p->rmt_inner = zerov6Addr;
3884 p->rmt_outer = zerov4Addr;
3885 p->rmt_outer_port = zeroIPPort;
3886 p->next = m->TunnelClients;
3887 m->TunnelClients = p; // We intentionally build list in reverse order
3888
3889 p->q.InterfaceID = mDNSInterface_Any;
3890 p->q.Target = zeroAddr;
3891 AssignDomainName(&p->q.qname, &q->qname);
3892 p->q.qtype = kDNSType_AAAA;
3893 p->q.qclass = kDNSClass_IN;
3894 p->q.LongLived = mDNSfalse;
3895 p->q.ExpectUnique = mDNStrue;
3896 p->q.ForceMCast = mDNSfalse;
3897 p->q.ReturnIntermed = mDNStrue;
3898 p->q.QuestionCallback = AutoTunnelCallback;
3899 p->q.QuestionContext = p;
3900
3901 LogInfo("AddNewClientTunnel start tun %p %##s (%s)%s", p, &q->qname.c, DNSTypeName(q->qtype), q->LongLived ? " LongLived" : "");
3902 mDNS_StartQuery_internal(m, &p->q);
3903 }
3904
3905 #endif // APPLE_OSX_mDNSResponder
3906
3907 #if COMPILER_LIKES_PRAGMA_MARK
3908 #pragma mark -
3909 #pragma mark - Power State & Configuration Change Management
3910 #endif
3911
3912 mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
3913 {
3914 mDNSBool foundav4 = mDNSfalse;
3915 mDNSBool foundav6 = mDNSfalse;
3916 struct ifaddrs *ifa = myGetIfAddrs(1);
3917 struct ifaddrs *v4Loopback = NULL;
3918 struct ifaddrs *v6Loopback = NULL;
3919 char defaultname[64];
3920 #ifndef NO_IPV6
3921 int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
3922 if (InfoSocket < 3 && errno != EAFNOSUPPORT) LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno));
3923 #endif
3924 if (m->SleepState == SleepState_Sleeping) ifa = NULL;
3925
3926 while (ifa)
3927 {
3928 #if LIST_ALL_INTERFACES
3929 if (ifa->ifa_addr->sa_family == AF_APPLETALK)
3930 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
3931 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
3932 else if (ifa->ifa_addr->sa_family == AF_LINK)
3933 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
3934 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
3935 else if (ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6)
3936 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
3937 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
3938 if (!(ifa->ifa_flags & IFF_UP))
3939 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
3940 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
3941 if (!(ifa->ifa_flags & IFF_MULTICAST))
3942 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
3943 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
3944 if (ifa->ifa_flags & IFF_POINTOPOINT)
3945 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
3946 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
3947 if (ifa->ifa_flags & IFF_LOOPBACK)
3948 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
3949 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
3950 #endif
3951
3952 if (ifa->ifa_addr->sa_family == AF_LINK)
3953 {
3954 struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
3955 if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == sizeof(m->PrimaryMAC) && mDNSSameEthAddress(&m->PrimaryMAC, &zeroEthAddr))
3956 mDNSPlatformMemCopy(m->PrimaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6);
3957 }
3958
3959 if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr)
3960 if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6)
3961 {
3962 if (!ifa->ifa_netmask)
3963 {
3964 mDNSAddr ip;
3965 SetupAddr(&ip, ifa->ifa_addr);
3966 LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
3967 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip);
3968 }
3969 // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be zero, so we don't complain about that
3970 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
3971 else if (ifa->ifa_netmask->sa_family != ifa->ifa_addr->sa_family && ifa->ifa_netmask->sa_family != 0)
3972 {
3973 mDNSAddr ip;
3974 SetupAddr(&ip, ifa->ifa_addr);
3975 LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
3976 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip, ifa->ifa_netmask->sa_family);
3977 }
3978 else
3979 {
3980 // Make sure ifa_netmask->sa_family is set correctly
3981 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
3982 ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family;
3983 int ifru_flags6 = 0;
3984 #ifndef NO_IPV6
3985 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
3986 if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
3987 {
3988 struct in6_ifreq ifr6;
3989 mDNSPlatformMemZero((char *)&ifr6, sizeof(ifr6));
3990 strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
3991 ifr6.ifr_addr = *sin6;
3992 if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
3993 ifru_flags6 = ifr6.ifr_ifru.ifru_flags6;
3994 verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6);
3995 }
3996 #endif
3997 if (!(ifru_flags6 & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
3998 {
3999 if (ifa->ifa_flags & IFF_LOOPBACK)
4000 {
4001 if (ifa->ifa_addr->sa_family == AF_INET) v4Loopback = ifa;
4002 #ifndef NO_IPV6
4003 else if (sin6->sin6_addr.s6_addr[0] != 0xFD) v6Loopback = ifa;
4004 #endif
4005 }
4006 else
4007 {
4008 NetworkInterfaceInfoOSX *i = AddInterfaceToList(m, ifa, utc);
4009 if (i && MulticastInterface(i) && i->ifinfo.Advertise)
4010 {
4011 if (ifa->ifa_addr->sa_family == AF_INET) foundav4 = mDNStrue;
4012 else foundav6 = mDNStrue;
4013 }
4014 }
4015 }
4016 }
4017 }
4018 ifa = ifa->ifa_next;
4019 }
4020
4021 // For efficiency, we don't register a loopback interface when other interfaces of that family are available and advertising
4022 if (!foundav4 && v4Loopback) AddInterfaceToList(m, v4Loopback, utc);
4023 if (!foundav6 && v6Loopback) AddInterfaceToList(m, v6Loopback, utc);
4024
4025 // Now the list is complete, set the McastTxRx setting for each interface.
4026 NetworkInterfaceInfoOSX *i;
4027 for (i = m->p->InterfaceList; i; i = i->next)
4028 if (i->Exists)
4029 {
4030 mDNSBool txrx = MulticastInterface(i);
4031 #if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
4032 txrx = txrx && ((i->ifinfo.ip.type == mDNSAddrType_IPv4) || !FindRoutableIPv4(m, i->scope_id));
4033 #endif
4034 if (i->ifinfo.McastTxRx != txrx)
4035 {
4036 i->ifinfo.McastTxRx = txrx;
4037 i->Exists = 2; // State change; need to deregister and reregister this interface
4038 }
4039 }
4040
4041 #ifndef NO_IPV6
4042 if (InfoSocket >= 0) close(InfoSocket);
4043 #endif
4044
4045 // If we haven't set up AutoTunnelHostAddr yet, do it now
4046 if (!mDNSSameEthAddress(&m->PrimaryMAC, &zeroEthAddr) && m->AutoTunnelHostAddr.b[0] == 0)
4047 {
4048 m->AutoTunnelHostAddr.b[0x0] = 0xFD; // Required prefix for "locally assigned" ULA (See RFC 4193)
4049 m->AutoTunnelHostAddr.b[0x1] = mDNSRandom(255);
4050 m->AutoTunnelHostAddr.b[0x2] = mDNSRandom(255);
4051 m->AutoTunnelHostAddr.b[0x3] = mDNSRandom(255);
4052 m->AutoTunnelHostAddr.b[0x4] = mDNSRandom(255);
4053 m->AutoTunnelHostAddr.b[0x5] = mDNSRandom(255);
4054 m->AutoTunnelHostAddr.b[0x6] = mDNSRandom(255);
4055 m->AutoTunnelHostAddr.b[0x7] = mDNSRandom(255);
4056 m->AutoTunnelHostAddr.b[0x8] = m->PrimaryMAC.b[0] ^ 0x02; // See RFC 3513, Appendix A for explanation
4057 m->AutoTunnelHostAddr.b[0x9] = m->PrimaryMAC.b[1];
4058 m->AutoTunnelHostAddr.b[0xA] = m->PrimaryMAC.b[2];
4059 m->AutoTunnelHostAddr.b[0xB] = 0xFF;
4060 m->AutoTunnelHostAddr.b[0xC] = 0xFE;
4061 m->AutoTunnelHostAddr.b[0xD] = m->PrimaryMAC.b[3];
4062 m->AutoTunnelHostAddr.b[0xE] = m->PrimaryMAC.b[4];
4063 m->AutoTunnelHostAddr.b[0xF] = m->PrimaryMAC.b[5];
4064 m->AutoTunnelLabel.c[0] = mDNS_snprintf((char*)m->AutoTunnelLabel.c+1, 254, "AutoTunnel-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X",
4065 m->AutoTunnelHostAddr.b[0x8], m->AutoTunnelHostAddr.b[0x9], m->AutoTunnelHostAddr.b[0xA], m->AutoTunnelHostAddr.b[0xB],
4066 m->AutoTunnelHostAddr.b[0xC], m->AutoTunnelHostAddr.b[0xD], m->AutoTunnelHostAddr.b[0xE], m->AutoTunnelHostAddr.b[0xF]);
4067 LogInfo("m->AutoTunnelLabel %#s", m->AutoTunnelLabel.c);
4068 }
4069
4070 mDNS_snprintf(defaultname, sizeof(defaultname), "%.*s-%02X%02X%02X%02X%02X%02X", HINFO_HWstring_prefixlen, HINFO_HWstring,
4071 m->PrimaryMAC.b[0], m->PrimaryMAC.b[1], m->PrimaryMAC.b[2], m->PrimaryMAC.b[3], m->PrimaryMAC.b[4], m->PrimaryMAC.b[5]);
4072
4073 // Set up the nice label
4074 domainlabel nicelabel;
4075 nicelabel.c[0] = 0;
4076 GetUserSpecifiedFriendlyComputerName(&nicelabel);
4077 if (nicelabel.c[0] == 0)
4078 {
4079 debugf("Couldn’t read user-specified Computer Name; using default “%s” instead", defaultname);
4080 MakeDomainLabelFromLiteralString(&nicelabel, defaultname);
4081 }
4082
4083 // Set up the RFC 1034-compliant label
4084 domainlabel hostlabel;
4085 hostlabel.c[0] = 0;
4086 GetUserSpecifiedLocalHostName(&hostlabel);
4087 if (hostlabel.c[0] == 0)
4088 {
4089 debugf("Couldn’t read user-specified Local Hostname; using default “%s.local” instead", defaultname);
4090 MakeDomainLabelFromLiteralString(&hostlabel, defaultname);
4091 }
4092
4093 mDNSBool namechange = mDNSfalse;
4094
4095 // We use a case-sensitive comparison here because even though changing the capitalization
4096 // of the name alone is not significant to DNS, it's still a change from the user's point of view
4097 if (SameDomainLabelCS(m->p->usernicelabel.c, nicelabel.c))
4098 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m->p->usernicelabel.c, m->nicelabel.c);
4099 else
4100 {
4101 if (m->p->usernicelabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
4102 LogMsg("User updated Computer Name from “%#s” to “%#s”", m->p->usernicelabel.c, nicelabel.c);
4103 m->p->usernicelabel = m->nicelabel = nicelabel;
4104 namechange = mDNStrue;
4105 }
4106
4107 if (SameDomainLabelCS(m->p->userhostlabel.c, hostlabel.c))
4108 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m->p->userhostlabel.c, m->hostlabel.c);
4109 else
4110 {
4111 if (m->p->userhostlabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
4112 LogMsg("User updated Local Hostname from “%#s” to “%#s”", m->p->userhostlabel.c, hostlabel.c);
4113 m->p->userhostlabel = m->hostlabel = hostlabel;
4114 mDNS_SetFQDN(m);
4115 namechange = mDNStrue;
4116 }
4117
4118 #if APPLE_OSX_mDNSResponder
4119 if (namechange) // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records
4120 {
4121 DomainAuthInfo *info;
4122 for (info = m->AuthInfoList; info; info = info->next)
4123 if (info->AutoTunnelNAT.clientContext && !mDNSIPv4AddressIsOnes(info->AutoTunnelNAT.ExternalAddress))
4124 AutoTunnelNATCallback(m, &info->AutoTunnelNAT);
4125 }
4126 #endif // APPLE_OSX_mDNSResponder
4127
4128 return(mStatus_NoError);
4129 }
4130
4131 // Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
4132 // Returns -1 if all the one-bits are not contiguous
4133 mDNSlocal int CountMaskBits(mDNSAddr *mask)
4134 {
4135 int i = 0, bits = 0;
4136 int bytes = mask->type == mDNSAddrType_IPv4 ? 4 : mask->type == mDNSAddrType_IPv6 ? 16 : 0;
4137 while (i < bytes)
4138 {
4139 mDNSu8 b = mask->ip.v6.b[i++];
4140 while (b & 0x80) { bits++; b <<= 1; }
4141 if (b) return(-1);
4142 }
4143 while (i < bytes) if (mask->ip.v6.b[i++]) return(-1);
4144 return(bits);
4145 }
4146
4147 // returns count of non-link local V4 addresses registered
4148 mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
4149 {
4150 NetworkInterfaceInfoOSX *i;
4151 int count = 0;
4152 for (i = m->p->InterfaceList; i; i = i->next)
4153 if (i->Exists)
4154 {
4155 NetworkInterfaceInfo *const n = &i->ifinfo;
4156 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifinfo.ifname, AAAA_OVER_V4 ? AF_UNSPEC : i->sa_family);
4157 if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifinfo.ifname);
4158
4159 if (n->InterfaceID && n->InterfaceID != (mDNSInterfaceID)primary) // Sanity check
4160 {
4161 LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != primary %p", n->InterfaceID, primary);
4162 n->InterfaceID = mDNSNULL;
4163 }
4164
4165 if (!n->InterfaceID)
4166 {
4167 // Note: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
4168 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
4169 // If n->InterfaceID is NOT set, then we haven't registered it and we should not try to deregister it
4170 n->InterfaceID = (mDNSInterfaceID)primary;
4171
4172 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
4173 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
4174 // 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.
4175 i->Occulting = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->LastSeen > 0 && utc - i->LastSeen < 60);
4176
4177 mDNS_RegisterInterface(m, n, i->Flashing && i->Occulting);
4178 if (!mDNSAddressIsLinkLocal(&n->ip)) count++;
4179 LogInfo("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s",
4180 i->ifinfo.ifname, i->scope_id, &i->BSSID, primary, &n->ip, CountMaskBits(&n->mask),
4181 i->Flashing ? " (Flashing)" : "",
4182 i->Occulting ? " (Occulting)" : "",
4183 n->InterfaceActive ? " (Primary)" : "");
4184
4185 if (!n->McastTxRx)
4186 debugf("SetupActiveInterfaces: No Tx/Rx on %5s(%lu) %.6a InterfaceID %p %#a", i->ifinfo.ifname, i->scope_id, &i->BSSID, primary, &n->ip);
4187 else
4188 {
4189 if (i->sa_family == AF_INET)
4190 {
4191 struct ip_mreq imr;
4192 primary->ifa_v4addr.s_addr = n->ip.ip.v4.NotAnInteger;
4193 imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
4194 imr.imr_interface = primary->ifa_v4addr;
4195
4196 // If this is our *first* IPv4 instance for this interface name, we need to do a IP_DROP_MEMBERSHIP first,
4197 // before trying to join the group, to clear out stale kernel state which may be lingering.
4198 // In particular, this happens with removable network interfaces like USB Ethernet adapters -- the kernel has stale state
4199 // from the last time the USB Ethernet adapter was connected, and part of the kernel thinks we've already joined the group
4200 // on that interface (so we get EADDRINUSE when we try to join again) but a different part of the kernel thinks we haven't
4201 // joined the group (so we receive no multicasts). Doing an IP_DROP_MEMBERSHIP before joining seems to flush the stale state.
4202 // Also, trying to make the code leave the group when the adapter is removed doesn't work either,
4203 // because by the time we get the configuration change notification, the interface is already gone,
4204 // so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address").
4205 // <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
4206 if (SearchForInterfaceByName(m, i->ifinfo.ifname, AF_INET) == i)
4207 {
4208 LogInfo("SetupActiveInterfaces: %5s(%lu) Doing precautionary IP_DROP_MEMBERSHIP for %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
4209 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(imr));
4210 if (err < 0 && (errno != EADDRNOTAVAIL))
4211 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err, errno, strerror(errno));
4212 }
4213
4214 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
4215 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
4216 // Joining same group twice can give "Address already in use" error -- no need to report that
4217 if (err < 0 && (errno != EADDRINUSE))
4218 LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %d errno %d (%s) group %.4a on %.4a", err, errno, strerror(errno), &imr.imr_multiaddr, &imr.imr_interface);
4219 }
4220 #ifndef NO_IPV6
4221 if (i->sa_family == AF_INET6)
4222 {
4223 struct ipv6_mreq i6mr;
4224 i6mr.ipv6mr_interface = primary->scope_id;
4225 i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
4226
4227 if (SearchForInterfaceByName(m, i->ifinfo.ifname, AF_INET6) == i)
4228 {
4229 LogInfo("SetupActiveInterfaces: %5s(%lu) Doing precautionary IPV6_LEAVE_GROUP for %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
4230 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
4231 if (err < 0 && (errno != EADDRNOTAVAIL))
4232 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
4233 }
4234
4235 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
4236 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
4237 // Joining same group twice can give "Address already in use" error -- no need to report that
4238 if (err < 0 && (errno != EADDRINUSE))
4239 LogMsg("setsockopt - IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
4240 }
4241 #endif
4242 }
4243 }
4244 }
4245
4246 return count;
4247 }
4248
4249 mDNSlocal void MarkAllInterfacesInactive(mDNS *const m, mDNSs32 utc)
4250 {
4251 NetworkInterfaceInfoOSX *i;
4252 for (i = m->p->InterfaceList; i; i = i->next)
4253 {
4254 if (i->Exists) i->LastSeen = utc;
4255 i->Exists = mDNSfalse;
4256 }
4257 }
4258
4259 // returns count of non-link local V4 addresses deregistered
4260 mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc)
4261 {
4262 // First pass:
4263 // If an interface is going away, then deregister this from the mDNSCore.
4264 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
4265 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
4266 // it refers to has gone away we'll crash.
4267 NetworkInterfaceInfoOSX *i;
4268 int count = 0;
4269 for (i = m->p->InterfaceList; i; i = i->next)
4270 {
4271 // If this interface is no longer active, or its InterfaceID is changing, deregister it
4272 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifinfo.ifname, AAAA_OVER_V4 ? AF_UNSPEC : i->sa_family);
4273 if (i->ifinfo.InterfaceID)
4274 if (i->Exists == 0 || i->Exists == 2 || i->ifinfo.InterfaceID != (mDNSInterfaceID)primary)
4275 {
4276 i->Flashing = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->AppearanceTime < 60);
4277 LogInfo("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s",
4278 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID,
4279 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask),
4280 i->Flashing ? " (Flashing)" : "",
4281 i->Occulting ? " (Occulting)" : "",
4282 i->ifinfo.InterfaceActive ? " (Primary)" : "");
4283 mDNS_DeregisterInterface(m, &i->ifinfo, i->Flashing && i->Occulting);
4284 if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++;
4285 i->ifinfo.InterfaceID = mDNSNULL;
4286 // Note: If i->ifinfo.InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
4287 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
4288 // If i->ifinfo.InterfaceID is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
4289
4290 // Caution: If we ever decide to add code here to leave the multicast group, we need to make sure that this
4291 // is the LAST representative of this physical interface, or we'll unsubscribe from the group prematurely.
4292 }
4293 }
4294
4295 // Second pass:
4296 // Now that everything that's going to deregister has done so, we can clean up and free the memory
4297 NetworkInterfaceInfoOSX **p = &m->p->InterfaceList;
4298 while (*p)
4299 {
4300 i = *p;
4301 // If no longer active, delete interface from list and free memory
4302 if (!i->Exists)
4303 {
4304 if (i->LastSeen == utc) i->LastSeen = utc - 1;
4305 mDNSBool delete = (NumCacheRecordsForInterfaceID(m, (mDNSInterfaceID)i) == 0) && (utc - i->LastSeen >= 60);
4306 LogInfo("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
4307 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID,
4308 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), utc - i->LastSeen,
4309 i->ifinfo.InterfaceActive ? " (Primary)" : "");
4310 #if APPLE_OSX_mDNSResponder
4311 if (i->BPF_fd >= 0) CloseBPF(i);
4312 #endif // APPLE_OSX_mDNSResponder
4313 if (delete)
4314 {
4315 *p = i->next;
4316 freeL("NetworkInterfaceInfoOSX", i);
4317 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
4318 }
4319 }
4320 p = &i->next;
4321 }
4322 return count;
4323 }
4324
4325 mDNSlocal void AppendDNameListElem(DNameListElem ***List, mDNSu32 uid, domainname *name)
4326 {
4327 DNameListElem *dnle = (DNameListElem*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem));
4328 if (!dnle) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
4329 else
4330 {
4331 dnle->next = mDNSNULL;
4332 dnle->uid = uid;
4333 AssignDomainName(&dnle->name, name);
4334 **List = dnle;
4335 *List = &dnle->next;
4336 }
4337 }
4338
4339 mDNSlocal int compare_dns_configs(const void *aa, const void *bb)
4340 {
4341 dns_resolver_t *a = *(dns_resolver_t**)aa;
4342 dns_resolver_t *b = *(dns_resolver_t**)bb;
4343
4344 return (a->search_order < b->search_order) ? -1 : (a->search_order == b->search_order) ? 0 : 1;
4345 }
4346
4347 mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains)
4348 {
4349 int i;
4350 char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
4351 domainname d;
4352
4353 // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
4354 if (fqdn) fqdn->c[0] = 0;
4355 if (RegDomains ) *RegDomains = NULL;
4356 if (BrowseDomains) *BrowseDomains = NULL;
4357
4358 LogInfo("mDNSPlatformSetDNSConfig:%s%s%s%s%s",
4359 setservers ? " setservers" : "",
4360 setsearch ? " setsearch" : "",
4361 fqdn ? " fqdn" : "",
4362 RegDomains ? " RegDomains" : "",
4363 BrowseDomains ? " BrowseDomains" : "");
4364
4365 // Add the inferred address-based configuration discovery domains
4366 // (should really be in core code I think, not platform-specific)
4367 if (setsearch)
4368 {
4369 struct ifaddrs *ifa = mDNSNULL;
4370 struct sockaddr_in saddr;
4371 mDNSPlatformMemZero(&saddr, sizeof(saddr));
4372 saddr.sin_len = sizeof(saddr);
4373 saddr.sin_family = AF_INET;
4374 saddr.sin_port = 0;
4375 saddr.sin_addr.s_addr = *(in_addr_t *)&m->Router.ip.v4;
4376
4377 // Don't add any reverse-IP search domains if doing the WAB bootstrap queries would cause dial-on-demand connection initiation
4378 if (!AddrRequiresPPPConnection((struct sockaddr *)&saddr)) ifa = myGetIfAddrs(1);
4379
4380 while (ifa)
4381 {
4382 mDNSAddr a, n;
4383 if (ifa->ifa_addr->sa_family == AF_INET &&
4384 ifa->ifa_netmask &&
4385 !(ifa->ifa_flags & IFF_LOOPBACK) &&
4386 !SetupAddr(&a, ifa->ifa_addr) &&
4387 !mDNSv4AddressIsLinkLocal(&a.ip.v4) )
4388 {
4389 // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be incorrect, so we explicitly fix it here before calling SetupAddr
4390 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
4391 ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family; // Make sure ifa_netmask->sa_family is set correctly
4392 SetupAddr(&n, ifa->ifa_netmask);
4393 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
4394 mDNS_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa.", a.ip.v4.b[3] & n.ip.v4.b[3],
4395 a.ip.v4.b[2] & n.ip.v4.b[2],
4396 a.ip.v4.b[1] & n.ip.v4.b[1],
4397 a.ip.v4.b[0] & n.ip.v4.b[0]);
4398 mDNS_AddSearchDomain_CString(buf);
4399 }
4400 ifa = ifa->ifa_next;
4401 }
4402 }
4403
4404 #ifndef MDNS_NO_DNSINFO
4405 if (setservers || setsearch)
4406 {
4407 dns_config_t *config = dns_configuration_copy();
4408 if (!config)
4409 {
4410 // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
4411 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
4412 // Apparently this is expected behaviour -- "not a bug".
4413 // Accordingly, we suppress syslog messages for the first three minutes after boot.
4414 // If we are still getting failures after three minutes, then we log them.
4415 if (OSXVers > OSXVers_10_3_Panther && (mDNSu32)mDNSPlatformRawTime() > (mDNSu32)(mDNSPlatformOneSecond * 180))
4416 LogMsg("mDNSPlatformSetDNSConfig: Error: dns_configuration_copy returned NULL");
4417 }
4418 else
4419 {
4420 LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d", config->n_resolver);
4421 if (setsearch && config->n_resolver)
4422 {
4423 // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
4424 // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
4425 // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
4426 // instead use the search domain list as the sole authority for what domains to search and in what order
4427 // (and the domain from the "domain" field will also appear somewhere in that list).
4428 // Also, all search domains get added to the search list for resolver[0], so the domains and/or
4429 // search lists for other resolvers in the list need to be ignored.
4430 if (config->resolver[0]->n_search == 0) mDNS_AddSearchDomain_CString(config->resolver[0]->domain);
4431 else for (i = 0; i < config->resolver[0]->n_search; i++) mDNS_AddSearchDomain_CString(config->resolver[0]->search[i]);
4432 }
4433
4434 #if APPLE_OSX_mDNSResponder
4435 // Record the so-called "primary" domain, which we use as a hint to tell if the user is on a network set up
4436 // by someone using Microsoft Active Directory using "local" as a private internal top-level domain
4437 if (config->n_resolver && config->resolver[0]->domain && config->resolver[0]->n_nameserver && config->resolver[0]->nameserver[0])
4438 MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, config->resolver[0]->domain);
4439 else ActiveDirectoryPrimaryDomain.c[0] = 0;
4440 //MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, "test.local");
4441 ActiveDirectoryPrimaryDomainLabelCount = CountLabels(&ActiveDirectoryPrimaryDomain);
4442 if (config->n_resolver && config->resolver[0]->n_nameserver && SameDomainName(SkipLeadingLabels(&ActiveDirectoryPrimaryDomain, ActiveDirectoryPrimaryDomainLabelCount - 1), &localdomain))
4443 SetupAddr(&ActiveDirectoryPrimaryDomainServer, config->resolver[0]->nameserver[0]);
4444 else
4445 {
4446 AssignDomainName(&ActiveDirectoryPrimaryDomain, (const domainname *)"");
4447 ActiveDirectoryPrimaryDomainLabelCount = 0;
4448 ActiveDirectoryPrimaryDomainServer = zeroAddr;
4449 }
4450 #endif
4451
4452 if (setservers)
4453 {
4454 // For the "default" resolver ("resolver #1") the "domain" value is bogus and we need to ignore it.
4455 // e.g. the default resolver's "domain" value might say "apple.com", which indicates that this resolver
4456 // is only for names that fall under "apple.com", but that's not correct. Actually the default resolver is
4457 // for all names not covered by a more specific resolver (i.e. its domain should be ".", the root domain).
4458 if (config->n_resolver && config->resolver[0]->domain)
4459 config->resolver[0]->domain[0] = 0; // don't stop pointing at the memory, just change the first byte
4460
4461 qsort(config->resolver, config->n_resolver, sizeof(dns_resolver_t*), compare_dns_configs);
4462
4463 for (i = 0; i < config->n_resolver; i++)
4464 {
4465 int n;
4466 dns_resolver_t *r = config->resolver[i];
4467 mDNSInterfaceID interface = mDNSInterface_Any;
4468 int disabled = 0;
4469
4470 // On Tiger, dnsinfo entries for mDNS domains have port 5353, the mDNS port. Ignore them.
4471 // Note: Unlike the BSD Sockets APIs (where TCP and UDP port numbers are universally in network byte order)
4472 // in Apple's "dnsinfo.h" API the port number is declared to be a "uint16_t in host byte order"
4473 // We also don't need to do any more work if there are no nameserver addresses
4474 if (r->port == 5353 || r->n_nameserver == 0) continue;
4475
4476 if (!r->domain || !*r->domain) d.c[0] = 0;
4477 else if (!MakeDomainNameFromDNSNameString(&d, r->domain)) { LogMsg("mDNSPlatformSetDNSConfig: bad domain %s", r->domain); continue; }
4478
4479 // DNS server option parsing
4480 if (r->options != NULL)
4481 {
4482 char *nextOption = r->options;
4483 char *currentOption = NULL;
4484 while ((currentOption = strsep(&nextOption, " ")) != NULL && currentOption[0] != 0)
4485 {
4486 // The option may be in the form of interface=xxx where xxx is an interface name.
4487 if (strncmp(currentOption, kInterfaceSpecificOption, sizeof(kInterfaceSpecificOption) - 1) == 0)
4488 {
4489 NetworkInterfaceInfoOSX *ni;
4490 char ifname[IF_NAMESIZE+1];
4491 mDNSu32 ifindex = 0;
4492 // If something goes wrong finding the interface, create the server entry anyhow but mark it as disabled.
4493 // This allows us to block these special queries from going out on the wire.
4494 strlcpy(ifname, currentOption + sizeof(kInterfaceSpecificOption)-1, sizeof(ifname));
4495 ifindex = if_nametoindex(ifname);
4496 if (ifindex == 0) { disabled = 1; LogMsg("RegisterSplitDNS: interfaceSpecific - interface %s not found", ifname); continue; }
4497 LogInfo("%s: Interface-specific entry: %s on %s (%d)", __FUNCTION__, r->domain, ifname, ifindex);
4498 // Find the interface, can't use mDNSPlatformInterfaceIDFromInterfaceIndex
4499 // because that will call mDNSMacOSXNetworkChanged if the interface doesn't exist
4500 for (ni = m->p->InterfaceList; ni; ni = ni->next)
4501 if (ni->ifinfo.InterfaceID && ni->scope_id == ifindex) break;
4502 if (ni != NULL) interface = ni->ifinfo.InterfaceID;
4503 if (interface == mDNSNULL) { disabled = 1; LogMsg("RegisterSplitDNS: interfaceSpecific - index %d (%s) not found", ifindex, ifname); continue; }
4504 }
4505 }
4506 }
4507
4508 for (n = 0; n < r->n_nameserver; n++)
4509 if (r->nameserver[n]->sa_family == AF_INET || r->nameserver[n]->sa_family == AF_INET6)
4510 {
4511 mDNSAddr saddr;
4512 // mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 192, 168, 1, 1 } } } }; // for testing
4513 if (SetupAddr(&saddr, r->nameserver[n])) LogMsg("RegisterSplitDNS: bad IP address");
4514 else
4515 {
4516 DNSServer *s = mDNS_AddDNSServer(m, &d, interface, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort);
4517 if (s)
4518 {
4519 if (disabled) s->teststate = DNSServer_Disabled;
4520 LogInfo("Added dns server %#a:%d for domain %##s from slot %d,%d", &s->addr, mDNSVal16(s->port), d.c, i, n);
4521 }
4522 }
4523 }
4524
4525 }
4526 }
4527
4528 dns_configuration_free(config);
4529 setservers = mDNSfalse; // Done these now -- no need to fetch the same data from SCDynamicStore
4530 setsearch = mDNSfalse;
4531 }
4532 }
4533 #endif // MDNS_NO_DNSINFO
4534
4535 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformSetDNSConfig"), NULL, NULL);
4536 if (!store)
4537 LogMsg("mDNSPlatformSetDNSConfig: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
4538 else
4539 {
4540 CFDictionaryRef ddnsdict = SCDynamicStoreCopyValue(store, NetworkChangedKey_DynamicDNS);
4541 if (ddnsdict)
4542 {
4543 if (fqdn)
4544 {
4545 CFArrayRef fqdnArray = CFDictionaryGetValue(ddnsdict, CFSTR("HostNames"));
4546 if (fqdnArray && CFArrayGetCount(fqdnArray) > 0)
4547 {
4548 // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
4549 CFDictionaryRef fqdnDict = CFArrayGetValueAtIndex(fqdnArray, 0);
4550 if (fqdnDict && DictionaryIsEnabled(fqdnDict))
4551 {
4552 CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain"));
4553 if (name)
4554 {
4555 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
4556 !MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0])
4557 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)");
4558 else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf);
4559 }
4560 }
4561 }
4562 }
4563
4564 if (RegDomains)
4565 {
4566 CFArrayRef regArray = CFDictionaryGetValue(ddnsdict, CFSTR("RegistrationDomains"));
4567 if (regArray && CFArrayGetCount(regArray) > 0)
4568 {
4569 CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0);
4570 if (regDict && DictionaryIsEnabled(regDict))
4571 {
4572 CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain"));
4573 if (name)
4574 {
4575 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
4576 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
4577 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)");
4578 else
4579 {
4580 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf);
4581 AppendDNameListElem(&RegDomains, 0, &d);
4582 }
4583 }
4584 }
4585 }
4586 }
4587
4588 if (BrowseDomains)
4589 {
4590 CFArrayRef browseArray = CFDictionaryGetValue(ddnsdict, CFSTR("BrowseDomains"));
4591 if (browseArray)
4592 {
4593 for (i = 0; i < CFArrayGetCount(browseArray); i++)
4594 {
4595 CFDictionaryRef browseDict = CFArrayGetValueAtIndex(browseArray, i);
4596 if (browseDict && DictionaryIsEnabled(browseDict))
4597 {
4598 CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain"));
4599 if (name)
4600 {
4601 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
4602 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
4603 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf[0] ? buf : "(unknown)");
4604 else
4605 {
4606 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf);
4607 AppendDNameListElem(&BrowseDomains, 0, &d);
4608 }
4609 }
4610 }
4611 }
4612 }
4613 }
4614 CFRelease(ddnsdict);
4615 }
4616
4617 if (RegDomains)
4618 {
4619 CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
4620 if (btmm)
4621 {
4622 CFIndex size = CFDictionaryGetCount(btmm);
4623 const void *key[size];
4624 const void *val[size];
4625 CFDictionaryGetKeysAndValues(btmm, key, val);
4626 for (i = 0; i < size; i++)
4627 {
4628 LogInfo("BackToMyMac %d", i);
4629 if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
4630 LogMsg("Can't read BackToMyMac %d key %s", i, buf);
4631 else
4632 {
4633 mDNSu32 uid = atoi(buf);
4634 if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
4635 LogMsg("Can't read BackToMyMac %d val %s", i, buf);
4636 else if (MakeDomainNameFromDNSNameString(&d, buf) && d.c[0])
4637 {
4638 LogInfo("BackToMyMac %d %d %##s", i, uid, d.c);
4639 AppendDNameListElem(&RegDomains, uid, &d);
4640 }
4641 }
4642 }
4643 CFRelease(btmm);
4644 }
4645 }
4646
4647 if (setservers || setsearch)
4648 {
4649 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_DNS);
4650 if (dict)
4651 {
4652 if (setservers)
4653 {
4654 CFArrayRef values = CFDictionaryGetValue(dict, kSCPropNetDNSServerAddresses);
4655 if (values)
4656 {
4657 LogInfo("DNS Server Address values: %d", CFArrayGetCount(values));
4658 for (i = 0; i < CFArrayGetCount(values); i++)
4659 {
4660 CFStringRef s = CFArrayGetValueAtIndex(values, i);
4661 mDNSAddr addr = { mDNSAddrType_IPv4, { { { 0 } } } };
4662 if (s && CFStringGetCString(s, buf, 256, kCFStringEncodingUTF8) &&
4663 inet_aton(buf, (struct in_addr *) &addr.ip.v4))
4664 {
4665 LogInfo("Adding DNS server from dict: %s", buf);
4666 mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, &addr, UnicastDNSPort);
4667 }
4668 }
4669 }
4670 else LogInfo("No DNS Server Address values");
4671 }
4672 if (setsearch)
4673 {
4674 // Add the manual and/or DHCP-dicovered search domains
4675 CFArrayRef searchDomains = CFDictionaryGetValue(dict, kSCPropNetDNSSearchDomains);
4676 if (searchDomains)
4677 {
4678 for (i = 0; i < CFArrayGetCount(searchDomains); i++)
4679 {
4680 CFStringRef s = CFArrayGetValueAtIndex(searchDomains, i);
4681 if (s && CFStringGetCString(s, buf, sizeof(buf), kCFStringEncodingUTF8))
4682 mDNS_AddSearchDomain_CString(buf);
4683 }
4684 }
4685 else // No kSCPropNetDNSSearchDomains, so use kSCPropNetDNSDomainName
4686 {
4687 // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
4688 // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
4689 // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
4690 // instead use the search domain list as the sole authority for what domains to search and in what order
4691 // (and the domain from the "domain" field will also appear somewhere in that list).
4692 CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetDNSDomainName);
4693 if (string && CFStringGetCString(string, buf, sizeof(buf), kCFStringEncodingUTF8))
4694 mDNS_AddSearchDomain_CString(buf);
4695 }
4696 }
4697 CFRelease(dict);
4698 }
4699 }
4700 CFRelease(store);
4701 }
4702 }
4703
4704 mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *r)
4705 {
4706 char buf[256];
4707 mStatus err = 0;
4708 (void)m; // Unused
4709
4710 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL, NULL);
4711 if (!store)
4712 LogMsg("mDNSPlatformGetPrimaryInterface: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
4713 else
4714 {
4715 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_IPv4);
4716 if (dict)
4717 {
4718 r->type = mDNSAddrType_IPv4;
4719 r->ip.v4 = zerov4Addr;
4720 CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
4721 if (string)
4722 {
4723 if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8))
4724 LogMsg("Could not convert router to CString");
4725 else
4726 {
4727 struct sockaddr_in saddr;
4728 saddr.sin_len = sizeof(saddr);
4729 saddr.sin_family = AF_INET;
4730 saddr.sin_port = 0;
4731 inet_aton(buf, &saddr.sin_addr);
4732
4733 *(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr;
4734 }
4735 }
4736
4737 string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
4738 if (string)
4739 {
4740 mDNSBool HavePrimaryGlobalv6 = mDNSfalse; // does the primary interface have a global v6 address?
4741 struct ifaddrs *ifa = myGetIfAddrs(1);
4742
4743 *v4 = *v6 = zeroAddr;
4744
4745 if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8)) { LogMsg("Could not convert router to CString"); goto exit; }
4746
4747 // find primary interface in list
4748 while (ifa && (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4) || !HavePrimaryGlobalv6))
4749 {
4750 mDNSAddr tmp6 = zeroAddr;
4751 if (!strcmp(buf, ifa->ifa_name))
4752 {
4753 if (ifa->ifa_addr->sa_family == AF_INET)
4754 {
4755 if (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4)) SetupAddr(v4, ifa->ifa_addr);
4756 }
4757 else if (ifa->ifa_addr->sa_family == AF_INET6)
4758 {
4759 SetupAddr(&tmp6, ifa->ifa_addr);
4760 if (tmp6.ip.v6.b[0] >> 5 == 1) // global prefix: 001
4761 { HavePrimaryGlobalv6 = mDNStrue; *v6 = tmp6; }
4762 }
4763 }
4764 else
4765 {
4766 // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
4767 if (!HavePrimaryGlobalv6 && ifa->ifa_addr->sa_family == AF_INET6 && !v6->ip.v6.b[0])
4768 {
4769 SetupAddr(&tmp6, ifa->ifa_addr);
4770 if (tmp6.ip.v6.b[0] >> 5 == 1) *v6 = tmp6;
4771 }
4772 }
4773 ifa = ifa->ifa_next;
4774 }
4775
4776 // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
4777 // V4 to communicate w/ our DNS server
4778 }
4779
4780 exit:
4781 CFRelease(dict);
4782 }
4783 CFRelease(store);
4784 }
4785 return err;
4786 }
4787
4788 mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
4789 {
4790 LogInfo("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status, dname->c);
4791 char uname[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
4792 ConvertDomainNameToCString(dname, uname);
4793
4794 char *p = uname;
4795 while (*p)
4796 {
4797 *p = tolower(*p);
4798 if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
4799 p++;
4800 }
4801
4802 // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
4803 // That single entity is a CFDictionary with name "HostNames".
4804 // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
4805 // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
4806 // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
4807 // The CFDictionary for each FQDN holds (at present) a single name/value pair,
4808 // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
4809
4810 const CFStringRef StateKeys [1] = { CFSTR("HostNames") };
4811 const CFStringRef HostKeys [1] = { CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8) };
4812 const CFStringRef StatusKeys[1] = { CFSTR("Status") };
4813 if (!HostKeys[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname);
4814 else
4815 {
4816 const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) };
4817 if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status);
4818 else
4819 {
4820 const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
4821 if (HostVals[0])
4822 {
4823 const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
4824 if (StateVals[0])
4825 {
4826 CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
4827 if (StateDict)
4828 {
4829 mDNSDynamicStoreSetConfig(kmDNSDynamicConfig, mDNSNULL, StateDict);
4830 CFRelease(StateDict);
4831 }
4832 CFRelease(StateVals[0]);
4833 }
4834 CFRelease(HostVals[0]);
4835 }
4836 CFRelease(StatusVals[0]);
4837 }
4838 CFRelease(HostKeys[0]);
4839 }
4840 }
4841
4842 // MUST be called holding the lock -- this routine calls SetupLocalAutoTunnelInterface_internal()
4843 mDNSexport void SetDomainSecrets(mDNS *m)
4844 {
4845 #ifdef NO_SECURITYFRAMEWORK
4846 (void)m;
4847 LogMsg("Note: SetDomainSecrets: no keychain support");
4848 #else
4849 mDNSBool haveAutoTunnels = mDNSfalse;
4850
4851 LogInfo("SetDomainSecrets");
4852
4853 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
4854 // In the case where the user simultaneously removes their DDNS host name and the key
4855 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
4856 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
4857 // address records behind that we no longer have permission to delete.
4858 DomainAuthInfo *ptr;
4859 for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
4860 ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10);
4861
4862 #if APPLE_OSX_mDNSResponder
4863 {
4864 // Mark all TunnelClients for deletion
4865 ClientTunnel *client;
4866 for (client = m->TunnelClients; client; client = client->next)
4867 {
4868 LogInfo("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c);
4869 client->MarkedForDeletion = mDNStrue;
4870 }
4871 }
4872 #endif // APPLE_OSX_mDNSResponder
4873
4874 // String Array used to write list of private domains to Dynamic Store
4875 CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
4876 if (!sa) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
4877 CFIndex i;
4878 CFDataRef data = NULL;
4879 const int itemsPerEntry = 3; // domain name, key name, key value
4880 CFArrayRef secrets = NULL;
4881 int err = mDNSKeychainGetSecrets(&secrets);
4882 if (err || !secrets)
4883 LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err, secrets);
4884 else
4885 {
4886 CFIndex ArrayCount = CFArrayGetCount(secrets);
4887 // Iterate through the secrets
4888 for (i = 0; i < ArrayCount; ++i)
4889 {
4890 int j;
4891 CFArrayRef entry = CFArrayGetValueAtIndex(secrets, i);
4892 if (CFArrayGetTypeID() != CFGetTypeID(entry) || itemsPerEntry != CFArrayGetCount(entry))
4893 { LogMsg("SetDomainSecrets: malformed entry"); continue; }
4894 for (j = 0; j < CFArrayGetCount(entry); ++j)
4895 if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry, j)))
4896 { LogMsg("SetDomainSecrets: malformed entry item"); continue; }
4897
4898 // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
4899
4900 // Get DNS domain this key is for
4901 char stringbuf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal domainname as C-string, including terminating NUL
4902 data = CFArrayGetValueAtIndex(entry, 0);
4903 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
4904 { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data)); continue; }
4905 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
4906 stringbuf[CFDataGetLength(data)] = '\0';
4907
4908 domainname domain;
4909 if (!MakeDomainNameFromDNSNameString(&domain, stringbuf)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf); continue; }
4910
4911 // Get key name
4912 data = CFArrayGetValueAtIndex(entry, 1);
4913 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
4914 { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data)); continue; }
4915 CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)stringbuf);
4916 stringbuf[CFDataGetLength(data)] = '\0';
4917
4918 domainname keyname;
4919 if (!MakeDomainNameFromDNSNameString(&keyname, stringbuf)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf); continue; }
4920
4921 // Get key data
4922 data = CFArrayGetValueAtIndex(entry, 2);
4923 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
4924 { LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data)); continue; }
4925 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
4926 stringbuf[CFDataGetLength(data)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key
4927
4928 DomainAuthInfo *FoundInList;
4929 for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
4930 if (SameDomainName(&FoundInList->domain, &domain)) break;
4931
4932 #if APPLE_OSX_mDNSResponder
4933 if (FoundInList)
4934 {
4935 // If any client tunnel destination is in this domain, set deletion flag to false
4936 ClientTunnel *client;
4937 for (client = m->TunnelClients; client; client = client->next)
4938 if (FoundInList == GetAuthInfoForName_internal(m, &client->dstname))
4939 {
4940 LogInfo("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client->dstname.c);
4941 client->MarkedForDeletion = mDNSfalse;
4942 }
4943 }
4944
4945 #endif // APPLE_OSX_mDNSResponder
4946
4947 // Uncomment the line below to view the keys as they're read out of the system keychain
4948 // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
4949 //LogInfo("SetDomainSecrets: %##s %##s %s", &domain.c, &keyname.c, stringbuf);
4950
4951 // If didn't find desired domain in the list, make a new entry
4952 ptr = FoundInList;
4953 if (FoundInList && FoundInList->AutoTunnel && haveAutoTunnels == mDNSfalse) haveAutoTunnels = mDNStrue;
4954 if (!FoundInList)
4955 {
4956 ptr = (DomainAuthInfo*)mallocL("DomainAuthInfo", sizeof(*ptr));
4957 if (!ptr) { LogMsg("SetDomainSecrets: No memory"); continue; }
4958 }
4959
4960 LogInfo("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain);
4961 if (mDNS_SetSecretForDomain(m, ptr, &domain, &keyname, stringbuf, IsTunnelModeDomain(&domain)) == mStatus_BadParamErr)
4962 {
4963 if (!FoundInList) mDNSPlatformMemFree(ptr); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
4964 continue;
4965 }
4966
4967 #if APPLE_OSX_mDNSResponder
4968 if (ptr->AutoTunnel) UpdateAutoTunnelDomainStatus(m, ptr);
4969 #endif // APPLE_OSX_mDNSResponder
4970
4971 ConvertDomainNameToCString(&domain, stringbuf);
4972 CFStringRef cfs = CFStringCreateWithCString(NULL, stringbuf, kCFStringEncodingUTF8);
4973 if (cfs) { CFArrayAppendValue(sa, cfs); CFRelease(cfs); }
4974 }
4975 CFRelease(secrets);
4976 }
4977 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, sa);
4978 CFRelease(sa);
4979
4980 #if APPLE_OSX_mDNSResponder
4981 {
4982 // clean up ClientTunnels
4983 ClientTunnel **pp = &m->TunnelClients;
4984 while (*pp)
4985 {
4986 if ((*pp)->MarkedForDeletion)
4987 {
4988 ClientTunnel *cur = *pp;
4989 LogInfo("SetDomainSecrets: removing client %p %##s from list", cur, cur->dstname.c);
4990 if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
4991 AutoTunnelSetKeys(cur, mDNSfalse);
4992 *pp = cur->next;
4993 freeL("ClientTunnel", cur);
4994 }
4995 else
4996 pp = &(*pp)->next;
4997 }
4998
4999 DomainAuthInfo *info = m->AuthInfoList;
5000 while (info)
5001 {
5002 if (info->AutoTunnel && info->deltime)
5003 {
5004 if (info->AutoTunnelNAT.clientContext)
5005 {
5006 // stop the NAT operation
5007 mDNS_StopNATOperation_internal(m, &info->AutoTunnelNAT);
5008 if (info->AutoTunnelNAT.clientCallback)
5009 {
5010 // Reset port and let the AutoTunnelNATCallback handle cleanup
5011 info->AutoTunnelNAT.ExternalAddress = m->ExternalAddress;
5012 info->AutoTunnelNAT.ExternalPort = zeroIPPort;
5013 info->AutoTunnelNAT.Lifetime = 0;
5014 info->AutoTunnelNAT.Result = mStatus_NoError;
5015 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
5016 info->AutoTunnelNAT.clientCallback(m, &info->AutoTunnelNAT);
5017 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
5018 }
5019 info->AutoTunnelNAT.clientContext = mDNSNULL;
5020 }
5021 RemoveAutoTunnelDomainStatus(m, info);
5022 }
5023 info = info->next;
5024 }
5025
5026 if (!haveAutoTunnels && !m->TunnelClients && m->AutoTunnelHostAddrActive)
5027 {
5028 // remove interface if no autotunnel servers and no more client tunnels
5029 LogInfo("SetDomainSecrets: Bringing tunnel interface DOWN");
5030 m->AutoTunnelHostAddrActive = mDNSfalse;
5031 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown, m->AutoTunnelHostAddr.b);
5032 mDNSPlatformMemZero(m->AutoTunnelHostAddr.b, sizeof(m->AutoTunnelHostAddr.b));
5033 }
5034
5035 UpdateConfigureServer(m);
5036
5037 if (m->AutoTunnelHostAddr.b[0])
5038 if (TunnelClients(m) || TunnelServers(m))
5039 SetupLocalAutoTunnelInterface_internal(m);
5040 }
5041 #endif // APPLE_OSX_mDNSResponder
5042
5043 #endif /* NO_SECURITYFRAMEWORK */
5044 }
5045
5046 mDNSlocal void SetLocalDomains(void)
5047 {
5048 CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
5049 if (!sa) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
5050
5051 CFArrayAppendValue(sa, CFSTR("local"));
5052 CFArrayAppendValue(sa, CFSTR("254.169.in-addr.arpa"));
5053 CFArrayAppendValue(sa, CFSTR("8.e.f.ip6.arpa"));
5054 CFArrayAppendValue(sa, CFSTR("9.e.f.ip6.arpa"));
5055 CFArrayAppendValue(sa, CFSTR("a.e.f.ip6.arpa"));
5056 CFArrayAppendValue(sa, CFSTR("b.e.f.ip6.arpa"));
5057
5058 mDNSDynamicStoreSetConfig(kmDNSMulticastConfig, mDNSNULL, sa);
5059 CFRelease(sa);
5060 }
5061
5062 mDNSlocal void GetCurrentPMSetting(const CFStringRef name, mDNSs32 *val)
5063 {
5064 #if USE_IOPMCOPYACTIVEPMPREFERENCES
5065 CFTypeRef blob = NULL;
5066 CFStringRef str = NULL;
5067 CFDictionaryRef odict = NULL;
5068 CFDictionaryRef idict = NULL;
5069 CFNumberRef number = NULL;
5070
5071 blob = IOPSCopyPowerSourcesInfo();
5072 if (!blob) { LogMsg("GetCurrentPMSetting: IOPSCopyPowerSourcesInfo failed!"); goto end; }
5073
5074 odict = IOPMCopyActivePMPreferences();
5075 if (!odict) { LogMsg("GetCurrentPMSetting: IOPMCopyActivePMPreferences failed!"); goto end; }
5076
5077 str = IOPSGetProvidingPowerSourceType(blob);
5078 if (!str) { LogMsg("GetCurrentPMSetting: IOPSGetProvidingPowerSourceType failed!"); goto end; }
5079
5080 idict = CFDictionaryGetValue(odict, str);
5081 if (!idict)
5082 {
5083 char buf[256];
5084 if (!CFStringGetCString(str, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
5085 LogMsg("GetCurrentPMSetting: CFDictionaryGetValue (%s) failed!", buf);
5086 goto end;
5087 }
5088
5089 number = CFDictionaryGetValue(idict, name);
5090 if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
5091 *val = 0;
5092 end:
5093 if (blob) CFRelease(blob);
5094 if (odict) CFRelease(odict);
5095
5096 #else
5097
5098 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetCurrentPMSetting"), NULL, NULL);
5099 if (!store) LogMsg("GetCurrentPMSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
5100 else
5101 {
5102 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, CFSTR("State:/IOKit/PowerManagement/CurrentSettings"));
5103 if (!dict) LogSPS("GetCurrentPMSetting: Could not get IOPM CurrentSettings dict");
5104 else
5105 {
5106 CFNumberRef number = CFDictionaryGetValue(dict, name);
5107 if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
5108 *val = 0;
5109 CFRelease(dict);
5110 }
5111 CFRelease(store);
5112 }
5113
5114 #endif
5115 }
5116
5117 #if APPLE_OSX_mDNSResponder
5118
5119 static CFMutableDictionaryRef spsStatusDict = NULL;
5120 static const CFStringRef kMetricRef = CFSTR("Metric");
5121
5122 mDNSlocal void SPSStatusPutNumber(CFMutableDictionaryRef dict, const mDNSu8* const ptr, CFStringRef key)
5123 {
5124 mDNSu8 tmp = (ptr[0] - '0') * 10 + ptr[1] - '0';
5125 CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt8Type, &tmp);
5126 if (!num)
5127 LogMsg("SPSStatusPutNumber: Could not create CFNumber");
5128 else
5129 {
5130 CFDictionarySetValue(dict, key, num);
5131 CFRelease(num);
5132 }
5133 }
5134
5135 mDNSlocal CFMutableDictionaryRef SPSCreateDict(const mDNSu8* const ptr)
5136 {
5137 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
5138 if (!dict) { LogMsg("SPSCreateDict: Could not create CFDictionary dict"); return dict; }
5139
5140 char buffer[1024];
5141 buffer[mDNS_snprintf(buffer, sizeof(buffer), "%##s", ptr) - 1] = 0;
5142 CFStringRef spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
5143 if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname full"); CFRelease(dict); return NULL; }
5144 CFDictionarySetValue(dict, CFSTR("FullName"), spsname);
5145 CFRelease(spsname);
5146
5147 if (ptr[0] >= 2) SPSStatusPutNumber(dict, ptr + 1, CFSTR("Type"));
5148 if (ptr[0] >= 5) SPSStatusPutNumber(dict, ptr + 4, CFSTR("Portability"));
5149 if (ptr[0] >= 8) SPSStatusPutNumber(dict, ptr + 7, CFSTR("MarginalPower"));
5150 if (ptr[0] >= 11) SPSStatusPutNumber(dict, ptr +10, CFSTR("TotalPower"));
5151
5152 mDNSu32 tmp = SPSMetric(ptr);
5153 CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tmp);
5154 if (!num)
5155 LogMsg("SPSCreateDict: Could not create CFNumber");
5156 else
5157 {
5158 CFDictionarySetValue(dict, kMetricRef, num);
5159 CFRelease(num);
5160 }
5161
5162 if (ptr[0] >= 12)
5163 {
5164 memcpy(buffer, ptr + 13, ptr[0] - 12);
5165 buffer[ptr[0] - 12] = 0;
5166 spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
5167 if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname"); CFRelease(dict); return NULL; }
5168 else
5169 {
5170 CFDictionarySetValue(dict, CFSTR("PrettyName"), spsname);
5171 CFRelease(spsname);
5172 }
5173 }
5174
5175 return dict;
5176 }
5177
5178 mDNSlocal CFComparisonResult CompareSPSEntries(const void *val1, const void *val2, void *context)
5179 {
5180 (void)context;
5181 return CFNumberCompare((CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val1, kMetricRef),
5182 (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val2, kMetricRef),
5183 NULL);
5184 }
5185
5186 mDNSlocal void UpdateSPSStatus(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
5187 {
5188 (void)m;
5189 NetworkInterfaceInfo* info = (NetworkInterfaceInfo*)question->QuestionContext;
5190 debugf("UpdateSPSStatus: %s %##s %s %s", info->ifname, question->qname.c, AddRecord ? "Add" : "Rmv", answer ? RRDisplayString(m, answer) : "<null>");
5191
5192 if (answer && SPSMetric(answer->rdata->u.name.c) > 999999) return; // Ignore instances with invalid names
5193
5194 if (!spsStatusDict)
5195 {
5196 spsStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
5197 if (!spsStatusDict) { LogMsg("UpdateSPSStatus: Could not create CFDictionary spsStatusDict"); return; }
5198 }
5199
5200 CFStringRef ifname = CFStringCreateWithCString(NULL, info->ifname, kCFStringEncodingUTF8);
5201 if (!ifname) { LogMsg("UpdateSPSStatus: Could not create CFString ifname"); return; }
5202
5203 CFMutableArrayRef array = NULL;
5204
5205 if (!CFDictionaryGetValueIfPresent(spsStatusDict, ifname, (const void**) &array))
5206 {
5207 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
5208 if (!array) { LogMsg("UpdateSPSStatus: Could not create CFMutableArray"); CFRelease(ifname); return; }
5209 CFDictionarySetValue(spsStatusDict, ifname, array);
5210 CFRelease(array); // let go of our reference, now that the dict has one
5211 }
5212 else
5213 if (!array) { LogMsg("UpdateSPSStatus: Could not get CFMutableArray for %s", info->ifname); CFRelease(ifname); return; }
5214
5215 if (!answer) // special call that means the question has been stopped (because the interface is going away)
5216 CFArrayRemoveAllValues(array);
5217 else
5218 {
5219 CFMutableDictionaryRef dict = SPSCreateDict(answer->rdata->u.name.c);
5220 if (!dict) { CFRelease(ifname); return; }
5221
5222 if (AddRecord)
5223 {
5224 if (!CFArrayContainsValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict))
5225 {
5226 int i=0;
5227 for (i=0; i<CFArrayGetCount(array); i++)
5228 if (CompareSPSEntries(CFArrayGetValueAtIndex(array, i), dict, NULL) != kCFCompareLessThan)
5229 break;
5230 CFArrayInsertValueAtIndex(array, i, dict);
5231 }
5232 else LogMsg("UpdateSPSStatus: %s array already contains %##s", info->ifname, answer->rdata->u.name.c);
5233 }
5234 else
5235 {
5236 CFIndex i = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict);
5237 if (i != -1) CFArrayRemoveValueAtIndex(array, i);
5238 else LogMsg("UpdateSPSStatus: %s array does not contain %##s", info->ifname, answer->rdata->u.name.c);
5239 }
5240
5241 CFRelease(dict);
5242 }
5243
5244 if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, info->ifname, array);
5245
5246 CFRelease(ifname);
5247 }
5248
5249 mDNSlocal mDNSs32 GetSystemSleepTimerSetting(void)
5250 {
5251 mDNSs32 val = -1;
5252 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetSystemSleepTimerSetting"), NULL, NULL);
5253 if (!store)
5254 LogMsg("GetSystemSleepTimerSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
5255 else
5256 {
5257 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, CFSTR("State:/IOKit/PowerManagement/CurrentSettings"));
5258 if (dict)
5259 {
5260 CFNumberRef number = CFDictionaryGetValue(dict, CFSTR("System Sleep Timer"));
5261 if (number) CFNumberGetValue(number, kCFNumberSInt32Type, &val);
5262 CFRelease(dict);
5263 }
5264 CFRelease(store);
5265 }
5266 return val;
5267 }
5268
5269 mDNSlocal void SetSPS(mDNS *const m)
5270 {
5271 SCPreferencesSynchronize(m->p->SCPrefs);
5272 CFDictionaryRef dict = SCPreferencesGetValue(m->p->SCPrefs, CFSTR("NAT"));
5273 mDNSBool natenabled = (dict && (CFGetTypeID(dict) == CFDictionaryGetTypeID()) && DictionaryIsEnabled(dict));
5274 mDNSu8 sps = natenabled ? 50 : (OfferSleepProxyService && GetSystemSleepTimerSetting() == 0) ? OfferSleepProxyService : 0;
5275
5276 // For devices that are not running NAT, but are set to never sleep, we may choose to act
5277 // as a Sleep Proxy, but only for non-portable Macs (Portability > 35 means nominal weight < 3kg)
5278 if (sps > 50 && SPMetricPortability > 35) sps = 0;
5279
5280 // If we decide to let laptops act as Sleep Proxy, we should do it only when running on AC power, not on battery
5281
5282 // For devices that are unable to sleep at all to save power (e.g. the current Apple TV hardware)
5283 // it makes sense for them to offer low-priority Sleep Proxy service on the network.
5284 // We rate such a device as metric 70 ("Incidentally Available Hardware")
5285 if (SPMetricMarginalPower == 10 && (!sps || sps > 70)) sps = 70;
5286
5287 mDNSCoreBeSleepProxyServer(m, sps, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower);
5288 }
5289
5290 mDNSlocal void InternetSharingChanged(SCPreferencesRef prefs, SCPreferencesNotification notificationType, void *context)
5291 {
5292 (void)prefs; // Parameter not used
5293 (void)notificationType; // Parameter not used
5294 mDNS *const m = (mDNS *const)context;
5295 KQueueLock(m);
5296 mDNS_Lock(m);
5297
5298 // Tell platform layer to open or close its BPF fds
5299 if (!m->p->NetworkChanged ||
5300 m->p->NetworkChanged - NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2) < 0)
5301 {
5302 m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
5303 LogInfo("InternetSharingChanged: Set NetworkChanged to %d (%d)", m->p->NetworkChanged - m->timenow, m->p->NetworkChanged);
5304 }
5305
5306 mDNS_Unlock(m);
5307 KQueueUnlock(m, "InternetSharingChanged");
5308 }
5309
5310 mDNSlocal mStatus WatchForInternetSharingChanges(mDNS *const m)
5311 {
5312 SCPreferencesRef SCPrefs = SCPreferencesCreate(NULL, CFSTR("mDNSResponder:WatchForInternetSharingChanges"), CFSTR("com.apple.nat.plist"));
5313 if (!SCPrefs) { LogMsg("SCPreferencesCreate failed: %s", SCErrorString(SCError())); return(mStatus_NoMemoryErr); }
5314
5315 SCPreferencesContext context = { 0, m, NULL, NULL, NULL };
5316 if (!SCPreferencesSetCallback(SCPrefs, InternetSharingChanged, &context))
5317 { LogMsg("SCPreferencesSetCallback failed: %s", SCErrorString(SCError())); CFRelease(SCPrefs); return(mStatus_NoMemoryErr); }
5318
5319 if (!SCPreferencesScheduleWithRunLoop(SCPrefs, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))
5320 { LogMsg("SCPreferencesScheduleWithRunLoop failed: %s", SCErrorString(SCError())); CFRelease(SCPrefs); return(mStatus_NoMemoryErr); }
5321
5322 m->p->SCPrefs = SCPrefs;
5323 return(mStatus_NoError);
5324 }
5325
5326 #endif // APPLE_OSX_mDNSResponder
5327
5328 static io_service_t g_rootdomain = MACH_PORT_NULL;
5329
5330 mDNSlocal mDNSBool SystemWakeForNetworkAccess(void)
5331 {
5332 mDNSs32 val = 0;
5333 CFBooleanRef clamshellStop = NULL;
5334 mDNSBool retnow = mDNSfalse;
5335
5336 GetCurrentPMSetting(CFSTR("Wake On LAN"), &val);
5337 LogSPS("SystemWakeForNetworkAccess: Wake On LAN: %d", val);
5338 if (!val) return mDNSfalse;
5339
5340 if (!g_rootdomain) g_rootdomain = IORegistryEntryFromPath(MACH_PORT_NULL, kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain");
5341 if (!g_rootdomain) { LogMsg("SystemWakeForNetworkAccess: IORegistryEntryFromPath failed; assuming no clamshell so can WOMP"); return mDNStrue; }
5342
5343 clamshellStop = (CFBooleanRef)IORegistryEntryCreateCFProperty(g_rootdomain, CFSTR(kAppleClamshellStateKey), kCFAllocatorDefault, 0);
5344 if (!clamshellStop) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellStateKey does not exist; assuming no clamshell so can WOMP"); return mDNStrue; }
5345 retnow = clamshellStop == kCFBooleanFalse;
5346 CFRelease(clamshellStop);
5347 if (retnow) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellStateKey is false; clamshell is open so can WOMP"); return mDNStrue; }
5348
5349 clamshellStop = (CFBooleanRef)IORegistryEntryCreateCFProperty(g_rootdomain, CFSTR(kAppleClamshellCausesSleepKey), kCFAllocatorDefault, 0);
5350 if (!clamshellStop) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellCausesSleepKey does not exist; assuming no clamshell so can WOMP"); return mDNStrue; }
5351 retnow = clamshellStop == kCFBooleanFalse;
5352 CFRelease(clamshellStop);
5353 if (retnow) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellCausesSleepKey is false; clamshell is closed but can WOMP"); return mDNStrue; }
5354
5355 LogSPS("SystemWakeForNetworkAccess: clamshell is closed and can't WOMP");
5356 return mDNSfalse;
5357 }
5358
5359 mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
5360 {
5361 LogInfo("*** Network Configuration Change *** (%d)%s",
5362 m->p->NetworkChanged ? mDNS_TimeNow(m) - m->p->NetworkChanged : 0,
5363 m->p->NetworkChanged ? "" : " (no scheduled configuration change)");
5364 m->p->NetworkChanged = 0; // If we received a network change event and deferred processing, we're now dealing with it
5365 mDNSs32 utc = mDNSPlatformUTC();
5366 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
5367 MarkAllInterfacesInactive(m, utc);
5368 UpdateInterfaceList(m, utc);
5369 ClearInactiveInterfaces(m, utc);
5370 SetupActiveInterfaces(m, utc);
5371
5372 #if APPLE_OSX_mDNSResponder
5373
5374 if (m->AutoTunnelHostAddr.b[0])
5375 {
5376 mDNS_Lock(m);
5377 if (TunnelClients(m) || TunnelServers(m))
5378 SetupLocalAutoTunnelInterface_internal(m);
5379 mDNS_Unlock(m);
5380 }
5381
5382 // Scan to find client tunnels whose questions have completed,
5383 // but whose local inner/outer addresses have changed since the tunnel was set up
5384 ClientTunnel *p;
5385 for (p = m->TunnelClients; p; p = p->next)
5386 if (p->q.ThisQInterval < 0)
5387 {
5388 mDNSAddr tmpSrc = zeroAddr;
5389 mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
5390 tmpDst.ip.v4 = p->rmt_outer;
5391 mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
5392 if (!mDNSSameIPv6Address(p->loc_inner, m->AutoTunnelHostAddr) ||
5393 !mDNSSameIPv4Address(p->loc_outer, tmpSrc.ip.v4))
5394 {
5395 AutoTunnelSetKeys(p, mDNSfalse);
5396 p->loc_inner = m->AutoTunnelHostAddr;
5397 p->loc_outer = tmpSrc.ip.v4;
5398 AutoTunnelSetKeys(p, mDNStrue);
5399 }
5400 }
5401
5402 SetSPS(m);
5403
5404 NetworkInterfaceInfoOSX *i;
5405 for (i = m->p->InterfaceList; i; i = i->next)
5406 {
5407 if (!m->SPSSocket) // Not being Sleep Proxy Server; close any open BPF fds
5408 {
5409 if (i->BPF_fd >= 0 && CountProxyTargets(m, i, mDNSNULL, mDNSNULL) == 0) CloseBPF(i);
5410 }
5411 else // else, we're Sleep Proxy Server; open BPF fds
5412 {
5413 if (i->Exists && i->ifinfo.InterfaceID == (mDNSInterfaceID)i && !(i->ifa_flags & IFF_LOOPBACK) && i->BPF_fd == -1)
5414 { LogSPS("%s requesting BPF", i->ifinfo.ifname); i->BPF_fd = -2; mDNSRequestBPF(); }
5415 }
5416 }
5417
5418 #endif // APPLE_OSX_mDNSResponder
5419
5420 uDNS_SetupDNSConfig(m);
5421 mDNS_ConfigChanged(m);
5422 }
5423
5424 // Called with KQueueLock & mDNS lock
5425 mDNSlocal void SetNetworkChanged(mDNS *const m, mDNSs32 delay)
5426 {
5427 if (!m->p->NetworkChanged || m->p->NetworkChanged - NonZeroTime(m->timenow + delay) < 0)
5428 {
5429 m->p->NetworkChanged = NonZeroTime(m->timenow + delay);
5430 LogInfo("SetNetworkChanged: setting network changed to %d (%d)", delay, m->p->NetworkChanged);
5431 }
5432 }
5433
5434
5435 mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
5436 {
5437 (void)store; // Parameter not used
5438 mDNS *const m = (mDNS *const)context;
5439 KQueueLock(m);
5440 mDNS_Lock(m);
5441
5442 mDNSs32 delay = mDNSPlatformOneSecond * 2; // Start off assuming a two-second delay
5443
5444 int c = CFArrayGetCount(changedKeys); // Count changes
5445 CFRange range = { 0, c };
5446 int c1 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Hostnames ) != 0);
5447 int c2 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Computername) != 0);
5448 int c3 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DynamicDNS ) != 0);
5449 int c4 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DNS ) != 0);
5450 if (c && c - c1 - c2 - c3 - c4 == 0) delay = mDNSPlatformOneSecond/10; // If these were the only changes, shorten delay
5451
5452 if (mDNS_LoggingEnabled)
5453 {
5454 int i;
5455 for (i=0; i<c; i++)
5456 {
5457 char buf[256];
5458 if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys, i), buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
5459 LogInfo("*** NetworkChanged SC key: %s", buf);
5460 }
5461 LogInfo("*** NetworkChanged *** %d change%s %s%s%s%sdelay %d",
5462 c, c>1?"s":"",
5463 c1 ? "(Local Hostname) " : "",
5464 c2 ? "(Computer Name) " : "",
5465 c3 ? "(DynamicDNS) " : "",
5466 c4 ? "(DNS) " : "",
5467 delay);
5468 }
5469
5470 SetNetworkChanged(m, delay);
5471
5472 // KeyChain frequently fails to notify clients of change events. To work around this
5473 // we set a timer and periodically poll to detect if any changes have occurred.
5474 // Without this Back To My Mac just does't work for a large number of users.
5475 // See <rdar://problem/5124399> Not getting Keychain Changed events when enabling BTMM
5476 if (c3 || CFArrayContainsValue(changedKeys, range, NetworkChangedKey_BackToMyMac))
5477 {
5478 LogInfo("*** NetworkChanged *** starting KeyChainBugTimer");
5479 m->p->KeyChainBugTimer = NonZeroTime(m->timenow + delay);
5480 m->p->KeyChainBugInterval = mDNSPlatformOneSecond;
5481 }
5482
5483 mDNS_Unlock(m);
5484
5485 // If DNS settings changed, immediately force a reconfig (esp. cache flush)
5486 if (c4) mDNSMacOSXNetworkChanged(m);
5487
5488 KQueueUnlock(m, "NetworkChanged");
5489 }
5490
5491 mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
5492 {
5493 mStatus err = -1;
5494 SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
5495 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged, &context);
5496 CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
5497 CFStringRef pattern1 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
5498 CFStringRef pattern2 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
5499 CFMutableArrayRef patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
5500
5501 if (!store) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error; }
5502 if (!keys || !pattern1 || !pattern2 || !patterns) goto error;
5503
5504 CFArrayAppendValue(keys, NetworkChangedKey_IPv4);
5505 CFArrayAppendValue(keys, NetworkChangedKey_IPv6);
5506 CFArrayAppendValue(keys, NetworkChangedKey_Hostnames);
5507 CFArrayAppendValue(keys, NetworkChangedKey_Computername);
5508 CFArrayAppendValue(keys, NetworkChangedKey_DNS);
5509 CFArrayAppendValue(keys, NetworkChangedKey_DynamicDNS);
5510 CFArrayAppendValue(keys, NetworkChangedKey_BackToMyMac);
5511 CFArrayAppendValue(keys, CFSTR("State:/IOKit/PowerManagement/CurrentSettings")); // should remove as part of <rdar://problem/6751656>
5512 CFArrayAppendValue(patterns, pattern1);
5513 CFArrayAppendValue(patterns, pattern2);
5514 CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
5515 if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns))
5516 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error; }
5517
5518 m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
5519 if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
5520
5521 CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
5522 m->p->Store = store;
5523 err = 0;
5524 goto exit;
5525
5526 error:
5527 if (store) CFRelease(store);
5528
5529 exit:
5530 if (patterns) CFRelease(patterns);
5531 if (pattern2) CFRelease(pattern2);
5532 if (pattern1) CFRelease(pattern1);
5533 if (keys) CFRelease(keys);
5534
5535 return(err);
5536 }
5537
5538 #if 0 // <rdar://problem/6751656>
5539 mDNSlocal void PMChanged(void *context)
5540 {
5541 mDNS *const m = (mDNS *const)context;
5542
5543 KQueueLock(m);
5544 mDNS_Lock(m);
5545
5546 LogSPS("PMChanged");
5547
5548 SetNetworkChanged(m, mDNSPlatformOneSecond * 2);
5549
5550 mDNS_Unlock(m);
5551 KQueueUnlock(m, "PMChanged");
5552 }
5553
5554 mDNSlocal mStatus WatchForPMChanges(mDNS *const m)
5555 {
5556 m->p->PMRLS = IOPMPrefsNotificationCreateRunLoopSource(PMChanged, m);
5557 if (!m->p->PMRLS) { LogMsg("IOPMPrefsNotificationCreateRunLoopSource failed!"); return mStatus_UnknownErr; }
5558
5559 CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->PMRLS, kCFRunLoopDefaultMode);
5560
5561 return mStatus_NoError;
5562 }
5563 #endif
5564
5565 #ifndef KEV_DL_WAKEFLAGS_CHANGED
5566 #define KEV_DL_WAKEFLAGS_CHANGED 17
5567 #endif
5568
5569 mDNSlocal void SysEventCallBack(int s1, short __unused filter, void *context)
5570 {
5571 mDNS *const m = (mDNS *const)context;
5572
5573 mDNS_Lock(m);
5574
5575 struct { struct kern_event_msg k; char extra[256]; } msg;
5576 int bytes = recv(s1, &msg, sizeof(msg), 0);
5577 if (bytes < 0)
5578 LogMsg("SysEventCallBack: recv error %d errno %d (%s)", bytes, errno, strerror(errno));
5579 else
5580 {
5581 LogInfo("SysEventCallBack got %d bytes size %d %X %s %X %s %X %s id %d code %d %s",
5582 bytes, msg.k.total_size,
5583 msg.k.vendor_code , msg.k.vendor_code == KEV_VENDOR_APPLE ? "KEV_VENDOR_APPLE" : "?",
5584 msg.k.kev_class , msg.k.kev_class == KEV_NETWORK_CLASS ? "KEV_NETWORK_CLASS" : "?",
5585 msg.k.kev_subclass, msg.k.kev_subclass == KEV_DL_SUBCLASS ? "KEV_DL_SUBCLASS" : "?",
5586 msg.k.id, msg.k.event_code,
5587 msg.k.event_code == KEV_DL_SIFFLAGS ? "KEV_DL_SIFFLAGS" :
5588 msg.k.event_code == KEV_DL_SIFMETRICS ? "KEV_DL_SIFMETRICS" :
5589 msg.k.event_code == KEV_DL_SIFMTU ? "KEV_DL_SIFMTU" :
5590 msg.k.event_code == KEV_DL_SIFPHYS ? "KEV_DL_SIFPHYS" :
5591 msg.k.event_code == KEV_DL_SIFMEDIA ? "KEV_DL_SIFMEDIA" :
5592 msg.k.event_code == KEV_DL_SIFGENERIC ? "KEV_DL_SIFGENERIC" :
5593 msg.k.event_code == KEV_DL_ADDMULTI ? "KEV_DL_ADDMULTI" :
5594 msg.k.event_code == KEV_DL_DELMULTI ? "KEV_DL_DELMULTI" :
5595 msg.k.event_code == KEV_DL_IF_ATTACHED ? "KEV_DL_IF_ATTACHED" :
5596 msg.k.event_code == KEV_DL_IF_DETACHING ? "KEV_DL_IF_DETACHING" :
5597 msg.k.event_code == KEV_DL_IF_DETACHED ? "KEV_DL_IF_DETACHED" :
5598 msg.k.event_code == KEV_DL_LINK_OFF ? "KEV_DL_LINK_OFF" :
5599 msg.k.event_code == KEV_DL_LINK_ON ? "KEV_DL_LINK_ON" :
5600 msg.k.event_code == KEV_DL_PROTO_ATTACHED ? "KEV_DL_PROTO_ATTACHED" :
5601 msg.k.event_code == KEV_DL_PROTO_DETACHED ? "KEV_DL_PROTO_DETACHED" :
5602 msg.k.event_code == KEV_DL_LINK_ADDRESS_CHANGED ? "KEV_DL_LINK_ADDRESS_CHANGED" :
5603 msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED ? "KEV_DL_WAKEFLAGS_CHANGED" : "?");
5604
5605 if (msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED) SetNetworkChanged(m, mDNSPlatformOneSecond * 2);
5606 }
5607
5608 mDNS_Unlock(m);
5609 }
5610
5611 mDNSlocal mStatus WatchForSysEvents(mDNS *const m)
5612 {
5613 m->p->SysEventNotifier = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
5614 if (m->p->SysEventNotifier < 0)
5615 { LogMsg("WatchForNetworkChanges: socket failed %s errno %d (%s)", errno, strerror(errno)); return(mStatus_NoMemoryErr); }
5616
5617 struct kev_request kev_req = { KEV_VENDOR_APPLE, KEV_NETWORK_CLASS, KEV_DL_SUBCLASS };
5618 int err = ioctl(m->p->SysEventNotifier, SIOCSKEVFILT, &kev_req);
5619 if (err < 0)
5620 {
5621 LogMsg("WatchForNetworkChanges: SIOCSKEVFILT failed %s errno %d (%s)", errno, strerror(errno));
5622 close(m->p->SysEventNotifier);
5623 m->p->SysEventNotifier = -1;
5624 return(mStatus_UnknownErr);
5625 }
5626
5627 m->p->SysEventKQueue.KQcallback = SysEventCallBack;
5628 m->p->SysEventKQueue.KQcontext = m;
5629 m->p->SysEventKQueue.KQtask = "System Event Notifier";
5630 KQueueSet(m->p->SysEventNotifier, EV_ADD, EVFILT_READ, &m->p->SysEventKQueue);
5631
5632 return(mStatus_NoError);
5633 }
5634
5635 #ifndef NO_SECURITYFRAMEWORK
5636 mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCallbackInfo *info, void *context)
5637 {
5638 LogInfo("*** Keychain Changed ***");
5639 mDNS *const m = (mDNS *const)context;
5640 SecKeychainRef skc;
5641 OSStatus err = SecKeychainCopyDefault(&skc);
5642 if (!err)
5643 {
5644 if (info->keychain == skc)
5645 {
5646 // 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
5647 mDNSBool relevant = (keychainEvent == kSecDeleteEvent);
5648 if (!relevant)
5649 {
5650 UInt32 tags[3] = { kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr };
5651 SecKeychainAttributeInfo attrInfo = { 3, tags, NULL }; // Count, array of tags, array of formats
5652 SecKeychainAttributeList *a = NULL;
5653 err = SecKeychainItemCopyAttributesAndData(info->item, &attrInfo, NULL, &a, NULL, NULL);
5654 if (!err)
5655 {
5656 relevant = ((a->attr[0].length == 4 && (!strncasecmp(a->attr[0].data, "ddns", 4) || !strncasecmp(a->attr[0].data, "sndd", 4))) ||
5657 (a->attr[1].length >= 4 && (!strncasecmp(a->attr[1].data, "dns:", 4))));
5658 SecKeychainItemFreeAttributesAndData(a, NULL);
5659 }
5660 }
5661 if (relevant)
5662 {
5663 LogInfo("*** Keychain Changed *** KeychainEvent=%d %s",
5664 keychainEvent,
5665 keychainEvent == kSecAddEvent ? "kSecAddEvent" :
5666 keychainEvent == kSecDeleteEvent ? "kSecDeleteEvent" :
5667 keychainEvent == kSecUpdateEvent ? "kSecUpdateEvent" : "<Unknown>");
5668 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
5669 KQueueLock(m);
5670 mDNS_Lock(m);
5671 SetDomainSecrets(m);
5672 mDNS_Unlock(m);
5673 KQueueUnlock(m, "KeychainChanged");
5674 }
5675 }
5676 CFRelease(skc);
5677 }
5678
5679 return 0;
5680 }
5681 #endif
5682
5683 #ifndef NO_IOPOWER
5684 mDNSlocal void PowerOn(mDNS *const m)
5685 {
5686 mDNSCoreMachineSleep(m, false); // Will set m->SleepState = SleepState_Awake;
5687 if (m->p->WakeAtUTC)
5688 {
5689 long utc = mDNSPlatformUTC();
5690 mDNSPowerRequest(-1,-1); // Need to explicitly clear any previous power requests -- they're not cleared automatically on wake
5691 if (m->p->WakeAtUTC - utc > 30) LogInfo("PowerChanged PowerOn %d seconds early, assuming not maintenance wake", m->p->WakeAtUTC - utc);
5692 else if (utc - m->p->WakeAtUTC > 30) LogInfo("PowerChanged PowerOn %d seconds late, assuming not maintenance wake", utc - m->p->WakeAtUTC);
5693 else
5694 {
5695 mDNSs32 i = 20;
5696 //int result = mDNSPowerRequest(0, i);
5697 //if (result == kIOReturnNotReady) do i += (i<20) ? 1 : ((i+3)/4); while (mDNSPowerRequest(0, i) == kIOReturnNotReady);
5698 LogMsg("PowerChanged: Waking for network maintenance operations %d seconds early; re-sleeping in %d seconds", m->p->WakeAtUTC - utc, i);
5699 m->p->RequestReSleep = mDNS_TimeNow(m) + i * mDNSPlatformOneSecond;
5700 }
5701 }
5702 }
5703
5704 mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
5705 {
5706 mDNS *const m = (mDNS *const)refcon;
5707 KQueueLock(m);
5708 (void)service; // Parameter not used
5709 debugf("PowerChanged %X %lX", messageType, messageArgument);
5710
5711 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
5712 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
5713
5714 switch(messageType)
5715 {
5716 case kIOMessageCanSystemPowerOff: LogInfo("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
5717 case kIOMessageSystemWillPowerOff: LogInfo("PowerChanged kIOMessageSystemWillPowerOff"); // E0000250
5718 mDNSCoreMachineSleep(m, true);
5719 if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
5720 break;
5721 case kIOMessageSystemWillNotPowerOff: LogInfo("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
5722 case kIOMessageCanSystemSleep: LogInfo("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
5723 case kIOMessageSystemWillSleep: LogInfo("PowerChanged kIOMessageSystemWillSleep"); // E0000280
5724 mDNSCoreMachineSleep(m, true);
5725 break;
5726 case kIOMessageSystemWillNotSleep: LogInfo("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
5727 case kIOMessageSystemHasPoweredOn: LogInfo("PowerChanged kIOMessageSystemHasPoweredOn"); // E0000300
5728 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
5729 if (m->SleepState)
5730 {
5731 LogMsg("PowerChanged kIOMessageSystemHasPoweredOn: ERROR m->SleepState %d", m->SleepState);
5732 PowerOn(m);
5733 }
5734 // Just to be safe, schedule a mDNSMacOSXNetworkChanged(), in case we never received
5735 // the System Configuration Framework "network changed" event that we expect
5736 // to receive some time shortly after the kIOMessageSystemWillPowerOn message
5737 mDNS_Lock(m);
5738 if (!m->p->NetworkChanged ||
5739 m->p->NetworkChanged - NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2) < 0)
5740 m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
5741 mDNS_Unlock(m);
5742
5743 break;
5744 case kIOMessageSystemWillRestart: LogInfo("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
5745 case kIOMessageSystemWillPowerOn: LogInfo("PowerChanged kIOMessageSystemWillPowerOn"); // E0000320
5746
5747 // On Leopard and earlier, on wake from sleep, instead of reporting link state down, Apple
5748 // Ethernet drivers report "hardware incapable of detecting link state", which the kernel
5749 // interprets as "should assume we have networking", which results in the first 4-5 seconds
5750 // of packets vanishing into a black hole. To work around this, on wake from sleep,
5751 // we block for five seconds to let Ethernet come up, and then resume normal operation.
5752 if (OSXVers < OSXVers_10_6_SnowLeopard)
5753 {
5754 sleep(5);
5755 LogMsg("Running on Mac OS X version 10.%d earlier than 10.6; "
5756 "PowerChanged did sleep(5) to wait for Ethernet hardware", OSXVers - OSXVers_Base);
5757 }
5758
5759 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
5760 if (m->SleepState != SleepState_Sleeping)
5761 {
5762 LogMsg("kIOMessageSystemWillPowerOn: ERROR m->SleepState %d", m->SleepState);
5763 m->SleepState = SleepState_Sleeping;
5764 mDNSMacOSXNetworkChanged(m);
5765 }
5766 PowerOn(m);
5767 break;
5768 default: LogInfo("PowerChanged unknown message %X", messageType); break;
5769 }
5770
5771 if (messageType == kIOMessageSystemWillSleep) m->p->SleepCookie = (long)messageArgument;
5772 else IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
5773
5774 KQueueUnlock(m, "PowerChanged Sleep/Wake");
5775 }
5776
5777 #ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements
5778 mDNSlocal void SnowLeopardPowerChanged(void *refcon, IOPMConnection connection, IOPMConnectionMessageToken token, IOPMSystemPowerStateCapabilities eventDescriptor)
5779 {
5780 mDNS *const m = (mDNS *const)refcon;
5781 KQueueLock(m);
5782 LogSPS("SnowLeopardPowerChanged %X %X %X%s%s%s%s%s",
5783 connection, token, eventDescriptor,
5784 eventDescriptor & kIOPMSystemPowerStateCapabilityCPU ? " CPU" : "",
5785 eventDescriptor & kIOPMSystemPowerStateCapabilityVideo ? " Video" : "",
5786 eventDescriptor & kIOPMSystemPowerStateCapabilityAudio ? " Audio" : "",
5787 eventDescriptor & kIOPMSystemPowerStateCapabilityNetwork ? " Network" : "",
5788 eventDescriptor & kIOPMSystemPowerStateCapabilityDisk ? " Disk" : "");
5789
5790 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
5791 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
5792
5793 if (eventDescriptor & kIOPMSystemPowerStateCapabilityCPU)
5794 {
5795 // CPU Waking. Note: Can get this message repeatedly, as other subsystems power up or down.
5796 if (m->SleepState == SleepState_Sleeping) PowerOn(m);
5797 IOPMConnectionAcknowledgeEvent(connection, token);
5798 }
5799 else
5800 {
5801 // CPU sleeping. Should not get this repeatedly -- once we're told that the CPU is halting
5802 // we should hear nothing more until we're told that the CPU has started executing again.
5803 if (m->SleepState) LogMsg("SnowLeopardPowerChanged: Sleep Error %X m->SleepState %d", eventDescriptor, m->SleepState);
5804 //sleep(5);
5805 //mDNSMacOSXNetworkChanged(m);
5806 mDNSCoreMachineSleep(m, true);
5807 //if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
5808 m->p->SleepCookie = token;
5809 }
5810
5811 KQueueUnlock(m, "SnowLeopardPowerChanged Sleep/Wake");
5812 }
5813 #endif
5814
5815 #endif /* NO_IOPOWER */
5816
5817 #if COMPILER_LIKES_PRAGMA_MARK
5818 #pragma mark -
5819 #pragma mark - Initialization & Teardown
5820 #endif
5821
5822 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
5823 CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
5824 CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
5825 CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
5826
5827 // Major version 6 is 10.2.x (Jaguar)
5828 // Major version 7 is 10.3.x (Panther)
5829 // Major version 8 is 10.4.x (Tiger)
5830 // Major version 9 is 10.5.x (Leopard)
5831 // Major version 10 is 10.6.x (SnowLeopard)
5832 mDNSexport int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
5833 {
5834 int major = 0, minor = 0;
5835 char letter = 0, prodname[256]="<Unknown>", prodvers[256]="<Unknown>", buildver[256]="<Unknown>";
5836 CFDictionaryRef vers = _CFCopySystemVersionDictionary();
5837 if (vers)
5838 {
5839 CFStringRef cfprodname = CFDictionaryGetValue(vers, _kCFSystemVersionProductNameKey);
5840 CFStringRef cfprodvers = CFDictionaryGetValue(vers, _kCFSystemVersionProductVersionKey);
5841 CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
5842 if (cfprodname) CFStringGetCString(cfprodname, prodname, sizeof(prodname), kCFStringEncodingUTF8);
5843 if (cfprodvers) CFStringGetCString(cfprodvers, prodvers, sizeof(prodvers), kCFStringEncodingUTF8);
5844 if (cfbuildver && CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8))
5845 sscanf(buildver, "%d%c%d", &major, &letter, &minor);
5846 CFRelease(vers);
5847 }
5848 if (!major) { major=8; LogMsg("Note: No Major Build Version number found; assuming 8"); }
5849 if (HINFO_SWstring) mDNS_snprintf(HINFO_SWstring, 256, "%s %s (%s), %s", prodname, prodvers, buildver, STRINGIFY(mDNSResponderVersion));
5850 return(major);
5851 }
5852
5853 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
5854 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
5855 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
5856 mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
5857 {
5858 int err = -1;
5859 int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
5860 if (s < 3)
5861 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s, errno, strerror(errno));
5862 else
5863 {
5864 struct sockaddr_in s5353;
5865 s5353.sin_family = AF_INET;
5866 s5353.sin_port = MulticastDNSPort.NotAnInteger;
5867 s5353.sin_addr.s_addr = 0;
5868 err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
5869 close(s);
5870 }
5871
5872 if (err) LogMsg("No unicast UDP responses");
5873 else debugf("Unicast UDP responses okay");
5874 return(err == 0);
5875 }
5876
5877 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
5878 // 1) query for b._dns-sd._udp.local on LocalOnly interface
5879 // (.local manually generated via explicit callback)
5880 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
5881 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
5882 // 4) result above should generate a callback from question in (1). result added to global list
5883 // 5) global list delivered to client via GetSearchDomainList()
5884 // 6) client calls to enumerate domains now go over LocalOnly interface
5885 // (!!!KRS may add outgoing interface in addition)
5886
5887 mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
5888 {
5889 mStatus err;
5890 m->p->CFRunLoop = CFRunLoopGetCurrent();
5891
5892 char HINFO_SWstring[256] = "";
5893 OSXVers = mDNSMacOSXSystemBuildNumber(HINFO_SWstring);
5894
5895 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
5896 // 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.
5897 int i;
5898 for (i=0; i<100; i++)
5899 {
5900 domainlabel testlabel;
5901 testlabel.c[0] = 0;
5902 GetUserSpecifiedLocalHostName(&testlabel);
5903 if (testlabel.c[0]) break;
5904 usleep(50000);
5905 }
5906
5907 m->hostlabel.c[0] = 0;
5908
5909 int get_model[2] = { CTL_HW, HW_MODEL };
5910 size_t len_model = sizeof(HINFO_HWstring_buffer);
5911 // Names that contain no commas are prototype model names, so we ignore those
5912 if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ','))
5913 HINFO_HWstring = HINFO_HWstring_buffer;
5914 HINFO_HWstring_prefixlen = strcspn(HINFO_HWstring, "0123456789");
5915
5916 if (OSXVers < OSXVers_10_3_Panther ) m->KnownBugs |= mDNS_KnownBug_PhantomInterfaces;
5917 if (OSXVers >= OSXVers_10_6_SnowLeopard ) m->KnownBugs |= mDNS_KnownBug_LossySyslog;
5918 if (mDNSPlatformInit_CanReceiveUnicast()) m->CanReceiveUnicastOn5353 = mDNStrue;
5919
5920 mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
5921 mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
5922 if (hlen + slen < 254)
5923 {
5924 m->HIHardware.c[0] = hlen;
5925 m->HISoftware.c[0] = slen;
5926 mDNSPlatformMemCopy(&m->HIHardware.c[1], HINFO_HWstring, hlen);
5927 mDNSPlatformMemCopy(&m->HISoftware.c[1], HINFO_SWstring, slen);
5928 }
5929
5930 m->p->permanentsockets.port = MulticastDNSPort;
5931 m->p->permanentsockets.m = m;
5932 m->p->permanentsockets.sktv4 = m->p->permanentsockets.sktv6 = -1;
5933 m->p->permanentsockets.kqsv4.KQcallback = m->p->permanentsockets.kqsv6.KQcallback = myKQSocketCallBack;
5934 m->p->permanentsockets.kqsv4.KQcontext = m->p->permanentsockets.kqsv6.KQcontext = &m->p->permanentsockets;
5935 m->p->permanentsockets.kqsv4.KQtask = m->p->permanentsockets.kqsv6.KQtask = "UDP packet reception";
5936
5937 err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET, mDNSNULL);
5938 #ifndef NO_IPV6
5939 err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET6, mDNSNULL);
5940 #endif
5941
5942 struct sockaddr_in s4;
5943 socklen_t n4 = sizeof(s4);
5944 if (getsockname(m->p->permanentsockets.sktv4, (struct sockaddr *)&s4, &n4) < 0) LogMsg("getsockname v4 error %d (%s)", errno, strerror(errno));
5945 else m->UnicastPort4.NotAnInteger = s4.sin_port;
5946 #ifndef NO_IPV6
5947 if (m->p->permanentsockets.sktv6 >= 0)
5948 {
5949 struct sockaddr_in6 s6;
5950 socklen_t n6 = sizeof(s6);
5951 if (getsockname(m->p->permanentsockets.sktv6, (struct sockaddr *)&s6, &n6) < 0) LogMsg("getsockname v6 error %d (%s)", errno, strerror(errno));
5952 else m->UnicastPort6.NotAnInteger = s6.sin6_port;
5953 }
5954 #endif
5955
5956 m->p->InterfaceList = mDNSNULL;
5957 m->p->userhostlabel.c[0] = 0;
5958 m->p->usernicelabel.c[0] = 0;
5959 m->p->NotifyUser = 0;
5960 m->p->KeyChainBugTimer = 0;
5961 m->p->WakeAtUTC = 0;
5962 m->p->RequestReSleep = 0;
5963
5964 #if APPLE_OSX_mDNSResponder
5965 uuid_generate(m->asl_uuid);
5966 #endif
5967
5968 m->AutoTunnelHostAddr.b[0] = 0; // Zero out AutoTunnelHostAddr so UpdateInterfaceList() know it has to set it up
5969
5970 NetworkChangedKey_IPv4 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
5971 NetworkChangedKey_IPv6 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
5972 NetworkChangedKey_Hostnames = SCDynamicStoreKeyCreateHostNames(NULL);
5973 NetworkChangedKey_Computername = SCDynamicStoreKeyCreateComputerName(NULL);
5974 NetworkChangedKey_DNS = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
5975 if (!NetworkChangedKey_IPv4 || !NetworkChangedKey_IPv6 || !NetworkChangedKey_Hostnames || !NetworkChangedKey_Computername || !NetworkChangedKey_DNS)
5976 { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr); }
5977
5978 err = WatchForNetworkChanges(m);
5979 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err); return(err); }
5980
5981 #if 0 // <rdar://problem/6751656>
5982 err = WatchForPMChanges(m);
5983 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForPMChanges failed %d", err); return(err); }
5984 #endif
5985
5986 err = WatchForSysEvents(m);
5987 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err); return(err); }
5988
5989 mDNSs32 utc = mDNSPlatformUTC();
5990 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
5991 UpdateInterfaceList(m, utc);
5992 SetupActiveInterfaces(m, utc);
5993
5994 // Explicitly ensure that our Keychain operations utilize the system domain.
5995 #ifndef NO_SECURITYFRAMEWORK
5996 SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
5997 #endif
5998
5999 mDNS_Lock(m);
6000 SetDomainSecrets(m);
6001 SetLocalDomains();
6002 mDNS_Unlock(m);
6003
6004 #ifndef NO_SECURITYFRAMEWORK
6005 err = SecKeychainAddCallback(KeychainChanged, kSecAddEventMask|kSecDeleteEventMask|kSecUpdateEventMask, m);
6006 if (err) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err); return(err); }
6007 #endif
6008
6009 #ifndef NO_IOPOWER
6010
6011 #ifndef kIOPMAcknowledgmentOptionSystemCapabilityRequirements
6012 LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support");
6013 #else
6014 IOPMConnection c;
6015 IOReturn iopmerr = IOPMConnectionCreate(CFSTR("mDNSResponder"), kIOPMSystemPowerStateCapabilityCPU, &c);
6016 if (iopmerr) LogMsg("IOPMConnectionCreate failed %d", iopmerr);
6017 else
6018 {
6019 iopmerr = IOPMConnectionSetNotification(c, m, SnowLeopardPowerChanged);
6020 if (iopmerr) LogMsg("IOPMConnectionSetNotification failed %d", iopmerr);
6021 else
6022 {
6023 iopmerr = IOPMConnectionScheduleWithRunLoop(c, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
6024 if (iopmerr) LogMsg("IOPMConnectionScheduleWithRunLoop failed %d", iopmerr);
6025 }
6026 }
6027 m->p->IOPMConnection = iopmerr ? mDNSNULL : c;
6028 if (iopmerr) // If IOPMConnectionCreate unavailable or failed, proceed with old-style power notification code below
6029 #endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements
6030 {
6031 m->p->PowerConnection = IORegisterForSystemPower(m, &m->p->PowerPortRef, PowerChanged, &m->p->PowerNotifier);
6032 if (!m->p->PowerConnection) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
6033 else CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
6034 }
6035 #endif /* NO_IOPOWER */
6036
6037 #if APPLE_OSX_mDNSResponder
6038 // Note: We use SPMetricPortability > 35 to indicate a laptop of some kind
6039 // SPMetricPortability <= 35 means nominally a non-portable machine (i.e. Mac mini or better)
6040 // An Apple TV does not actually weigh 3kg, but we assign it a 'nominal' mass of 3kg to indicate that it's treated as being relatively less portable than a laptop
6041 if (!strncasecmp(HINFO_HWstring, "Xserve", 6)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
6042 else if (!strncasecmp(HINFO_HWstring, "RackMac", 7)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
6043 else if (!strncasecmp(HINFO_HWstring, "MacPro", 6)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
6044 else if (!strncasecmp(HINFO_HWstring, "PowerMac", 8)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 82 /* 160W */; SPMetricTotalPower = 83 /* 200W */; }
6045 else if (!strncasecmp(HINFO_HWstring, "iMac", 4)) { SPMetricPortability = 30 /* 10kg */; SPMetricMarginalPower = 77 /* 50W */; SPMetricTotalPower = 78 /* 60W */; }
6046 else if (!strncasecmp(HINFO_HWstring, "Macmini", 7)) { SPMetricPortability = 33 /* 5kg */; SPMetricMarginalPower = 73 /* 20W */; SPMetricTotalPower = 74 /* 25W */; }
6047 else if (!strncasecmp(HINFO_HWstring, "AppleTV", 7)) { SPMetricPortability = 35 /* 3kg */; SPMetricMarginalPower = 10 /* 0W */; SPMetricTotalPower = 73 /* 20W */; }
6048 else if (!strncasecmp(HINFO_HWstring, "MacBook", 7)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; }
6049 else if (!strncasecmp(HINFO_HWstring, "PowerBook",9)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; }
6050 LogSPS("HW_MODEL: %.*s (%s) Portability %d Marginal Power %d Total Power %d",
6051 HINFO_HWstring_prefixlen, HINFO_HWstring, HINFO_HWstring, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower);
6052
6053 err = WatchForInternetSharingChanges(m);
6054 if (err) { LogMsg("WatchForInternetSharingChanges failed %d", err); return(err); }
6055 #endif // APPLE_OSX_mDNSResponder
6056
6057 return(mStatus_NoError);
6058 }
6059
6060 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
6061 {
6062 #if MDNS_NO_DNSINFO
6063 LogMsg("Note: Compiled without Apple-specific Split-DNS support");
6064 #endif
6065
6066 // Adding interfaces will use this flag, so set it now.
6067 m->DivertMulticastAdvertisements = !m->AdvertiseLocalAddresses;
6068
6069 #if APPLE_OSX_mDNSResponder
6070 m->SPSBrowseCallback = UpdateSPSStatus;
6071 #endif
6072
6073 mStatus result = mDNSPlatformInit_setup(m);
6074
6075 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
6076 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
6077 if (result == mStatus_NoError) mDNSCoreInitComplete(m, mStatus_NoError);
6078 return(result);
6079 }
6080
6081 mDNSexport void mDNSPlatformClose(mDNS *const m)
6082 {
6083 if (m->p->PowerConnection)
6084 {
6085 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
6086 #ifndef NO_IOPOWER
6087 // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
6088 // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
6089 IODeregisterForSystemPower(&m->p->PowerNotifier);
6090 IOServiceClose ( m->p->PowerConnection);
6091 IONotificationPortDestroy ( m->p->PowerPortRef);
6092 #endif /* NO_IOPOWER */
6093 m->p->PowerConnection = 0;
6094 }
6095
6096 if (m->p->Store)
6097 {
6098 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
6099 CFRunLoopSourceInvalidate(m->p->StoreRLS);
6100 CFRelease(m->p->StoreRLS);
6101 CFRelease(m->p->Store);
6102 m->p->Store = NULL;
6103 m->p->StoreRLS = NULL;
6104 }
6105
6106 if (m->p->PMRLS)
6107 {
6108 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->PMRLS, kCFRunLoopDefaultMode);
6109 CFRunLoopSourceInvalidate(m->p->PMRLS);
6110 CFRelease(m->p->PMRLS);
6111 m->p->PMRLS = NULL;
6112 }
6113
6114 if (m->p->SysEventNotifier >= 0) { close(m->p->SysEventNotifier); m->p->SysEventNotifier = -1; }
6115
6116 mDNSs32 utc = mDNSPlatformUTC();
6117 MarkAllInterfacesInactive(m, utc);
6118 ClearInactiveInterfaces(m, utc);
6119 CloseSocketSet(&m->p->permanentsockets);
6120
6121 #if APPLE_OSX_mDNSResponder
6122 // clean up tunnels
6123 while (m->TunnelClients)
6124 {
6125 ClientTunnel *cur = m->TunnelClients;
6126 LogInfo("mDNSPlatformClose: removing client tunnel %p %##s from list", cur, cur->dstname.c);
6127 if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
6128 AutoTunnelSetKeys(cur, mDNSfalse);
6129 m->TunnelClients = cur->next;
6130 freeL("ClientTunnel", cur);
6131 }
6132
6133 if (AnonymousRacoonConfig)
6134 {
6135 AnonymousRacoonConfig = mDNSNULL;
6136 LogInfo("mDNSPlatformClose: Deconfiguring autotunnel");
6137 (void)mDNSConfigureServer(kmDNSDown, mDNSNULL);
6138 }
6139
6140 if (m->AutoTunnelHostAddrActive && m->AutoTunnelHostAddr.b[0])
6141 {
6142 m->AutoTunnelHostAddrActive = mDNSfalse;
6143 LogInfo("mDNSPlatformClose: Removing AutoTunnel address %.16a", &m->AutoTunnelHostAddr);
6144 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown, m->AutoTunnelHostAddr.b);
6145 }
6146 #endif // APPLE_OSX_mDNSResponder
6147 }
6148
6149 #if COMPILER_LIKES_PRAGMA_MARK
6150 #pragma mark -
6151 #pragma mark - General Platform Support Layer functions
6152 #endif
6153
6154 mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
6155 {
6156 return(arc4random());
6157 }
6158
6159 mDNSexport mDNSs32 mDNSPlatformOneSecond = 1000;
6160 mDNSexport mDNSu32 mDNSPlatformClockDivisor = 0;
6161
6162 mDNSexport mStatus mDNSPlatformTimeInit(void)
6163 {
6164 // Notes: Typical values for mach_timebase_info:
6165 // tbi.numer = 1000 million
6166 // tbi.denom = 33 million
6167 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
6168 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
6169 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
6170 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
6171 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
6172 //
6173 // Arithmetic notes:
6174 // tbi.denom is at least 1, and not more than 2^32-1.
6175 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
6176 // tbi.denom is at least 1, and not more than 2^32-1.
6177 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
6178 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
6179 // which is unlikely on any current or future Macintosh.
6180 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
6181 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
6182 struct mach_timebase_info tbi;
6183 kern_return_t result = mach_timebase_info(&tbi);
6184 if (result == KERN_SUCCESS) mDNSPlatformClockDivisor = ((uint64_t)tbi.denom * 1000000) / tbi.numer;
6185 return(result);
6186 }
6187
6188 mDNSexport mDNSs32 mDNSPlatformRawTime(void)
6189 {
6190 if (mDNSPlatformClockDivisor == 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
6191
6192 static uint64_t last_mach_absolute_time = 0;
6193 //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
6194 uint64_t this_mach_absolute_time = mach_absolute_time();
6195 if ((int64_t)this_mach_absolute_time - (int64_t)last_mach_absolute_time < 0)
6196 {
6197 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time);
6198 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time);
6199 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
6200 last_mach_absolute_time = this_mach_absolute_time;
6201 // Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xyyy) or later.
6202 // (This bug happens all the time on 10.3, and we know that's not going to be fixed.)
6203 if (OSXVers >= OSXVers_10_4_Tiger)
6204 NotifyOfElusiveBug("mach_absolute_time went backwards!",
6205 "This error occurs from time to time, often on newly released hardware, "
6206 "and usually the exact cause is different in each instance.\r\r"
6207 "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
6208 "and assign it to Radar Component “Kernel” Version “X”.");
6209 }
6210 last_mach_absolute_time = this_mach_absolute_time;
6211
6212 return((mDNSs32)(this_mach_absolute_time / mDNSPlatformClockDivisor));
6213 }
6214
6215 mDNSexport mDNSs32 mDNSPlatformUTC(void)
6216 {
6217 return time(NULL);
6218 }
6219
6220 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
6221 mDNSexport void mDNSPlatformLock (const mDNS *const m) { (void)m; }
6222 mDNSexport void mDNSPlatformUnlock (const mDNS *const m) { (void)m; }
6223 mDNSexport void mDNSPlatformStrCopy( void *dst, const void *src) { strcpy((char *)dst, (char *)src); }
6224 mDNSexport mDNSu32 mDNSPlatformStrLen ( const void *src) { return(strlen((char*)src)); }
6225 mDNSexport void mDNSPlatformMemCopy( void *dst, const void *src, mDNSu32 len) { memcpy(dst, src, len); }
6226 mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len) == 0); }
6227 mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len) { memset(dst, 0, len); }
6228 #if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
6229 mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
6230 #endif
6231 mDNSexport void mDNSPlatformMemFree (void *mem) { freeL("mDNSPlatformMemFree", mem); }