1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2007 Apple Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 Change History (most recent first):
20 Revision 1.66 2009/04/20 20:40:14 cheshire
21 <rdar://problem/6786150> uDNS: Running location cycling caused configd and mDNSResponder to deadlock
22 Changed mDNSPreferencesSetName (and similar) routines from MIG "routine" to MIG "simpleroutine"
23 so we don't deadlock waiting for a result that we're just going to ignore anyway
25 Revision 1.65 2009/03/20 22:12:28 mcguire
26 <rdar://problem/6703952> Support CFUserNotificationDisplayNotice in mDNSResponderHelper
27 Make the call to the helper a simpleroutine: don't wait for an unused return value
29 Revision 1.64 2009/03/20 21:52:39 cheshire
30 <rdar://problem/6703952> Support CFUserNotificationDisplayNotice in mDNSResponderHelper
31 Need to CFRelease strings in do_mDNSNotify
33 Revision 1.63 2009/03/20 21:21:15 cheshire
34 <rdar://problem/6703952> Support CFUserNotificationDisplayNotice in mDNSResponderHelper
35 Need to set error code correctly in do_mDNSNotify
37 Revision 1.62 2009/03/20 20:52:22 cheshire
38 <rdar://problem/6703952> Support CFUserNotificationDisplayNotice in mDNSResponderHelper
40 Revision 1.61 2009/03/14 01:42:56 mcguire
41 <rdar://problem/5457116> BTMM: Fix issues with multiple .Mac accounts on the same machine
43 Revision 1.60 2009/02/18 02:09:10 cheshire
44 <rdar://problem/6514947> Sleep Proxy: PF_ROUTE command to set ARP entry returns errno 17 (EEXIST)
45 Also need to set rtmsg.hdr.rtm_index
47 Revision 1.59 2009/02/17 23:33:45 cheshire
48 <rdar://problem/6514947> Sleep Proxy: PF_ROUTE command to set ARP entry returns errno 17 (EEXIST)
50 Revision 1.58 2009/02/04 22:23:04 cheshire
51 Simplified do_mDNSPowerRequest --
52 code was checking for CFAbsoluteTimeGetCurrent() returning NULL, which makes no sense
54 Revision 1.57 2009/01/22 02:14:27 cheshire
55 <rdar://problem/6515626> Sleep Proxy: Set correct target MAC address, instead of all zeroes
57 Revision 1.56 2009/01/20 21:03:22 cheshire
58 Improved debugging messages
60 Revision 1.55 2009/01/20 02:37:26 mcguire
61 revert previous erroneous commit
63 Revision 1.54 2009/01/20 02:35:15 mcguire
64 mDNSMacOSX/mDNSMacOSX.c
66 Revision 1.53 2009/01/14 01:38:42 mcguire
67 <rdar://problem/6492710> Write out DynamicStore per-interface SleepProxyServer info
69 Revision 1.52 2009/01/13 05:31:34 mkrochma
70 <rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
72 Revision 1.51 2009/01/12 22:26:12 mkrochma
73 Change DynamicStore location from BonjourSleepProxy/DiscoveredServers to SleepProxyServers
75 Revision 1.50 2008/12/15 18:40:41 mcguire
76 <rdar://problem/6444440> Socket leak in helper's doTunnelPolicy
78 Revision 1.49 2008/12/12 00:37:42 mcguire
79 <rdar://problem/6417648> BTMM outbound fails if /var/run/racoon doesn't exist
81 Revision 1.48 2008/12/05 02:35:24 mcguire
82 <rdar://problem/6107390> Write to the DynamicStore when a Sleep Proxy server is available on the network
84 Revision 1.47 2008/11/21 02:28:55 mcguire
85 <rdar://problem/6354979> send racoon a SIGUSR1 instead of SIGHUP
87 Revision 1.46 2008/11/11 02:09:42 cheshire
88 Removed some unnecessary log messages
90 Revision 1.45 2008/11/06 23:35:38 cheshire
91 Refinements to the do_mDNSSetARP() routine
93 Revision 1.44 2008/11/05 18:41:14 cheshire
94 Log errors from read() call in do_mDNSSetARP()
96 Revision 1.43 2008/11/04 23:54:09 cheshire
97 Added routine mDNSSetARP(), used to replace an SPS client's entry in our ARP cache with
98 a dummy one, so that IP traffic to the SPS client initiated by the SPS machine can be
99 captured by our BPF filters, and used as a trigger to wake the sleeping machine.
101 Revision 1.42 2008/10/31 23:35:31 cheshire
102 When scheduling new power event make sure all old events are deleted;
103 mDNSPowerRequest(-1,-1); just clears old events without scheduling a new one
105 Revision 1.41 2008/10/31 18:41:55 cheshire
106 Do update_idle_timer() before returning from do_mDNSRequestBPF()
108 Revision 1.40 2008/10/30 01:05:27 cheshire
109 mDNSPowerRequest(0, 0) means "sleep now"
111 Revision 1.39 2008/10/29 21:26:50 cheshire
112 Only log IOPMSchedulePowerEvent calls when there's an error
114 Revision 1.38 2008/10/24 01:42:36 cheshire
115 Added mDNSPowerRequest helper routine to request a scheduled wakeup some time in the future
117 Revision 1.37 2008/10/24 00:17:22 mcguire
118 Add compatibility for older racoon behavior
120 Revision 1.36 2008/10/22 17:22:31 cheshire
121 Remove SO_NOSIGPIPE bug workaround
123 Revision 1.35 2008/10/20 22:01:28 cheshire
124 Made new Mach simpleroutine "mDNSRequestBPF"
126 Revision 1.34 2008/10/02 23:50:07 mcguire
127 <rdar://problem/6136442> shutdown time issues
128 improve log messages when SCDynamicStoreCreate() fails
130 Revision 1.33 2008/09/30 01:00:45 cheshire
131 Added workaround to avoid SO_NOSIGPIPE bug
133 Revision 1.32 2008/09/27 01:11:46 cheshire
134 Added handler to respond to kmDNSSendBPF message
136 Revision 1.31 2008/09/08 17:42:40 mcguire
137 <rdar://problem/5536811> change location of racoon files
138 cleanup, handle stat failure cases, reduce log messages
140 Revision 1.30 2008/09/05 21:51:26 mcguire
141 <rdar://problem/6077707> BTMM: Need to launch racoon by opening VPN control socket
143 Revision 1.29 2008/09/05 18:26:53 mcguire
144 <rdar://problem/6077707> BTMM: Need to launch racoon by opening VPN control socket
146 Revision 1.28 2008/09/04 22:49:28 mcguire
147 <rdar://problem/5536811> change location of racoon files
149 Revision 1.27 2008/08/28 23:11:12 mcguire
150 <rdar://problem/5858535> handle SIGTERM in mDNSResponderHelper
152 Revision 1.26 2008/08/19 00:35:02 mcguire
153 <rdar://problem/5858535> handle SIGTERM in mDNSResponderHelper
155 Revision 1.25 2008/08/13 23:04:06 mcguire
156 <rdar://problem/5858535> handle SIGTERM in mDNSResponderHelper
157 Preparation: rename message function, as it will no longer be called only on idle exit
159 Revision 1.24 2008/01/30 19:01:51 mcguire
160 <rdar://problem/5703989> Crash in mDNSResponderHelper
162 Revision 1.23 2007/11/30 23:21:51 cheshire
163 Rename variables to eliminate "declaration of 'sin_loc' shadows a previous local" warning
165 Revision 1.22 2007/11/27 00:08:49 jgraessley
166 <rdar://problem/5613538> Interface specific resolvers not setup correctly
168 Revision 1.21 2007/11/07 00:22:30 jgraessley
169 Bug #: <rdar://problem/5573573> mDNSResponder doesn't build without IPSec
170 Reviewed by: Stuart Cheshire
172 Revision 1.20 2007/09/12 18:07:44 cheshire
173 Fix compile errors ("passing argument from incompatible pointer type")
175 Revision 1.19 2007/09/12 00:42:47 mcguire
176 <rdar://problem/5468236> BTMM: Need to clean up security associations
178 Revision 1.18 2007/09/12 00:40:16 mcguire
179 <rdar://problem/5469660> 9A547: Computer Name had incorrectly encoded unicode
181 Revision 1.17 2007/09/09 02:21:17 mcguire
182 <rdar://problem/5469345> Leopard Server9A547(Insatll):mDNSResponderHelper crashing
184 Revision 1.16 2007/09/07 22:44:03 mcguire
185 <rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
187 Revision 1.15 2007/09/07 22:24:36 vazquez
188 <rdar://problem/5466301> Need to stop spewing mDNSResponderHelper logs
190 Revision 1.14 2007/09/06 20:39:05 cheshire
191 Added comment explaining why we allow both "ddns" and "sndd" as valid item types
192 The Keychain APIs on Intel appear to store the four-character item type backwards (at least some of the time)
194 Revision 1.13 2007/09/04 22:32:58 mcguire
195 <rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
197 Revision 1.12 2007/08/29 21:42:12 mcguire
198 <rdar://problem/5431192> BTMM: Duplicate Private DNS names are being added to DynamicStore
200 Revision 1.11 2007/08/28 00:33:04 jgraessley
201 <rdar://problem/5423932> Selective compilation options
203 Revision 1.10 2007/08/27 22:16:38 mcguire
204 <rdar://problem/5437362> BTMM: MTU should be set to 1280
206 Revision 1.9 2007/08/27 22:13:59 mcguire
207 <rdar://problem/5437373> BTMM: IPSec security associations should have a shorter timeout
209 Revision 1.8 2007/08/23 21:49:51 cheshire
210 Made code layout style consistent with existing project style; added $Log header
212 Revision 1.7 2007/08/23 00:29:05 mcguire
213 <rdar://problem/5425800> BTMM: IPSec policy not installed in some situations - connections fail
215 Revision 1.6 2007/08/18 01:02:03 mcguire
216 <rdar://problem/5415593> No Bonjour services are getting registered at boot
218 Revision 1.5 2007/08/18 00:59:55 mcguire
219 <rdar://problem/5392568> Blocked: BTMM: Start racoon with '-e' parameter
221 Revision 1.4 2007/08/16 01:00:06 mcguire
222 <rdar://problem/5392548> BTMM: Install generate IPsec policies to block non-BTMM traffic
224 Revision 1.3 2007/08/15 23:20:28 mcguire
225 <rdar://problem/5408105> BTMM: racoon files can get corrupted if autotunnel is listening on port > 32767
227 Revision 1.2 2007/08/10 22:30:39 mcguire
228 <rdar://problem/5400259> BTMM: racoon config files are not always the correct mode
230 Revision 1.1 2007/08/08 22:34:58 mcguire
231 <rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
234 #include <sys/cdefs.h>
235 #include <arpa/inet.h>
236 #include <bsm/libbsm.h>
238 #include <net/route.h>
239 #include <net/if_dl.h>
240 #include <net/if_types.h>
241 #include <netinet/in.h>
242 #include <netinet/if_ether.h>
243 #include <netinet6/in6_var.h>
244 #include <netinet6/nd6.h>
245 #include <netinet6/ipsec.h>
246 #include <sys/ioctl.h>
247 #include <sys/socket.h>
257 #include <Security/Security.h>
258 #include <SystemConfiguration/SystemConfiguration.h>
259 #include <SystemConfiguration/SCDynamicStore.h>
260 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
261 #include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
262 #include <TargetConditionals.h>
263 #include <IOKit/pwr_mgt/IOPMLib.h>
265 #include "mDNSEmbeddedAPI.h"
267 #include "dnssd_ipc.h"
268 #include "libpfkey.h"
270 #include "helpermsgServer.h"
271 #include "helper-server.h"
272 #include "ipsec_options.h"
275 #define RTF_IFSCOPE 0x1000000
278 #if TARGET_OS_EMBEDDED
279 #define NO_CFUSERNOTIFICATION 1
280 #define NO_SECURITYFRAMEWORK 1
283 // Embed the client stub code here, so we can access private functions like ConnectToServer, create_hdr, deliver_request
284 #include "../mDNSShared/dnssd_ipc.c"
285 #include "../mDNSShared/dnssd_clientstub.c"
287 typedef struct sadb_x_policy
*ipsec_policy_t
;
289 uid_t mDNSResponderUID
;
290 gid_t mDNSResponderGID
;
291 static const char kTunnelAddressInterface
[] = "lo0";
294 debug_(const char *func
, const char *fmt
, ...)
300 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
302 helplog(ASL_LEVEL_DEBUG
, "%s: %s", func
, buf
);
306 authorized(audit_token_t
*token
)
309 pid_t pid
= (pid_t
)-1;
310 uid_t euid
= (uid_t
)-1;
312 audit_token_to_au32(*token
, NULL
, &euid
, NULL
, NULL
, NULL
, &pid
, NULL
,
314 ok
= (euid
== mDNSResponderUID
|| euid
== 0);
316 helplog(ASL_LEVEL_NOTICE
,
317 "Unauthorized access by euid=%lu pid=%lu",
318 (unsigned long)euid
, (unsigned long)pid
);
323 do_mDNSExit(__unused mach_port_t port
, audit_token_t token
)
326 if (!authorized(&token
))
328 helplog(ASL_LEVEL_INFO
, "exit");
336 kern_return_t
do_mDNSRequestBPF(__unused mach_port_t port
, audit_token_t token
)
338 if (!authorized(&token
)) return KERN_SUCCESS
;
340 DNSServiceErrorType err
= ConnectToServer(&ref
, 0, send_bpf
, NULL
, NULL
, NULL
);
341 if (err
) { helplog(ASL_LEVEL_ERR
, "do_mDNSRequestBPF: ConnectToServer %d", err
); return err
; }
344 size_t len
= sizeof(DNSServiceFlags
);
345 ipc_msg_hdr
*hdr
= create_hdr(send_bpf
, &len
, &ptr
, 0, ref
);
346 if (!hdr
) { DNSServiceRefDeallocate(ref
); return kDNSServiceErr_NoMemory
; }
348 deliver_request(hdr
, ref
); // Will free hdr for us
349 DNSServiceRefDeallocate(ref
);
354 kern_return_t
do_mDNSPowerRequest(__unused mach_port_t port
, int key
, int interval
, int *err
, audit_token_t token
)
357 if (!authorized(&token
)) { *err
= kmDNSHelperNotAuthorized
; goto fin
; }
359 CFArrayRef events
= IOPMCopyScheduledPowerEvents();
363 CFIndex count
= CFArrayGetCount(events
);
364 for (i
=0; i
<count
; i
++)
366 CFDictionaryRef dict
= CFArrayGetValueAtIndex(events
, i
);
367 CFStringRef id
= CFDictionaryGetValue(dict
, CFSTR(kIOPMPowerEventAppNameKey
));
368 if (CFEqual(id
, CFSTR("mDNSResponderHelper")))
370 CFDateRef EventTime
= CFDictionaryGetValue(dict
, CFSTR(kIOPMPowerEventTimeKey
));
371 CFStringRef EventType
= CFDictionaryGetValue(dict
, CFSTR(kIOPMPowerEventTypeKey
));
372 IOReturn result
= IOPMCancelScheduledPowerEvent(EventTime
, id
, EventType
);
373 //helplog(ASL_LEVEL_ERR, "Deleting old event %s");
374 if (result
) helplog(ASL_LEVEL_ERR
, "IOPMCancelScheduledPowerEvent %d failed %d", i
, result
);
380 if (key
< 0) // mDNSPowerRequest(-1,-1) means "clear any stale schedules" (see above)
382 else if (key
== 0) // mDNSPowerRequest(0, 0) means "sleep now"
384 IOReturn r
= IOPMSleepSystem(IOPMFindPowerManagement(MACH_PORT_NULL
));
385 if (r
) { usleep(100000); helplog(ASL_LEVEL_ERR
, "IOPMSleepSystem %d", r
); }
390 CFDateRef w
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent() + interval
);
393 IOReturn r
= IOPMSchedulePowerEvent(w
, CFSTR("mDNSResponderHelper"), key
? CFSTR(kIOPMAutoWake
) : CFSTR(kIOPMAutoSleep
));
394 if (r
) { usleep(100000); helplog(ASL_LEVEL_ERR
, "IOPMSchedulePowerEvent(%d) %d %x", interval
, r
, r
); }
404 kern_return_t
do_mDNSSetARP(__unused mach_port_t port
, int ifindex
, v4addr_t v4
, ethaddr_t eth
, int *err
, audit_token_t token
)
406 //helplog(ASL_LEVEL_ERR, "do_mDNSSetARP %d %d.%d.%d.%d %02X:%02X:%02X:%02X:%02X:%02X",
407 // ifindex, v4[0], v4[1], v4[2], v4[3], eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
410 if (!authorized(&token
)) { *err
= kmDNSHelperNotAuthorized
; goto fin
; }
412 static int s
= -1, seq
= 0;
415 s
= socket(PF_ROUTE
, SOCK_RAW
, 0);
416 if (s
< 0) helplog(ASL_LEVEL_ERR
, "do_mDNSSetARP: socket(PF_ROUTE, SOCK_RAW, 0) failed %d (%s)", errno
, strerror(errno
));
422 gettimeofday(&tv
, 0);
424 struct { struct rt_msghdr hdr
; struct sockaddr_inarp dst
; struct sockaddr_dl sdl
; } rtmsg
;
425 memset(&rtmsg
, 0, sizeof(rtmsg
));
427 rtmsg
.hdr
.rtm_msglen
= sizeof(rtmsg
);
428 rtmsg
.hdr
.rtm_version
= RTM_VERSION
;
429 rtmsg
.hdr
.rtm_type
= RTM_ADD
;
430 rtmsg
.hdr
.rtm_index
= ifindex
;
431 rtmsg
.hdr
.rtm_flags
= RTF_HOST
| RTF_STATIC
| RTF_IFSCOPE
;
432 rtmsg
.hdr
.rtm_addrs
= RTA_DST
| RTA_GATEWAY
;
433 rtmsg
.hdr
.rtm_pid
= 0;
434 rtmsg
.hdr
.rtm_seq
= seq
++;
435 rtmsg
.hdr
.rtm_errno
= 0;
436 rtmsg
.hdr
.rtm_use
= 0;
437 rtmsg
.hdr
.rtm_inits
= RTV_EXPIRE
;
438 rtmsg
.hdr
.rtm_rmx
.rmx_expire
= tv
.tv_sec
+ 30;
440 rtmsg
.dst
.sin_len
= sizeof(struct sockaddr_inarp
);
441 rtmsg
.dst
.sin_family
= AF_INET
;
442 rtmsg
.dst
.sin_port
= 0;
443 rtmsg
.dst
.sin_addr
.s_addr
= *(in_addr_t
*)v4
;
444 rtmsg
.dst
.sin_srcaddr
.s_addr
= 0;
445 rtmsg
.dst
.sin_tos
= 0;
446 rtmsg
.dst
.sin_other
= 0;
448 rtmsg
.sdl
.sdl_len
= sizeof(struct sockaddr_dl
);
449 rtmsg
.sdl
.sdl_family
= AF_LINK
;
450 rtmsg
.sdl
.sdl_index
= ifindex
;
451 rtmsg
.sdl
.sdl_type
= IFT_ETHER
;
452 rtmsg
.sdl
.sdl_nlen
= 0;
453 rtmsg
.sdl
.sdl_alen
= ETHER_ADDR_LEN
;
454 rtmsg
.sdl
.sdl_slen
= 0;
456 // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h)
457 memcpy(rtmsg
.sdl
.sdl_data
, eth
, sizeof(ethaddr_t
));
459 int len
= write(s
, (char *)&rtmsg
, sizeof(rtmsg
));
461 helplog(ASL_LEVEL_ERR
, "do_mDNSSetARP: write(%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s)",
462 sizeof(rtmsg
), ifindex
, v4
[0], v4
[1], v4
[2], v4
[3], rtmsg
.hdr
.rtm_seq
, len
, errno
, strerror(errno
));
463 len
= read(s
, (char *)&rtmsg
, sizeof(rtmsg
));
465 helplog(ASL_LEVEL_ERR
, "do_mDNSSetARP: read (%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s)",
466 sizeof(rtmsg
), ifindex
, v4
[0], v4
[1], v4
[2], v4
[3], rtmsg
.hdr
.rtm_seq
, len
, errno
, strerror(errno
));
476 kern_return_t
do_mDNSNotify(__unused mach_port_t port
, const char *title
, const char *msg
, audit_token_t token
)
478 if (!authorized(&token
)) return KERN_SUCCESS
;
480 #ifndef NO_CFUSERNOTIFICATION
481 static const char footer
[] = "(Note: This message only appears on machines with 17.x.x.x IP addresses — i.e. at Apple — not on customer machines.)";
482 CFStringRef alertHeader
= CFStringCreateWithCString(NULL
, title
, kCFStringEncodingUTF8
);
483 CFStringRef alertBody
= CFStringCreateWithCString(NULL
, msg
, kCFStringEncodingUTF8
);
484 CFStringRef alertFooter
= CFStringCreateWithCString(NULL
, footer
, kCFStringEncodingUTF8
);
485 CFStringRef alertMessage
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@\r\r%@"), alertBody
, alertFooter
);
486 CFRelease(alertBody
);
487 CFRelease(alertFooter
);
488 int err
= CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel
, NULL
, NULL
, NULL
, alertHeader
, alertMessage
, NULL
);
489 if (err
) helplog(ASL_LEVEL_ERR
, "CFUserNotificationDisplayNotice returned %d", err
);
490 CFRelease(alertHeader
);
491 CFRelease(alertMessage
);
492 #endif /* NO_CFUSERNOTIFICATION */
499 do_mDNSDynamicStoreSetConfig(__unused mach_port_t port
, int key
,
500 const char* subkey
, vm_offset_t value
, mach_msg_type_number_t valueCnt
,
503 CFStringRef sckey
= NULL
;
504 Boolean release_sckey
= FALSE
;
505 CFDataRef bytes
= NULL
;
506 CFPropertyListRef plist
= NULL
;
507 SCDynamicStoreRef store
= NULL
;
510 if (!authorized(&token
)) goto fin
;
512 switch ((enum mDNSDynamicStoreSetConfigKey
)key
)
514 case kmDNSMulticastConfig
:
515 sckey
= CFSTR("State:/Network/" kDNSServiceCompMulticastDNS
);
517 case kmDNSDynamicConfig
:
518 sckey
= CFSTR("State:/Network/DynamicDNS");
520 case kmDNSPrivateConfig
:
521 sckey
= CFSTR("State:/Network/" kDNSServiceCompPrivateDNS
);
523 case kmDNSBackToMyMacConfig
:
524 sckey
= CFSTR("State:/Network/BackToMyMac");
526 case kmDNSSleepProxyServersState
:
528 CFMutableStringRef tmp
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
529 CFStringAppend(tmp
, CFSTR("State:/Network/Interface/"));
530 CFStringAppendCString(tmp
, subkey
, kCFStringEncodingUTF8
);
531 CFStringAppend(tmp
, CFSTR("/SleepProxyServers"));
532 sckey
= CFStringCreateCopy(kCFAllocatorDefault
, tmp
);
533 release_sckey
= TRUE
;
538 debug("unrecognized key %d", key
);
541 if (NULL
== (bytes
= CFDataCreateWithBytesNoCopy(NULL
, (void *)value
,
542 valueCnt
, kCFAllocatorNull
)))
544 debug("CFDataCreateWithBytesNoCopy of value failed");
547 if (NULL
== (plist
= CFPropertyListCreateFromXMLData(NULL
, bytes
,
548 kCFPropertyListImmutable
, NULL
)))
550 debug("CFPropertyListCreateFromXMLData of bytes failed");
555 if (NULL
== (store
= SCDynamicStoreCreate(NULL
,
556 CFSTR(kmDNSHelperServiceName
), NULL
, NULL
)))
558 debug("SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
561 SCDynamicStoreSetValue(store
, sckey
, plist
);
571 if (release_sckey
&& sckey
)
573 vm_deallocate(mach_task_self(), value
, valueCnt
);
578 char usercompname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last computer name the user saw
579 char userhostname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last local host name the user saw
580 char lastcompname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last computer name saved to preferences
581 char lasthostname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last local host name saved to preferences
583 #ifndef NO_CFUSERNOTIFICATION
584 static CFStringRef CFS_OQ
= NULL
;
585 static CFStringRef CFS_CQ
= NULL
;
586 static CFStringRef CFS_Format
= NULL
;
587 static CFStringRef CFS_ComputerName
= NULL
;
588 static CFStringRef CFS_ComputerNameMsg
= NULL
;
589 static CFStringRef CFS_LocalHostName
= NULL
;
590 static CFStringRef CFS_LocalHostNameMsg
= NULL
;
591 static CFStringRef CFS_Problem
= NULL
;
593 static CFUserNotificationRef gNotification
= NULL
;
594 static CFRunLoopSourceRef gNotificationRLS
= NULL
;
596 static void NotificationCallBackDismissed(CFUserNotificationRef userNotification
, CFOptionFlags responseFlags
)
599 (void)responseFlags
; // Unused
600 if (userNotification
!= gNotification
) helplog(ASL_LEVEL_ERR
, "NotificationCallBackDismissed: Wrong CFUserNotificationRef");
601 if (gNotificationRLS
)
603 // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
604 // We need to explicitly specify the desired CFRunLoop from which we want to remove this event source.
605 CFRunLoopRemoveSource(gRunLoop
, gNotificationRLS
, kCFRunLoopDefaultMode
);
606 CFRelease(gNotificationRLS
);
607 gNotificationRLS
= NULL
;
608 CFRelease(gNotification
);
609 gNotification
= NULL
;
611 // By dismissing the alert, the user has conceptually acknowleged the rename.
612 // (e.g. the machine's name is now officially "computer-2.local", not "computer.local".)
613 // If we get *another* conflict, the new alert should refer to the 'old' name
614 // as now being "computer-2.local", not "computer.local"
620 unpause_idle_timer();
623 static void ShowNameConflictNotification(CFMutableArrayRef header
, CFStringRef subtext
)
625 CFMutableDictionaryRef dictionary
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
626 if (!dictionary
) return;
630 CFDictionarySetValue(dictionary
, kCFUserNotificationAlertHeaderKey
, header
);
631 CFDictionarySetValue(dictionary
, kCFUserNotificationAlertMessageKey
, subtext
);
633 CFURLRef urlRef
= CFURLCreateWithFileSystemPath(NULL
, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle
, true);
634 if (urlRef
) { CFDictionarySetValue(dictionary
, kCFUserNotificationLocalizationURLKey
, urlRef
); CFRelease(urlRef
); }
636 if (gNotification
) // If notification already on-screen, update it in place
637 CFUserNotificationUpdate(gNotification
, 0, kCFUserNotificationCautionAlertLevel
, dictionary
);
638 else // else, we need to create it
641 gNotification
= CFUserNotificationCreate(NULL
, 0, kCFUserNotificationCautionAlertLevel
, &error
, dictionary
);
642 if (!gNotification
|| error
) { helplog(ASL_LEVEL_ERR
, "ShowNameConflictNotification: CFUserNotificationRef: Error %d", error
); return; }
643 gNotificationRLS
= CFUserNotificationCreateRunLoopSource(NULL
, gNotification
, NotificationCallBackDismissed
, 0);
644 if (!gNotificationRLS
) { helplog(ASL_LEVEL_ERR
,"ShowNameConflictNotification: RLS"); CFRelease(gNotification
); gNotification
= NULL
; return; }
645 // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
646 // We need to explicitly specify the desired CFRunLoop to which we want to add this event source.
647 CFRunLoopAddSource(gRunLoop
, gNotificationRLS
, kCFRunLoopDefaultMode
);
648 debug("gRunLoop=%p gNotification=%p gNotificationRLS=%p", gRunLoop
, gNotification
, gNotificationRLS
);
652 CFRelease(dictionary
);
655 static CFMutableArrayRef
GetHeader(const char* oldname
, const char* newname
, const CFStringRef msg
, const char* suffix
)
657 CFMutableArrayRef alertHeader
= NULL
;
659 const CFStringRef cfoldname
= CFStringCreateWithCString(NULL
, oldname
, kCFStringEncodingUTF8
);
660 // NULL newname means we've given up trying to construct a name that doesn't conflict
661 const CFStringRef cfnewname
= newname
? CFStringCreateWithCString(NULL
, newname
, kCFStringEncodingUTF8
) : NULL
;
662 // We tag a zero-width non-breaking space at the end of the literal text to guarantee that, no matter what
663 // arbitrary computer name the user may choose, this exact text (with zero-width non-breaking space added)
664 // can never be one that occurs in the Localizable.strings translation file.
666 helplog(ASL_LEVEL_ERR
,"Could not construct CFStrings for old=%s", newname
);
667 else if (newname
&& !cfnewname
)
668 helplog(ASL_LEVEL_ERR
,"Could not construct CFStrings for new=%s", newname
);
671 const CFStringRef s1
= CFStringCreateWithFormat(NULL
, NULL
, CFS_Format
, cfoldname
, suffix
);
672 const CFStringRef s2
= cfnewname
? CFStringCreateWithFormat(NULL
, NULL
, CFS_Format
, cfnewname
, suffix
) : NULL
;
674 alertHeader
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
677 helplog(ASL_LEVEL_ERR
, "Could not construct secondary CFString for old=%s", oldname
);
678 else if (cfnewname
&& !s2
)
679 helplog(ASL_LEVEL_ERR
, "Could not construct secondary CFString for new=%s", newname
);
680 else if (!alertHeader
)
681 helplog(ASL_LEVEL_ERR
, "Could not construct CFArray for notification");
684 // Make sure someone is logged in. We don't want this popping up over the login window
687 CFStringRef userName
= SCDynamicStoreCopyConsoleUser(NULL
, &uid
, &gid
);
691 CFArrayAppendValue(alertHeader
, msg
); // Opening phrase of message, provided by caller
692 CFArrayAppendValue(alertHeader
, CFS_OQ
); CFArrayAppendValue(alertHeader
, s1
); CFArrayAppendValue(alertHeader
, CFS_CQ
);
693 CFArrayAppendValue(alertHeader
, CFSTR(" is already in use on this network. "));
696 CFArrayAppendValue(alertHeader
, CFSTR("The name has been changed to "));
697 CFArrayAppendValue(alertHeader
, CFS_OQ
); CFArrayAppendValue(alertHeader
, s2
); CFArrayAppendValue(alertHeader
, CFS_CQ
);
698 CFArrayAppendValue(alertHeader
, CFSTR("."));
701 CFArrayAppendValue(alertHeader
, CFSTR("All attempts to find an available name by adding a number to the name were also unsuccessful."));
704 if (s1
) CFRelease(s1
);
705 if (s2
) CFRelease(s2
);
707 if (cfoldname
) CFRelease(cfoldname
);
708 if (cfnewname
) CFRelease(cfnewname
);
712 #endif /* ndef NO_CFUSERNOTIFICATION */
714 static void update_notification(void)
716 #ifndef NO_CFUSERNOTIFICATION
717 debug("entry ucn=%s, uhn=%s, lcn=%s, lhn=%s", usercompname
, userhostname
, lastcompname
, lasthostname
);
720 // Note: the "\xEF\xBB\xBF" byte sequence in the CFS_Format string is the UTF-8 encoding of the zero-width non-breaking space character.
721 // By appending this invisible character on the end of literal names, we ensure the these strings cannot inadvertently match any string
722 // in the localization file -- since we know for sure that none of our strings in the localization file contain the ZWNBS character.
723 CFS_OQ
= CFStringCreateWithCString(NULL
, "“", kCFStringEncodingUTF8
);
724 CFS_CQ
= CFStringCreateWithCString(NULL
, "”", kCFStringEncodingUTF8
);
725 CFS_Format
= CFStringCreateWithCString(NULL
, "%@%s\xEF\xBB\xBF", kCFStringEncodingUTF8
);
726 CFS_ComputerName
= CFStringCreateWithCString(NULL
, "The name of your computer ", kCFStringEncodingUTF8
);
727 CFS_ComputerNameMsg
= CFStringCreateWithCString(NULL
, "To change the name of your computer, "
728 "open System Preferences and click Sharing, then type the name in the Computer Name field.", kCFStringEncodingUTF8
);
729 CFS_LocalHostName
= CFStringCreateWithCString(NULL
, "This computer’s local hostname ", kCFStringEncodingUTF8
);
730 CFS_LocalHostNameMsg
= CFStringCreateWithCString(NULL
, "To change the local hostname, "
731 "open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field.", kCFStringEncodingUTF8
);
732 CFS_Problem
= CFStringCreateWithCString(NULL
, "This may indicate a problem with the local network. "
733 "Please inform your network administrator.", kCFStringEncodingUTF8
);
736 if (!usercompname
[0] && !userhostname
[0])
738 if (gNotificationRLS
)
740 debug("canceling notification %p", gNotification
);
741 CFUserNotificationCancel(gNotification
);
742 unpause_idle_timer();
747 CFMutableArrayRef header
= NULL
;
748 CFStringRef
* subtext
= NULL
;
749 if (userhostname
[0] && !lasthostname
[0]) // we've given up trying to construct a name that doesn't conflict
751 header
= GetHeader(userhostname
, NULL
, CFS_LocalHostName
, ".local");
752 subtext
= &CFS_Problem
;
754 else if (usercompname
[0])
756 header
= GetHeader(usercompname
, lastcompname
, CFS_ComputerName
, "");
757 subtext
= &CFS_ComputerNameMsg
;
761 header
= GetHeader(userhostname
, lasthostname
, CFS_LocalHostName
, ".local");
762 subtext
= &CFS_LocalHostNameMsg
;
764 ShowNameConflictNotification(header
, *subtext
);
771 do_mDNSPreferencesSetName(__unused mach_port_t port
, int key
, const char* old
, const char* new, audit_token_t token
)
773 SCPreferencesRef session
= NULL
;
775 Boolean locked
= FALSE
;
776 CFStringRef cfstr
= NULL
;
779 Boolean needUpdate
= FALSE
;
781 debug("entry %s old=%s new=%s", key
==kmDNSComputerName
? "ComputerName" : (key
==kmDNSLocalHostName
? "LocalHostName" : "UNKNOWN"), old
, new);
782 if (!authorized(&token
)) goto fin
;
784 switch ((enum mDNSPreferencesSetNameKey
)key
)
786 case kmDNSComputerName
:
790 case kmDNSLocalHostName
:
795 debug("unrecognized key: %d", key
);
801 helplog(ASL_LEVEL_ERR
, "%s: no last ptr", __func__
);
807 helplog(ASL_LEVEL_ERR
, "%s: no user ptr", __func__
);
811 if (0 == strncmp(old
, new, MAX_DOMAIN_LABEL
+1))
813 // if we've changed the name, but now someone else has set it to something different, we no longer need the notification
814 if (last
[0] && 0 != strncmp(last
, new, MAX_DOMAIN_LABEL
+1))
824 if (strncmp(last
, new, MAX_DOMAIN_LABEL
+1))
826 strncpy(last
, new, MAX_DOMAIN_LABEL
);
833 strncpy(user
, old
, MAX_DOMAIN_LABEL
);
837 if (!new[0]) // we've given up trying to construct a name that doesn't conflict
840 cfstr
= CFStringCreateWithCString(NULL
, new, kCFStringEncodingUTF8
);
842 session
= SCPreferencesCreate(NULL
, CFSTR(kmDNSHelperServiceName
), NULL
);
844 if (cfstr
== NULL
|| session
== NULL
)
846 debug("SCPreferencesCreate failed");
849 if (!SCPreferencesLock(session
, 0))
851 debug("lock failed");
856 switch ((enum mDNSPreferencesSetNameKey
)key
)
858 case kmDNSComputerName
:
860 // We want to write the new Computer Name to System Preferences, without disturbing the user-selected
861 // system-wide default character set used for things like AppleTalk NBP and NETBIOS service advertising.
862 // Note that this encoding is not used for the computer name, but since both are set by the same call,
863 // we need to take care to set the name without changing the character set.
864 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
865 CFStringRef unused
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
866 if (unused
) { CFRelease(unused
); unused
= NULL
; }
867 else encoding
= kCFStringEncodingUTF8
;
869 ok
= SCPreferencesSetComputerName(session
, cfstr
, encoding
);
872 case kmDNSLocalHostName
:
873 ok
= SCPreferencesSetLocalHostName(session
, cfstr
);
879 if (!ok
|| !SCPreferencesCommitChanges(session
) ||
880 !SCPreferencesApplyChanges(session
))
882 debug("SCPreferences update failed");
893 SCPreferencesUnlock(session
);
897 if (needUpdate
) update_notification();
903 formatNotDNSKey
, formatDdnsTypeItem
, formatDnsPrefixedServiceItem
906 // On Mac OS X on Intel, the four-character string seems to be stored backwards, at least sometimes.
907 // I suspect some overenthusiastic inexperienced engineer said, "On Intel everything's backwards,
908 // therefore I need to add some byte swapping in this API to make this four-character string backwards too."
909 // To cope with this we allow *both* "ddns" and "sndd" as valid item types.
911 static const char dnsprefix
[] = "dns:";
912 static const char ddns
[] = "ddns";
913 static const char ddnsrev
[] = "sndd";
915 #ifndef NO_SECURITYFRAMEWORK
916 static enum DNSKeyFormat
917 getDNSKeyFormat(SecKeychainItemRef item
, SecKeychainAttributeList
**attributesp
)
919 static UInt32 tags
[3] =
921 kSecTypeItemAttr
, kSecServiceItemAttr
, kSecAccountItemAttr
923 static SecKeychainAttributeInfo attributeInfo
=
925 sizeof(tags
)/sizeof(tags
[0]), tags
, NULL
927 SecKeychainAttributeList
*attributes
= NULL
;
928 enum DNSKeyFormat format
;
929 Boolean malformed
= FALSE
;
930 OSStatus status
= noErr
;
934 if (noErr
!= (status
= SecKeychainItemCopyAttributesAndData(item
,
935 &attributeInfo
, NULL
, &attributes
, NULL
, NULL
)))
937 debug("SecKeychainItemCopyAttributesAndData %d - skipping",
941 if (attributeInfo
.count
!= attributes
->count
)
943 for (i
= 0; !malformed
&& i
< (int)attributeInfo
.count
; ++i
)
944 if (attributeInfo
.tag
[i
] != attributes
->attr
[i
].tag
)
949 "malformed result from SecKeychainItemCopyAttributesAndData - skipping");
952 debug("entry (\"%.*s\", \"%.*s\", \"%.*s\")",
953 (int)attributes
->attr
[0].length
, attributes
->attr
[0].data
,
954 (int)attributes
->attr
[1].length
, attributes
->attr
[1].data
,
955 (int)attributes
->attr
[2].length
, attributes
->attr
[2].data
);
956 if (attributes
->attr
[1].length
>= MAX_ESCAPED_DOMAIN_NAME
+
959 debug("kSecServiceItemAttr too long (%u) - skipping",
960 (unsigned int)attributes
->attr
[1].length
);
963 if (attributes
->attr
[2].length
>= MAX_ESCAPED_DOMAIN_NAME
)
965 debug("kSecAccountItemAttr too long (%u) - skipping",
966 (unsigned int)attributes
->attr
[2].length
);
969 if (attributes
->attr
[1].length
>= sizeof(dnsprefix
)-1 &&
970 0 == strncasecmp(attributes
->attr
[1].data
, dnsprefix
,
971 sizeof(dnsprefix
)-1))
972 format
= formatDnsPrefixedServiceItem
;
973 else if (attributes
->attr
[0].length
== sizeof(ddns
)-1 &&
974 0 == strncasecmp(attributes
->attr
[0].data
, ddns
, sizeof(ddns
)-1))
975 format
= formatDdnsTypeItem
;
976 else if (attributes
->attr
[0].length
== sizeof(ddnsrev
)-1 &&
977 0 == strncasecmp(attributes
->attr
[0].data
, ddnsrev
, sizeof(ddnsrev
)-1))
978 format
= formatDdnsTypeItem
;
981 debug("uninterested in this entry");
984 *attributesp
= attributes
;
985 debug("accepting this entry");
989 SecKeychainItemFreeAttributesAndData(attributes
, NULL
);
990 return formatNotDNSKey
;
993 static CFPropertyListRef
994 getKeychainItemInfo(SecKeychainItemRef item
,
995 SecKeychainAttributeList
*attributes
, enum DNSKeyFormat format
)
997 CFMutableArrayRef entry
= NULL
;
998 CFDataRef data
= NULL
;
999 OSStatus status
= noErr
;
1003 if (NULL
== (entry
= CFArrayCreateMutable(NULL
, 0,
1004 &kCFTypeArrayCallBacks
)))
1006 debug("CFArrayCreateMutable failed");
1009 switch ((enum DNSKeyFormat
)format
)
1011 case formatDdnsTypeItem
:
1012 data
= CFDataCreate(kCFAllocatorDefault
,
1013 attributes
->attr
[1].data
, attributes
->attr
[1].length
);
1015 case formatDnsPrefixedServiceItem
:
1016 data
= CFDataCreate(kCFAllocatorDefault
,
1017 attributes
->attr
[1].data
+ sizeof(dnsprefix
)-1,
1018 attributes
->attr
[1].length
- (sizeof(dnsprefix
)-1));
1020 assert("unknown DNSKeyFormat value");
1025 debug("CFDataCreate for attr[1] failed");
1028 CFArrayAppendValue(entry
, data
);
1030 if (NULL
== (data
= CFDataCreate(kCFAllocatorDefault
,
1031 attributes
->attr
[2].data
, attributes
->attr
[2].length
)))
1033 debug("CFDataCreate for attr[2] failed");
1036 CFArrayAppendValue(entry
, data
);
1038 if (noErr
!= (status
= SecKeychainItemCopyAttributesAndData(item
, NULL
,
1039 NULL
, NULL
, &keylen
, &keyp
)))
1041 debug("could not retrieve key for \"%.*s\": %d",
1042 (int)attributes
->attr
[1].length
, attributes
->attr
[1].data
,
1046 data
= CFDataCreate(kCFAllocatorDefault
, keyp
, keylen
);
1047 SecKeychainItemFreeAttributesAndData(NULL
, keyp
);
1050 debug("CFDataCreate for keyp failed");
1053 CFArrayAppendValue(entry
, data
);
1065 do_mDNSKeychainGetSecrets(__unused mach_port_t port
, __unused
unsigned int *numsecrets
,
1066 __unused vm_offset_t
*secrets
, __unused mach_msg_type_number_t
*secretsCnt
, __unused
int *err
,
1067 __unused audit_token_t token
)
1069 #ifndef NO_SECURITYFRAMEWORK
1070 CFWriteStreamRef stream
= NULL
;
1071 CFDataRef result
= NULL
;
1072 CFPropertyListRef entry
= NULL
;
1073 CFMutableArrayRef keys
= NULL
;
1074 SecKeychainRef skc
= NULL
;
1075 SecKeychainItemRef item
= NULL
;
1076 SecKeychainSearchRef search
= NULL
;
1077 SecKeychainAttributeList
*attributes
= NULL
;
1078 enum DNSKeyFormat format
;
1079 OSStatus status
= 0;
1084 *secrets
= (vm_offset_t
)NULL
;
1085 if (!authorized(&token
))
1087 *err
= kmDNSHelperNotAuthorized
;
1090 if (NULL
== (keys
= CFArrayCreateMutable(NULL
, 0,
1091 &kCFTypeArrayCallBacks
)))
1093 debug("CFArrayCreateMutable failed");
1094 *err
= kmDNSHelperCreationFailed
;
1097 if (noErr
!= (status
= SecKeychainCopyDefault(&skc
)))
1099 *err
= kmDNSHelperKeychainCopyDefaultFailed
;
1102 if (noErr
!= (status
= SecKeychainSearchCreateFromAttributes(skc
, kSecGenericPasswordItemClass
, NULL
, &search
)))
1104 *err
= kmDNSHelperKeychainSearchCreationFailed
;
1107 for (status
= SecKeychainSearchCopyNext(search
, &item
);
1109 status
= SecKeychainSearchCopyNext(search
, &item
))
1111 if (formatNotDNSKey
!= (format
= getDNSKeyFormat(item
,
1113 NULL
!= (entry
= getKeychainItemInfo(item
, attributes
,
1116 CFArrayAppendValue(keys
, entry
);
1119 SecKeychainItemFreeAttributesAndData(attributes
, NULL
);
1122 if (errSecItemNotFound
!= status
)
1123 helplog(ASL_LEVEL_ERR
, "%s: SecKeychainSearchCopyNext failed: %d",
1125 if (NULL
== (stream
=
1126 CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorDefault
,
1127 kCFAllocatorDefault
)))
1129 *err
= kmDNSHelperCreationFailed
;
1130 debug("CFWriteStreamCreateWithAllocatedBuffers failed");
1133 CFWriteStreamOpen(stream
);
1134 if (0 == CFPropertyListWriteToStream(keys
, stream
,
1135 kCFPropertyListBinaryFormat_v1_0
, NULL
))
1137 *err
= kmDNSHelperPListWriteFailed
;
1138 debug("CFPropertyListWriteToStream failed");
1141 result
= CFWriteStreamCopyProperty(stream
,
1142 kCFStreamPropertyDataWritten
);
1143 if (KERN_SUCCESS
!= vm_allocate(mach_task_self(), secrets
,
1144 CFDataGetLength(result
), VM_FLAGS_ANYWHERE
))
1146 *err
= kmDNSHelperCreationFailed
;
1147 debug("vm_allocate failed");
1150 CFDataGetBytes(result
, CFRangeMake(0, CFDataGetLength(result
)),
1152 *secretsCnt
= CFDataGetLength(result
);
1153 *numsecrets
= CFArrayGetCount(keys
);
1157 debug("returning %u secrets", *numsecrets
);
1160 CFWriteStreamClose(stream
);
1171 update_idle_timer();
1172 return KERN_SUCCESS
;
1174 return KERN_FAILURE
;
1178 #ifndef MDNS_NO_IPSEC
1179 typedef enum _mDNSTunnelPolicyWhich
1181 kmDNSTunnelPolicySetup
,
1182 kmDNSTunnelPolicyTeardown
,
1183 kmDNSTunnelPolicyGenerate
1184 } mDNSTunnelPolicyWhich
;
1186 static const uint8_t kWholeV6Mask
= 128;
1187 static const uint8_t kZeroV6Mask
= 0;
1190 doTunnelPolicy(mDNSTunnelPolicyWhich which
,
1191 v6addr_t loc_inner
, uint8_t loc_bits
,
1192 v4addr_t loc_outer
, uint16_t loc_port
,
1193 v6addr_t rmt_inner
, uint8_t rmt_bits
,
1194 v4addr_t rmt_outer
, uint16_t rmt_port
);
1197 aliasTunnelAddress(v6addr_t address
)
1199 struct in6_aliasreq ifra_in6
;
1203 if (0 > (s
= socket(AF_INET6
, SOCK_DGRAM
, 0)))
1205 helplog(ASL_LEVEL_ERR
, "socket(AF_INET6, ...) failed: %s",
1207 err
= kmDNSHelperDatagramSocketCreationFailed
;
1210 memset(&ifra_in6
, 0, sizeof(ifra_in6
));
1211 strlcpy(ifra_in6
.ifra_name
, kTunnelAddressInterface
,
1212 sizeof(ifra_in6
.ifra_name
));
1213 ifra_in6
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
1214 ifra_in6
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
1216 ifra_in6
.ifra_addr
.sin6_family
= AF_INET6
;
1217 ifra_in6
.ifra_addr
.sin6_len
= sizeof(struct sockaddr_in6
);
1218 memcpy(&(ifra_in6
.ifra_addr
.sin6_addr
), address
,
1219 sizeof(ifra_in6
.ifra_addr
.sin6_addr
));
1221 ifra_in6
.ifra_prefixmask
.sin6_family
= AF_INET6
;
1222 ifra_in6
.ifra_prefixmask
.sin6_len
= sizeof(struct sockaddr_in6
);
1223 memset(&(ifra_in6
.ifra_prefixmask
.sin6_addr
), 0xFF,
1224 sizeof(ifra_in6
.ifra_prefixmask
.sin6_addr
));
1226 if (0 > ioctl(s
, SIOCAIFADDR_IN6
, &ifra_in6
))
1228 helplog(ASL_LEVEL_ERR
,
1229 "ioctl(..., SIOCAIFADDR_IN6, ...) failed: %s",
1231 err
= kmDNSHelperInterfaceCreationFailed
;
1235 v6addr_t zero
= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
1236 err
= doTunnelPolicy(kmDNSTunnelPolicyGenerate
,
1237 address
, kWholeV6Mask
, NULL
, 0,
1238 zero
, kZeroV6Mask
, NULL
, 0);
1247 unaliasTunnelAddress(v6addr_t address
)
1249 struct in6_ifreq ifr
;
1253 if (0 > (s
= socket(AF_INET6
, SOCK_DGRAM
, 0)))
1255 helplog(ASL_LEVEL_ERR
, "socket(AF_INET6, ...) failed: %s",
1257 err
= kmDNSHelperDatagramSocketCreationFailed
;
1260 memset(&ifr
, 0, sizeof(ifr
));
1261 strlcpy(ifr
.ifr_name
, kTunnelAddressInterface
, sizeof(ifr
.ifr_name
));
1262 ifr
.ifr_ifru
.ifru_addr
.sin6_family
= AF_INET6
;
1263 ifr
.ifr_ifru
.ifru_addr
.sin6_len
= sizeof(struct sockaddr_in6
);
1264 memcpy(&(ifr
.ifr_ifru
.ifru_addr
.sin6_addr
), address
,
1265 sizeof(ifr
.ifr_ifru
.ifru_addr
.sin6_addr
));
1267 if (0 > ioctl(s
, SIOCDIFADDR_IN6
, &ifr
))
1269 helplog(ASL_LEVEL_ERR
,
1270 "ioctl(..., SIOCDIFADDR_IN6, ...) failed: %s",
1272 err
= kmDNSHelperInterfaceDeletionFailed
;
1276 v6addr_t zero
= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
1277 err
= doTunnelPolicy(kmDNSTunnelPolicyTeardown
,
1278 address
, kWholeV6Mask
, NULL
, 0,
1279 zero
, kZeroV6Mask
, NULL
, 0);
1286 #endif /* ifndef MDNS_NO_IPSEC */
1289 do_mDNSAutoTunnelInterfaceUpDown(__unused mach_port_t port
, int updown
,
1290 v6addr_t address
, audit_token_t token
)
1292 #ifndef MDNS_NO_IPSEC
1294 if (!authorized(&token
)) goto fin
;
1296 switch ((enum mDNSUpDown
)updown
)
1299 aliasTunnelAddress(address
);
1302 unaliasTunnelAddress(address
);
1311 (void)port
; (void)updown
; (void)address
; (void)token
;
1312 *err
= kmDNSHelperIPsecDisabled
;
1314 update_idle_timer();
1315 return KERN_SUCCESS
;
1318 #ifndef MDNS_NO_IPSEC
1320 static const char g_racoon_config_dir
[] = "/var/run/racoon/";
1321 static const char g_racoon_config_dir_old
[] = "/etc/racoon/remote/";
1323 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
1324 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
1326 // Major version 6 is 10.2.x (Jaguar)
1327 // Major version 7 is 10.3.x (Panther)
1328 // Major version 8 is 10.4.x (Tiger)
1329 // Major version 9 is 10.5.x (Leopard)
1330 // Major version 10 is 10.6.x (SnowLeopard)
1331 static int MacOSXSystemBuildNumber(char* letter_out
, int* minor_out
)
1333 int major
= 0, minor
= 0;
1334 char letter
= 0, buildver
[256]="<Unknown>";
1335 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
1338 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
1339 if (cfbuildver
) CFStringGetCString(cfbuildver
, buildver
, sizeof(buildver
), kCFStringEncodingUTF8
);
1340 sscanf(buildver
, "%d%c%d", &major
, &letter
, &minor
);
1344 helplog(ASL_LEVEL_NOTICE
, "_CFCopySystemVersionDictionary failed");
1346 if (!major
) { major
=10; letter
= 'A'; minor
= 190; helplog(ASL_LEVEL_NOTICE
, "Note: No Major Build Version number found; assuming 10A190"); }
1347 if (letter_out
) *letter_out
= letter
;
1348 if (minor_out
) *minor_out
= minor
;
1352 static int g_oldRacoon
= -1;
1353 static int g_racoonSignal
= SIGUSR1
;
1355 static void DetermineRacoonVersion()
1357 if (g_oldRacoon
== -1)
1361 g_oldRacoon
= (MacOSXSystemBuildNumber(&letter
, &minor
) < 10);
1362 if (g_oldRacoon
|| (letter
== 'A' && minor
< 218)) g_racoonSignal
= SIGHUP
;
1363 debug("%s, signal=%d", g_oldRacoon
?"old":"new", g_racoonSignal
);
1367 static int UseOldRacoon()
1369 DetermineRacoonVersion();
1373 static int RacoonSignal()
1375 DetermineRacoonVersion();
1376 return g_racoonSignal
;
1379 static const char* GetRacoonConfigDir()
1381 return UseOldRacoon() ? g_racoon_config_dir_old
: g_racoon_config_dir
;
1384 static const char* GetOldRacoonConfigDir()
1386 return UseOldRacoon() ? NULL
: g_racoon_config_dir_old
;
1389 static const char racoon_config_file
[] = "anonymous.conf";
1390 static const char racoon_config_file_orig
[] = "anonymous.conf.orig";
1392 static const char configHeader
[] = "# BackToMyMac\n";
1394 static int IsFamiliarRacoonConfiguration(const char* racoon_config_path
)
1396 int fd
= open(racoon_config_path
, O_RDONLY
);
1397 debug("entry %s", racoon_config_path
);
1400 helplog(ASL_LEVEL_NOTICE
, "open \"%s\" failed: %s", racoon_config_path
, strerror(errno
));
1405 char header
[sizeof(configHeader
)] = {0};
1406 ssize_t bytesRead
= read(fd
, header
, sizeof(header
)-1);
1408 if (bytesRead
!= sizeof(header
)-1) return 0;
1409 return (0 == memcmp(header
, configHeader
, sizeof(header
)-1));
1414 revertAnonymousRacoonConfiguration(const char* dir
)
1418 debug("entry %s", dir
);
1420 char racoon_config_path
[64];
1421 strlcpy(racoon_config_path
, dir
, sizeof(racoon_config_path
));
1422 strlcat(racoon_config_path
, racoon_config_file
, sizeof(racoon_config_path
));
1425 int ret
= stat(racoon_config_path
, &s
);
1426 debug("stat(%s): %d errno=%d", racoon_config_path
, ret
, errno
);
1429 if (IsFamiliarRacoonConfiguration(racoon_config_path
))
1431 helplog(ASL_LEVEL_INFO
, "\"%s\" looks familiar, unlinking", racoon_config_path
);
1432 unlink(racoon_config_path
);
1436 helplog(ASL_LEVEL_NOTICE
, "\"%s\" does not look familiar, leaving in place", racoon_config_path
);
1440 else if (errno
!= ENOENT
)
1442 helplog(ASL_LEVEL_NOTICE
, "stat failed for \"%s\", leaving in place: %s", racoon_config_path
, strerror(errno
));
1446 char racoon_config_path_orig
[64];
1447 strlcpy(racoon_config_path_orig
, dir
, sizeof(racoon_config_path_orig
));
1448 strlcat(racoon_config_path_orig
, racoon_config_file_orig
, sizeof(racoon_config_path_orig
));
1450 ret
= stat(racoon_config_path_orig
, &s
);
1451 debug("stat(%s): %d errno=%d", racoon_config_path_orig
, ret
, errno
);
1454 if (0 > rename(racoon_config_path_orig
, racoon_config_path
))
1455 helplog(ASL_LEVEL_NOTICE
, "rename \"%s\" \"%s\" failed: %s", racoon_config_path_orig
, racoon_config_path
, strerror(errno
));
1457 debug("reverted \"%s\" to \"%s\"", racoon_config_path_orig
, racoon_config_path
);
1459 else if (errno
!= ENOENT
)
1461 helplog(ASL_LEVEL_NOTICE
, "stat failed for \"%s\", leaving in place: %s", racoon_config_path_orig
, strerror(errno
));
1467 moveAsideAnonymousRacoonConfiguration(const char* dir
)
1471 debug("entry %s", dir
);
1473 char racoon_config_path
[64];
1474 strlcpy(racoon_config_path
, dir
, sizeof(racoon_config_path
));
1475 strlcat(racoon_config_path
, racoon_config_file
, sizeof(racoon_config_path
));
1478 int ret
= stat(racoon_config_path
, &s
);
1481 if (IsFamiliarRacoonConfiguration(racoon_config_path
))
1483 helplog(ASL_LEVEL_INFO
, "\"%s\" looks familiar, unlinking", racoon_config_path
);
1484 unlink(racoon_config_path
);
1488 char racoon_config_path_orig
[64];
1489 strlcpy(racoon_config_path_orig
, dir
, sizeof(racoon_config_path_orig
));
1490 strlcat(racoon_config_path_orig
, racoon_config_file_orig
, sizeof(racoon_config_path_orig
));
1491 if (0 > rename(racoon_config_path
, racoon_config_path_orig
)) // If we didn't write it, move it to the side so it can be reverted later
1492 helplog(ASL_LEVEL_NOTICE
, "rename \"%s\" to \"%s\" failed: %s", racoon_config_path
, racoon_config_path_orig
, strerror(errno
));
1494 debug("successfully renamed \"%s\" to \"%s\"", racoon_config_path
, racoon_config_path_orig
);
1497 else if (errno
!= ENOENT
)
1499 helplog(ASL_LEVEL_NOTICE
, "stat failed for \"%s\", leaving in place: %s", racoon_config_path
, strerror(errno
));
1505 ensureExistenceOfRacoonConfigDir(const char* const racoon_config_dir
)
1508 int ret
= stat(racoon_config_dir
, &s
);
1511 if (errno
!= ENOENT
)
1513 helplog(ASL_LEVEL_ERR
, "stat of \"%s\" failed (%d): %s",
1514 racoon_config_dir
, ret
, strerror(errno
));
1519 ret
= mkdir(racoon_config_dir
, S_IRWXU
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
);
1522 helplog(ASL_LEVEL_ERR
, "mkdir \"%s\" failed: %s",
1523 racoon_config_dir
, strerror(errno
));
1527 helplog(ASL_LEVEL_INFO
, "created directory \"%s\"", racoon_config_dir
);
1530 else if (!(s
.st_mode
& S_IFDIR
))
1532 helplog(ASL_LEVEL_ERR
, "\"%s\" is not a directory!",
1541 createAnonymousRacoonConfiguration(const char *fqdn
)
1543 static const char config1
[] =
1544 "remote anonymous {\n"
1545 " exchange_mode aggressive;\n"
1547 " situation identity_only;\n"
1548 " verify_identifier off;\n"
1549 " generate_policy on;\n"
1550 " shared_secret keychain_by_id \"dns:";
1551 static const char config2
[] =
1554 " lifetime time 15 min;\n"
1555 " initial_contact on;\n"
1556 " support_proxy on;\n"
1557 " nat_traversal force;\n"
1558 " proposal_check claim;\n"
1560 " encryption_algorithm aes;\n"
1561 " hash_algorithm sha1;\n"
1562 " authentication_method pre_shared_key;\n"
1564 " lifetime time 15 min;\n"
1567 "sainfo anonymous { \n"
1569 " lifetime time 10 min;\n"
1570 " encryption_algorithm aes;\n"
1571 " authentication_algorithm hmac_sha1;\n"
1572 " compression_algorithm deflate;\n"
1574 char tmp_config_path
[64];
1575 char racoon_config_path
[64];
1576 const char* const racoon_config_dir
= GetRacoonConfigDir();
1577 const char* const racoon_config_dir_old
= GetOldRacoonConfigDir();
1582 if (0 > ensureExistenceOfRacoonConfigDir(racoon_config_dir
))
1585 strlcpy(tmp_config_path
, racoon_config_dir
, sizeof(tmp_config_path
));
1586 strlcat(tmp_config_path
, "tmp.XXXXXX", sizeof(tmp_config_path
));
1588 fd
= mkstemp(tmp_config_path
);
1592 helplog(ASL_LEVEL_ERR
, "mkstemp \"%s\" failed: %s",
1593 tmp_config_path
, strerror(errno
));
1596 write(fd
, configHeader
, sizeof(configHeader
)-1);
1597 write(fd
, config1
, sizeof(config1
)-1);
1598 write(fd
, fqdn
, strlen(fqdn
));
1599 write(fd
, config2
, sizeof(config2
)-1);
1602 strlcpy(racoon_config_path
, racoon_config_dir
, sizeof(racoon_config_path
));
1603 strlcat(racoon_config_path
, racoon_config_file
, sizeof(racoon_config_path
));
1605 moveAsideAnonymousRacoonConfiguration(racoon_config_dir_old
);
1606 moveAsideAnonymousRacoonConfiguration(racoon_config_dir
);
1608 if (0 > rename(tmp_config_path
, racoon_config_path
))
1610 unlink(tmp_config_path
);
1611 helplog(ASL_LEVEL_ERR
, "rename \"%s\" \"%s\" failed: %s",
1612 tmp_config_path
, racoon_config_path
, strerror(errno
));
1613 revertAnonymousRacoonConfiguration(racoon_config_dir_old
);
1614 revertAnonymousRacoonConfiguration(racoon_config_dir
);
1618 debug("successfully renamed \"%s\" \"%s\"", tmp_config_path
, racoon_config_path
);
1626 static const char racoon_pid_path
[] = "/var/run/racoon.pid";
1627 char buf
[] = "18446744073709551615"; /* largest 64-bit integer */
1630 unsigned long m
= 0;
1631 int fd
= open(racoon_pid_path
, O_RDONLY
);
1635 debug("open \"%s\" failed, and that's OK: %s", racoon_pid_path
,
1637 return kmDNSHelperRacoonNotificationFailed
;
1639 n
= read(fd
, buf
, sizeof(buf
)-1);
1643 debug("read of \"%s\" failed: %s", racoon_pid_path
,
1644 n
== 0 ? "empty file" : strerror(errno
));
1645 return kmDNSHelperRacoonNotificationFailed
;
1648 m
= strtoul(buf
, &p
, 10);
1649 if (*p
!= '\0' && !isspace(*p
))
1651 debug("invalid PID \"%s\" (around '%c')", buf
, *p
);
1652 return kmDNSHelperRacoonNotificationFailed
;
1656 debug("refusing to kill PID %lu", m
);
1657 return kmDNSHelperRacoonNotificationFailed
;
1659 if (0 != kill(m
, RacoonSignal()))
1661 debug("Could not signal racoon (%lu): %s", m
, strerror(errno
));
1662 return kmDNSHelperRacoonNotificationFailed
;
1664 debug("Sent racoon (%lu) signal %d", m
, RacoonSignal());
1672 struct dirent entry
, *entryp
= NULL
;
1673 DIR *dirp
= opendir("/dev/fd");
1677 /* fall back to the erroneous getdtablesize method */
1678 for (fd
= from
; fd
< getdtablesize(); ++fd
)
1682 while (0 == readdir_r(dirp
, &entry
, &entryp
) && NULL
!= entryp
)
1684 fd
= atoi(entryp
->d_name
);
1685 if (fd
>= from
&& fd
!= dirfd(dirp
))
1692 startRacoonOld(void)
1695 char * const racoon_args
[] = { "/usr/sbin/racoon", "-e", NULL
};
1700 if (0 == (pid
= fork()))
1703 execve(racoon_args
[0], racoon_args
, NULL
);
1704 helplog(ASL_LEVEL_ERR
, "execve of \"%s\" failed: %s",
1705 racoon_args
[0], strerror(errno
));
1708 helplog(ASL_LEVEL_NOTICE
, "racoon (pid=%lu) started",
1709 (unsigned long)pid
);
1710 n
= waitpid(pid
, &status
, 0);
1713 helplog(ASL_LEVEL_ERR
, "Unexpected waitpid failure: %s",
1715 return kmDNSHelperRacoonStartFailed
;
1719 helplog(ASL_LEVEL_ERR
, "Unexpected waitpid return value %d",
1721 return kmDNSHelperRacoonStartFailed
;
1723 else if (WIFSIGNALED(status
))
1725 helplog(ASL_LEVEL_ERR
,
1726 "racoon (pid=%lu) terminated due to signal %d",
1727 (unsigned long)pid
, WTERMSIG(status
));
1728 return kmDNSHelperRacoonStartFailed
;
1730 else if (WIFSTOPPED(status
))
1732 helplog(ASL_LEVEL_ERR
,
1733 "racoon (pid=%lu) has stopped due to signal %d",
1734 (unsigned long)pid
, WSTOPSIG(status
));
1735 return kmDNSHelperRacoonStartFailed
;
1737 else if (0 != WEXITSTATUS(status
))
1739 helplog(ASL_LEVEL_ERR
,
1740 "racoon (pid=%lu) exited with status %d",
1741 (unsigned long)pid
, WEXITSTATUS(status
));
1742 return kmDNSHelperRacoonStartFailed
;
1744 debug("racoon (pid=%lu) daemonized normally", (unsigned long)pid
);
1748 // constant and structure for the racoon control socket
1749 #define VPNCTL_CMD_PING 0x0004
1750 typedef struct vpnctl_hdr_struct
1764 int fd
= socket(PF_UNIX
, SOCK_STREAM
, 0);
1767 helplog(ASL_LEVEL_ERR
, "Could not create endpoint for racoon control socket: %d %s",
1768 errno
, strerror(errno
));
1769 return kmDNSHelperRacoonStartFailed
;
1772 struct sockaddr_un saddr
;
1773 memset(&saddr
, 0, sizeof(saddr
));
1774 saddr
.sun_family
= AF_UNIX
;
1775 saddr
.sun_len
= sizeof(saddr
);
1776 static const char racoon_control_sock_path
[] = "/var/run/vpncontrol.sock";
1777 strcpy(saddr
.sun_path
, racoon_control_sock_path
);
1778 int result
= connect(fd
, (struct sockaddr
*) &saddr
, saddr
.sun_len
);
1781 helplog(ASL_LEVEL_ERR
, "Could not connect racoon control socket %s: %d %s",
1782 racoon_control_sock_path
, errno
, strerror(errno
));
1783 return kmDNSHelperRacoonStartFailed
;
1786 u_int32_t btmm_cookie
= 0x4d4d5442;
1787 vpnctl_hdr h
= { VPNCTL_CMD_PING
, 0, btmm_cookie
, 0, 0, 0 };
1791 while (bytes
< sizeof(vpnctl_hdr
))
1793 ret
= write(fd
, ((unsigned char*)&h
)+bytes
, sizeof(vpnctl_hdr
) - bytes
);
1796 helplog(ASL_LEVEL_ERR
, "Could not write to racoon control socket: %d %s",
1797 errno
, strerror(errno
));
1798 return kmDNSHelperRacoonStartFailed
;
1810 while (counter
< 100)
1814 tv
= (struct timeval
){ 0, 10000 }; // 10 milliseconds * 100 iterations = 1 second max wait time
1816 result
= select(nfds
, &fds
, (fd_set
*)NULL
, (fd_set
*)NULL
, &tv
);
1819 if (FD_ISSET(fd
, &fds
))
1821 ret
= read(fd
, ((unsigned char*)&h
)+bytes
, sizeof(vpnctl_hdr
) - bytes
);
1825 helplog(ASL_LEVEL_ERR
, "Could not read from racoon control socket: %d %s",
1830 if (bytes
>= sizeof(vpnctl_hdr
)) break;
1834 debug("select returned but fd_isset not on expected fd\n");
1837 else if (result
< 0)
1839 debug("select returned %d errno %d %s\n", result
, errno
, strerror(errno
));
1840 if (errno
!= EINTR
) break;
1846 if (bytes
< sizeof(vpnctl_hdr
) || h
.cookie
!= btmm_cookie
) return kmDNSHelperRacoonStartFailed
;
1848 debug("racoon started");
1855 if ( 0 == notifyRacoon() )
1857 return UseOldRacoon() ? startRacoonOld() : startRacoon();
1860 #endif /* ndef MDNS_NO_IPSEC */
1863 do_mDNSConfigureServer(__unused mach_port_t port
, int updown
, const char *fqdn
, audit_token_t token
)
1865 #ifndef MDNS_NO_IPSEC
1867 if (!authorized(&token
)) goto fin
;
1869 switch ((enum mDNSUpDown
)updown
)
1872 if (0 != createAnonymousRacoonConfiguration(fqdn
)) goto fin
;
1875 revertAnonymousRacoonConfiguration(GetOldRacoonConfigDir());
1876 revertAnonymousRacoonConfiguration(GetRacoonConfigDir());
1882 if (0 != kickRacoon())
1888 (void)port
; (void)updown
; (void)fqdn
; (void)token
;
1889 *err
= kmDNSHelperIPsecDisabled
;
1891 update_idle_timer();
1892 return KERN_SUCCESS
;
1895 #ifndef MDNS_NO_IPSEC
1897 static unsigned int routeSeq
= 1;
1900 setupTunnelRoute(v6addr_t local
, v6addr_t remote
)
1904 struct rt_msghdr hdr
;
1905 struct sockaddr_in6 dst
;
1906 struct sockaddr_in6 gtwy
;
1911 if (0 > (s
= socket(PF_ROUTE
, SOCK_RAW
, AF_INET
)))
1913 helplog(ASL_LEVEL_ERR
, "socket(PF_ROUTE, ...) failed: %s",
1915 err
= kmDNSHelperRoutingSocketCreationFailed
;
1918 memset(&msg
, 0, sizeof(msg
));
1919 msg
.hdr
.rtm_msglen
= sizeof(msg
);
1920 msg
.hdr
.rtm_type
= RTM_ADD
;
1921 /* The following flags are set by `route add -inet6 -host ...` */
1922 msg
.hdr
.rtm_flags
= RTF_UP
| RTF_GATEWAY
| RTF_HOST
| RTF_STATIC
;
1923 msg
.hdr
.rtm_version
= RTM_VERSION
;
1924 msg
.hdr
.rtm_seq
= routeSeq
++;
1925 msg
.hdr
.rtm_addrs
= RTA_DST
| RTA_GATEWAY
;
1926 msg
.hdr
.rtm_inits
= RTV_MTU
;
1927 msg
.hdr
.rtm_rmx
.rmx_mtu
= 1280;
1929 msg
.dst
.sin6_len
= sizeof(msg
.dst
);
1930 msg
.dst
.sin6_family
= AF_INET6
;
1931 memcpy(&msg
.dst
.sin6_addr
, remote
, sizeof(msg
.dst
.sin6_addr
));
1933 msg
.gtwy
.sin6_len
= sizeof(msg
.gtwy
);
1934 msg
.gtwy
.sin6_family
= AF_INET6
;
1935 memcpy(&msg
.gtwy
.sin6_addr
, local
, sizeof(msg
.gtwy
.sin6_addr
));
1937 /* send message, ignore error when route already exists */
1938 if (0 > write(s
, &msg
, msg
.hdr
.rtm_msglen
))
1942 debug("write to routing socket failed: %s", strerror(errno_
));
1943 if (EEXIST
!= errno_
)
1945 err
= kmDNSHelperRouteAdditionFailed
;
1957 teardownTunnelRoute(v6addr_t remote
)
1961 struct rt_msghdr hdr
;
1962 struct sockaddr_in6 dst
;
1967 if (0 > (s
= socket(PF_ROUTE
, SOCK_RAW
, AF_INET
)))
1969 helplog(ASL_LEVEL_ERR
, "socket(PF_ROUTE, ...) failed: %s",
1971 err
= kmDNSHelperRoutingSocketCreationFailed
;
1974 memset(&msg
, 0, sizeof(msg
));
1976 msg
.hdr
.rtm_msglen
= sizeof(msg
);
1977 msg
.hdr
.rtm_type
= RTM_DELETE
;
1978 msg
.hdr
.rtm_version
= RTM_VERSION
;
1979 msg
.hdr
.rtm_seq
= routeSeq
++;
1980 msg
.hdr
.rtm_addrs
= RTA_DST
;
1982 msg
.dst
.sin6_len
= sizeof(msg
.dst
);
1983 msg
.dst
.sin6_family
= AF_INET6
;
1984 memcpy(&msg
.dst
.sin6_addr
, remote
, sizeof(msg
.dst
.sin6_addr
));
1985 if (0 > write(s
, &msg
, msg
.hdr
.rtm_msglen
))
1989 debug("write to routing socket failed: %s", strerror(errno_
));
1990 if (ESRCH
!= errno_
)
1992 err
= kmDNSHelperRouteDeletionFailed
;
2004 v4addr_to_string(v4addr_t addr
, char *buf
, size_t buflen
)
2006 if (NULL
== inet_ntop(AF_INET
, addr
, buf
, buflen
))
2008 helplog(ASL_LEVEL_ERR
, "inet_ntop failed: %s",
2010 return kmDNSHelperInvalidNetworkAddress
;
2017 v6addr_to_string(v6addr_t addr
, char *buf
, size_t buflen
)
2019 if (NULL
== inet_ntop(AF_INET6
, addr
, buf
, buflen
))
2021 helplog(ASL_LEVEL_ERR
, "inet_ntop failed: %s",
2023 return kmDNSHelperInvalidNetworkAddress
;
2029 /* Caller owns object returned in `policy' */
2031 generateTunnelPolicy(mDNSTunnelPolicyWhich which
, int in
,
2032 v4addr_t src
, uint16_t src_port
,
2033 v4addr_t dst
, uint16_t dst_port
,
2034 ipsec_policy_t
*policy
, size_t *len
)
2036 char srcs
[INET_ADDRSTRLEN
], dsts
[INET_ADDRSTRLEN
];
2038 char *inOut
= in
? "in" : "out";
2047 case kmDNSTunnelPolicySetup
:
2048 if (0 != (err
= v4addr_to_string(src
, srcs
, sizeof(srcs
))))
2050 if (0 != (err
= v4addr_to_string(dst
, dsts
, sizeof(dsts
))))
2052 n
= snprintf(buf
, sizeof(buf
),
2053 "%s ipsec esp/tunnel/%s[%u]-%s[%u]/require",
2054 inOut
, srcs
, src_port
, dsts
, dst_port
);
2056 case kmDNSTunnelPolicyTeardown
:
2057 n
= strlcpy(buf
, inOut
, sizeof(buf
));
2059 case kmDNSTunnelPolicyGenerate
:
2060 n
= snprintf(buf
, sizeof(buf
), "%s generate", inOut
);
2063 err
= kmDNSHelperIPsecPolicyCreationFailed
;
2067 if (n
>= (int)sizeof(buf
))
2069 err
= kmDNSHelperResultTooLarge
;
2073 debug("policy=\"%s\"", buf
);
2074 if (NULL
== (*policy
= (ipsec_policy_t
)ipsec_set_policy(buf
, n
)))
2076 helplog(ASL_LEVEL_ERR
,
2077 "Could not create IPsec policy from \"%s\"", buf
);
2078 err
= kmDNSHelperIPsecPolicyCreationFailed
;
2081 *len
= ((ipsec_policy_t
)(*policy
))->sadb_x_policy_len
* 8;
2088 sendPolicy(int s
, int setup
,
2089 struct sockaddr
*src
, uint8_t src_bits
,
2090 struct sockaddr
*dst
, uint8_t dst_bits
,
2091 ipsec_policy_t policy
, size_t len
)
2093 static unsigned int policySeq
= 0;
2096 debug("entry, setup=%d", setup
);
2098 err
= pfkey_send_spdadd(s
, src
, src_bits
, dst
, dst_bits
, -1,
2099 (char *)policy
, len
, policySeq
++);
2101 err
= pfkey_send_spddelete(s
, src
, src_bits
, dst
, dst_bits
, -1,
2102 (char *)policy
, len
, policySeq
++);
2105 helplog(ASL_LEVEL_ERR
, "Could not set IPsec policy: %s",
2107 err
= kmDNSHelperIPsecPolicySetFailed
;
2119 removeSA(int s
, struct sockaddr
*src
, struct sockaddr
*dst
)
2124 err
= pfkey_send_delete_all(s
, SADB_SATYPE_ESP
, IPSEC_MODE_ANY
, src
, dst
);
2127 helplog(ASL_LEVEL_ERR
, "Could not remove IPsec SA: %s", ipsec_strerror());
2128 err
= kmDNSHelperIPsecRemoveSAFailed
;
2131 err
= pfkey_send_delete_all(s
, SADB_SATYPE_ESP
, IPSEC_MODE_ANY
, dst
, src
);
2134 helplog(ASL_LEVEL_ERR
, "Could not remove IPsec SA: %s", ipsec_strerror());
2135 err
= kmDNSHelperIPsecRemoveSAFailed
;
2148 doTunnelPolicy(mDNSTunnelPolicyWhich which
,
2149 v6addr_t loc_inner
, uint8_t loc_bits
,
2150 v4addr_t loc_outer
, uint16_t loc_port
,
2151 v6addr_t rmt_inner
, uint8_t rmt_bits
,
2152 v4addr_t rmt_outer
, uint16_t rmt_port
)
2154 struct sockaddr_in6 sin6_loc
;
2155 struct sockaddr_in6 sin6_rmt
;
2156 ipsec_policy_t policy
= NULL
;
2162 if (0 > (s
= pfkey_open()))
2164 helplog(ASL_LEVEL_ERR
,
2165 "Could not create IPsec policy socket: %s",
2167 err
= kmDNSHelperIPsecPolicySocketCreationFailed
;
2171 memset(&sin6_loc
, 0, sizeof(sin6_loc
));
2172 sin6_loc
.sin6_len
= sizeof(sin6_loc
);
2173 sin6_loc
.sin6_family
= AF_INET6
;
2174 sin6_loc
.sin6_port
= htons(0);
2175 memcpy(&sin6_loc
.sin6_addr
, loc_inner
, sizeof(sin6_loc
.sin6_addr
));
2177 memset(&sin6_rmt
, 0, sizeof(sin6_rmt
));
2178 sin6_rmt
.sin6_len
= sizeof(sin6_rmt
);
2179 sin6_rmt
.sin6_family
= AF_INET6
;
2180 sin6_rmt
.sin6_port
= htons(0);
2181 memcpy(&sin6_rmt
.sin6_addr
, rmt_inner
, sizeof(sin6_rmt
.sin6_addr
));
2183 int setup
= which
!= kmDNSTunnelPolicyTeardown
;
2185 if (0 != (err
= generateTunnelPolicy(which
, 1,
2186 rmt_outer
, rmt_port
,
2187 loc_outer
, loc_port
,
2190 if (0 != (err
= sendPolicy(s
, setup
,
2191 (struct sockaddr
*)&sin6_rmt
, rmt_bits
,
2192 (struct sockaddr
*)&sin6_loc
, loc_bits
,
2200 if (0 != (err
= generateTunnelPolicy(which
, 0,
2201 loc_outer
, loc_port
,
2202 rmt_outer
, rmt_port
,
2205 if (0 != (err
= sendPolicy(s
, setup
,
2206 (struct sockaddr
*)&sin6_loc
, loc_bits
,
2207 (struct sockaddr
*)&sin6_rmt
, rmt_bits
,
2211 if (which
== kmDNSTunnelPolicyTeardown
&& loc_outer
&& rmt_outer
)
2213 struct sockaddr_in sin_loc
;
2214 struct sockaddr_in sin_rmt
;
2216 memset(&sin_loc
, 0, sizeof(sin_loc
));
2217 sin_loc
.sin_len
= sizeof(sin_loc
);
2218 sin_loc
.sin_family
= AF_INET
;
2219 sin_loc
.sin_port
= htons(0);
2220 memcpy(&sin_loc
.sin_addr
, loc_outer
, sizeof(sin_loc
.sin_addr
));
2222 memset(&sin_rmt
, 0, sizeof(sin_rmt
));
2223 sin_rmt
.sin_len
= sizeof(sin_rmt
);
2224 sin_rmt
.sin_family
= AF_INET
;
2225 sin_rmt
.sin_port
= htons(0);
2226 memcpy(&sin_rmt
.sin_addr
, rmt_outer
, sizeof(sin_rmt
.sin_addr
));
2228 if (0 != (err
= removeSA(s
, (struct sockaddr
*)&sin_loc
, (struct sockaddr
*)&sin_rmt
)))
2242 #endif /* ndef MDNS_NO_IPSEC */
2245 do_mDNSAutoTunnelSetKeys(__unused mach_port_t port
, int replacedelete
,
2246 v6addr_t loc_inner
, v4addr_t loc_outer
, uint16_t loc_port
,
2247 v6addr_t rmt_inner
, v4addr_t rmt_outer
, uint16_t rmt_port
,
2248 const char *fqdn
, int *err
, audit_token_t token
)
2250 #ifndef MDNS_NO_IPSEC
2251 static const char config
[] =
2253 "remote %s [%u] {\n"
2254 " disconnect_on_idle idle_timeout 600 idle_direction idle_outbound;\n"
2255 " exchange_mode aggressive;\n"
2257 " situation identity_only;\n"
2258 " verify_identifier off;\n"
2259 " generate_policy on;\n"
2260 " my_identifier user_fqdn \"dns:%s\";\n"
2261 " shared_secret keychain \"dns:%s\";\n"
2263 " lifetime time 15 min;\n"
2264 " initial_contact on;\n"
2265 " support_proxy on;\n"
2266 " nat_traversal force;\n"
2267 " proposal_check claim;\n"
2269 " encryption_algorithm aes;\n"
2270 " hash_algorithm sha1;\n"
2271 " authentication_method pre_shared_key;\n"
2273 " lifetime time 15 min;\n"
2276 "sainfo address %s any address %s any {\n"
2278 " lifetime time 10 min;\n"
2279 " encryption_algorithm aes;\n"
2280 " authentication_algorithm hmac_sha1;\n"
2281 " compression_algorithm deflate;\n"
2283 "sainfo address %s any address %s any {\n"
2285 " lifetime time 10 min;\n"
2286 " encryption_algorithm aes;\n"
2287 " authentication_algorithm hmac_sha1;\n"
2288 " compression_algorithm deflate;\n"
2290 char path
[PATH_MAX
] = "";
2291 char li
[INET6_ADDRSTRLEN
], lo
[INET_ADDRSTRLEN
],
2292 ri
[INET6_ADDRSTRLEN
], ro
[INET_ADDRSTRLEN
];
2295 char tmp_path
[PATH_MAX
] = "";
2299 if (!authorized(&token
))
2301 *err
= kmDNSHelperNotAuthorized
;
2304 switch ((enum mDNSAutoTunnelSetKeysReplaceDelete
)replacedelete
)
2306 case kmDNSAutoTunnelSetKeysReplace
:
2307 case kmDNSAutoTunnelSetKeysDelete
:
2310 *err
= kmDNSHelperInvalidTunnelSetKeysOperation
;
2313 if (0 != (*err
= v6addr_to_string(loc_inner
, li
, sizeof(li
))))
2315 if (0 != (*err
= v6addr_to_string(rmt_inner
, ri
, sizeof(ri
))))
2317 if (0 != (*err
= v4addr_to_string(loc_outer
, lo
, sizeof(lo
))))
2319 if (0 != (*err
= v4addr_to_string(rmt_outer
, ro
, sizeof(ro
))))
2321 debug("loc_inner=%s rmt_inner=%s", li
, ri
);
2322 debug("loc_outer=%s loc_port=%u rmt_outer=%s rmt_port=%u",
2323 lo
, loc_port
, ro
, rmt_port
);
2325 if ((int)sizeof(path
) <= snprintf(path
, sizeof(path
),
2326 "%s%s.%u.conf", GetRacoonConfigDir(), ro
,
2329 *err
= kmDNSHelperResultTooLarge
;
2332 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
)
2334 if (0 > ensureExistenceOfRacoonConfigDir(GetRacoonConfigDir()))
2336 *err
= kmDNSHelperRacoonConfigCreationFailed
;
2339 if ((int)sizeof(tmp_path
) <=
2340 snprintf(tmp_path
, sizeof(tmp_path
), "%s.XXXXXX", path
))
2342 *err
= kmDNSHelperResultTooLarge
;
2345 if (0 > (fd
= mkstemp(tmp_path
)))
2347 helplog(ASL_LEVEL_ERR
, "mkstemp \"%s\" failed: %s",
2348 tmp_path
, strerror(errno
));
2349 *err
= kmDNSHelperRacoonConfigCreationFailed
;
2352 if (NULL
== (fp
= fdopen(fd
, "w")))
2354 helplog(ASL_LEVEL_ERR
, "fdopen: %s",
2356 *err
= kmDNSHelperRacoonConfigCreationFailed
;
2360 fprintf(fp
, config
, configHeader
, ro
, rmt_port
, fqdn
, fqdn
, ri
, li
, li
, ri
);
2363 if (0 > rename(tmp_path
, path
))
2365 helplog(ASL_LEVEL_ERR
,
2366 "rename \"%s\" \"%s\" failed: %s",
2367 tmp_path
, path
, strerror(errno
));
2368 *err
= kmDNSHelperRacoonConfigCreationFailed
;
2371 if (0 != (*err
= kickRacoon()))
2376 if (0 != unlink(path
))
2377 debug("unlink \"%s\" failed: %s", path
,
2381 if (0 != (*err
= doTunnelPolicy(kmDNSTunnelPolicyTeardown
,
2382 loc_inner
, kWholeV6Mask
, loc_outer
, loc_port
,
2383 rmt_inner
, kWholeV6Mask
, rmt_outer
, rmt_port
)))
2385 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
&&
2386 0 != (*err
= doTunnelPolicy(kmDNSTunnelPolicySetup
,
2387 loc_inner
, kWholeV6Mask
, loc_outer
, loc_port
,
2388 rmt_inner
, kWholeV6Mask
, rmt_outer
, rmt_port
)))
2391 if (0 != (*err
= teardownTunnelRoute(rmt_inner
)))
2393 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
&&
2394 0 != (*err
= setupTunnelRoute(loc_inner
, rmt_inner
)))
2406 (void)replacedelete
; (void)loc_inner
; (void)loc_outer
; (void)loc_port
; (void)rmt_inner
;
2407 (void)rmt_outer
; (void)rmt_port
; (void)keydata
; (void)token
;
2409 *err
= kmDNSHelperIPsecDisabled
;
2410 #endif /* MDNS_NO_IPSEC */
2411 update_idle_timer();
2412 return KERN_SUCCESS
;