1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2007-2018 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>
42 #include <Security/Security.h>
43 #include <SystemConfiguration/SystemConfiguration.h>
44 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
45 #include <TargetConditionals.h>
46 #include <IOKit/pwr_mgt/IOPMLib.h>
48 #include <sys/sysctl.h>
50 #include "mDNSEmbeddedAPI.h"
52 #include "dnssd_ipc.h"
55 #include "helper-server.h"
56 #include "P2PPacketFilter.h"
58 #include <netinet/ip.h>
59 #include <netinet/tcp.h>
61 #include <IOKit/pwr_mgt/IOPMLibPrivate.h>
64 #define RTF_IFSCOPE 0x1000000
67 #if TARGET_OS_EMBEDDED
69 #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 uid_t mDNSResponderUID
;
83 gid_t mDNSResponderGID
;
87 os_log_info(log_handle
,"mDNSResponderHelper exiting");
91 mDNSexport
void RequestBPF()
95 DNSServiceErrorType err
= ConnectToServer(&ref
, 0, send_bpf
, NULL
, NULL
, NULL
);
98 os_log(log_handle
, "RequestBPF: ConnectToServer %d", err
);
103 size_t len
= sizeof(DNSServiceFlags
);
104 ipc_msg_hdr
*hdr
= create_hdr(send_bpf
, &len
, &ptr
, 0, ref
);
107 os_log(log_handle
, "RequestBPF: No mem to allocate");
108 DNSServiceRefDeallocate(ref
);
113 deliver_request(hdr
, ref
); // Will free hdr for us
114 DNSServiceRefDeallocate(ref
);
117 os_log_info(log_handle
,"RequestBPF: Successful");
121 void PowerRequest(int key
, int interval
, int *err
)
123 *err
= kHelperErr_DefaultErr
;
125 os_log_info(log_handle
,"PowerRequest: key %d interval %d, err %d", key
, interval
, *err
);
127 CFArrayRef events
= IOPMCopyScheduledPowerEvents();
131 CFIndex count
= CFArrayGetCount(events
);
132 for (i
=0; i
<count
; i
++)
134 CFDictionaryRef dict
= CFArrayGetValueAtIndex(events
, i
);
135 CFStringRef id
= CFDictionaryGetValue(dict
, CFSTR(kIOPMPowerEventAppNameKey
));
136 if (CFEqual(id
, CFSTR("mDNSResponderHelper")))
138 CFDateRef EventTime
= CFDictionaryGetValue(dict
, CFSTR(kIOPMPowerEventTimeKey
));
139 CFStringRef EventType
= CFDictionaryGetValue(dict
, CFSTR(kIOPMPowerEventTypeKey
));
140 IOReturn result
= IOPMCancelScheduledPowerEvent(EventTime
, id
, EventType
);
141 //os_log(log_handle, "Deleting old event %s");
143 os_log(log_handle
, "IOPMCancelScheduledPowerEvent %d failed %d", i
, result
);
149 if (key
< 0) // mDNSPowerRequest(-1,-1) means "clear any stale schedules" (see above)
151 *err
= kHelperErr_NoErr
;
153 else if (key
== 0) // mDNSPowerRequest(0, 0) means "sleep now"
155 IOReturn r
= IOPMSleepSystem(IOPMFindPowerManagement(MACH_PORT_NULL
));
159 os_log_info(log_handle
, "IOPMSleepSystem %d", r
);
165 CFDateRef wakeTime
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent() + interval
);
168 CFMutableDictionaryRef scheduleDict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
170 CFDictionaryAddValue(scheduleDict
, CFSTR(kIOPMPowerEventTimeKey
), wakeTime
);
171 CFDictionaryAddValue(scheduleDict
, CFSTR(kIOPMPowerEventAppNameKey
), CFSTR("mDNSResponderHelper"));
172 CFDictionaryAddValue(scheduleDict
, CFSTR(kIOPMPowerEventTypeKey
), key
? CFSTR(kIOPMAutoWake
) : CFSTR(kIOPMAutoSleep
));
174 IOReturn r
= IOPMRequestSysWake(scheduleDict
);
178 os_log_info(log_handle
, "IOPMRequestSysWake(%d) %d %x", interval
, r
, r
);
182 CFRelease(scheduleDict
);
189 void SetLocalAddressCacheEntry(int ifindex
, int family
, const v6addr_t ip
, const ethaddr_t eth
, int *err
)
192 #define IPv6FMTSTRING "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X"
193 #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]
197 os_log_info(log_handle
,"SetLocalAddressCacheEntry %d IPv%d %d.%d.%d.%d %02X:%02X:%02X:%02X:%02X:%02X",
198 ifindex
, family
, ip
[0], ip
[1], ip
[2], ip
[3], eth
[0], eth
[1], eth
[2], eth
[3], eth
[4], eth
[5]);
202 os_log_info(log_handle
,"SetLocalAddressCacheEntry %d IPv%d " IPv6FMTSTRING
" %02X:%02X:%02X:%02X:%02X:%02X",
203 ifindex
, family
, IPv6FMTARGS
, eth
[0], eth
[1], eth
[2], eth
[3], eth
[4], eth
[5]);
206 *err
= kHelperErr_DefaultErr
;
208 static int s
= -1, seq
= 0;
211 s
= socket(PF_ROUTE
, SOCK_RAW
, 0);
213 os_log(log_handle
, "SetLocalAddressCacheEntry: socket(PF_ROUTE, SOCK_RAW, 0) failed %d (%s)", errno
, strerror(errno
));
219 gettimeofday(&tv
, 0);
222 struct { struct rt_msghdr hdr
; struct sockaddr_inarp dst
; struct sockaddr_dl sdl
; } rtmsg
;
223 memset(&rtmsg
, 0, sizeof(rtmsg
));
225 rtmsg
.hdr
.rtm_msglen
= sizeof(rtmsg
);
226 rtmsg
.hdr
.rtm_version
= RTM_VERSION
;
227 rtmsg
.hdr
.rtm_type
= RTM_ADD
;
228 rtmsg
.hdr
.rtm_index
= ifindex
;
229 rtmsg
.hdr
.rtm_flags
= RTF_HOST
| RTF_STATIC
| RTF_IFSCOPE
;
230 rtmsg
.hdr
.rtm_addrs
= RTA_DST
| RTA_GATEWAY
;
231 rtmsg
.hdr
.rtm_pid
= 0;
232 rtmsg
.hdr
.rtm_seq
= seq
++;
233 rtmsg
.hdr
.rtm_errno
= 0;
234 rtmsg
.hdr
.rtm_use
= 0;
235 rtmsg
.hdr
.rtm_inits
= RTV_EXPIRE
;
236 rtmsg
.hdr
.rtm_rmx
.rmx_expire
= tv
.tv_sec
+ 30;
238 rtmsg
.dst
.sin_len
= sizeof(rtmsg
.dst
);
239 rtmsg
.dst
.sin_family
= AF_INET
;
240 rtmsg
.dst
.sin_port
= 0;
241 rtmsg
.dst
.sin_addr
.s_addr
= *(in_addr_t
*)ip
;
242 rtmsg
.dst
.sin_srcaddr
.s_addr
= 0;
243 rtmsg
.dst
.sin_tos
= 0;
244 rtmsg
.dst
.sin_other
= 0;
246 rtmsg
.sdl
.sdl_len
= sizeof(rtmsg
.sdl
);
247 rtmsg
.sdl
.sdl_family
= AF_LINK
;
248 rtmsg
.sdl
.sdl_index
= ifindex
;
249 rtmsg
.sdl
.sdl_type
= IFT_ETHER
;
250 rtmsg
.sdl
.sdl_nlen
= 0;
251 rtmsg
.sdl
.sdl_alen
= ETHER_ADDR_LEN
;
252 rtmsg
.sdl
.sdl_slen
= 0;
254 // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h)
255 memcpy(rtmsg
.sdl
.sdl_data
, eth
, sizeof(ethaddr_t
));
257 int len
= write(s
, (char *)&rtmsg
, sizeof(rtmsg
));
259 os_log(log_handle
, "SetLocalAddressCacheEntry: write(%zu) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s)",
260 sizeof(rtmsg
), ifindex
, ip
[0], ip
[1], ip
[2], ip
[3], rtmsg
.hdr
.rtm_seq
, len
, errno
, strerror(errno
));
261 len
= read(s
, (char *)&rtmsg
, sizeof(rtmsg
));
262 if (len
< 0 || rtmsg
.hdr
.rtm_errno
)
263 os_log(log_handle
, "SetLocalAddressCacheEntry: read (%zu) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s) %d",
264 sizeof(rtmsg
), ifindex
, ip
[0], ip
[1], ip
[2], ip
[3], rtmsg
.hdr
.rtm_seq
, len
, errno
, strerror(errno
), rtmsg
.hdr
.rtm_errno
);
266 *err
= kHelperErr_NoErr
;
270 struct { struct rt_msghdr hdr
; struct sockaddr_in6 dst
; struct sockaddr_dl sdl
; } rtmsg
;
271 memset(&rtmsg
, 0, sizeof(rtmsg
));
273 rtmsg
.hdr
.rtm_msglen
= sizeof(rtmsg
);
274 rtmsg
.hdr
.rtm_version
= RTM_VERSION
;
275 rtmsg
.hdr
.rtm_type
= RTM_ADD
;
276 rtmsg
.hdr
.rtm_index
= ifindex
;
277 rtmsg
.hdr
.rtm_flags
= RTF_HOST
| RTF_STATIC
| RTF_IFSCOPE
;
278 rtmsg
.hdr
.rtm_addrs
= RTA_DST
| RTA_GATEWAY
;
279 rtmsg
.hdr
.rtm_pid
= 0;
280 rtmsg
.hdr
.rtm_seq
= seq
++;
281 rtmsg
.hdr
.rtm_errno
= 0;
282 rtmsg
.hdr
.rtm_use
= 0;
283 rtmsg
.hdr
.rtm_inits
= RTV_EXPIRE
;
284 rtmsg
.hdr
.rtm_rmx
.rmx_expire
= tv
.tv_sec
+ 30;
286 rtmsg
.dst
.sin6_len
= sizeof(rtmsg
.dst
);
287 rtmsg
.dst
.sin6_family
= AF_INET6
;
288 rtmsg
.dst
.sin6_port
= 0;
289 rtmsg
.dst
.sin6_flowinfo
= 0;
290 rtmsg
.dst
.sin6_addr
= *(struct in6_addr
*)ip
;
291 rtmsg
.dst
.sin6_scope_id
= ifindex
;
293 rtmsg
.sdl
.sdl_len
= sizeof(rtmsg
.sdl
);
294 rtmsg
.sdl
.sdl_family
= AF_LINK
;
295 rtmsg
.sdl
.sdl_index
= ifindex
;
296 rtmsg
.sdl
.sdl_type
= IFT_ETHER
;
297 rtmsg
.sdl
.sdl_nlen
= 0;
298 rtmsg
.sdl
.sdl_alen
= ETHER_ADDR_LEN
;
299 rtmsg
.sdl
.sdl_slen
= 0;
301 // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h)
302 memcpy(rtmsg
.sdl
.sdl_data
, eth
, sizeof(ethaddr_t
));
304 int len
= write(s
, (char *)&rtmsg
, sizeof(rtmsg
));
306 os_log(log_handle
, "SetLocalAddressCacheEntry: write(%zu) interface %d address " IPv6FMTSTRING
" seq %d result %d errno %d (%s)",
307 sizeof(rtmsg
), ifindex
, IPv6FMTARGS
, rtmsg
.hdr
.rtm_seq
, len
, errno
, strerror(errno
));
308 len
= read(s
, (char *)&rtmsg
, sizeof(rtmsg
));
309 if (len
< 0 || rtmsg
.hdr
.rtm_errno
)
310 os_log(log_handle
, "SetLocalAddressCacheEntry: read (%zu) interface %d address " IPv6FMTSTRING
" seq %d result %d errno %d (%s) %d",
311 sizeof(rtmsg
), ifindex
, IPv6FMTARGS
, rtmsg
.hdr
.rtm_seq
, len
, errno
, strerror(errno
), rtmsg
.hdr
.rtm_errno
);
313 *err
= kHelperErr_NoErr
;
321 void UserNotify(const char *title
, const char *msg
)
324 #ifndef NO_CFUSERNOTIFICATION
325 static const char footer
[] = "(Note: This message only appears on machines with 17.x.x.x IP addresses"
326 " or on debugging builds with ForceAlerts set — i.e. only at Apple — not on customer machines.)";
327 CFStringRef alertHeader
= CFStringCreateWithCString(NULL
, title
, kCFStringEncodingUTF8
);
328 CFStringRef alertBody
= CFStringCreateWithCString(NULL
, msg
, kCFStringEncodingUTF8
);
329 CFStringRef alertFooter
= CFStringCreateWithCString(NULL
, footer
, kCFStringEncodingUTF8
);
330 CFStringRef alertMessage
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@\r\r%@"), alertBody
, alertFooter
);
331 CFRelease(alertBody
);
332 CFRelease(alertFooter
);
333 int err
= CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel
, NULL
, NULL
, NULL
, alertHeader
, alertMessage
, NULL
);
335 os_log(log_handle
, "CFUserNotificationDisplayNotice returned %d", err
);
336 CFRelease(alertHeader
);
337 CFRelease(alertMessage
);
341 #endif /* NO_CFUSERNOTIFICATION */
347 char usercompname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last computer name the user saw
348 char userhostname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last local host name the user saw
349 char lastcompname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last computer name saved to preferences
350 char lasthostname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last local host name saved to preferences
352 #ifndef NO_CFUSERNOTIFICATION
353 static CFStringRef CFS_OQ
= NULL
;
354 static CFStringRef CFS_CQ
= NULL
;
355 static CFStringRef CFS_Format
= NULL
;
356 static CFStringRef CFS_ComputerName
= NULL
;
357 static CFStringRef CFS_ComputerNameMsg
= NULL
;
358 static CFStringRef CFS_LocalHostName
= NULL
;
359 static CFStringRef CFS_LocalHostNameMsg
= NULL
;
360 static CFStringRef CFS_Problem
= NULL
;
362 static CFUserNotificationRef gNotification
= NULL
;
363 static CFRunLoopSourceRef gNotificationRLS
= NULL
;
365 static void NotificationCallBackDismissed(CFUserNotificationRef userNotification
, CFOptionFlags responseFlags
)
367 os_log_debug(log_handle
,"entry");
368 (void)responseFlags
; // Unused
369 if (userNotification
!= gNotification
) os_log(log_handle
, "NotificationCallBackDismissed: Wrong CFUserNotificationRef");
370 if (gNotificationRLS
)
372 // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
373 // We need to explicitly specify the desired CFRunLoop from which we want to remove this event source.
374 CFRunLoopRemoveSource(gRunLoop
, gNotificationRLS
, kCFRunLoopDefaultMode
);
375 CFRelease(gNotificationRLS
);
376 gNotificationRLS
= NULL
;
377 CFRelease(gNotification
);
378 gNotification
= NULL
;
380 // By dismissing the alert, the user has conceptually acknowleged the rename.
381 // (e.g. the machine's name is now officially "computer-2.local", not "computer.local".)
382 // If we get *another* conflict, the new alert should refer to the 'old' name
383 // as now being "computer-2.local", not "computer.local"
389 unpause_idle_timer();
392 static void ShowNameConflictNotification(CFMutableArrayRef header
, CFStringRef subtext
)
394 CFMutableDictionaryRef dictionary
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
395 if (!dictionary
) return;
397 os_log_debug(log_handle
,"entry");
399 CFDictionarySetValue(dictionary
, kCFUserNotificationAlertHeaderKey
, header
);
400 CFDictionarySetValue(dictionary
, kCFUserNotificationAlertMessageKey
, subtext
);
402 CFURLRef urlRef
= CFURLCreateWithFileSystemPath(NULL
, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle
, true);
403 if (urlRef
) { CFDictionarySetValue(dictionary
, kCFUserNotificationLocalizationURLKey
, urlRef
); CFRelease(urlRef
); }
405 if (gNotification
) // If notification already on-screen, update it in place
406 CFUserNotificationUpdate(gNotification
, 0, kCFUserNotificationCautionAlertLevel
, dictionary
);
407 else // else, we need to create it
410 gNotification
= CFUserNotificationCreate(NULL
, 0, kCFUserNotificationCautionAlertLevel
, &error
, dictionary
);
411 if (!gNotification
|| error
) { os_log(log_handle
, "ShowNameConflictNotification: CFUserNotificationRef: Error %d", error
); return; }
412 gNotificationRLS
= CFUserNotificationCreateRunLoopSource(NULL
, gNotification
, NotificationCallBackDismissed
, 0);
413 if (!gNotificationRLS
) { os_log(log_handle
, "ShowNameConflictNotification: RLS"); CFRelease(gNotification
); gNotification
= NULL
; return; }
414 // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
415 // We need to explicitly specify the desired CFRunLoop to which we want to add this event source.
416 CFRunLoopAddSource(gRunLoop
, gNotificationRLS
, kCFRunLoopDefaultMode
);
417 os_log_debug(log_handle
,"gRunLoop=%p gNotification=%p gNotificationRLS=%p", gRunLoop
, gNotification
, gNotificationRLS
);
421 CFRelease(dictionary
);
424 static CFMutableArrayRef
CreateAlertHeader(const char* oldname
, const char* newname
, const CFStringRef msg
, const char* suffix
)
426 CFMutableArrayRef alertHeader
= NULL
;
428 const CFStringRef cfoldname
= CFStringCreateWithCString(NULL
, oldname
, kCFStringEncodingUTF8
);
429 // NULL newname means we've given up trying to construct a name that doesn't conflict
430 const CFStringRef cfnewname
= newname
? CFStringCreateWithCString(NULL
, newname
, kCFStringEncodingUTF8
) : NULL
;
431 // We tag a zero-width non-breaking space at the end of the literal text to guarantee that, no matter what
432 // arbitrary computer name the user may choose, this exact text (with zero-width non-breaking space added)
433 // can never be one that occurs in the Localizable.strings translation file.
436 os_log(log_handle
, "Could not construct CFStrings for old=%s", newname
);
438 else if (newname
&& !cfnewname
)
440 os_log(log_handle
, "Could not construct CFStrings for new=%s", newname
);
444 const CFStringRef s1
= CFStringCreateWithFormat(NULL
, NULL
, CFS_Format
, cfoldname
, suffix
);
445 const CFStringRef s2
= cfnewname
? CFStringCreateWithFormat(NULL
, NULL
, CFS_Format
, cfnewname
, suffix
) : NULL
;
447 alertHeader
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
451 os_log(log_handle
, "Could not construct secondary CFString for old=%s", oldname
);
453 else if (cfnewname
&& !s2
)
455 os_log(log_handle
, "Could not construct secondary CFString for new=%s", newname
);
457 else if (!alertHeader
)
459 os_log(log_handle
, "Could not construct CFArray for notification");
463 // Make sure someone is logged in. We don't want this popping up over the login window
466 CFStringRef userName
= SCDynamicStoreCopyConsoleUser(NULL
, &uid
, &gid
);
469 if (!CFEqual(userName
, CFSTR("_mbsetupuser")))
471 CFArrayAppendValue(alertHeader
, msg
); // Opening phrase of message, provided by caller
472 CFArrayAppendValue(alertHeader
, CFS_OQ
); CFArrayAppendValue(alertHeader
, s1
); CFArrayAppendValue(alertHeader
, CFS_CQ
);
473 CFArrayAppendValue(alertHeader
, CFSTR(" is already in use on this network. "));
476 CFArrayAppendValue(alertHeader
, CFSTR("The name has been changed to "));
477 CFArrayAppendValue(alertHeader
, CFS_OQ
); CFArrayAppendValue(alertHeader
, s2
); CFArrayAppendValue(alertHeader
, CFS_CQ
);
478 CFArrayAppendValue(alertHeader
, CFSTR("."));
482 CFArrayAppendValue(alertHeader
, CFSTR("All attempts to find an available name by adding a number to the name were also unsuccessful."));
488 if (s1
) CFRelease(s1
);
489 if (s2
) CFRelease(s2
);
491 if (cfoldname
) CFRelease(cfoldname
);
492 if (cfnewname
) CFRelease(cfnewname
);
496 #endif /* ndef NO_CFUSERNOTIFICATION */
498 static void update_notification(void)
500 #ifndef NO_CFUSERNOTIFICATION
501 os_log_debug(log_handle
,"entry ucn=%s, uhn=%s, lcn=%s, lhn=%s", usercompname
, userhostname
, lastcompname
, lasthostname
);
504 // Note: The "\xEF\xBB\xBF" byte sequence (U+FEFF) in the CFS_Format string is the UTF-8 encoding of the zero-width non-breaking space character.
505 // By appending this invisible character on the end of literal names, we ensure the these strings cannot inadvertently match any string
506 // in the localization file -- since we know for sure that none of our strings in the localization file contain the ZWNBS character.
507 CFS_Format
= CFStringCreateWithCString(NULL
, "%@%s\xEF\xBB\xBF", kCFStringEncodingUTF8
);
509 // The strings CFS_OQ, CFS_CQ and the others below are the localization keys for the “Localizable.strings” files,
510 // and MUST NOT BE CHANGED, or localization substitution will be broken.
511 // To change the text displayed to the user, edit the values in the appropriate “Localizable.strings” file, not the keys here.
512 // This includes making changes for adding appropriate directionality overrides like LRM, LRE, RLE, PDF, etc. These need to go in the values
513 // in the appropriate “Localizable.strings” entries, not in the keys here (which then won’t match *any* entry in the localization files).
514 // These localization keys here were broken in <rdar://problem/8629082> and then subsequently repaired in
515 // <rdar://problem/21071535> [mDNSResponder]: TA: Gala15A185: Incorrect punctuation marks when Change the host name to an exist one
516 CFS_OQ
= CFStringCreateWithCString(NULL
, "“", kCFStringEncodingUTF8
); // DO NOT CHANGE THIS STRING
517 CFS_CQ
= CFStringCreateWithCString(NULL
, "”", kCFStringEncodingUTF8
); // DO NOT CHANGE THIS STRING
518 CFS_ComputerName
= CFStringCreateWithCString(NULL
, "The name of your computer ", kCFStringEncodingUTF8
);
519 CFS_ComputerNameMsg
= CFStringCreateWithCString(NULL
, "To change the name of your computer, "
520 "open System Preferences and click Sharing, then type the name in the Computer Name field.", kCFStringEncodingUTF8
);
521 CFS_LocalHostName
= CFStringCreateWithCString(NULL
, "This computer’s local hostname ", kCFStringEncodingUTF8
);
522 CFS_LocalHostNameMsg
= CFStringCreateWithCString(NULL
, "To change the local hostname, "
523 "open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field.", kCFStringEncodingUTF8
);
524 CFS_Problem
= CFStringCreateWithCString(NULL
, "This may indicate a problem with the local network. "
525 "Please inform your network administrator.", kCFStringEncodingUTF8
);
528 if (!usercompname
[0] && !userhostname
[0])
530 if (gNotificationRLS
)
532 os_log_debug(log_handle
,"canceling notification %p", gNotification
);
533 CFUserNotificationCancel(gNotification
);
534 unpause_idle_timer();
539 CFMutableArrayRef header
= NULL
;
540 CFStringRef
* subtext
= NULL
;
541 if (userhostname
[0] && !lasthostname
[0]) // we've given up trying to construct a name that doesn't conflict
543 header
= CreateAlertHeader(userhostname
, NULL
, CFS_LocalHostName
, ".local");
544 subtext
= &CFS_Problem
;
546 else if (usercompname
[0])
548 header
= CreateAlertHeader(usercompname
, lastcompname
, CFS_ComputerName
, "");
549 subtext
= &CFS_ComputerNameMsg
;
553 header
= CreateAlertHeader(userhostname
, lasthostname
, CFS_LocalHostName
, ".local");
554 subtext
= &CFS_LocalHostNameMsg
;
556 ShowNameConflictNotification(header
, *subtext
);
562 void PreferencesSetName(int key
, const char* old
, const char* new)
564 SCPreferencesRef session
= NULL
;
566 Boolean locked
= FALSE
;
567 CFStringRef cfstr
= NULL
;
570 Boolean needUpdate
= FALSE
;
572 os_log_info(log_handle
,"PreferencesSetName: entry %s old=%s new=%s",
573 key
==kmDNSComputerName
? "ComputerName" : (key
==kmDNSLocalHostName
? "LocalHostName" : "UNKNOWN"), old
, new);
575 switch ((enum mDNSPreferencesSetNameKey
)key
)
577 case kmDNSComputerName
:
581 case kmDNSLocalHostName
:
586 os_log(log_handle
, "PreferencesSetName: unrecognized key: %d", key
);
592 os_log(log_handle
, "PreferencesSetName: no last ptr");
598 os_log(log_handle
, "PreferencesSetName:: no user ptr");
602 if (0 == strncmp(old
, new, MAX_DOMAIN_LABEL
+1))
604 // old and new are same means the config changed i.e, the user has set something in the preferences pane.
605 // This means the conflict has been resolved. We need to dismiss the dialogue.
606 if (last
[0] && 0 != strncmp(last
, new, MAX_DOMAIN_LABEL
+1))
616 // old and new are not same, this means there is a conflict. For the first conflict, we show
617 // the old value and the new value. For all subsequent conflicts, while the dialogue is still
618 // up, we do a real time update of the "new" value in the dialogue. That's why we update just
619 // "last" here and not "user".
620 if (strncmp(last
, new, MAX_DOMAIN_LABEL
+1))
622 strncpy(last
, new, MAX_DOMAIN_LABEL
);
627 // If we are not showing the dialogue, we need to remember the first "old" value so that
628 // we maintain the same through the lifetime of the dialogue. Subsequent conflicts don't
629 // update the "old" value.
632 strncpy(user
, old
, MAX_DOMAIN_LABEL
);
636 if (!new[0]) // we've given up trying to construct a name that doesn't conflict
639 cfstr
= CFStringCreateWithCString(NULL
, new, kCFStringEncodingUTF8
);
641 session
= SCPreferencesCreate(NULL
, CFSTR(kHelperService
), NULL
);
643 if (cfstr
== NULL
|| session
== NULL
)
645 os_log(log_handle
, "PreferencesSetName: SCPreferencesCreate failed");
648 if (!SCPreferencesLock(session
, 0))
650 os_log(log_handle
,"PreferencesSetName: lock failed");
655 switch ((enum mDNSPreferencesSetNameKey
)key
)
657 case kmDNSComputerName
:
659 // We want to write the new Computer Name to System Preferences, without disturbing the user-selected
660 // system-wide default character set used for things like AppleTalk NBP and NETBIOS service advertising.
661 // Note that this encoding is not used for the computer name, but since both are set by the same call,
662 // we need to take care to set the name without changing the character set.
663 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
664 CFStringRef unused
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
672 encoding
= kCFStringEncodingUTF8
;
675 ok
= SCPreferencesSetComputerName(session
, cfstr
, encoding
);
679 case kmDNSLocalHostName
:
680 ok
= SCPreferencesSetLocalHostName(session
, cfstr
);
687 if (!ok
|| !SCPreferencesCommitChanges(session
) ||
688 !SCPreferencesApplyChanges(session
))
690 os_log(log_handle
, "PreferencesSetName: SCPreferences update failed");
693 os_log_info(log_handle
,"PreferencesSetName: succeeded");
701 SCPreferencesUnlock(session
);
706 update_notification();
715 formatDnsPrefixedServiceItem
,
716 #if MDNSRESPONDER_BTMM_SUPPORT
717 formatBtmmPrefixedServiceItem
721 // On Mac OS X on Intel, the four-character string seems to be stored backwards, at least sometimes.
722 // I suspect some overenthusiastic inexperienced engineer said, "On Intel everything's backwards,
723 // therefore I need to add some byte swapping in this API to make this four-character string backwards too."
724 // To cope with this we allow *both* "ddns" and "sndd" as valid item types.
727 #ifndef NO_SECURITYFRAMEWORK
728 #if MDNSRESPONDER_BTMM_SUPPORT
729 static const char btmmprefix
[] = "btmmdns:";
731 static const char dnsprefix
[] = "dns:";
732 static const char ddns
[] = "ddns";
733 static const char ddnsrev
[] = "sndd";
735 static enum DNSKeyFormat
getDNSKeyFormat(SecKeychainItemRef item
, SecKeychainAttributeList
**attributesp
)
737 static UInt32 tags
[4] =
739 kSecTypeItemAttr
, kSecServiceItemAttr
, kSecAccountItemAttr
, kSecLabelItemAttr
741 static SecKeychainAttributeInfo attributeInfo
=
743 sizeof(tags
)/sizeof(tags
[0]), tags
, NULL
745 SecKeychainAttributeList
*attributes
= NULL
;
746 enum DNSKeyFormat format
;
747 Boolean malformed
= FALSE
;
748 OSStatus status
= noErr
;
752 if (noErr
!= (status
= SecKeychainItemCopyAttributesAndData(item
, &attributeInfo
, NULL
, &attributes
, NULL
, NULL
)))
754 os_log_info(log_handle
,"getDNSKeyFormat: SecKeychainItemCopyAttributesAndData %d - skipping", status
);
757 if (attributeInfo
.count
!= attributes
->count
)
759 for (i
= 0; !malformed
&& i
< (int)attributeInfo
.count
; ++i
)
760 if (attributeInfo
.tag
[i
] != attributes
->attr
[i
].tag
)
764 os_log(log_handle
, "getDNSKeyFormat: malformed result from SecKeychainItemCopyAttributesAndData - skipping");
768 os_log_info(log_handle
,"getDNSKeyFormat: entry (\"%.*s\", \"%.*s\", \"%.*s\")",
769 (int)attributes
->attr
[0].length
, attributes
->attr
[0].data
,
770 (int)attributes
->attr
[1].length
, attributes
->attr
[1].data
,
771 (int)attributes
->attr
[2].length
, attributes
->attr
[2].data
);
773 if (attributes
->attr
[1].length
>= MAX_ESCAPED_DOMAIN_NAME
+
776 os_log(log_handle
, "getDNSKeyFormat: kSecServiceItemAttr too long (%u) - skipping",
777 (unsigned int)attributes
->attr
[1].length
);
780 if (attributes
->attr
[2].length
>= MAX_ESCAPED_DOMAIN_NAME
)
782 os_log(log_handle
, "getDNSKeyFormat: kSecAccountItemAttr too long (%u) - skipping",
783 (unsigned int)attributes
->attr
[2].length
);
786 if (attributes
->attr
[1].length
>= sizeof(dnsprefix
)-1 && 0 == strncasecmp(attributes
->attr
[1].data
, dnsprefix
, sizeof(dnsprefix
)-1))
787 format
= formatDnsPrefixedServiceItem
;
788 #if MDNSRESPONDER_BTMM_SUPPORT
789 else if (attributes
->attr
[1].length
>= sizeof(btmmprefix
)-1 && 0 == strncasecmp(attributes
->attr
[1].data
, btmmprefix
, sizeof(btmmprefix
)-1))
790 format
= formatBtmmPrefixedServiceItem
;
792 else if (attributes
->attr
[0].length
== sizeof(ddns
)-1 && 0 == strncasecmp(attributes
->attr
[0].data
, ddns
, sizeof(ddns
)-1))
793 format
= formatDdnsTypeItem
;
794 else if (attributes
->attr
[0].length
== sizeof(ddnsrev
)-1 && 0 == strncasecmp(attributes
->attr
[0].data
, ddnsrev
, sizeof(ddnsrev
)-1))
795 format
= formatDdnsTypeItem
;
798 os_log_info(log_handle
,"getDNSKeyFormat: uninterested in this entry");
802 *attributesp
= attributes
;
803 os_log_info(log_handle
,"getDNSKeyFormat: accepting this entry");
807 SecKeychainItemFreeAttributesAndData(attributes
, NULL
);
808 return formatNotDNSKey
;
811 // Insert the attributes as defined by mDNSKeyChainAttributes
812 static CFPropertyListRef
copyKeychainItemInfo(SecKeychainItemRef item
, SecKeychainAttributeList
*attributes
, enum DNSKeyFormat format
)
814 CFMutableArrayRef entry
= NULL
;
815 CFDataRef data
= NULL
;
816 OSStatus status
= noErr
;
820 if (NULL
== (entry
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
)))
822 os_log(log_handle
, "copyKeychainItemInfo: CFArrayCreateMutable failed");
826 // Insert the Account attribute (kmDNSKcWhere)
827 switch ((enum DNSKeyFormat
)format
)
829 case formatDdnsTypeItem
:
830 data
= CFDataCreate(kCFAllocatorDefault
, attributes
->attr
[1].data
, attributes
->attr
[1].length
);
832 case formatDnsPrefixedServiceItem
:
833 #if MDNSRESPONDER_BTMM_SUPPORT
834 case formatBtmmPrefixedServiceItem
:
836 data
= CFDataCreate(kCFAllocatorDefault
, attributes
->attr
[1].data
, attributes
->attr
[1].length
);
839 os_log(log_handle
, "copyKeychainItemInfo: unknown DNSKeyFormat value");
844 os_log(log_handle
, "copyKeychainItemInfo: CFDataCreate for attr[1] failed");
847 CFArrayAppendValue(entry
, data
);
850 // Insert the Where attribute (kmDNSKcAccount)
851 if (NULL
== (data
= CFDataCreate(kCFAllocatorDefault
, attributes
->attr
[2].data
, attributes
->attr
[2].length
)))
853 os_log(log_handle
, "copyKeychainItemInfo: CFDataCreate for attr[2] failed");
857 CFArrayAppendValue(entry
, data
);
860 // Insert the Key attribute (kmDNSKcKey)
861 if (noErr
!= (status
= SecKeychainItemCopyAttributesAndData(item
, NULL
, NULL
, NULL
, &keylen
, &keyp
)))
863 os_log(log_handle
, "copyKeychainItemInfo: could not retrieve key for \"%.*s\": %d",
864 (int)attributes
->attr
[1].length
, attributes
->attr
[1].data
, status
);
868 data
= CFDataCreate(kCFAllocatorDefault
, keyp
, keylen
);
869 SecKeychainItemFreeAttributesAndData(NULL
, keyp
);
872 os_log(log_handle
, "copyKeychainItemInfo: CFDataCreate for keyp failed");
875 CFArrayAppendValue(entry
, data
);
878 // Insert the Name attribute (kmDNSKcName)
879 if (NULL
== (data
= CFDataCreate(kCFAllocatorDefault
, attributes
->attr
[3].data
, attributes
->attr
[3].length
)))
881 os_log(log_handle
, "copyKeychainItemInfo: CFDataCreate for attr[3] failed");
885 CFArrayAppendValue(entry
, data
);
896 void KeychainGetSecrets(__unused
unsigned int *numsecrets
,__unused
unsigned long *secrets
, __unused
unsigned int *secretsCnt
, __unused
int *err
)
898 #ifndef NO_SECURITYFRAMEWORK
899 CFWriteStreamRef stream
= NULL
;
900 CFDataRef result
= NULL
;
901 CFPropertyListRef entry
= NULL
;
902 CFMutableArrayRef keys
= NULL
;
903 SecKeychainRef skc
= NULL
;
904 SecKeychainItemRef item
= NULL
;
905 SecKeychainSearchRef search
= NULL
;
906 SecKeychainAttributeList
*attributes
= NULL
;
907 enum DNSKeyFormat format
;
910 os_log_info(log_handle
,"KeychainGetSecrets: entry");
911 *err
= kHelperErr_NoErr
;
913 *secrets
= (vm_offset_t
)NULL
;
915 if (NULL
== (keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
)))
917 os_log(log_handle
, "KeychainGetSecrets: CFArrayCreateMutable failed");
918 *err
= kHelperErr_ApiErr
;
921 if (noErr
!= (status
= SecKeychainCopyDefault(&skc
)))
923 *err
= kHelperErr_ApiErr
;
926 #pragma clang diagnostic push
927 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
928 if (noErr
!= (status
= SecKeychainSearchCreateFromAttributes(skc
, kSecGenericPasswordItemClass
, NULL
, &search
)))
930 *err
= kHelperErr_ApiErr
;
933 for (status
= SecKeychainSearchCopyNext(search
, &item
); noErr
== status
; status
= SecKeychainSearchCopyNext(search
, &item
))
935 if (formatNotDNSKey
!= (format
= getDNSKeyFormat(item
, &attributes
)) &&
936 NULL
!= (entry
= copyKeychainItemInfo(item
, attributes
, format
)))
938 CFArrayAppendValue(keys
, entry
);
941 SecKeychainItemFreeAttributesAndData(attributes
, NULL
);
944 #pragma clang diagnostic pop
945 if (errSecItemNotFound
!= status
)
946 os_log(log_handle
, "KeychainGetSecrets: SecKeychainSearchCopyNext failed: %d", status
);
948 if (NULL
== (stream
= CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorDefault
, kCFAllocatorDefault
)))
950 *err
= kHelperErr_ApiErr
;
951 os_log(log_handle
, "KeychainGetSecrets:CFWriteStreamCreateWithAllocatedBuffers failed");
955 CFWriteStreamOpen(stream
);
956 if (0 == CFPropertyListWrite(keys
, stream
, kCFPropertyListBinaryFormat_v1_0
, 0, NULL
))
958 *err
= kHelperErr_ApiErr
;
959 os_log(log_handle
, "KeychainGetSecrets:CFPropertyListWriteToStream failed");
962 result
= CFWriteStreamCopyProperty(stream
, kCFStreamPropertyDataWritten
);
964 if (KERN_SUCCESS
!= vm_allocate(mach_task_self(), secrets
, CFDataGetLength(result
), VM_FLAGS_ANYWHERE
))
966 *err
= kHelperErr_ApiErr
;
967 os_log(log_handle
, "KeychainGetSecrets: vm_allocate failed");
971 CFDataGetBytes(result
, CFRangeMake(0, CFDataGetLength(result
)), (void *)*secrets
);
972 *secretsCnt
= CFDataGetLength(result
);
973 *numsecrets
= CFArrayGetCount(keys
);
975 os_log_info(log_handle
,"KeychainGetSecrets: succeeded");
978 os_log_info(log_handle
,"KeychainGetSecrets: returning numsecrets[%u] secrets[%lu] secrets addr[%p] secretscount[%u]",
979 *numsecrets
, *secrets
, secrets
, *secretsCnt
);
983 CFWriteStreamClose(stream
);
1000 *err
= KERN_FAILURE
;
1007 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
1008 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
1011 void SendWakeupPacket(unsigned int ifid
, const char *eth_addr
, const char *ip_addr
, int iteration
)
1015 char ifname
[IFNAMSIZ
];
1018 char bpf_device
[12];
1019 struct ether_addr
*ea
;
1020 // (void) ip_addr; // unused
1021 // (void) iteration; // unused
1023 os_log_info(log_handle
,"SendWakeupPacket() ether_addr[%s] ip_addr[%s] if_id[%d] iteration[%d]",
1024 eth_addr
, ip_addr
, ifid
, iteration
);
1026 if (if_indextoname(ifid
, ifname
) == NULL
)
1028 os_log(log_handle
, "SendWakeupPacket: invalid interface index %u", ifid
);
1032 ea
= ether_aton(eth_addr
);
1035 os_log(log_handle
, "SendWakeupPacket: invalid ethernet address %s", eth_addr
);
1039 for (i
= 0; i
< 100; i
++)
1041 snprintf(bpf_device
, sizeof(bpf_device
), "/dev/bpf%d", i
);
1042 bpf_fd
= open(bpf_device
, O_RDWR
, 0);
1052 os_log(log_handle
, "SendWakeupPacket: cannot find a bpf device");
1056 memset(&ifr
, 0, sizeof(ifr
));
1057 strlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
1059 if (ioctl(bpf_fd
, BIOCSETIF
, (char *)&ifr
) < 0)
1061 os_log(log_handle
, "SendWakeupPacket: BIOCSETIF failed %s", strerror(errno
));
1065 // 0x00 Destination address
1067 *ptr
++ = ea
->octet
[i
];
1069 // 0x06 Source address (Note: Since we don't currently set the BIOCSHDRCMPLT option,
1070 // BPF will fill in the real interface address for us)
1074 // 0x0C Ethertype (0x0842)
1078 // 0x0E Wakeup sync sequence
1083 for (j
=0; j
<16; j
++)
1085 *ptr
++ = ea
->octet
[i
];
1091 if (write(bpf_fd
, packet
, ptr
- packet
) < 0)
1093 os_log(log_handle
, "SendWakeupPacket: write failed %s", strerror(errno
));
1096 os_log(log_handle
, "SendWakeupPacket: sent unicast eth_addr %s, ip_addr %s", eth_addr
, ip_addr
);
1098 // Send a broadcast one to handle ethernet switches that don't flood forward packets with
1099 // unknown mac addresses.
1103 if (write(bpf_fd
, packet
, ptr
- packet
) < 0)
1105 os_log(log_handle
, "SendWakeupPacket: write failed %s", strerror(errno
));
1108 os_log(log_handle
, "SendWakeupPacket: sent broadcast eth_addr %s, ip_addr %s", eth_addr
, ip_addr
);
1115 // Open the specified port for protocol in the P2P firewall.
1116 void PacketFilterControl(uint32_t command
, const char * ifname
, uint32_t count
, pfArray_t portArray
, pfArray_t protocolArray
)
1120 os_log_info(log_handle
,"PacketFilterControl: command %d ifname %s, count %d",
1121 command
, ifname
, count
);
1122 os_log_info(log_handle
,"PacketFilterControl: portArray0[%d] portArray1[%d] portArray2[%d] portArray3[%d] protocolArray0[%d] protocolArray1[%d] protocolArray2[%d] protocolArray3[%d]", portArray
[0], portArray
[1], portArray
[2], portArray
[3], protocolArray
[0], protocolArray
[1], protocolArray
[2], protocolArray
[3]);
1127 error
= P2PPacketFilterAddBonjourRuleSet(ifname
, count
, portArray
, protocolArray
);
1129 os_log(log_handle
, "P2PPacketFilterAddBonjourRuleSet failed %s", strerror(error
));
1132 case PF_CLEAR_RULES
:
1133 error
= P2PPacketFilterClearBonjourRules();
1135 os_log(log_handle
, "P2PPacketFilterClearBonjourRules failed %s", strerror(error
));
1139 os_log(log_handle
, "PacketFilterControl: invalid command %d", command
);
1145 static unsigned long in_cksum(unsigned short *ptr
, int nbytes
)
1151 * Our algorithm is simple, using a 32-bit accumulator (sum),
1152 * we add sequential 16-bit words to it, and at the end, fold back
1153 * all the carry bits from the top 16 bits into the lower 16 bits.
1162 /* mop up an odd byte, if necessary */
1165 /* make sure top half is zero */
1169 *((u_char
*)&oddbyte
) = *(u_char
*)ptr
;
1172 /* Add back carry outs from top 16 bits to low 16 bits. */
1173 sum
= (sum
>> 16) + (sum
& 0xffff);
1181 static unsigned short InetChecksum(unsigned short *ptr
, int nbytes
)
1185 sum
= in_cksum(ptr
, nbytes
);
1186 return (unsigned short)~sum
;
1189 static void TCPCheckSum(int af
, struct tcphdr
*t
, int tcplen
, const v6addr_t sadd6
, const v6addr_t dadd6
)
1191 unsigned long sum
= 0;
1192 unsigned short *ptr
;
1194 /* TCP header checksum */
1195 sum
= in_cksum((unsigned short *)t
, tcplen
);
1200 ptr
= (unsigned short *)sadd6
;
1203 ptr
= (unsigned short *)dadd6
;
1207 else if (af
== AF_INET6
)
1210 ptr
= (unsigned short *)sadd6
;
1219 ptr
= (unsigned short *)dadd6
;
1230 sum
+= htons(tcplen
);
1231 sum
+= htons(IPPROTO_TCP
);
1234 sum
= (sum
>> 16) + (sum
& 0xFFFF);
1240 void SendKeepalive(const v6addr_t sadd6
, const v6addr_t dadd6
, uint16_t lport
, uint16_t rport
, uint32_t seq
, uint32_t ack
, uint16_t win
)
1243 #define IPv6FMTSTRING "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X"
1244 #define IPv6FMTSARGS sadd6[0], sadd6[1], sadd6[2], sadd6[3], sadd6[4], sadd6[5], sadd6[6], sadd6[7], sadd6[8], sadd6[9], sadd6[10], sadd6[11], sadd6[12], sadd6[13], sadd6[14], sadd6[15]
1245 #define IPv6FMTDARGS dadd6[0], dadd6[1], dadd6[2], dadd6[3], dadd6[4], dadd6[5], dadd6[6], dadd6[7], dadd6[8], dadd6[9], dadd6[10], dadd6[11], dadd6[12], dadd6[13], dadd6[14], dadd6[15]
1247 os_log_info(log_handle
, "SendKeepalive: "IPv6FMTSTRING
" :space: "IPv6FMTSTRING
"",
1248 IPv6FMTSARGS
, IPv6FMTDARGS
);
1262 struct sockaddr_storage ss_to
;
1263 struct sockaddr_in
*sin_to
= (struct sockaddr_in
*)&ss_to
;
1264 struct sockaddr_in6
*sin6_to
= (struct sockaddr_in6
*)&ss_to
;
1267 char ctlbuf
[CMSG_SPACE(sizeof(struct in6_pktinfo
))];
1268 struct msghdr msghdr
;
1272 os_log_info(log_handle
,"SendKeepalive invoked: lport is[%d] rport is[%d] seq is[%d] ack is[%d] win is[%d]",
1273 lport
, rport
, seq
, ack
, win
);
1275 char buf1
[INET6_ADDRSTRLEN
];
1276 char buf2
[INET6_ADDRSTRLEN
];
1281 inet_ntop(AF_INET6
, sadd6
, buf1
, sizeof(buf1
));
1282 inet_ntop(AF_INET6
, dadd6
, buf2
, sizeof(buf2
));
1284 os_log_info(log_handle
,"SendKeepalive invoked: sadd6 is %s, dadd6 is %s", buf1
, buf2
);
1286 // all the incoming arguments are in network order
1287 if ((*(unsigned *)(sadd6
+4) == 0) && (*(unsigned *)(sadd6
+ 8) == 0) && (*(unsigned *)(sadd6
+ 12) == 0))
1290 memset(&packet4
, 0, sizeof (packet4
));
1292 /* Fill in all the IP header information - should be in host order*/
1293 packet4
.ip
.ip_v
= 4; /* 4-bit Version */
1294 packet4
.ip
.ip_hl
= 5; /* 4-bit Header Length */
1295 packet4
.ip
.ip_tos
= 0; /* 8-bit Type of service */
1296 packet4
.ip
.ip_len
= 40; /* 16-bit Total length */
1297 packet4
.ip
.ip_id
= 9864; /* 16-bit ID field */
1298 packet4
.ip
.ip_off
= 0; /* 13-bit Fragment offset */
1299 packet4
.ip
.ip_ttl
= 63; /* 8-bit Time To Live */
1300 packet4
.ip
.ip_p
= IPPROTO_TCP
; /* 8-bit Protocol */
1301 packet4
.ip
.ip_sum
= 0; /* 16-bit Header checksum (below) */
1302 memcpy(&packet4
.ip
.ip_src
.s_addr
, sadd6
, 4);
1303 memcpy(&packet4
.ip
.ip_dst
.s_addr
, dadd6
, 4);
1305 /* IP header checksum */
1306 packet4
.ip
.ip_sum
= InetChecksum((unsigned short *)&packet4
.ip
, 20);
1309 packetlen
= 40; // sum of IPv4 header len(20) and TCP header len(20)
1314 memset(&packet6
, 0, sizeof (packet6
));
1317 // We don't send IPv6 header, hence just the TCP header len (20)
1321 /* Fill in all the TCP header information */
1322 t
->th_sport
= lport
; /* 16-bit Source port number */
1323 t
->th_dport
= rport
; /* 16-bit Destination port */
1324 t
->th_seq
= seq
; /* 32-bit Sequence Number */
1325 t
->th_ack
= ack
; /* 32-bit Acknowledgement Number */
1326 t
->th_off
= 5; /* Data offset */
1327 t
->th_flags
= TH_ACK
;
1329 t
->th_sum
= 0; /* 16-bit checksum (below) */
1330 t
->th_urp
= 0; /* 16-bit urgent offset */
1332 TCPCheckSum(af
, t
, 20, sadd6
, dadd6
);
1334 /* Open up a RAW socket */
1335 if ((sock
= socket(af
, SOCK_RAW
, IPPROTO_TCP
)) < 0)
1337 os_log(log_handle
, "SendKeepalive: socket %s", strerror(errno
));
1344 if (setsockopt(sock
, IPPROTO_IP
, IP_HDRINCL
, &on
, sizeof (on
)))
1347 os_log(log_handle
, "SendKeepalive: setsockopt %s", strerror(errno
));
1351 memset(sin_to
, 0, sizeof(struct sockaddr_in
));
1352 sin_to
->sin_len
= sizeof(struct sockaddr_in
);
1353 sin_to
->sin_family
= AF_INET
;
1354 memcpy(&sin_to
->sin_addr
, sadd6
, sizeof(struct in_addr
));
1355 sin_to
->sin_port
= rport
;
1357 msghdr
.msg_control
= NULL
;
1358 msghdr
.msg_controllen
= 0;
1363 struct cmsghdr
*ctl
;
1365 memset(sin6_to
, 0, sizeof(struct sockaddr_in6
));
1366 sin6_to
->sin6_len
= sizeof(struct sockaddr_in6
);
1367 sin6_to
->sin6_family
= AF_INET6
;
1368 memcpy(&sin6_to
->sin6_addr
, dadd6
, sizeof(struct in6_addr
));
1370 sin6_to
->sin6_port
= rport
;
1371 sin6_to
->sin6_flowinfo
= 0;
1374 msghdr
.msg_control
= ctlbuf
;
1375 msghdr
.msg_controllen
= sizeof(ctlbuf
);
1376 ctl
= CMSG_FIRSTHDR(&msghdr
);
1377 ctl
->cmsg_len
= CMSG_LEN(sizeof(struct in6_pktinfo
));
1378 ctl
->cmsg_level
= IPPROTO_IPV6
;
1379 ctl
->cmsg_type
= IPV6_PKTINFO
;
1380 struct in6_pktinfo
*pktinfo
= (struct in6_pktinfo
*) CMSG_DATA(ctl
);
1381 memcpy(&pktinfo
->ipi6_addr
, sadd6
, sizeof(struct in6_addr
));
1382 pktinfo
->ipi6_ifindex
= 0;
1385 msghdr
.msg_name
= (struct sockaddr
*)&ss_to
;
1386 msghdr
.msg_namelen
= ss_to
.ss_len
;
1387 iov
.iov_base
= packet
;
1388 iov
.iov_len
= packetlen
;
1389 msghdr
.msg_iov
= &iov
;
1390 msghdr
.msg_iovlen
= 1;
1391 msghdr
.msg_flags
= 0;
1394 len
= sendmsg(sock
, &msghdr
, 0);
1401 if (len
!= packetlen
)
1403 os_log(log_handle
, "SendKeepalive: sendmsg failed %s", strerror(errno
));
1407 char source
[INET6_ADDRSTRLEN
], dest
[INET6_ADDRSTRLEN
];
1409 inet_ntop(af
, (void *)sadd6
, source
, sizeof(source
));
1410 inet_ntop(af
, (void *)dadd6
, dest
, sizeof(dest
));
1412 os_log(log_handle
, "SendKeepalive: Success Source %s:%d, Dest %s:%d, %u, %u, %u",
1413 source
, ntohs(lport
), dest
, ntohs(rport
), ntohl(seq
), ntohl(ack
), ntohs(win
));
1421 void RetrieveTCPInfo(int family
, const v6addr_t laddr
, uint16_t lport
, const v6addr_t raddr
, uint16_t rport
, uint32_t *seq
, uint32_t *ack
, uint16_t *win
, int32_t *intfid
, int *err
)
1425 struct info_tuple itpl
;
1427 unsigned int miblen
;
1431 memset(&itpl
, 0, sizeof(struct info_tuple
));
1432 memset(&ti
, 0, sizeof(struct tcp_info
));
1434 char buf1
[INET6_ADDRSTRLEN
];
1435 char buf2
[INET6_ADDRSTRLEN
];
1440 inet_ntop(AF_INET6
, laddr
, buf1
, sizeof(buf1
));
1441 inet_ntop(AF_INET6
, raddr
, buf2
, sizeof(buf2
));
1443 os_log_info(log_handle
, "RetrieveTCPInfo invoked: laddr is %s, raddr is %s", buf1
, buf2
);
1445 os_log_info(log_handle
,"RetrieveTCPInfo invoked: lport is[%d] rport is[%d] family is [%d]",
1446 lport
, rport
, family
);
1448 if (family
== AF_INET
)
1450 memcpy(&itpl
.itpl_local_sin
.sin_addr
, laddr
, sizeof(struct in_addr
));
1451 memcpy(&itpl
.itpl_remote_sin
.sin_addr
, raddr
, sizeof(struct in_addr
));
1452 itpl
.itpl_local_sin
.sin_port
= lport
;
1453 itpl
.itpl_remote_sin
.sin_port
= rport
;
1454 itpl
.itpl_local_sin
.sin_family
= AF_INET
;
1455 itpl
.itpl_remote_sin
.sin_family
= AF_INET
;
1459 memcpy(&itpl
.itpl_local_sin6
.sin6_addr
, laddr
, sizeof(struct in6_addr
));
1460 memcpy(&itpl
.itpl_remote_sin6
.sin6_addr
, raddr
, sizeof(struct in6_addr
));
1461 itpl
.itpl_local_sin6
.sin6_port
= lport
;
1462 itpl
.itpl_remote_sin6
.sin6_port
= rport
;
1463 itpl
.itpl_local_sin6
.sin6_family
= AF_INET6
;
1464 itpl
.itpl_remote_sin6
.sin6_family
= AF_INET6
;
1466 itpl
.itpl_proto
= IPPROTO_TCP
;
1467 sz
= sizeof(mib
)/sizeof(mib
[0]);
1468 if (sysctlnametomib("net.inet.tcp.info", mib
, &sz
) == -1)
1470 const int sysctl_errno
= errno
;
1471 os_log(log_handle
, "RetrieveTCPInfo: sysctlnametomib failed %d, %s", sysctl_errno
, strerror(sysctl_errno
));
1472 *err
= sysctl_errno
;
1474 miblen
= (unsigned int)sz
;
1475 len
= sizeof(struct tcp_info
);
1476 if (sysctl(mib
, miblen
, &ti
, &len
, &itpl
, sizeof(struct info_tuple
)) == -1)
1478 const int sysctl_errno
= errno
;
1479 os_log(log_handle
, "RetrieveTCPInfo: sysctl failed %d, %s", sysctl_errno
, strerror(sysctl_errno
));
1480 *err
= sysctl_errno
;
1483 *seq
= ti
.tcpi_snd_nxt
- 1;
1484 *ack
= ti
.tcpi_rcv_nxt
;
1485 *win
= ti
.tcpi_rcv_space
>> ti
.tcpi_rcv_wscale
;
1486 *intfid
= ti
.tcpi_last_outif
;
1487 *err
= KERN_SUCCESS
;
1491 #ifndef MDNS_NO_IPSEC
1493 static const char configHeader
[] = "# BackToMyMac\n";
1494 static const char g_racoon_config_dir
[] = "/var/run/racoon/";
1495 static const char g_racoon_config_dir_old
[] = "/etc/racoon/remote/";
1497 static int MacOSXSystemBuildNumber(char* letter_out
, int* minor_out
)
1499 int major
= 0, minor
= 0;
1500 char letter
= 0, buildver
[256]="<Unknown>";
1501 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
1504 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
1505 if (cfbuildver
) CFStringGetCString(cfbuildver
, buildver
, sizeof(buildver
), kCFStringEncodingUTF8
);
1506 sscanf(buildver
, "%d%c%d", &major
, &letter
, &minor
);
1510 os_log_info(log_handle
, "_CFCopySystemVersionDictionary failed");
1512 if (!major
) { major
=16; letter
= 'A'; minor
= 300; os_log_info(log_handle
, "Note: No Major Build Version number found; assuming 16A300"); }
1513 if (letter_out
) *letter_out
= letter
;
1514 if (minor_out
) *minor_out
= minor
;
1518 static int UseOldRacoon()
1520 static int g_oldRacoon
= -1;
1522 if (g_oldRacoon
== -1)
1526 g_oldRacoon
= (MacOSXSystemBuildNumber(&letter
, &minor
) < 10);
1527 os_log_debug(log_handle
, "%s", g_oldRacoon
? "old" : "new");
1533 static int RacoonSignal()
1535 return UseOldRacoon() ? SIGHUP
: SIGUSR1
;
1538 static int notifyRacoon(void)
1540 os_log_debug(log_handle
,"entry");
1541 static const char racoon_pid_path
[] = "/var/run/racoon.pid";
1542 char buf
[] = "18446744073709551615"; /* largest 64-bit integer */
1545 unsigned long m
= 0;
1546 int fd
= open(racoon_pid_path
, O_RDONLY
);
1550 os_log_debug(log_handle
,"open \"%s\" failed, and that's OK: %s", racoon_pid_path
,
1552 return kHelperErr_RacoonNotificationFailed
;
1554 n
= read(fd
, buf
, sizeof(buf
)-1);
1558 os_log_debug(log_handle
,"read of \"%s\" failed: %s", racoon_pid_path
,
1559 n
== 0 ? "empty file" : strerror(errno
));
1560 return kHelperErr_RacoonNotificationFailed
;
1563 m
= strtoul(buf
, &p
, 10);
1564 if (*p
!= '\0' && !isspace(*p
))
1566 os_log_debug(log_handle
,"invalid PID \"%s\" (around '%c')", buf
, *p
);
1567 return kHelperErr_RacoonNotificationFailed
;
1571 os_log_debug(log_handle
,"refusing to kill PID %lu", m
);
1572 return kHelperErr_RacoonNotificationFailed
;
1574 if (0 != kill(m
, RacoonSignal()))
1576 os_log_debug(log_handle
,"Could not signal racoon (%lu): %s", m
, strerror(errno
));
1577 return kHelperErr_RacoonNotificationFailed
;
1580 os_log_debug(log_handle
, "Sent racoon (%lu) signal %d", m
, RacoonSignal());
1584 static const char* GetRacoonConfigDir()
1586 return UseOldRacoon() ? g_racoon_config_dir_old
: g_racoon_config_dir
;
1589 static const char* GetOldRacoonConfigDir()
1591 return UseOldRacoon() ? NULL : g_racoon_config_dir_old;
1595 static void closefds(int from
)
1598 struct dirent entry
, *entryp
= NULL
;
1599 DIR *dirp
= opendir("/dev/fd");
1603 /* fall back to the erroneous getdtablesize method */
1604 for (fd
= from
; fd
< getdtablesize(); ++fd
)
1608 while (0 == readdir_r(dirp
, &entry
, &entryp
) && NULL
!= entryp
)
1610 fd
= atoi(entryp
->d_name
);
1611 if (fd
>= from
&& fd
!= dirfd(dirp
))
1618 static int startRacoonOld(void)
1620 os_log_debug(log_handle
,"entry");
1621 char * const racoon_args
[] = { "/usr/sbin/racoon", "-e", NULL
};
1626 if (0 == (pid
= fork()))
1629 execve(racoon_args
[0], racoon_args
, NULL
);
1630 os_log_info(log_handle
, "execve of \"%s\" failed: %s",
1631 racoon_args
[0], strerror(errno
));
1634 os_log_info(log_handle
,"racoon (pid=%lu) started",
1635 (unsigned long)pid
);
1636 n
= waitpid(pid
, &status
, 0);
1639 os_log(log_handle
, "Unexpected waitpid failure: %s",
1641 return kHelperErr_RacoonStartFailed
;
1645 os_log(log_handle
, "Unexpected waitpid return value %d", (int)n
);
1646 return kHelperErr_RacoonStartFailed
;
1648 else if (WIFSIGNALED(status
))
1651 "racoon (pid=%lu) terminated due to signal %d",
1652 (unsigned long)pid
, WTERMSIG(status
));
1653 return kHelperErr_RacoonStartFailed
;
1655 else if (WIFSTOPPED(status
))
1658 "racoon (pid=%lu) has stopped due to signal %d",
1659 (unsigned long)pid
, WSTOPSIG(status
));
1660 return kHelperErr_RacoonStartFailed
;
1662 else if (0 != WEXITSTATUS(status
))
1665 "racoon (pid=%lu) exited with status %d",
1666 (unsigned long)pid
, WEXITSTATUS(status
));
1667 return kHelperErr_RacoonStartFailed
;
1669 os_log_debug(log_handle
, "racoon (pid=%lu) daemonized normally", (unsigned long)pid
);
1673 // constant and structure for the racoon control socket
1674 #define VPNCTL_CMD_PING 0x0004
1675 typedef struct vpnctl_hdr_struct
1685 static int startRacoon(void)
1687 os_log_debug(log_handle
,"entry");
1688 int fd
= socket(PF_UNIX
, SOCK_STREAM
, 0);
1691 os_log(log_handle
,"Could not create endpoint for racoon control socket: %d %s",
1692 errno
, strerror(errno
));
1693 return kHelperErr_RacoonStartFailed
;
1696 struct sockaddr_un saddr
;
1697 memset(&saddr
, 0, sizeof(saddr
));
1698 saddr
.sun_family
= AF_UNIX
;
1699 saddr
.sun_len
= sizeof(saddr
);
1700 static const char racoon_control_sock_path
[] = "/var/run/vpncontrol.sock";
1701 strcpy(saddr
.sun_path
, racoon_control_sock_path
);
1702 int result
= connect(fd
, (struct sockaddr
*) &saddr
, saddr
.sun_len
);
1705 os_log(log_handle
, "Could not connect racoon control socket %s: %d %s",
1706 racoon_control_sock_path
, errno
, strerror(errno
));
1707 return kHelperErr_RacoonStartFailed
;
1710 u_int32_t btmm_cookie
= 0x4d4d5442;
1711 vpnctl_hdr h
= { htons(VPNCTL_CMD_PING
), 0, btmm_cookie
, 0, 0, 0 };
1715 while (bytes
< sizeof(vpnctl_hdr
))
1717 ret
= write(fd
, ((unsigned char*)&h
)+bytes
, sizeof(vpnctl_hdr
) - bytes
);
1720 os_log(log_handle
, "Could not write to racoon control socket: %d %s", errno
, strerror(errno
));
1721 return kHelperErr_RacoonStartFailed
;
1733 for (counter
= 0; counter
< 100; counter
++)
1737 tv
= (struct timeval
){ 0, 10000 }; // 10 milliseconds * 100 iterations = 1 second max wait time
1739 result
= select(nfds
, &fds
, (fd_set
*)NULL
, (fd_set
*)NULL
, &tv
);
1742 if (FD_ISSET(fd
, &fds
))
1744 ret
= read(fd
, ((unsigned char*)&h
)+bytes
, sizeof(vpnctl_hdr
) - bytes
);
1748 os_log(log_handle
,"Could not read from racoon control socket: %d %s", errno
, strerror(errno
));
1752 if (bytes
>= sizeof(vpnctl_hdr
)) break;
1756 os_log_debug(log_handle
, "select returned but fd_isset not on expected fd");
1759 else if (result
< 0)
1761 const int select_errno
= errno
;
1762 os_log_debug(log_handle
, "select returned %d errno %d %s", result
, select_errno
, strerror(select_errno
));
1763 if (select_errno
!= EINTR
) break;
1769 if (bytes
< sizeof(vpnctl_hdr
) || h
.cookie
!= btmm_cookie
)
1770 return kHelperErr_RacoonStartFailed
;
1772 os_log_debug(log_handle
, "racoon started");
1776 static int kickRacoon(void)
1778 if ( 0 == notifyRacoon() )
1780 return UseOldRacoon() ? startRacoonOld() : startRacoon();
1783 typedef enum _mDNSTunnelPolicyWhich
1785 kmDNSTunnelPolicySetup
,
1786 kmDNSTunnelPolicyTeardown
,
1787 kmDNSTunnelPolicyGenerate
1788 } mDNSTunnelPolicyWhich
;
1790 // For kmDNSTunnelPolicySetup, you can setup IPv6-in-IPv6 tunnel or IPv6-in-IPv4 tunnel
1791 // kmDNSNoTunnel is used for other Policy types
1792 typedef enum _mDNSTunnelType
1795 kmDNSIPv6IPv4Tunnel
,
1799 static const uint8_t kWholeV6Mask
= 128;
1801 static unsigned int routeSeq
= 1;
1803 static int setupTunnelRoute(const v6addr_t local
, const v6addr_t remote
)
1807 struct rt_msghdr hdr
;
1808 struct sockaddr_in6 dst
;
1809 struct sockaddr_in6 gtwy
;
1814 if (0 > (s
= socket(PF_ROUTE
, SOCK_RAW
, AF_INET
)))
1816 os_log(log_handle
,"socket(PF_ROUTE, ...) failed: %s", strerror(errno
));
1818 err
= kHelperErr_RoutingSocketCreationFailed
;
1822 memset(&msg
, 0, sizeof(msg
));
1823 msg
.hdr
.rtm_msglen
= sizeof(msg
);
1824 msg
.hdr
.rtm_type
= RTM_ADD
;
1825 /* The following flags are set by `route add -inet6 -host ...` */
1826 msg
.hdr
.rtm_flags
= RTF_UP
| RTF_GATEWAY
| RTF_HOST
| RTF_STATIC
;
1827 msg
.hdr
.rtm_version
= RTM_VERSION
;
1828 msg
.hdr
.rtm_seq
= routeSeq
++;
1829 msg
.hdr
.rtm_addrs
= RTA_DST
| RTA_GATEWAY
;
1830 msg
.hdr
.rtm_inits
= RTV_MTU
;
1831 msg
.hdr
.rtm_rmx
.rmx_mtu
= 1280;
1833 msg
.dst
.sin6_len
= sizeof(msg
.dst
);
1834 msg
.dst
.sin6_family
= AF_INET6
;
1835 memcpy(&msg
.dst
.sin6_addr
, remote
, sizeof(msg
.dst
.sin6_addr
));
1837 msg
.gtwy
.sin6_len
= sizeof(msg
.gtwy
);
1838 msg
.gtwy
.sin6_family
= AF_INET6
;
1839 memcpy(&msg
.gtwy
.sin6_addr
, local
, sizeof(msg
.gtwy
.sin6_addr
));
1841 /* send message, ignore error when route already exists */
1842 if (0 > write(s
, &msg
, msg
.hdr
.rtm_msglen
))
1844 const int errno_
= errno
;
1846 os_log_info(log_handle
,"write to routing socket failed: %s", strerror(errno_
));
1847 if (EEXIST
!= errno_
)
1849 err
= kHelperErr_RouteAdditionFailed
;
1860 static int teardownTunnelRoute(const v6addr_t remote
)
1864 struct rt_msghdr hdr
;
1865 struct sockaddr_in6 dst
;
1870 if (0 > (s
= socket(PF_ROUTE
, SOCK_RAW
, AF_INET
)))
1872 os_log(log_handle
, "socket(PF_ROUTE, ...) failed: %s", strerror(errno
));
1873 err
= kHelperErr_RoutingSocketCreationFailed
;
1876 memset(&msg
, 0, sizeof(msg
));
1878 msg
.hdr
.rtm_msglen
= sizeof(msg
);
1879 msg
.hdr
.rtm_type
= RTM_DELETE
;
1880 msg
.hdr
.rtm_version
= RTM_VERSION
;
1881 msg
.hdr
.rtm_seq
= routeSeq
++;
1882 msg
.hdr
.rtm_addrs
= RTA_DST
;
1884 msg
.dst
.sin6_len
= sizeof(msg
.dst
);
1885 msg
.dst
.sin6_family
= AF_INET6
;
1886 memcpy(&msg
.dst
.sin6_addr
, remote
, sizeof(msg
.dst
.sin6_addr
));
1887 if (0 > write(s
, &msg
, msg
.hdr
.rtm_msglen
))
1889 const int errno_
= errno
;
1891 os_log_debug(log_handle
,"write to routing socket failed: %s", strerror(errno_
));
1893 if (ESRCH
!= errno_
)
1895 err
= kHelperErr_RouteDeletionFailed
;
1906 static int v4addr_to_string(v4addr_t addr
, char *buf
, size_t buflen
)
1908 if (NULL
== inet_ntop(AF_INET
, addr
, buf
, buflen
))
1910 os_log(log_handle
, "v4addr_to_string() inet_ntop failed: %s", strerror(errno
));
1911 return kHelperErr_InvalidNetworkAddress
;
1919 static int v6addr_to_string(const v6addr_t addr
, char *buf
, size_t buflen
)
1921 if (NULL
== inet_ntop(AF_INET6
, addr
, buf
, buflen
))
1923 os_log(log_handle
, "v6addr_to_string inet_ntop failed: %s", strerror(errno
));
1924 return kHelperErr_InvalidNetworkAddress
;
1932 static int ensureExistenceOfRacoonConfigDir(const char* const racoon_config_dir
)
1935 int ret
= stat(racoon_config_dir
, &s
);
1938 if (errno
!= ENOENT
)
1940 os_log(log_handle
, "stat of \"%s\" failed (%d): %s",
1941 racoon_config_dir
, ret
, strerror(errno
));
1946 ret
= mkdir(racoon_config_dir
, S_IRWXU
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
);
1949 os_log(log_handle
, "mkdir \"%s\" failed: %s",
1950 racoon_config_dir
, strerror(errno
));
1955 os_log_info(log_handle
, "created directory \"%s\"", racoon_config_dir
);
1959 else if (!(s
.st_mode
& S_IFDIR
))
1961 os_log(log_handle
, "\"%s\" is not a directory!",
1971 /* Caller owns object returned in `policy' */
1972 static int generateTunnelPolicy(mDNSTunnelPolicyWhich which
, mDNSTunnelType type
, int in
,
1973 v4addr_t src
, uint16_t src_port
,
1974 v4addr_t dst
, uint16_t dst_port
,
1975 const v6addr_t src6
, const v6addr_t dst6
,
1976 ipsec_policy_t
*policy
, size_t *len
)
1978 char srcs
[INET_ADDRSTRLEN
], dsts
[INET_ADDRSTRLEN
];
1979 char srcs6
[INET6_ADDRSTRLEN
], dsts6
[INET6_ADDRSTRLEN
];
1981 char *inOut
= in
? "in" : "out";
1990 case kmDNSTunnelPolicySetup
:
1991 if (type
== kmDNSIPv6IPv4Tunnel
)
1993 if (0 != (err
= v4addr_to_string(src
, srcs
, sizeof(srcs
))))
1995 if (0 != (err
= v4addr_to_string(dst
, dsts
, sizeof(dsts
))))
1997 n
= snprintf(buf
, sizeof(buf
),
1998 "%s ipsec esp/tunnel/%s[%u]-%s[%u]/require",
1999 inOut
, srcs
, src_port
, dsts
, dst_port
);
2001 else if (type
== kmDNSIPv6IPv6Tunnel
)
2003 if (0 != (err
= v6addr_to_string(src6
, srcs6
, sizeof(srcs6
))))
2005 if (0 != (err
= v6addr_to_string(dst6
, dsts6
, sizeof(dsts6
))))
2007 n
= snprintf(buf
, sizeof(buf
),
2008 "%s ipsec esp/tunnel/%s-%s/require",
2009 inOut
, srcs6
, dsts6
);
2012 case kmDNSTunnelPolicyTeardown
:
2013 n
= strlcpy(buf
, inOut
, sizeof(buf
));
2015 case kmDNSTunnelPolicyGenerate
:
2016 n
= snprintf(buf
, sizeof(buf
), "%s generate", inOut
);
2019 err
= kHelperErr_IPsecPolicyCreationFailed
;
2023 if (n
>= (int)sizeof(buf
))
2025 err
= kHelperErr_ResultTooLarge
;
2029 os_log_info(log_handle
, "policy=\"%s\"", buf
);
2031 if (NULL
== (*policy
= (ipsec_policy_t
)ipsec_set_policy(buf
, n
)))
2033 os_log_info(log_handle
, "Could not create IPsec policy from \"%s\"", buf
);
2034 err
= kHelperErr_IPsecPolicyCreationFailed
;
2037 *len
= ((ipsec_policy_t
)(*policy
))->sadb_x_policy_len
* 8;
2043 static int sendPolicy(int s
, int setup
,
2044 struct sockaddr
*src
, uint8_t src_bits
,
2045 struct sockaddr
*dst
, uint8_t dst_bits
,
2046 ipsec_policy_t policy
, size_t len
)
2048 static unsigned int policySeq
= 0;
2051 os_log_debug(log_handle
, "entry, setup=%d", setup
);
2054 err
= pfkey_send_spdadd(s
, src
, src_bits
, dst
, dst_bits
, -1,
2055 (char *)policy
, len
, policySeq
++);
2057 err
= pfkey_send_spddelete(s
, src
, src_bits
, dst
, dst_bits
, -1,
2058 (char *)policy
, len
, policySeq
++);
2062 os_log(log_handle
, "Could not set IPsec policy: %s", ipsec_strerror());
2063 err
= kHelperErr_IPsecPolicySetFailed
;
2071 os_log_debug(log_handle
, "succeeded");
2077 static int removeSA(int s
, struct sockaddr
*src
, struct sockaddr
*dst
)
2081 os_log_debug(log_handle
, "entry");
2083 err
= pfkey_send_delete_all(s
, SADB_SATYPE_ESP
, IPSEC_MODE_ANY
, src
, dst
);
2086 os_log(log_handle
, "Could not remove IPsec SA: %s", ipsec_strerror());
2087 err
= kHelperErr_IPsecRemoveSAFailed
;
2090 err
= pfkey_send_delete_all(s
, SADB_SATYPE_ESP
, IPSEC_MODE_ANY
, dst
, src
);
2093 os_log(log_handle
, "Could not remove IPsec SA: %s", ipsec_strerror());
2094 err
= kHelperErr_IPsecRemoveSAFailed
;
2100 os_log_debug(log_handle
, "succeeded");
2106 static int doTunnelPolicy(mDNSTunnelPolicyWhich which
, mDNSTunnelType type
,
2107 const v6addr_t loc_inner
, uint8_t loc_bits
,
2108 v4addr_t loc_outer
, uint16_t loc_port
,
2109 const v6addr_t rmt_inner
, uint8_t rmt_bits
,
2110 v4addr_t rmt_outer
, uint16_t rmt_port
,
2111 const v6addr_t loc_outer6
, const v6addr_t rmt_outer6
)
2113 struct sockaddr_in6 sin6_loc
;
2114 struct sockaddr_in6 sin6_rmt
;
2115 ipsec_policy_t policy
= NULL
;
2120 os_log_debug(log_handle
,"entry");
2121 if (0 > (s
= pfkey_open()))
2123 os_log(log_handle
, "Could not create IPsec policy socket: %s", ipsec_strerror());
2124 err
= kHelperErr_IPsecPolicySocketCreationFailed
;
2128 memset(&sin6_loc
, 0, sizeof(sin6_loc
));
2129 sin6_loc
.sin6_len
= sizeof(sin6_loc
);
2130 sin6_loc
.sin6_family
= AF_INET6
;
2131 sin6_loc
.sin6_port
= htons(0);
2132 memcpy(&sin6_loc
.sin6_addr
, loc_inner
, sizeof(sin6_loc
.sin6_addr
));
2134 memset(&sin6_rmt
, 0, sizeof(sin6_rmt
));
2135 sin6_rmt
.sin6_len
= sizeof(sin6_rmt
);
2136 sin6_rmt
.sin6_family
= AF_INET6
;
2137 sin6_rmt
.sin6_port
= htons(0);
2138 memcpy(&sin6_rmt
.sin6_addr
, rmt_inner
, sizeof(sin6_rmt
.sin6_addr
));
2140 int setup
= which
!= kmDNSTunnelPolicyTeardown
;
2142 if (0 != (err
= generateTunnelPolicy(which
, type
, 1,
2143 rmt_outer
, rmt_port
,
2144 loc_outer
, loc_port
,
2145 rmt_outer6
, loc_outer6
,
2149 if (0 != (err
= sendPolicy(s
, setup
,
2150 (struct sockaddr
*)&sin6_rmt
, rmt_bits
,
2151 (struct sockaddr
*)&sin6_loc
, loc_bits
,
2161 if (0 != (err
= generateTunnelPolicy(which
, type
, 0,
2162 loc_outer
, loc_port
,
2163 rmt_outer
, rmt_port
,
2164 loc_outer6
, rmt_outer6
,
2167 if (0 != (err
= sendPolicy(s
, setup
,
2168 (struct sockaddr
*)&sin6_loc
, loc_bits
,
2169 (struct sockaddr
*)&sin6_rmt
, rmt_bits
,
2173 if (which
== kmDNSTunnelPolicyTeardown
)
2175 if (rmt_port
) // Outer tunnel is IPv4
2177 if (loc_outer
&& rmt_outer
)
2179 struct sockaddr_in sin_loc
;
2180 struct sockaddr_in sin_rmt
;
2181 memset(&sin_loc
, 0, sizeof(sin_loc
));
2182 sin_loc
.sin_len
= sizeof(sin_loc
);
2183 sin_loc
.sin_family
= AF_INET
;
2184 memcpy(&sin_loc
.sin_addr
, loc_outer
, sizeof(sin_loc
.sin_addr
));
2186 memset(&sin_rmt
, 0, sizeof(sin_rmt
));
2187 sin_rmt
.sin_len
= sizeof(sin_rmt
);
2188 sin_rmt
.sin_family
= AF_INET
;
2189 memcpy(&sin_rmt
.sin_addr
, rmt_outer
, sizeof(sin_rmt
.sin_addr
));
2190 if (0 != (err
= removeSA(s
, (struct sockaddr
*)&sin_loc
, (struct sockaddr
*)&sin_rmt
)))
2196 if (loc_outer6
&& rmt_outer6
)
2198 struct sockaddr_in6 sin6_lo
;
2199 struct sockaddr_in6 sin6_rm
;
2201 memset(&sin6_lo
, 0, sizeof(sin6_lo
));
2202 sin6_lo
.sin6_len
= sizeof(sin6_lo
);
2203 sin6_lo
.sin6_family
= AF_INET6
;
2204 memcpy(&sin6_lo
.sin6_addr
, loc_outer6
, sizeof(sin6_lo
.sin6_addr
));
2206 memset(&sin6_rm
, 0, sizeof(sin6_rm
));
2207 sin6_rm
.sin6_len
= sizeof(sin6_rm
);
2208 sin6_rm
.sin6_family
= AF_INET6
;
2209 memcpy(&sin6_rm
.sin6_addr
, rmt_outer6
, sizeof(sin6_rm
.sin6_addr
));
2210 if (0 != (err
= removeSA(s
, (struct sockaddr
*)&sin6_lo
, (struct sockaddr
*)&sin6_rm
)))
2216 os_log_debug(log_handle
,"succeeded");
2226 #endif /* ndef MDNS_NO_IPSEC */
2228 int HelperAutoTunnelSetKeys(int replacedelete
, const v6addr_t loc_inner
, const v6addr_t loc_outer6
, uint16_t loc_port
, const v6addr_t rmt_inner
,
2229 const v6addr_t rmt_outer6
, uint16_t rmt_port
, const char *id
, int *err
)
2231 #ifndef MDNS_NO_IPSEC
2232 static const char config
[] =
2234 "remote %s [%u] {\n"
2235 " disconnect_on_idle idle_timeout 600 idle_direction idle_outbound;\n"
2236 " exchange_mode aggressive;\n"
2238 " situation identity_only;\n"
2239 " verify_identifier off;\n"
2240 " generate_policy on;\n"
2241 " my_identifier user_fqdn \"%s\";\n"
2242 " shared_secret keychain \"%s\";\n"
2244 " lifetime time 15 min;\n"
2245 " initial_contact on;\n"
2246 " support_proxy on;\n"
2247 " nat_traversal force;\n"
2248 " proposal_check claim;\n"
2250 " encryption_algorithm aes;\n"
2251 " hash_algorithm sha256;\n"
2252 " authentication_method pre_shared_key;\n"
2254 " lifetime time 15 min;\n"
2257 " encryption_algorithm aes;\n"
2258 " hash_algorithm sha1;\n"
2259 " authentication_method pre_shared_key;\n"
2261 " lifetime time 15 min;\n"
2264 "sainfo address %s any address %s any {\n"
2266 " lifetime time 10 min;\n"
2267 " encryption_algorithm aes;\n"
2268 " authentication_algorithm hmac_sha256,hmac_sha1;\n"
2269 " compression_algorithm deflate;\n"
2271 "sainfo address %s any address %s any {\n"
2273 " lifetime time 10 min;\n"
2274 " encryption_algorithm aes;\n"
2275 " authentication_algorithm hmac_sha256,hmac_sha1;\n"
2276 " compression_algorithm deflate;\n"
2278 char path
[PATH_MAX
] = "";
2279 char li
[INET6_ADDRSTRLEN
], lo
[INET_ADDRSTRLEN
], lo6
[INET6_ADDRSTRLEN
],
2280 ri
[INET6_ADDRSTRLEN
], ro
[INET_ADDRSTRLEN
], ro6
[INET6_ADDRSTRLEN
];
2283 char tmp_path
[PATH_MAX
] = "";
2284 v4addr_t loc_outer
, rmt_outer
;
2286 os_log_debug(log_handle
,"HelperAutoTunnelSetKeys: entry");
2287 *err
= kHelperErr_NoErr
;
2289 char buf1
[INET6_ADDRSTRLEN
];
2290 char buf2
[INET6_ADDRSTRLEN
];
2291 char buf3
[INET6_ADDRSTRLEN
];
2292 char buf4
[INET6_ADDRSTRLEN
];
2299 inet_ntop(AF_INET6
, loc_inner
, buf1
, sizeof(buf1
));
2300 inet_ntop(AF_INET6
, loc_outer6
, buf2
, sizeof(buf2
));
2301 inet_ntop(AF_INET6
, rmt_inner
, buf3
, sizeof(buf3
));
2302 inet_ntop(AF_INET6
, rmt_outer6
, buf4
, sizeof(buf4
));
2304 os_log_info(log_handle
, "HelperAutoTunnelSetKeys: Parameters are local_inner is %s, local_outer is %s, remote_inner is %s, remote_outer is %s id is %s",
2305 buf1
, buf2
, buf3
, buf4
, id
);
2307 switch ((enum mDNSAutoTunnelSetKeysReplaceDelete
)replacedelete
)
2309 case kmDNSAutoTunnelSetKeysReplace
:
2310 case kmDNSAutoTunnelSetKeysDelete
:
2313 *err
= kHelperErr_InvalidTunnelSetKeysOperation
;
2317 if (0 != (*err
= v6addr_to_string(loc_inner
, li
, sizeof(li
))))
2319 if (0 != (*err
= v6addr_to_string(rmt_inner
, ri
, sizeof(ri
))))
2322 os_log_debug(log_handle
, "loc_inner=%s rmt_inner=%s", li
, ri
);
2326 loc_outer
[0] = loc_outer
[1] = loc_outer
[2] = loc_outer
[3] = 0;
2327 rmt_outer
[0] = rmt_outer
[1] = rmt_outer
[2] = rmt_outer
[3] = 0;
2329 if (0 != (*err
= v6addr_to_string(loc_outer6
, lo6
, sizeof(lo6
))))
2331 if (0 != (*err
= v6addr_to_string(rmt_outer6
, ro6
, sizeof(ro6
))))
2334 os_log_debug(log_handle
, "IPv6 outer tunnel: loc_outer6=%s rmt_outer6=%s", lo6
, ro6
);
2336 if ((int)sizeof(path
) <= snprintf(path
, sizeof(path
), "%s%s.conf", GetRacoonConfigDir(), ro6
))
2338 *err
= kHelperErr_ResultTooLarge
;
2344 loc_outer
[0] = loc_outer6
[0];
2345 loc_outer
[1] = loc_outer6
[1];
2346 loc_outer
[2] = loc_outer6
[2];
2347 loc_outer
[3] = loc_outer6
[3];
2349 rmt_outer
[0] = rmt_outer6
[0];
2350 rmt_outer
[1] = rmt_outer6
[1];
2351 rmt_outer
[2] = rmt_outer6
[2];
2352 rmt_outer
[3] = rmt_outer6
[3];
2354 if (0 != (*err
= v4addr_to_string(loc_outer
, lo
, sizeof(lo
))))
2356 if (0 != (*err
= v4addr_to_string(rmt_outer
, ro
, sizeof(ro
))))
2359 os_log_debug(log_handle
, "IPv4 outer tunnel: loc_outer=%s loc_port=%u rmt_outer=%s rmt_port=%u",
2360 lo
, loc_port
, ro
, rmt_port
);
2362 if ((int)sizeof(path
) <= snprintf(path
, sizeof(path
), "%s%s.%u.conf", GetRacoonConfigDir(), ro
, rmt_port
))
2364 *err
= kHelperErr_ResultTooLarge
;
2369 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
)
2371 if (0 > ensureExistenceOfRacoonConfigDir(GetRacoonConfigDir()))
2373 *err
= kHelperErr_RacoonConfigCreationFailed
;
2376 if ((int)sizeof(tmp_path
) <=
2377 snprintf(tmp_path
, sizeof(tmp_path
), "%s.XXXXXX", path
))
2379 *err
= kHelperErr_ResultTooLarge
;
2382 if (0 > (fd
= mkstemp(tmp_path
)))
2384 os_log(log_handle
, "mkstemp \"%s\" failed: %s", tmp_path
, strerror(errno
));
2385 *err
= kHelperErr_RacoonConfigCreationFailed
;
2388 if (NULL
== (fp
= fdopen(fd
, "w")))
2390 os_log(log_handle
, "fdopen: %s", strerror(errno
));
2391 *err
= kHelperErr_RacoonConfigCreationFailed
;
2396 fprintf(fp
, config
, configHeader
, (!rmt_port
? ro6
: ro
), rmt_port
, id
, id
, ri
, li
, li
, ri
);
2400 if (0 > rename(tmp_path
, path
))
2402 os_log(log_handle
, "rename \"%s\" \"%s\" failed: %s", tmp_path
, path
, strerror(errno
));
2403 *err
= kHelperErr_RacoonConfigCreationFailed
;
2409 if (0 != unlink(path
))
2410 os_log_debug(log_handle
, "unlink \"%s\" failed: %s", path
, strerror(errno
));
2413 if (0 != (*err
= doTunnelPolicy(kmDNSTunnelPolicyTeardown
, kmDNSNoTunnel
,
2414 loc_inner
, kWholeV6Mask
, loc_outer
, loc_port
,
2415 rmt_inner
, kWholeV6Mask
, rmt_outer
, rmt_port
, loc_outer6
, rmt_outer6
)))
2417 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
&&
2418 0 != (*err
= doTunnelPolicy(kmDNSTunnelPolicySetup
, (!rmt_port
? kmDNSIPv6IPv6Tunnel
: kmDNSIPv6IPv4Tunnel
),
2419 loc_inner
, kWholeV6Mask
, loc_outer
, loc_port
,
2420 rmt_inner
, kWholeV6Mask
, rmt_outer
, rmt_port
, loc_outer6
, rmt_outer6
)))
2423 if (0 != (*err
= teardownTunnelRoute(rmt_inner
)))
2426 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
&&
2427 0 != (*err
= setupTunnelRoute(loc_inner
, rmt_inner
)))
2430 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
&&
2431 0 != (*err
= kickRacoon()))
2434 os_log_debug(log_handle
, "succeeded");
2443 (void)replacedelete
; (void)loc_inner
; (void)loc_outer6
; (void)loc_port
; (void)rmt_inner
;
2444 (void)rmt_outer6
; (void)rmt_port
; (void)id
;
2446 *err
= kHelperErr_IPsecDisabled
;
2447 #endif /* MDNS_NO_IPSEC */
2448 update_idle_timer();
2449 return KERN_SUCCESS
;