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