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"
60 #include "P2PPacketFilter.h"
63 #define RTF_IFSCOPE 0x1000000
66 #if TARGET_OS_EMBEDDED
68 #define MDNS_NO_IPSEC 1
70 #define NO_CFUSERNOTIFICATION 1
71 #define NO_SECURITYFRAMEWORK 1
74 // Embed the client stub code here, so we can access private functions like ConnectToServer, create_hdr, deliver_request
75 #include "../mDNSShared/dnssd_ipc.c"
76 #include "../mDNSShared/dnssd_clientstub.c"
78 typedef struct sadb_x_policy
*ipsec_policy_t
;
80 uid_t mDNSResponderUID
;
81 gid_t mDNSResponderGID
;
82 static const char kTunnelAddressInterface
[] = "lo0";
85 debug_(const char *func
, const char *fmt
, ...)
91 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
93 helplog(ASL_LEVEL_DEBUG
, "%s: %s", func
, buf
);
97 authorized(audit_token_t
*token
)
100 pid_t pid
= (pid_t
)-1;
101 uid_t euid
= (uid_t
)-1;
103 audit_token_to_au32(*token
, NULL
, &euid
, NULL
, NULL
, NULL
, &pid
, NULL
,
105 ok
= (euid
== mDNSResponderUID
|| euid
== 0);
107 helplog(ASL_LEVEL_NOTICE
,
108 "Unauthorized access by euid=%lu pid=%lu",
109 (unsigned long)euid
, (unsigned long)pid
);
114 do_mDNSExit(__unused mach_port_t port
, audit_token_t token
)
117 if (!authorized(&token
))
119 helplog(ASL_LEVEL_INFO
, "exit");
127 kern_return_t
do_mDNSRequestBPF(__unused mach_port_t port
, audit_token_t token
)
129 if (!authorized(&token
)) return KERN_SUCCESS
;
131 DNSServiceErrorType err
= ConnectToServer(&ref
, 0, send_bpf
, NULL
, NULL
, NULL
);
132 if (err
) { helplog(ASL_LEVEL_ERR
, "do_mDNSRequestBPF: ConnectToServer %d", err
); return err
; }
135 size_t len
= sizeof(DNSServiceFlags
);
136 ipc_msg_hdr
*hdr
= create_hdr(send_bpf
, &len
, &ptr
, 0, ref
);
137 if (!hdr
) { DNSServiceRefDeallocate(ref
); return kDNSServiceErr_NoMemory
; }
139 deliver_request(hdr
, ref
); // Will free hdr for us
140 DNSServiceRefDeallocate(ref
);
145 kern_return_t
do_mDNSPowerRequest(__unused mach_port_t port
, int key
, int interval
, int *err
, audit_token_t token
)
148 if (!authorized(&token
)) { *err
= kmDNSHelperNotAuthorized
; goto fin
; }
150 CFArrayRef events
= IOPMCopyScheduledPowerEvents();
154 CFIndex count
= CFArrayGetCount(events
);
155 for (i
=0; i
<count
; i
++)
157 CFDictionaryRef dict
= CFArrayGetValueAtIndex(events
, i
);
158 CFStringRef id
= CFDictionaryGetValue(dict
, CFSTR(kIOPMPowerEventAppNameKey
));
159 if (CFEqual(id
, CFSTR("mDNSResponderHelper")))
161 CFDateRef EventTime
= CFDictionaryGetValue(dict
, CFSTR(kIOPMPowerEventTimeKey
));
162 CFStringRef EventType
= CFDictionaryGetValue(dict
, CFSTR(kIOPMPowerEventTypeKey
));
163 IOReturn result
= IOPMCancelScheduledPowerEvent(EventTime
, id
, EventType
);
164 //helplog(ASL_LEVEL_ERR, "Deleting old event %s");
165 if (result
) helplog(ASL_LEVEL_ERR
, "IOPMCancelScheduledPowerEvent %d failed %d", i
, result
);
171 if (key
< 0) // mDNSPowerRequest(-1,-1) means "clear any stale schedules" (see above)
173 else if (key
== 0) // mDNSPowerRequest(0, 0) means "sleep now"
175 IOReturn r
= IOPMSleepSystem(IOPMFindPowerManagement(MACH_PORT_NULL
));
176 if (r
) { usleep(100000); helplog(ASL_LEVEL_ERR
, "IOPMSleepSystem %d", r
); }
181 CFDateRef w
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent() + interval
);
184 IOReturn r
= IOPMSchedulePowerEvent(w
, CFSTR("mDNSResponderHelper"), key
? CFSTR(kIOPMAutoWake
) : CFSTR(kIOPMAutoSleep
));
185 if (r
) { usleep(100000); helplog(ASL_LEVEL_ERR
, "IOPMSchedulePowerEvent(%d) %d %x", interval
, r
, r
); }
195 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
)
197 #define IPv6FMTSTRING "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X"
198 #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]
201 helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry %d IPv%d %d.%d.%d.%d %02X:%02X:%02X:%02X:%02X:%02X",
202 ifindex
, family
, ip
[0], ip
[1], ip
[2], ip
[3], eth
[0], eth
[1], eth
[2], eth
[3], eth
[4], eth
[5]);
204 helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry %d IPv%d " IPv6FMTSTRING
" %02X:%02X:%02X:%02X:%02X:%02X",
205 ifindex
, family
, IPv6FMTARGS
, eth
[0], eth
[1], eth
[2], eth
[3], eth
[4], eth
[5]);
209 if (!authorized(&token
)) { *err
= kmDNSHelperNotAuthorized
; goto fin
; }
211 static int s
= -1, seq
= 0;
214 s
= socket(PF_ROUTE
, SOCK_RAW
, 0);
215 if (s
< 0) helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry: socket(PF_ROUTE, SOCK_RAW, 0) failed %d (%s)", errno
, strerror(errno
));
221 gettimeofday(&tv
, 0);
224 struct { struct rt_msghdr hdr
; struct sockaddr_inarp dst
; struct sockaddr_dl sdl
; } rtmsg
;
225 memset(&rtmsg
, 0, sizeof(rtmsg
));
227 rtmsg
.hdr
.rtm_msglen
= sizeof(rtmsg
);
228 rtmsg
.hdr
.rtm_version
= RTM_VERSION
;
229 rtmsg
.hdr
.rtm_type
= RTM_ADD
;
230 rtmsg
.hdr
.rtm_index
= ifindex
;
231 rtmsg
.hdr
.rtm_flags
= RTF_HOST
| RTF_STATIC
| RTF_IFSCOPE
;
232 rtmsg
.hdr
.rtm_addrs
= RTA_DST
| RTA_GATEWAY
;
233 rtmsg
.hdr
.rtm_pid
= 0;
234 rtmsg
.hdr
.rtm_seq
= seq
++;
235 rtmsg
.hdr
.rtm_errno
= 0;
236 rtmsg
.hdr
.rtm_use
= 0;
237 rtmsg
.hdr
.rtm_inits
= RTV_EXPIRE
;
238 rtmsg
.hdr
.rtm_rmx
.rmx_expire
= tv
.tv_sec
+ 30;
240 rtmsg
.dst
.sin_len
= sizeof(rtmsg
.dst
);
241 rtmsg
.dst
.sin_family
= AF_INET
;
242 rtmsg
.dst
.sin_port
= 0;
243 rtmsg
.dst
.sin_addr
.s_addr
= *(in_addr_t
*)ip
;
244 rtmsg
.dst
.sin_srcaddr
.s_addr
= 0;
245 rtmsg
.dst
.sin_tos
= 0;
246 rtmsg
.dst
.sin_other
= 0;
248 rtmsg
.sdl
.sdl_len
= sizeof(rtmsg
.sdl
);
249 rtmsg
.sdl
.sdl_family
= AF_LINK
;
250 rtmsg
.sdl
.sdl_index
= ifindex
;
251 rtmsg
.sdl
.sdl_type
= IFT_ETHER
;
252 rtmsg
.sdl
.sdl_nlen
= 0;
253 rtmsg
.sdl
.sdl_alen
= ETHER_ADDR_LEN
;
254 rtmsg
.sdl
.sdl_slen
= 0;
256 // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h)
257 memcpy(rtmsg
.sdl
.sdl_data
, eth
, sizeof(ethaddr_t
));
259 int len
= write(s
, (char *)&rtmsg
, sizeof(rtmsg
));
261 helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry: write(%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s)",
262 sizeof(rtmsg
), ifindex
, ip
[0], ip
[1], ip
[2], ip
[3], rtmsg
.hdr
.rtm_seq
, len
, errno
, strerror(errno
));
263 len
= read(s
, (char *)&rtmsg
, sizeof(rtmsg
));
264 if (len
< 0 || rtmsg
.hdr
.rtm_errno
)
265 helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry: read (%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s) %d",
266 sizeof(rtmsg
), ifindex
, ip
[0], ip
[1], ip
[2], ip
[3], rtmsg
.hdr
.rtm_seq
, len
, errno
, strerror(errno
), rtmsg
.hdr
.rtm_errno
);
272 struct { struct rt_msghdr hdr
; struct sockaddr_in6 dst
; struct sockaddr_dl sdl
; } rtmsg
;
273 memset(&rtmsg
, 0, sizeof(rtmsg
));
275 rtmsg
.hdr
.rtm_msglen
= sizeof(rtmsg
);
276 rtmsg
.hdr
.rtm_version
= RTM_VERSION
;
277 rtmsg
.hdr
.rtm_type
= RTM_ADD
;
278 rtmsg
.hdr
.rtm_index
= ifindex
;
279 rtmsg
.hdr
.rtm_flags
= RTF_HOST
| RTF_STATIC
| RTF_IFSCOPE
;
280 rtmsg
.hdr
.rtm_addrs
= RTA_DST
| RTA_GATEWAY
;
281 rtmsg
.hdr
.rtm_pid
= 0;
282 rtmsg
.hdr
.rtm_seq
= seq
++;
283 rtmsg
.hdr
.rtm_errno
= 0;
284 rtmsg
.hdr
.rtm_use
= 0;
285 rtmsg
.hdr
.rtm_inits
= RTV_EXPIRE
;
286 rtmsg
.hdr
.rtm_rmx
.rmx_expire
= tv
.tv_sec
+ 30;
288 rtmsg
.dst
.sin6_len
= sizeof(rtmsg
.dst
);
289 rtmsg
.dst
.sin6_family
= AF_INET6
;
290 rtmsg
.dst
.sin6_port
= 0;
291 rtmsg
.dst
.sin6_flowinfo
= 0;
292 rtmsg
.dst
.sin6_addr
= *(struct in6_addr
*)ip
;
293 rtmsg
.dst
.sin6_scope_id
= ifindex
;
295 rtmsg
.sdl
.sdl_len
= sizeof(rtmsg
.sdl
);
296 rtmsg
.sdl
.sdl_family
= AF_LINK
;
297 rtmsg
.sdl
.sdl_index
= ifindex
;
298 rtmsg
.sdl
.sdl_type
= IFT_ETHER
;
299 rtmsg
.sdl
.sdl_nlen
= 0;
300 rtmsg
.sdl
.sdl_alen
= ETHER_ADDR_LEN
;
301 rtmsg
.sdl
.sdl_slen
= 0;
303 // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h)
304 memcpy(rtmsg
.sdl
.sdl_data
, eth
, sizeof(ethaddr_t
));
306 int len
= write(s
, (char *)&rtmsg
, sizeof(rtmsg
));
308 helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry: write(%d) interface %d address " IPv6FMTSTRING
" seq %d result %d errno %d (%s)",
309 sizeof(rtmsg
), ifindex
, IPv6FMTARGS
, rtmsg
.hdr
.rtm_seq
, len
, errno
, strerror(errno
));
310 len
= read(s
, (char *)&rtmsg
, sizeof(rtmsg
));
311 if (len
< 0 || rtmsg
.hdr
.rtm_errno
)
312 helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry: read (%d) interface %d address " IPv6FMTSTRING
" seq %d result %d errno %d (%s) %d",
313 sizeof(rtmsg
), ifindex
, IPv6FMTARGS
, rtmsg
.hdr
.rtm_seq
, len
, errno
, strerror(errno
), rtmsg
.hdr
.rtm_errno
);
325 kern_return_t
do_mDNSNotify(__unused mach_port_t port
, const char *title
, const char *msg
, audit_token_t token
)
327 if (!authorized(&token
)) return KERN_SUCCESS
;
329 #ifndef NO_CFUSERNOTIFICATION
330 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.)";
331 CFStringRef alertHeader
= CFStringCreateWithCString(NULL
, title
, kCFStringEncodingUTF8
);
332 CFStringRef alertBody
= CFStringCreateWithCString(NULL
, msg
, kCFStringEncodingUTF8
);
333 CFStringRef alertFooter
= CFStringCreateWithCString(NULL
, footer
, kCFStringEncodingUTF8
);
334 CFStringRef alertMessage
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@\r\r%@"), alertBody
, alertFooter
);
335 CFRelease(alertBody
);
336 CFRelease(alertFooter
);
337 int err
= CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel
, NULL
, NULL
, NULL
, alertHeader
, alertMessage
, NULL
);
338 if (err
) helplog(ASL_LEVEL_ERR
, "CFUserNotificationDisplayNotice returned %d", err
);
339 CFRelease(alertHeader
);
340 CFRelease(alertMessage
);
344 #endif /* NO_CFUSERNOTIFICATION */
351 do_mDNSDynamicStoreSetConfig(__unused mach_port_t port
, int key
,
352 const char* subkey
, vm_offset_t value
, mach_msg_type_number_t valueCnt
,
355 CFStringRef sckey
= NULL
;
356 Boolean release_sckey
= FALSE
;
357 CFDataRef bytes
= NULL
;
358 CFPropertyListRef plist
= NULL
;
359 SCDynamicStoreRef store
= NULL
;
362 if (!authorized(&token
)) goto fin
;
364 switch ((enum mDNSDynamicStoreSetConfigKey
)key
)
366 case kmDNSMulticastConfig
:
367 sckey
= CFSTR("State:/Network/" kDNSServiceCompMulticastDNS
);
369 case kmDNSDynamicConfig
:
370 sckey
= CFSTR("State:/Network/DynamicDNS");
372 case kmDNSPrivateConfig
:
373 sckey
= CFSTR("State:/Network/" kDNSServiceCompPrivateDNS
);
375 case kmDNSBackToMyMacConfig
:
376 sckey
= CFSTR("State:/Network/BackToMyMac");
378 case kmDNSSleepProxyServersState
:
380 CFMutableStringRef tmp
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
381 CFStringAppend(tmp
, CFSTR("State:/Network/Interface/"));
382 CFStringAppendCString(tmp
, subkey
, kCFStringEncodingUTF8
);
383 CFStringAppend(tmp
, CFSTR("/SleepProxyServers"));
384 sckey
= CFStringCreateCopy(kCFAllocatorDefault
, tmp
);
385 release_sckey
= TRUE
;
390 debug("unrecognized key %d", key
);
393 if (NULL
== (bytes
= CFDataCreateWithBytesNoCopy(NULL
, (void *)value
,
394 valueCnt
, kCFAllocatorNull
)))
396 debug("CFDataCreateWithBytesNoCopy of value failed");
399 if (NULL
== (plist
= CFPropertyListCreateFromXMLData(NULL
, bytes
,
400 kCFPropertyListImmutable
, NULL
)))
402 debug("CFPropertyListCreateFromXMLData of bytes failed");
407 if (NULL
== (store
= SCDynamicStoreCreate(NULL
,
408 CFSTR(kmDNSHelperServiceName
), NULL
, NULL
)))
410 debug("SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
413 SCDynamicStoreSetValue(store
, sckey
, plist
);
423 if (release_sckey
&& sckey
)
425 vm_deallocate(mach_task_self(), value
, valueCnt
);
430 char usercompname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last computer name the user saw
431 char userhostname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last local host name the user saw
432 char lastcompname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last computer name saved to preferences
433 char lasthostname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last local host name saved to preferences
435 #ifndef NO_CFUSERNOTIFICATION
436 static CFStringRef CFS_OQ
= NULL
;
437 static CFStringRef CFS_CQ
= NULL
;
438 static CFStringRef CFS_Format
= NULL
;
439 static CFStringRef CFS_ComputerName
= NULL
;
440 static CFStringRef CFS_ComputerNameMsg
= NULL
;
441 static CFStringRef CFS_LocalHostName
= NULL
;
442 static CFStringRef CFS_LocalHostNameMsg
= NULL
;
443 static CFStringRef CFS_Problem
= NULL
;
445 static CFUserNotificationRef gNotification
= NULL
;
446 static CFRunLoopSourceRef gNotificationRLS
= NULL
;
448 static void NotificationCallBackDismissed(CFUserNotificationRef userNotification
, CFOptionFlags responseFlags
)
451 (void)responseFlags
; // Unused
452 if (userNotification
!= gNotification
) helplog(ASL_LEVEL_ERR
, "NotificationCallBackDismissed: Wrong CFUserNotificationRef");
453 if (gNotificationRLS
)
455 // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
456 // We need to explicitly specify the desired CFRunLoop from which we want to remove this event source.
457 CFRunLoopRemoveSource(gRunLoop
, gNotificationRLS
, kCFRunLoopDefaultMode
);
458 CFRelease(gNotificationRLS
);
459 gNotificationRLS
= NULL
;
460 CFRelease(gNotification
);
461 gNotification
= NULL
;
463 // By dismissing the alert, the user has conceptually acknowleged the rename.
464 // (e.g. the machine's name is now officially "computer-2.local", not "computer.local".)
465 // If we get *another* conflict, the new alert should refer to the 'old' name
466 // as now being "computer-2.local", not "computer.local"
472 unpause_idle_timer();
475 static void ShowNameConflictNotification(CFMutableArrayRef header
, CFStringRef subtext
)
477 CFMutableDictionaryRef dictionary
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
478 if (!dictionary
) return;
482 CFDictionarySetValue(dictionary
, kCFUserNotificationAlertHeaderKey
, header
);
483 CFDictionarySetValue(dictionary
, kCFUserNotificationAlertMessageKey
, subtext
);
485 CFURLRef urlRef
= CFURLCreateWithFileSystemPath(NULL
, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle
, true);
486 if (urlRef
) { CFDictionarySetValue(dictionary
, kCFUserNotificationLocalizationURLKey
, urlRef
); CFRelease(urlRef
); }
488 if (gNotification
) // If notification already on-screen, update it in place
489 CFUserNotificationUpdate(gNotification
, 0, kCFUserNotificationCautionAlertLevel
, dictionary
);
490 else // else, we need to create it
493 gNotification
= CFUserNotificationCreate(NULL
, 0, kCFUserNotificationCautionAlertLevel
, &error
, dictionary
);
494 if (!gNotification
|| error
) { helplog(ASL_LEVEL_ERR
, "ShowNameConflictNotification: CFUserNotificationRef: Error %d", error
); return; }
495 gNotificationRLS
= CFUserNotificationCreateRunLoopSource(NULL
, gNotification
, NotificationCallBackDismissed
, 0);
496 if (!gNotificationRLS
) { helplog(ASL_LEVEL_ERR
,"ShowNameConflictNotification: RLS"); CFRelease(gNotification
); gNotification
= NULL
; return; }
497 // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
498 // We need to explicitly specify the desired CFRunLoop to which we want to add this event source.
499 CFRunLoopAddSource(gRunLoop
, gNotificationRLS
, kCFRunLoopDefaultMode
);
500 debug("gRunLoop=%p gNotification=%p gNotificationRLS=%p", gRunLoop
, gNotification
, gNotificationRLS
);
504 CFRelease(dictionary
);
507 static CFMutableArrayRef
GetHeader(const char* oldname
, const char* newname
, const CFStringRef msg
, const char* suffix
)
509 CFMutableArrayRef alertHeader
= NULL
;
511 const CFStringRef cfoldname
= CFStringCreateWithCString(NULL
, oldname
, kCFStringEncodingUTF8
);
512 // NULL newname means we've given up trying to construct a name that doesn't conflict
513 const CFStringRef cfnewname
= newname
? CFStringCreateWithCString(NULL
, newname
, kCFStringEncodingUTF8
) : NULL
;
514 // We tag a zero-width non-breaking space at the end of the literal text to guarantee that, no matter what
515 // arbitrary computer name the user may choose, this exact text (with zero-width non-breaking space added)
516 // can never be one that occurs in the Localizable.strings translation file.
518 helplog(ASL_LEVEL_ERR
,"Could not construct CFStrings for old=%s", newname
);
519 else if (newname
&& !cfnewname
)
520 helplog(ASL_LEVEL_ERR
,"Could not construct CFStrings for new=%s", newname
);
523 const CFStringRef s1
= CFStringCreateWithFormat(NULL
, NULL
, CFS_Format
, cfoldname
, suffix
);
524 const CFStringRef s2
= cfnewname
? CFStringCreateWithFormat(NULL
, NULL
, CFS_Format
, cfnewname
, suffix
) : NULL
;
526 alertHeader
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
529 helplog(ASL_LEVEL_ERR
, "Could not construct secondary CFString for old=%s", oldname
);
530 else if (cfnewname
&& !s2
)
531 helplog(ASL_LEVEL_ERR
, "Could not construct secondary CFString for new=%s", newname
);
532 else if (!alertHeader
)
533 helplog(ASL_LEVEL_ERR
, "Could not construct CFArray for notification");
536 // Make sure someone is logged in. We don't want this popping up over the login window
539 CFStringRef userName
= SCDynamicStoreCopyConsoleUser(NULL
, &uid
, &gid
);
543 CFArrayAppendValue(alertHeader
, msg
); // Opening phrase of message, provided by caller
544 CFArrayAppendValue(alertHeader
, CFS_OQ
); CFArrayAppendValue(alertHeader
, s1
); CFArrayAppendValue(alertHeader
, CFS_CQ
);
545 CFArrayAppendValue(alertHeader
, CFSTR(" is already in use on this network. "));
548 CFArrayAppendValue(alertHeader
, CFSTR("The name has been changed to "));
549 CFArrayAppendValue(alertHeader
, CFS_OQ
); CFArrayAppendValue(alertHeader
, s2
); CFArrayAppendValue(alertHeader
, CFS_CQ
);
550 CFArrayAppendValue(alertHeader
, CFSTR("."));
553 CFArrayAppendValue(alertHeader
, CFSTR("All attempts to find an available name by adding a number to the name were also unsuccessful."));
556 if (s1
) CFRelease(s1
);
557 if (s2
) CFRelease(s2
);
559 if (cfoldname
) CFRelease(cfoldname
);
560 if (cfnewname
) CFRelease(cfnewname
);
564 #endif /* ndef NO_CFUSERNOTIFICATION */
566 static void update_notification(void)
568 #ifndef NO_CFUSERNOTIFICATION
569 debug("entry ucn=%s, uhn=%s, lcn=%s, lhn=%s", usercompname
, userhostname
, lastcompname
, lasthostname
);
572 // 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.
573 // By appending this invisible character on the end of literal names, we ensure the these strings cannot inadvertently match any string
574 // in the localization file -- since we know for sure that none of our strings in the localization file contain the ZWNBS character.
576 // For languages that are written right to left, when we mix English (host names could be in english with brackets etc. and the
577 // rest in Arabic) we need unicode markups for proper formatting. The Unicode sequence 202C (UTF8 E2 80 AC), 200E (UTF8 E2 80 8E) and
578 // 202B (UTF8 E2 80 AB) helps with the formatting. See <rdar://problem/8629082> for more details.
579 CFS_OQ
= CFStringCreateWithCString(NULL
, "“\xE2\x80\xAB", kCFStringEncodingUTF8
);
580 CFS_CQ
= CFStringCreateWithCString(NULL
, "\xE2\x80\xAC”", kCFStringEncodingUTF8
);
581 CFS_Format
= CFStringCreateWithCString(NULL
, "%@%s\xEF\xBB\xBF\xE2\x80\x8E", kCFStringEncodingUTF8
);
582 CFS_ComputerName
= CFStringCreateWithCString(NULL
, "The name of your computer ", kCFStringEncodingUTF8
);
583 CFS_ComputerNameMsg
= CFStringCreateWithCString(NULL
, "To change the name of your computer, "
584 "open System Preferences and click Sharing, then type the name in the Computer Name field.", kCFStringEncodingUTF8
);
585 CFS_LocalHostName
= CFStringCreateWithCString(NULL
, "This computer’s local hostname ", kCFStringEncodingUTF8
);
586 CFS_LocalHostNameMsg
= CFStringCreateWithCString(NULL
, "To change the local hostname, "
587 "open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field.", kCFStringEncodingUTF8
);
588 CFS_Problem
= CFStringCreateWithCString(NULL
, "This may indicate a problem with the local network. "
589 "Please inform your network administrator.", kCFStringEncodingUTF8
);
592 if (!usercompname
[0] && !userhostname
[0])
594 if (gNotificationRLS
)
596 debug("canceling notification %p", gNotification
);
597 CFUserNotificationCancel(gNotification
);
598 unpause_idle_timer();
603 CFMutableArrayRef header
= NULL
;
604 CFStringRef
* subtext
= NULL
;
605 if (userhostname
[0] && !lasthostname
[0]) // we've given up trying to construct a name that doesn't conflict
607 header
= GetHeader(userhostname
, NULL
, CFS_LocalHostName
, ".local");
608 subtext
= &CFS_Problem
;
610 else if (usercompname
[0])
612 header
= GetHeader(usercompname
, lastcompname
, CFS_ComputerName
, "");
613 subtext
= &CFS_ComputerNameMsg
;
617 header
= GetHeader(userhostname
, lasthostname
, CFS_LocalHostName
, ".local");
618 subtext
= &CFS_LocalHostNameMsg
;
620 ShowNameConflictNotification(header
, *subtext
);
627 do_mDNSPreferencesSetName(__unused mach_port_t port
, int key
, const char* old
, const char* new, audit_token_t token
)
629 SCPreferencesRef session
= NULL
;
631 Boolean locked
= FALSE
;
632 CFStringRef cfstr
= NULL
;
635 Boolean needUpdate
= FALSE
;
637 debug("entry %s old=%s new=%s", key
==kmDNSComputerName
? "ComputerName" : (key
==kmDNSLocalHostName
? "LocalHostName" : "UNKNOWN"), old
, new);
638 if (!authorized(&token
)) goto fin
;
640 switch ((enum mDNSPreferencesSetNameKey
)key
)
642 case kmDNSComputerName
:
646 case kmDNSLocalHostName
:
651 debug("unrecognized key: %d", key
);
657 helplog(ASL_LEVEL_ERR
, "%s: no last ptr", __func__
);
663 helplog(ASL_LEVEL_ERR
, "%s: no user ptr", __func__
);
667 if (0 == strncmp(old
, new, MAX_DOMAIN_LABEL
+1))
669 // old and new are same means the config changed i.e, the user has set something in the preferences pane.
670 // This means the conflict has been resolved. We need to dismiss the dialogue.
671 if (last
[0] && 0 != strncmp(last
, new, MAX_DOMAIN_LABEL
+1))
681 // old and new are not same, this means there is a conflict. For the first conflict, we show
682 // the old value and the new value. For all subsequent conflicts, while the dialogue is still
683 // up, we do a real time update of the "new" value in the dialogue. That's why we update just
684 // "last" here and not "user".
685 if (strncmp(last
, new, MAX_DOMAIN_LABEL
+1))
687 strncpy(last
, new, MAX_DOMAIN_LABEL
);
692 // If we are not showing the dialogue, we need to remember the first "old" value so that
693 // we maintain the same through the lifetime of the dialogue. Subsequence conflicts don't
694 // update the "old" value.
697 strncpy(user
, old
, MAX_DOMAIN_LABEL
);
701 if (!new[0]) // we've given up trying to construct a name that doesn't conflict
704 cfstr
= CFStringCreateWithCString(NULL
, new, kCFStringEncodingUTF8
);
706 session
= SCPreferencesCreate(NULL
, CFSTR(kmDNSHelperServiceName
), NULL
);
708 if (cfstr
== NULL
|| session
== NULL
)
710 debug("SCPreferencesCreate failed");
713 if (!SCPreferencesLock(session
, 0))
715 debug("lock failed");
720 switch ((enum mDNSPreferencesSetNameKey
)key
)
722 case kmDNSComputerName
:
724 // We want to write the new Computer Name to System Preferences, without disturbing the user-selected
725 // system-wide default character set used for things like AppleTalk NBP and NETBIOS service advertising.
726 // Note that this encoding is not used for the computer name, but since both are set by the same call,
727 // we need to take care to set the name without changing the character set.
728 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
729 CFStringRef unused
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
730 if (unused
) { CFRelease(unused
); unused
= NULL
; }
731 else encoding
= kCFStringEncodingUTF8
;
733 ok
= SCPreferencesSetComputerName(session
, cfstr
, encoding
);
736 case kmDNSLocalHostName
:
737 ok
= SCPreferencesSetLocalHostName(session
, cfstr
);
743 if (!ok
|| !SCPreferencesCommitChanges(session
) ||
744 !SCPreferencesApplyChanges(session
))
746 debug("SCPreferences update failed");
757 SCPreferencesUnlock(session
);
761 if (needUpdate
) update_notification();
767 formatNotDNSKey
, formatDdnsTypeItem
, formatDnsPrefixedServiceItem
, formatBtmmPrefixedServiceItem
770 // On Mac OS X on Intel, the four-character string seems to be stored backwards, at least sometimes.
771 // I suspect some overenthusiastic inexperienced engineer said, "On Intel everything's backwards,
772 // therefore I need to add some byte swapping in this API to make this four-character string backwards too."
773 // To cope with this we allow *both* "ddns" and "sndd" as valid item types.
775 static const char dnsprefix
[] = "dns:";
776 static const char ddns
[] = "ddns";
777 static const char ddnsrev
[] = "sndd";
778 static const char btmmprefix
[] = "btmmdns:";
780 #ifndef NO_SECURITYFRAMEWORK
781 static enum DNSKeyFormat
782 getDNSKeyFormat(SecKeychainItemRef item
, SecKeychainAttributeList
**attributesp
)
784 static UInt32 tags
[4] =
786 kSecTypeItemAttr
, kSecServiceItemAttr
, kSecAccountItemAttr
, kSecLabelItemAttr
788 static SecKeychainAttributeInfo attributeInfo
=
790 sizeof(tags
)/sizeof(tags
[0]), tags
, NULL
792 SecKeychainAttributeList
*attributes
= NULL
;
793 enum DNSKeyFormat format
;
794 Boolean malformed
= FALSE
;
795 OSStatus status
= noErr
;
799 if (noErr
!= (status
= SecKeychainItemCopyAttributesAndData(item
,
800 &attributeInfo
, NULL
, &attributes
, NULL
, NULL
)))
802 debug("SecKeychainItemCopyAttributesAndData %d - skipping",
806 if (attributeInfo
.count
!= attributes
->count
)
808 for (i
= 0; !malformed
&& i
< (int)attributeInfo
.count
; ++i
)
809 if (attributeInfo
.tag
[i
] != attributes
->attr
[i
].tag
)
814 "malformed result from SecKeychainItemCopyAttributesAndData - skipping");
818 debug("entry (\"%.*s\", \"%.*s\", \"%.*s\")",
819 (int)attributes
->attr
[0].length
, attributes
->attr
[0].data
,
820 (int)attributes
->attr
[1].length
, attributes
->attr
[1].data
,
821 (int)attributes
->attr
[2].length
, attributes
->attr
[2].data
);
822 if (attributes
->attr
[1].length
>= MAX_ESCAPED_DOMAIN_NAME
+
825 debug("kSecServiceItemAttr too long (%u) - skipping",
826 (unsigned int)attributes
->attr
[1].length
);
829 if (attributes
->attr
[2].length
>= MAX_ESCAPED_DOMAIN_NAME
)
831 debug("kSecAccountItemAttr too long (%u) - skipping",
832 (unsigned int)attributes
->attr
[2].length
);
835 if (attributes
->attr
[1].length
>= sizeof(dnsprefix
)-1 &&
836 0 == strncasecmp(attributes
->attr
[1].data
, dnsprefix
,
837 sizeof(dnsprefix
)-1))
838 format
= formatDnsPrefixedServiceItem
;
839 else if (attributes
->attr
[1].length
>= sizeof(btmmprefix
)-1 &&
840 0 == strncasecmp(attributes
->attr
[1].data
, btmmprefix
, sizeof(btmmprefix
)-1))
841 format
= formatBtmmPrefixedServiceItem
;
842 else if (attributes
->attr
[0].length
== sizeof(ddns
)-1 &&
843 0 == strncasecmp(attributes
->attr
[0].data
, ddns
, sizeof(ddns
)-1))
844 format
= formatDdnsTypeItem
;
845 else if (attributes
->attr
[0].length
== sizeof(ddnsrev
)-1 &&
846 0 == strncasecmp(attributes
->attr
[0].data
, ddnsrev
, sizeof(ddnsrev
)-1))
847 format
= formatDdnsTypeItem
;
850 debug("uninterested in this entry");
853 *attributesp
= attributes
;
854 debug("accepting this entry");
858 SecKeychainItemFreeAttributesAndData(attributes
, NULL
);
859 return formatNotDNSKey
;
862 // Insert the attributes as defined by mDNSKeyChainAttributes
863 static CFPropertyListRef
864 getKeychainItemInfo(SecKeychainItemRef item
,
865 SecKeychainAttributeList
*attributes
, enum DNSKeyFormat format
)
867 CFMutableArrayRef entry
= NULL
;
868 CFDataRef data
= NULL
;
869 OSStatus status
= noErr
;
873 if (NULL
== (entry
= CFArrayCreateMutable(NULL
, 0,
874 &kCFTypeArrayCallBacks
)))
876 debug("CFArrayCreateMutable failed");
880 // Insert the Account attribute (kmDNSKcWhere)
881 switch ((enum DNSKeyFormat
)format
)
883 case formatDdnsTypeItem
:
884 data
= CFDataCreate(kCFAllocatorDefault
,
885 attributes
->attr
[1].data
, attributes
->attr
[1].length
);
887 case formatDnsPrefixedServiceItem
:
888 case formatBtmmPrefixedServiceItem
:
889 data
= CFDataCreate(kCFAllocatorDefault
,
890 attributes
->attr
[1].data
, attributes
->attr
[1].length
);
893 assert("unknown DNSKeyFormat value");
898 debug("CFDataCreate for attr[1] failed");
901 CFArrayAppendValue(entry
, data
);
904 // Insert the Where attribute (kmDNSKcAccount)
905 if (NULL
== (data
= CFDataCreate(kCFAllocatorDefault
,
906 attributes
->attr
[2].data
, attributes
->attr
[2].length
)))
908 debug("CFDataCreate for attr[2] failed");
911 CFArrayAppendValue(entry
, data
);
914 // Insert the Key attribute (kmDNSKcKey)
915 if (noErr
!= (status
= SecKeychainItemCopyAttributesAndData(item
, NULL
,
916 NULL
, NULL
, &keylen
, &keyp
)))
918 debug("could not retrieve key for \"%.*s\": %d",
919 (int)attributes
->attr
[1].length
, attributes
->attr
[1].data
,
923 data
= CFDataCreate(kCFAllocatorDefault
, keyp
, keylen
);
924 SecKeychainItemFreeAttributesAndData(NULL
, keyp
);
927 debug("CFDataCreate for keyp failed");
930 CFArrayAppendValue(entry
, data
);
933 // Insert the Name attribute (kmDNSKcName)
934 if (NULL
== (data
= CFDataCreate(kCFAllocatorDefault
,
935 attributes
->attr
[3].data
, attributes
->attr
[3].length
)))
937 debug("CFDataCreate for attr[3] failed");
940 CFArrayAppendValue(entry
, data
);
952 do_mDNSKeychainGetSecrets(__unused mach_port_t port
, __unused
unsigned int *numsecrets
,
953 __unused vm_offset_t
*secrets
, __unused mach_msg_type_number_t
*secretsCnt
, __unused
int *err
,
954 __unused audit_token_t token
)
956 #ifndef NO_SECURITYFRAMEWORK
957 CFWriteStreamRef stream
= NULL
;
958 CFDataRef result
= NULL
;
959 CFPropertyListRef entry
= NULL
;
960 CFMutableArrayRef keys
= NULL
;
961 SecKeychainRef skc
= NULL
;
962 SecKeychainItemRef item
= NULL
;
963 SecKeychainSearchRef search
= NULL
;
964 SecKeychainAttributeList
*attributes
= NULL
;
965 enum DNSKeyFormat format
;
971 *secrets
= (vm_offset_t
)NULL
;
972 if (!authorized(&token
))
974 *err
= kmDNSHelperNotAuthorized
;
977 if (NULL
== (keys
= CFArrayCreateMutable(NULL
, 0,
978 &kCFTypeArrayCallBacks
)))
980 debug("CFArrayCreateMutable failed");
981 *err
= kmDNSHelperCreationFailed
;
984 if (noErr
!= (status
= SecKeychainCopyDefault(&skc
)))
986 *err
= kmDNSHelperKeychainCopyDefaultFailed
;
989 if (noErr
!= (status
= SecKeychainSearchCreateFromAttributes(skc
, kSecGenericPasswordItemClass
, NULL
, &search
)))
991 *err
= kmDNSHelperKeychainSearchCreationFailed
;
994 for (status
= SecKeychainSearchCopyNext(search
, &item
);
996 status
= SecKeychainSearchCopyNext(search
, &item
))
998 if (formatNotDNSKey
!= (format
= getDNSKeyFormat(item
,
1000 NULL
!= (entry
= getKeychainItemInfo(item
, attributes
,
1003 CFArrayAppendValue(keys
, entry
);
1006 SecKeychainItemFreeAttributesAndData(attributes
, NULL
);
1009 if (errSecItemNotFound
!= status
)
1010 helplog(ASL_LEVEL_ERR
, "%s: SecKeychainSearchCopyNext failed: %d",
1012 if (NULL
== (stream
=
1013 CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorDefault
,
1014 kCFAllocatorDefault
)))
1016 *err
= kmDNSHelperCreationFailed
;
1017 debug("CFWriteStreamCreateWithAllocatedBuffers failed");
1020 CFWriteStreamOpen(stream
);
1021 if (0 == CFPropertyListWriteToStream(keys
, stream
,
1022 kCFPropertyListBinaryFormat_v1_0
, NULL
))
1024 *err
= kmDNSHelperPListWriteFailed
;
1025 debug("CFPropertyListWriteToStream failed");
1028 result
= CFWriteStreamCopyProperty(stream
,
1029 kCFStreamPropertyDataWritten
);
1030 if (KERN_SUCCESS
!= vm_allocate(mach_task_self(), secrets
,
1031 CFDataGetLength(result
), VM_FLAGS_ANYWHERE
))
1033 *err
= kmDNSHelperCreationFailed
;
1034 debug("vm_allocate failed");
1037 CFDataGetBytes(result
, CFRangeMake(0, CFDataGetLength(result
)),
1039 *secretsCnt
= CFDataGetLength(result
);
1040 *numsecrets
= CFArrayGetCount(keys
);
1044 debug("returning %u secrets", *numsecrets
);
1047 CFWriteStreamClose(stream
);
1058 update_idle_timer();
1059 return KERN_SUCCESS
;
1061 return KERN_FAILURE
;
1065 #ifndef MDNS_NO_IPSEC
1066 typedef enum _mDNSTunnelPolicyWhich
1068 kmDNSTunnelPolicySetup
,
1069 kmDNSTunnelPolicyTeardown
,
1070 kmDNSTunnelPolicyGenerate
1071 } mDNSTunnelPolicyWhich
;
1073 // For kmDNSTunnelPolicySetup, you can setup IPv6-in-IPv6 tunnel or IPv6-in-IPv4 tunnel
1074 // kmDNSNoTunnel is used for other Policy types
1075 typedef enum _mDNSTunnelType
1078 kmDNSIPv6IPv4Tunnel
,
1082 static const uint8_t kWholeV6Mask
= 128;
1083 static const uint8_t kZeroV6Mask
= 0;
1086 doTunnelPolicy(mDNSTunnelPolicyWhich which
, mDNSTunnelType type
,
1087 v6addr_t loc_inner
, uint8_t loc_bits
,
1088 v4addr_t loc_outer
, uint16_t loc_port
,
1089 v6addr_t rmt_inner
, uint8_t rmt_bits
,
1090 v4addr_t rmt_outer
, uint16_t rmt_port
,
1091 v6addr_t loc_outer6
, v6addr_t rmt_outer6
);
1094 aliasTunnelAddress(v6addr_t address
)
1096 struct in6_aliasreq ifra_in6
;
1100 if (0 > (s
= socket(AF_INET6
, SOCK_DGRAM
, 0)))
1102 helplog(ASL_LEVEL_ERR
, "socket(AF_INET6, ...) failed: %s",
1104 err
= kmDNSHelperDatagramSocketCreationFailed
;
1107 memset(&ifra_in6
, 0, sizeof(ifra_in6
));
1108 strlcpy(ifra_in6
.ifra_name
, kTunnelAddressInterface
,
1109 sizeof(ifra_in6
.ifra_name
));
1110 ifra_in6
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
1111 ifra_in6
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
1113 ifra_in6
.ifra_addr
.sin6_family
= AF_INET6
;
1114 ifra_in6
.ifra_addr
.sin6_len
= sizeof(struct sockaddr_in6
);
1115 memcpy(&(ifra_in6
.ifra_addr
.sin6_addr
), address
,
1116 sizeof(ifra_in6
.ifra_addr
.sin6_addr
));
1118 ifra_in6
.ifra_prefixmask
.sin6_family
= AF_INET6
;
1119 ifra_in6
.ifra_prefixmask
.sin6_len
= sizeof(struct sockaddr_in6
);
1120 memset(&(ifra_in6
.ifra_prefixmask
.sin6_addr
), 0xFF,
1121 sizeof(ifra_in6
.ifra_prefixmask
.sin6_addr
));
1123 if (0 > ioctl(s
, SIOCAIFADDR_IN6
, &ifra_in6
))
1125 helplog(ASL_LEVEL_ERR
,
1126 "ioctl(..., SIOCAIFADDR_IN6, ...) failed: %s",
1128 err
= kmDNSHelperInterfaceCreationFailed
;
1132 v6addr_t zero
= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
1133 err
= doTunnelPolicy(kmDNSTunnelPolicyGenerate
, kmDNSNoTunnel
,
1134 address
, kWholeV6Mask
, NULL
, 0,
1135 zero
, kZeroV6Mask
, NULL
, 0, NULL
, NULL
);
1144 unaliasTunnelAddress(v6addr_t address
)
1146 struct in6_ifreq ifr
;
1150 if (0 > (s
= socket(AF_INET6
, SOCK_DGRAM
, 0)))
1152 helplog(ASL_LEVEL_ERR
, "socket(AF_INET6, ...) failed: %s",
1154 err
= kmDNSHelperDatagramSocketCreationFailed
;
1157 memset(&ifr
, 0, sizeof(ifr
));
1158 strlcpy(ifr
.ifr_name
, kTunnelAddressInterface
, sizeof(ifr
.ifr_name
));
1159 ifr
.ifr_ifru
.ifru_addr
.sin6_family
= AF_INET6
;
1160 ifr
.ifr_ifru
.ifru_addr
.sin6_len
= sizeof(struct sockaddr_in6
);
1161 memcpy(&(ifr
.ifr_ifru
.ifru_addr
.sin6_addr
), address
,
1162 sizeof(ifr
.ifr_ifru
.ifru_addr
.sin6_addr
));
1164 if (0 > ioctl(s
, SIOCDIFADDR_IN6
, &ifr
))
1166 helplog(ASL_LEVEL_ERR
,
1167 "ioctl(..., SIOCDIFADDR_IN6, ...) failed: %s",
1169 err
= kmDNSHelperInterfaceDeletionFailed
;
1173 v6addr_t zero
= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
1174 err
= doTunnelPolicy(kmDNSTunnelPolicyTeardown
, kmDNSNoTunnel
,
1175 address
, kWholeV6Mask
, NULL
, 0,
1176 zero
, kZeroV6Mask
, NULL
, 0, NULL
, NULL
);
1183 #endif /* ifndef MDNS_NO_IPSEC */
1186 do_mDNSAutoTunnelInterfaceUpDown(__unused mach_port_t port
, int updown
,
1187 v6addr_t address
, audit_token_t token
)
1189 #ifndef MDNS_NO_IPSEC
1191 if (!authorized(&token
)) goto fin
;
1193 switch ((enum mDNSUpDown
)updown
)
1196 aliasTunnelAddress(address
);
1199 unaliasTunnelAddress(address
);
1208 (void)port
; (void)updown
; (void)address
; (void)token
;
1210 update_idle_timer();
1211 return KERN_SUCCESS
;
1214 #ifndef MDNS_NO_IPSEC
1216 static const char g_racoon_config_dir
[] = "/var/run/racoon/";
1217 static const char g_racoon_config_dir_old
[] = "/etc/racoon/remote/";
1219 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
1220 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
1222 // Major version 6 is 10.2.x (Jaguar)
1223 // Major version 7 is 10.3.x (Panther)
1224 // Major version 8 is 10.4.x (Tiger)
1225 // Major version 9 is 10.5.x (Leopard)
1226 // Major version 10 is 10.6.x (SnowLeopard)
1227 static int MacOSXSystemBuildNumber(char* letter_out
, int* minor_out
)
1229 int major
= 0, minor
= 0;
1230 char letter
= 0, buildver
[256]="<Unknown>";
1231 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
1234 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
1235 if (cfbuildver
) CFStringGetCString(cfbuildver
, buildver
, sizeof(buildver
), kCFStringEncodingUTF8
);
1236 sscanf(buildver
, "%d%c%d", &major
, &letter
, &minor
);
1240 helplog(ASL_LEVEL_NOTICE
, "_CFCopySystemVersionDictionary failed");
1242 if (!major
) { major
=10; letter
= 'A'; minor
= 190; helplog(ASL_LEVEL_NOTICE
, "Note: No Major Build Version number found; assuming 10A190"); }
1243 if (letter_out
) *letter_out
= letter
;
1244 if (minor_out
) *minor_out
= minor
;
1248 static int UseOldRacoon()
1250 static int g_oldRacoon
= -1;
1252 if (g_oldRacoon
== -1)
1256 g_oldRacoon
= (MacOSXSystemBuildNumber(&letter
, &minor
) < 10);
1257 debug("%s", g_oldRacoon
?"old":"new");
1263 static int RacoonSignal()
1265 return UseOldRacoon() ? SIGHUP
: SIGUSR1
;
1268 static const char* GetRacoonConfigDir()
1270 return UseOldRacoon() ? g_racoon_config_dir_old
: g_racoon_config_dir
;
1273 static const char* GetOldRacoonConfigDir()
1275 return UseOldRacoon() ? NULL
: g_racoon_config_dir_old
;
1278 static const char racoon_config_file
[] = "anonymous.conf";
1279 static const char racoon_config_file_orig
[] = "anonymous.conf.orig";
1281 static const char configHeader
[] = "# BackToMyMac\n";
1283 static int IsFamiliarRacoonConfiguration(const char* racoon_config_path
)
1285 int fd
= open(racoon_config_path
, O_RDONLY
);
1286 debug("entry %s", racoon_config_path
);
1289 helplog(ASL_LEVEL_NOTICE
, "open \"%s\" failed: %s", racoon_config_path
, strerror(errno
));
1294 char header
[sizeof(configHeader
)] = {0};
1295 ssize_t bytesRead
= read(fd
, header
, sizeof(header
)-1);
1297 if (bytesRead
!= sizeof(header
)-1) return 0;
1298 return (0 == memcmp(header
, configHeader
, sizeof(header
)-1));
1303 revertAnonymousRacoonConfiguration(const char* dir
)
1307 debug("entry %s", dir
);
1309 char racoon_config_path
[64];
1310 strlcpy(racoon_config_path
, dir
, sizeof(racoon_config_path
));
1311 strlcat(racoon_config_path
, racoon_config_file
, sizeof(racoon_config_path
));
1314 int ret
= stat(racoon_config_path
, &s
);
1315 debug("stat(%s): %d errno=%d", racoon_config_path
, ret
, errno
);
1318 if (IsFamiliarRacoonConfiguration(racoon_config_path
))
1320 helplog(ASL_LEVEL_INFO
, "\"%s\" looks familiar, unlinking", racoon_config_path
);
1321 unlink(racoon_config_path
);
1325 helplog(ASL_LEVEL_NOTICE
, "\"%s\" does not look familiar, leaving in place", racoon_config_path
);
1329 else if (errno
!= ENOENT
)
1331 helplog(ASL_LEVEL_NOTICE
, "stat failed for \"%s\", leaving in place: %s", racoon_config_path
, strerror(errno
));
1335 char racoon_config_path_orig
[64];
1336 strlcpy(racoon_config_path_orig
, dir
, sizeof(racoon_config_path_orig
));
1337 strlcat(racoon_config_path_orig
, racoon_config_file_orig
, sizeof(racoon_config_path_orig
));
1339 ret
= stat(racoon_config_path_orig
, &s
);
1340 debug("stat(%s): %d errno=%d", racoon_config_path_orig
, ret
, errno
);
1343 if (0 > rename(racoon_config_path_orig
, racoon_config_path
))
1344 helplog(ASL_LEVEL_NOTICE
, "rename \"%s\" \"%s\" failed: %s", racoon_config_path_orig
, racoon_config_path
, strerror(errno
));
1346 debug("reverted \"%s\" to \"%s\"", racoon_config_path_orig
, racoon_config_path
);
1348 else if (errno
!= ENOENT
)
1350 helplog(ASL_LEVEL_NOTICE
, "stat failed for \"%s\", leaving in place: %s", racoon_config_path_orig
, strerror(errno
));
1356 moveAsideAnonymousRacoonConfiguration(const char* dir
)
1360 debug("entry %s", dir
);
1362 char racoon_config_path
[64];
1363 strlcpy(racoon_config_path
, dir
, sizeof(racoon_config_path
));
1364 strlcat(racoon_config_path
, racoon_config_file
, sizeof(racoon_config_path
));
1367 int ret
= stat(racoon_config_path
, &s
);
1370 if (IsFamiliarRacoonConfiguration(racoon_config_path
))
1372 helplog(ASL_LEVEL_INFO
, "\"%s\" looks familiar, unlinking", racoon_config_path
);
1373 unlink(racoon_config_path
);
1377 char racoon_config_path_orig
[64];
1378 strlcpy(racoon_config_path_orig
, dir
, sizeof(racoon_config_path_orig
));
1379 strlcat(racoon_config_path_orig
, racoon_config_file_orig
, sizeof(racoon_config_path_orig
));
1380 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
1381 helplog(ASL_LEVEL_NOTICE
, "rename \"%s\" to \"%s\" failed: %s", racoon_config_path
, racoon_config_path_orig
, strerror(errno
));
1383 debug("successfully renamed \"%s\" to \"%s\"", racoon_config_path
, racoon_config_path_orig
);
1386 else if (errno
!= ENOENT
)
1388 helplog(ASL_LEVEL_NOTICE
, "stat failed for \"%s\", leaving in place: %s", racoon_config_path
, strerror(errno
));
1394 ensureExistenceOfRacoonConfigDir(const char* const racoon_config_dir
)
1397 int ret
= stat(racoon_config_dir
, &s
);
1400 if (errno
!= ENOENT
)
1402 helplog(ASL_LEVEL_ERR
, "stat of \"%s\" failed (%d): %s",
1403 racoon_config_dir
, ret
, strerror(errno
));
1408 ret
= mkdir(racoon_config_dir
, S_IRWXU
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
);
1411 helplog(ASL_LEVEL_ERR
, "mkdir \"%s\" failed: %s",
1412 racoon_config_dir
, strerror(errno
));
1416 helplog(ASL_LEVEL_INFO
, "created directory \"%s\"", racoon_config_dir
);
1419 else if (!(s
.st_mode
& S_IFDIR
))
1421 helplog(ASL_LEVEL_ERR
, "\"%s\" is not a directory!",
1430 createAnonymousRacoonConfiguration(const char *fqdn
)
1432 static const char config1
[] =
1433 "remote anonymous {\n"
1434 " exchange_mode aggressive;\n"
1436 " situation identity_only;\n"
1437 " verify_identifier off;\n"
1438 " generate_policy on;\n"
1439 " shared_secret keychain_by_id \"";
1440 static const char config2
[] =
1443 " lifetime time 15 min;\n"
1444 " initial_contact on;\n"
1445 " support_proxy on;\n"
1446 " nat_traversal force;\n"
1447 " proposal_check claim;\n"
1449 " encryption_algorithm aes;\n"
1450 " hash_algorithm sha1;\n"
1451 " authentication_method pre_shared_key;\n"
1453 " lifetime time 15 min;\n"
1456 "sainfo anonymous { \n"
1458 " lifetime time 10 min;\n"
1459 " encryption_algorithm aes;\n"
1460 " authentication_algorithm hmac_sha1;\n"
1461 " compression_algorithm deflate;\n"
1463 char tmp_config_path
[64];
1464 char racoon_config_path
[64];
1465 const char* const racoon_config_dir
= GetRacoonConfigDir();
1466 const char* const racoon_config_dir_old
= GetOldRacoonConfigDir();
1471 if (0 > ensureExistenceOfRacoonConfigDir(racoon_config_dir
))
1474 strlcpy(tmp_config_path
, racoon_config_dir
, sizeof(tmp_config_path
));
1475 strlcat(tmp_config_path
, "tmp.XXXXXX", sizeof(tmp_config_path
));
1477 fd
= mkstemp(tmp_config_path
);
1481 helplog(ASL_LEVEL_ERR
, "mkstemp \"%s\" failed: %s",
1482 tmp_config_path
, strerror(errno
));
1485 write(fd
, configHeader
, sizeof(configHeader
)-1);
1486 write(fd
, config1
, sizeof(config1
)-1);
1487 write(fd
, fqdn
, strlen(fqdn
));
1488 write(fd
, config2
, sizeof(config2
)-1);
1491 strlcpy(racoon_config_path
, racoon_config_dir
, sizeof(racoon_config_path
));
1492 strlcat(racoon_config_path
, racoon_config_file
, sizeof(racoon_config_path
));
1494 moveAsideAnonymousRacoonConfiguration(racoon_config_dir_old
);
1495 moveAsideAnonymousRacoonConfiguration(racoon_config_dir
);
1497 if (0 > rename(tmp_config_path
, racoon_config_path
))
1499 unlink(tmp_config_path
);
1500 helplog(ASL_LEVEL_ERR
, "rename \"%s\" \"%s\" failed: %s",
1501 tmp_config_path
, racoon_config_path
, strerror(errno
));
1502 revertAnonymousRacoonConfiguration(racoon_config_dir_old
);
1503 revertAnonymousRacoonConfiguration(racoon_config_dir
);
1507 debug("successfully renamed \"%s\" \"%s\"", tmp_config_path
, racoon_config_path
);
1515 static const char racoon_pid_path
[] = "/var/run/racoon.pid";
1516 char buf
[] = "18446744073709551615"; /* largest 64-bit integer */
1519 unsigned long m
= 0;
1520 int fd
= open(racoon_pid_path
, O_RDONLY
);
1524 debug("open \"%s\" failed, and that's OK: %s", racoon_pid_path
,
1526 return kmDNSHelperRacoonNotificationFailed
;
1528 n
= read(fd
, buf
, sizeof(buf
)-1);
1532 debug("read of \"%s\" failed: %s", racoon_pid_path
,
1533 n
== 0 ? "empty file" : strerror(errno
));
1534 return kmDNSHelperRacoonNotificationFailed
;
1537 m
= strtoul(buf
, &p
, 10);
1538 if (*p
!= '\0' && !isspace(*p
))
1540 debug("invalid PID \"%s\" (around '%c')", buf
, *p
);
1541 return kmDNSHelperRacoonNotificationFailed
;
1545 debug("refusing to kill PID %lu", m
);
1546 return kmDNSHelperRacoonNotificationFailed
;
1548 if (0 != kill(m
, RacoonSignal()))
1550 debug("Could not signal racoon (%lu): %s", m
, strerror(errno
));
1551 return kmDNSHelperRacoonNotificationFailed
;
1553 debug("Sent racoon (%lu) signal %d", m
, RacoonSignal());
1561 struct dirent entry
, *entryp
= NULL
;
1562 DIR *dirp
= opendir("/dev/fd");
1566 /* fall back to the erroneous getdtablesize method */
1567 for (fd
= from
; fd
< getdtablesize(); ++fd
)
1571 while (0 == readdir_r(dirp
, &entry
, &entryp
) && NULL
!= entryp
)
1573 fd
= atoi(entryp
->d_name
);
1574 if (fd
>= from
&& fd
!= dirfd(dirp
))
1581 startRacoonOld(void)
1584 char * const racoon_args
[] = { "/usr/sbin/racoon", "-e", NULL
};
1589 if (0 == (pid
= fork()))
1592 execve(racoon_args
[0], racoon_args
, NULL
);
1593 helplog(ASL_LEVEL_ERR
, "execve of \"%s\" failed: %s",
1594 racoon_args
[0], strerror(errno
));
1597 helplog(ASL_LEVEL_NOTICE
, "racoon (pid=%lu) started",
1598 (unsigned long)pid
);
1599 n
= waitpid(pid
, &status
, 0);
1602 helplog(ASL_LEVEL_ERR
, "Unexpected waitpid failure: %s",
1604 return kmDNSHelperRacoonStartFailed
;
1608 helplog(ASL_LEVEL_ERR
, "Unexpected waitpid return value %d",
1610 return kmDNSHelperRacoonStartFailed
;
1612 else if (WIFSIGNALED(status
))
1614 helplog(ASL_LEVEL_ERR
,
1615 "racoon (pid=%lu) terminated due to signal %d",
1616 (unsigned long)pid
, WTERMSIG(status
));
1617 return kmDNSHelperRacoonStartFailed
;
1619 else if (WIFSTOPPED(status
))
1621 helplog(ASL_LEVEL_ERR
,
1622 "racoon (pid=%lu) has stopped due to signal %d",
1623 (unsigned long)pid
, WSTOPSIG(status
));
1624 return kmDNSHelperRacoonStartFailed
;
1626 else if (0 != WEXITSTATUS(status
))
1628 helplog(ASL_LEVEL_ERR
,
1629 "racoon (pid=%lu) exited with status %d",
1630 (unsigned long)pid
, WEXITSTATUS(status
));
1631 return kmDNSHelperRacoonStartFailed
;
1633 debug("racoon (pid=%lu) daemonized normally", (unsigned long)pid
);
1637 // constant and structure for the racoon control socket
1638 #define VPNCTL_CMD_PING 0x0004
1639 typedef struct vpnctl_hdr_struct
1653 int fd
= socket(PF_UNIX
, SOCK_STREAM
, 0);
1656 helplog(ASL_LEVEL_ERR
, "Could not create endpoint for racoon control socket: %d %s",
1657 errno
, strerror(errno
));
1658 return kmDNSHelperRacoonStartFailed
;
1661 struct sockaddr_un saddr
;
1662 memset(&saddr
, 0, sizeof(saddr
));
1663 saddr
.sun_family
= AF_UNIX
;
1664 saddr
.sun_len
= sizeof(saddr
);
1665 static const char racoon_control_sock_path
[] = "/var/run/vpncontrol.sock";
1666 strcpy(saddr
.sun_path
, racoon_control_sock_path
);
1667 int result
= connect(fd
, (struct sockaddr
*) &saddr
, saddr
.sun_len
);
1670 helplog(ASL_LEVEL_ERR
, "Could not connect racoon control socket %s: %d %s",
1671 racoon_control_sock_path
, errno
, strerror(errno
));
1672 return kmDNSHelperRacoonStartFailed
;
1675 u_int32_t btmm_cookie
= 0x4d4d5442;
1676 vpnctl_hdr h
= { VPNCTL_CMD_PING
, 0, btmm_cookie
, 0, 0, 0 };
1680 while (bytes
< sizeof(vpnctl_hdr
))
1682 ret
= write(fd
, ((unsigned char*)&h
)+bytes
, sizeof(vpnctl_hdr
) - bytes
);
1685 helplog(ASL_LEVEL_ERR
, "Could not write to racoon control socket: %d %s",
1686 errno
, strerror(errno
));
1687 return kmDNSHelperRacoonStartFailed
;
1699 for (counter
= 0; counter
< 100; counter
++)
1703 tv
= (struct timeval
){ 0, 10000 }; // 10 milliseconds * 100 iterations = 1 second max wait time
1705 result
= select(nfds
, &fds
, (fd_set
*)NULL
, (fd_set
*)NULL
, &tv
);
1708 if (FD_ISSET(fd
, &fds
))
1710 ret
= read(fd
, ((unsigned char*)&h
)+bytes
, sizeof(vpnctl_hdr
) - bytes
);
1714 helplog(ASL_LEVEL_ERR
, "Could not read from racoon control socket: %d %s",
1719 if (bytes
>= sizeof(vpnctl_hdr
)) break;
1723 debug("select returned but fd_isset not on expected fd\n");
1726 else if (result
< 0)
1728 debug("select returned %d errno %d %s\n", result
, errno
, strerror(errno
));
1729 if (errno
!= EINTR
) break;
1735 if (bytes
< sizeof(vpnctl_hdr
) || h
.cookie
!= btmm_cookie
) return kmDNSHelperRacoonStartFailed
;
1737 debug("racoon started");
1744 if ( 0 == notifyRacoon() )
1746 return UseOldRacoon() ? startRacoonOld() : startRacoon();
1749 #endif /* ndef MDNS_NO_IPSEC */
1752 do_mDNSConfigureServer(__unused mach_port_t port
, int updown
, const char *fqdn
, audit_token_t token
)
1754 #ifndef MDNS_NO_IPSEC
1756 if (!authorized(&token
)) goto fin
;
1758 switch ((enum mDNSUpDown
)updown
)
1761 if (0 != createAnonymousRacoonConfiguration(fqdn
)) goto fin
;
1764 revertAnonymousRacoonConfiguration(GetOldRacoonConfigDir());
1765 revertAnonymousRacoonConfiguration(GetRacoonConfigDir());
1771 if (0 != kickRacoon())
1777 (void)port
; (void)updown
; (void)fqdn
; (void)token
;
1779 update_idle_timer();
1780 return KERN_SUCCESS
;
1783 #ifndef MDNS_NO_IPSEC
1785 static unsigned int routeSeq
= 1;
1788 setupTunnelRoute(v6addr_t local
, v6addr_t remote
)
1792 struct rt_msghdr hdr
;
1793 struct sockaddr_in6 dst
;
1794 struct sockaddr_in6 gtwy
;
1799 if (0 > (s
= socket(PF_ROUTE
, SOCK_RAW
, AF_INET
)))
1801 helplog(ASL_LEVEL_ERR
, "socket(PF_ROUTE, ...) failed: %s",
1803 err
= kmDNSHelperRoutingSocketCreationFailed
;
1806 memset(&msg
, 0, sizeof(msg
));
1807 msg
.hdr
.rtm_msglen
= sizeof(msg
);
1808 msg
.hdr
.rtm_type
= RTM_ADD
;
1809 /* The following flags are set by `route add -inet6 -host ...` */
1810 msg
.hdr
.rtm_flags
= RTF_UP
| RTF_GATEWAY
| RTF_HOST
| RTF_STATIC
;
1811 msg
.hdr
.rtm_version
= RTM_VERSION
;
1812 msg
.hdr
.rtm_seq
= routeSeq
++;
1813 msg
.hdr
.rtm_addrs
= RTA_DST
| RTA_GATEWAY
;
1814 msg
.hdr
.rtm_inits
= RTV_MTU
;
1815 msg
.hdr
.rtm_rmx
.rmx_mtu
= 1280;
1817 msg
.dst
.sin6_len
= sizeof(msg
.dst
);
1818 msg
.dst
.sin6_family
= AF_INET6
;
1819 memcpy(&msg
.dst
.sin6_addr
, remote
, sizeof(msg
.dst
.sin6_addr
));
1821 msg
.gtwy
.sin6_len
= sizeof(msg
.gtwy
);
1822 msg
.gtwy
.sin6_family
= AF_INET6
;
1823 memcpy(&msg
.gtwy
.sin6_addr
, local
, sizeof(msg
.gtwy
.sin6_addr
));
1825 /* send message, ignore error when route already exists */
1826 if (0 > write(s
, &msg
, msg
.hdr
.rtm_msglen
))
1830 debug("write to routing socket failed: %s", strerror(errno_
));
1831 if (EEXIST
!= errno_
)
1833 err
= kmDNSHelperRouteAdditionFailed
;
1845 teardownTunnelRoute(v6addr_t remote
)
1849 struct rt_msghdr hdr
;
1850 struct sockaddr_in6 dst
;
1855 if (0 > (s
= socket(PF_ROUTE
, SOCK_RAW
, AF_INET
)))
1857 helplog(ASL_LEVEL_ERR
, "socket(PF_ROUTE, ...) failed: %s",
1859 err
= kmDNSHelperRoutingSocketCreationFailed
;
1862 memset(&msg
, 0, sizeof(msg
));
1864 msg
.hdr
.rtm_msglen
= sizeof(msg
);
1865 msg
.hdr
.rtm_type
= RTM_DELETE
;
1866 msg
.hdr
.rtm_version
= RTM_VERSION
;
1867 msg
.hdr
.rtm_seq
= routeSeq
++;
1868 msg
.hdr
.rtm_addrs
= RTA_DST
;
1870 msg
.dst
.sin6_len
= sizeof(msg
.dst
);
1871 msg
.dst
.sin6_family
= AF_INET6
;
1872 memcpy(&msg
.dst
.sin6_addr
, remote
, sizeof(msg
.dst
.sin6_addr
));
1873 if (0 > write(s
, &msg
, msg
.hdr
.rtm_msglen
))
1877 debug("write to routing socket failed: %s", strerror(errno_
));
1878 if (ESRCH
!= errno_
)
1880 err
= kmDNSHelperRouteDeletionFailed
;
1892 v4addr_to_string(v4addr_t addr
, char *buf
, size_t buflen
)
1894 if (NULL
== inet_ntop(AF_INET
, addr
, buf
, buflen
))
1896 helplog(ASL_LEVEL_ERR
, "inet_ntop failed: %s",
1898 return kmDNSHelperInvalidNetworkAddress
;
1905 v6addr_to_string(v6addr_t addr
, char *buf
, size_t buflen
)
1907 if (NULL
== inet_ntop(AF_INET6
, addr
, buf
, buflen
))
1909 helplog(ASL_LEVEL_ERR
, "inet_ntop failed: %s",
1911 return kmDNSHelperInvalidNetworkAddress
;
1917 /* Caller owns object returned in `policy' */
1919 generateTunnelPolicy(mDNSTunnelPolicyWhich which
, mDNSTunnelType type
, int in
,
1920 v4addr_t src
, uint16_t src_port
,
1921 v4addr_t dst
, uint16_t dst_port
,
1922 v6addr_t src6
, v6addr_t dst6
,
1923 ipsec_policy_t
*policy
, size_t *len
)
1925 char srcs
[INET_ADDRSTRLEN
], dsts
[INET_ADDRSTRLEN
];
1926 char srcs6
[INET6_ADDRSTRLEN
], dsts6
[INET6_ADDRSTRLEN
];
1928 char *inOut
= in
? "in" : "out";
1937 case kmDNSTunnelPolicySetup
:
1938 if (type
== kmDNSIPv6IPv4Tunnel
)
1940 if (0 != (err
= v4addr_to_string(src
, srcs
, sizeof(srcs
))))
1942 if (0 != (err
= v4addr_to_string(dst
, dsts
, sizeof(dsts
))))
1944 n
= snprintf(buf
, sizeof(buf
),
1945 "%s ipsec esp/tunnel/%s[%u]-%s[%u]/require",
1946 inOut
, srcs
, src_port
, dsts
, dst_port
);
1948 else if (type
== kmDNSIPv6IPv6Tunnel
)
1950 if (0 != (err
= v6addr_to_string(src6
, srcs6
, sizeof(srcs6
))))
1952 if (0 != (err
= v6addr_to_string(dst6
, dsts6
, sizeof(dsts6
))))
1954 n
= snprintf(buf
, sizeof(buf
),
1955 "%s ipsec esp/tunnel/%s-%s/require",
1956 inOut
, srcs6
, dsts6
);
1959 case kmDNSTunnelPolicyTeardown
:
1960 n
= strlcpy(buf
, inOut
, sizeof(buf
));
1962 case kmDNSTunnelPolicyGenerate
:
1963 n
= snprintf(buf
, sizeof(buf
), "%s generate", inOut
);
1966 err
= kmDNSHelperIPsecPolicyCreationFailed
;
1970 if (n
>= (int)sizeof(buf
))
1972 err
= kmDNSHelperResultTooLarge
;
1976 debug("policy=\"%s\"", buf
);
1977 if (NULL
== (*policy
= (ipsec_policy_t
)ipsec_set_policy(buf
, n
)))
1979 helplog(ASL_LEVEL_ERR
,
1980 "Could not create IPsec policy from \"%s\"", buf
);
1981 err
= kmDNSHelperIPsecPolicyCreationFailed
;
1984 *len
= ((ipsec_policy_t
)(*policy
))->sadb_x_policy_len
* 8;
1991 sendPolicy(int s
, int setup
,
1992 struct sockaddr
*src
, uint8_t src_bits
,
1993 struct sockaddr
*dst
, uint8_t dst_bits
,
1994 ipsec_policy_t policy
, size_t len
)
1996 static unsigned int policySeq
= 0;
1999 debug("entry, setup=%d", setup
);
2001 err
= pfkey_send_spdadd(s
, src
, src_bits
, dst
, dst_bits
, -1,
2002 (char *)policy
, len
, policySeq
++);
2004 err
= pfkey_send_spddelete(s
, src
, src_bits
, dst
, dst_bits
, -1,
2005 (char *)policy
, len
, policySeq
++);
2008 helplog(ASL_LEVEL_ERR
, "Could not set IPsec policy: %s",
2010 err
= kmDNSHelperIPsecPolicySetFailed
;
2022 removeSA(int s
, struct sockaddr
*src
, struct sockaddr
*dst
)
2027 err
= pfkey_send_delete_all(s
, SADB_SATYPE_ESP
, IPSEC_MODE_ANY
, src
, dst
);
2030 helplog(ASL_LEVEL_ERR
, "Could not remove IPsec SA: %s", ipsec_strerror());
2031 err
= kmDNSHelperIPsecRemoveSAFailed
;
2034 err
= pfkey_send_delete_all(s
, SADB_SATYPE_ESP
, IPSEC_MODE_ANY
, dst
, src
);
2037 helplog(ASL_LEVEL_ERR
, "Could not remove IPsec SA: %s", ipsec_strerror());
2038 err
= kmDNSHelperIPsecRemoveSAFailed
;
2051 doTunnelPolicy(mDNSTunnelPolicyWhich which
, mDNSTunnelType type
,
2052 v6addr_t loc_inner
, uint8_t loc_bits
,
2053 v4addr_t loc_outer
, uint16_t loc_port
,
2054 v6addr_t rmt_inner
, uint8_t rmt_bits
,
2055 v4addr_t rmt_outer
, uint16_t rmt_port
,
2056 v6addr_t loc_outer6
, v6addr_t rmt_outer6
)
2058 struct sockaddr_in6 sin6_loc
;
2059 struct sockaddr_in6 sin6_rmt
;
2060 ipsec_policy_t policy
= NULL
;
2066 if (0 > (s
= pfkey_open()))
2068 helplog(ASL_LEVEL_ERR
,
2069 "Could not create IPsec policy socket: %s",
2071 err
= kmDNSHelperIPsecPolicySocketCreationFailed
;
2075 memset(&sin6_loc
, 0, sizeof(sin6_loc
));
2076 sin6_loc
.sin6_len
= sizeof(sin6_loc
);
2077 sin6_loc
.sin6_family
= AF_INET6
;
2078 sin6_loc
.sin6_port
= htons(0);
2079 memcpy(&sin6_loc
.sin6_addr
, loc_inner
, sizeof(sin6_loc
.sin6_addr
));
2081 memset(&sin6_rmt
, 0, sizeof(sin6_rmt
));
2082 sin6_rmt
.sin6_len
= sizeof(sin6_rmt
);
2083 sin6_rmt
.sin6_family
= AF_INET6
;
2084 sin6_rmt
.sin6_port
= htons(0);
2085 memcpy(&sin6_rmt
.sin6_addr
, rmt_inner
, sizeof(sin6_rmt
.sin6_addr
));
2087 int setup
= which
!= kmDNSTunnelPolicyTeardown
;
2089 if (0 != (err
= generateTunnelPolicy(which
, type
, 1,
2090 rmt_outer
, rmt_port
,
2091 loc_outer
, loc_port
,
2092 rmt_outer6
, loc_outer6
,
2095 if (0 != (err
= sendPolicy(s
, setup
,
2096 (struct sockaddr
*)&sin6_rmt
, rmt_bits
,
2097 (struct sockaddr
*)&sin6_loc
, loc_bits
,
2105 if (0 != (err
= generateTunnelPolicy(which
, type
, 0,
2106 loc_outer
, loc_port
,
2107 rmt_outer
, rmt_port
,
2108 loc_outer6
, rmt_outer6
,
2111 if (0 != (err
= sendPolicy(s
, setup
,
2112 (struct sockaddr
*)&sin6_loc
, loc_bits
,
2113 (struct sockaddr
*)&sin6_rmt
, rmt_bits
,
2117 if (which
== kmDNSTunnelPolicyTeardown
)
2119 if (rmt_port
) // Outer tunnel is IPv4
2121 if (loc_outer
&& rmt_outer
)
2123 struct sockaddr_in sin_loc
;
2124 struct sockaddr_in sin_rmt
;
2125 memset(&sin_loc
, 0, sizeof(sin_loc
));
2126 sin_loc
.sin_len
= sizeof(sin_loc
);
2127 sin_loc
.sin_family
= AF_INET
;
2128 memcpy(&sin_loc
.sin_addr
, loc_outer
, sizeof(sin_loc
.sin_addr
));
2130 memset(&sin_rmt
, 0, sizeof(sin_rmt
));
2131 sin_rmt
.sin_len
= sizeof(sin_rmt
);
2132 sin_rmt
.sin_family
= AF_INET
;
2133 memcpy(&sin_rmt
.sin_addr
, rmt_outer
, sizeof(sin_rmt
.sin_addr
));
2134 if (0 != (err
= removeSA(s
, (struct sockaddr
*)&sin_loc
, (struct sockaddr
*)&sin_rmt
)))
2140 if (loc_outer6
&& rmt_outer6
)
2142 struct sockaddr_in6 sin6_lo
;
2143 struct sockaddr_in6 sin6_rm
;
2145 memset(&sin6_lo
, 0, sizeof(sin6_lo
));
2146 sin6_lo
.sin6_len
= sizeof(sin6_lo
);
2147 sin6_lo
.sin6_family
= AF_INET6
;
2148 memcpy(&sin6_lo
.sin6_addr
, loc_outer6
, sizeof(sin6_lo
.sin6_addr
));
2150 memset(&sin6_rm
, 0, sizeof(sin6_rm
));
2151 sin6_rm
.sin6_len
= sizeof(sin6_rm
);
2152 sin6_rm
.sin6_family
= AF_INET6
;
2153 memcpy(&sin6_rm
.sin6_addr
, rmt_outer6
, sizeof(sin6_rm
.sin6_addr
));
2154 if (0 != (err
= removeSA(s
, (struct sockaddr
*)&sin6_lo
, (struct sockaddr
*)&sin6_rm
)))
2171 #endif /* ndef MDNS_NO_IPSEC */
2174 do_mDNSAutoTunnelSetKeys(__unused mach_port_t port
, int replacedelete
,
2175 v6addr_t loc_inner
, v6addr_t loc_outer6
, uint16_t loc_port
,
2176 v6addr_t rmt_inner
, v6addr_t rmt_outer6
, uint16_t rmt_port
,
2177 const char *id
, int *err
, audit_token_t token
)
2179 #ifndef MDNS_NO_IPSEC
2180 static const char config
[] =
2182 "remote %s [%u] {\n"
2183 " disconnect_on_idle idle_timeout 600 idle_direction idle_outbound;\n"
2184 " exchange_mode aggressive;\n"
2186 " situation identity_only;\n"
2187 " verify_identifier off;\n"
2188 " generate_policy on;\n"
2189 " my_identifier user_fqdn \"%s\";\n"
2190 " shared_secret keychain \"%s\";\n"
2192 " lifetime time 15 min;\n"
2193 " initial_contact on;\n"
2194 " support_proxy on;\n"
2195 " nat_traversal force;\n"
2196 " proposal_check claim;\n"
2198 " encryption_algorithm aes;\n"
2199 " hash_algorithm sha1;\n"
2200 " authentication_method pre_shared_key;\n"
2202 " lifetime time 15 min;\n"
2205 "sainfo address %s any address %s any {\n"
2207 " lifetime time 10 min;\n"
2208 " encryption_algorithm aes;\n"
2209 " authentication_algorithm hmac_sha1;\n"
2210 " compression_algorithm deflate;\n"
2212 "sainfo address %s any address %s any {\n"
2214 " lifetime time 10 min;\n"
2215 " encryption_algorithm aes;\n"
2216 " authentication_algorithm hmac_sha1;\n"
2217 " compression_algorithm deflate;\n"
2219 char path
[PATH_MAX
] = "";
2220 char li
[INET6_ADDRSTRLEN
], lo
[INET_ADDRSTRLEN
], lo6
[INET6_ADDRSTRLEN
],
2221 ri
[INET6_ADDRSTRLEN
], ro
[INET_ADDRSTRLEN
], ro6
[INET6_ADDRSTRLEN
];
2224 char tmp_path
[PATH_MAX
] = "";
2225 v4addr_t loc_outer
, rmt_outer
;
2229 if (!authorized(&token
))
2231 *err
= kmDNSHelperNotAuthorized
;
2234 switch ((enum mDNSAutoTunnelSetKeysReplaceDelete
)replacedelete
)
2236 case kmDNSAutoTunnelSetKeysReplace
:
2237 case kmDNSAutoTunnelSetKeysDelete
:
2240 *err
= kmDNSHelperInvalidTunnelSetKeysOperation
;
2244 if (0 != (*err
= v6addr_to_string(loc_inner
, li
, sizeof(li
))))
2246 if (0 != (*err
= v6addr_to_string(rmt_inner
, ri
, sizeof(ri
))))
2249 debug("loc_inner=%s rmt_inner=%s", li
, ri
);
2252 loc_outer
[0] = loc_outer
[1] = loc_outer
[2] = loc_outer
[3] = 0;
2253 rmt_outer
[0] = rmt_outer
[1] = rmt_outer
[2] = rmt_outer
[3] = 0;
2255 if (0 != (*err
= v6addr_to_string(loc_outer6
, lo6
, sizeof(lo6
))))
2257 if (0 != (*err
= v6addr_to_string(rmt_outer6
, ro6
, sizeof(ro6
))))
2259 debug("IPv6 outer tunnel: loc_outer6=%s rmt_outer6=%s", lo6
, ro6
);
2260 if ((int)sizeof(path
) <= snprintf(path
, sizeof(path
),
2261 "%s%s.conf", GetRacoonConfigDir(), ro6
))
2263 *err
= kmDNSHelperResultTooLarge
;
2269 loc_outer
[0] = loc_outer6
[0];
2270 loc_outer
[1] = loc_outer6
[1];
2271 loc_outer
[2] = loc_outer6
[2];
2272 loc_outer
[3] = loc_outer6
[3];
2274 rmt_outer
[0] = rmt_outer6
[0];
2275 rmt_outer
[1] = rmt_outer6
[1];
2276 rmt_outer
[2] = rmt_outer6
[2];
2277 rmt_outer
[3] = rmt_outer6
[3];
2279 if (0 != (*err
= v4addr_to_string(loc_outer
, lo
, sizeof(lo
))))
2281 if (0 != (*err
= v4addr_to_string(rmt_outer
, ro
, sizeof(ro
))))
2283 debug("IPv4 outer tunnel: loc_outer=%s loc_port=%u rmt_outer=%s rmt_port=%u",
2284 lo
, loc_port
, ro
, rmt_port
);
2286 if ((int)sizeof(path
) <= snprintf(path
, sizeof(path
),
2287 "%s%s.%u.conf", GetRacoonConfigDir(), ro
,
2290 *err
= kmDNSHelperResultTooLarge
;
2297 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
)
2299 if (0 > ensureExistenceOfRacoonConfigDir(GetRacoonConfigDir()))
2301 *err
= kmDNSHelperRacoonConfigCreationFailed
;
2304 if ((int)sizeof(tmp_path
) <=
2305 snprintf(tmp_path
, sizeof(tmp_path
), "%s.XXXXXX", path
))
2307 *err
= kmDNSHelperResultTooLarge
;
2310 if (0 > (fd
= mkstemp(tmp_path
)))
2312 helplog(ASL_LEVEL_ERR
, "mkstemp \"%s\" failed: %s",
2313 tmp_path
, strerror(errno
));
2314 *err
= kmDNSHelperRacoonConfigCreationFailed
;
2317 if (NULL
== (fp
= fdopen(fd
, "w")))
2319 helplog(ASL_LEVEL_ERR
, "fdopen: %s",
2321 *err
= kmDNSHelperRacoonConfigCreationFailed
;
2325 fprintf(fp
, config
, configHeader
, (!rmt_port
? ro6
: ro
), rmt_port
, id
, id
, ri
, li
, li
, ri
);
2328 if (0 > rename(tmp_path
, path
))
2330 helplog(ASL_LEVEL_ERR
,
2331 "rename \"%s\" \"%s\" failed: %s",
2332 tmp_path
, path
, strerror(errno
));
2333 *err
= kmDNSHelperRacoonConfigCreationFailed
;
2339 if (0 != unlink(path
))
2340 debug("unlink \"%s\" failed: %s", path
,
2344 if (0 != (*err
= doTunnelPolicy(kmDNSTunnelPolicyTeardown
, kmDNSNoTunnel
,
2345 loc_inner
, kWholeV6Mask
, loc_outer
, loc_port
,
2346 rmt_inner
, kWholeV6Mask
, rmt_outer
, rmt_port
, loc_outer6
, rmt_outer6
)))
2348 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
&&
2349 0 != (*err
= doTunnelPolicy(kmDNSTunnelPolicySetup
, (!rmt_port
? kmDNSIPv6IPv6Tunnel
: kmDNSIPv6IPv4Tunnel
),
2350 loc_inner
, kWholeV6Mask
, loc_outer
, loc_port
,
2351 rmt_inner
, kWholeV6Mask
, rmt_outer
, rmt_port
, loc_outer6
, rmt_outer6
)))
2354 if (0 != (*err
= teardownTunnelRoute(rmt_inner
)))
2356 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
&&
2357 0 != (*err
= setupTunnelRoute(loc_inner
, rmt_inner
)))
2360 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
&&
2361 0 != (*err
= kickRacoon()))
2373 (void)replacedelete
; (void)loc_inner
; (void)loc_outer6
; (void)loc_port
; (void)rmt_inner
;
2374 (void)rmt_outer6
; (void)rmt_port
; (void)id
; (void)token
;
2376 *err
= kmDNSHelperIPsecDisabled
;
2377 #endif /* MDNS_NO_IPSEC */
2378 update_idle_timer();
2379 return KERN_SUCCESS
;
2383 do_mDNSSendWakeupPacket(__unused mach_port_t port
, unsigned ifid
, const char *eth_addr
, const char *ip_addr
, int iteration
, audit_token_t token
)
2387 char ifname
[IFNAMSIZ
];
2390 char bpf_device
[12];
2391 struct ether_addr
*ea
;
2392 (void) ip_addr
; // unused
2393 (void) iteration
; // unused
2394 (void) token
; // unused
2396 if (if_indextoname(ifid
, ifname
) == NULL
)
2398 helplog(ASL_LEVEL_ERR
, "do_mDNSSendWakeupPacket invalid interface index %u", ifid
);
2402 ea
= ether_aton(eth_addr
);
2405 helplog(ASL_LEVEL_ERR
, "do_mDNSSendWakeupPacket invalid ethernet address %s", eth_addr
);
2409 for (i
= 0; i
< 100; i
++)
2411 snprintf(bpf_device
, sizeof(bpf_device
), "/dev/bpf%d", i
);
2412 bpf_fd
= open(bpf_device
, O_RDWR
, 0);
2420 helplog(ASL_LEVEL_ERR
, "do_mDNSSendWakeupPacket cannot find a bpf device");
2424 memset(&ifr
, 0, sizeof(ifr
));
2425 strlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
2427 if (ioctl(bpf_fd
, BIOCSETIF
, (char *)&ifr
) < 0)
2429 helplog(ASL_LEVEL_ERR
, "do_mDNSSendWakeupPacket BIOCSETIF failed %s", strerror(errno
));
2433 // 0x00 Destination address
2434 for (i
=0; i
<6; i
++) *ptr
++ = ea
->octet
[i
];
2436 // 0x06 Source address (Note: Since we don't currently set the BIOCSHDRCMPLT option, BPF will fill in the real interface address for us)
2437 for (i
=0; i
<6; i
++) *ptr
++ = 0;
2439 // 0x0C Ethertype (0x0842)
2443 // 0x0E Wakeup sync sequence
2444 for (i
=0; i
<6; i
++) *ptr
++ = 0xFF;
2447 for (j
=0; j
<16; j
++) for (i
=0; i
<6; i
++) *ptr
++ = ea
->octet
[i
];
2450 for (i
=0; i
<6; i
++) *ptr
++ = 0;
2452 if (write(bpf_fd
, packet
, ptr
- packet
) < 0)
2454 helplog(ASL_LEVEL_ERR
, "do_mDNSSendWakeupPacket write failed %s", strerror(errno
));
2457 helplog(ASL_LEVEL_INFO
, "do_mDNSSendWakeupPacket sent unicast eth_addr %s, ip_addr %s", eth_addr
, ip_addr
);
2458 // Send a broadcast one to handle ethernet switches that don't flood forward packets with
2459 // unknown mac addresses.
2460 for (i
=0; i
<6; i
++) packet
[i
] = 0xFF;
2461 if (write(bpf_fd
, packet
, ptr
- packet
) < 0)
2463 helplog(ASL_LEVEL_ERR
, "do_mDNSSendWakeupPacket write failed %s", strerror(errno
));
2466 helplog(ASL_LEVEL_INFO
, "do_mDNSSendWakeupPacket sent broadcast eth_addr %s, ip_addr %s", eth_addr
, ip_addr
);
2468 return KERN_SUCCESS
;
2471 // Open the specified port for protocol in the P2P firewall.
2473 do_mDNSPacketFilterControl(__unused mach_port_t port
, uint32_t command
, const char * ifname
, uint16_t servicePort
, uint16_t protocol
, audit_token_t token
)
2475 (void) token
; // unused
2477 kern_return_t result
= KERN_SUCCESS
;
2479 helplog(ASL_LEVEL_INFO
, "do_mDNSPacketFilterControl: command %d ifname %s, servicePort 0x%x, protocol %d",
2480 command
, ifname
, servicePort
, protocol
);
2485 error
= P2PPacketFilterAddBonjourRuleSet(ifname
, servicePort
, protocol
);
2488 helplog(ASL_LEVEL_ERR
, "P2PPacketFilterAddBonjourRuleSet failed %s", strerror(error
));
2489 result
= KERN_FAILURE
;
2493 case PF_CLEAR_RULES
:
2494 error
= P2PPacketFilterClearBonjourRules();
2497 helplog(ASL_LEVEL_ERR
, "P2PPacketFilterClearBonjourRules failed %s", strerror(error
));
2498 result
= KERN_FAILURE
;
2503 helplog(ASL_LEVEL_ERR
, "do_mDNSPacketFilterControl: invalid command %d", command
);
2504 result
= KERN_INVALID_ARGUMENT
;