1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2007-2015 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();
713 formatNotDNSKey
, formatDdnsTypeItem
, formatDnsPrefixedServiceItem
, formatBtmmPrefixedServiceItem
716 // On Mac OS X on Intel, the four-character string seems to be stored backwards, at least sometimes.
717 // I suspect some overenthusiastic inexperienced engineer said, "On Intel everything's backwards,
718 // therefore I need to add some byte swapping in this API to make this four-character string backwards too."
719 // To cope with this we allow *both* "ddns" and "sndd" as valid item types.
722 #ifndef NO_SECURITYFRAMEWORK
723 static const char btmmprefix
[] = "btmmdns:";
724 static const char dnsprefix
[] = "dns:";
725 static const char ddns
[] = "ddns";
726 static const char ddnsrev
[] = "sndd";
728 static enum DNSKeyFormat
getDNSKeyFormat(SecKeychainItemRef item
, SecKeychainAttributeList
**attributesp
)
730 static UInt32 tags
[4] =
732 kSecTypeItemAttr
, kSecServiceItemAttr
, kSecAccountItemAttr
, kSecLabelItemAttr
734 static SecKeychainAttributeInfo attributeInfo
=
736 sizeof(tags
)/sizeof(tags
[0]), tags
, NULL
738 SecKeychainAttributeList
*attributes
= NULL
;
739 enum DNSKeyFormat format
;
740 Boolean malformed
= FALSE
;
741 OSStatus status
= noErr
;
745 if (noErr
!= (status
= SecKeychainItemCopyAttributesAndData(item
, &attributeInfo
, NULL
, &attributes
, NULL
, NULL
)))
747 os_log_info(log_handle
,"getDNSKeyFormat: SecKeychainItemCopyAttributesAndData %d - skipping", status
);
750 if (attributeInfo
.count
!= attributes
->count
)
752 for (i
= 0; !malformed
&& i
< (int)attributeInfo
.count
; ++i
)
753 if (attributeInfo
.tag
[i
] != attributes
->attr
[i
].tag
)
757 os_log(log_handle
, "getDNSKeyFormat: malformed result from SecKeychainItemCopyAttributesAndData - skipping");
761 os_log_info(log_handle
,"getDNSKeyFormat: entry (\"%.*s\", \"%.*s\", \"%.*s\")",
762 (int)attributes
->attr
[0].length
, attributes
->attr
[0].data
,
763 (int)attributes
->attr
[1].length
, attributes
->attr
[1].data
,
764 (int)attributes
->attr
[2].length
, attributes
->attr
[2].data
);
766 if (attributes
->attr
[1].length
>= MAX_ESCAPED_DOMAIN_NAME
+
769 os_log(log_handle
, "getDNSKeyFormat: kSecServiceItemAttr too long (%u) - skipping",
770 (unsigned int)attributes
->attr
[1].length
);
773 if (attributes
->attr
[2].length
>= MAX_ESCAPED_DOMAIN_NAME
)
775 os_log(log_handle
, "getDNSKeyFormat: kSecAccountItemAttr too long (%u) - skipping",
776 (unsigned int)attributes
->attr
[2].length
);
779 if (attributes
->attr
[1].length
>= sizeof(dnsprefix
)-1 && 0 == strncasecmp(attributes
->attr
[1].data
, dnsprefix
, sizeof(dnsprefix
)-1))
780 format
= formatDnsPrefixedServiceItem
;
781 else if (attributes
->attr
[1].length
>= sizeof(btmmprefix
)-1 && 0 == strncasecmp(attributes
->attr
[1].data
, btmmprefix
, sizeof(btmmprefix
)-1))
782 format
= formatBtmmPrefixedServiceItem
;
783 else if (attributes
->attr
[0].length
== sizeof(ddns
)-1 && 0 == strncasecmp(attributes
->attr
[0].data
, ddns
, sizeof(ddns
)-1))
784 format
= formatDdnsTypeItem
;
785 else if (attributes
->attr
[0].length
== sizeof(ddnsrev
)-1 && 0 == strncasecmp(attributes
->attr
[0].data
, ddnsrev
, sizeof(ddnsrev
)-1))
786 format
= formatDdnsTypeItem
;
789 os_log_info(log_handle
,"getDNSKeyFormat: uninterested in this entry");
793 *attributesp
= attributes
;
794 os_log_info(log_handle
,"getDNSKeyFormat: accepting this entry");
798 SecKeychainItemFreeAttributesAndData(attributes
, NULL
);
799 return formatNotDNSKey
;
802 // Insert the attributes as defined by mDNSKeyChainAttributes
803 static CFPropertyListRef
copyKeychainItemInfo(SecKeychainItemRef item
, SecKeychainAttributeList
*attributes
, enum DNSKeyFormat format
)
805 CFMutableArrayRef entry
= NULL
;
806 CFDataRef data
= NULL
;
807 OSStatus status
= noErr
;
811 if (NULL
== (entry
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
)))
813 os_log(log_handle
, "copyKeychainItemInfo: CFArrayCreateMutable failed");
817 // Insert the Account attribute (kmDNSKcWhere)
818 switch ((enum DNSKeyFormat
)format
)
820 case formatDdnsTypeItem
:
821 data
= CFDataCreate(kCFAllocatorDefault
, attributes
->attr
[1].data
, attributes
->attr
[1].length
);
823 case formatDnsPrefixedServiceItem
:
824 case formatBtmmPrefixedServiceItem
:
825 data
= CFDataCreate(kCFAllocatorDefault
, attributes
->attr
[1].data
, attributes
->attr
[1].length
);
828 os_log(log_handle
, "copyKeychainItemInfo: unknown DNSKeyFormat value");
833 os_log(log_handle
, "copyKeychainItemInfo: CFDataCreate for attr[1] failed");
836 CFArrayAppendValue(entry
, data
);
839 // Insert the Where attribute (kmDNSKcAccount)
840 if (NULL
== (data
= CFDataCreate(kCFAllocatorDefault
, attributes
->attr
[2].data
, attributes
->attr
[2].length
)))
842 os_log(log_handle
, "copyKeychainItemInfo: CFDataCreate for attr[2] failed");
846 CFArrayAppendValue(entry
, data
);
849 // Insert the Key attribute (kmDNSKcKey)
850 if (noErr
!= (status
= SecKeychainItemCopyAttributesAndData(item
, NULL
, NULL
, NULL
, &keylen
, &keyp
)))
852 os_log(log_handle
, "copyKeychainItemInfo: could not retrieve key for \"%.*s\": %d",
853 (int)attributes
->attr
[1].length
, attributes
->attr
[1].data
, status
);
857 data
= CFDataCreate(kCFAllocatorDefault
, keyp
, keylen
);
858 SecKeychainItemFreeAttributesAndData(NULL
, keyp
);
861 os_log(log_handle
, "copyKeychainItemInfo: CFDataCreate for keyp failed");
864 CFArrayAppendValue(entry
, data
);
867 // Insert the Name attribute (kmDNSKcName)
868 if (NULL
== (data
= CFDataCreate(kCFAllocatorDefault
, attributes
->attr
[3].data
, attributes
->attr
[3].length
)))
870 os_log(log_handle
, "copyKeychainItemInfo: CFDataCreate for attr[3] failed");
874 CFArrayAppendValue(entry
, data
);
885 void KeychainGetSecrets(__unused
unsigned int *numsecrets
,__unused
unsigned long *secrets
, __unused
unsigned int *secretsCnt
, __unused
int *err
)
887 #ifndef NO_SECURITYFRAMEWORK
888 CFWriteStreamRef stream
= NULL
;
889 CFDataRef result
= NULL
;
890 CFPropertyListRef entry
= NULL
;
891 CFMutableArrayRef keys
= NULL
;
892 SecKeychainRef skc
= NULL
;
893 SecKeychainItemRef item
= NULL
;
894 SecKeychainSearchRef search
= NULL
;
895 SecKeychainAttributeList
*attributes
= NULL
;
896 enum DNSKeyFormat format
;
899 os_log_info(log_handle
,"KeychainGetSecrets: entry");
900 *err
= kHelperErr_NoErr
;
902 *secrets
= (vm_offset_t
)NULL
;
904 if (NULL
== (keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
)))
906 os_log(log_handle
, "KeychainGetSecrets: CFArrayCreateMutable failed");
907 *err
= kHelperErr_ApiErr
;
910 if (noErr
!= (status
= SecKeychainCopyDefault(&skc
)))
912 *err
= kHelperErr_ApiErr
;
915 #pragma clang diagnostic push
916 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
917 if (noErr
!= (status
= SecKeychainSearchCreateFromAttributes(skc
, kSecGenericPasswordItemClass
, NULL
, &search
)))
919 *err
= kHelperErr_ApiErr
;
922 for (status
= SecKeychainSearchCopyNext(search
, &item
); noErr
== status
; status
= SecKeychainSearchCopyNext(search
, &item
))
924 if (formatNotDNSKey
!= (format
= getDNSKeyFormat(item
, &attributes
)) &&
925 NULL
!= (entry
= copyKeychainItemInfo(item
, attributes
, format
)))
927 CFArrayAppendValue(keys
, entry
);
930 SecKeychainItemFreeAttributesAndData(attributes
, NULL
);
933 #pragma clang diagnostic pop
934 if (errSecItemNotFound
!= status
)
935 os_log(log_handle
, "KeychainGetSecrets: SecKeychainSearchCopyNext failed: %d", status
);
937 if (NULL
== (stream
= CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorDefault
, kCFAllocatorDefault
)))
939 *err
= kHelperErr_ApiErr
;
940 os_log(log_handle
, "KeychainGetSecrets:CFWriteStreamCreateWithAllocatedBuffers failed");
944 CFWriteStreamOpen(stream
);
945 if (0 == CFPropertyListWrite(keys
, stream
, kCFPropertyListBinaryFormat_v1_0
, 0, NULL
))
947 *err
= kHelperErr_ApiErr
;
948 os_log(log_handle
, "KeychainGetSecrets:CFPropertyListWriteToStream failed");
951 result
= CFWriteStreamCopyProperty(stream
, kCFStreamPropertyDataWritten
);
953 if (KERN_SUCCESS
!= vm_allocate(mach_task_self(), secrets
, CFDataGetLength(result
), VM_FLAGS_ANYWHERE
))
955 *err
= kHelperErr_ApiErr
;
956 os_log(log_handle
, "KeychainGetSecrets: vm_allocate failed");
960 CFDataGetBytes(result
, CFRangeMake(0, CFDataGetLength(result
)), (void *)*secrets
);
961 *secretsCnt
= CFDataGetLength(result
);
962 *numsecrets
= CFArrayGetCount(keys
);
964 os_log_info(log_handle
,"KeychainGetSecrets: succeeded");
967 os_log_info(log_handle
,"KeychainGetSecrets: returning numsecrets[%u] secrets[%lu] secrets addr[%p] secretscount[%u]",
968 *numsecrets
, *secrets
, secrets
, *secretsCnt
);
972 CFWriteStreamClose(stream
);
996 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
997 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
1000 void SendWakeupPacket(unsigned int ifid
, const char *eth_addr
, const char *ip_addr
, int iteration
)
1004 char ifname
[IFNAMSIZ
];
1007 char bpf_device
[12];
1008 struct ether_addr
*ea
;
1009 // (void) ip_addr; // unused
1010 // (void) iteration; // unused
1012 os_log_info(log_handle
,"SendWakeupPacket() ether_addr[%s] ip_addr[%s] if_id[%d] iteration[%d]",
1013 eth_addr
, ip_addr
, ifid
, iteration
);
1015 if (if_indextoname(ifid
, ifname
) == NULL
)
1017 os_log(log_handle
, "SendWakeupPacket: invalid interface index %u", ifid
);
1021 ea
= ether_aton(eth_addr
);
1024 os_log(log_handle
, "SendWakeupPacket: invalid ethernet address %s", eth_addr
);
1028 for (i
= 0; i
< 100; i
++)
1030 snprintf(bpf_device
, sizeof(bpf_device
), "/dev/bpf%d", i
);
1031 bpf_fd
= open(bpf_device
, O_RDWR
, 0);
1041 os_log(log_handle
, "SendWakeupPacket: cannot find a bpf device");
1045 memset(&ifr
, 0, sizeof(ifr
));
1046 strlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
1048 if (ioctl(bpf_fd
, BIOCSETIF
, (char *)&ifr
) < 0)
1050 os_log(log_handle
, "SendWakeupPacket: BIOCSETIF failed %s", strerror(errno
));
1054 // 0x00 Destination address
1056 *ptr
++ = ea
->octet
[i
];
1058 // 0x06 Source address (Note: Since we don't currently set the BIOCSHDRCMPLT option,
1059 // BPF will fill in the real interface address for us)
1063 // 0x0C Ethertype (0x0842)
1067 // 0x0E Wakeup sync sequence
1072 for (j
=0; j
<16; j
++)
1074 *ptr
++ = ea
->octet
[i
];
1080 if (write(bpf_fd
, packet
, ptr
- packet
) < 0)
1082 os_log(log_handle
, "SendWakeupPacket: write failed %s", strerror(errno
));
1085 os_log(log_handle
, "SendWakeupPacket: sent unicast eth_addr %s, ip_addr %s", eth_addr
, ip_addr
);
1087 // Send a broadcast one to handle ethernet switches that don't flood forward packets with
1088 // unknown mac addresses.
1092 if (write(bpf_fd
, packet
, ptr
- packet
) < 0)
1094 os_log(log_handle
, "SendWakeupPacket: write failed %s", strerror(errno
));
1097 os_log(log_handle
, "SendWakeupPacket: sent broadcast eth_addr %s, ip_addr %s", eth_addr
, ip_addr
);
1104 // Open the specified port for protocol in the P2P firewall.
1105 void PacketFilterControl(uint32_t command
, const char * ifname
, uint32_t count
, pfArray_t portArray
, pfArray_t protocolArray
)
1109 os_log_info(log_handle
,"PacketFilterControl: command %d ifname %s, count %d",
1110 command
, ifname
, count
);
1111 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]);
1116 error
= P2PPacketFilterAddBonjourRuleSet(ifname
, count
, portArray
, protocolArray
);
1118 os_log(log_handle
, "P2PPacketFilterAddBonjourRuleSet failed %s", strerror(error
));
1121 case PF_CLEAR_RULES
:
1122 error
= P2PPacketFilterClearBonjourRules();
1124 os_log(log_handle
, "P2PPacketFilterClearBonjourRules failed %s", strerror(error
));
1128 os_log(log_handle
, "PacketFilterControl: invalid command %d", command
);
1134 static unsigned long in_cksum(unsigned short *ptr
, int nbytes
)
1140 * Our algorithm is simple, using a 32-bit accumulator (sum),
1141 * we add sequential 16-bit words to it, and at the end, fold back
1142 * all the carry bits from the top 16 bits into the lower 16 bits.
1151 /* mop up an odd byte, if necessary */
1154 /* make sure top half is zero */
1158 *((u_char
*)&oddbyte
) = *(u_char
*)ptr
;
1161 /* Add back carry outs from top 16 bits to low 16 bits. */
1162 sum
= (sum
>> 16) + (sum
& 0xffff);
1170 static unsigned short InetChecksum(unsigned short *ptr
, int nbytes
)
1174 sum
= in_cksum(ptr
, nbytes
);
1175 return (unsigned short)~sum
;
1178 static void TCPCheckSum(int af
, struct tcphdr
*t
, int tcplen
, const v6addr_t sadd6
, const v6addr_t dadd6
)
1180 unsigned long sum
= 0;
1181 unsigned short *ptr
;
1183 /* TCP header checksum */
1184 sum
= in_cksum((unsigned short *)t
, tcplen
);
1189 ptr
= (unsigned short *)sadd6
;
1192 ptr
= (unsigned short *)dadd6
;
1196 else if (af
== AF_INET6
)
1199 ptr
= (unsigned short *)sadd6
;
1208 ptr
= (unsigned short *)dadd6
;
1219 sum
+= htons(tcplen
);
1220 sum
+= htons(IPPROTO_TCP
);
1223 sum
= (sum
>> 16) + (sum
& 0xFFFF);
1229 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
)
1232 #define IPv6FMTSTRING "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X"
1233 #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]
1234 #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]
1236 os_log_info(log_handle
, "SendKeepalive: "IPv6FMTSTRING
" :space: "IPv6FMTSTRING
"",
1237 IPv6FMTSARGS
, IPv6FMTDARGS
);
1251 struct sockaddr_storage ss_to
;
1252 struct sockaddr_in
*sin_to
= (struct sockaddr_in
*)&ss_to
;
1253 struct sockaddr_in6
*sin6_to
= (struct sockaddr_in6
*)&ss_to
;
1256 char ctlbuf
[CMSG_SPACE(sizeof(struct in6_pktinfo
))];
1257 struct msghdr msghdr
;
1261 os_log_info(log_handle
,"SendKeepalive invoked: lport is[%d] rport is[%d] seq is[%d] ack is[%d] win is[%d]",
1262 lport
, rport
, seq
, ack
, win
);
1264 char buf1
[INET6_ADDRSTRLEN
];
1265 char buf2
[INET6_ADDRSTRLEN
];
1270 inet_ntop(AF_INET6
, sadd6
, buf1
, sizeof(buf1
));
1271 inet_ntop(AF_INET6
, dadd6
, buf2
, sizeof(buf2
));
1273 os_log_info(log_handle
,"SendKeepalive invoked: sadd6 is %s, dadd6 is %s", buf1
, buf2
);
1275 // all the incoming arguments are in network order
1276 if ((*(unsigned *)(sadd6
+4) == 0) && (*(unsigned *)(sadd6
+ 8) == 0) && (*(unsigned *)(sadd6
+ 12) == 0))
1279 memset(&packet4
, 0, sizeof (packet4
));
1281 /* Fill in all the IP header information - should be in host order*/
1282 packet4
.ip
.ip_v
= 4; /* 4-bit Version */
1283 packet4
.ip
.ip_hl
= 5; /* 4-bit Header Length */
1284 packet4
.ip
.ip_tos
= 0; /* 8-bit Type of service */
1285 packet4
.ip
.ip_len
= 40; /* 16-bit Total length */
1286 packet4
.ip
.ip_id
= 9864; /* 16-bit ID field */
1287 packet4
.ip
.ip_off
= 0; /* 13-bit Fragment offset */
1288 packet4
.ip
.ip_ttl
= 63; /* 8-bit Time To Live */
1289 packet4
.ip
.ip_p
= IPPROTO_TCP
; /* 8-bit Protocol */
1290 packet4
.ip
.ip_sum
= 0; /* 16-bit Header checksum (below) */
1291 memcpy(&packet4
.ip
.ip_src
.s_addr
, sadd6
, 4);
1292 memcpy(&packet4
.ip
.ip_dst
.s_addr
, dadd6
, 4);
1294 /* IP header checksum */
1295 packet4
.ip
.ip_sum
= InetChecksum((unsigned short *)&packet4
.ip
, 20);
1298 packetlen
= 40; // sum of IPv4 header len(20) and TCP header len(20)
1303 memset(&packet6
, 0, sizeof (packet6
));
1306 // We don't send IPv6 header, hence just the TCP header len (20)
1310 /* Fill in all the TCP header information */
1311 t
->th_sport
= lport
; /* 16-bit Source port number */
1312 t
->th_dport
= rport
; /* 16-bit Destination port */
1313 t
->th_seq
= seq
; /* 32-bit Sequence Number */
1314 t
->th_ack
= ack
; /* 32-bit Acknowledgement Number */
1315 t
->th_off
= 5; /* Data offset */
1316 t
->th_flags
= TH_ACK
;
1318 t
->th_sum
= 0; /* 16-bit checksum (below) */
1319 t
->th_urp
= 0; /* 16-bit urgent offset */
1321 TCPCheckSum(af
, t
, 20, sadd6
, dadd6
);
1323 /* Open up a RAW socket */
1324 if ((sock
= socket(af
, SOCK_RAW
, IPPROTO_TCP
)) < 0)
1326 os_log(log_handle
, "SendKeepalive: socket %s", strerror(errno
));
1333 if (setsockopt(sock
, IPPROTO_IP
, IP_HDRINCL
, &on
, sizeof (on
)))
1336 os_log(log_handle
, "SendKeepalive: setsockopt %s", strerror(errno
));
1340 memset(sin_to
, 0, sizeof(struct sockaddr_in
));
1341 sin_to
->sin_len
= sizeof(struct sockaddr_in
);
1342 sin_to
->sin_family
= AF_INET
;
1343 memcpy(&sin_to
->sin_addr
, sadd6
, sizeof(struct in_addr
));
1344 sin_to
->sin_port
= rport
;
1346 msghdr
.msg_control
= NULL
;
1347 msghdr
.msg_controllen
= 0;
1352 struct cmsghdr
*ctl
;
1354 memset(sin6_to
, 0, sizeof(struct sockaddr_in6
));
1355 sin6_to
->sin6_len
= sizeof(struct sockaddr_in6
);
1356 sin6_to
->sin6_family
= AF_INET6
;
1357 memcpy(&sin6_to
->sin6_addr
, dadd6
, sizeof(struct in6_addr
));
1359 sin6_to
->sin6_port
= rport
;
1360 sin6_to
->sin6_flowinfo
= 0;
1363 msghdr
.msg_control
= ctlbuf
;
1364 msghdr
.msg_controllen
= sizeof(ctlbuf
);
1365 ctl
= CMSG_FIRSTHDR(&msghdr
);
1366 ctl
->cmsg_len
= CMSG_LEN(sizeof(struct in6_pktinfo
));
1367 ctl
->cmsg_level
= IPPROTO_IPV6
;
1368 ctl
->cmsg_type
= IPV6_PKTINFO
;
1369 struct in6_pktinfo
*pktinfo
= (struct in6_pktinfo
*) CMSG_DATA(ctl
);
1370 memcpy(&pktinfo
->ipi6_addr
, sadd6
, sizeof(struct in6_addr
));
1371 pktinfo
->ipi6_ifindex
= 0;
1374 msghdr
.msg_name
= (struct sockaddr
*)&ss_to
;
1375 msghdr
.msg_namelen
= ss_to
.ss_len
;
1376 iov
.iov_base
= packet
;
1377 iov
.iov_len
= packetlen
;
1378 msghdr
.msg_iov
= &iov
;
1379 msghdr
.msg_iovlen
= 1;
1380 msghdr
.msg_flags
= 0;
1383 len
= sendmsg(sock
, &msghdr
, 0);
1390 if (len
!= packetlen
)
1392 os_log(log_handle
, "SendKeepalive: sendmsg failed %s", strerror(errno
));
1396 char source
[INET6_ADDRSTRLEN
], dest
[INET6_ADDRSTRLEN
];
1398 inet_ntop(af
, (void *)sadd6
, source
, sizeof(source
));
1399 inet_ntop(af
, (void *)dadd6
, dest
, sizeof(dest
));
1401 os_log(log_handle
, "SendKeepalive: Success Source %s:%d, Dest %s:%d, %u, %u, %u",
1402 source
, ntohs(lport
), dest
, ntohs(rport
), ntohl(seq
), ntohl(ack
), ntohs(win
));
1410 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
)
1414 struct info_tuple itpl
;
1416 unsigned int miblen
;
1420 memset(&itpl
, 0, sizeof(struct info_tuple
));
1421 memset(&ti
, 0, sizeof(struct tcp_info
));
1423 char buf1
[INET6_ADDRSTRLEN
];
1424 char buf2
[INET6_ADDRSTRLEN
];
1429 inet_ntop(AF_INET6
, laddr
, buf1
, sizeof(buf1
));
1430 inet_ntop(AF_INET6
, raddr
, buf2
, sizeof(buf2
));
1432 os_log_info(log_handle
, "RetrieveTCPInfo invoked: laddr is %s, raddr is %s", buf1
, buf2
);
1434 os_log_info(log_handle
,"RetrieveTCPInfo invoked: lport is[%d] rport is[%d] family is [%d]",
1435 lport
, rport
, family
);
1437 if (family
== AF_INET
)
1439 memcpy(&itpl
.itpl_local_sin
.sin_addr
, laddr
, sizeof(struct in_addr
));
1440 memcpy(&itpl
.itpl_remote_sin
.sin_addr
, raddr
, sizeof(struct in_addr
));
1441 itpl
.itpl_local_sin
.sin_port
= lport
;
1442 itpl
.itpl_remote_sin
.sin_port
= rport
;
1443 itpl
.itpl_local_sin
.sin_family
= AF_INET
;
1444 itpl
.itpl_remote_sin
.sin_family
= AF_INET
;
1448 memcpy(&itpl
.itpl_local_sin6
.sin6_addr
, laddr
, sizeof(struct in6_addr
));
1449 memcpy(&itpl
.itpl_remote_sin6
.sin6_addr
, raddr
, sizeof(struct in6_addr
));
1450 itpl
.itpl_local_sin6
.sin6_port
= lport
;
1451 itpl
.itpl_remote_sin6
.sin6_port
= rport
;
1452 itpl
.itpl_local_sin6
.sin6_family
= AF_INET6
;
1453 itpl
.itpl_remote_sin6
.sin6_family
= AF_INET6
;
1455 itpl
.itpl_proto
= IPPROTO_TCP
;
1456 sz
= sizeof(mib
)/sizeof(mib
[0]);
1457 if (sysctlnametomib("net.inet.tcp.info", mib
, &sz
) == -1)
1459 const int sysctl_errno
= errno
;
1460 os_log(log_handle
, "RetrieveTCPInfo: sysctlnametomib failed %d, %s", sysctl_errno
, strerror(sysctl_errno
));
1461 *err
= sysctl_errno
;
1463 miblen
= (unsigned int)sz
;
1464 len
= sizeof(struct tcp_info
);
1465 if (sysctl(mib
, miblen
, &ti
, &len
, &itpl
, sizeof(struct info_tuple
)) == -1)
1467 const int sysctl_errno
= errno
;
1468 os_log(log_handle
, "RetrieveTCPInfo: sysctl failed %d, %s", sysctl_errno
, strerror(sysctl_errno
));
1469 *err
= sysctl_errno
;
1472 *seq
= ti
.tcpi_snd_nxt
- 1;
1473 *ack
= ti
.tcpi_rcv_nxt
;
1474 *win
= ti
.tcpi_rcv_space
>> ti
.tcpi_rcv_wscale
;
1475 *intfid
= ti
.tcpi_last_outif
;
1476 *err
= KERN_SUCCESS
;
1480 #ifndef MDNS_NO_IPSEC
1482 static const char configHeader
[] = "# BackToMyMac\n";
1483 static const char g_racoon_config_dir
[] = "/var/run/racoon/";
1484 static const char g_racoon_config_dir_old
[] = "/etc/racoon/remote/";
1486 static int MacOSXSystemBuildNumber(char* letter_out
, int* minor_out
)
1488 int major
= 0, minor
= 0;
1489 char letter
= 0, buildver
[256]="<Unknown>";
1490 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
1493 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
1494 if (cfbuildver
) CFStringGetCString(cfbuildver
, buildver
, sizeof(buildver
), kCFStringEncodingUTF8
);
1495 sscanf(buildver
, "%d%c%d", &major
, &letter
, &minor
);
1499 os_log_info(log_handle
, "_CFCopySystemVersionDictionary failed");
1501 if (!major
) { major
=16; letter
= 'A'; minor
= 300; os_log_info(log_handle
, "Note: No Major Build Version number found; assuming 16A300"); }
1502 if (letter_out
) *letter_out
= letter
;
1503 if (minor_out
) *minor_out
= minor
;
1507 static int UseOldRacoon()
1509 static int g_oldRacoon
= -1;
1511 if (g_oldRacoon
== -1)
1515 g_oldRacoon
= (MacOSXSystemBuildNumber(&letter
, &minor
) < 10);
1516 os_log_debug(log_handle
, "%s", g_oldRacoon
? "old" : "new");
1522 static int RacoonSignal()
1524 return UseOldRacoon() ? SIGHUP
: SIGUSR1
;
1527 static int notifyRacoon(void)
1529 os_log_debug(log_handle
,"entry");
1530 static const char racoon_pid_path
[] = "/var/run/racoon.pid";
1531 char buf
[] = "18446744073709551615"; /* largest 64-bit integer */
1534 unsigned long m
= 0;
1535 int fd
= open(racoon_pid_path
, O_RDONLY
);
1539 os_log_debug(log_handle
,"open \"%s\" failed, and that's OK: %s", racoon_pid_path
,
1541 return kHelperErr_RacoonNotificationFailed
;
1543 n
= read(fd
, buf
, sizeof(buf
)-1);
1547 os_log_debug(log_handle
,"read of \"%s\" failed: %s", racoon_pid_path
,
1548 n
== 0 ? "empty file" : strerror(errno
));
1549 return kHelperErr_RacoonNotificationFailed
;
1552 m
= strtoul(buf
, &p
, 10);
1553 if (*p
!= '\0' && !isspace(*p
))
1555 os_log_debug(log_handle
,"invalid PID \"%s\" (around '%c')", buf
, *p
);
1556 return kHelperErr_RacoonNotificationFailed
;
1560 os_log_debug(log_handle
,"refusing to kill PID %lu", m
);
1561 return kHelperErr_RacoonNotificationFailed
;
1563 if (0 != kill(m
, RacoonSignal()))
1565 os_log_debug(log_handle
,"Could not signal racoon (%lu): %s", m
, strerror(errno
));
1566 return kHelperErr_RacoonNotificationFailed
;
1569 os_log_debug(log_handle
, "Sent racoon (%lu) signal %d", m
, RacoonSignal());
1573 static const char* GetRacoonConfigDir()
1575 return UseOldRacoon() ? g_racoon_config_dir_old
: g_racoon_config_dir
;
1578 static const char* GetOldRacoonConfigDir()
1580 return UseOldRacoon() ? NULL : g_racoon_config_dir_old;
1584 static void closefds(int from
)
1587 struct dirent entry
, *entryp
= NULL
;
1588 DIR *dirp
= opendir("/dev/fd");
1592 /* fall back to the erroneous getdtablesize method */
1593 for (fd
= from
; fd
< getdtablesize(); ++fd
)
1597 while (0 == readdir_r(dirp
, &entry
, &entryp
) && NULL
!= entryp
)
1599 fd
= atoi(entryp
->d_name
);
1600 if (fd
>= from
&& fd
!= dirfd(dirp
))
1607 static int startRacoonOld(void)
1609 os_log_debug(log_handle
,"entry");
1610 char * const racoon_args
[] = { "/usr/sbin/racoon", "-e", NULL
};
1615 if (0 == (pid
= fork()))
1618 execve(racoon_args
[0], racoon_args
, NULL
);
1619 os_log_info(log_handle
, "execve of \"%s\" failed: %s",
1620 racoon_args
[0], strerror(errno
));
1623 os_log_info(log_handle
,"racoon (pid=%lu) started",
1624 (unsigned long)pid
);
1625 n
= waitpid(pid
, &status
, 0);
1628 os_log(log_handle
, "Unexpected waitpid failure: %s",
1630 return kHelperErr_RacoonStartFailed
;
1634 os_log(log_handle
, "Unexpected waitpid return value %d", (int)n
);
1635 return kHelperErr_RacoonStartFailed
;
1637 else if (WIFSIGNALED(status
))
1640 "racoon (pid=%lu) terminated due to signal %d",
1641 (unsigned long)pid
, WTERMSIG(status
));
1642 return kHelperErr_RacoonStartFailed
;
1644 else if (WIFSTOPPED(status
))
1647 "racoon (pid=%lu) has stopped due to signal %d",
1648 (unsigned long)pid
, WSTOPSIG(status
));
1649 return kHelperErr_RacoonStartFailed
;
1651 else if (0 != WEXITSTATUS(status
))
1654 "racoon (pid=%lu) exited with status %d",
1655 (unsigned long)pid
, WEXITSTATUS(status
));
1656 return kHelperErr_RacoonStartFailed
;
1658 os_log_debug(log_handle
, "racoon (pid=%lu) daemonized normally", (unsigned long)pid
);
1662 // constant and structure for the racoon control socket
1663 #define VPNCTL_CMD_PING 0x0004
1664 typedef struct vpnctl_hdr_struct
1674 static int startRacoon(void)
1676 os_log_debug(log_handle
,"entry");
1677 int fd
= socket(PF_UNIX
, SOCK_STREAM
, 0);
1680 os_log(log_handle
,"Could not create endpoint for racoon control socket: %d %s",
1681 errno
, strerror(errno
));
1682 return kHelperErr_RacoonStartFailed
;
1685 struct sockaddr_un saddr
;
1686 memset(&saddr
, 0, sizeof(saddr
));
1687 saddr
.sun_family
= AF_UNIX
;
1688 saddr
.sun_len
= sizeof(saddr
);
1689 static const char racoon_control_sock_path
[] = "/var/run/vpncontrol.sock";
1690 strcpy(saddr
.sun_path
, racoon_control_sock_path
);
1691 int result
= connect(fd
, (struct sockaddr
*) &saddr
, saddr
.sun_len
);
1694 os_log(log_handle
, "Could not connect racoon control socket %s: %d %s",
1695 racoon_control_sock_path
, errno
, strerror(errno
));
1696 return kHelperErr_RacoonStartFailed
;
1699 u_int32_t btmm_cookie
= 0x4d4d5442;
1700 vpnctl_hdr h
= { htons(VPNCTL_CMD_PING
), 0, btmm_cookie
, 0, 0, 0 };
1704 while (bytes
< sizeof(vpnctl_hdr
))
1706 ret
= write(fd
, ((unsigned char*)&h
)+bytes
, sizeof(vpnctl_hdr
) - bytes
);
1709 os_log(log_handle
, "Could not write to racoon control socket: %d %s", errno
, strerror(errno
));
1710 return kHelperErr_RacoonStartFailed
;
1722 for (counter
= 0; counter
< 100; counter
++)
1726 tv
= (struct timeval
){ 0, 10000 }; // 10 milliseconds * 100 iterations = 1 second max wait time
1728 result
= select(nfds
, &fds
, (fd_set
*)NULL
, (fd_set
*)NULL
, &tv
);
1731 if (FD_ISSET(fd
, &fds
))
1733 ret
= read(fd
, ((unsigned char*)&h
)+bytes
, sizeof(vpnctl_hdr
) - bytes
);
1737 os_log(log_handle
,"Could not read from racoon control socket: %d %s", errno
, strerror(errno
));
1741 if (bytes
>= sizeof(vpnctl_hdr
)) break;
1745 os_log_debug(log_handle
, "select returned but fd_isset not on expected fd");
1748 else if (result
< 0)
1750 const int select_errno
= errno
;
1751 os_log_debug(log_handle
, "select returned %d errno %d %s", result
, select_errno
, strerror(select_errno
));
1752 if (select_errno
!= EINTR
) break;
1758 if (bytes
< sizeof(vpnctl_hdr
) || h
.cookie
!= btmm_cookie
)
1759 return kHelperErr_RacoonStartFailed
;
1761 os_log_debug(log_handle
, "racoon started");
1765 static int kickRacoon(void)
1767 if ( 0 == notifyRacoon() )
1769 return UseOldRacoon() ? startRacoonOld() : startRacoon();
1772 typedef enum _mDNSTunnelPolicyWhich
1774 kmDNSTunnelPolicySetup
,
1775 kmDNSTunnelPolicyTeardown
,
1776 kmDNSTunnelPolicyGenerate
1777 } mDNSTunnelPolicyWhich
;
1779 // For kmDNSTunnelPolicySetup, you can setup IPv6-in-IPv6 tunnel or IPv6-in-IPv4 tunnel
1780 // kmDNSNoTunnel is used for other Policy types
1781 typedef enum _mDNSTunnelType
1784 kmDNSIPv6IPv4Tunnel
,
1788 static const uint8_t kWholeV6Mask
= 128;
1790 static unsigned int routeSeq
= 1;
1792 static int setupTunnelRoute(const v6addr_t local
, const v6addr_t remote
)
1796 struct rt_msghdr hdr
;
1797 struct sockaddr_in6 dst
;
1798 struct sockaddr_in6 gtwy
;
1803 if (0 > (s
= socket(PF_ROUTE
, SOCK_RAW
, AF_INET
)))
1805 os_log(log_handle
,"socket(PF_ROUTE, ...) failed: %s", strerror(errno
));
1807 err
= kHelperErr_RoutingSocketCreationFailed
;
1811 memset(&msg
, 0, sizeof(msg
));
1812 msg
.hdr
.rtm_msglen
= sizeof(msg
);
1813 msg
.hdr
.rtm_type
= RTM_ADD
;
1814 /* The following flags are set by `route add -inet6 -host ...` */
1815 msg
.hdr
.rtm_flags
= RTF_UP
| RTF_GATEWAY
| RTF_HOST
| RTF_STATIC
;
1816 msg
.hdr
.rtm_version
= RTM_VERSION
;
1817 msg
.hdr
.rtm_seq
= routeSeq
++;
1818 msg
.hdr
.rtm_addrs
= RTA_DST
| RTA_GATEWAY
;
1819 msg
.hdr
.rtm_inits
= RTV_MTU
;
1820 msg
.hdr
.rtm_rmx
.rmx_mtu
= 1280;
1822 msg
.dst
.sin6_len
= sizeof(msg
.dst
);
1823 msg
.dst
.sin6_family
= AF_INET6
;
1824 memcpy(&msg
.dst
.sin6_addr
, remote
, sizeof(msg
.dst
.sin6_addr
));
1826 msg
.gtwy
.sin6_len
= sizeof(msg
.gtwy
);
1827 msg
.gtwy
.sin6_family
= AF_INET6
;
1828 memcpy(&msg
.gtwy
.sin6_addr
, local
, sizeof(msg
.gtwy
.sin6_addr
));
1830 /* send message, ignore error when route already exists */
1831 if (0 > write(s
, &msg
, msg
.hdr
.rtm_msglen
))
1833 const int errno_
= errno
;
1835 os_log_info(log_handle
,"write to routing socket failed: %s", strerror(errno_
));
1836 if (EEXIST
!= errno_
)
1838 err
= kHelperErr_RouteAdditionFailed
;
1849 static int teardownTunnelRoute(const v6addr_t remote
)
1853 struct rt_msghdr hdr
;
1854 struct sockaddr_in6 dst
;
1859 if (0 > (s
= socket(PF_ROUTE
, SOCK_RAW
, AF_INET
)))
1861 os_log(log_handle
, "socket(PF_ROUTE, ...) failed: %s", strerror(errno
));
1862 err
= kHelperErr_RoutingSocketCreationFailed
;
1865 memset(&msg
, 0, sizeof(msg
));
1867 msg
.hdr
.rtm_msglen
= sizeof(msg
);
1868 msg
.hdr
.rtm_type
= RTM_DELETE
;
1869 msg
.hdr
.rtm_version
= RTM_VERSION
;
1870 msg
.hdr
.rtm_seq
= routeSeq
++;
1871 msg
.hdr
.rtm_addrs
= RTA_DST
;
1873 msg
.dst
.sin6_len
= sizeof(msg
.dst
);
1874 msg
.dst
.sin6_family
= AF_INET6
;
1875 memcpy(&msg
.dst
.sin6_addr
, remote
, sizeof(msg
.dst
.sin6_addr
));
1876 if (0 > write(s
, &msg
, msg
.hdr
.rtm_msglen
))
1878 const int errno_
= errno
;
1880 os_log_debug(log_handle
,"write to routing socket failed: %s", strerror(errno_
));
1882 if (ESRCH
!= errno_
)
1884 err
= kHelperErr_RouteDeletionFailed
;
1895 static int v4addr_to_string(v4addr_t addr
, char *buf
, size_t buflen
)
1897 if (NULL
== inet_ntop(AF_INET
, addr
, buf
, buflen
))
1899 os_log(log_handle
, "v4addr_to_string() inet_ntop failed: %s", strerror(errno
));
1900 return kHelperErr_InvalidNetworkAddress
;
1908 static int v6addr_to_string(const v6addr_t addr
, char *buf
, size_t buflen
)
1910 if (NULL
== inet_ntop(AF_INET6
, addr
, buf
, buflen
))
1912 os_log(log_handle
, "v6addr_to_string inet_ntop failed: %s", strerror(errno
));
1913 return kHelperErr_InvalidNetworkAddress
;
1921 static int ensureExistenceOfRacoonConfigDir(const char* const racoon_config_dir
)
1924 int ret
= stat(racoon_config_dir
, &s
);
1927 if (errno
!= ENOENT
)
1929 os_log(log_handle
, "stat of \"%s\" failed (%d): %s",
1930 racoon_config_dir
, ret
, strerror(errno
));
1935 ret
= mkdir(racoon_config_dir
, S_IRWXU
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
);
1938 os_log(log_handle
, "mkdir \"%s\" failed: %s",
1939 racoon_config_dir
, strerror(errno
));
1944 os_log_info(log_handle
, "created directory \"%s\"", racoon_config_dir
);
1948 else if (!(s
.st_mode
& S_IFDIR
))
1950 os_log(log_handle
, "\"%s\" is not a directory!",
1960 /* Caller owns object returned in `policy' */
1961 static int generateTunnelPolicy(mDNSTunnelPolicyWhich which
, mDNSTunnelType type
, int in
,
1962 v4addr_t src
, uint16_t src_port
,
1963 v4addr_t dst
, uint16_t dst_port
,
1964 const v6addr_t src6
, const v6addr_t dst6
,
1965 ipsec_policy_t
*policy
, size_t *len
)
1967 char srcs
[INET_ADDRSTRLEN
], dsts
[INET_ADDRSTRLEN
];
1968 char srcs6
[INET6_ADDRSTRLEN
], dsts6
[INET6_ADDRSTRLEN
];
1970 char *inOut
= in
? "in" : "out";
1979 case kmDNSTunnelPolicySetup
:
1980 if (type
== kmDNSIPv6IPv4Tunnel
)
1982 if (0 != (err
= v4addr_to_string(src
, srcs
, sizeof(srcs
))))
1984 if (0 != (err
= v4addr_to_string(dst
, dsts
, sizeof(dsts
))))
1986 n
= snprintf(buf
, sizeof(buf
),
1987 "%s ipsec esp/tunnel/%s[%u]-%s[%u]/require",
1988 inOut
, srcs
, src_port
, dsts
, dst_port
);
1990 else if (type
== kmDNSIPv6IPv6Tunnel
)
1992 if (0 != (err
= v6addr_to_string(src6
, srcs6
, sizeof(srcs6
))))
1994 if (0 != (err
= v6addr_to_string(dst6
, dsts6
, sizeof(dsts6
))))
1996 n
= snprintf(buf
, sizeof(buf
),
1997 "%s ipsec esp/tunnel/%s-%s/require",
1998 inOut
, srcs6
, dsts6
);
2001 case kmDNSTunnelPolicyTeardown
:
2002 n
= strlcpy(buf
, inOut
, sizeof(buf
));
2004 case kmDNSTunnelPolicyGenerate
:
2005 n
= snprintf(buf
, sizeof(buf
), "%s generate", inOut
);
2008 err
= kHelperErr_IPsecPolicyCreationFailed
;
2012 if (n
>= (int)sizeof(buf
))
2014 err
= kHelperErr_ResultTooLarge
;
2018 os_log_info(log_handle
, "policy=\"%s\"", buf
);
2020 if (NULL
== (*policy
= (ipsec_policy_t
)ipsec_set_policy(buf
, n
)))
2022 os_log_info(log_handle
, "Could not create IPsec policy from \"%s\"", buf
);
2023 err
= kHelperErr_IPsecPolicyCreationFailed
;
2026 *len
= ((ipsec_policy_t
)(*policy
))->sadb_x_policy_len
* 8;
2032 static int sendPolicy(int s
, int setup
,
2033 struct sockaddr
*src
, uint8_t src_bits
,
2034 struct sockaddr
*dst
, uint8_t dst_bits
,
2035 ipsec_policy_t policy
, size_t len
)
2037 static unsigned int policySeq
= 0;
2040 os_log_debug(log_handle
, "entry, setup=%d", setup
);
2043 err
= pfkey_send_spdadd(s
, src
, src_bits
, dst
, dst_bits
, -1,
2044 (char *)policy
, len
, policySeq
++);
2046 err
= pfkey_send_spddelete(s
, src
, src_bits
, dst
, dst_bits
, -1,
2047 (char *)policy
, len
, policySeq
++);
2051 os_log(log_handle
, "Could not set IPsec policy: %s", ipsec_strerror());
2052 err
= kHelperErr_IPsecPolicySetFailed
;
2060 os_log_debug(log_handle
, "succeeded");
2066 static int removeSA(int s
, struct sockaddr
*src
, struct sockaddr
*dst
)
2070 os_log_debug(log_handle
, "entry");
2072 err
= pfkey_send_delete_all(s
, SADB_SATYPE_ESP
, IPSEC_MODE_ANY
, src
, dst
);
2075 os_log(log_handle
, "Could not remove IPsec SA: %s", ipsec_strerror());
2076 err
= kHelperErr_IPsecRemoveSAFailed
;
2079 err
= pfkey_send_delete_all(s
, SADB_SATYPE_ESP
, IPSEC_MODE_ANY
, dst
, src
);
2082 os_log(log_handle
, "Could not remove IPsec SA: %s", ipsec_strerror());
2083 err
= kHelperErr_IPsecRemoveSAFailed
;
2089 os_log_debug(log_handle
, "succeeded");
2095 static int doTunnelPolicy(mDNSTunnelPolicyWhich which
, mDNSTunnelType type
,
2096 const v6addr_t loc_inner
, uint8_t loc_bits
,
2097 v4addr_t loc_outer
, uint16_t loc_port
,
2098 const v6addr_t rmt_inner
, uint8_t rmt_bits
,
2099 v4addr_t rmt_outer
, uint16_t rmt_port
,
2100 const v6addr_t loc_outer6
, const v6addr_t rmt_outer6
)
2102 struct sockaddr_in6 sin6_loc
;
2103 struct sockaddr_in6 sin6_rmt
;
2104 ipsec_policy_t policy
= NULL
;
2109 os_log_debug(log_handle
,"entry");
2110 if (0 > (s
= pfkey_open()))
2112 os_log(log_handle
, "Could not create IPsec policy socket: %s", ipsec_strerror());
2113 err
= kHelperErr_IPsecPolicySocketCreationFailed
;
2117 memset(&sin6_loc
, 0, sizeof(sin6_loc
));
2118 sin6_loc
.sin6_len
= sizeof(sin6_loc
);
2119 sin6_loc
.sin6_family
= AF_INET6
;
2120 sin6_loc
.sin6_port
= htons(0);
2121 memcpy(&sin6_loc
.sin6_addr
, loc_inner
, sizeof(sin6_loc
.sin6_addr
));
2123 memset(&sin6_rmt
, 0, sizeof(sin6_rmt
));
2124 sin6_rmt
.sin6_len
= sizeof(sin6_rmt
);
2125 sin6_rmt
.sin6_family
= AF_INET6
;
2126 sin6_rmt
.sin6_port
= htons(0);
2127 memcpy(&sin6_rmt
.sin6_addr
, rmt_inner
, sizeof(sin6_rmt
.sin6_addr
));
2129 int setup
= which
!= kmDNSTunnelPolicyTeardown
;
2131 if (0 != (err
= generateTunnelPolicy(which
, type
, 1,
2132 rmt_outer
, rmt_port
,
2133 loc_outer
, loc_port
,
2134 rmt_outer6
, loc_outer6
,
2138 if (0 != (err
= sendPolicy(s
, setup
,
2139 (struct sockaddr
*)&sin6_rmt
, rmt_bits
,
2140 (struct sockaddr
*)&sin6_loc
, loc_bits
,
2150 if (0 != (err
= generateTunnelPolicy(which
, type
, 0,
2151 loc_outer
, loc_port
,
2152 rmt_outer
, rmt_port
,
2153 loc_outer6
, rmt_outer6
,
2156 if (0 != (err
= sendPolicy(s
, setup
,
2157 (struct sockaddr
*)&sin6_loc
, loc_bits
,
2158 (struct sockaddr
*)&sin6_rmt
, rmt_bits
,
2162 if (which
== kmDNSTunnelPolicyTeardown
)
2164 if (rmt_port
) // Outer tunnel is IPv4
2166 if (loc_outer
&& rmt_outer
)
2168 struct sockaddr_in sin_loc
;
2169 struct sockaddr_in sin_rmt
;
2170 memset(&sin_loc
, 0, sizeof(sin_loc
));
2171 sin_loc
.sin_len
= sizeof(sin_loc
);
2172 sin_loc
.sin_family
= AF_INET
;
2173 memcpy(&sin_loc
.sin_addr
, loc_outer
, sizeof(sin_loc
.sin_addr
));
2175 memset(&sin_rmt
, 0, sizeof(sin_rmt
));
2176 sin_rmt
.sin_len
= sizeof(sin_rmt
);
2177 sin_rmt
.sin_family
= AF_INET
;
2178 memcpy(&sin_rmt
.sin_addr
, rmt_outer
, sizeof(sin_rmt
.sin_addr
));
2179 if (0 != (err
= removeSA(s
, (struct sockaddr
*)&sin_loc
, (struct sockaddr
*)&sin_rmt
)))
2185 if (loc_outer6
&& rmt_outer6
)
2187 struct sockaddr_in6 sin6_lo
;
2188 struct sockaddr_in6 sin6_rm
;
2190 memset(&sin6_lo
, 0, sizeof(sin6_lo
));
2191 sin6_lo
.sin6_len
= sizeof(sin6_lo
);
2192 sin6_lo
.sin6_family
= AF_INET6
;
2193 memcpy(&sin6_lo
.sin6_addr
, loc_outer6
, sizeof(sin6_lo
.sin6_addr
));
2195 memset(&sin6_rm
, 0, sizeof(sin6_rm
));
2196 sin6_rm
.sin6_len
= sizeof(sin6_rm
);
2197 sin6_rm
.sin6_family
= AF_INET6
;
2198 memcpy(&sin6_rm
.sin6_addr
, rmt_outer6
, sizeof(sin6_rm
.sin6_addr
));
2199 if (0 != (err
= removeSA(s
, (struct sockaddr
*)&sin6_lo
, (struct sockaddr
*)&sin6_rm
)))
2205 os_log_debug(log_handle
,"succeeded");
2215 #endif /* ndef MDNS_NO_IPSEC */
2217 int HelperAutoTunnelSetKeys(int replacedelete
, const v6addr_t loc_inner
, const v6addr_t loc_outer6
, uint16_t loc_port
, const v6addr_t rmt_inner
,
2218 const v6addr_t rmt_outer6
, uint16_t rmt_port
, const char *id
, int *err
)
2220 #ifndef MDNS_NO_IPSEC
2221 static const char config
[] =
2223 "remote %s [%u] {\n"
2224 " disconnect_on_idle idle_timeout 600 idle_direction idle_outbound;\n"
2225 " exchange_mode aggressive;\n"
2227 " situation identity_only;\n"
2228 " verify_identifier off;\n"
2229 " generate_policy on;\n"
2230 " my_identifier user_fqdn \"%s\";\n"
2231 " shared_secret keychain \"%s\";\n"
2233 " lifetime time 15 min;\n"
2234 " initial_contact on;\n"
2235 " support_proxy on;\n"
2236 " nat_traversal force;\n"
2237 " proposal_check claim;\n"
2239 " encryption_algorithm aes;\n"
2240 " hash_algorithm sha256;\n"
2241 " authentication_method pre_shared_key;\n"
2243 " lifetime time 15 min;\n"
2246 " encryption_algorithm aes;\n"
2247 " hash_algorithm sha1;\n"
2248 " authentication_method pre_shared_key;\n"
2250 " lifetime time 15 min;\n"
2253 "sainfo address %s any address %s any {\n"
2255 " lifetime time 10 min;\n"
2256 " encryption_algorithm aes;\n"
2257 " authentication_algorithm hmac_sha256,hmac_sha1;\n"
2258 " compression_algorithm deflate;\n"
2260 "sainfo address %s any address %s any {\n"
2262 " lifetime time 10 min;\n"
2263 " encryption_algorithm aes;\n"
2264 " authentication_algorithm hmac_sha256,hmac_sha1;\n"
2265 " compression_algorithm deflate;\n"
2267 char path
[PATH_MAX
] = "";
2268 char li
[INET6_ADDRSTRLEN
], lo
[INET_ADDRSTRLEN
], lo6
[INET6_ADDRSTRLEN
],
2269 ri
[INET6_ADDRSTRLEN
], ro
[INET_ADDRSTRLEN
], ro6
[INET6_ADDRSTRLEN
];
2272 char tmp_path
[PATH_MAX
] = "";
2273 v4addr_t loc_outer
, rmt_outer
;
2275 os_log_debug(log_handle
,"HelperAutoTunnelSetKeys: entry");
2276 *err
= kHelperErr_NoErr
;
2278 char buf1
[INET6_ADDRSTRLEN
];
2279 char buf2
[INET6_ADDRSTRLEN
];
2280 char buf3
[INET6_ADDRSTRLEN
];
2281 char buf4
[INET6_ADDRSTRLEN
];
2288 inet_ntop(AF_INET6
, loc_inner
, buf1
, sizeof(buf1
));
2289 inet_ntop(AF_INET6
, loc_outer6
, buf2
, sizeof(buf2
));
2290 inet_ntop(AF_INET6
, rmt_inner
, buf3
, sizeof(buf3
));
2291 inet_ntop(AF_INET6
, rmt_outer6
, buf4
, sizeof(buf4
));
2293 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",
2294 buf1
, buf2
, buf3
, buf4
, id
);
2296 switch ((enum mDNSAutoTunnelSetKeysReplaceDelete
)replacedelete
)
2298 case kmDNSAutoTunnelSetKeysReplace
:
2299 case kmDNSAutoTunnelSetKeysDelete
:
2302 *err
= kHelperErr_InvalidTunnelSetKeysOperation
;
2306 if (0 != (*err
= v6addr_to_string(loc_inner
, li
, sizeof(li
))))
2308 if (0 != (*err
= v6addr_to_string(rmt_inner
, ri
, sizeof(ri
))))
2311 os_log_debug(log_handle
, "loc_inner=%s rmt_inner=%s", li
, ri
);
2315 loc_outer
[0] = loc_outer
[1] = loc_outer
[2] = loc_outer
[3] = 0;
2316 rmt_outer
[0] = rmt_outer
[1] = rmt_outer
[2] = rmt_outer
[3] = 0;
2318 if (0 != (*err
= v6addr_to_string(loc_outer6
, lo6
, sizeof(lo6
))))
2320 if (0 != (*err
= v6addr_to_string(rmt_outer6
, ro6
, sizeof(ro6
))))
2323 os_log_debug(log_handle
, "IPv6 outer tunnel: loc_outer6=%s rmt_outer6=%s", lo6
, ro6
);
2325 if ((int)sizeof(path
) <= snprintf(path
, sizeof(path
), "%s%s.conf", GetRacoonConfigDir(), ro6
))
2327 *err
= kHelperErr_ResultTooLarge
;
2333 loc_outer
[0] = loc_outer6
[0];
2334 loc_outer
[1] = loc_outer6
[1];
2335 loc_outer
[2] = loc_outer6
[2];
2336 loc_outer
[3] = loc_outer6
[3];
2338 rmt_outer
[0] = rmt_outer6
[0];
2339 rmt_outer
[1] = rmt_outer6
[1];
2340 rmt_outer
[2] = rmt_outer6
[2];
2341 rmt_outer
[3] = rmt_outer6
[3];
2343 if (0 != (*err
= v4addr_to_string(loc_outer
, lo
, sizeof(lo
))))
2345 if (0 != (*err
= v4addr_to_string(rmt_outer
, ro
, sizeof(ro
))))
2348 os_log_debug(log_handle
, "IPv4 outer tunnel: loc_outer=%s loc_port=%u rmt_outer=%s rmt_port=%u",
2349 lo
, loc_port
, ro
, rmt_port
);
2351 if ((int)sizeof(path
) <= snprintf(path
, sizeof(path
), "%s%s.%u.conf", GetRacoonConfigDir(), ro
, rmt_port
))
2353 *err
= kHelperErr_ResultTooLarge
;
2358 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
)
2360 if (0 > ensureExistenceOfRacoonConfigDir(GetRacoonConfigDir()))
2362 *err
= kHelperErr_RacoonConfigCreationFailed
;
2365 if ((int)sizeof(tmp_path
) <=
2366 snprintf(tmp_path
, sizeof(tmp_path
), "%s.XXXXXX", path
))
2368 *err
= kHelperErr_ResultTooLarge
;
2371 if (0 > (fd
= mkstemp(tmp_path
)))
2373 os_log(log_handle
, "mkstemp \"%s\" failed: %s", tmp_path
, strerror(errno
));
2374 *err
= kHelperErr_RacoonConfigCreationFailed
;
2377 if (NULL
== (fp
= fdopen(fd
, "w")))
2379 os_log(log_handle
, "fdopen: %s", strerror(errno
));
2380 *err
= kHelperErr_RacoonConfigCreationFailed
;
2385 fprintf(fp
, config
, configHeader
, (!rmt_port
? ro6
: ro
), rmt_port
, id
, id
, ri
, li
, li
, ri
);
2389 if (0 > rename(tmp_path
, path
))
2391 os_log(log_handle
, "rename \"%s\" \"%s\" failed: %s", tmp_path
, path
, strerror(errno
));
2392 *err
= kHelperErr_RacoonConfigCreationFailed
;
2398 if (0 != unlink(path
))
2399 os_log_debug(log_handle
, "unlink \"%s\" failed: %s", path
, strerror(errno
));
2402 if (0 != (*err
= doTunnelPolicy(kmDNSTunnelPolicyTeardown
, kmDNSNoTunnel
,
2403 loc_inner
, kWholeV6Mask
, loc_outer
, loc_port
,
2404 rmt_inner
, kWholeV6Mask
, rmt_outer
, rmt_port
, loc_outer6
, rmt_outer6
)))
2406 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
&&
2407 0 != (*err
= doTunnelPolicy(kmDNSTunnelPolicySetup
, (!rmt_port
? kmDNSIPv6IPv6Tunnel
: kmDNSIPv6IPv4Tunnel
),
2408 loc_inner
, kWholeV6Mask
, loc_outer
, loc_port
,
2409 rmt_inner
, kWholeV6Mask
, rmt_outer
, rmt_port
, loc_outer6
, rmt_outer6
)))
2412 if (0 != (*err
= teardownTunnelRoute(rmt_inner
)))
2415 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
&&
2416 0 != (*err
= setupTunnelRoute(loc_inner
, rmt_inner
)))
2419 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
&&
2420 0 != (*err
= kickRacoon()))
2423 os_log_debug(log_handle
, "succeeded");
2432 (void)replacedelete
; (void)loc_inner
; (void)loc_outer6
; (void)loc_port
; (void)rmt_inner
;
2433 (void)rmt_outer6
; (void)rmt_port
; (void)id
;
2435 *err
= kHelperErr_IPsecDisabled
;
2436 #endif /* MDNS_NO_IPSEC */
2437 update_idle_timer();
2438 return KERN_SUCCESS
;