1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2007-2012 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/SCPreferencesSetSpecific.h>
46 #include <TargetConditionals.h>
47 #include <IOKit/pwr_mgt/IOPMLib.h>
49 #include <sys/sysctl.h>
51 #include "mDNSEmbeddedAPI.h"
53 #include "dnssd_ipc.h"
56 #include "helpermsgServer.h"
57 #include "helper-server.h"
58 #include "ipsec_options.h"
59 #include "P2PPacketFilter.h"
61 #include <netinet/ip.h>
62 #include <netinet/tcp.h>
65 #define RTF_IFSCOPE 0x1000000
68 #if TARGET_OS_EMBEDDED
70 #define MDNS_NO_IPSEC 1
72 #define NO_CFUSERNOTIFICATION 1
73 #define NO_SECURITYFRAMEWORK 1
76 // Embed the client stub code here, so we can access private functions like ConnectToServer, create_hdr, deliver_request
77 #include "../mDNSShared/dnssd_ipc.c"
78 #include "../mDNSShared/dnssd_clientstub.c"
80 typedef struct sadb_x_policy
*ipsec_policy_t
;
82 unsigned short InetChecksum(unsigned short *ptr
,int nbytes
);
83 unsigned long in_cksum(unsigned short *ptr
,int nbytes
);
84 void TCPCheckSum(int af
, struct tcphdr
*t
, int tcplen
, v6addr_t sadd6
, v6addr_t dadd6
);
86 uid_t mDNSResponderUID
;
87 gid_t mDNSResponderGID
;
90 debug_(const char *func
, const char *fmt
, ...)
96 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
98 helplog(ASL_LEVEL_DEBUG
, "%s: %s", func
, buf
);
102 authorized(audit_token_t
*token
)
105 pid_t pid
= (pid_t
)-1;
106 uid_t euid
= (uid_t
)-1;
108 audit_token_to_au32(*token
, NULL
, &euid
, NULL
, NULL
, NULL
, &pid
, NULL
,
110 ok
= (euid
== mDNSResponderUID
|| euid
== 0);
112 helplog(ASL_LEVEL_NOTICE
,
113 "Unauthorized access by euid=%lu pid=%lu",
114 (unsigned long)euid
, (unsigned long)pid
);
119 do_mDNSExit(__unused mach_port_t port
, audit_token_t token
)
122 if (!authorized(&token
))
124 helplog(ASL_LEVEL_INFO
, "exit");
132 kern_return_t
do_mDNSRequestBPF(__unused mach_port_t port
, audit_token_t token
)
134 if (!authorized(&token
)) return KERN_SUCCESS
;
136 DNSServiceErrorType err
= ConnectToServer(&ref
, 0, send_bpf
, NULL
, NULL
, NULL
);
137 if (err
) { helplog(ASL_LEVEL_ERR
, "do_mDNSRequestBPF: ConnectToServer %d", err
); return err
; }
140 size_t len
= sizeof(DNSServiceFlags
);
141 ipc_msg_hdr
*hdr
= create_hdr(send_bpf
, &len
, &ptr
, 0, ref
);
142 if (!hdr
) { DNSServiceRefDeallocate(ref
); return kDNSServiceErr_NoMemory
; }
144 deliver_request(hdr
, ref
); // Will free hdr for us
145 DNSServiceRefDeallocate(ref
);
150 kern_return_t
do_mDNSPowerRequest(__unused mach_port_t port
, int key
, int interval
, int *err
, audit_token_t token
)
153 if (!authorized(&token
)) { *err
= kmDNSHelperNotAuthorized
; goto fin
; }
155 CFArrayRef events
= IOPMCopyScheduledPowerEvents();
159 CFIndex count
= CFArrayGetCount(events
);
160 for (i
=0; i
<count
; i
++)
162 CFDictionaryRef dict
= CFArrayGetValueAtIndex(events
, i
);
163 CFStringRef id
= CFDictionaryGetValue(dict
, CFSTR(kIOPMPowerEventAppNameKey
));
164 if (CFEqual(id
, CFSTR("mDNSResponderHelper")))
166 CFDateRef EventTime
= CFDictionaryGetValue(dict
, CFSTR(kIOPMPowerEventTimeKey
));
167 CFStringRef EventType
= CFDictionaryGetValue(dict
, CFSTR(kIOPMPowerEventTypeKey
));
168 IOReturn result
= IOPMCancelScheduledPowerEvent(EventTime
, id
, EventType
);
169 //helplog(ASL_LEVEL_ERR, "Deleting old event %s");
170 if (result
) helplog(ASL_LEVEL_ERR
, "IOPMCancelScheduledPowerEvent %d failed %d", i
, result
);
176 if (key
< 0) // mDNSPowerRequest(-1,-1) means "clear any stale schedules" (see above)
178 else if (key
== 0) // mDNSPowerRequest(0, 0) means "sleep now"
180 IOReturn r
= IOPMSleepSystem(IOPMFindPowerManagement(MACH_PORT_NULL
));
181 if (r
) { usleep(100000); helplog(ASL_LEVEL_ERR
, "IOPMSleepSystem %d", r
); }
186 CFDateRef w
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent() + interval
);
189 IOReturn r
= IOPMSchedulePowerEvent(w
, CFSTR("mDNSResponderHelper"), key
? CFSTR(kIOPMAutoWake
) : CFSTR(kIOPMAutoSleep
));
190 if (r
) { usleep(100000); helplog(ASL_LEVEL_ERR
, "IOPMSchedulePowerEvent(%d) %d %x", interval
, r
, r
); }
200 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
)
202 #define IPv6FMTSTRING "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X"
203 #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]
206 helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry %d IPv%d %d.%d.%d.%d %02X:%02X:%02X:%02X:%02X:%02X",
207 ifindex
, family
, ip
[0], ip
[1], ip
[2], ip
[3], eth
[0], eth
[1], eth
[2], eth
[3], eth
[4], eth
[5]);
209 helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry %d IPv%d " IPv6FMTSTRING
" %02X:%02X:%02X:%02X:%02X:%02X",
210 ifindex
, family
, IPv6FMTARGS
, eth
[0], eth
[1], eth
[2], eth
[3], eth
[4], eth
[5]);
214 if (!authorized(&token
)) { *err
= kmDNSHelperNotAuthorized
; goto fin
; }
216 static int s
= -1, seq
= 0;
219 s
= socket(PF_ROUTE
, SOCK_RAW
, 0);
220 if (s
< 0) helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry: socket(PF_ROUTE, SOCK_RAW, 0) failed %d (%s)", errno
, strerror(errno
));
226 gettimeofday(&tv
, 0);
229 struct { struct rt_msghdr hdr
; struct sockaddr_inarp dst
; struct sockaddr_dl sdl
; } rtmsg
;
230 memset(&rtmsg
, 0, sizeof(rtmsg
));
232 rtmsg
.hdr
.rtm_msglen
= sizeof(rtmsg
);
233 rtmsg
.hdr
.rtm_version
= RTM_VERSION
;
234 rtmsg
.hdr
.rtm_type
= RTM_ADD
;
235 rtmsg
.hdr
.rtm_index
= ifindex
;
236 rtmsg
.hdr
.rtm_flags
= RTF_HOST
| RTF_STATIC
| RTF_IFSCOPE
;
237 rtmsg
.hdr
.rtm_addrs
= RTA_DST
| RTA_GATEWAY
;
238 rtmsg
.hdr
.rtm_pid
= 0;
239 rtmsg
.hdr
.rtm_seq
= seq
++;
240 rtmsg
.hdr
.rtm_errno
= 0;
241 rtmsg
.hdr
.rtm_use
= 0;
242 rtmsg
.hdr
.rtm_inits
= RTV_EXPIRE
;
243 rtmsg
.hdr
.rtm_rmx
.rmx_expire
= tv
.tv_sec
+ 30;
245 rtmsg
.dst
.sin_len
= sizeof(rtmsg
.dst
);
246 rtmsg
.dst
.sin_family
= AF_INET
;
247 rtmsg
.dst
.sin_port
= 0;
248 rtmsg
.dst
.sin_addr
.s_addr
= *(in_addr_t
*)ip
;
249 rtmsg
.dst
.sin_srcaddr
.s_addr
= 0;
250 rtmsg
.dst
.sin_tos
= 0;
251 rtmsg
.dst
.sin_other
= 0;
253 rtmsg
.sdl
.sdl_len
= sizeof(rtmsg
.sdl
);
254 rtmsg
.sdl
.sdl_family
= AF_LINK
;
255 rtmsg
.sdl
.sdl_index
= ifindex
;
256 rtmsg
.sdl
.sdl_type
= IFT_ETHER
;
257 rtmsg
.sdl
.sdl_nlen
= 0;
258 rtmsg
.sdl
.sdl_alen
= ETHER_ADDR_LEN
;
259 rtmsg
.sdl
.sdl_slen
= 0;
261 // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h)
262 memcpy(rtmsg
.sdl
.sdl_data
, eth
, sizeof(ethaddr_t
));
264 int len
= write(s
, (char *)&rtmsg
, sizeof(rtmsg
));
266 helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry: write(%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s)",
267 sizeof(rtmsg
), ifindex
, ip
[0], ip
[1], ip
[2], ip
[3], rtmsg
.hdr
.rtm_seq
, len
, errno
, strerror(errno
));
268 len
= read(s
, (char *)&rtmsg
, sizeof(rtmsg
));
269 if (len
< 0 || rtmsg
.hdr
.rtm_errno
)
270 helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry: read (%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s) %d",
271 sizeof(rtmsg
), ifindex
, ip
[0], ip
[1], ip
[2], ip
[3], rtmsg
.hdr
.rtm_seq
, len
, errno
, strerror(errno
), rtmsg
.hdr
.rtm_errno
);
277 struct { struct rt_msghdr hdr
; struct sockaddr_in6 dst
; struct sockaddr_dl sdl
; } rtmsg
;
278 memset(&rtmsg
, 0, sizeof(rtmsg
));
280 rtmsg
.hdr
.rtm_msglen
= sizeof(rtmsg
);
281 rtmsg
.hdr
.rtm_version
= RTM_VERSION
;
282 rtmsg
.hdr
.rtm_type
= RTM_ADD
;
283 rtmsg
.hdr
.rtm_index
= ifindex
;
284 rtmsg
.hdr
.rtm_flags
= RTF_HOST
| RTF_STATIC
| RTF_IFSCOPE
;
285 rtmsg
.hdr
.rtm_addrs
= RTA_DST
| RTA_GATEWAY
;
286 rtmsg
.hdr
.rtm_pid
= 0;
287 rtmsg
.hdr
.rtm_seq
= seq
++;
288 rtmsg
.hdr
.rtm_errno
= 0;
289 rtmsg
.hdr
.rtm_use
= 0;
290 rtmsg
.hdr
.rtm_inits
= RTV_EXPIRE
;
291 rtmsg
.hdr
.rtm_rmx
.rmx_expire
= tv
.tv_sec
+ 30;
293 rtmsg
.dst
.sin6_len
= sizeof(rtmsg
.dst
);
294 rtmsg
.dst
.sin6_family
= AF_INET6
;
295 rtmsg
.dst
.sin6_port
= 0;
296 rtmsg
.dst
.sin6_flowinfo
= 0;
297 rtmsg
.dst
.sin6_addr
= *(struct in6_addr
*)ip
;
298 rtmsg
.dst
.sin6_scope_id
= ifindex
;
300 rtmsg
.sdl
.sdl_len
= sizeof(rtmsg
.sdl
);
301 rtmsg
.sdl
.sdl_family
= AF_LINK
;
302 rtmsg
.sdl
.sdl_index
= ifindex
;
303 rtmsg
.sdl
.sdl_type
= IFT_ETHER
;
304 rtmsg
.sdl
.sdl_nlen
= 0;
305 rtmsg
.sdl
.sdl_alen
= ETHER_ADDR_LEN
;
306 rtmsg
.sdl
.sdl_slen
= 0;
308 // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h)
309 memcpy(rtmsg
.sdl
.sdl_data
, eth
, sizeof(ethaddr_t
));
311 int len
= write(s
, (char *)&rtmsg
, sizeof(rtmsg
));
313 helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry: write(%d) interface %d address " IPv6FMTSTRING
" seq %d result %d errno %d (%s)",
314 sizeof(rtmsg
), ifindex
, IPv6FMTARGS
, rtmsg
.hdr
.rtm_seq
, len
, errno
, strerror(errno
));
315 len
= read(s
, (char *)&rtmsg
, sizeof(rtmsg
));
316 if (len
< 0 || rtmsg
.hdr
.rtm_errno
)
317 helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry: read (%d) interface %d address " IPv6FMTSTRING
" seq %d result %d errno %d (%s) %d",
318 sizeof(rtmsg
), ifindex
, IPv6FMTARGS
, rtmsg
.hdr
.rtm_seq
, len
, errno
, strerror(errno
), rtmsg
.hdr
.rtm_errno
);
330 kern_return_t
do_mDNSNotify(__unused mach_port_t port
, const char *title
, const char *msg
, audit_token_t token
)
332 if (!authorized(&token
)) return KERN_SUCCESS
;
334 #ifndef NO_CFUSERNOTIFICATION
335 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.)";
336 CFStringRef alertHeader
= CFStringCreateWithCString(NULL
, title
, kCFStringEncodingUTF8
);
337 CFStringRef alertBody
= CFStringCreateWithCString(NULL
, msg
, kCFStringEncodingUTF8
);
338 CFStringRef alertFooter
= CFStringCreateWithCString(NULL
, footer
, kCFStringEncodingUTF8
);
339 CFStringRef alertMessage
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@\r\r%@"), alertBody
, alertFooter
);
340 CFRelease(alertBody
);
341 CFRelease(alertFooter
);
342 int err
= CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel
, NULL
, NULL
, NULL
, alertHeader
, alertMessage
, NULL
);
343 if (err
) helplog(ASL_LEVEL_ERR
, "CFUserNotificationDisplayNotice returned %d", err
);
344 CFRelease(alertHeader
);
345 CFRelease(alertMessage
);
349 #endif /* NO_CFUSERNOTIFICATION */
355 char usercompname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last computer name the user saw
356 char userhostname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last local host name the user saw
357 char lastcompname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last computer name saved to preferences
358 char lasthostname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last local host name saved to preferences
360 #ifndef NO_CFUSERNOTIFICATION
361 static CFStringRef CFS_OQ
= NULL
;
362 static CFStringRef CFS_CQ
= NULL
;
363 static CFStringRef CFS_Format
= NULL
;
364 static CFStringRef CFS_ComputerName
= NULL
;
365 static CFStringRef CFS_ComputerNameMsg
= NULL
;
366 static CFStringRef CFS_LocalHostName
= NULL
;
367 static CFStringRef CFS_LocalHostNameMsg
= NULL
;
368 static CFStringRef CFS_Problem
= NULL
;
370 static CFUserNotificationRef gNotification
= NULL
;
371 static CFRunLoopSourceRef gNotificationRLS
= NULL
;
373 static void NotificationCallBackDismissed(CFUserNotificationRef userNotification
, CFOptionFlags responseFlags
)
376 (void)responseFlags
; // Unused
377 if (userNotification
!= gNotification
) helplog(ASL_LEVEL_ERR
, "NotificationCallBackDismissed: Wrong CFUserNotificationRef");
378 if (gNotificationRLS
)
380 // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
381 // We need to explicitly specify the desired CFRunLoop from which we want to remove this event source.
382 CFRunLoopRemoveSource(gRunLoop
, gNotificationRLS
, kCFRunLoopDefaultMode
);
383 CFRelease(gNotificationRLS
);
384 gNotificationRLS
= NULL
;
385 CFRelease(gNotification
);
386 gNotification
= NULL
;
388 // By dismissing the alert, the user has conceptually acknowleged the rename.
389 // (e.g. the machine's name is now officially "computer-2.local", not "computer.local".)
390 // If we get *another* conflict, the new alert should refer to the 'old' name
391 // as now being "computer-2.local", not "computer.local"
397 unpause_idle_timer();
400 static void ShowNameConflictNotification(CFMutableArrayRef header
, CFStringRef subtext
)
402 CFMutableDictionaryRef dictionary
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
403 if (!dictionary
) return;
407 CFDictionarySetValue(dictionary
, kCFUserNotificationAlertHeaderKey
, header
);
408 CFDictionarySetValue(dictionary
, kCFUserNotificationAlertMessageKey
, subtext
);
410 CFURLRef urlRef
= CFURLCreateWithFileSystemPath(NULL
, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle
, true);
411 if (urlRef
) { CFDictionarySetValue(dictionary
, kCFUserNotificationLocalizationURLKey
, urlRef
); CFRelease(urlRef
); }
413 if (gNotification
) // If notification already on-screen, update it in place
414 CFUserNotificationUpdate(gNotification
, 0, kCFUserNotificationCautionAlertLevel
, dictionary
);
415 else // else, we need to create it
418 gNotification
= CFUserNotificationCreate(NULL
, 0, kCFUserNotificationCautionAlertLevel
, &error
, dictionary
);
419 if (!gNotification
|| error
) { helplog(ASL_LEVEL_ERR
, "ShowNameConflictNotification: CFUserNotificationRef: Error %d", error
); return; }
420 gNotificationRLS
= CFUserNotificationCreateRunLoopSource(NULL
, gNotification
, NotificationCallBackDismissed
, 0);
421 if (!gNotificationRLS
) { helplog(ASL_LEVEL_ERR
,"ShowNameConflictNotification: RLS"); CFRelease(gNotification
); gNotification
= NULL
; return; }
422 // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
423 // We need to explicitly specify the desired CFRunLoop to which we want to add this event source.
424 CFRunLoopAddSource(gRunLoop
, gNotificationRLS
, kCFRunLoopDefaultMode
);
425 debug("gRunLoop=%p gNotification=%p gNotificationRLS=%p", gRunLoop
, gNotification
, gNotificationRLS
);
429 CFRelease(dictionary
);
432 static CFMutableArrayRef
GetHeader(const char* oldname
, const char* newname
, const CFStringRef msg
, const char* suffix
)
434 CFMutableArrayRef alertHeader
= NULL
;
436 const CFStringRef cfoldname
= CFStringCreateWithCString(NULL
, oldname
, kCFStringEncodingUTF8
);
437 // NULL newname means we've given up trying to construct a name that doesn't conflict
438 const CFStringRef cfnewname
= newname
? CFStringCreateWithCString(NULL
, newname
, kCFStringEncodingUTF8
) : NULL
;
439 // We tag a zero-width non-breaking space at the end of the literal text to guarantee that, no matter what
440 // arbitrary computer name the user may choose, this exact text (with zero-width non-breaking space added)
441 // can never be one that occurs in the Localizable.strings translation file.
443 helplog(ASL_LEVEL_ERR
,"Could not construct CFStrings for old=%s", newname
);
444 else if (newname
&& !cfnewname
)
445 helplog(ASL_LEVEL_ERR
,"Could not construct CFStrings for new=%s", newname
);
448 const CFStringRef s1
= CFStringCreateWithFormat(NULL
, NULL
, CFS_Format
, cfoldname
, suffix
);
449 const CFStringRef s2
= cfnewname
? CFStringCreateWithFormat(NULL
, NULL
, CFS_Format
, cfnewname
, suffix
) : NULL
;
451 alertHeader
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
454 helplog(ASL_LEVEL_ERR
, "Could not construct secondary CFString for old=%s", oldname
);
455 else if (cfnewname
&& !s2
)
456 helplog(ASL_LEVEL_ERR
, "Could not construct secondary CFString for new=%s", newname
);
457 else if (!alertHeader
)
458 helplog(ASL_LEVEL_ERR
, "Could not construct CFArray for notification");
461 // Make sure someone is logged in. We don't want this popping up over the login window
464 CFStringRef userName
= SCDynamicStoreCopyConsoleUser(NULL
, &uid
, &gid
);
468 CFArrayAppendValue(alertHeader
, msg
); // Opening phrase of message, provided by caller
469 CFArrayAppendValue(alertHeader
, CFS_OQ
); CFArrayAppendValue(alertHeader
, s1
); CFArrayAppendValue(alertHeader
, CFS_CQ
);
470 CFArrayAppendValue(alertHeader
, CFSTR(" is already in use on this network. "));
473 CFArrayAppendValue(alertHeader
, CFSTR("The name has been changed to "));
474 CFArrayAppendValue(alertHeader
, CFS_OQ
); CFArrayAppendValue(alertHeader
, s2
); CFArrayAppendValue(alertHeader
, CFS_CQ
);
475 CFArrayAppendValue(alertHeader
, CFSTR("."));
478 CFArrayAppendValue(alertHeader
, CFSTR("All attempts to find an available name by adding a number to the name were also unsuccessful."));
481 if (s1
) CFRelease(s1
);
482 if (s2
) CFRelease(s2
);
484 if (cfoldname
) CFRelease(cfoldname
);
485 if (cfnewname
) CFRelease(cfnewname
);
489 #endif /* ndef NO_CFUSERNOTIFICATION */
491 static void update_notification(void)
493 #ifndef NO_CFUSERNOTIFICATION
494 debug("entry ucn=%s, uhn=%s, lcn=%s, lhn=%s", usercompname
, userhostname
, lastcompname
, lasthostname
);
497 // 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.
498 // By appending this invisible character on the end of literal names, we ensure the these strings cannot inadvertently match any string
499 // in the localization file -- since we know for sure that none of our strings in the localization file contain the ZWNBS character.
501 // For languages that are written right to left, when we mix English (host names could be in english with brackets etc. and the
502 // rest in Arabic) we need unicode markups for proper formatting. The Unicode sequence 202C (UTF8 E2 80 AC), 200E (UTF8 E2 80 8E) and
503 // 202B (UTF8 E2 80 AB) helps with the formatting. See <rdar://problem/8629082> for more details.
504 CFS_OQ
= CFStringCreateWithCString(NULL
, "“\xE2\x80\xAB", kCFStringEncodingUTF8
);
505 CFS_CQ
= CFStringCreateWithCString(NULL
, "\xE2\x80\xAC”", kCFStringEncodingUTF8
);
506 CFS_Format
= CFStringCreateWithCString(NULL
, "%@%s\xEF\xBB\xBF\xE2\x80\x8E", kCFStringEncodingUTF8
);
507 CFS_ComputerName
= CFStringCreateWithCString(NULL
, "The name of your computer ", kCFStringEncodingUTF8
);
508 CFS_ComputerNameMsg
= CFStringCreateWithCString(NULL
, "To change the name of your computer, "
509 "open System Preferences and click Sharing, then type the name in the Computer Name field.", kCFStringEncodingUTF8
);
510 CFS_LocalHostName
= CFStringCreateWithCString(NULL
, "This computer’s local hostname ", kCFStringEncodingUTF8
);
511 CFS_LocalHostNameMsg
= CFStringCreateWithCString(NULL
, "To change the local hostname, "
512 "open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field.", kCFStringEncodingUTF8
);
513 CFS_Problem
= CFStringCreateWithCString(NULL
, "This may indicate a problem with the local network. "
514 "Please inform your network administrator.", kCFStringEncodingUTF8
);
517 if (!usercompname
[0] && !userhostname
[0])
519 if (gNotificationRLS
)
521 debug("canceling notification %p", gNotification
);
522 CFUserNotificationCancel(gNotification
);
523 unpause_idle_timer();
528 CFMutableArrayRef header
= NULL
;
529 CFStringRef
* subtext
= NULL
;
530 if (userhostname
[0] && !lasthostname
[0]) // we've given up trying to construct a name that doesn't conflict
532 header
= GetHeader(userhostname
, NULL
, CFS_LocalHostName
, ".local");
533 subtext
= &CFS_Problem
;
535 else if (usercompname
[0])
537 header
= GetHeader(usercompname
, lastcompname
, CFS_ComputerName
, "");
538 subtext
= &CFS_ComputerNameMsg
;
542 header
= GetHeader(userhostname
, lasthostname
, CFS_LocalHostName
, ".local");
543 subtext
= &CFS_LocalHostNameMsg
;
545 ShowNameConflictNotification(header
, *subtext
);
552 do_mDNSPreferencesSetName(__unused mach_port_t port
, int key
, const char* old
, const char* new, audit_token_t token
)
554 SCPreferencesRef session
= NULL
;
556 Boolean locked
= FALSE
;
557 CFStringRef cfstr
= NULL
;
560 Boolean needUpdate
= FALSE
;
562 debug("entry %s old=%s new=%s", key
==kmDNSComputerName
? "ComputerName" : (key
==kmDNSLocalHostName
? "LocalHostName" : "UNKNOWN"), old
, new);
563 if (!authorized(&token
)) goto fin
;
565 switch ((enum mDNSPreferencesSetNameKey
)key
)
567 case kmDNSComputerName
:
571 case kmDNSLocalHostName
:
576 debug("unrecognized key: %d", key
);
582 helplog(ASL_LEVEL_ERR
, "%s: no last ptr", __func__
);
588 helplog(ASL_LEVEL_ERR
, "%s: no user ptr", __func__
);
592 if (0 == strncmp(old
, new, MAX_DOMAIN_LABEL
+1))
594 // old and new are same means the config changed i.e, the user has set something in the preferences pane.
595 // This means the conflict has been resolved. We need to dismiss the dialogue.
596 if (last
[0] && 0 != strncmp(last
, new, MAX_DOMAIN_LABEL
+1))
606 // old and new are not same, this means there is a conflict. For the first conflict, we show
607 // the old value and the new value. For all subsequent conflicts, while the dialogue is still
608 // up, we do a real time update of the "new" value in the dialogue. That's why we update just
609 // "last" here and not "user".
610 if (strncmp(last
, new, MAX_DOMAIN_LABEL
+1))
612 strncpy(last
, new, MAX_DOMAIN_LABEL
);
617 // If we are not showing the dialogue, we need to remember the first "old" value so that
618 // we maintain the same through the lifetime of the dialogue. Subsequence conflicts don't
619 // update the "old" value.
622 strncpy(user
, old
, MAX_DOMAIN_LABEL
);
626 if (!new[0]) // we've given up trying to construct a name that doesn't conflict
629 cfstr
= CFStringCreateWithCString(NULL
, new, kCFStringEncodingUTF8
);
631 session
= SCPreferencesCreate(NULL
, CFSTR(kmDNSHelperServiceName
), NULL
);
633 if (cfstr
== NULL
|| session
== NULL
)
635 debug("SCPreferencesCreate failed");
638 if (!SCPreferencesLock(session
, 0))
640 debug("lock failed");
645 switch ((enum mDNSPreferencesSetNameKey
)key
)
647 case kmDNSComputerName
:
649 // We want to write the new Computer Name to System Preferences, without disturbing the user-selected
650 // system-wide default character set used for things like AppleTalk NBP and NETBIOS service advertising.
651 // Note that this encoding is not used for the computer name, but since both are set by the same call,
652 // we need to take care to set the name without changing the character set.
653 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
654 CFStringRef unused
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
655 if (unused
) { CFRelease(unused
); unused
= NULL
; }
656 else encoding
= kCFStringEncodingUTF8
;
658 ok
= SCPreferencesSetComputerName(session
, cfstr
, encoding
);
661 case kmDNSLocalHostName
:
662 ok
= SCPreferencesSetLocalHostName(session
, cfstr
);
668 if (!ok
|| !SCPreferencesCommitChanges(session
) ||
669 !SCPreferencesApplyChanges(session
))
671 debug("SCPreferences update failed");
682 SCPreferencesUnlock(session
);
686 if (needUpdate
) update_notification();
692 formatNotDNSKey
, formatDdnsTypeItem
, formatDnsPrefixedServiceItem
, formatBtmmPrefixedServiceItem
695 // On Mac OS X on Intel, the four-character string seems to be stored backwards, at least sometimes.
696 // I suspect some overenthusiastic inexperienced engineer said, "On Intel everything's backwards,
697 // therefore I need to add some byte swapping in this API to make this four-character string backwards too."
698 // To cope with this we allow *both* "ddns" and "sndd" as valid item types.
701 #ifndef NO_SECURITYFRAMEWORK
702 static const char btmmprefix
[] = "btmmdns:";
703 static const char dnsprefix
[] = "dns:";
704 static const char ddns
[] = "ddns";
705 static const char ddnsrev
[] = "sndd";
707 static enum DNSKeyFormat
708 getDNSKeyFormat(SecKeychainItemRef item
, SecKeychainAttributeList
**attributesp
)
710 static UInt32 tags
[4] =
712 kSecTypeItemAttr
, kSecServiceItemAttr
, kSecAccountItemAttr
, kSecLabelItemAttr
714 static SecKeychainAttributeInfo attributeInfo
=
716 sizeof(tags
)/sizeof(tags
[0]), tags
, NULL
718 SecKeychainAttributeList
*attributes
= NULL
;
719 enum DNSKeyFormat format
;
720 Boolean malformed
= FALSE
;
721 OSStatus status
= noErr
;
725 if (noErr
!= (status
= SecKeychainItemCopyAttributesAndData(item
,
726 &attributeInfo
, NULL
, &attributes
, NULL
, NULL
)))
728 debug("SecKeychainItemCopyAttributesAndData %d - skipping",
732 if (attributeInfo
.count
!= attributes
->count
)
734 for (i
= 0; !malformed
&& i
< (int)attributeInfo
.count
; ++i
)
735 if (attributeInfo
.tag
[i
] != attributes
->attr
[i
].tag
)
740 "malformed result from SecKeychainItemCopyAttributesAndData - skipping");
744 debug("entry (\"%.*s\", \"%.*s\", \"%.*s\")",
745 (int)attributes
->attr
[0].length
, attributes
->attr
[0].data
,
746 (int)attributes
->attr
[1].length
, attributes
->attr
[1].data
,
747 (int)attributes
->attr
[2].length
, attributes
->attr
[2].data
);
748 if (attributes
->attr
[1].length
>= MAX_ESCAPED_DOMAIN_NAME
+
751 debug("kSecServiceItemAttr too long (%u) - skipping",
752 (unsigned int)attributes
->attr
[1].length
);
755 if (attributes
->attr
[2].length
>= MAX_ESCAPED_DOMAIN_NAME
)
757 debug("kSecAccountItemAttr too long (%u) - skipping",
758 (unsigned int)attributes
->attr
[2].length
);
761 if (attributes
->attr
[1].length
>= sizeof(dnsprefix
)-1 &&
762 0 == strncasecmp(attributes
->attr
[1].data
, dnsprefix
,
763 sizeof(dnsprefix
)-1))
764 format
= formatDnsPrefixedServiceItem
;
765 else if (attributes
->attr
[1].length
>= sizeof(btmmprefix
)-1 &&
766 0 == strncasecmp(attributes
->attr
[1].data
, btmmprefix
, sizeof(btmmprefix
)-1))
767 format
= formatBtmmPrefixedServiceItem
;
768 else if (attributes
->attr
[0].length
== sizeof(ddns
)-1 &&
769 0 == strncasecmp(attributes
->attr
[0].data
, ddns
, sizeof(ddns
)-1))
770 format
= formatDdnsTypeItem
;
771 else if (attributes
->attr
[0].length
== sizeof(ddnsrev
)-1 &&
772 0 == strncasecmp(attributes
->attr
[0].data
, ddnsrev
, sizeof(ddnsrev
)-1))
773 format
= formatDdnsTypeItem
;
776 debug("uninterested in this entry");
779 *attributesp
= attributes
;
780 debug("accepting this entry");
784 SecKeychainItemFreeAttributesAndData(attributes
, NULL
);
785 return formatNotDNSKey
;
788 // Insert the attributes as defined by mDNSKeyChainAttributes
789 static CFPropertyListRef
790 getKeychainItemInfo(SecKeychainItemRef item
,
791 SecKeychainAttributeList
*attributes
, enum DNSKeyFormat format
)
793 CFMutableArrayRef entry
= NULL
;
794 CFDataRef data
= NULL
;
795 OSStatus status
= noErr
;
799 if (NULL
== (entry
= CFArrayCreateMutable(NULL
, 0,
800 &kCFTypeArrayCallBacks
)))
802 debug("CFArrayCreateMutable failed");
806 // Insert the Account attribute (kmDNSKcWhere)
807 switch ((enum DNSKeyFormat
)format
)
809 case formatDdnsTypeItem
:
810 data
= CFDataCreate(kCFAllocatorDefault
,
811 attributes
->attr
[1].data
, attributes
->attr
[1].length
);
813 case formatDnsPrefixedServiceItem
:
814 case formatBtmmPrefixedServiceItem
:
815 data
= CFDataCreate(kCFAllocatorDefault
,
816 attributes
->attr
[1].data
, attributes
->attr
[1].length
);
819 assert("unknown DNSKeyFormat value");
824 debug("CFDataCreate for attr[1] failed");
827 CFArrayAppendValue(entry
, data
);
830 // Insert the Where attribute (kmDNSKcAccount)
831 if (NULL
== (data
= CFDataCreate(kCFAllocatorDefault
,
832 attributes
->attr
[2].data
, attributes
->attr
[2].length
)))
834 debug("CFDataCreate for attr[2] failed");
837 CFArrayAppendValue(entry
, data
);
840 // Insert the Key attribute (kmDNSKcKey)
841 if (noErr
!= (status
= SecKeychainItemCopyAttributesAndData(item
, NULL
,
842 NULL
, NULL
, &keylen
, &keyp
)))
844 debug("could not retrieve key for \"%.*s\": %d",
845 (int)attributes
->attr
[1].length
, attributes
->attr
[1].data
,
849 data
= CFDataCreate(kCFAllocatorDefault
, keyp
, keylen
);
850 SecKeychainItemFreeAttributesAndData(NULL
, keyp
);
853 debug("CFDataCreate for keyp failed");
856 CFArrayAppendValue(entry
, data
);
859 // Insert the Name attribute (kmDNSKcName)
860 if (NULL
== (data
= CFDataCreate(kCFAllocatorDefault
,
861 attributes
->attr
[3].data
, attributes
->attr
[3].length
)))
863 debug("CFDataCreate for attr[3] failed");
866 CFArrayAppendValue(entry
, data
);
878 do_mDNSKeychainGetSecrets(__unused mach_port_t port
, __unused
unsigned int *numsecrets
,
879 __unused vm_offset_t
*secrets
, __unused mach_msg_type_number_t
*secretsCnt
, __unused
int *err
,
880 __unused audit_token_t token
)
882 #ifndef NO_SECURITYFRAMEWORK
883 CFWriteStreamRef stream
= NULL
;
884 CFDataRef result
= NULL
;
885 CFPropertyListRef entry
= NULL
;
886 CFMutableArrayRef keys
= NULL
;
887 SecKeychainRef skc
= NULL
;
888 SecKeychainItemRef item
= NULL
;
889 SecKeychainSearchRef search
= NULL
;
890 SecKeychainAttributeList
*attributes
= NULL
;
891 enum DNSKeyFormat format
;
897 *secrets
= (vm_offset_t
)NULL
;
898 if (!authorized(&token
))
900 *err
= kmDNSHelperNotAuthorized
;
903 if (NULL
== (keys
= CFArrayCreateMutable(NULL
, 0,
904 &kCFTypeArrayCallBacks
)))
906 debug("CFArrayCreateMutable failed");
907 *err
= kmDNSHelperCreationFailed
;
910 if (noErr
!= (status
= SecKeychainCopyDefault(&skc
)))
912 *err
= kmDNSHelperKeychainCopyDefaultFailed
;
915 if (noErr
!= (status
= SecKeychainSearchCreateFromAttributes(skc
, kSecGenericPasswordItemClass
, NULL
, &search
)))
917 *err
= kmDNSHelperKeychainSearchCreationFailed
;
920 for (status
= SecKeychainSearchCopyNext(search
, &item
);
922 status
= SecKeychainSearchCopyNext(search
, &item
))
924 if (formatNotDNSKey
!= (format
= getDNSKeyFormat(item
,
926 NULL
!= (entry
= getKeychainItemInfo(item
, attributes
,
929 CFArrayAppendValue(keys
, entry
);
932 SecKeychainItemFreeAttributesAndData(attributes
, NULL
);
935 if (errSecItemNotFound
!= status
)
936 helplog(ASL_LEVEL_ERR
, "%s: SecKeychainSearchCopyNext failed: %d",
938 if (NULL
== (stream
=
939 CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorDefault
,
940 kCFAllocatorDefault
)))
942 *err
= kmDNSHelperCreationFailed
;
943 debug("CFWriteStreamCreateWithAllocatedBuffers failed");
946 CFWriteStreamOpen(stream
);
947 if (0 == CFPropertyListWriteToStream(keys
, stream
,
948 kCFPropertyListBinaryFormat_v1_0
, NULL
))
950 *err
= kmDNSHelperPListWriteFailed
;
951 debug("CFPropertyListWriteToStream failed");
954 result
= CFWriteStreamCopyProperty(stream
,
955 kCFStreamPropertyDataWritten
);
956 if (KERN_SUCCESS
!= vm_allocate(mach_task_self(), secrets
,
957 CFDataGetLength(result
), VM_FLAGS_ANYWHERE
))
959 *err
= kmDNSHelperCreationFailed
;
960 debug("vm_allocate failed");
963 CFDataGetBytes(result
, CFRangeMake(0, CFDataGetLength(result
)),
965 *secretsCnt
= CFDataGetLength(result
);
966 *numsecrets
= CFArrayGetCount(keys
);
970 debug("returning %u secrets", *numsecrets
);
973 CFWriteStreamClose(stream
);
991 #ifndef MDNS_NO_IPSEC
992 typedef enum _mDNSTunnelPolicyWhich
994 kmDNSTunnelPolicySetup
,
995 kmDNSTunnelPolicyTeardown
,
996 kmDNSTunnelPolicyGenerate
997 } mDNSTunnelPolicyWhich
;
999 // For kmDNSTunnelPolicySetup, you can setup IPv6-in-IPv6 tunnel or IPv6-in-IPv4 tunnel
1000 // kmDNSNoTunnel is used for other Policy types
1001 typedef enum _mDNSTunnelType
1004 kmDNSIPv6IPv4Tunnel
,
1008 static const uint8_t kWholeV6Mask
= 128;
1010 #endif /* ifndef MDNS_NO_IPSEC */
1012 #ifndef MDNS_NO_IPSEC
1014 static const char g_racoon_config_dir
[] = "/var/run/racoon/";
1015 static const char g_racoon_config_dir_old
[] = "/etc/racoon/remote/";
1017 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
1018 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
1020 // Major version 6 is 10.2.x (Jaguar)
1021 // Major version 7 is 10.3.x (Panther)
1022 // Major version 8 is 10.4.x (Tiger)
1023 // Major version 9 is 10.5.x (Leopard)
1024 // Major version 10 is 10.6.x (SnowLeopard)
1025 static int MacOSXSystemBuildNumber(char* letter_out
, int* minor_out
)
1027 int major
= 0, minor
= 0;
1028 char letter
= 0, buildver
[256]="<Unknown>";
1029 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
1032 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
1033 if (cfbuildver
) CFStringGetCString(cfbuildver
, buildver
, sizeof(buildver
), kCFStringEncodingUTF8
);
1034 sscanf(buildver
, "%d%c%d", &major
, &letter
, &minor
);
1038 helplog(ASL_LEVEL_NOTICE
, "_CFCopySystemVersionDictionary failed");
1040 if (!major
) { major
=10; letter
= 'A'; minor
= 190; helplog(ASL_LEVEL_NOTICE
, "Note: No Major Build Version number found; assuming 10A190"); }
1041 if (letter_out
) *letter_out
= letter
;
1042 if (minor_out
) *minor_out
= minor
;
1046 static int UseOldRacoon()
1048 static int g_oldRacoon
= -1;
1050 if (g_oldRacoon
== -1)
1054 g_oldRacoon
= (MacOSXSystemBuildNumber(&letter
, &minor
) < 10);
1055 debug("%s", g_oldRacoon
? "old" : "new");
1061 static int RacoonSignal()
1063 return UseOldRacoon() ? SIGHUP
: SIGUSR1
;
1066 static const char* GetRacoonConfigDir()
1068 return UseOldRacoon() ? g_racoon_config_dir_old
: g_racoon_config_dir
;
1071 static const char* GetOldRacoonConfigDir()
1073 return UseOldRacoon() ? NULL
: g_racoon_config_dir_old
;
1076 static const char racoon_config_file
[] = "anonymous.conf";
1077 static const char racoon_config_file_orig
[] = "anonymous.conf.orig";
1079 static const char configHeader
[] = "# BackToMyMac\n";
1081 static int IsFamiliarRacoonConfiguration(const char* racoon_config_path
)
1083 int fd
= open(racoon_config_path
, O_RDONLY
);
1084 debug("entry %s", racoon_config_path
);
1087 helplog(ASL_LEVEL_NOTICE
, "open \"%s\" failed: %s", racoon_config_path
, strerror(errno
));
1092 char header
[sizeof(configHeader
)] = {0};
1093 ssize_t bytesRead
= read(fd
, header
, sizeof(header
)-1);
1095 if (bytesRead
!= sizeof(header
)-1) return 0;
1096 return (0 == memcmp(header
, configHeader
, sizeof(header
)-1));
1101 revertAnonymousRacoonConfiguration(const char* dir
)
1105 debug("entry %s", dir
);
1107 char racoon_config_path
[64];
1108 strlcpy(racoon_config_path
, dir
, sizeof(racoon_config_path
));
1109 strlcat(racoon_config_path
, racoon_config_file
, sizeof(racoon_config_path
));
1112 int ret
= stat(racoon_config_path
, &s
);
1113 debug("stat(%s): %d errno=%d", racoon_config_path
, ret
, errno
);
1116 if (IsFamiliarRacoonConfiguration(racoon_config_path
))
1118 helplog(ASL_LEVEL_INFO
, "\"%s\" looks familiar, unlinking", racoon_config_path
);
1119 unlink(racoon_config_path
);
1123 helplog(ASL_LEVEL_NOTICE
, "\"%s\" does not look familiar, leaving in place", racoon_config_path
);
1127 else if (errno
!= ENOENT
)
1129 helplog(ASL_LEVEL_NOTICE
, "stat failed for \"%s\", leaving in place: %s", racoon_config_path
, strerror(errno
));
1133 char racoon_config_path_orig
[64];
1134 strlcpy(racoon_config_path_orig
, dir
, sizeof(racoon_config_path_orig
));
1135 strlcat(racoon_config_path_orig
, racoon_config_file_orig
, sizeof(racoon_config_path_orig
));
1137 ret
= stat(racoon_config_path_orig
, &s
);
1138 debug("stat(%s): %d errno=%d", racoon_config_path_orig
, ret
, errno
);
1141 if (0 > rename(racoon_config_path_orig
, racoon_config_path
))
1142 helplog(ASL_LEVEL_NOTICE
, "rename \"%s\" \"%s\" failed: %s", racoon_config_path_orig
, racoon_config_path
, strerror(errno
));
1144 debug("reverted \"%s\" to \"%s\"", racoon_config_path_orig
, racoon_config_path
);
1146 else if (errno
!= ENOENT
)
1148 helplog(ASL_LEVEL_NOTICE
, "stat failed for \"%s\", leaving in place: %s", racoon_config_path_orig
, strerror(errno
));
1154 moveAsideAnonymousRacoonConfiguration(const char* dir
)
1158 debug("entry %s", dir
);
1160 char racoon_config_path
[64];
1161 strlcpy(racoon_config_path
, dir
, sizeof(racoon_config_path
));
1162 strlcat(racoon_config_path
, racoon_config_file
, sizeof(racoon_config_path
));
1165 int ret
= stat(racoon_config_path
, &s
);
1168 if (IsFamiliarRacoonConfiguration(racoon_config_path
))
1170 helplog(ASL_LEVEL_INFO
, "\"%s\" looks familiar, unlinking", racoon_config_path
);
1171 unlink(racoon_config_path
);
1175 char racoon_config_path_orig
[64];
1176 strlcpy(racoon_config_path_orig
, dir
, sizeof(racoon_config_path_orig
));
1177 strlcat(racoon_config_path_orig
, racoon_config_file_orig
, sizeof(racoon_config_path_orig
));
1178 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
1179 helplog(ASL_LEVEL_NOTICE
, "rename \"%s\" to \"%s\" failed: %s", racoon_config_path
, racoon_config_path_orig
, strerror(errno
));
1181 debug("successfully renamed \"%s\" to \"%s\"", racoon_config_path
, racoon_config_path_orig
);
1184 else if (errno
!= ENOENT
)
1186 helplog(ASL_LEVEL_NOTICE
, "stat failed for \"%s\", leaving in place: %s", racoon_config_path
, strerror(errno
));
1192 ensureExistenceOfRacoonConfigDir(const char* const racoon_config_dir
)
1195 int ret
= stat(racoon_config_dir
, &s
);
1198 if (errno
!= ENOENT
)
1200 helplog(ASL_LEVEL_ERR
, "stat of \"%s\" failed (%d): %s",
1201 racoon_config_dir
, ret
, strerror(errno
));
1206 ret
= mkdir(racoon_config_dir
, S_IRWXU
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
);
1209 helplog(ASL_LEVEL_ERR
, "mkdir \"%s\" failed: %s",
1210 racoon_config_dir
, strerror(errno
));
1214 helplog(ASL_LEVEL_INFO
, "created directory \"%s\"", racoon_config_dir
);
1217 else if (!(s
.st_mode
& S_IFDIR
))
1219 helplog(ASL_LEVEL_ERR
, "\"%s\" is not a directory!",
1228 createAnonymousRacoonConfiguration(const char *fqdn
)
1230 static const char config1
[] =
1231 "remote anonymous {\n"
1232 " exchange_mode aggressive;\n"
1234 " situation identity_only;\n"
1235 " verify_identifier off;\n"
1236 " generate_policy on;\n"
1237 " shared_secret keychain_by_id \"";
1238 static const char config2
[] =
1241 " lifetime time 15 min;\n"
1242 " initial_contact on;\n"
1243 " support_proxy on;\n"
1244 " nat_traversal force;\n"
1245 " proposal_check claim;\n"
1247 " encryption_algorithm aes;\n"
1248 " hash_algorithm sha256;\n"
1249 " authentication_method pre_shared_key;\n"
1251 " lifetime time 15 min;\n"
1254 " encryption_algorithm aes;\n"
1255 " hash_algorithm sha1;\n"
1256 " authentication_method pre_shared_key;\n"
1258 " lifetime time 15 min;\n"
1261 "sainfo anonymous { \n"
1263 " lifetime time 10 min;\n"
1264 " encryption_algorithm aes;\n"
1265 " authentication_algorithm hmac_sha256,hmac_sha1;\n"
1266 " compression_algorithm deflate;\n"
1268 char tmp_config_path
[64];
1269 char racoon_config_path
[64];
1270 const char* const racoon_config_dir
= GetRacoonConfigDir();
1271 const char* const racoon_config_dir_old
= GetOldRacoonConfigDir();
1276 if (0 > ensureExistenceOfRacoonConfigDir(racoon_config_dir
))
1279 strlcpy(tmp_config_path
, racoon_config_dir
, sizeof(tmp_config_path
));
1280 strlcat(tmp_config_path
, "tmp.XXXXXX", sizeof(tmp_config_path
));
1282 fd
= mkstemp(tmp_config_path
);
1286 helplog(ASL_LEVEL_ERR
, "mkstemp \"%s\" failed: %s",
1287 tmp_config_path
, strerror(errno
));
1290 write(fd
, configHeader
, sizeof(configHeader
)-1);
1291 write(fd
, config1
, sizeof(config1
)-1);
1292 write(fd
, fqdn
, strlen(fqdn
));
1293 write(fd
, config2
, sizeof(config2
)-1);
1296 strlcpy(racoon_config_path
, racoon_config_dir
, sizeof(racoon_config_path
));
1297 strlcat(racoon_config_path
, racoon_config_file
, sizeof(racoon_config_path
));
1299 moveAsideAnonymousRacoonConfiguration(racoon_config_dir_old
);
1300 moveAsideAnonymousRacoonConfiguration(racoon_config_dir
);
1302 if (0 > rename(tmp_config_path
, racoon_config_path
))
1304 unlink(tmp_config_path
);
1305 helplog(ASL_LEVEL_ERR
, "rename \"%s\" \"%s\" failed: %s",
1306 tmp_config_path
, racoon_config_path
, strerror(errno
));
1307 revertAnonymousRacoonConfiguration(racoon_config_dir_old
);
1308 revertAnonymousRacoonConfiguration(racoon_config_dir
);
1312 debug("successfully renamed \"%s\" \"%s\"", tmp_config_path
, racoon_config_path
);
1320 static const char racoon_pid_path
[] = "/var/run/racoon.pid";
1321 char buf
[] = "18446744073709551615"; /* largest 64-bit integer */
1324 unsigned long m
= 0;
1325 int fd
= open(racoon_pid_path
, O_RDONLY
);
1329 debug("open \"%s\" failed, and that's OK: %s", racoon_pid_path
,
1331 return kmDNSHelperRacoonNotificationFailed
;
1333 n
= read(fd
, buf
, sizeof(buf
)-1);
1337 debug("read of \"%s\" failed: %s", racoon_pid_path
,
1338 n
== 0 ? "empty file" : strerror(errno
));
1339 return kmDNSHelperRacoonNotificationFailed
;
1342 m
= strtoul(buf
, &p
, 10);
1343 if (*p
!= '\0' && !isspace(*p
))
1345 debug("invalid PID \"%s\" (around '%c')", buf
, *p
);
1346 return kmDNSHelperRacoonNotificationFailed
;
1350 debug("refusing to kill PID %lu", m
);
1351 return kmDNSHelperRacoonNotificationFailed
;
1353 if (0 != kill(m
, RacoonSignal()))
1355 debug("Could not signal racoon (%lu): %s", m
, strerror(errno
));
1356 return kmDNSHelperRacoonNotificationFailed
;
1358 debug("Sent racoon (%lu) signal %d", m
, RacoonSignal());
1366 struct dirent entry
, *entryp
= NULL
;
1367 DIR *dirp
= opendir("/dev/fd");
1371 /* fall back to the erroneous getdtablesize method */
1372 for (fd
= from
; fd
< getdtablesize(); ++fd
)
1376 while (0 == readdir_r(dirp
, &entry
, &entryp
) && NULL
!= entryp
)
1378 fd
= atoi(entryp
->d_name
);
1379 if (fd
>= from
&& fd
!= dirfd(dirp
))
1386 startRacoonOld(void)
1389 char * const racoon_args
[] = { "/usr/sbin/racoon", "-e", NULL
};
1394 if (0 == (pid
= fork()))
1397 execve(racoon_args
[0], racoon_args
, NULL
);
1398 helplog(ASL_LEVEL_ERR
, "execve of \"%s\" failed: %s",
1399 racoon_args
[0], strerror(errno
));
1402 helplog(ASL_LEVEL_NOTICE
, "racoon (pid=%lu) started",
1403 (unsigned long)pid
);
1404 n
= waitpid(pid
, &status
, 0);
1407 helplog(ASL_LEVEL_ERR
, "Unexpected waitpid failure: %s",
1409 return kmDNSHelperRacoonStartFailed
;
1413 helplog(ASL_LEVEL_ERR
, "Unexpected waitpid return value %d",
1415 return kmDNSHelperRacoonStartFailed
;
1417 else if (WIFSIGNALED(status
))
1419 helplog(ASL_LEVEL_ERR
,
1420 "racoon (pid=%lu) terminated due to signal %d",
1421 (unsigned long)pid
, WTERMSIG(status
));
1422 return kmDNSHelperRacoonStartFailed
;
1424 else if (WIFSTOPPED(status
))
1426 helplog(ASL_LEVEL_ERR
,
1427 "racoon (pid=%lu) has stopped due to signal %d",
1428 (unsigned long)pid
, WSTOPSIG(status
));
1429 return kmDNSHelperRacoonStartFailed
;
1431 else if (0 != WEXITSTATUS(status
))
1433 helplog(ASL_LEVEL_ERR
,
1434 "racoon (pid=%lu) exited with status %d",
1435 (unsigned long)pid
, WEXITSTATUS(status
));
1436 return kmDNSHelperRacoonStartFailed
;
1438 debug("racoon (pid=%lu) daemonized normally", (unsigned long)pid
);
1442 // constant and structure for the racoon control socket
1443 #define VPNCTL_CMD_PING 0x0004
1444 typedef struct vpnctl_hdr_struct
1458 int fd
= socket(PF_UNIX
, SOCK_STREAM
, 0);
1461 helplog(ASL_LEVEL_ERR
, "Could not create endpoint for racoon control socket: %d %s",
1462 errno
, strerror(errno
));
1463 return kmDNSHelperRacoonStartFailed
;
1466 struct sockaddr_un saddr
;
1467 memset(&saddr
, 0, sizeof(saddr
));
1468 saddr
.sun_family
= AF_UNIX
;
1469 saddr
.sun_len
= sizeof(saddr
);
1470 static const char racoon_control_sock_path
[] = "/var/run/vpncontrol.sock";
1471 strcpy(saddr
.sun_path
, racoon_control_sock_path
);
1472 int result
= connect(fd
, (struct sockaddr
*) &saddr
, saddr
.sun_len
);
1475 helplog(ASL_LEVEL_ERR
, "Could not connect racoon control socket %s: %d %s",
1476 racoon_control_sock_path
, errno
, strerror(errno
));
1477 return kmDNSHelperRacoonStartFailed
;
1480 u_int32_t btmm_cookie
= 0x4d4d5442;
1481 vpnctl_hdr h
= { htons(VPNCTL_CMD_PING
), 0, btmm_cookie
, 0, 0, 0 };
1485 while (bytes
< sizeof(vpnctl_hdr
))
1487 ret
= write(fd
, ((unsigned char*)&h
)+bytes
, sizeof(vpnctl_hdr
) - bytes
);
1490 helplog(ASL_LEVEL_ERR
, "Could not write to racoon control socket: %d %s",
1491 errno
, strerror(errno
));
1492 return kmDNSHelperRacoonStartFailed
;
1504 for (counter
= 0; counter
< 100; counter
++)
1508 tv
= (struct timeval
){ 0, 10000 }; // 10 milliseconds * 100 iterations = 1 second max wait time
1510 result
= select(nfds
, &fds
, (fd_set
*)NULL
, (fd_set
*)NULL
, &tv
);
1513 if (FD_ISSET(fd
, &fds
))
1515 ret
= read(fd
, ((unsigned char*)&h
)+bytes
, sizeof(vpnctl_hdr
) - bytes
);
1519 helplog(ASL_LEVEL_ERR
, "Could not read from racoon control socket: %d %s",
1524 if (bytes
>= sizeof(vpnctl_hdr
)) break;
1528 debug("select returned but fd_isset not on expected fd\n");
1531 else if (result
< 0)
1533 debug("select returned %d errno %d %s\n", result
, errno
, strerror(errno
));
1534 if (errno
!= EINTR
) break;
1540 if (bytes
< sizeof(vpnctl_hdr
) || h
.cookie
!= btmm_cookie
) return kmDNSHelperRacoonStartFailed
;
1542 debug("racoon started");
1549 if ( 0 == notifyRacoon() )
1551 return UseOldRacoon() ? startRacoonOld() : startRacoon();
1554 #endif /* ndef MDNS_NO_IPSEC */
1557 do_mDNSConfigureServer(__unused mach_port_t port
, int updown
, const char *fqdn
, audit_token_t token
)
1559 #ifndef MDNS_NO_IPSEC
1561 if (!authorized(&token
)) goto fin
;
1563 switch ((enum mDNSUpDown
)updown
)
1566 if (0 != createAnonymousRacoonConfiguration(fqdn
)) goto fin
;
1569 revertAnonymousRacoonConfiguration(GetOldRacoonConfigDir());
1570 revertAnonymousRacoonConfiguration(GetRacoonConfigDir());
1576 if (0 != kickRacoon())
1582 (void)port
; (void)updown
; (void)fqdn
; (void)token
;
1584 update_idle_timer();
1585 return KERN_SUCCESS
;
1588 #ifndef MDNS_NO_IPSEC
1590 static unsigned int routeSeq
= 1;
1593 setupTunnelRoute(v6addr_t local
, v6addr_t remote
)
1597 struct rt_msghdr hdr
;
1598 struct sockaddr_in6 dst
;
1599 struct sockaddr_in6 gtwy
;
1604 if (0 > (s
= socket(PF_ROUTE
, SOCK_RAW
, AF_INET
)))
1606 helplog(ASL_LEVEL_ERR
, "socket(PF_ROUTE, ...) failed: %s",
1608 err
= kmDNSHelperRoutingSocketCreationFailed
;
1611 memset(&msg
, 0, sizeof(msg
));
1612 msg
.hdr
.rtm_msglen
= sizeof(msg
);
1613 msg
.hdr
.rtm_type
= RTM_ADD
;
1614 /* The following flags are set by `route add -inet6 -host ...` */
1615 msg
.hdr
.rtm_flags
= RTF_UP
| RTF_GATEWAY
| RTF_HOST
| RTF_STATIC
;
1616 msg
.hdr
.rtm_version
= RTM_VERSION
;
1617 msg
.hdr
.rtm_seq
= routeSeq
++;
1618 msg
.hdr
.rtm_addrs
= RTA_DST
| RTA_GATEWAY
;
1619 msg
.hdr
.rtm_inits
= RTV_MTU
;
1620 msg
.hdr
.rtm_rmx
.rmx_mtu
= 1280;
1622 msg
.dst
.sin6_len
= sizeof(msg
.dst
);
1623 msg
.dst
.sin6_family
= AF_INET6
;
1624 memcpy(&msg
.dst
.sin6_addr
, remote
, sizeof(msg
.dst
.sin6_addr
));
1626 msg
.gtwy
.sin6_len
= sizeof(msg
.gtwy
);
1627 msg
.gtwy
.sin6_family
= AF_INET6
;
1628 memcpy(&msg
.gtwy
.sin6_addr
, local
, sizeof(msg
.gtwy
.sin6_addr
));
1630 /* send message, ignore error when route already exists */
1631 if (0 > write(s
, &msg
, msg
.hdr
.rtm_msglen
))
1635 debug("write to routing socket failed: %s", strerror(errno_
));
1636 if (EEXIST
!= errno_
)
1638 err
= kmDNSHelperRouteAdditionFailed
;
1650 teardownTunnelRoute(v6addr_t remote
)
1654 struct rt_msghdr hdr
;
1655 struct sockaddr_in6 dst
;
1660 if (0 > (s
= socket(PF_ROUTE
, SOCK_RAW
, AF_INET
)))
1662 helplog(ASL_LEVEL_ERR
, "socket(PF_ROUTE, ...) failed: %s",
1664 err
= kmDNSHelperRoutingSocketCreationFailed
;
1667 memset(&msg
, 0, sizeof(msg
));
1669 msg
.hdr
.rtm_msglen
= sizeof(msg
);
1670 msg
.hdr
.rtm_type
= RTM_DELETE
;
1671 msg
.hdr
.rtm_version
= RTM_VERSION
;
1672 msg
.hdr
.rtm_seq
= routeSeq
++;
1673 msg
.hdr
.rtm_addrs
= RTA_DST
;
1675 msg
.dst
.sin6_len
= sizeof(msg
.dst
);
1676 msg
.dst
.sin6_family
= AF_INET6
;
1677 memcpy(&msg
.dst
.sin6_addr
, remote
, sizeof(msg
.dst
.sin6_addr
));
1678 if (0 > write(s
, &msg
, msg
.hdr
.rtm_msglen
))
1682 debug("write to routing socket failed: %s", strerror(errno_
));
1683 if (ESRCH
!= errno_
)
1685 err
= kmDNSHelperRouteDeletionFailed
;
1697 v4addr_to_string(v4addr_t addr
, char *buf
, size_t buflen
)
1699 if (NULL
== inet_ntop(AF_INET
, addr
, buf
, buflen
))
1701 helplog(ASL_LEVEL_ERR
, "inet_ntop failed: %s",
1703 return kmDNSHelperInvalidNetworkAddress
;
1710 v6addr_to_string(v6addr_t addr
, char *buf
, size_t buflen
)
1712 if (NULL
== inet_ntop(AF_INET6
, addr
, buf
, buflen
))
1714 helplog(ASL_LEVEL_ERR
, "inet_ntop failed: %s",
1716 return kmDNSHelperInvalidNetworkAddress
;
1722 /* Caller owns object returned in `policy' */
1724 generateTunnelPolicy(mDNSTunnelPolicyWhich which
, mDNSTunnelType type
, int in
,
1725 v4addr_t src
, uint16_t src_port
,
1726 v4addr_t dst
, uint16_t dst_port
,
1727 v6addr_t src6
, v6addr_t dst6
,
1728 ipsec_policy_t
*policy
, size_t *len
)
1730 char srcs
[INET_ADDRSTRLEN
], dsts
[INET_ADDRSTRLEN
];
1731 char srcs6
[INET6_ADDRSTRLEN
], dsts6
[INET6_ADDRSTRLEN
];
1733 char *inOut
= in
? "in" : "out";
1742 case kmDNSTunnelPolicySetup
:
1743 if (type
== kmDNSIPv6IPv4Tunnel
)
1745 if (0 != (err
= v4addr_to_string(src
, srcs
, sizeof(srcs
))))
1747 if (0 != (err
= v4addr_to_string(dst
, dsts
, sizeof(dsts
))))
1749 n
= snprintf(buf
, sizeof(buf
),
1750 "%s ipsec esp/tunnel/%s[%u]-%s[%u]/require",
1751 inOut
, srcs
, src_port
, dsts
, dst_port
);
1753 else if (type
== kmDNSIPv6IPv6Tunnel
)
1755 if (0 != (err
= v6addr_to_string(src6
, srcs6
, sizeof(srcs6
))))
1757 if (0 != (err
= v6addr_to_string(dst6
, dsts6
, sizeof(dsts6
))))
1759 n
= snprintf(buf
, sizeof(buf
),
1760 "%s ipsec esp/tunnel/%s-%s/require",
1761 inOut
, srcs6
, dsts6
);
1764 case kmDNSTunnelPolicyTeardown
:
1765 n
= strlcpy(buf
, inOut
, sizeof(buf
));
1767 case kmDNSTunnelPolicyGenerate
:
1768 n
= snprintf(buf
, sizeof(buf
), "%s generate", inOut
);
1771 err
= kmDNSHelperIPsecPolicyCreationFailed
;
1775 if (n
>= (int)sizeof(buf
))
1777 err
= kmDNSHelperResultTooLarge
;
1781 debug("policy=\"%s\"", buf
);
1782 if (NULL
== (*policy
= (ipsec_policy_t
)ipsec_set_policy(buf
, n
)))
1784 helplog(ASL_LEVEL_ERR
,
1785 "Could not create IPsec policy from \"%s\"", buf
);
1786 err
= kmDNSHelperIPsecPolicyCreationFailed
;
1789 *len
= ((ipsec_policy_t
)(*policy
))->sadb_x_policy_len
* 8;
1796 sendPolicy(int s
, int setup
,
1797 struct sockaddr
*src
, uint8_t src_bits
,
1798 struct sockaddr
*dst
, uint8_t dst_bits
,
1799 ipsec_policy_t policy
, size_t len
)
1801 static unsigned int policySeq
= 0;
1804 debug("entry, setup=%d", setup
);
1806 err
= pfkey_send_spdadd(s
, src
, src_bits
, dst
, dst_bits
, -1,
1807 (char *)policy
, len
, policySeq
++);
1809 err
= pfkey_send_spddelete(s
, src
, src_bits
, dst
, dst_bits
, -1,
1810 (char *)policy
, len
, policySeq
++);
1813 helplog(ASL_LEVEL_ERR
, "Could not set IPsec policy: %s",
1815 err
= kmDNSHelperIPsecPolicySetFailed
;
1827 removeSA(int s
, struct sockaddr
*src
, struct sockaddr
*dst
)
1832 err
= pfkey_send_delete_all(s
, SADB_SATYPE_ESP
, IPSEC_MODE_ANY
, src
, dst
);
1835 helplog(ASL_LEVEL_ERR
, "Could not remove IPsec SA: %s", ipsec_strerror());
1836 err
= kmDNSHelperIPsecRemoveSAFailed
;
1839 err
= pfkey_send_delete_all(s
, SADB_SATYPE_ESP
, IPSEC_MODE_ANY
, dst
, src
);
1842 helplog(ASL_LEVEL_ERR
, "Could not remove IPsec SA: %s", ipsec_strerror());
1843 err
= kmDNSHelperIPsecRemoveSAFailed
;
1856 doTunnelPolicy(mDNSTunnelPolicyWhich which
, mDNSTunnelType type
,
1857 v6addr_t loc_inner
, uint8_t loc_bits
,
1858 v4addr_t loc_outer
, uint16_t loc_port
,
1859 v6addr_t rmt_inner
, uint8_t rmt_bits
,
1860 v4addr_t rmt_outer
, uint16_t rmt_port
,
1861 v6addr_t loc_outer6
, v6addr_t rmt_outer6
)
1863 struct sockaddr_in6 sin6_loc
;
1864 struct sockaddr_in6 sin6_rmt
;
1865 ipsec_policy_t policy
= NULL
;
1871 if (0 > (s
= pfkey_open()))
1873 helplog(ASL_LEVEL_ERR
,
1874 "Could not create IPsec policy socket: %s",
1876 err
= kmDNSHelperIPsecPolicySocketCreationFailed
;
1880 memset(&sin6_loc
, 0, sizeof(sin6_loc
));
1881 sin6_loc
.sin6_len
= sizeof(sin6_loc
);
1882 sin6_loc
.sin6_family
= AF_INET6
;
1883 sin6_loc
.sin6_port
= htons(0);
1884 memcpy(&sin6_loc
.sin6_addr
, loc_inner
, sizeof(sin6_loc
.sin6_addr
));
1886 memset(&sin6_rmt
, 0, sizeof(sin6_rmt
));
1887 sin6_rmt
.sin6_len
= sizeof(sin6_rmt
);
1888 sin6_rmt
.sin6_family
= AF_INET6
;
1889 sin6_rmt
.sin6_port
= htons(0);
1890 memcpy(&sin6_rmt
.sin6_addr
, rmt_inner
, sizeof(sin6_rmt
.sin6_addr
));
1892 int setup
= which
!= kmDNSTunnelPolicyTeardown
;
1894 if (0 != (err
= generateTunnelPolicy(which
, type
, 1,
1895 rmt_outer
, rmt_port
,
1896 loc_outer
, loc_port
,
1897 rmt_outer6
, loc_outer6
,
1900 if (0 != (err
= sendPolicy(s
, setup
,
1901 (struct sockaddr
*)&sin6_rmt
, rmt_bits
,
1902 (struct sockaddr
*)&sin6_loc
, loc_bits
,
1910 if (0 != (err
= generateTunnelPolicy(which
, type
, 0,
1911 loc_outer
, loc_port
,
1912 rmt_outer
, rmt_port
,
1913 loc_outer6
, rmt_outer6
,
1916 if (0 != (err
= sendPolicy(s
, setup
,
1917 (struct sockaddr
*)&sin6_loc
, loc_bits
,
1918 (struct sockaddr
*)&sin6_rmt
, rmt_bits
,
1922 if (which
== kmDNSTunnelPolicyTeardown
)
1924 if (rmt_port
) // Outer tunnel is IPv4
1926 if (loc_outer
&& rmt_outer
)
1928 struct sockaddr_in sin_loc
;
1929 struct sockaddr_in sin_rmt
;
1930 memset(&sin_loc
, 0, sizeof(sin_loc
));
1931 sin_loc
.sin_len
= sizeof(sin_loc
);
1932 sin_loc
.sin_family
= AF_INET
;
1933 memcpy(&sin_loc
.sin_addr
, loc_outer
, sizeof(sin_loc
.sin_addr
));
1935 memset(&sin_rmt
, 0, sizeof(sin_rmt
));
1936 sin_rmt
.sin_len
= sizeof(sin_rmt
);
1937 sin_rmt
.sin_family
= AF_INET
;
1938 memcpy(&sin_rmt
.sin_addr
, rmt_outer
, sizeof(sin_rmt
.sin_addr
));
1939 if (0 != (err
= removeSA(s
, (struct sockaddr
*)&sin_loc
, (struct sockaddr
*)&sin_rmt
)))
1945 if (loc_outer6
&& rmt_outer6
)
1947 struct sockaddr_in6 sin6_lo
;
1948 struct sockaddr_in6 sin6_rm
;
1950 memset(&sin6_lo
, 0, sizeof(sin6_lo
));
1951 sin6_lo
.sin6_len
= sizeof(sin6_lo
);
1952 sin6_lo
.sin6_family
= AF_INET6
;
1953 memcpy(&sin6_lo
.sin6_addr
, loc_outer6
, sizeof(sin6_lo
.sin6_addr
));
1955 memset(&sin6_rm
, 0, sizeof(sin6_rm
));
1956 sin6_rm
.sin6_len
= sizeof(sin6_rm
);
1957 sin6_rm
.sin6_family
= AF_INET6
;
1958 memcpy(&sin6_rm
.sin6_addr
, rmt_outer6
, sizeof(sin6_rm
.sin6_addr
));
1959 if (0 != (err
= removeSA(s
, (struct sockaddr
*)&sin6_lo
, (struct sockaddr
*)&sin6_rm
)))
1976 #endif /* ndef MDNS_NO_IPSEC */
1979 do_mDNSAutoTunnelSetKeys(__unused mach_port_t port
, int replacedelete
,
1980 v6addr_t loc_inner
, v6addr_t loc_outer6
, uint16_t loc_port
,
1981 v6addr_t rmt_inner
, v6addr_t rmt_outer6
, uint16_t rmt_port
,
1982 const char *id
, int *err
, audit_token_t token
)
1984 #ifndef MDNS_NO_IPSEC
1985 static const char config
[] =
1987 "remote %s [%u] {\n"
1988 " disconnect_on_idle idle_timeout 600 idle_direction idle_outbound;\n"
1989 " exchange_mode aggressive;\n"
1991 " situation identity_only;\n"
1992 " verify_identifier off;\n"
1993 " generate_policy on;\n"
1994 " my_identifier user_fqdn \"%s\";\n"
1995 " shared_secret keychain \"%s\";\n"
1997 " lifetime time 15 min;\n"
1998 " initial_contact on;\n"
1999 " support_proxy on;\n"
2000 " nat_traversal force;\n"
2001 " proposal_check claim;\n"
2003 " encryption_algorithm aes;\n"
2004 " hash_algorithm sha256;\n"
2005 " authentication_method pre_shared_key;\n"
2007 " lifetime time 15 min;\n"
2010 " encryption_algorithm aes;\n"
2011 " hash_algorithm sha1;\n"
2012 " authentication_method pre_shared_key;\n"
2014 " lifetime time 15 min;\n"
2017 "sainfo address %s any address %s any {\n"
2019 " lifetime time 10 min;\n"
2020 " encryption_algorithm aes;\n"
2021 " authentication_algorithm hmac_sha256,hmac_sha1;\n"
2022 " compression_algorithm deflate;\n"
2024 "sainfo address %s any address %s any {\n"
2026 " lifetime time 10 min;\n"
2027 " encryption_algorithm aes;\n"
2028 " authentication_algorithm hmac_sha256,hmac_sha1;\n"
2029 " compression_algorithm deflate;\n"
2031 char path
[PATH_MAX
] = "";
2032 char li
[INET6_ADDRSTRLEN
], lo
[INET_ADDRSTRLEN
], lo6
[INET6_ADDRSTRLEN
],
2033 ri
[INET6_ADDRSTRLEN
], ro
[INET_ADDRSTRLEN
], ro6
[INET6_ADDRSTRLEN
];
2036 char tmp_path
[PATH_MAX
] = "";
2037 v4addr_t loc_outer
, rmt_outer
;
2041 if (!authorized(&token
))
2043 *err
= kmDNSHelperNotAuthorized
;
2046 switch ((enum mDNSAutoTunnelSetKeysReplaceDelete
)replacedelete
)
2048 case kmDNSAutoTunnelSetKeysReplace
:
2049 case kmDNSAutoTunnelSetKeysDelete
:
2052 *err
= kmDNSHelperInvalidTunnelSetKeysOperation
;
2056 if (0 != (*err
= v6addr_to_string(loc_inner
, li
, sizeof(li
))))
2058 if (0 != (*err
= v6addr_to_string(rmt_inner
, ri
, sizeof(ri
))))
2061 debug("loc_inner=%s rmt_inner=%s", li
, ri
);
2064 loc_outer
[0] = loc_outer
[1] = loc_outer
[2] = loc_outer
[3] = 0;
2065 rmt_outer
[0] = rmt_outer
[1] = rmt_outer
[2] = rmt_outer
[3] = 0;
2067 if (0 != (*err
= v6addr_to_string(loc_outer6
, lo6
, sizeof(lo6
))))
2069 if (0 != (*err
= v6addr_to_string(rmt_outer6
, ro6
, sizeof(ro6
))))
2071 debug("IPv6 outer tunnel: loc_outer6=%s rmt_outer6=%s", lo6
, ro6
);
2072 if ((int)sizeof(path
) <= snprintf(path
, sizeof(path
),
2073 "%s%s.conf", GetRacoonConfigDir(), ro6
))
2075 *err
= kmDNSHelperResultTooLarge
;
2081 loc_outer
[0] = loc_outer6
[0];
2082 loc_outer
[1] = loc_outer6
[1];
2083 loc_outer
[2] = loc_outer6
[2];
2084 loc_outer
[3] = loc_outer6
[3];
2086 rmt_outer
[0] = rmt_outer6
[0];
2087 rmt_outer
[1] = rmt_outer6
[1];
2088 rmt_outer
[2] = rmt_outer6
[2];
2089 rmt_outer
[3] = rmt_outer6
[3];
2091 if (0 != (*err
= v4addr_to_string(loc_outer
, lo
, sizeof(lo
))))
2093 if (0 != (*err
= v4addr_to_string(rmt_outer
, ro
, sizeof(ro
))))
2095 debug("IPv4 outer tunnel: loc_outer=%s loc_port=%u rmt_outer=%s rmt_port=%u",
2096 lo
, loc_port
, ro
, rmt_port
);
2098 if ((int)sizeof(path
) <= snprintf(path
, sizeof(path
),
2099 "%s%s.%u.conf", GetRacoonConfigDir(), ro
,
2102 *err
= kmDNSHelperResultTooLarge
;
2109 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
)
2111 if (0 > ensureExistenceOfRacoonConfigDir(GetRacoonConfigDir()))
2113 *err
= kmDNSHelperRacoonConfigCreationFailed
;
2116 if ((int)sizeof(tmp_path
) <=
2117 snprintf(tmp_path
, sizeof(tmp_path
), "%s.XXXXXX", path
))
2119 *err
= kmDNSHelperResultTooLarge
;
2122 if (0 > (fd
= mkstemp(tmp_path
)))
2124 helplog(ASL_LEVEL_ERR
, "mkstemp \"%s\" failed: %s",
2125 tmp_path
, strerror(errno
));
2126 *err
= kmDNSHelperRacoonConfigCreationFailed
;
2129 if (NULL
== (fp
= fdopen(fd
, "w")))
2131 helplog(ASL_LEVEL_ERR
, "fdopen: %s",
2133 *err
= kmDNSHelperRacoonConfigCreationFailed
;
2137 fprintf(fp
, config
, configHeader
, (!rmt_port
? ro6
: ro
), rmt_port
, id
, id
, ri
, li
, li
, ri
);
2140 if (0 > rename(tmp_path
, path
))
2142 helplog(ASL_LEVEL_ERR
,
2143 "rename \"%s\" \"%s\" failed: %s",
2144 tmp_path
, path
, strerror(errno
));
2145 *err
= kmDNSHelperRacoonConfigCreationFailed
;
2151 if (0 != unlink(path
))
2152 debug("unlink \"%s\" failed: %s", path
,
2156 if (0 != (*err
= doTunnelPolicy(kmDNSTunnelPolicyTeardown
, kmDNSNoTunnel
,
2157 loc_inner
, kWholeV6Mask
, loc_outer
, loc_port
,
2158 rmt_inner
, kWholeV6Mask
, rmt_outer
, rmt_port
, loc_outer6
, rmt_outer6
)))
2160 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
&&
2161 0 != (*err
= doTunnelPolicy(kmDNSTunnelPolicySetup
, (!rmt_port
? kmDNSIPv6IPv6Tunnel
: kmDNSIPv6IPv4Tunnel
),
2162 loc_inner
, kWholeV6Mask
, loc_outer
, loc_port
,
2163 rmt_inner
, kWholeV6Mask
, rmt_outer
, rmt_port
, loc_outer6
, rmt_outer6
)))
2166 if (0 != (*err
= teardownTunnelRoute(rmt_inner
)))
2168 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
&&
2169 0 != (*err
= setupTunnelRoute(loc_inner
, rmt_inner
)))
2172 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
&&
2173 0 != (*err
= kickRacoon()))
2185 (void)replacedelete
; (void)loc_inner
; (void)loc_outer6
; (void)loc_port
; (void)rmt_inner
;
2186 (void)rmt_outer6
; (void)rmt_port
; (void)id
; (void)token
;
2188 *err
= kmDNSHelperIPsecDisabled
;
2189 #endif /* MDNS_NO_IPSEC */
2190 update_idle_timer();
2191 return KERN_SUCCESS
;
2195 do_mDNSSendWakeupPacket(__unused mach_port_t port
, unsigned ifid
, const char *eth_addr
, const char *ip_addr
, int iteration
, audit_token_t token
)
2199 char ifname
[IFNAMSIZ
];
2202 char bpf_device
[12];
2203 struct ether_addr
*ea
;
2204 (void) ip_addr
; // unused
2205 (void) iteration
; // unused
2206 (void) token
; // unused
2208 if (if_indextoname(ifid
, ifname
) == NULL
)
2210 helplog(ASL_LEVEL_ERR
, "do_mDNSSendWakeupPacket invalid interface index %u", ifid
);
2214 ea
= ether_aton(eth_addr
);
2217 helplog(ASL_LEVEL_ERR
, "do_mDNSSendWakeupPacket invalid ethernet address %s", eth_addr
);
2221 for (i
= 0; i
< 100; i
++)
2223 snprintf(bpf_device
, sizeof(bpf_device
), "/dev/bpf%d", i
);
2224 bpf_fd
= open(bpf_device
, O_RDWR
, 0);
2232 helplog(ASL_LEVEL_ERR
, "do_mDNSSendWakeupPacket cannot find a bpf device");
2236 memset(&ifr
, 0, sizeof(ifr
));
2237 strlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
2239 if (ioctl(bpf_fd
, BIOCSETIF
, (char *)&ifr
) < 0)
2241 helplog(ASL_LEVEL_ERR
, "do_mDNSSendWakeupPacket BIOCSETIF failed %s", strerror(errno
));
2245 // 0x00 Destination address
2246 for (i
=0; i
<6; i
++) *ptr
++ = ea
->octet
[i
];
2248 // 0x06 Source address (Note: Since we don't currently set the BIOCSHDRCMPLT option, BPF will fill in the real interface address for us)
2249 for (i
=0; i
<6; i
++) *ptr
++ = 0;
2251 // 0x0C Ethertype (0x0842)
2255 // 0x0E Wakeup sync sequence
2256 for (i
=0; i
<6; i
++) *ptr
++ = 0xFF;
2259 for (j
=0; j
<16; j
++) for (i
=0; i
<6; i
++) *ptr
++ = ea
->octet
[i
];
2262 for (i
=0; i
<6; i
++) *ptr
++ = 0;
2264 if (write(bpf_fd
, packet
, ptr
- packet
) < 0)
2266 helplog(ASL_LEVEL_ERR
, "do_mDNSSendWakeupPacket write failed %s", strerror(errno
));
2269 helplog(ASL_LEVEL_INFO
, "do_mDNSSendWakeupPacket sent unicast eth_addr %s, ip_addr %s", eth_addr
, ip_addr
);
2270 // Send a broadcast one to handle ethernet switches that don't flood forward packets with
2271 // unknown mac addresses.
2272 for (i
=0; i
<6; i
++) packet
[i
] = 0xFF;
2273 if (write(bpf_fd
, packet
, ptr
- packet
) < 0)
2275 helplog(ASL_LEVEL_ERR
, "do_mDNSSendWakeupPacket write failed %s", strerror(errno
));
2278 helplog(ASL_LEVEL_INFO
, "do_mDNSSendWakeupPacket sent broadcast eth_addr %s, ip_addr %s", eth_addr
, ip_addr
);
2280 return KERN_SUCCESS
;
2283 // Open the specified port for protocol in the P2P firewall.
2285 do_mDNSPacketFilterControl(__unused mach_port_t port
, uint32_t command
, const char * ifname
, uint32_t count
, pfArray_t portArray
, pfArray_t protocolArray
, audit_token_t token
)
2287 (void) token
; // unused
2289 kern_return_t result
= KERN_SUCCESS
;
2291 helplog(ASL_LEVEL_INFO
, "do_mDNSPacketFilterControl: command %d ifname %s, count %d",
2292 command
, ifname
, count
);
2297 error
= P2PPacketFilterAddBonjourRuleSet(ifname
, count
, portArray
, protocolArray
);
2300 helplog(ASL_LEVEL_ERR
, "P2PPacketFilterAddBonjourRuleSet failed %s", strerror(error
));
2301 result
= KERN_FAILURE
;
2305 case PF_CLEAR_RULES
:
2306 error
= P2PPacketFilterClearBonjourRules();
2309 helplog(ASL_LEVEL_ERR
, "P2PPacketFilterClearBonjourRules failed %s", strerror(error
));
2310 result
= KERN_FAILURE
;
2315 helplog(ASL_LEVEL_ERR
, "do_mDNSPacketFilterControl: invalid command %d", command
);
2316 result
= KERN_INVALID_ARGUMENT
;
2324 in_cksum(unsigned short *ptr
,int nbytes
)
2330 * Our algorithm is simple, using a 32-bit accumulator (sum),
2331 * we add sequential 16-bit words to it, and at the end, fold back
2332 * all the carry bits from the top 16 bits into the lower 16 bits.
2335 while (nbytes
> 1) {
2340 /* mop up an odd byte, if necessary */
2342 /* make sure top half is zero */
2346 *((u_char
*)&oddbyte
) = *(u_char
*)ptr
;
2349 /* Add back carry outs from top 16 bits to low 16 bits. */
2350 sum
= (sum
>> 16) + (sum
& 0xffff);
2359 InetChecksum(unsigned short *ptr
,int nbytes
)
2363 sum
= in_cksum(ptr
, nbytes
);
2364 return (unsigned short)~sum
;
2367 void TCPCheckSum(int af
, struct tcphdr
*t
, int tcplen
, v6addr_t sadd6
, v6addr_t dadd6
)
2369 unsigned long sum
= 0;
2370 unsigned short *ptr
;
2372 /* TCP header checksum */
2373 sum
= in_cksum((unsigned short *)t
, tcplen
);
2378 ptr
= (unsigned short *)sadd6
;
2381 ptr
= (unsigned short *)dadd6
;
2385 else if (af
== AF_INET6
)
2388 ptr
= (unsigned short *)sadd6
;
2397 ptr
= (unsigned short *)dadd6
;
2408 sum
+= htons(tcplen
);
2409 sum
+= htons(IPPROTO_TCP
);
2412 sum
= (sum
>> 16) + (sum
& 0xFFFF);
2418 kern_return_t
do_mDNSSendKeepalive(__unused mach_port_t port
, v6addr_t sadd6
, v6addr_t dadd6
, uint16_t lport
, uint16_t rport
, unsigned seq
, unsigned ack
, uint16_t win
, audit_token_t token
)
2430 struct sockaddr_storage ss_to
;
2431 struct sockaddr_in
*sin_to
= (struct sockaddr_in
*)&ss_to
;
2432 struct sockaddr_in6
*sin6_to
= (struct sockaddr_in6
*)&ss_to
;
2435 char ctlbuf
[CMSG_SPACE(sizeof(struct in6_pktinfo
))];
2436 struct msghdr msghdr
;
2440 if (!authorized(&token
))
2442 helplog(ASL_LEVEL_ERR
, "mDNSSendKeepalive: Not authorized");
2443 return kmDNSHelperNotAuthorized
;
2446 helplog(ASL_LEVEL_ERR
, "mDNSSendKeepalive: called");
2448 // all the incoming arguments are in network order
2449 if ((*(unsigned *)(sadd6
+4) == 0) && (*(unsigned *)(sadd6
+ 8) == 0) && (*(unsigned *)(sadd6
+ 12) == 0))
2452 memset(&packet4
, 0, sizeof (packet4
));
2454 /* Fill in all the IP header information - should be in host order*/
2455 packet4
.ip
.ip_v
= 4; /* 4-bit Version */
2456 packet4
.ip
.ip_hl
= 5; /* 4-bit Header Length */
2457 packet4
.ip
.ip_tos
= 0; /* 8-bit Type of service */
2458 packet4
.ip
.ip_len
= 40; /* 16-bit Total length */
2459 packet4
.ip
.ip_id
= 9864; /* 16-bit ID field */
2460 packet4
.ip
.ip_off
= 0; /* 13-bit Fragment offset */
2461 packet4
.ip
.ip_ttl
= 63; /* 8-bit Time To Live */
2462 packet4
.ip
.ip_p
= IPPROTO_TCP
; /* 8-bit Protocol */
2463 packet4
.ip
.ip_sum
= 0; /* 16-bit Header checksum (below) */
2464 memcpy(&packet4
.ip
.ip_src
.s_addr
, sadd6
, 4);
2465 memcpy(&packet4
.ip
.ip_dst
.s_addr
, dadd6
, 4);
2467 /* IP header checksum */
2468 packet4
.ip
.ip_sum
= InetChecksum((unsigned short *)&packet4
.ip
, 20);
2471 packetlen
= 40; // sum of IPv4 header len(20) and TCP header len(20)
2476 memset(&packet6
, 0, sizeof (packet6
));
2479 // We don't send IPv6 header, hence just the TCP header len (20)
2483 /* Fill in all the TCP header information */
2484 t
->th_sport
= lport
; /* 16-bit Source port number */
2485 t
->th_dport
= rport
; /* 16-bit Destination port */
2486 t
->th_seq
= seq
; /* 32-bit Sequence Number */
2487 t
->th_ack
= ack
; /* 32-bit Acknowledgement Number */
2488 t
->th_off
= 5; /* Data offset */
2489 t
->th_flags
= TH_ACK
;
2491 t
->th_sum
= 0; /* 16-bit checksum (below) */
2492 t
->th_urp
= 0; /* 16-bit urgent offset */
2494 TCPCheckSum(af
, t
, 20, sadd6
, dadd6
);
2496 /* Open up a RAW socket */
2497 if ((sock
= socket(af
, SOCK_RAW
, IPPROTO_TCP
)) < 0)
2499 helplog(ASL_LEVEL_ERR
, "mDNSSendKeepalive: socket %s", strerror(errno
));
2507 if (setsockopt(sock
, IPPROTO_IP
, IP_HDRINCL
, &on
, sizeof (on
)))
2510 helplog(ASL_LEVEL_ERR
, "mDNSSendKeepalive: setsockopt %s", strerror(errno
));
2514 memset(sin_to
, 0, sizeof(struct sockaddr_in
));
2515 sin_to
->sin_len
= sizeof(struct sockaddr_in
);
2516 sin_to
->sin_family
= AF_INET
;
2517 memcpy(&sin_to
->sin_addr
, sadd6
, sizeof(struct in_addr
));
2518 sin_to
->sin_port
= rport
;
2520 msghdr
.msg_control
= NULL
;
2521 msghdr
.msg_controllen
= 0;
2526 struct cmsghdr
*ctl
;
2528 memset(sin6_to
, 0, sizeof(struct sockaddr_in6
));
2529 sin6_to
->sin6_len
= sizeof(struct sockaddr_in6
);
2530 sin6_to
->sin6_family
= AF_INET6
;
2531 memcpy(&sin6_to
->sin6_addr
, dadd6
, sizeof(struct in6_addr
));
2533 sin6_to
->sin6_port
= rport
;
2534 sin6_to
->sin6_flowinfo
= 0;
2537 msghdr
.msg_control
= ctlbuf
;
2538 msghdr
.msg_controllen
= sizeof(ctlbuf
);
2539 ctl
= CMSG_FIRSTHDR(&msghdr
);
2540 ctl
->cmsg_len
= CMSG_LEN(sizeof(struct in6_pktinfo
));
2541 ctl
->cmsg_level
= IPPROTO_IPV6
;
2542 ctl
->cmsg_type
= IPV6_PKTINFO
;
2543 struct in6_pktinfo
*pktinfo
= (struct in6_pktinfo
*) CMSG_DATA(ctl
);
2544 memcpy(&pktinfo
->ipi6_addr
, sadd6
, sizeof(struct in6_addr
));
2545 pktinfo
->ipi6_ifindex
= 0;
2548 msghdr
.msg_name
= (struct sockaddr
*)&ss_to
;
2549 msghdr
.msg_namelen
= ss_to
.ss_len
;
2550 iov
.iov_base
= packet
;
2551 iov
.iov_len
= packetlen
;
2552 msghdr
.msg_iov
= &iov
;
2553 msghdr
.msg_iovlen
= 1;
2554 msghdr
.msg_flags
= 0;
2556 len
= sendmsg(sock
, &msghdr
, 0);
2563 if (len
!= packetlen
)
2565 helplog(ASL_LEVEL_ERR
, "mDNSSendKeepalive: sendmsg failed %s", strerror(errno
));
2569 char source
[INET6_ADDRSTRLEN
], dest
[INET6_ADDRSTRLEN
];
2571 inet_ntop(af
, (void *)sadd6
, source
, sizeof(source
));
2572 inet_ntop(af
, (void *)dadd6
, dest
, sizeof(dest
));
2574 helplog(ASL_LEVEL_ERR
, "mDNSSendKeepalive: Success Source %s:%d, Dest %s:%d, %u, %u, %u", source
, ntohs(lport
), dest
, ntohs(rport
), ntohl(seq
), ntohl(ack
), ntohs(win
));
2578 return KERN_SUCCESS
;
2582 kern_return_t
do_mDNSRetrieveTCPInfo(__unused mach_port_t port
, int family
, v6addr_t laddr
, uint16_t lport
, v6addr_t raddr
, uint16_t rport
,
2583 uint32_t *seq
, uint32_t *ack
, uint16_t *win
, int32_t *intfid
, audit_token_t token
)
2586 struct info_tuple itpl
;
2588 unsigned int miblen
;
2592 memset(&itpl
, 0, sizeof(struct info_tuple
));
2593 memset(&ti
, 0, sizeof(struct tcp_info
));
2595 if (!authorized(&token
))
2597 helplog(ASL_LEVEL_ERR
, "mDNSRetrieveTCPInfo: Not authorized");
2598 return kmDNSHelperNotAuthorized
;
2601 if (family
== AF_INET
)
2603 memcpy(&itpl
.itpl_local_sin
.sin_addr
, laddr
, sizeof(struct in_addr
));
2604 memcpy(&itpl
.itpl_remote_sin
.sin_addr
, raddr
, sizeof(struct in_addr
));
2605 itpl
.itpl_local_sin
.sin_port
= lport
;
2606 itpl
.itpl_remote_sin
.sin_port
= rport
;
2607 itpl
.itpl_local_sin
.sin_family
= AF_INET
;
2608 itpl
.itpl_remote_sin
.sin_family
= AF_INET
;
2612 memcpy(&itpl
.itpl_local_sin6
.sin6_addr
, laddr
, sizeof(struct in6_addr
));
2613 memcpy(&itpl
.itpl_remote_sin6
.sin6_addr
, raddr
, sizeof(struct in6_addr
));
2614 itpl
.itpl_local_sin6
.sin6_port
= lport
;
2615 itpl
.itpl_remote_sin6
.sin6_port
= rport
;
2616 itpl
.itpl_local_sin6
.sin6_family
= AF_INET6
;
2617 itpl
.itpl_remote_sin6
.sin6_family
= AF_INET6
;
2619 itpl
.itpl_proto
= IPPROTO_TCP
;
2620 sz
= sizeof(mib
)/sizeof(mib
[0]);
2621 if (sysctlnametomib("net.inet.tcp.info", mib
, &sz
) == -1)
2623 helplog(ASL_LEVEL_ERR
, "do_RetrieveTCPInfo: sysctlnametomib failed %d, %s", errno
, strerror(errno
));
2626 miblen
= (unsigned int)sz
;
2627 len
= sizeof(struct tcp_info
);
2628 if (sysctl(mib
, miblen
, &ti
, &len
, &itpl
, sizeof(struct info_tuple
)) == -1)
2630 helplog(ASL_LEVEL_ERR
, "do_RetrieveTCPInfo: sysctl failed %d, %s", errno
, strerror(errno
));
2634 *seq
= ti
.tcpi_snd_nxt
- 1;
2635 *ack
= ti
.tcpi_rcv_nxt
;
2636 *win
= ti
.tcpi_rcv_space
>> ti
.tcpi_rcv_wscale
;
2637 *intfid
= ti
.tcpi_last_outif
;
2638 return KERN_SUCCESS
;
2641 static int getMACAddress(int family
, v6addr_t raddr
, v6addr_t gaddr
, int *gfamily
, ethaddr_t eth
)
2645 struct rt_msghdr m_rtm
;
2649 struct rt_msghdr
*rtm
= &(m_rtmsg
.m_rtm
);
2650 char *cp
= m_rtmsg
.m_space
;
2651 int seq
= 6367, sock
, rlen
, i
;
2652 struct sockaddr_in
*sin
= NULL
;
2653 struct sockaddr_in6
*sin6
= NULL
;
2654 struct sockaddr_dl
*sdl
= NULL
;
2655 struct sockaddr_storage sins
;
2656 struct sockaddr_dl sdl_m
;
2658 #define NEXTADDR(w, s, len) \
2659 if (rtm->rtm_addrs & (w)) \
2661 bcopy((char *)s, cp, len); \
2665 bzero(&sins
, sizeof(struct sockaddr_storage
));
2666 bzero(&sdl_m
, sizeof(struct sockaddr_dl
));
2667 bzero((char *)&m_rtmsg
, sizeof(m_rtmsg
));
2669 sock
= socket(PF_ROUTE
, SOCK_RAW
, 0);
2672 helplog(ASL_LEVEL_ERR
, "mDNSGetRemoteMAC: Can not open the socket - %s", strerror(errno
));
2676 rtm
->rtm_addrs
|= RTA_DST
| RTA_GATEWAY
;
2677 rtm
->rtm_type
= RTM_GET
;
2679 rtm
->rtm_version
= RTM_VERSION
;
2680 rtm
->rtm_seq
= ++seq
;
2682 sdl_m
.sdl_len
= sizeof(sdl_m
);
2683 sdl_m
.sdl_family
= AF_LINK
;
2684 if (family
== AF_INET
)
2686 sin
= (struct sockaddr_in
*)&sins
;
2687 sin
->sin_family
= AF_INET
;
2688 sin
->sin_len
= sizeof(struct sockaddr_in
);
2689 memcpy(&sin
->sin_addr
, raddr
, sizeof(struct in_addr
));
2690 NEXTADDR(RTA_DST
, sin
, sin
->sin_len
);
2692 else if (family
== AF_INET6
)
2694 sin6
= (struct sockaddr_in6
*)&sins
;
2695 sin6
->sin6_len
= sizeof(struct sockaddr_in6
);
2696 sin6
->sin6_family
= AF_INET6
;
2697 memcpy(&sin6
->sin6_addr
, raddr
, sizeof(struct in6_addr
));
2698 NEXTADDR(RTA_DST
, sin6
, sin6
->sin6_len
);
2700 NEXTADDR(RTA_GATEWAY
, &sdl_m
, sdl_m
.sdl_len
);
2701 rtm
->rtm_msglen
= rlen
= cp
- (char *)&m_rtmsg
;
2703 if (write(sock
, (char *)&m_rtmsg
, rlen
) < 0)
2705 helplog(ASL_LEVEL_INFO
, "do_mDNSGetRemoteMAC: writing to routing socket: %s", strerror(errno
));
2712 rlen
= read(sock
, (char *)&m_rtmsg
, sizeof(m_rtmsg
));
2714 while (rlen
> 0 && (rtm
->rtm_seq
!= seq
|| rtm
->rtm_pid
!= getpid()));
2717 helplog(ASL_LEVEL_ERR
, "do_mDNSGetRemoteMAC: Read from routing socket failed");
2719 if (family
== AF_INET
)
2721 sin
= (struct sockaddr_in
*) (rtm
+ 1);
2722 sdl
= (struct sockaddr_dl
*) (sin
->sin_len
+ (char *) sin
);
2724 else if (family
== AF_INET6
)
2726 sin6
= (struct sockaddr_in6
*) (rtm
+1);
2727 sdl
= (struct sockaddr_dl
*) (sin6
->sin6_len
+ (char *) sin6
);
2729 // If the address is not on the local net, we get the IP address of the gateway.
2730 // We would have to repeat the process to get the MAC address of the gateway
2731 *gfamily
= sdl
->sdl_family
;
2732 if (sdl
->sdl_family
== AF_INET
)
2734 struct sockaddr_in
*new_sin
= (struct sockaddr_in
*)(sin
->sin_len
+(char*) sin
);
2735 memcpy(gaddr
, &new_sin
->sin_addr
, sizeof(struct in_addr
));
2739 else if (sdl
->sdl_family
== AF_INET6
)
2741 struct sockaddr_in6
*new_sin6
= (struct sockaddr_in6
*)(sin6
->sin6_len
+(char*) sin6
);
2742 memcpy(gaddr
, &new_sin6
->sin6_addr
, sizeof(struct in6_addr
));
2747 unsigned char *ptr
= (unsigned char *)LLADDR(sdl
);
2748 for (i
= 0; i
< ETHER_ADDR_LEN
; i
++)
2749 (eth
)[i
] = *(ptr
+i
);
2752 return KERN_SUCCESS
;
2755 kern_return_t
do_mDNSGetRemoteMAC(__unused mach_port_t port
, int family
, v6addr_t raddr
, ethaddr_t eth
, audit_token_t token
)
2762 if (!authorized(&token
))
2764 helplog(ASL_LEVEL_ERR
, "mDNSGetRemoteMAC: Not authorized");
2765 return kmDNSHelperNotAuthorized
;
2770 ret
= getMACAddress(family
, raddr
, gateway
, &gfamily
, eth
);
2773 memcpy(raddr
, gateway
, sizeof(family
));
2778 while ((ret
== -1) && (count
< 5));
2783 kern_return_t
do_mDNSStoreSPSMACAddress(__unused mach_port_t port
, int family
, v6addr_t spsaddr
, const char *ifname
, audit_token_t token
)
2786 char spsip
[INET6_ADDRSTRLEN
];
2788 CFStringRef sckey
= NULL
;
2789 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:StoreSPSMACAddress"), NULL
, NULL
);
2790 SCDynamicStoreRef ipstore
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetIPv6Addresses"), NULL
, NULL
);
2791 CFMutableDictionaryRef dict
= NULL
;
2792 CFStringRef entityname
= NULL
;
2793 CFDictionaryRef ipdict
= NULL
;
2794 CFArrayRef addrs
= NULL
;
2796 if (!authorized(&token
))
2798 helplog(ASL_LEVEL_ERR
, "mDNSStoreSPSMAC: Not authorized");
2799 return kmDNSHelperNotAuthorized
;
2802 if ((store
== NULL
) || (ipstore
== NULL
))
2804 helplog(ASL_LEVEL_ERR
, "Unable to access SC Dynamic Store");
2805 return KERN_FAILURE
;
2808 // Get the MAC address of the Sleep Proxy Server
2809 memset(eth
, 0, sizeof(eth
));
2810 ret
= do_mDNSGetRemoteMAC(port
, family
, spsaddr
, eth
, token
);
2811 if (ret
!= KERN_SUCCESS
)
2813 helplog(ASL_LEVEL_ERR
, "mDNSStoreSPSMAC: Failed to determine the MAC address");
2817 // Create/Update the dynamic store entry for the specified interface
2818 sckey
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname
, "/BonjourSleepProxyAddress");
2819 dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2822 helplog(ASL_LEVEL_ERR
, "SPSCreateDict: Could not create CFDictionary dict");
2827 CFStringRef macaddr
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%02x:%02x:%02x:%02x:%02x:%02x"), eth
[0], eth
[1], eth
[2], eth
[3], eth
[4], eth
[5]);
2828 CFDictionarySetValue(dict
, CFSTR("MACAddress"), macaddr
);
2829 if (NULL
!= macaddr
) CFRelease(macaddr
);
2831 if( NULL
== inet_ntop(family
, (void *)spsaddr
, spsip
, sizeof(spsip
)))
2833 helplog(ASL_LEVEL_ERR
, "inet_ntop failed: %s", strerror(errno
));
2834 ret
= kmDNSHelperInvalidNetworkAddress
;
2838 CFStringRef ipaddr
= CFStringCreateWithCString(NULL
, spsip
, kCFStringEncodingUTF8
);
2839 CFDictionarySetValue(dict
, CFSTR("IPAddress"), ipaddr
);
2840 if (NULL
!= ipaddr
) CFRelease(ipaddr
);
2842 // Get the current IPv6 addresses on this interface and store them so NAs can be sent on wakeup
2843 if ((entityname
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("State:/Network/Interface/%s/IPv6"), ifname
)) != NULL
)
2845 if ((ipdict
= SCDynamicStoreCopyValue(ipstore
, entityname
)) != NULL
)
2847 if((addrs
= CFDictionaryGetValue(ipdict
, CFSTR("Addresses"))) != NULL
)
2849 addrs
= CFRetain(addrs
);
2850 CFDictionarySetValue(dict
, CFSTR("RegisteredAddresses"), addrs
);
2854 SCDynamicStoreSetValue(store
, sckey
, dict
);
2857 if (store
) CFRelease(store
);
2858 if (ipstore
) CFRelease(ipstore
);
2859 if (sckey
) CFRelease(sckey
);
2860 if (dict
) CFRelease(dict
);
2861 if (ipdict
) CFRelease(ipdict
);
2862 if (entityname
) CFRelease(entityname
);
2863 if (addrs
) CFRelease(addrs
);
2865 update_idle_timer();