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.
18 #include <sys/cdefs.h>
19 #include <arpa/inet.h>
20 #include <bsm/libbsm.h>
22 #include <net/route.h>
23 #include <net/if_dl.h>
24 #include <net/if_types.h>
25 #include <netinet/in.h>
26 #include <netinet/if_ether.h>
27 #include <netinet6/in6_var.h>
28 #include <netinet6/nd6.h>
29 #include <netinet6/ipsec.h>
30 #include <sys/ioctl.h>
31 #include <sys/param.h>
32 #include <sys/socket.h>
43 #include <Security/Security.h>
44 #include <SystemConfiguration/SystemConfiguration.h>
45 #include <SystemConfiguration/SCDynamicStore.h>
46 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
47 #include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
48 #include <TargetConditionals.h>
49 #include <IOKit/pwr_mgt/IOPMLib.h>
52 #include "mDNSEmbeddedAPI.h"
54 #include "dnssd_ipc.h"
57 #include "helpermsgServer.h"
58 #include "helper-server.h"
59 #include "ipsec_options.h"
62 #define RTF_IFSCOPE 0x1000000
65 #if TARGET_OS_EMBEDDED
67 #define MDNS_NO_IPSEC 1
69 #define NO_CFUSERNOTIFICATION 1
70 #define NO_SECURITYFRAMEWORK 1
73 // Embed the client stub code here, so we can access private functions like ConnectToServer, create_hdr, deliver_request
74 #include "../mDNSShared/dnssd_ipc.c"
75 #include "../mDNSShared/dnssd_clientstub.c"
77 typedef struct sadb_x_policy
*ipsec_policy_t
;
79 uid_t mDNSResponderUID
;
80 gid_t mDNSResponderGID
;
81 static const char kTunnelAddressInterface
[] = "lo0";
84 debug_(const char *func
, const char *fmt
, ...)
90 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
92 helplog(ASL_LEVEL_DEBUG
, "%s: %s", func
, buf
);
96 authorized(audit_token_t
*token
)
99 pid_t pid
= (pid_t
)-1;
100 uid_t euid
= (uid_t
)-1;
102 audit_token_to_au32(*token
, NULL
, &euid
, NULL
, NULL
, NULL
, &pid
, NULL
,
104 ok
= (euid
== mDNSResponderUID
|| euid
== 0);
106 helplog(ASL_LEVEL_NOTICE
,
107 "Unauthorized access by euid=%lu pid=%lu",
108 (unsigned long)euid
, (unsigned long)pid
);
113 do_mDNSExit(__unused mach_port_t port
, audit_token_t token
)
116 if (!authorized(&token
))
118 helplog(ASL_LEVEL_INFO
, "exit");
126 kern_return_t
do_mDNSRequestBPF(__unused mach_port_t port
, audit_token_t token
)
128 if (!authorized(&token
)) return KERN_SUCCESS
;
130 DNSServiceErrorType err
= ConnectToServer(&ref
, 0, send_bpf
, NULL
, NULL
, NULL
);
131 if (err
) { helplog(ASL_LEVEL_ERR
, "do_mDNSRequestBPF: ConnectToServer %d", err
); return err
; }
134 size_t len
= sizeof(DNSServiceFlags
);
135 ipc_msg_hdr
*hdr
= create_hdr(send_bpf
, &len
, &ptr
, 0, ref
);
136 if (!hdr
) { DNSServiceRefDeallocate(ref
); return kDNSServiceErr_NoMemory
; }
138 deliver_request(hdr
, ref
); // Will free hdr for us
139 DNSServiceRefDeallocate(ref
);
144 kern_return_t
do_mDNSPowerRequest(__unused mach_port_t port
, int key
, int interval
, int *err
, audit_token_t token
)
147 if (!authorized(&token
)) { *err
= kmDNSHelperNotAuthorized
; goto fin
; }
149 CFArrayRef events
= IOPMCopyScheduledPowerEvents();
153 CFIndex count
= CFArrayGetCount(events
);
154 for (i
=0; i
<count
; i
++)
156 CFDictionaryRef dict
= CFArrayGetValueAtIndex(events
, i
);
157 CFStringRef id
= CFDictionaryGetValue(dict
, CFSTR(kIOPMPowerEventAppNameKey
));
158 if (CFEqual(id
, CFSTR("mDNSResponderHelper")))
160 CFDateRef EventTime
= CFDictionaryGetValue(dict
, CFSTR(kIOPMPowerEventTimeKey
));
161 CFStringRef EventType
= CFDictionaryGetValue(dict
, CFSTR(kIOPMPowerEventTypeKey
));
162 IOReturn result
= IOPMCancelScheduledPowerEvent(EventTime
, id
, EventType
);
163 //helplog(ASL_LEVEL_ERR, "Deleting old event %s");
164 if (result
) helplog(ASL_LEVEL_ERR
, "IOPMCancelScheduledPowerEvent %d failed %d", i
, result
);
170 if (key
< 0) // mDNSPowerRequest(-1,-1) means "clear any stale schedules" (see above)
172 else if (key
== 0) // mDNSPowerRequest(0, 0) means "sleep now"
174 IOReturn r
= IOPMSleepSystem(IOPMFindPowerManagement(MACH_PORT_NULL
));
175 if (r
) { usleep(100000); helplog(ASL_LEVEL_ERR
, "IOPMSleepSystem %d", r
); }
180 CFDateRef w
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent() + interval
);
183 IOReturn r
= IOPMSchedulePowerEvent(w
, CFSTR("mDNSResponderHelper"), key
? CFSTR(kIOPMAutoWake
) : CFSTR(kIOPMAutoSleep
));
184 if (r
) { usleep(100000); helplog(ASL_LEVEL_ERR
, "IOPMSchedulePowerEvent(%d) %d %x", interval
, r
, r
); }
194 kern_return_t
do_mDNSSetLocalAddressCacheEntry(__unused mach_port_t port
, int ifindex
, int family
, v6addr_t ip
, ethaddr_t eth
, int *err
, audit_token_t token
)
196 #define IPv6FMTSTRING "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X"
197 #define IPv6FMTARGS ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7], ip[8], ip[9], ip[10], ip[11], ip[12], ip[13], ip[14], ip[15]
200 helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry %d IPv%d %d.%d.%d.%d %02X:%02X:%02X:%02X:%02X:%02X",
201 ifindex
, family
, ip
[0], ip
[1], ip
[2], ip
[3], eth
[0], eth
[1], eth
[2], eth
[3], eth
[4], eth
[5]);
203 helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry %d IPv%d " IPv6FMTSTRING
" %02X:%02X:%02X:%02X:%02X:%02X",
204 ifindex
, family
, IPv6FMTARGS
, eth
[0], eth
[1], eth
[2], eth
[3], eth
[4], eth
[5]);
208 if (!authorized(&token
)) { *err
= kmDNSHelperNotAuthorized
; goto fin
; }
210 static int s
= -1, seq
= 0;
213 s
= socket(PF_ROUTE
, SOCK_RAW
, 0);
214 if (s
< 0) helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry: socket(PF_ROUTE, SOCK_RAW, 0) failed %d (%s)", errno
, strerror(errno
));
220 gettimeofday(&tv
, 0);
223 struct { struct rt_msghdr hdr
; struct sockaddr_inarp dst
; struct sockaddr_dl sdl
; } rtmsg
;
224 memset(&rtmsg
, 0, sizeof(rtmsg
));
226 rtmsg
.hdr
.rtm_msglen
= sizeof(rtmsg
);
227 rtmsg
.hdr
.rtm_version
= RTM_VERSION
;
228 rtmsg
.hdr
.rtm_type
= RTM_ADD
;
229 rtmsg
.hdr
.rtm_index
= ifindex
;
230 rtmsg
.hdr
.rtm_flags
= RTF_HOST
| RTF_STATIC
| RTF_IFSCOPE
;
231 rtmsg
.hdr
.rtm_addrs
= RTA_DST
| RTA_GATEWAY
;
232 rtmsg
.hdr
.rtm_pid
= 0;
233 rtmsg
.hdr
.rtm_seq
= seq
++;
234 rtmsg
.hdr
.rtm_errno
= 0;
235 rtmsg
.hdr
.rtm_use
= 0;
236 rtmsg
.hdr
.rtm_inits
= RTV_EXPIRE
;
237 rtmsg
.hdr
.rtm_rmx
.rmx_expire
= tv
.tv_sec
+ 30;
239 rtmsg
.dst
.sin_len
= sizeof(rtmsg
.dst
);
240 rtmsg
.dst
.sin_family
= AF_INET
;
241 rtmsg
.dst
.sin_port
= 0;
242 rtmsg
.dst
.sin_addr
.s_addr
= *(in_addr_t
*)ip
;
243 rtmsg
.dst
.sin_srcaddr
.s_addr
= 0;
244 rtmsg
.dst
.sin_tos
= 0;
245 rtmsg
.dst
.sin_other
= 0;
247 rtmsg
.sdl
.sdl_len
= sizeof(rtmsg
.sdl
);
248 rtmsg
.sdl
.sdl_family
= AF_LINK
;
249 rtmsg
.sdl
.sdl_index
= ifindex
;
250 rtmsg
.sdl
.sdl_type
= IFT_ETHER
;
251 rtmsg
.sdl
.sdl_nlen
= 0;
252 rtmsg
.sdl
.sdl_alen
= ETHER_ADDR_LEN
;
253 rtmsg
.sdl
.sdl_slen
= 0;
255 // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h)
256 memcpy(rtmsg
.sdl
.sdl_data
, eth
, sizeof(ethaddr_t
));
258 int len
= write(s
, (char *)&rtmsg
, sizeof(rtmsg
));
260 helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry: write(%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s)",
261 sizeof(rtmsg
), ifindex
, ip
[0], ip
[1], ip
[2], ip
[3], rtmsg
.hdr
.rtm_seq
, len
, errno
, strerror(errno
));
262 len
= read(s
, (char *)&rtmsg
, sizeof(rtmsg
));
263 if (len
< 0 || rtmsg
.hdr
.rtm_errno
)
264 helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry: read (%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s) %d",
265 sizeof(rtmsg
), ifindex
, ip
[0], ip
[1], ip
[2], ip
[3], rtmsg
.hdr
.rtm_seq
, len
, errno
, strerror(errno
), rtmsg
.hdr
.rtm_errno
);
271 struct { struct rt_msghdr hdr
; struct sockaddr_in6 dst
; struct sockaddr_dl sdl
; } rtmsg
;
272 memset(&rtmsg
, 0, sizeof(rtmsg
));
274 rtmsg
.hdr
.rtm_msglen
= sizeof(rtmsg
);
275 rtmsg
.hdr
.rtm_version
= RTM_VERSION
;
276 rtmsg
.hdr
.rtm_type
= RTM_ADD
;
277 rtmsg
.hdr
.rtm_index
= ifindex
;
278 rtmsg
.hdr
.rtm_flags
= RTF_HOST
| RTF_STATIC
| RTF_IFSCOPE
;
279 rtmsg
.hdr
.rtm_addrs
= RTA_DST
| RTA_GATEWAY
;
280 rtmsg
.hdr
.rtm_pid
= 0;
281 rtmsg
.hdr
.rtm_seq
= seq
++;
282 rtmsg
.hdr
.rtm_errno
= 0;
283 rtmsg
.hdr
.rtm_use
= 0;
284 rtmsg
.hdr
.rtm_inits
= RTV_EXPIRE
;
285 rtmsg
.hdr
.rtm_rmx
.rmx_expire
= tv
.tv_sec
+ 30;
287 rtmsg
.dst
.sin6_len
= sizeof(rtmsg
.dst
);
288 rtmsg
.dst
.sin6_family
= AF_INET6
;
289 rtmsg
.dst
.sin6_port
= 0;
290 rtmsg
.dst
.sin6_flowinfo
= 0;
291 rtmsg
.dst
.sin6_addr
= *(struct in6_addr
*)ip
;
292 rtmsg
.dst
.sin6_scope_id
= ifindex
;
294 rtmsg
.sdl
.sdl_len
= sizeof(rtmsg
.sdl
);
295 rtmsg
.sdl
.sdl_family
= AF_LINK
;
296 rtmsg
.sdl
.sdl_index
= ifindex
;
297 rtmsg
.sdl
.sdl_type
= IFT_ETHER
;
298 rtmsg
.sdl
.sdl_nlen
= 0;
299 rtmsg
.sdl
.sdl_alen
= ETHER_ADDR_LEN
;
300 rtmsg
.sdl
.sdl_slen
= 0;
302 // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h)
303 memcpy(rtmsg
.sdl
.sdl_data
, eth
, sizeof(ethaddr_t
));
305 int len
= write(s
, (char *)&rtmsg
, sizeof(rtmsg
));
307 helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry: write(%d) interface %d address " IPv6FMTSTRING
" seq %d result %d errno %d (%s)",
308 sizeof(rtmsg
), ifindex
, IPv6FMTARGS
, rtmsg
.hdr
.rtm_seq
, len
, errno
, strerror(errno
));
309 len
= read(s
, (char *)&rtmsg
, sizeof(rtmsg
));
310 if (len
< 0 || rtmsg
.hdr
.rtm_errno
)
311 helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry: read (%d) interface %d address " IPv6FMTSTRING
" seq %d result %d errno %d (%s) %d",
312 sizeof(rtmsg
), ifindex
, IPv6FMTARGS
, rtmsg
.hdr
.rtm_seq
, len
, errno
, strerror(errno
), rtmsg
.hdr
.rtm_errno
);
324 kern_return_t
do_mDNSNotify(__unused mach_port_t port
, const char *title
, const char *msg
, audit_token_t token
)
326 if (!authorized(&token
)) return KERN_SUCCESS
;
328 #ifndef NO_CFUSERNOTIFICATION
329 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.)";
330 CFStringRef alertHeader
= CFStringCreateWithCString(NULL
, title
, kCFStringEncodingUTF8
);
331 CFStringRef alertBody
= CFStringCreateWithCString(NULL
, msg
, kCFStringEncodingUTF8
);
332 CFStringRef alertFooter
= CFStringCreateWithCString(NULL
, footer
, kCFStringEncodingUTF8
);
333 CFStringRef alertMessage
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@\r\r%@"), alertBody
, alertFooter
);
334 CFRelease(alertBody
);
335 CFRelease(alertFooter
);
336 int err
= CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel
, NULL
, NULL
, NULL
, alertHeader
, alertMessage
, NULL
);
337 if (err
) helplog(ASL_LEVEL_ERR
, "CFUserNotificationDisplayNotice returned %d", err
);
338 CFRelease(alertHeader
);
339 CFRelease(alertMessage
);
343 #endif /* NO_CFUSERNOTIFICATION */
350 do_mDNSDynamicStoreSetConfig(__unused mach_port_t port
, int key
,
351 const char* subkey
, vm_offset_t value
, mach_msg_type_number_t valueCnt
,
354 CFStringRef sckey
= NULL
;
355 Boolean release_sckey
= FALSE
;
356 CFDataRef bytes
= NULL
;
357 CFPropertyListRef plist
= NULL
;
358 SCDynamicStoreRef store
= NULL
;
361 if (!authorized(&token
)) goto fin
;
363 switch ((enum mDNSDynamicStoreSetConfigKey
)key
)
365 case kmDNSMulticastConfig
:
366 sckey
= CFSTR("State:/Network/" kDNSServiceCompMulticastDNS
);
368 case kmDNSDynamicConfig
:
369 sckey
= CFSTR("State:/Network/DynamicDNS");
371 case kmDNSPrivateConfig
:
372 sckey
= CFSTR("State:/Network/" kDNSServiceCompPrivateDNS
);
374 case kmDNSBackToMyMacConfig
:
375 sckey
= CFSTR("State:/Network/BackToMyMac");
377 case kmDNSSleepProxyServersState
:
379 CFMutableStringRef tmp
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
380 CFStringAppend(tmp
, CFSTR("State:/Network/Interface/"));
381 CFStringAppendCString(tmp
, subkey
, kCFStringEncodingUTF8
);
382 CFStringAppend(tmp
, CFSTR("/SleepProxyServers"));
383 sckey
= CFStringCreateCopy(kCFAllocatorDefault
, tmp
);
384 release_sckey
= TRUE
;
389 debug("unrecognized key %d", key
);
392 if (NULL
== (bytes
= CFDataCreateWithBytesNoCopy(NULL
, (void *)value
,
393 valueCnt
, kCFAllocatorNull
)))
395 debug("CFDataCreateWithBytesNoCopy of value failed");
398 if (NULL
== (plist
= CFPropertyListCreateFromXMLData(NULL
, bytes
,
399 kCFPropertyListImmutable
, NULL
)))
401 debug("CFPropertyListCreateFromXMLData of bytes failed");
406 if (NULL
== (store
= SCDynamicStoreCreate(NULL
,
407 CFSTR(kmDNSHelperServiceName
), NULL
, NULL
)))
409 debug("SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
412 SCDynamicStoreSetValue(store
, sckey
, plist
);
422 if (release_sckey
&& sckey
)
424 vm_deallocate(mach_task_self(), value
, valueCnt
);
429 char usercompname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last computer name the user saw
430 char userhostname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last local host name the user saw
431 char lastcompname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last computer name saved to preferences
432 char lasthostname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last local host name saved to preferences
434 #ifndef NO_CFUSERNOTIFICATION
435 static CFStringRef CFS_OQ
= NULL
;
436 static CFStringRef CFS_CQ
= NULL
;
437 static CFStringRef CFS_Format
= NULL
;
438 static CFStringRef CFS_ComputerName
= NULL
;
439 static CFStringRef CFS_ComputerNameMsg
= NULL
;
440 static CFStringRef CFS_LocalHostName
= NULL
;
441 static CFStringRef CFS_LocalHostNameMsg
= NULL
;
442 static CFStringRef CFS_Problem
= NULL
;
444 static CFUserNotificationRef gNotification
= NULL
;
445 static CFRunLoopSourceRef gNotificationRLS
= NULL
;
447 static void NotificationCallBackDismissed(CFUserNotificationRef userNotification
, CFOptionFlags responseFlags
)
450 (void)responseFlags
; // Unused
451 if (userNotification
!= gNotification
) helplog(ASL_LEVEL_ERR
, "NotificationCallBackDismissed: Wrong CFUserNotificationRef");
452 if (gNotificationRLS
)
454 // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
455 // We need to explicitly specify the desired CFRunLoop from which we want to remove this event source.
456 CFRunLoopRemoveSource(gRunLoop
, gNotificationRLS
, kCFRunLoopDefaultMode
);
457 CFRelease(gNotificationRLS
);
458 gNotificationRLS
= NULL
;
459 CFRelease(gNotification
);
460 gNotification
= NULL
;
462 // By dismissing the alert, the user has conceptually acknowleged the rename.
463 // (e.g. the machine's name is now officially "computer-2.local", not "computer.local".)
464 // If we get *another* conflict, the new alert should refer to the 'old' name
465 // as now being "computer-2.local", not "computer.local"
471 unpause_idle_timer();
474 static void ShowNameConflictNotification(CFMutableArrayRef header
, CFStringRef subtext
)
476 CFMutableDictionaryRef dictionary
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
477 if (!dictionary
) return;
481 CFDictionarySetValue(dictionary
, kCFUserNotificationAlertHeaderKey
, header
);
482 CFDictionarySetValue(dictionary
, kCFUserNotificationAlertMessageKey
, subtext
);
484 CFURLRef urlRef
= CFURLCreateWithFileSystemPath(NULL
, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle
, true);
485 if (urlRef
) { CFDictionarySetValue(dictionary
, kCFUserNotificationLocalizationURLKey
, urlRef
); CFRelease(urlRef
); }
487 if (gNotification
) // If notification already on-screen, update it in place
488 CFUserNotificationUpdate(gNotification
, 0, kCFUserNotificationCautionAlertLevel
, dictionary
);
489 else // else, we need to create it
492 gNotification
= CFUserNotificationCreate(NULL
, 0, kCFUserNotificationCautionAlertLevel
, &error
, dictionary
);
493 if (!gNotification
|| error
) { helplog(ASL_LEVEL_ERR
, "ShowNameConflictNotification: CFUserNotificationRef: Error %d", error
); return; }
494 gNotificationRLS
= CFUserNotificationCreateRunLoopSource(NULL
, gNotification
, NotificationCallBackDismissed
, 0);
495 if (!gNotificationRLS
) { helplog(ASL_LEVEL_ERR
,"ShowNameConflictNotification: RLS"); CFRelease(gNotification
); gNotification
= NULL
; return; }
496 // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
497 // We need to explicitly specify the desired CFRunLoop to which we want to add this event source.
498 CFRunLoopAddSource(gRunLoop
, gNotificationRLS
, kCFRunLoopDefaultMode
);
499 debug("gRunLoop=%p gNotification=%p gNotificationRLS=%p", gRunLoop
, gNotification
, gNotificationRLS
);
503 CFRelease(dictionary
);
506 static CFMutableArrayRef
GetHeader(const char* oldname
, const char* newname
, const CFStringRef msg
, const char* suffix
)
508 CFMutableArrayRef alertHeader
= NULL
;
510 const CFStringRef cfoldname
= CFStringCreateWithCString(NULL
, oldname
, kCFStringEncodingUTF8
);
511 // NULL newname means we've given up trying to construct a name that doesn't conflict
512 const CFStringRef cfnewname
= newname
? CFStringCreateWithCString(NULL
, newname
, kCFStringEncodingUTF8
) : NULL
;
513 // We tag a zero-width non-breaking space at the end of the literal text to guarantee that, no matter what
514 // arbitrary computer name the user may choose, this exact text (with zero-width non-breaking space added)
515 // can never be one that occurs in the Localizable.strings translation file.
517 helplog(ASL_LEVEL_ERR
,"Could not construct CFStrings for old=%s", newname
);
518 else if (newname
&& !cfnewname
)
519 helplog(ASL_LEVEL_ERR
,"Could not construct CFStrings for new=%s", newname
);
522 const CFStringRef s1
= CFStringCreateWithFormat(NULL
, NULL
, CFS_Format
, cfoldname
, suffix
);
523 const CFStringRef s2
= cfnewname
? CFStringCreateWithFormat(NULL
, NULL
, CFS_Format
, cfnewname
, suffix
) : NULL
;
525 alertHeader
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
528 helplog(ASL_LEVEL_ERR
, "Could not construct secondary CFString for old=%s", oldname
);
529 else if (cfnewname
&& !s2
)
530 helplog(ASL_LEVEL_ERR
, "Could not construct secondary CFString for new=%s", newname
);
531 else if (!alertHeader
)
532 helplog(ASL_LEVEL_ERR
, "Could not construct CFArray for notification");
535 // Make sure someone is logged in. We don't want this popping up over the login window
538 CFStringRef userName
= SCDynamicStoreCopyConsoleUser(NULL
, &uid
, &gid
);
542 CFArrayAppendValue(alertHeader
, msg
); // Opening phrase of message, provided by caller
543 CFArrayAppendValue(alertHeader
, CFS_OQ
); CFArrayAppendValue(alertHeader
, s1
); CFArrayAppendValue(alertHeader
, CFS_CQ
);
544 CFArrayAppendValue(alertHeader
, CFSTR(" is already in use on this network. "));
547 CFArrayAppendValue(alertHeader
, CFSTR("The name has been changed to "));
548 CFArrayAppendValue(alertHeader
, CFS_OQ
); CFArrayAppendValue(alertHeader
, s2
); CFArrayAppendValue(alertHeader
, CFS_CQ
);
549 CFArrayAppendValue(alertHeader
, CFSTR("."));
552 CFArrayAppendValue(alertHeader
, CFSTR("All attempts to find an available name by adding a number to the name were also unsuccessful."));
555 if (s1
) CFRelease(s1
);
556 if (s2
) CFRelease(s2
);
558 if (cfoldname
) CFRelease(cfoldname
);
559 if (cfnewname
) CFRelease(cfnewname
);
563 #endif /* ndef NO_CFUSERNOTIFICATION */
565 static void update_notification(void)
567 #ifndef NO_CFUSERNOTIFICATION
568 debug("entry ucn=%s, uhn=%s, lcn=%s, lhn=%s", usercompname
, userhostname
, lastcompname
, lasthostname
);
571 // 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.
572 // By appending this invisible character on the end of literal names, we ensure the these strings cannot inadvertently match any string
573 // in the localization file -- since we know for sure that none of our strings in the localization file contain the ZWNBS character.
574 CFS_OQ
= CFStringCreateWithCString(NULL
, "“", kCFStringEncodingUTF8
);
575 CFS_CQ
= CFStringCreateWithCString(NULL
, "”", kCFStringEncodingUTF8
);
576 CFS_Format
= CFStringCreateWithCString(NULL
, "%@%s\xEF\xBB\xBF", kCFStringEncodingUTF8
);
577 CFS_ComputerName
= CFStringCreateWithCString(NULL
, "The name of your computer ", kCFStringEncodingUTF8
);
578 CFS_ComputerNameMsg
= CFStringCreateWithCString(NULL
, "To change the name of your computer, "
579 "open System Preferences and click Sharing, then type the name in the Computer Name field.", kCFStringEncodingUTF8
);
580 CFS_LocalHostName
= CFStringCreateWithCString(NULL
, "This computer’s local hostname ", kCFStringEncodingUTF8
);
581 CFS_LocalHostNameMsg
= CFStringCreateWithCString(NULL
, "To change the local hostname, "
582 "open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field.", kCFStringEncodingUTF8
);
583 CFS_Problem
= CFStringCreateWithCString(NULL
, "This may indicate a problem with the local network. "
584 "Please inform your network administrator.", kCFStringEncodingUTF8
);
587 if (!usercompname
[0] && !userhostname
[0])
589 if (gNotificationRLS
)
591 debug("canceling notification %p", gNotification
);
592 CFUserNotificationCancel(gNotification
);
593 unpause_idle_timer();
598 CFMutableArrayRef header
= NULL
;
599 CFStringRef
* subtext
= NULL
;
600 if (userhostname
[0] && !lasthostname
[0]) // we've given up trying to construct a name that doesn't conflict
602 header
= GetHeader(userhostname
, NULL
, CFS_LocalHostName
, ".local");
603 subtext
= &CFS_Problem
;
605 else if (usercompname
[0])
607 header
= GetHeader(usercompname
, lastcompname
, CFS_ComputerName
, "");
608 subtext
= &CFS_ComputerNameMsg
;
612 header
= GetHeader(userhostname
, lasthostname
, CFS_LocalHostName
, ".local");
613 subtext
= &CFS_LocalHostNameMsg
;
615 ShowNameConflictNotification(header
, *subtext
);
622 do_mDNSPreferencesSetName(__unused mach_port_t port
, int key
, const char* old
, const char* new, audit_token_t token
)
624 SCPreferencesRef session
= NULL
;
626 Boolean locked
= FALSE
;
627 CFStringRef cfstr
= NULL
;
630 Boolean needUpdate
= FALSE
;
632 debug("entry %s old=%s new=%s", key
==kmDNSComputerName
? "ComputerName" : (key
==kmDNSLocalHostName
? "LocalHostName" : "UNKNOWN"), old
, new);
633 if (!authorized(&token
)) goto fin
;
635 switch ((enum mDNSPreferencesSetNameKey
)key
)
637 case kmDNSComputerName
:
641 case kmDNSLocalHostName
:
646 debug("unrecognized key: %d", key
);
652 helplog(ASL_LEVEL_ERR
, "%s: no last ptr", __func__
);
658 helplog(ASL_LEVEL_ERR
, "%s: no user ptr", __func__
);
662 if (0 == strncmp(old
, new, MAX_DOMAIN_LABEL
+1))
664 // old and new are same means the config changed i.e, the user has set something in the preferences pane.
665 // This means the conflict has been resolved. We need to dismiss the dialogue.
666 if (last
[0] && 0 != strncmp(last
, new, MAX_DOMAIN_LABEL
+1))
676 // old and new are not same, this means there is a conflict. For the first conflict, we show
677 // the old value and the new value. For all subsequent conflicts, while the dialogue is still
678 // up, we do a real time update of the "new" value in the dialogue. That's why we update just
679 // "last" here and not "user".
680 if (strncmp(last
, new, MAX_DOMAIN_LABEL
+1))
682 strncpy(last
, new, MAX_DOMAIN_LABEL
);
687 // If we are not showing the dialogue, we need to remember the first "old" value so that
688 // we maintain the same through the lifetime of the dialogue. Subsequence conflicts don't
689 // update the "old" value.
692 strncpy(user
, old
, MAX_DOMAIN_LABEL
);
696 if (!new[0]) // we've given up trying to construct a name that doesn't conflict
699 cfstr
= CFStringCreateWithCString(NULL
, new, kCFStringEncodingUTF8
);
701 session
= SCPreferencesCreate(NULL
, CFSTR(kmDNSHelperServiceName
), NULL
);
703 if (cfstr
== NULL
|| session
== NULL
)
705 debug("SCPreferencesCreate failed");
708 if (!SCPreferencesLock(session
, 0))
710 debug("lock failed");
715 switch ((enum mDNSPreferencesSetNameKey
)key
)
717 case kmDNSComputerName
:
719 // We want to write the new Computer Name to System Preferences, without disturbing the user-selected
720 // system-wide default character set used for things like AppleTalk NBP and NETBIOS service advertising.
721 // Note that this encoding is not used for the computer name, but since both are set by the same call,
722 // we need to take care to set the name without changing the character set.
723 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
724 CFStringRef unused
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
725 if (unused
) { CFRelease(unused
); unused
= NULL
; }
726 else encoding
= kCFStringEncodingUTF8
;
728 ok
= SCPreferencesSetComputerName(session
, cfstr
, encoding
);
731 case kmDNSLocalHostName
:
732 ok
= SCPreferencesSetLocalHostName(session
, cfstr
);
738 if (!ok
|| !SCPreferencesCommitChanges(session
) ||
739 !SCPreferencesApplyChanges(session
))
741 debug("SCPreferences update failed");
752 SCPreferencesUnlock(session
);
756 if (needUpdate
) update_notification();
762 formatNotDNSKey
, formatDdnsTypeItem
, formatDnsPrefixedServiceItem
765 // On Mac OS X on Intel, the four-character string seems to be stored backwards, at least sometimes.
766 // I suspect some overenthusiastic inexperienced engineer said, "On Intel everything's backwards,
767 // therefore I need to add some byte swapping in this API to make this four-character string backwards too."
768 // To cope with this we allow *both* "ddns" and "sndd" as valid item types.
770 static const char dnsprefix
[] = "dns:";
771 static const char ddns
[] = "ddns";
772 static const char ddnsrev
[] = "sndd";
774 #ifndef NO_SECURITYFRAMEWORK
775 static enum DNSKeyFormat
776 getDNSKeyFormat(SecKeychainItemRef item
, SecKeychainAttributeList
**attributesp
)
778 static UInt32 tags
[3] =
780 kSecTypeItemAttr
, kSecServiceItemAttr
, kSecAccountItemAttr
782 static SecKeychainAttributeInfo attributeInfo
=
784 sizeof(tags
)/sizeof(tags
[0]), tags
, NULL
786 SecKeychainAttributeList
*attributes
= NULL
;
787 enum DNSKeyFormat format
;
788 Boolean malformed
= FALSE
;
789 OSStatus status
= noErr
;
793 if (noErr
!= (status
= SecKeychainItemCopyAttributesAndData(item
,
794 &attributeInfo
, NULL
, &attributes
, NULL
, NULL
)))
796 debug("SecKeychainItemCopyAttributesAndData %d - skipping",
800 if (attributeInfo
.count
!= attributes
->count
)
802 for (i
= 0; !malformed
&& i
< (int)attributeInfo
.count
; ++i
)
803 if (attributeInfo
.tag
[i
] != attributes
->attr
[i
].tag
)
808 "malformed result from SecKeychainItemCopyAttributesAndData - skipping");
811 debug("entry (\"%.*s\", \"%.*s\", \"%.*s\")",
812 (int)attributes
->attr
[0].length
, attributes
->attr
[0].data
,
813 (int)attributes
->attr
[1].length
, attributes
->attr
[1].data
,
814 (int)attributes
->attr
[2].length
, attributes
->attr
[2].data
);
815 if (attributes
->attr
[1].length
>= MAX_ESCAPED_DOMAIN_NAME
+
818 debug("kSecServiceItemAttr too long (%u) - skipping",
819 (unsigned int)attributes
->attr
[1].length
);
822 if (attributes
->attr
[2].length
>= MAX_ESCAPED_DOMAIN_NAME
)
824 debug("kSecAccountItemAttr too long (%u) - skipping",
825 (unsigned int)attributes
->attr
[2].length
);
828 if (attributes
->attr
[1].length
>= sizeof(dnsprefix
)-1 &&
829 0 == strncasecmp(attributes
->attr
[1].data
, dnsprefix
,
830 sizeof(dnsprefix
)-1))
831 format
= formatDnsPrefixedServiceItem
;
832 else if (attributes
->attr
[0].length
== sizeof(ddns
)-1 &&
833 0 == strncasecmp(attributes
->attr
[0].data
, ddns
, sizeof(ddns
)-1))
834 format
= formatDdnsTypeItem
;
835 else if (attributes
->attr
[0].length
== sizeof(ddnsrev
)-1 &&
836 0 == strncasecmp(attributes
->attr
[0].data
, ddnsrev
, sizeof(ddnsrev
)-1))
837 format
= formatDdnsTypeItem
;
840 debug("uninterested in this entry");
843 *attributesp
= attributes
;
844 debug("accepting this entry");
848 SecKeychainItemFreeAttributesAndData(attributes
, NULL
);
849 return formatNotDNSKey
;
852 static CFPropertyListRef
853 getKeychainItemInfo(SecKeychainItemRef item
,
854 SecKeychainAttributeList
*attributes
, enum DNSKeyFormat format
)
856 CFMutableArrayRef entry
= NULL
;
857 CFDataRef data
= NULL
;
858 OSStatus status
= noErr
;
862 if (NULL
== (entry
= CFArrayCreateMutable(NULL
, 0,
863 &kCFTypeArrayCallBacks
)))
865 debug("CFArrayCreateMutable failed");
868 switch ((enum DNSKeyFormat
)format
)
870 case formatDdnsTypeItem
:
871 data
= CFDataCreate(kCFAllocatorDefault
,
872 attributes
->attr
[1].data
, attributes
->attr
[1].length
);
874 case formatDnsPrefixedServiceItem
:
875 data
= CFDataCreate(kCFAllocatorDefault
,
876 attributes
->attr
[1].data
+ sizeof(dnsprefix
)-1,
877 attributes
->attr
[1].length
- (sizeof(dnsprefix
)-1));
879 assert("unknown DNSKeyFormat value");
884 debug("CFDataCreate for attr[1] failed");
887 CFArrayAppendValue(entry
, data
);
889 if (NULL
== (data
= CFDataCreate(kCFAllocatorDefault
,
890 attributes
->attr
[2].data
, attributes
->attr
[2].length
)))
892 debug("CFDataCreate for attr[2] failed");
895 CFArrayAppendValue(entry
, data
);
897 if (noErr
!= (status
= SecKeychainItemCopyAttributesAndData(item
, NULL
,
898 NULL
, NULL
, &keylen
, &keyp
)))
900 debug("could not retrieve key for \"%.*s\": %d",
901 (int)attributes
->attr
[1].length
, attributes
->attr
[1].data
,
905 data
= CFDataCreate(kCFAllocatorDefault
, keyp
, keylen
);
906 SecKeychainItemFreeAttributesAndData(NULL
, keyp
);
909 debug("CFDataCreate for keyp failed");
912 CFArrayAppendValue(entry
, data
);
924 do_mDNSKeychainGetSecrets(__unused mach_port_t port
, __unused
unsigned int *numsecrets
,
925 __unused vm_offset_t
*secrets
, __unused mach_msg_type_number_t
*secretsCnt
, __unused
int *err
,
926 __unused audit_token_t token
)
928 #ifndef NO_SECURITYFRAMEWORK
929 CFWriteStreamRef stream
= NULL
;
930 CFDataRef result
= NULL
;
931 CFPropertyListRef entry
= NULL
;
932 CFMutableArrayRef keys
= NULL
;
933 SecKeychainRef skc
= NULL
;
934 SecKeychainItemRef item
= NULL
;
935 SecKeychainSearchRef search
= NULL
;
936 SecKeychainAttributeList
*attributes
= NULL
;
937 enum DNSKeyFormat format
;
943 *secrets
= (vm_offset_t
)NULL
;
944 if (!authorized(&token
))
946 *err
= kmDNSHelperNotAuthorized
;
949 if (NULL
== (keys
= CFArrayCreateMutable(NULL
, 0,
950 &kCFTypeArrayCallBacks
)))
952 debug("CFArrayCreateMutable failed");
953 *err
= kmDNSHelperCreationFailed
;
956 if (noErr
!= (status
= SecKeychainCopyDefault(&skc
)))
958 *err
= kmDNSHelperKeychainCopyDefaultFailed
;
961 if (noErr
!= (status
= SecKeychainSearchCreateFromAttributes(skc
, kSecGenericPasswordItemClass
, NULL
, &search
)))
963 *err
= kmDNSHelperKeychainSearchCreationFailed
;
966 for (status
= SecKeychainSearchCopyNext(search
, &item
);
968 status
= SecKeychainSearchCopyNext(search
, &item
))
970 if (formatNotDNSKey
!= (format
= getDNSKeyFormat(item
,
972 NULL
!= (entry
= getKeychainItemInfo(item
, attributes
,
975 CFArrayAppendValue(keys
, entry
);
978 SecKeychainItemFreeAttributesAndData(attributes
, NULL
);
981 if (errSecItemNotFound
!= status
)
982 helplog(ASL_LEVEL_ERR
, "%s: SecKeychainSearchCopyNext failed: %d",
984 if (NULL
== (stream
=
985 CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorDefault
,
986 kCFAllocatorDefault
)))
988 *err
= kmDNSHelperCreationFailed
;
989 debug("CFWriteStreamCreateWithAllocatedBuffers failed");
992 CFWriteStreamOpen(stream
);
993 if (0 == CFPropertyListWriteToStream(keys
, stream
,
994 kCFPropertyListBinaryFormat_v1_0
, NULL
))
996 *err
= kmDNSHelperPListWriteFailed
;
997 debug("CFPropertyListWriteToStream failed");
1000 result
= CFWriteStreamCopyProperty(stream
,
1001 kCFStreamPropertyDataWritten
);
1002 if (KERN_SUCCESS
!= vm_allocate(mach_task_self(), secrets
,
1003 CFDataGetLength(result
), VM_FLAGS_ANYWHERE
))
1005 *err
= kmDNSHelperCreationFailed
;
1006 debug("vm_allocate failed");
1009 CFDataGetBytes(result
, CFRangeMake(0, CFDataGetLength(result
)),
1011 *secretsCnt
= CFDataGetLength(result
);
1012 *numsecrets
= CFArrayGetCount(keys
);
1016 debug("returning %u secrets", *numsecrets
);
1019 CFWriteStreamClose(stream
);
1030 update_idle_timer();
1031 return KERN_SUCCESS
;
1033 return KERN_FAILURE
;
1037 #ifndef MDNS_NO_IPSEC
1038 typedef enum _mDNSTunnelPolicyWhich
1040 kmDNSTunnelPolicySetup
,
1041 kmDNSTunnelPolicyTeardown
,
1042 kmDNSTunnelPolicyGenerate
1043 } mDNSTunnelPolicyWhich
;
1045 // For kmDNSTunnelPolicySetup, you can setup IPv6-in-IPv6 tunnel or IPv6-in-IPv4 tunnel
1046 // kmDNSNoTunnel is used for other Policy types
1047 typedef enum _mDNSTunnelType
1050 kmDNSIPv6IPv4Tunnel
,
1054 static const uint8_t kWholeV6Mask
= 128;
1055 static const uint8_t kZeroV6Mask
= 0;
1058 doTunnelPolicy(mDNSTunnelPolicyWhich which
, mDNSTunnelType type
,
1059 v6addr_t loc_inner
, uint8_t loc_bits
,
1060 v4addr_t loc_outer
, uint16_t loc_port
,
1061 v6addr_t rmt_inner
, uint8_t rmt_bits
,
1062 v4addr_t rmt_outer
, uint16_t rmt_port
,
1063 v6addr_t loc_outer6
, v6addr_t rmt_outer6
);
1066 aliasTunnelAddress(v6addr_t address
)
1068 struct in6_aliasreq ifra_in6
;
1072 if (0 > (s
= socket(AF_INET6
, SOCK_DGRAM
, 0)))
1074 helplog(ASL_LEVEL_ERR
, "socket(AF_INET6, ...) failed: %s",
1076 err
= kmDNSHelperDatagramSocketCreationFailed
;
1079 memset(&ifra_in6
, 0, sizeof(ifra_in6
));
1080 strlcpy(ifra_in6
.ifra_name
, kTunnelAddressInterface
,
1081 sizeof(ifra_in6
.ifra_name
));
1082 ifra_in6
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
1083 ifra_in6
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
1085 ifra_in6
.ifra_addr
.sin6_family
= AF_INET6
;
1086 ifra_in6
.ifra_addr
.sin6_len
= sizeof(struct sockaddr_in6
);
1087 memcpy(&(ifra_in6
.ifra_addr
.sin6_addr
), address
,
1088 sizeof(ifra_in6
.ifra_addr
.sin6_addr
));
1090 ifra_in6
.ifra_prefixmask
.sin6_family
= AF_INET6
;
1091 ifra_in6
.ifra_prefixmask
.sin6_len
= sizeof(struct sockaddr_in6
);
1092 memset(&(ifra_in6
.ifra_prefixmask
.sin6_addr
), 0xFF,
1093 sizeof(ifra_in6
.ifra_prefixmask
.sin6_addr
));
1095 if (0 > ioctl(s
, SIOCAIFADDR_IN6
, &ifra_in6
))
1097 helplog(ASL_LEVEL_ERR
,
1098 "ioctl(..., SIOCAIFADDR_IN6, ...) failed: %s",
1100 err
= kmDNSHelperInterfaceCreationFailed
;
1104 v6addr_t zero
= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
1105 err
= doTunnelPolicy(kmDNSTunnelPolicyGenerate
, kmDNSNoTunnel
,
1106 address
, kWholeV6Mask
, NULL
, 0,
1107 zero
, kZeroV6Mask
, NULL
, 0, NULL
, NULL
);
1116 unaliasTunnelAddress(v6addr_t address
)
1118 struct in6_ifreq ifr
;
1122 if (0 > (s
= socket(AF_INET6
, SOCK_DGRAM
, 0)))
1124 helplog(ASL_LEVEL_ERR
, "socket(AF_INET6, ...) failed: %s",
1126 err
= kmDNSHelperDatagramSocketCreationFailed
;
1129 memset(&ifr
, 0, sizeof(ifr
));
1130 strlcpy(ifr
.ifr_name
, kTunnelAddressInterface
, sizeof(ifr
.ifr_name
));
1131 ifr
.ifr_ifru
.ifru_addr
.sin6_family
= AF_INET6
;
1132 ifr
.ifr_ifru
.ifru_addr
.sin6_len
= sizeof(struct sockaddr_in6
);
1133 memcpy(&(ifr
.ifr_ifru
.ifru_addr
.sin6_addr
), address
,
1134 sizeof(ifr
.ifr_ifru
.ifru_addr
.sin6_addr
));
1136 if (0 > ioctl(s
, SIOCDIFADDR_IN6
, &ifr
))
1138 helplog(ASL_LEVEL_ERR
,
1139 "ioctl(..., SIOCDIFADDR_IN6, ...) failed: %s",
1141 err
= kmDNSHelperInterfaceDeletionFailed
;
1145 v6addr_t zero
= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
1146 err
= doTunnelPolicy(kmDNSTunnelPolicyTeardown
, kmDNSNoTunnel
,
1147 address
, kWholeV6Mask
, NULL
, 0,
1148 zero
, kZeroV6Mask
, NULL
, 0, NULL
, NULL
);
1155 #endif /* ifndef MDNS_NO_IPSEC */
1158 do_mDNSAutoTunnelInterfaceUpDown(__unused mach_port_t port
, int updown
,
1159 v6addr_t address
, audit_token_t token
)
1161 #ifndef MDNS_NO_IPSEC
1163 if (!authorized(&token
)) goto fin
;
1165 switch ((enum mDNSUpDown
)updown
)
1168 aliasTunnelAddress(address
);
1171 unaliasTunnelAddress(address
);
1180 (void)port
; (void)updown
; (void)address
; (void)token
;
1182 update_idle_timer();
1183 return KERN_SUCCESS
;
1186 #ifndef MDNS_NO_IPSEC
1188 static const char g_racoon_config_dir
[] = "/var/run/racoon/";
1189 static const char g_racoon_config_dir_old
[] = "/etc/racoon/remote/";
1191 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
1192 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
1194 // Major version 6 is 10.2.x (Jaguar)
1195 // Major version 7 is 10.3.x (Panther)
1196 // Major version 8 is 10.4.x (Tiger)
1197 // Major version 9 is 10.5.x (Leopard)
1198 // Major version 10 is 10.6.x (SnowLeopard)
1199 static int MacOSXSystemBuildNumber(char* letter_out
, int* minor_out
)
1201 int major
= 0, minor
= 0;
1202 char letter
= 0, buildver
[256]="<Unknown>";
1203 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
1206 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
1207 if (cfbuildver
) CFStringGetCString(cfbuildver
, buildver
, sizeof(buildver
), kCFStringEncodingUTF8
);
1208 sscanf(buildver
, "%d%c%d", &major
, &letter
, &minor
);
1212 helplog(ASL_LEVEL_NOTICE
, "_CFCopySystemVersionDictionary failed");
1214 if (!major
) { major
=10; letter
= 'A'; minor
= 190; helplog(ASL_LEVEL_NOTICE
, "Note: No Major Build Version number found; assuming 10A190"); }
1215 if (letter_out
) *letter_out
= letter
;
1216 if (minor_out
) *minor_out
= minor
;
1220 static int UseOldRacoon()
1222 static int g_oldRacoon
= -1;
1224 if (g_oldRacoon
== -1)
1228 g_oldRacoon
= (MacOSXSystemBuildNumber(&letter
, &minor
) < 10);
1229 debug("%s", g_oldRacoon
?"old":"new");
1235 static int RacoonSignal()
1237 return UseOldRacoon() ? SIGHUP
: SIGUSR1
;
1240 static const char* GetRacoonConfigDir()
1242 return UseOldRacoon() ? g_racoon_config_dir_old
: g_racoon_config_dir
;
1245 static const char* GetOldRacoonConfigDir()
1247 return UseOldRacoon() ? NULL
: g_racoon_config_dir_old
;
1250 static const char racoon_config_file
[] = "anonymous.conf";
1251 static const char racoon_config_file_orig
[] = "anonymous.conf.orig";
1253 static const char configHeader
[] = "# BackToMyMac\n";
1255 static int IsFamiliarRacoonConfiguration(const char* racoon_config_path
)
1257 int fd
= open(racoon_config_path
, O_RDONLY
);
1258 debug("entry %s", racoon_config_path
);
1261 helplog(ASL_LEVEL_NOTICE
, "open \"%s\" failed: %s", racoon_config_path
, strerror(errno
));
1266 char header
[sizeof(configHeader
)] = {0};
1267 ssize_t bytesRead
= read(fd
, header
, sizeof(header
)-1);
1269 if (bytesRead
!= sizeof(header
)-1) return 0;
1270 return (0 == memcmp(header
, configHeader
, sizeof(header
)-1));
1275 revertAnonymousRacoonConfiguration(const char* dir
)
1279 debug("entry %s", dir
);
1281 char racoon_config_path
[64];
1282 strlcpy(racoon_config_path
, dir
, sizeof(racoon_config_path
));
1283 strlcat(racoon_config_path
, racoon_config_file
, sizeof(racoon_config_path
));
1286 int ret
= stat(racoon_config_path
, &s
);
1287 debug("stat(%s): %d errno=%d", racoon_config_path
, ret
, errno
);
1290 if (IsFamiliarRacoonConfiguration(racoon_config_path
))
1292 helplog(ASL_LEVEL_INFO
, "\"%s\" looks familiar, unlinking", racoon_config_path
);
1293 unlink(racoon_config_path
);
1297 helplog(ASL_LEVEL_NOTICE
, "\"%s\" does not look familiar, leaving in place", racoon_config_path
);
1301 else if (errno
!= ENOENT
)
1303 helplog(ASL_LEVEL_NOTICE
, "stat failed for \"%s\", leaving in place: %s", racoon_config_path
, strerror(errno
));
1307 char racoon_config_path_orig
[64];
1308 strlcpy(racoon_config_path_orig
, dir
, sizeof(racoon_config_path_orig
));
1309 strlcat(racoon_config_path_orig
, racoon_config_file_orig
, sizeof(racoon_config_path_orig
));
1311 ret
= stat(racoon_config_path_orig
, &s
);
1312 debug("stat(%s): %d errno=%d", racoon_config_path_orig
, ret
, errno
);
1315 if (0 > rename(racoon_config_path_orig
, racoon_config_path
))
1316 helplog(ASL_LEVEL_NOTICE
, "rename \"%s\" \"%s\" failed: %s", racoon_config_path_orig
, racoon_config_path
, strerror(errno
));
1318 debug("reverted \"%s\" to \"%s\"", racoon_config_path_orig
, racoon_config_path
);
1320 else if (errno
!= ENOENT
)
1322 helplog(ASL_LEVEL_NOTICE
, "stat failed for \"%s\", leaving in place: %s", racoon_config_path_orig
, strerror(errno
));
1328 moveAsideAnonymousRacoonConfiguration(const char* dir
)
1332 debug("entry %s", dir
);
1334 char racoon_config_path
[64];
1335 strlcpy(racoon_config_path
, dir
, sizeof(racoon_config_path
));
1336 strlcat(racoon_config_path
, racoon_config_file
, sizeof(racoon_config_path
));
1339 int ret
= stat(racoon_config_path
, &s
);
1342 if (IsFamiliarRacoonConfiguration(racoon_config_path
))
1344 helplog(ASL_LEVEL_INFO
, "\"%s\" looks familiar, unlinking", racoon_config_path
);
1345 unlink(racoon_config_path
);
1349 char racoon_config_path_orig
[64];
1350 strlcpy(racoon_config_path_orig
, dir
, sizeof(racoon_config_path_orig
));
1351 strlcat(racoon_config_path_orig
, racoon_config_file_orig
, sizeof(racoon_config_path_orig
));
1352 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
1353 helplog(ASL_LEVEL_NOTICE
, "rename \"%s\" to \"%s\" failed: %s", racoon_config_path
, racoon_config_path_orig
, strerror(errno
));
1355 debug("successfully renamed \"%s\" to \"%s\"", racoon_config_path
, racoon_config_path_orig
);
1358 else if (errno
!= ENOENT
)
1360 helplog(ASL_LEVEL_NOTICE
, "stat failed for \"%s\", leaving in place: %s", racoon_config_path
, strerror(errno
));
1366 ensureExistenceOfRacoonConfigDir(const char* const racoon_config_dir
)
1369 int ret
= stat(racoon_config_dir
, &s
);
1372 if (errno
!= ENOENT
)
1374 helplog(ASL_LEVEL_ERR
, "stat of \"%s\" failed (%d): %s",
1375 racoon_config_dir
, ret
, strerror(errno
));
1380 ret
= mkdir(racoon_config_dir
, S_IRWXU
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
);
1383 helplog(ASL_LEVEL_ERR
, "mkdir \"%s\" failed: %s",
1384 racoon_config_dir
, strerror(errno
));
1388 helplog(ASL_LEVEL_INFO
, "created directory \"%s\"", racoon_config_dir
);
1391 else if (!(s
.st_mode
& S_IFDIR
))
1393 helplog(ASL_LEVEL_ERR
, "\"%s\" is not a directory!",
1402 createAnonymousRacoonConfiguration(const char *fqdn
)
1404 static const char config1
[] =
1405 "remote anonymous {\n"
1406 " exchange_mode aggressive;\n"
1408 " situation identity_only;\n"
1409 " verify_identifier off;\n"
1410 " generate_policy on;\n"
1411 " shared_secret keychain_by_id \"dns:";
1412 static const char config2
[] =
1415 " lifetime time 15 min;\n"
1416 " initial_contact on;\n"
1417 " support_proxy on;\n"
1418 " nat_traversal force;\n"
1419 " proposal_check claim;\n"
1421 " encryption_algorithm aes;\n"
1422 " hash_algorithm sha1;\n"
1423 " authentication_method pre_shared_key;\n"
1425 " lifetime time 15 min;\n"
1428 "sainfo anonymous { \n"
1430 " lifetime time 10 min;\n"
1431 " encryption_algorithm aes;\n"
1432 " authentication_algorithm hmac_sha1;\n"
1433 " compression_algorithm deflate;\n"
1435 char tmp_config_path
[64];
1436 char racoon_config_path
[64];
1437 const char* const racoon_config_dir
= GetRacoonConfigDir();
1438 const char* const racoon_config_dir_old
= GetOldRacoonConfigDir();
1443 if (0 > ensureExistenceOfRacoonConfigDir(racoon_config_dir
))
1446 strlcpy(tmp_config_path
, racoon_config_dir
, sizeof(tmp_config_path
));
1447 strlcat(tmp_config_path
, "tmp.XXXXXX", sizeof(tmp_config_path
));
1449 fd
= mkstemp(tmp_config_path
);
1453 helplog(ASL_LEVEL_ERR
, "mkstemp \"%s\" failed: %s",
1454 tmp_config_path
, strerror(errno
));
1457 write(fd
, configHeader
, sizeof(configHeader
)-1);
1458 write(fd
, config1
, sizeof(config1
)-1);
1459 write(fd
, fqdn
, strlen(fqdn
));
1460 write(fd
, config2
, sizeof(config2
)-1);
1463 strlcpy(racoon_config_path
, racoon_config_dir
, sizeof(racoon_config_path
));
1464 strlcat(racoon_config_path
, racoon_config_file
, sizeof(racoon_config_path
));
1466 moveAsideAnonymousRacoonConfiguration(racoon_config_dir_old
);
1467 moveAsideAnonymousRacoonConfiguration(racoon_config_dir
);
1469 if (0 > rename(tmp_config_path
, racoon_config_path
))
1471 unlink(tmp_config_path
);
1472 helplog(ASL_LEVEL_ERR
, "rename \"%s\" \"%s\" failed: %s",
1473 tmp_config_path
, racoon_config_path
, strerror(errno
));
1474 revertAnonymousRacoonConfiguration(racoon_config_dir_old
);
1475 revertAnonymousRacoonConfiguration(racoon_config_dir
);
1479 debug("successfully renamed \"%s\" \"%s\"", tmp_config_path
, racoon_config_path
);
1487 static const char racoon_pid_path
[] = "/var/run/racoon.pid";
1488 char buf
[] = "18446744073709551615"; /* largest 64-bit integer */
1491 unsigned long m
= 0;
1492 int fd
= open(racoon_pid_path
, O_RDONLY
);
1496 debug("open \"%s\" failed, and that's OK: %s", racoon_pid_path
,
1498 return kmDNSHelperRacoonNotificationFailed
;
1500 n
= read(fd
, buf
, sizeof(buf
)-1);
1504 debug("read of \"%s\" failed: %s", racoon_pid_path
,
1505 n
== 0 ? "empty file" : strerror(errno
));
1506 return kmDNSHelperRacoonNotificationFailed
;
1509 m
= strtoul(buf
, &p
, 10);
1510 if (*p
!= '\0' && !isspace(*p
))
1512 debug("invalid PID \"%s\" (around '%c')", buf
, *p
);
1513 return kmDNSHelperRacoonNotificationFailed
;
1517 debug("refusing to kill PID %lu", m
);
1518 return kmDNSHelperRacoonNotificationFailed
;
1520 if (0 != kill(m
, RacoonSignal()))
1522 debug("Could not signal racoon (%lu): %s", m
, strerror(errno
));
1523 return kmDNSHelperRacoonNotificationFailed
;
1525 debug("Sent racoon (%lu) signal %d", m
, RacoonSignal());
1533 struct dirent entry
, *entryp
= NULL
;
1534 DIR *dirp
= opendir("/dev/fd");
1538 /* fall back to the erroneous getdtablesize method */
1539 for (fd
= from
; fd
< getdtablesize(); ++fd
)
1543 while (0 == readdir_r(dirp
, &entry
, &entryp
) && NULL
!= entryp
)
1545 fd
= atoi(entryp
->d_name
);
1546 if (fd
>= from
&& fd
!= dirfd(dirp
))
1553 startRacoonOld(void)
1556 char * const racoon_args
[] = { "/usr/sbin/racoon", "-e", NULL
};
1561 if (0 == (pid
= fork()))
1564 execve(racoon_args
[0], racoon_args
, NULL
);
1565 helplog(ASL_LEVEL_ERR
, "execve of \"%s\" failed: %s",
1566 racoon_args
[0], strerror(errno
));
1569 helplog(ASL_LEVEL_NOTICE
, "racoon (pid=%lu) started",
1570 (unsigned long)pid
);
1571 n
= waitpid(pid
, &status
, 0);
1574 helplog(ASL_LEVEL_ERR
, "Unexpected waitpid failure: %s",
1576 return kmDNSHelperRacoonStartFailed
;
1580 helplog(ASL_LEVEL_ERR
, "Unexpected waitpid return value %d",
1582 return kmDNSHelperRacoonStartFailed
;
1584 else if (WIFSIGNALED(status
))
1586 helplog(ASL_LEVEL_ERR
,
1587 "racoon (pid=%lu) terminated due to signal %d",
1588 (unsigned long)pid
, WTERMSIG(status
));
1589 return kmDNSHelperRacoonStartFailed
;
1591 else if (WIFSTOPPED(status
))
1593 helplog(ASL_LEVEL_ERR
,
1594 "racoon (pid=%lu) has stopped due to signal %d",
1595 (unsigned long)pid
, WSTOPSIG(status
));
1596 return kmDNSHelperRacoonStartFailed
;
1598 else if (0 != WEXITSTATUS(status
))
1600 helplog(ASL_LEVEL_ERR
,
1601 "racoon (pid=%lu) exited with status %d",
1602 (unsigned long)pid
, WEXITSTATUS(status
));
1603 return kmDNSHelperRacoonStartFailed
;
1605 debug("racoon (pid=%lu) daemonized normally", (unsigned long)pid
);
1609 // constant and structure for the racoon control socket
1610 #define VPNCTL_CMD_PING 0x0004
1611 typedef struct vpnctl_hdr_struct
1625 int fd
= socket(PF_UNIX
, SOCK_STREAM
, 0);
1628 helplog(ASL_LEVEL_ERR
, "Could not create endpoint for racoon control socket: %d %s",
1629 errno
, strerror(errno
));
1630 return kmDNSHelperRacoonStartFailed
;
1633 struct sockaddr_un saddr
;
1634 memset(&saddr
, 0, sizeof(saddr
));
1635 saddr
.sun_family
= AF_UNIX
;
1636 saddr
.sun_len
= sizeof(saddr
);
1637 static const char racoon_control_sock_path
[] = "/var/run/vpncontrol.sock";
1638 strcpy(saddr
.sun_path
, racoon_control_sock_path
);
1639 int result
= connect(fd
, (struct sockaddr
*) &saddr
, saddr
.sun_len
);
1642 helplog(ASL_LEVEL_ERR
, "Could not connect racoon control socket %s: %d %s",
1643 racoon_control_sock_path
, errno
, strerror(errno
));
1644 return kmDNSHelperRacoonStartFailed
;
1647 u_int32_t btmm_cookie
= 0x4d4d5442;
1648 vpnctl_hdr h
= { VPNCTL_CMD_PING
, 0, btmm_cookie
, 0, 0, 0 };
1652 while (bytes
< sizeof(vpnctl_hdr
))
1654 ret
= write(fd
, ((unsigned char*)&h
)+bytes
, sizeof(vpnctl_hdr
) - bytes
);
1657 helplog(ASL_LEVEL_ERR
, "Could not write to racoon control socket: %d %s",
1658 errno
, strerror(errno
));
1659 return kmDNSHelperRacoonStartFailed
;
1671 for (counter
= 0; counter
< 100; counter
++)
1675 tv
= (struct timeval
){ 0, 10000 }; // 10 milliseconds * 100 iterations = 1 second max wait time
1677 result
= select(nfds
, &fds
, (fd_set
*)NULL
, (fd_set
*)NULL
, &tv
);
1680 if (FD_ISSET(fd
, &fds
))
1682 ret
= read(fd
, ((unsigned char*)&h
)+bytes
, sizeof(vpnctl_hdr
) - bytes
);
1686 helplog(ASL_LEVEL_ERR
, "Could not read from racoon control socket: %d %s",
1691 if (bytes
>= sizeof(vpnctl_hdr
)) break;
1695 debug("select returned but fd_isset not on expected fd\n");
1698 else if (result
< 0)
1700 debug("select returned %d errno %d %s\n", result
, errno
, strerror(errno
));
1701 if (errno
!= EINTR
) break;
1707 if (bytes
< sizeof(vpnctl_hdr
) || h
.cookie
!= btmm_cookie
) return kmDNSHelperRacoonStartFailed
;
1709 debug("racoon started");
1716 if ( 0 == notifyRacoon() )
1718 return UseOldRacoon() ? startRacoonOld() : startRacoon();
1721 #endif /* ndef MDNS_NO_IPSEC */
1724 do_mDNSConfigureServer(__unused mach_port_t port
, int updown
, const char *fqdn
, audit_token_t token
)
1726 #ifndef MDNS_NO_IPSEC
1728 if (!authorized(&token
)) goto fin
;
1730 switch ((enum mDNSUpDown
)updown
)
1733 if (0 != createAnonymousRacoonConfiguration(fqdn
)) goto fin
;
1736 revertAnonymousRacoonConfiguration(GetOldRacoonConfigDir());
1737 revertAnonymousRacoonConfiguration(GetRacoonConfigDir());
1743 if (0 != kickRacoon())
1749 (void)port
; (void)updown
; (void)fqdn
; (void)token
;
1751 update_idle_timer();
1752 return KERN_SUCCESS
;
1755 #ifndef MDNS_NO_IPSEC
1757 static unsigned int routeSeq
= 1;
1760 setupTunnelRoute(v6addr_t local
, v6addr_t remote
)
1764 struct rt_msghdr hdr
;
1765 struct sockaddr_in6 dst
;
1766 struct sockaddr_in6 gtwy
;
1771 if (0 > (s
= socket(PF_ROUTE
, SOCK_RAW
, AF_INET
)))
1773 helplog(ASL_LEVEL_ERR
, "socket(PF_ROUTE, ...) failed: %s",
1775 err
= kmDNSHelperRoutingSocketCreationFailed
;
1778 memset(&msg
, 0, sizeof(msg
));
1779 msg
.hdr
.rtm_msglen
= sizeof(msg
);
1780 msg
.hdr
.rtm_type
= RTM_ADD
;
1781 /* The following flags are set by `route add -inet6 -host ...` */
1782 msg
.hdr
.rtm_flags
= RTF_UP
| RTF_GATEWAY
| RTF_HOST
| RTF_STATIC
;
1783 msg
.hdr
.rtm_version
= RTM_VERSION
;
1784 msg
.hdr
.rtm_seq
= routeSeq
++;
1785 msg
.hdr
.rtm_addrs
= RTA_DST
| RTA_GATEWAY
;
1786 msg
.hdr
.rtm_inits
= RTV_MTU
;
1787 msg
.hdr
.rtm_rmx
.rmx_mtu
= 1280;
1789 msg
.dst
.sin6_len
= sizeof(msg
.dst
);
1790 msg
.dst
.sin6_family
= AF_INET6
;
1791 memcpy(&msg
.dst
.sin6_addr
, remote
, sizeof(msg
.dst
.sin6_addr
));
1793 msg
.gtwy
.sin6_len
= sizeof(msg
.gtwy
);
1794 msg
.gtwy
.sin6_family
= AF_INET6
;
1795 memcpy(&msg
.gtwy
.sin6_addr
, local
, sizeof(msg
.gtwy
.sin6_addr
));
1797 /* send message, ignore error when route already exists */
1798 if (0 > write(s
, &msg
, msg
.hdr
.rtm_msglen
))
1802 debug("write to routing socket failed: %s", strerror(errno_
));
1803 if (EEXIST
!= errno_
)
1805 err
= kmDNSHelperRouteAdditionFailed
;
1817 teardownTunnelRoute(v6addr_t remote
)
1821 struct rt_msghdr hdr
;
1822 struct sockaddr_in6 dst
;
1827 if (0 > (s
= socket(PF_ROUTE
, SOCK_RAW
, AF_INET
)))
1829 helplog(ASL_LEVEL_ERR
, "socket(PF_ROUTE, ...) failed: %s",
1831 err
= kmDNSHelperRoutingSocketCreationFailed
;
1834 memset(&msg
, 0, sizeof(msg
));
1836 msg
.hdr
.rtm_msglen
= sizeof(msg
);
1837 msg
.hdr
.rtm_type
= RTM_DELETE
;
1838 msg
.hdr
.rtm_version
= RTM_VERSION
;
1839 msg
.hdr
.rtm_seq
= routeSeq
++;
1840 msg
.hdr
.rtm_addrs
= RTA_DST
;
1842 msg
.dst
.sin6_len
= sizeof(msg
.dst
);
1843 msg
.dst
.sin6_family
= AF_INET6
;
1844 memcpy(&msg
.dst
.sin6_addr
, remote
, sizeof(msg
.dst
.sin6_addr
));
1845 if (0 > write(s
, &msg
, msg
.hdr
.rtm_msglen
))
1849 debug("write to routing socket failed: %s", strerror(errno_
));
1850 if (ESRCH
!= errno_
)
1852 err
= kmDNSHelperRouteDeletionFailed
;
1864 v4addr_to_string(v4addr_t addr
, char *buf
, size_t buflen
)
1866 if (NULL
== inet_ntop(AF_INET
, addr
, buf
, buflen
))
1868 helplog(ASL_LEVEL_ERR
, "inet_ntop failed: %s",
1870 return kmDNSHelperInvalidNetworkAddress
;
1877 v6addr_to_string(v6addr_t addr
, char *buf
, size_t buflen
)
1879 if (NULL
== inet_ntop(AF_INET6
, addr
, buf
, buflen
))
1881 helplog(ASL_LEVEL_ERR
, "inet_ntop failed: %s",
1883 return kmDNSHelperInvalidNetworkAddress
;
1889 /* Caller owns object returned in `policy' */
1891 generateTunnelPolicy(mDNSTunnelPolicyWhich which
, mDNSTunnelType type
, int in
,
1892 v4addr_t src
, uint16_t src_port
,
1893 v4addr_t dst
, uint16_t dst_port
,
1894 v6addr_t src6
, v6addr_t dst6
,
1895 ipsec_policy_t
*policy
, size_t *len
)
1897 char srcs
[INET_ADDRSTRLEN
], dsts
[INET_ADDRSTRLEN
];
1898 char srcs6
[INET6_ADDRSTRLEN
], dsts6
[INET6_ADDRSTRLEN
];
1900 char *inOut
= in
? "in" : "out";
1909 case kmDNSTunnelPolicySetup
:
1910 if (type
== kmDNSIPv6IPv4Tunnel
)
1912 if (0 != (err
= v4addr_to_string(src
, srcs
, sizeof(srcs
))))
1914 if (0 != (err
= v4addr_to_string(dst
, dsts
, sizeof(dsts
))))
1916 n
= snprintf(buf
, sizeof(buf
),
1917 "%s ipsec esp/tunnel/%s[%u]-%s[%u]/require",
1918 inOut
, srcs
, src_port
, dsts
, dst_port
);
1920 else if (type
== kmDNSIPv6IPv6Tunnel
)
1922 if (0 != (err
= v6addr_to_string(src6
, srcs6
, sizeof(srcs6
))))
1924 if (0 != (err
= v6addr_to_string(dst6
, dsts6
, sizeof(dsts6
))))
1926 n
= snprintf(buf
, sizeof(buf
),
1927 "%s ipsec esp/tunnel/%s-%s/require",
1928 inOut
, srcs6
, dsts6
);
1931 case kmDNSTunnelPolicyTeardown
:
1932 n
= strlcpy(buf
, inOut
, sizeof(buf
));
1934 case kmDNSTunnelPolicyGenerate
:
1935 n
= snprintf(buf
, sizeof(buf
), "%s generate", inOut
);
1938 err
= kmDNSHelperIPsecPolicyCreationFailed
;
1942 if (n
>= (int)sizeof(buf
))
1944 err
= kmDNSHelperResultTooLarge
;
1948 debug("policy=\"%s\"", buf
);
1949 if (NULL
== (*policy
= (ipsec_policy_t
)ipsec_set_policy(buf
, n
)))
1951 helplog(ASL_LEVEL_ERR
,
1952 "Could not create IPsec policy from \"%s\"", buf
);
1953 err
= kmDNSHelperIPsecPolicyCreationFailed
;
1956 *len
= ((ipsec_policy_t
)(*policy
))->sadb_x_policy_len
* 8;
1963 sendPolicy(int s
, int setup
,
1964 struct sockaddr
*src
, uint8_t src_bits
,
1965 struct sockaddr
*dst
, uint8_t dst_bits
,
1966 ipsec_policy_t policy
, size_t len
)
1968 static unsigned int policySeq
= 0;
1971 debug("entry, setup=%d", setup
);
1973 err
= pfkey_send_spdadd(s
, src
, src_bits
, dst
, dst_bits
, -1,
1974 (char *)policy
, len
, policySeq
++);
1976 err
= pfkey_send_spddelete(s
, src
, src_bits
, dst
, dst_bits
, -1,
1977 (char *)policy
, len
, policySeq
++);
1980 helplog(ASL_LEVEL_ERR
, "Could not set IPsec policy: %s",
1982 err
= kmDNSHelperIPsecPolicySetFailed
;
1994 removeSA(int s
, struct sockaddr
*src
, struct sockaddr
*dst
)
1999 err
= pfkey_send_delete_all(s
, SADB_SATYPE_ESP
, IPSEC_MODE_ANY
, src
, dst
);
2002 helplog(ASL_LEVEL_ERR
, "Could not remove IPsec SA: %s", ipsec_strerror());
2003 err
= kmDNSHelperIPsecRemoveSAFailed
;
2006 err
= pfkey_send_delete_all(s
, SADB_SATYPE_ESP
, IPSEC_MODE_ANY
, dst
, src
);
2009 helplog(ASL_LEVEL_ERR
, "Could not remove IPsec SA: %s", ipsec_strerror());
2010 err
= kmDNSHelperIPsecRemoveSAFailed
;
2023 doTunnelPolicy(mDNSTunnelPolicyWhich which
, mDNSTunnelType type
,
2024 v6addr_t loc_inner
, uint8_t loc_bits
,
2025 v4addr_t loc_outer
, uint16_t loc_port
,
2026 v6addr_t rmt_inner
, uint8_t rmt_bits
,
2027 v4addr_t rmt_outer
, uint16_t rmt_port
,
2028 v6addr_t loc_outer6
, v6addr_t rmt_outer6
)
2030 struct sockaddr_in6 sin6_loc
;
2031 struct sockaddr_in6 sin6_rmt
;
2032 ipsec_policy_t policy
= NULL
;
2038 if (0 > (s
= pfkey_open()))
2040 helplog(ASL_LEVEL_ERR
,
2041 "Could not create IPsec policy socket: %s",
2043 err
= kmDNSHelperIPsecPolicySocketCreationFailed
;
2047 memset(&sin6_loc
, 0, sizeof(sin6_loc
));
2048 sin6_loc
.sin6_len
= sizeof(sin6_loc
);
2049 sin6_loc
.sin6_family
= AF_INET6
;
2050 sin6_loc
.sin6_port
= htons(0);
2051 memcpy(&sin6_loc
.sin6_addr
, loc_inner
, sizeof(sin6_loc
.sin6_addr
));
2053 memset(&sin6_rmt
, 0, sizeof(sin6_rmt
));
2054 sin6_rmt
.sin6_len
= sizeof(sin6_rmt
);
2055 sin6_rmt
.sin6_family
= AF_INET6
;
2056 sin6_rmt
.sin6_port
= htons(0);
2057 memcpy(&sin6_rmt
.sin6_addr
, rmt_inner
, sizeof(sin6_rmt
.sin6_addr
));
2059 int setup
= which
!= kmDNSTunnelPolicyTeardown
;
2061 if (0 != (err
= generateTunnelPolicy(which
, type
, 1,
2062 rmt_outer
, rmt_port
,
2063 loc_outer
, loc_port
,
2064 rmt_outer6
, loc_outer6
,
2067 if (0 != (err
= sendPolicy(s
, setup
,
2068 (struct sockaddr
*)&sin6_rmt
, rmt_bits
,
2069 (struct sockaddr
*)&sin6_loc
, loc_bits
,
2077 if (0 != (err
= generateTunnelPolicy(which
, type
, 0,
2078 loc_outer
, loc_port
,
2079 rmt_outer
, rmt_port
,
2080 loc_outer6
, rmt_outer6
,
2083 if (0 != (err
= sendPolicy(s
, setup
,
2084 (struct sockaddr
*)&sin6_loc
, loc_bits
,
2085 (struct sockaddr
*)&sin6_rmt
, rmt_bits
,
2089 if (which
== kmDNSTunnelPolicyTeardown
)
2091 if (rmt_port
) // Outer tunnel is IPv4
2093 if (loc_outer
&& rmt_outer
)
2095 struct sockaddr_in sin_loc
;
2096 struct sockaddr_in sin_rmt
;
2097 memset(&sin_loc
, 0, sizeof(sin_loc
));
2098 sin_loc
.sin_len
= sizeof(sin_loc
);
2099 sin_loc
.sin_family
= AF_INET
;
2100 memcpy(&sin_loc
.sin_addr
, loc_outer
, sizeof(sin_loc
.sin_addr
));
2102 memset(&sin_rmt
, 0, sizeof(sin_rmt
));
2103 sin_rmt
.sin_len
= sizeof(sin_rmt
);
2104 sin_rmt
.sin_family
= AF_INET
;
2105 memcpy(&sin_rmt
.sin_addr
, rmt_outer
, sizeof(sin_rmt
.sin_addr
));
2106 if (0 != (err
= removeSA(s
, (struct sockaddr
*)&sin_loc
, (struct sockaddr
*)&sin_rmt
)))
2112 if (loc_outer6
&& rmt_outer6
)
2114 struct sockaddr_in6 sin6_lo
;
2115 struct sockaddr_in6 sin6_rm
;
2117 memset(&sin6_lo
, 0, sizeof(sin6_lo
));
2118 sin6_lo
.sin6_len
= sizeof(sin6_lo
);
2119 sin6_lo
.sin6_family
= AF_INET6
;
2120 memcpy(&sin6_lo
.sin6_addr
, loc_outer6
, sizeof(sin6_lo
.sin6_addr
));
2122 memset(&sin6_rm
, 0, sizeof(sin6_rm
));
2123 sin6_rm
.sin6_len
= sizeof(sin6_rm
);
2124 sin6_rm
.sin6_family
= AF_INET6
;
2125 memcpy(&sin6_rm
.sin6_addr
, rmt_outer6
, sizeof(sin6_rm
.sin6_addr
));
2126 if (0 != (err
= removeSA(s
, (struct sockaddr
*)&sin6_lo
, (struct sockaddr
*)&sin6_rm
)))
2143 #endif /* ndef MDNS_NO_IPSEC */
2146 do_mDNSAutoTunnelSetKeys(__unused mach_port_t port
, int replacedelete
,
2147 v6addr_t loc_inner
, v6addr_t loc_outer6
, uint16_t loc_port
,
2148 v6addr_t rmt_inner
, v6addr_t rmt_outer6
, uint16_t rmt_port
,
2149 const char *fqdn
, int *err
, audit_token_t token
)
2151 #ifndef MDNS_NO_IPSEC
2152 static const char config
[] =
2154 "remote %s [%u] {\n"
2155 " disconnect_on_idle idle_timeout 600 idle_direction idle_outbound;\n"
2156 " exchange_mode aggressive;\n"
2158 " situation identity_only;\n"
2159 " verify_identifier off;\n"
2160 " generate_policy on;\n"
2161 " my_identifier user_fqdn \"dns:%s\";\n"
2162 " shared_secret keychain \"dns:%s\";\n"
2164 " lifetime time 15 min;\n"
2165 " initial_contact on;\n"
2166 " support_proxy on;\n"
2167 " nat_traversal force;\n"
2168 " proposal_check claim;\n"
2170 " encryption_algorithm aes;\n"
2171 " hash_algorithm sha1;\n"
2172 " authentication_method pre_shared_key;\n"
2174 " lifetime time 15 min;\n"
2177 "sainfo address %s any address %s any {\n"
2179 " lifetime time 10 min;\n"
2180 " encryption_algorithm aes;\n"
2181 " authentication_algorithm hmac_sha1;\n"
2182 " compression_algorithm deflate;\n"
2184 "sainfo address %s any address %s any {\n"
2186 " lifetime time 10 min;\n"
2187 " encryption_algorithm aes;\n"
2188 " authentication_algorithm hmac_sha1;\n"
2189 " compression_algorithm deflate;\n"
2191 char path
[PATH_MAX
] = "";
2192 char li
[INET6_ADDRSTRLEN
], lo
[INET_ADDRSTRLEN
], lo6
[INET6_ADDRSTRLEN
],
2193 ri
[INET6_ADDRSTRLEN
], ro
[INET_ADDRSTRLEN
], ro6
[INET6_ADDRSTRLEN
];
2196 char tmp_path
[PATH_MAX
] = "";
2197 v4addr_t loc_outer
, rmt_outer
;
2201 if (!authorized(&token
))
2203 *err
= kmDNSHelperNotAuthorized
;
2206 switch ((enum mDNSAutoTunnelSetKeysReplaceDelete
)replacedelete
)
2208 case kmDNSAutoTunnelSetKeysReplace
:
2209 case kmDNSAutoTunnelSetKeysDelete
:
2212 *err
= kmDNSHelperInvalidTunnelSetKeysOperation
;
2216 if (0 != (*err
= v6addr_to_string(loc_inner
, li
, sizeof(li
))))
2218 if (0 != (*err
= v6addr_to_string(rmt_inner
, ri
, sizeof(ri
))))
2221 debug("loc_inner=%s rmt_inner=%s", li
, ri
);
2224 loc_outer
[0] = loc_outer
[1] = loc_outer
[2] = loc_outer
[3] = 0;
2225 rmt_outer
[0] = rmt_outer
[1] = rmt_outer
[2] = rmt_outer
[3] = 0;
2227 if (0 != (*err
= v6addr_to_string(loc_outer6
, lo6
, sizeof(lo6
))))
2229 if (0 != (*err
= v6addr_to_string(rmt_outer6
, ro6
, sizeof(ro6
))))
2231 debug("IPv6 outer tunnel: loc_outer6=%s rmt_outer6=%s", lo6
, ro6
);
2232 if ((int)sizeof(path
) <= snprintf(path
, sizeof(path
),
2233 "%s%s.conf", GetRacoonConfigDir(), ro6
))
2235 *err
= kmDNSHelperResultTooLarge
;
2241 loc_outer
[0] = loc_outer6
[0];
2242 loc_outer
[1] = loc_outer6
[1];
2243 loc_outer
[2] = loc_outer6
[2];
2244 loc_outer
[3] = loc_outer6
[3];
2246 rmt_outer
[0] = rmt_outer6
[0];
2247 rmt_outer
[1] = rmt_outer6
[1];
2248 rmt_outer
[2] = rmt_outer6
[2];
2249 rmt_outer
[3] = rmt_outer6
[3];
2251 if (0 != (*err
= v4addr_to_string(loc_outer
, lo
, sizeof(lo
))))
2253 if (0 != (*err
= v4addr_to_string(rmt_outer
, ro
, sizeof(ro
))))
2255 debug("IPv4 outer tunnel: loc_outer=%s loc_port=%u rmt_outer=%s rmt_port=%u",
2256 lo
, loc_port
, ro
, rmt_port
);
2258 if ((int)sizeof(path
) <= snprintf(path
, sizeof(path
),
2259 "%s%s.%u.conf", GetRacoonConfigDir(), ro
,
2262 *err
= kmDNSHelperResultTooLarge
;
2269 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
)
2271 if (0 > ensureExistenceOfRacoonConfigDir(GetRacoonConfigDir()))
2273 *err
= kmDNSHelperRacoonConfigCreationFailed
;
2276 if ((int)sizeof(tmp_path
) <=
2277 snprintf(tmp_path
, sizeof(tmp_path
), "%s.XXXXXX", path
))
2279 *err
= kmDNSHelperResultTooLarge
;
2282 if (0 > (fd
= mkstemp(tmp_path
)))
2284 helplog(ASL_LEVEL_ERR
, "mkstemp \"%s\" failed: %s",
2285 tmp_path
, strerror(errno
));
2286 *err
= kmDNSHelperRacoonConfigCreationFailed
;
2289 if (NULL
== (fp
= fdopen(fd
, "w")))
2291 helplog(ASL_LEVEL_ERR
, "fdopen: %s",
2293 *err
= kmDNSHelperRacoonConfigCreationFailed
;
2297 fprintf(fp
, config
, configHeader
, (!rmt_port
? ro6
: ro
), rmt_port
, fqdn
, fqdn
, ri
, li
, li
, ri
);
2300 if (0 > rename(tmp_path
, path
))
2302 helplog(ASL_LEVEL_ERR
,
2303 "rename \"%s\" \"%s\" failed: %s",
2304 tmp_path
, path
, strerror(errno
));
2305 *err
= kmDNSHelperRacoonConfigCreationFailed
;
2311 if (0 != unlink(path
))
2312 debug("unlink \"%s\" failed: %s", path
,
2316 if (0 != (*err
= doTunnelPolicy(kmDNSTunnelPolicyTeardown
, kmDNSNoTunnel
,
2317 loc_inner
, kWholeV6Mask
, loc_outer
, loc_port
,
2318 rmt_inner
, kWholeV6Mask
, rmt_outer
, rmt_port
, loc_outer6
, rmt_outer6
)))
2320 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
&&
2321 0 != (*err
= doTunnelPolicy(kmDNSTunnelPolicySetup
, (!rmt_port
? kmDNSIPv6IPv6Tunnel
: kmDNSIPv6IPv4Tunnel
),
2322 loc_inner
, kWholeV6Mask
, loc_outer
, loc_port
,
2323 rmt_inner
, kWholeV6Mask
, rmt_outer
, rmt_port
, loc_outer6
, rmt_outer6
)))
2326 if (0 != (*err
= teardownTunnelRoute(rmt_inner
)))
2328 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
&&
2329 0 != (*err
= setupTunnelRoute(loc_inner
, rmt_inner
)))
2332 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
&&
2333 0 != (*err
= kickRacoon()))
2345 (void)replacedelete
; (void)loc_inner
; (void)loc_outer6
; (void)loc_port
; (void)rmt_inner
;
2346 (void)rmt_outer6
; (void)rmt_port
; (void)fqdn
; (void)token
;
2348 *err
= kmDNSHelperIPsecDisabled
;
2349 #endif /* MDNS_NO_IPSEC */
2350 update_idle_timer();
2351 return KERN_SUCCESS
;
2355 do_mDNSSendWakeupPacket(__unused mach_port_t port
, unsigned ifid
, const char *eth_addr
, const char *ip_addr
, int iteration
, audit_token_t token
)
2359 char ifname
[IFNAMSIZ
];
2362 char bpf_device
[12];
2363 struct ether_addr
*ea
;
2364 (void) ip_addr
; // unused
2365 (void) iteration
; // unused
2366 (void) token
; // unused
2368 if (if_indextoname(ifid
, ifname
) == NULL
)
2370 helplog(ASL_LEVEL_ERR
, "do_mDNSSendWakeupPacket invalid interface index %u", ifid
);
2374 ea
= ether_aton(eth_addr
);
2377 helplog(ASL_LEVEL_ERR
, "do_mDNSSendWakeupPacket invalid ethernet address %s", eth_addr
);
2381 for (i
= 0; i
< 100; i
++)
2383 snprintf(bpf_device
, sizeof(bpf_device
), "/dev/bpf%d", i
);
2384 bpf_fd
= open(bpf_device
, O_RDWR
, 0);
2392 helplog(ASL_LEVEL_ERR
, "do_mDNSSendWakeupPacket cannot find a bpf device");
2396 memset(&ifr
, 0, sizeof(ifr
));
2397 strlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
2399 if (ioctl(bpf_fd
, BIOCSETIF
, (char *)&ifr
) < 0)
2401 helplog(ASL_LEVEL_ERR
, "do_mDNSSendWakeupPacket BIOCSETIF failed %s", strerror(errno
));
2405 // 0x00 Destination address
2406 for (i
=0; i
<6; i
++) *ptr
++ = ea
->octet
[i
];
2408 // 0x06 Source address (Note: Since we don't currently set the BIOCSHDRCMPLT option, BPF will fill in the real interface address for us)
2409 for (i
=0; i
<6; i
++) *ptr
++ = 0;
2411 // 0x0C Ethertype (0x0842)
2415 // 0x0E Wakeup sync sequence
2416 for (i
=0; i
<6; i
++) *ptr
++ = 0xFF;
2419 for (j
=0; j
<16; j
++) for (i
=0; i
<6; i
++) *ptr
++ = ea
->octet
[i
];
2422 for (i
=0; i
<6; i
++) *ptr
++ = 0;
2424 if (write(bpf_fd
, packet
, ptr
- packet
) < 0)
2426 helplog(ASL_LEVEL_ERR
, "do_mDNSSendWakeupPacket write failed %s", strerror(errno
));
2429 helplog(ASL_LEVEL_INFO
, "do_mDNSSendWakeupPacket sent unicast eth_addr %s, ip_addr %s", eth_addr
, ip_addr
);
2430 // Send a broadcast one to handle ethernet switches that don't flood forward packets with
2431 // unknown mac addresses.
2432 for (i
=0; i
<6; i
++) packet
[i
] = 0xFF;
2433 if (write(bpf_fd
, packet
, ptr
- packet
) < 0)
2435 helplog(ASL_LEVEL_ERR
, "do_mDNSSendWakeupPacket write failed %s", strerror(errno
));
2438 helplog(ASL_LEVEL_INFO
, "do_mDNSSendWakeupPacket sent broadcast eth_addr %s, ip_addr %s", eth_addr
, ip_addr
);
2440 return KERN_SUCCESS
;