]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/helper.c
mDNSResponder-878.230.2.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / helper.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2007-2018 Apple Inc. All rights reserved.
4 *
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
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
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.
16 */
17
18 #include <sys/cdefs.h>
19 #include <arpa/inet.h>
20 #include <bsm/libbsm.h>
21 #include <net/if.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>
33 #include <ctype.h>
34 #include <dirent.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <signal.h>
38 #include <stdarg.h>
39 #include <stdbool.h>
40 #include <string.h>
41 #include <unistd.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>
47 #include <net/bpf.h>
48 #include <sys/sysctl.h>
49
50 #include "mDNSEmbeddedAPI.h"
51 #include "dns_sd.h"
52 #include "dnssd_ipc.h"
53 #include "libpfkey.h"
54 #include "helper.h"
55 #include "helper-server.h"
56 #include "P2PPacketFilter.h"
57
58 #include <netinet/ip.h>
59 #include <netinet/tcp.h>
60
61 #include <IOKit/pwr_mgt/IOPMLibPrivate.h>
62
63 #ifndef RTF_IFSCOPE
64 #define RTF_IFSCOPE 0x1000000
65 #endif
66
67 #if TARGET_OS_EMBEDDED
68 #ifndef MDNS_NO_IPSEC
69 #define MDNS_NO_IPSEC 1
70 #endif
71
72 #define NO_CFUSERNOTIFICATION 1
73 #define NO_SECURITYFRAMEWORK 1
74 #endif
75
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"
79
80 typedef struct sadb_x_policy *ipsec_policy_t;
81
82 uid_t mDNSResponderUID;
83 gid_t mDNSResponderGID;
84
85 void helper_exit()
86 {
87 os_log_info(log_handle,"mDNSResponderHelper exiting");
88 exit(0);
89 }
90
91 mDNSexport void RequestBPF()
92 {
93 DNSServiceRef ref;
94
95 DNSServiceErrorType err = ConnectToServer(&ref, 0, send_bpf, NULL, NULL, NULL);
96 if (err)
97 {
98 os_log(log_handle, "RequestBPF: ConnectToServer %d", err);
99 return;
100 }
101
102 char *ptr;
103 size_t len = sizeof(DNSServiceFlags);
104 ipc_msg_hdr *hdr = create_hdr(send_bpf, &len, &ptr, 0, ref);
105 if (!hdr)
106 {
107 os_log(log_handle, "RequestBPF: No mem to allocate");
108 DNSServiceRefDeallocate(ref);
109 return;
110 }
111
112 put_flags(0, &ptr);
113 deliver_request(hdr, ref); // Will free hdr for us
114 DNSServiceRefDeallocate(ref);
115 update_idle_timer();
116
117 os_log_info(log_handle,"RequestBPF: Successful");
118 }
119
120
121 void PowerRequest(int key, int interval, int *err)
122 {
123 *err = kHelperErr_DefaultErr;
124
125 os_log_info(log_handle,"PowerRequest: key %d interval %d, err %d", key, interval, *err);
126
127 CFArrayRef events = IOPMCopyScheduledPowerEvents();
128 if (events)
129 {
130 int i;
131 CFIndex count = CFArrayGetCount(events);
132 for (i=0; i<count; i++)
133 {
134 CFDictionaryRef dict = CFArrayGetValueAtIndex(events, i);
135 CFStringRef id = CFDictionaryGetValue(dict, CFSTR(kIOPMPowerEventAppNameKey));
136 if (CFEqual(id, CFSTR("mDNSResponderHelper")))
137 {
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");
142 if (result)
143 os_log(log_handle, "IOPMCancelScheduledPowerEvent %d failed %d", i, result);
144 }
145 }
146 CFRelease(events);
147 }
148
149 if (key < 0) // mDNSPowerRequest(-1,-1) means "clear any stale schedules" (see above)
150 {
151 *err = kHelperErr_NoErr;
152 }
153 else if (key == 0) // mDNSPowerRequest(0, 0) means "sleep now"
154 {
155 IOReturn r = IOPMSleepSystem(IOPMFindPowerManagement(MACH_PORT_NULL));
156 if (r)
157 {
158 usleep(100000);
159 os_log_info(log_handle, "IOPMSleepSystem %d", r);
160 }
161 *err = r;
162 }
163 else if (key > 0)
164 {
165 CFDateRef wakeTime = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent() + interval);
166 if (wakeTime)
167 {
168 CFMutableDictionaryRef scheduleDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
169
170 CFDictionaryAddValue(scheduleDict, CFSTR(kIOPMPowerEventTimeKey), wakeTime);
171 CFDictionaryAddValue(scheduleDict, CFSTR(kIOPMPowerEventAppNameKey), CFSTR("mDNSResponderHelper"));
172 CFDictionaryAddValue(scheduleDict, CFSTR(kIOPMPowerEventTypeKey), key ? CFSTR(kIOPMAutoWake) : CFSTR(kIOPMAutoSleep));
173
174 IOReturn r = IOPMRequestSysWake(scheduleDict);
175 if (r)
176 {
177 usleep(100000);
178 os_log_info(log_handle, "IOPMRequestSysWake(%d) %d %x", interval, r, r);
179 }
180 *err = r;
181 CFRelease(wakeTime);
182 CFRelease(scheduleDict);
183 }
184 }
185
186 update_idle_timer();
187 }
188
189 void SetLocalAddressCacheEntry(int ifindex, int family, const v6addr_t ip, const ethaddr_t eth, int *err)
190 {
191
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]
194
195 if (family == 4)
196 {
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]);
199 }
200 else
201 {
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]);
204 }
205
206 *err = kHelperErr_DefaultErr;
207
208 static int s = -1, seq = 0;
209 if (s < 0)
210 {
211 s = socket(PF_ROUTE, SOCK_RAW, 0);
212 if (s < 0)
213 os_log(log_handle, "SetLocalAddressCacheEntry: socket(PF_ROUTE, SOCK_RAW, 0) failed %d (%s)", errno, strerror(errno));
214 }
215
216 if (s >= 0)
217 {
218 struct timeval tv;
219 gettimeofday(&tv, 0);
220 if (family == 4)
221 {
222 struct { struct rt_msghdr hdr; struct sockaddr_inarp dst; struct sockaddr_dl sdl; } rtmsg;
223 memset(&rtmsg, 0, sizeof(rtmsg));
224
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;
237
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;
245
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;
253
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));
256
257 int len = write(s, (char *)&rtmsg, sizeof(rtmsg));
258 if (len < 0)
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);
265
266 *err = kHelperErr_NoErr;
267 }
268 else
269 {
270 struct { struct rt_msghdr hdr; struct sockaddr_in6 dst; struct sockaddr_dl sdl; } rtmsg;
271 memset(&rtmsg, 0, sizeof(rtmsg));
272
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;
285
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;
292
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;
300
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));
303
304 int len = write(s, (char *)&rtmsg, sizeof(rtmsg));
305 if (len < 0)
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);
312
313 *err = kHelperErr_NoErr;
314 }
315 }
316
317 update_idle_timer();
318 }
319
320
321 void UserNotify(const char *title, const char *msg)
322 {
323
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);
334 if (err)
335 os_log(log_handle, "CFUserNotificationDisplayNotice returned %d", err);
336 CFRelease(alertHeader);
337 CFRelease(alertMessage);
338 #else
339 (void)title;
340 (void)msg;
341 #endif /* NO_CFUSERNOTIFICATION */
342
343 update_idle_timer();
344 }
345
346
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
351
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;
361
362 static CFUserNotificationRef gNotification = NULL;
363 static CFRunLoopSourceRef gNotificationRLS = NULL;
364
365 static void NotificationCallBackDismissed(CFUserNotificationRef userNotification, CFOptionFlags responseFlags)
366 {
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)
371 {
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;
379 }
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"
384 usercompname[0] = 0;
385 userhostname[0] = 0;
386 lastcompname[0] = 0;
387 lasthostname[0] = 0;
388 update_idle_timer();
389 unpause_idle_timer();
390 }
391
392 static void ShowNameConflictNotification(CFMutableArrayRef header, CFStringRef subtext)
393 {
394 CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
395 if (!dictionary) return;
396
397 os_log_debug(log_handle,"entry");
398
399 CFDictionarySetValue(dictionary, kCFUserNotificationAlertHeaderKey, header);
400 CFDictionarySetValue(dictionary, kCFUserNotificationAlertMessageKey, subtext);
401
402 CFURLRef urlRef = CFURLCreateWithFileSystemPath(NULL, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle, true);
403 if (urlRef) { CFDictionarySetValue(dictionary, kCFUserNotificationLocalizationURLKey, urlRef); CFRelease(urlRef); }
404
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
408 {
409 SInt32 error;
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);
418 pause_idle_timer();
419 }
420
421 CFRelease(dictionary);
422 }
423
424 static CFMutableArrayRef CreateAlertHeader(const char* oldname, const char* newname, const CFStringRef msg, const char* suffix)
425 {
426 CFMutableArrayRef alertHeader = NULL;
427
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.
434 if (!cfoldname)
435 {
436 os_log(log_handle, "Could not construct CFStrings for old=%s", newname);
437 }
438 else if (newname && !cfnewname)
439 {
440 os_log(log_handle, "Could not construct CFStrings for new=%s", newname);
441 }
442 else
443 {
444 const CFStringRef s1 = CFStringCreateWithFormat(NULL, NULL, CFS_Format, cfoldname, suffix);
445 const CFStringRef s2 = cfnewname ? CFStringCreateWithFormat(NULL, NULL, CFS_Format, cfnewname, suffix) : NULL;
446
447 alertHeader = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
448
449 if (!s1)
450 {
451 os_log(log_handle, "Could not construct secondary CFString for old=%s", oldname);
452 }
453 else if (cfnewname && !s2)
454 {
455 os_log(log_handle, "Could not construct secondary CFString for new=%s", newname);
456 }
457 else if (!alertHeader)
458 {
459 os_log(log_handle, "Could not construct CFArray for notification");
460 }
461 else
462 {
463 // Make sure someone is logged in. We don't want this popping up over the login window
464 uid_t uid;
465 gid_t gid;
466 CFStringRef userName = SCDynamicStoreCopyConsoleUser(NULL, &uid, &gid);
467 if (userName)
468 {
469 if (!CFEqual(userName, CFSTR("_mbsetupuser")))
470 {
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. "));
474 if (s2)
475 {
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("."));
479 }
480 else
481 {
482 CFArrayAppendValue(alertHeader, CFSTR("All attempts to find an available name by adding a number to the name were also unsuccessful."));
483 }
484 }
485 CFRelease(userName);
486 }
487 }
488 if (s1) CFRelease(s1);
489 if (s2) CFRelease(s2);
490 }
491 if (cfoldname) CFRelease(cfoldname);
492 if (cfnewname) CFRelease(cfnewname);
493
494 return alertHeader;
495 }
496 #endif /* ndef NO_CFUSERNOTIFICATION */
497
498 static void update_notification(void)
499 {
500 #ifndef NO_CFUSERNOTIFICATION
501 os_log_debug(log_handle,"entry ucn=%s, uhn=%s, lcn=%s, lhn=%s", usercompname, userhostname, lastcompname, lasthostname);
502 if (!CFS_OQ)
503 {
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);
508
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);
526 }
527
528 if (!usercompname[0] && !userhostname[0])
529 {
530 if (gNotificationRLS)
531 {
532 os_log_debug(log_handle,"canceling notification %p", gNotification);
533 CFUserNotificationCancel(gNotification);
534 unpause_idle_timer();
535 }
536 }
537 else
538 {
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
542 {
543 header = CreateAlertHeader(userhostname, NULL, CFS_LocalHostName, ".local");
544 subtext = &CFS_Problem;
545 }
546 else if (usercompname[0])
547 {
548 header = CreateAlertHeader(usercompname, lastcompname, CFS_ComputerName, "");
549 subtext = &CFS_ComputerNameMsg;
550 }
551 else
552 {
553 header = CreateAlertHeader(userhostname, lasthostname, CFS_LocalHostName, ".local");
554 subtext = &CFS_LocalHostNameMsg;
555 }
556 ShowNameConflictNotification(header, *subtext);
557 CFRelease(header);
558 }
559 #endif
560 }
561
562 void PreferencesSetName(int key, const char* old, const char* new)
563 {
564 SCPreferencesRef session = NULL;
565 Boolean ok = FALSE;
566 Boolean locked = FALSE;
567 CFStringRef cfstr = NULL;
568 char* user = NULL;
569 char* last = NULL;
570 Boolean needUpdate = FALSE;
571
572 os_log_info(log_handle,"PreferencesSetName: entry %s old=%s new=%s",
573 key==kmDNSComputerName ? "ComputerName" : (key==kmDNSLocalHostName ? "LocalHostName" : "UNKNOWN"), old, new);
574
575 switch ((enum mDNSPreferencesSetNameKey)key)
576 {
577 case kmDNSComputerName:
578 user = usercompname;
579 last = lastcompname;
580 break;
581 case kmDNSLocalHostName:
582 user = userhostname;
583 last = lasthostname;
584 break;
585 default:
586 os_log(log_handle, "PreferencesSetName: unrecognized key: %d", key);
587 goto fin;
588 }
589
590 if (!last)
591 {
592 os_log(log_handle, "PreferencesSetName: no last ptr");
593 goto fin;
594 }
595
596 if (!user)
597 {
598 os_log(log_handle, "PreferencesSetName:: no user ptr");
599 goto fin;
600 }
601
602 if (0 == strncmp(old, new, MAX_DOMAIN_LABEL+1))
603 {
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))
607 {
608 last[0] = 0;
609 user[0] = 0;
610 needUpdate = TRUE;
611 }
612 goto fin;
613 }
614 else
615 {
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))
621 {
622 strncpy(last, new, MAX_DOMAIN_LABEL);
623 needUpdate = TRUE;
624 }
625 }
626
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.
630 if (!user[0])
631 {
632 strncpy(user, old, MAX_DOMAIN_LABEL);
633 needUpdate = TRUE;
634 }
635
636 if (!new[0]) // we've given up trying to construct a name that doesn't conflict
637 goto fin;
638
639 cfstr = CFStringCreateWithCString(NULL, new, kCFStringEncodingUTF8);
640
641 session = SCPreferencesCreate(NULL, CFSTR(kHelperService), NULL);
642
643 if (cfstr == NULL || session == NULL)
644 {
645 os_log(log_handle, "PreferencesSetName: SCPreferencesCreate failed");
646 goto fin;
647 }
648 if (!SCPreferencesLock(session, 0))
649 {
650 os_log(log_handle,"PreferencesSetName: lock failed");
651 goto fin;
652 }
653 locked = TRUE;
654
655 switch ((enum mDNSPreferencesSetNameKey)key)
656 {
657 case kmDNSComputerName:
658 {
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);
665 if (unused)
666 {
667 CFRelease(unused);
668 unused = NULL;
669 }
670 else
671 {
672 encoding = kCFStringEncodingUTF8;
673 }
674
675 ok = SCPreferencesSetComputerName(session, cfstr, encoding);
676 }
677 break;
678
679 case kmDNSLocalHostName:
680 ok = SCPreferencesSetLocalHostName(session, cfstr);
681 break;
682
683 default:
684 break;
685 }
686
687 if (!ok || !SCPreferencesCommitChanges(session) ||
688 !SCPreferencesApplyChanges(session))
689 {
690 os_log(log_handle, "PreferencesSetName: SCPreferences update failed");
691 goto fin;
692 }
693 os_log_info(log_handle,"PreferencesSetName: succeeded");
694
695 fin:
696 if (NULL != cfstr)
697 CFRelease(cfstr);
698 if (NULL != session)
699 {
700 if (locked)
701 SCPreferencesUnlock(session);
702 CFRelease(session);
703 }
704 update_idle_timer();
705 if (needUpdate)
706 update_notification();
707
708 }
709
710
711 enum DNSKeyFormat
712 {
713 formatNotDNSKey,
714 formatDdnsTypeItem,
715 formatDnsPrefixedServiceItem,
716 #if MDNSRESPONDER_BTMM_SUPPORT
717 formatBtmmPrefixedServiceItem
718 #endif
719 };
720
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.
725
726
727 #ifndef NO_SECURITYFRAMEWORK
728 #if MDNSRESPONDER_BTMM_SUPPORT
729 static const char btmmprefix[] = "btmmdns:";
730 #endif
731 static const char dnsprefix[] = "dns:";
732 static const char ddns[] = "ddns";
733 static const char ddnsrev[] = "sndd";
734
735 static enum DNSKeyFormat getDNSKeyFormat(SecKeychainItemRef item, SecKeychainAttributeList **attributesp)
736 {
737 static UInt32 tags[4] =
738 {
739 kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr, kSecLabelItemAttr
740 };
741 static SecKeychainAttributeInfo attributeInfo =
742 {
743 sizeof(tags)/sizeof(tags[0]), tags, NULL
744 };
745 SecKeychainAttributeList *attributes = NULL;
746 enum DNSKeyFormat format;
747 Boolean malformed = FALSE;
748 OSStatus status = noErr;
749 int i = 0;
750
751 *attributesp = NULL;
752 if (noErr != (status = SecKeychainItemCopyAttributesAndData(item, &attributeInfo, NULL, &attributes, NULL, NULL)))
753 {
754 os_log_info(log_handle,"getDNSKeyFormat: SecKeychainItemCopyAttributesAndData %d - skipping", status);
755 goto skip;
756 }
757 if (attributeInfo.count != attributes->count)
758 malformed = TRUE;
759 for (i = 0; !malformed && i < (int)attributeInfo.count; ++i)
760 if (attributeInfo.tag[i] != attributes->attr[i].tag)
761 malformed = TRUE;
762 if (malformed)
763 {
764 os_log(log_handle, "getDNSKeyFormat: malformed result from SecKeychainItemCopyAttributesAndData - skipping");
765 goto skip;
766 }
767
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);
772
773 if (attributes->attr[1].length >= MAX_ESCAPED_DOMAIN_NAME +
774 sizeof(dnsprefix)-1)
775 {
776 os_log(log_handle, "getDNSKeyFormat: kSecServiceItemAttr too long (%u) - skipping",
777 (unsigned int)attributes->attr[1].length);
778 goto skip;
779 }
780 if (attributes->attr[2].length >= MAX_ESCAPED_DOMAIN_NAME)
781 {
782 os_log(log_handle, "getDNSKeyFormat: kSecAccountItemAttr too long (%u) - skipping",
783 (unsigned int)attributes->attr[2].length);
784 goto skip;
785 }
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;
791 #endif
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;
796 else
797 {
798 os_log_info(log_handle,"getDNSKeyFormat: uninterested in this entry");
799 goto skip;
800 }
801
802 *attributesp = attributes;
803 os_log_info(log_handle,"getDNSKeyFormat: accepting this entry");
804 return format;
805
806 skip:
807 SecKeychainItemFreeAttributesAndData(attributes, NULL);
808 return formatNotDNSKey;
809 }
810
811 // Insert the attributes as defined by mDNSKeyChainAttributes
812 static CFPropertyListRef copyKeychainItemInfo(SecKeychainItemRef item, SecKeychainAttributeList *attributes, enum DNSKeyFormat format)
813 {
814 CFMutableArrayRef entry = NULL;
815 CFDataRef data = NULL;
816 OSStatus status = noErr;
817 UInt32 keylen = 0;
818 void *keyp = 0;
819
820 if (NULL == (entry = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)))
821 {
822 os_log(log_handle, "copyKeychainItemInfo: CFArrayCreateMutable failed");
823 goto error;
824 }
825
826 // Insert the Account attribute (kmDNSKcWhere)
827 switch ((enum DNSKeyFormat)format)
828 {
829 case formatDdnsTypeItem:
830 data = CFDataCreate(kCFAllocatorDefault, attributes->attr[1].data, attributes->attr[1].length);
831 break;
832 case formatDnsPrefixedServiceItem:
833 #if MDNSRESPONDER_BTMM_SUPPORT
834 case formatBtmmPrefixedServiceItem:
835 #endif
836 data = CFDataCreate(kCFAllocatorDefault, attributes->attr[1].data, attributes->attr[1].length);
837 break;
838 default:
839 os_log(log_handle, "copyKeychainItemInfo: unknown DNSKeyFormat value");
840 break;
841 }
842 if (NULL == data)
843 {
844 os_log(log_handle, "copyKeychainItemInfo: CFDataCreate for attr[1] failed");
845 goto error;
846 }
847 CFArrayAppendValue(entry, data);
848 CFRelease(data);
849
850 // Insert the Where attribute (kmDNSKcAccount)
851 if (NULL == (data = CFDataCreate(kCFAllocatorDefault, attributes->attr[2].data, attributes->attr[2].length)))
852 {
853 os_log(log_handle, "copyKeychainItemInfo: CFDataCreate for attr[2] failed");
854 goto error;
855 }
856
857 CFArrayAppendValue(entry, data);
858 CFRelease(data);
859
860 // Insert the Key attribute (kmDNSKcKey)
861 if (noErr != (status = SecKeychainItemCopyAttributesAndData(item, NULL, NULL, NULL, &keylen, &keyp)))
862 {
863 os_log(log_handle, "copyKeychainItemInfo: could not retrieve key for \"%.*s\": %d",
864 (int)attributes->attr[1].length, attributes->attr[1].data, status);
865 goto error;
866 }
867
868 data = CFDataCreate(kCFAllocatorDefault, keyp, keylen);
869 SecKeychainItemFreeAttributesAndData(NULL, keyp);
870 if (NULL == data)
871 {
872 os_log(log_handle, "copyKeychainItemInfo: CFDataCreate for keyp failed");
873 goto error;
874 }
875 CFArrayAppendValue(entry, data);
876 CFRelease(data);
877
878 // Insert the Name attribute (kmDNSKcName)
879 if (NULL == (data = CFDataCreate(kCFAllocatorDefault, attributes->attr[3].data, attributes->attr[3].length)))
880 {
881 os_log(log_handle, "copyKeychainItemInfo: CFDataCreate for attr[3] failed");
882 goto error;
883 }
884
885 CFArrayAppendValue(entry, data);
886 CFRelease(data);
887 return entry;
888
889 error:
890 if (NULL != entry)
891 CFRelease(entry);
892 return NULL;
893 }
894 #endif
895
896 void KeychainGetSecrets(__unused unsigned int *numsecrets,__unused unsigned long *secrets, __unused unsigned int *secretsCnt, __unused int *err)
897 {
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;
908 OSStatus status = 0;
909
910 os_log_info(log_handle,"KeychainGetSecrets: entry");
911 *err = kHelperErr_NoErr;
912 *numsecrets = 0;
913 *secrets = (vm_offset_t)NULL;
914
915 if (NULL == (keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)))
916 {
917 os_log(log_handle, "KeychainGetSecrets: CFArrayCreateMutable failed");
918 *err = kHelperErr_ApiErr;
919 goto fin;
920 }
921 if (noErr != (status = SecKeychainCopyDefault(&skc)))
922 {
923 *err = kHelperErr_ApiErr;
924 goto fin;
925 }
926 #pragma clang diagnostic push
927 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
928 if (noErr != (status = SecKeychainSearchCreateFromAttributes(skc, kSecGenericPasswordItemClass, NULL, &search)))
929 {
930 *err = kHelperErr_ApiErr;
931 goto fin;
932 }
933 for (status = SecKeychainSearchCopyNext(search, &item); noErr == status; status = SecKeychainSearchCopyNext(search, &item))
934 {
935 if (formatNotDNSKey != (format = getDNSKeyFormat(item, &attributes)) &&
936 NULL != (entry = copyKeychainItemInfo(item, attributes, format)))
937 {
938 CFArrayAppendValue(keys, entry);
939 CFRelease(entry);
940 }
941 SecKeychainItemFreeAttributesAndData(attributes, NULL);
942 CFRelease(item);
943 }
944 #pragma clang diagnostic pop
945 if (errSecItemNotFound != status)
946 os_log(log_handle, "KeychainGetSecrets: SecKeychainSearchCopyNext failed: %d", status);
947
948 if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorDefault, kCFAllocatorDefault)))
949 {
950 *err = kHelperErr_ApiErr;
951 os_log(log_handle, "KeychainGetSecrets:CFWriteStreamCreateWithAllocatedBuffers failed");
952 goto fin;
953 }
954
955 CFWriteStreamOpen(stream);
956 if (0 == CFPropertyListWrite(keys, stream, kCFPropertyListBinaryFormat_v1_0, 0, NULL))
957 {
958 *err = kHelperErr_ApiErr;
959 os_log(log_handle, "KeychainGetSecrets:CFPropertyListWriteToStream failed");
960 goto fin;
961 }
962 result = CFWriteStreamCopyProperty(stream, kCFStreamPropertyDataWritten);
963
964 if (KERN_SUCCESS != vm_allocate(mach_task_self(), secrets, CFDataGetLength(result), VM_FLAGS_ANYWHERE))
965 {
966 *err = kHelperErr_ApiErr;
967 os_log(log_handle, "KeychainGetSecrets: vm_allocate failed");
968 goto fin;
969 }
970
971 CFDataGetBytes(result, CFRangeMake(0, CFDataGetLength(result)), (void *)*secrets);
972 *secretsCnt = CFDataGetLength(result);
973 *numsecrets = CFArrayGetCount(keys);
974
975 os_log_info(log_handle,"KeychainGetSecrets: succeeded");
976
977 fin:
978 os_log_info(log_handle,"KeychainGetSecrets: returning numsecrets[%u] secrets[%lu] secrets addr[%p] secretscount[%u]",
979 *numsecrets, *secrets, secrets, *secretsCnt);
980
981 if (NULL != stream)
982 {
983 CFWriteStreamClose(stream);
984 CFRelease(stream);
985 }
986 if (NULL != result)
987 CFRelease(result);
988 if (NULL != keys)
989 CFRelease(keys);
990 if (NULL != search)
991 CFRelease(search);
992 if (NULL != skc)
993 CFRelease(skc);
994 update_idle_timer();
995
996 *err = KERN_SUCCESS;
997
998 #else
999
1000 *err = KERN_FAILURE;
1001
1002 #endif
1003
1004 }
1005
1006
1007 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
1008 CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
1009
1010
1011 void SendWakeupPacket(unsigned int ifid, const char *eth_addr, const char *ip_addr, int iteration)
1012 {
1013 int bpf_fd, i, j;
1014 struct ifreq ifr;
1015 char ifname[IFNAMSIZ];
1016 char packet[512];
1017 char *ptr = packet;
1018 char bpf_device[12];
1019 struct ether_addr *ea;
1020 // (void) ip_addr; // unused
1021 // (void) iteration; // unused
1022
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);
1025
1026 if (if_indextoname(ifid, ifname) == NULL)
1027 {
1028 os_log(log_handle, "SendWakeupPacket: invalid interface index %u", ifid);
1029 return;
1030 }
1031
1032 ea = ether_aton(eth_addr);
1033 if (ea == NULL)
1034 {
1035 os_log(log_handle, "SendWakeupPacket: invalid ethernet address %s", eth_addr);
1036 return;
1037 }
1038
1039 for (i = 0; i < 100; i++)
1040 {
1041 snprintf(bpf_device, sizeof(bpf_device), "/dev/bpf%d", i);
1042 bpf_fd = open(bpf_device, O_RDWR, 0);
1043
1044 if (bpf_fd == -1)
1045 continue;
1046 else
1047 break;
1048 }
1049
1050 if (bpf_fd == -1)
1051 {
1052 os_log(log_handle, "SendWakeupPacket: cannot find a bpf device");
1053 return;
1054 }
1055
1056 memset(&ifr, 0, sizeof(ifr));
1057 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1058
1059 if (ioctl(bpf_fd, BIOCSETIF, (char *)&ifr) < 0)
1060 {
1061 os_log(log_handle, "SendWakeupPacket: BIOCSETIF failed %s", strerror(errno));
1062 return;
1063 }
1064
1065 // 0x00 Destination address
1066 for (i=0; i<6; i++)
1067 *ptr++ = ea->octet[i];
1068
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)
1071 for (i=0; i<6; i++)
1072 *ptr++ = 0;
1073
1074 // 0x0C Ethertype (0x0842)
1075 *ptr++ = 0x08;
1076 *ptr++ = 0x42;
1077
1078 // 0x0E Wakeup sync sequence
1079 for (i=0; i<6; i++)
1080 *ptr++ = 0xFF;
1081
1082 // 0x14 Wakeup data
1083 for (j=0; j<16; j++)
1084 for (i=0; i<6; i++)
1085 *ptr++ = ea->octet[i];
1086
1087 // 0x74 Password
1088 for (i=0; i<6; i++)
1089 *ptr++ = 0;
1090
1091 if (write(bpf_fd, packet, ptr - packet) < 0)
1092 {
1093 os_log(log_handle, "SendWakeupPacket: write failed %s", strerror(errno));
1094 return;
1095 }
1096 os_log(log_handle, "SendWakeupPacket: sent unicast eth_addr %s, ip_addr %s", eth_addr, ip_addr);
1097
1098 // Send a broadcast one to handle ethernet switches that don't flood forward packets with
1099 // unknown mac addresses.
1100 for (i=0; i<6; i++)
1101 packet[i] = 0xFF;
1102
1103 if (write(bpf_fd, packet, ptr - packet) < 0)
1104 {
1105 os_log(log_handle, "SendWakeupPacket: write failed %s", strerror(errno));
1106 return;
1107 }
1108 os_log(log_handle, "SendWakeupPacket: sent broadcast eth_addr %s, ip_addr %s", eth_addr, ip_addr);
1109
1110 close(bpf_fd);
1111
1112 }
1113
1114
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)
1117 {
1118 int error;
1119
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]);
1123
1124 switch (command)
1125 {
1126 case PF_SET_RULES:
1127 error = P2PPacketFilterAddBonjourRuleSet(ifname, count, portArray, protocolArray);
1128 if (error)
1129 os_log(log_handle, "P2PPacketFilterAddBonjourRuleSet failed %s", strerror(error));
1130 break;
1131
1132 case PF_CLEAR_RULES:
1133 error = P2PPacketFilterClearBonjourRules();
1134 if (error)
1135 os_log(log_handle, "P2PPacketFilterClearBonjourRules failed %s", strerror(error));
1136 break;
1137
1138 default:
1139 os_log(log_handle, "PacketFilterControl: invalid command %d", command);
1140 break;
1141 }
1142
1143 }
1144
1145 static unsigned long in_cksum(unsigned short *ptr, int nbytes)
1146 {
1147 unsigned long sum;
1148 u_short oddbyte;
1149
1150 /*
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.
1154 */
1155 sum = 0;
1156 while (nbytes > 1)
1157 {
1158 sum += *ptr++;
1159 nbytes -= 2;
1160 }
1161
1162 /* mop up an odd byte, if necessary */
1163 if (nbytes == 1)
1164 {
1165 /* make sure top half is zero */
1166 oddbyte = 0;
1167
1168 /* one byte only */
1169 *((u_char *)&oddbyte) = *(u_char *)ptr;
1170 sum += oddbyte;
1171 }
1172 /* Add back carry outs from top 16 bits to low 16 bits. */
1173 sum = (sum >> 16) + (sum & 0xffff);
1174
1175 /* add carry */
1176 sum += (sum >> 16);
1177
1178 return sum;
1179 }
1180
1181 static unsigned short InetChecksum(unsigned short *ptr, int nbytes)
1182 {
1183 unsigned long sum;
1184
1185 sum = in_cksum(ptr, nbytes);
1186 return (unsigned short)~sum;
1187 }
1188
1189 static void TCPCheckSum(int af, struct tcphdr *t, int tcplen, const v6addr_t sadd6, const v6addr_t dadd6)
1190 {
1191 unsigned long sum = 0;
1192 unsigned short *ptr;
1193
1194 /* TCP header checksum */
1195 sum = in_cksum((unsigned short *)t, tcplen);
1196
1197 if (af == AF_INET)
1198 {
1199 /* Pseudo header */
1200 ptr = (unsigned short *)sadd6;
1201 sum += *ptr++;
1202 sum += *ptr++;
1203 ptr = (unsigned short *)dadd6;
1204 sum += *ptr++;
1205 sum += *ptr++;
1206 }
1207 else if (af == AF_INET6)
1208 {
1209 /* Pseudo header */
1210 ptr = (unsigned short *)sadd6;
1211 sum += *ptr++;
1212 sum += *ptr++;
1213 sum += *ptr++;
1214 sum += *ptr++;
1215 sum += *ptr++;
1216 sum += *ptr++;
1217 sum += *ptr++;
1218 sum += *ptr++;
1219 ptr = (unsigned short *)dadd6;
1220 sum += *ptr++;
1221 sum += *ptr++;
1222 sum += *ptr++;
1223 sum += *ptr++;
1224 sum += *ptr++;
1225 sum += *ptr++;
1226 sum += *ptr++;
1227 sum += *ptr++;
1228 }
1229
1230 sum += htons(tcplen);
1231 sum += htons(IPPROTO_TCP);
1232
1233 while (sum >> 16)
1234 sum = (sum >> 16) + (sum & 0xFFFF);
1235
1236 t->th_sum = ~sum;
1237
1238 }
1239
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)
1241 {
1242
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]
1246
1247 os_log_info(log_handle, "SendKeepalive: "IPv6FMTSTRING" :space: "IPv6FMTSTRING"",
1248 IPv6FMTSARGS, IPv6FMTDARGS);
1249
1250 struct packet4
1251 {
1252 struct ip ip;
1253 struct tcphdr tcp;
1254 } packet4;
1255 struct packet6
1256 {
1257 struct tcphdr tcp;
1258 } packet6;
1259 int sock, on;
1260 struct tcphdr *t;
1261 int af;
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;
1265 void *packet;
1266 ssize_t packetlen;
1267 char ctlbuf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
1268 struct msghdr msghdr;
1269 struct iovec iov;
1270 ssize_t len;
1271
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);
1274
1275 char buf1[INET6_ADDRSTRLEN];
1276 char buf2[INET6_ADDRSTRLEN];
1277
1278 buf1[0] = 0;
1279 buf2[0] = 0;
1280
1281 inet_ntop(AF_INET6, sadd6, buf1, sizeof(buf1));
1282 inet_ntop(AF_INET6, dadd6, buf2, sizeof(buf2));
1283
1284 os_log_info(log_handle,"SendKeepalive invoked: sadd6 is %s, dadd6 is %s", buf1, buf2);
1285
1286 // all the incoming arguments are in network order
1287 if ((*(unsigned *)(sadd6 +4) == 0) && (*(unsigned *)(sadd6 + 8) == 0) && (*(unsigned *)(sadd6 + 12) == 0))
1288 {
1289 af = AF_INET;
1290 memset(&packet4, 0, sizeof (packet4));
1291
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);
1304
1305 /* IP header checksum */
1306 packet4.ip.ip_sum = InetChecksum((unsigned short *)&packet4.ip, 20);
1307 t = &packet4.tcp;
1308 packet = &packet4;
1309 packetlen = 40; // sum of IPv4 header len(20) and TCP header len(20)
1310 }
1311 else
1312 {
1313 af = AF_INET6;
1314 memset(&packet6, 0, sizeof (packet6));
1315 t = &packet6.tcp;
1316 packet = &packet6;
1317 // We don't send IPv6 header, hence just the TCP header len (20)
1318 packetlen = 20;
1319 }
1320
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;
1328 t->th_win = win;
1329 t->th_sum = 0; /* 16-bit checksum (below) */
1330 t->th_urp = 0; /* 16-bit urgent offset */
1331
1332 TCPCheckSum(af, t, 20, sadd6, dadd6);
1333
1334 /* Open up a RAW socket */
1335 if ((sock = socket(af, SOCK_RAW, IPPROTO_TCP)) < 0)
1336 {
1337 os_log(log_handle, "SendKeepalive: socket %s", strerror(errno));
1338 return;
1339 }
1340
1341 if (af == AF_INET)
1342 {
1343 on = 1;
1344 if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &on, sizeof (on)))
1345 {
1346 close(sock);
1347 os_log(log_handle, "SendKeepalive: setsockopt %s", strerror(errno));
1348 return;
1349 }
1350
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;
1356
1357 msghdr.msg_control = NULL;
1358 msghdr.msg_controllen = 0;
1359
1360 }
1361 else
1362 {
1363 struct cmsghdr *ctl;
1364
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));
1369
1370 sin6_to->sin6_port = rport;
1371 sin6_to->sin6_flowinfo = 0;
1372
1373
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;
1383 }
1384
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;
1392
1393 again:
1394 len = sendmsg(sock, &msghdr, 0);
1395 if (len == -1)
1396 {
1397 if (errno == EINTR)
1398 goto again;
1399 }
1400
1401 if (len != packetlen)
1402 {
1403 os_log(log_handle, "SendKeepalive: sendmsg failed %s", strerror(errno));
1404 }
1405 else
1406 {
1407 char source[INET6_ADDRSTRLEN], dest[INET6_ADDRSTRLEN];
1408
1409 inet_ntop(af, (void *)sadd6, source, sizeof(source));
1410 inet_ntop(af, (void *)dadd6, dest, sizeof(dest));
1411
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));
1414
1415 }
1416 close(sock);
1417
1418 }
1419
1420
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)
1422 {
1423
1424 struct tcp_info ti;
1425 struct info_tuple itpl;
1426 int mib[4];
1427 unsigned int miblen;
1428 size_t len;
1429 size_t sz;
1430
1431 memset(&itpl, 0, sizeof(struct info_tuple));
1432 memset(&ti, 0, sizeof(struct tcp_info));
1433
1434 char buf1[INET6_ADDRSTRLEN];
1435 char buf2[INET6_ADDRSTRLEN];
1436
1437 buf1[0] = 0;
1438 buf2[0] = 0;
1439
1440 inet_ntop(AF_INET6, laddr, buf1, sizeof(buf1));
1441 inet_ntop(AF_INET6, raddr, buf2, sizeof(buf2));
1442
1443 os_log_info(log_handle, "RetrieveTCPInfo invoked: laddr is %s, raddr is %s", buf1, buf2);
1444
1445 os_log_info(log_handle,"RetrieveTCPInfo invoked: lport is[%d] rport is[%d] family is [%d]",
1446 lport, rport, family);
1447
1448 if (family == AF_INET)
1449 {
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;
1456 }
1457 else
1458 {
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;
1465 }
1466 itpl.itpl_proto = IPPROTO_TCP;
1467 sz = sizeof(mib)/sizeof(mib[0]);
1468 if (sysctlnametomib("net.inet.tcp.info", mib, &sz) == -1)
1469 {
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;
1473 }
1474 miblen = (unsigned int)sz;
1475 len = sizeof(struct tcp_info);
1476 if (sysctl(mib, miblen, &ti, &len, &itpl, sizeof(struct info_tuple)) == -1)
1477 {
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;
1481 }
1482
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;
1488
1489 }
1490
1491 #ifndef MDNS_NO_IPSEC
1492
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/";
1496
1497 static int MacOSXSystemBuildNumber(char* letter_out, int* minor_out)
1498 {
1499 int major = 0, minor = 0;
1500 char letter = 0, buildver[256]="<Unknown>";
1501 CFDictionaryRef vers = _CFCopySystemVersionDictionary();
1502 if (vers)
1503 {
1504 CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
1505 if (cfbuildver) CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8);
1506 sscanf(buildver, "%d%c%d", &major, &letter, &minor);
1507 CFRelease(vers);
1508 }
1509 else
1510 os_log_info(log_handle, "_CFCopySystemVersionDictionary failed");
1511
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;
1515 return(major);
1516 }
1517
1518 static int UseOldRacoon()
1519 {
1520 static int g_oldRacoon = -1;
1521
1522 if (g_oldRacoon == -1)
1523 {
1524 char letter = 0;
1525 int minor = 0;
1526 g_oldRacoon = (MacOSXSystemBuildNumber(&letter, &minor) < 10);
1527 os_log_debug(log_handle, "%s", g_oldRacoon ? "old" : "new");
1528 }
1529
1530 return g_oldRacoon;
1531 }
1532
1533 static int RacoonSignal()
1534 {
1535 return UseOldRacoon() ? SIGHUP : SIGUSR1;
1536 }
1537
1538 static int notifyRacoon(void)
1539 {
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 */
1543 char *p = NULL;
1544 ssize_t n = 0;
1545 unsigned long m = 0;
1546 int fd = open(racoon_pid_path, O_RDONLY);
1547
1548 if (0 > fd)
1549 {
1550 os_log_debug(log_handle,"open \"%s\" failed, and that's OK: %s", racoon_pid_path,
1551 strerror(errno));
1552 return kHelperErr_RacoonNotificationFailed;
1553 }
1554 n = read(fd, buf, sizeof(buf)-1);
1555 close(fd);
1556 if (1 > n)
1557 {
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;
1561 }
1562 buf[n] = '\0';
1563 m = strtoul(buf, &p, 10);
1564 if (*p != '\0' && !isspace(*p))
1565 {
1566 os_log_debug(log_handle,"invalid PID \"%s\" (around '%c')", buf, *p);
1567 return kHelperErr_RacoonNotificationFailed;
1568 }
1569 if (2 > m)
1570 {
1571 os_log_debug(log_handle,"refusing to kill PID %lu", m);
1572 return kHelperErr_RacoonNotificationFailed;
1573 }
1574 if (0 != kill(m, RacoonSignal()))
1575 {
1576 os_log_debug(log_handle,"Could not signal racoon (%lu): %s", m, strerror(errno));
1577 return kHelperErr_RacoonNotificationFailed;
1578 }
1579
1580 os_log_debug(log_handle, "Sent racoon (%lu) signal %d", m, RacoonSignal());
1581 return 0;
1582 }
1583
1584 static const char* GetRacoonConfigDir()
1585 {
1586 return UseOldRacoon() ? g_racoon_config_dir_old : g_racoon_config_dir;
1587 }
1588 /*
1589 static const char* GetOldRacoonConfigDir()
1590 {
1591 return UseOldRacoon() ? NULL : g_racoon_config_dir_old;
1592 }
1593 */
1594
1595 static void closefds(int from)
1596 {
1597 int fd = 0;
1598 struct dirent entry, *entryp = NULL;
1599 DIR *dirp = opendir("/dev/fd");
1600
1601 if (dirp == NULL)
1602 {
1603 /* fall back to the erroneous getdtablesize method */
1604 for (fd = from; fd < getdtablesize(); ++fd)
1605 close(fd);
1606 return;
1607 }
1608 while (0 == readdir_r(dirp, &entry, &entryp) && NULL != entryp)
1609 {
1610 fd = atoi(entryp->d_name);
1611 if (fd >= from && fd != dirfd(dirp))
1612 close(fd);
1613 }
1614 closedir(dirp);
1615 }
1616
1617
1618 static int startRacoonOld(void)
1619 {
1620 os_log_debug(log_handle,"entry");
1621 char * const racoon_args[] = { "/usr/sbin/racoon", "-e", NULL };
1622 ssize_t n = 0;
1623 pid_t pid = 0;
1624 int status = 0;
1625
1626 if (0 == (pid = fork()))
1627 {
1628 closefds(0);
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));
1632 exit(2);
1633 }
1634 os_log_info(log_handle,"racoon (pid=%lu) started",
1635 (unsigned long)pid);
1636 n = waitpid(pid, &status, 0);
1637 if (-1 == n)
1638 {
1639 os_log(log_handle, "Unexpected waitpid failure: %s",
1640 strerror(errno));
1641 return kHelperErr_RacoonStartFailed;
1642 }
1643 else if (pid != n)
1644 {
1645 os_log(log_handle, "Unexpected waitpid return value %d", (int)n);
1646 return kHelperErr_RacoonStartFailed;
1647 }
1648 else if (WIFSIGNALED(status))
1649 {
1650 os_log(log_handle,
1651 "racoon (pid=%lu) terminated due to signal %d",
1652 (unsigned long)pid, WTERMSIG(status));
1653 return kHelperErr_RacoonStartFailed;
1654 }
1655 else if (WIFSTOPPED(status))
1656 {
1657 os_log(log_handle,
1658 "racoon (pid=%lu) has stopped due to signal %d",
1659 (unsigned long)pid, WSTOPSIG(status));
1660 return kHelperErr_RacoonStartFailed;
1661 }
1662 else if (0 != WEXITSTATUS(status))
1663 {
1664 os_log(log_handle,
1665 "racoon (pid=%lu) exited with status %d",
1666 (unsigned long)pid, WEXITSTATUS(status));
1667 return kHelperErr_RacoonStartFailed;
1668 }
1669 os_log_debug(log_handle, "racoon (pid=%lu) daemonized normally", (unsigned long)pid);
1670 return 0;
1671 }
1672
1673 // constant and structure for the racoon control socket
1674 #define VPNCTL_CMD_PING 0x0004
1675 typedef struct vpnctl_hdr_struct
1676 {
1677 u_int16_t msg_type;
1678 u_int16_t flags;
1679 u_int32_t cookie;
1680 u_int32_t reserved;
1681 u_int16_t result;
1682 u_int16_t len;
1683 } vpnctl_hdr;
1684
1685 static int startRacoon(void)
1686 {
1687 os_log_debug(log_handle,"entry");
1688 int fd = socket(PF_UNIX, SOCK_STREAM, 0);
1689 if (0 > fd)
1690 {
1691 os_log(log_handle,"Could not create endpoint for racoon control socket: %d %s",
1692 errno, strerror(errno));
1693 return kHelperErr_RacoonStartFailed;
1694 }
1695
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);
1703 if (0 > result)
1704 {
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;
1708 }
1709
1710 u_int32_t btmm_cookie = 0x4d4d5442;
1711 vpnctl_hdr h = { htons(VPNCTL_CMD_PING), 0, btmm_cookie, 0, 0, 0 };
1712 size_t bytes = 0;
1713 ssize_t ret = 0;
1714
1715 while (bytes < sizeof(vpnctl_hdr))
1716 {
1717 ret = write(fd, ((unsigned char*)&h)+bytes, sizeof(vpnctl_hdr) - bytes);
1718 if (ret == -1)
1719 {
1720 os_log(log_handle, "Could not write to racoon control socket: %d %s", errno, strerror(errno));
1721 return kHelperErr_RacoonStartFailed;
1722 }
1723 bytes += ret;
1724 }
1725
1726 int nfds = fd + 1;
1727 fd_set fds;
1728 int counter = 0;
1729 struct timeval tv;
1730 bytes = 0;
1731 h.cookie = 0;
1732
1733 for (counter = 0; counter < 100; counter++)
1734 {
1735 FD_ZERO(&fds);
1736 FD_SET(fd, &fds);
1737 tv = (struct timeval){ 0, 10000 }; // 10 milliseconds * 100 iterations = 1 second max wait time
1738
1739 result = select(nfds, &fds, (fd_set*)NULL, (fd_set*)NULL, &tv);
1740 if (result > 0)
1741 {
1742 if (FD_ISSET(fd, &fds))
1743 {
1744 ret = read(fd, ((unsigned char*)&h)+bytes, sizeof(vpnctl_hdr) - bytes);
1745
1746 if (ret == -1)
1747 {
1748 os_log(log_handle,"Could not read from racoon control socket: %d %s", errno, strerror(errno));
1749 break;
1750 }
1751 bytes += ret;
1752 if (bytes >= sizeof(vpnctl_hdr)) break;
1753 }
1754 else
1755 {
1756 os_log_debug(log_handle, "select returned but fd_isset not on expected fd");
1757 }
1758 }
1759 else if (result < 0)
1760 {
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;
1764 }
1765 }
1766
1767 close(fd);
1768
1769 if (bytes < sizeof(vpnctl_hdr) || h.cookie != btmm_cookie)
1770 return kHelperErr_RacoonStartFailed;
1771
1772 os_log_debug(log_handle, "racoon started");
1773 return 0;
1774 }
1775
1776 static int kickRacoon(void)
1777 {
1778 if ( 0 == notifyRacoon() )
1779 return 0;
1780 return UseOldRacoon() ? startRacoonOld() : startRacoon();
1781 }
1782
1783 typedef enum _mDNSTunnelPolicyWhich
1784 {
1785 kmDNSTunnelPolicySetup,
1786 kmDNSTunnelPolicyTeardown,
1787 kmDNSTunnelPolicyGenerate
1788 } mDNSTunnelPolicyWhich;
1789
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
1793 {
1794 kmDNSNoTunnel,
1795 kmDNSIPv6IPv4Tunnel,
1796 kmDNSIPv6IPv6Tunnel
1797 } mDNSTunnelType;
1798
1799 static const uint8_t kWholeV6Mask = 128;
1800
1801 static unsigned int routeSeq = 1;
1802
1803 static int setupTunnelRoute(const v6addr_t local, const v6addr_t remote)
1804 {
1805 struct
1806 {
1807 struct rt_msghdr hdr;
1808 struct sockaddr_in6 dst;
1809 struct sockaddr_in6 gtwy;
1810 } msg;
1811 int err = 0;
1812 int s = -1;
1813
1814 if (0 > (s = socket(PF_ROUTE, SOCK_RAW, AF_INET)))
1815 {
1816 os_log(log_handle,"socket(PF_ROUTE, ...) failed: %s", strerror(errno));
1817
1818 err = kHelperErr_RoutingSocketCreationFailed;
1819 goto fin;
1820 }
1821
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;
1832
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));
1836
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));
1840
1841 /* send message, ignore error when route already exists */
1842 if (0 > write(s, &msg, msg.hdr.rtm_msglen))
1843 {
1844 const int errno_ = errno;
1845
1846 os_log_info(log_handle,"write to routing socket failed: %s", strerror(errno_));
1847 if (EEXIST != errno_)
1848 {
1849 err = kHelperErr_RouteAdditionFailed;
1850 goto fin;
1851 }
1852 }
1853
1854 fin:
1855 if (0 <= s)
1856 close(s);
1857 return err;
1858 }
1859
1860 static int teardownTunnelRoute(const v6addr_t remote)
1861 {
1862 struct
1863 {
1864 struct rt_msghdr hdr;
1865 struct sockaddr_in6 dst;
1866 } msg;
1867 int err = 0;
1868 int s = -1;
1869
1870 if (0 > (s = socket(PF_ROUTE, SOCK_RAW, AF_INET)))
1871 {
1872 os_log(log_handle, "socket(PF_ROUTE, ...) failed: %s", strerror(errno));
1873 err = kHelperErr_RoutingSocketCreationFailed;
1874 goto fin;
1875 }
1876 memset(&msg, 0, sizeof(msg));
1877
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;
1883
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))
1888 {
1889 const int errno_ = errno;
1890
1891 os_log_debug(log_handle,"write to routing socket failed: %s", strerror(errno_));
1892
1893 if (ESRCH != errno_)
1894 {
1895 err = kHelperErr_RouteDeletionFailed;
1896 goto fin;
1897 }
1898 }
1899
1900 fin:
1901 if (0 <= s)
1902 close(s);
1903 return err;
1904 }
1905
1906 static int v4addr_to_string(v4addr_t addr, char *buf, size_t buflen)
1907 {
1908 if (NULL == inet_ntop(AF_INET, addr, buf, buflen))
1909 {
1910 os_log(log_handle, "v4addr_to_string() inet_ntop failed: %s", strerror(errno));
1911 return kHelperErr_InvalidNetworkAddress;
1912 }
1913 else
1914 {
1915 return 0;
1916 }
1917 }
1918
1919 static int v6addr_to_string(const v6addr_t addr, char *buf, size_t buflen)
1920 {
1921 if (NULL == inet_ntop(AF_INET6, addr, buf, buflen))
1922 {
1923 os_log(log_handle, "v6addr_to_string inet_ntop failed: %s", strerror(errno));
1924 return kHelperErr_InvalidNetworkAddress;
1925 }
1926 else
1927 {
1928 return 0;
1929 }
1930 }
1931
1932 static int ensureExistenceOfRacoonConfigDir(const char* const racoon_config_dir)
1933 {
1934 struct stat s;
1935 int ret = stat(racoon_config_dir, &s);
1936 if (ret != 0)
1937 {
1938 if (errno != ENOENT)
1939 {
1940 os_log(log_handle, "stat of \"%s\" failed (%d): %s",
1941 racoon_config_dir, ret, strerror(errno));
1942 return -1;
1943 }
1944 else
1945 {
1946 ret = mkdir(racoon_config_dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
1947 if (ret != 0)
1948 {
1949 os_log(log_handle, "mkdir \"%s\" failed: %s",
1950 racoon_config_dir, strerror(errno));
1951 return -1;
1952 }
1953 else
1954 {
1955 os_log_info(log_handle, "created directory \"%s\"", racoon_config_dir);
1956 }
1957 }
1958 }
1959 else if (!(s.st_mode & S_IFDIR))
1960 {
1961 os_log(log_handle, "\"%s\" is not a directory!",
1962 racoon_config_dir);
1963 return -1;
1964 }
1965
1966 return 0;
1967 }
1968
1969
1970
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)
1977 {
1978 char srcs[INET_ADDRSTRLEN], dsts[INET_ADDRSTRLEN];
1979 char srcs6[INET6_ADDRSTRLEN], dsts6[INET6_ADDRSTRLEN];
1980 char buf[512];
1981 char *inOut = in ? "in" : "out";
1982 ssize_t n = 0;
1983 int err = 0;
1984
1985 *policy = NULL;
1986 *len = 0;
1987
1988 switch (which)
1989 {
1990 case kmDNSTunnelPolicySetup:
1991 if (type == kmDNSIPv6IPv4Tunnel)
1992 {
1993 if (0 != (err = v4addr_to_string(src, srcs, sizeof(srcs))))
1994 goto fin;
1995 if (0 != (err = v4addr_to_string(dst, dsts, sizeof(dsts))))
1996 goto fin;
1997 n = snprintf(buf, sizeof(buf),
1998 "%s ipsec esp/tunnel/%s[%u]-%s[%u]/require",
1999 inOut, srcs, src_port, dsts, dst_port);
2000 }
2001 else if (type == kmDNSIPv6IPv6Tunnel)
2002 {
2003 if (0 != (err = v6addr_to_string(src6, srcs6, sizeof(srcs6))))
2004 goto fin;
2005 if (0 != (err = v6addr_to_string(dst6, dsts6, sizeof(dsts6))))
2006 goto fin;
2007 n = snprintf(buf, sizeof(buf),
2008 "%s ipsec esp/tunnel/%s-%s/require",
2009 inOut, srcs6, dsts6);
2010 }
2011 break;
2012 case kmDNSTunnelPolicyTeardown:
2013 n = strlcpy(buf, inOut, sizeof(buf));
2014 break;
2015 case kmDNSTunnelPolicyGenerate:
2016 n = snprintf(buf, sizeof(buf), "%s generate", inOut);
2017 break;
2018 default:
2019 err = kHelperErr_IPsecPolicyCreationFailed;
2020 goto fin;
2021 }
2022
2023 if (n >= (int)sizeof(buf))
2024 {
2025 err = kHelperErr_ResultTooLarge;
2026 goto fin;
2027 }
2028
2029 os_log_info(log_handle, "policy=\"%s\"", buf);
2030
2031 if (NULL == (*policy = (ipsec_policy_t)ipsec_set_policy(buf, n)))
2032 {
2033 os_log_info(log_handle, "Could not create IPsec policy from \"%s\"", buf);
2034 err = kHelperErr_IPsecPolicyCreationFailed;
2035 goto fin;
2036 }
2037 *len = ((ipsec_policy_t)(*policy))->sadb_x_policy_len * 8;
2038
2039 fin:
2040 return err;
2041 }
2042
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)
2047 {
2048 static unsigned int policySeq = 0;
2049 int err = 0;
2050
2051 os_log_debug(log_handle, "entry, setup=%d", setup);
2052
2053 if (setup)
2054 err = pfkey_send_spdadd(s, src, src_bits, dst, dst_bits, -1,
2055 (char *)policy, len, policySeq++);
2056 else
2057 err = pfkey_send_spddelete(s, src, src_bits, dst, dst_bits, -1,
2058 (char *)policy, len, policySeq++);
2059
2060 if (0 > err)
2061 {
2062 os_log(log_handle, "Could not set IPsec policy: %s", ipsec_strerror());
2063 err = kHelperErr_IPsecPolicySetFailed;
2064 goto fin;
2065 }
2066 else
2067 {
2068 err = 0;
2069 }
2070
2071 os_log_debug(log_handle, "succeeded");
2072
2073 fin:
2074 return err;
2075 }
2076
2077 static int removeSA(int s, struct sockaddr *src, struct sockaddr *dst)
2078 {
2079 int err = 0;
2080
2081 os_log_debug(log_handle, "entry");
2082
2083 err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, src, dst);
2084 if (0 > err)
2085 {
2086 os_log(log_handle, "Could not remove IPsec SA: %s", ipsec_strerror());
2087 err = kHelperErr_IPsecRemoveSAFailed;
2088 goto fin;
2089 }
2090 err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, dst, src);
2091 if (0 > err)
2092 {
2093 os_log(log_handle, "Could not remove IPsec SA: %s", ipsec_strerror());
2094 err = kHelperErr_IPsecRemoveSAFailed;
2095 goto fin;
2096 }
2097 else
2098 err = 0;
2099
2100 os_log_debug(log_handle, "succeeded");
2101
2102 fin:
2103 return err;
2104 }
2105
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)
2112 {
2113 struct sockaddr_in6 sin6_loc;
2114 struct sockaddr_in6 sin6_rmt;
2115 ipsec_policy_t policy = NULL;
2116 size_t len = 0;
2117 int s = -1;
2118 int err = 0;
2119
2120 os_log_debug(log_handle,"entry");
2121 if (0 > (s = pfkey_open()))
2122 {
2123 os_log(log_handle, "Could not create IPsec policy socket: %s", ipsec_strerror());
2124 err = kHelperErr_IPsecPolicySocketCreationFailed;
2125 goto fin;
2126 }
2127
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));
2133
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));
2139
2140 int setup = which != kmDNSTunnelPolicyTeardown;
2141
2142 if (0 != (err = generateTunnelPolicy(which, type, 1,
2143 rmt_outer, rmt_port,
2144 loc_outer, loc_port,
2145 rmt_outer6, loc_outer6,
2146 &policy, &len)))
2147 goto fin;
2148
2149 if (0 != (err = sendPolicy(s, setup,
2150 (struct sockaddr *)&sin6_rmt, rmt_bits,
2151 (struct sockaddr *)&sin6_loc, loc_bits,
2152 policy, len)))
2153 goto fin;
2154
2155 if (NULL != policy)
2156 {
2157 free(policy);
2158 policy = NULL;
2159 }
2160
2161 if (0 != (err = generateTunnelPolicy(which, type, 0,
2162 loc_outer, loc_port,
2163 rmt_outer, rmt_port,
2164 loc_outer6, rmt_outer6,
2165 &policy, &len)))
2166 goto fin;
2167 if (0 != (err = sendPolicy(s, setup,
2168 (struct sockaddr *)&sin6_loc, loc_bits,
2169 (struct sockaddr *)&sin6_rmt, rmt_bits,
2170 policy, len)))
2171 goto fin;
2172
2173 if (which == kmDNSTunnelPolicyTeardown)
2174 {
2175 if (rmt_port) // Outer tunnel is IPv4
2176 {
2177 if (loc_outer && rmt_outer)
2178 {
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));
2185
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)))
2191 goto fin;
2192 }
2193 }
2194 else
2195 {
2196 if (loc_outer6 && rmt_outer6)
2197 {
2198 struct sockaddr_in6 sin6_lo;
2199 struct sockaddr_in6 sin6_rm;
2200
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));
2205
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)))
2211 goto fin;
2212 }
2213 }
2214 }
2215
2216 os_log_debug(log_handle,"succeeded");
2217
2218 fin:
2219 if (s >= 0)
2220 pfkey_close(s);
2221 if (NULL != policy)
2222 free(policy);
2223 return err;
2224 }
2225
2226 #endif /* ndef MDNS_NO_IPSEC */
2227
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)
2230 {
2231 #ifndef MDNS_NO_IPSEC
2232 static const char config[] =
2233 "%s"
2234 "remote %s [%u] {\n"
2235 " disconnect_on_idle idle_timeout 600 idle_direction idle_outbound;\n"
2236 " exchange_mode aggressive;\n"
2237 " doi ipsec_doi;\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"
2243 " nonce_size 16;\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"
2249 " proposal {\n"
2250 " encryption_algorithm aes;\n"
2251 " hash_algorithm sha256;\n"
2252 " authentication_method pre_shared_key;\n"
2253 " dh_group 2;\n"
2254 " lifetime time 15 min;\n"
2255 " }\n"
2256 " proposal {\n"
2257 " encryption_algorithm aes;\n"
2258 " hash_algorithm sha1;\n"
2259 " authentication_method pre_shared_key;\n"
2260 " dh_group 2;\n"
2261 " lifetime time 15 min;\n"
2262 " }\n"
2263 "}\n\n"
2264 "sainfo address %s any address %s any {\n"
2265 " pfs_group 2;\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"
2270 "}\n\n"
2271 "sainfo address %s any address %s any {\n"
2272 " pfs_group 2;\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"
2277 "}\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];
2281 FILE *fp = NULL;
2282 int fd = -1;
2283 char tmp_path[PATH_MAX] = "";
2284 v4addr_t loc_outer, rmt_outer;
2285
2286 os_log_debug(log_handle,"HelperAutoTunnelSetKeys: entry");
2287 *err = kHelperErr_NoErr;
2288
2289 char buf1[INET6_ADDRSTRLEN];
2290 char buf2[INET6_ADDRSTRLEN];
2291 char buf3[INET6_ADDRSTRLEN];
2292 char buf4[INET6_ADDRSTRLEN];
2293
2294 buf1[0] = 0;
2295 buf2[0] = 0;
2296 buf3[0] = 0;
2297 buf4[0] = 0;
2298
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));
2303
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);
2306
2307 switch ((enum mDNSAutoTunnelSetKeysReplaceDelete)replacedelete)
2308 {
2309 case kmDNSAutoTunnelSetKeysReplace:
2310 case kmDNSAutoTunnelSetKeysDelete:
2311 break;
2312 default:
2313 *err = kHelperErr_InvalidTunnelSetKeysOperation;
2314 goto fin;
2315 }
2316
2317 if (0 != (*err = v6addr_to_string(loc_inner, li, sizeof(li))))
2318 goto fin;
2319 if (0 != (*err = v6addr_to_string(rmt_inner, ri, sizeof(ri))))
2320 goto fin;
2321
2322 os_log_debug(log_handle, "loc_inner=%s rmt_inner=%s", li, ri);
2323
2324 if (!rmt_port)
2325 {
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;
2328
2329 if (0 != (*err = v6addr_to_string(loc_outer6, lo6, sizeof(lo6))))
2330 goto fin;
2331 if (0 != (*err = v6addr_to_string(rmt_outer6, ro6, sizeof(ro6))))
2332 goto fin;
2333
2334 os_log_debug(log_handle, "IPv6 outer tunnel: loc_outer6=%s rmt_outer6=%s", lo6, ro6);
2335
2336 if ((int)sizeof(path) <= snprintf(path, sizeof(path), "%s%s.conf", GetRacoonConfigDir(), ro6))
2337 {
2338 *err = kHelperErr_ResultTooLarge;
2339 goto fin;
2340 }
2341 }
2342 else
2343 {
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];
2348
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];
2353
2354 if (0 != (*err = v4addr_to_string(loc_outer, lo, sizeof(lo))))
2355 goto fin;
2356 if (0 != (*err = v4addr_to_string(rmt_outer, ro, sizeof(ro))))
2357 goto fin;
2358
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);
2361
2362 if ((int)sizeof(path) <= snprintf(path, sizeof(path), "%s%s.%u.conf", GetRacoonConfigDir(), ro, rmt_port))
2363 {
2364 *err = kHelperErr_ResultTooLarge;
2365 goto fin;
2366 }
2367 }
2368
2369 if (kmDNSAutoTunnelSetKeysReplace == replacedelete)
2370 {
2371 if (0 > ensureExistenceOfRacoonConfigDir(GetRacoonConfigDir()))
2372 {
2373 *err = kHelperErr_RacoonConfigCreationFailed;
2374 goto fin;
2375 }
2376 if ((int)sizeof(tmp_path) <=
2377 snprintf(tmp_path, sizeof(tmp_path), "%s.XXXXXX", path))
2378 {
2379 *err = kHelperErr_ResultTooLarge;
2380 goto fin;
2381 }
2382 if (0 > (fd = mkstemp(tmp_path)))
2383 {
2384 os_log(log_handle, "mkstemp \"%s\" failed: %s", tmp_path, strerror(errno));
2385 *err = kHelperErr_RacoonConfigCreationFailed;
2386 goto fin;
2387 }
2388 if (NULL == (fp = fdopen(fd, "w")))
2389 {
2390 os_log(log_handle, "fdopen: %s", strerror(errno));
2391 *err = kHelperErr_RacoonConfigCreationFailed;
2392 goto fin;
2393 }
2394
2395 fd = -1;
2396 fprintf(fp, config, configHeader, (!rmt_port ? ro6 : ro), rmt_port, id, id, ri, li, li, ri);
2397 fclose(fp);
2398 fp = NULL;
2399
2400 if (0 > rename(tmp_path, path))
2401 {
2402 os_log(log_handle, "rename \"%s\" \"%s\" failed: %s", tmp_path, path, strerror(errno));
2403 *err = kHelperErr_RacoonConfigCreationFailed;
2404 goto fin;
2405 }
2406 }
2407 else
2408 {
2409 if (0 != unlink(path))
2410 os_log_debug(log_handle, "unlink \"%s\" failed: %s", path, strerror(errno));
2411 }
2412
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)))
2416 goto fin;
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)))
2421 goto fin;
2422
2423 if (0 != (*err = teardownTunnelRoute(rmt_inner)))
2424 goto fin;
2425
2426 if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
2427 0 != (*err = setupTunnelRoute(loc_inner, rmt_inner)))
2428 goto fin;
2429
2430 if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
2431 0 != (*err = kickRacoon()))
2432 goto fin;
2433
2434 os_log_debug(log_handle, "succeeded");
2435
2436 fin:
2437 if (NULL != fp)
2438 fclose(fp);
2439 if (0 <= fd)
2440 close(fd);
2441 unlink(tmp_path);
2442 #else
2443 (void)replacedelete; (void)loc_inner; (void)loc_outer6; (void)loc_port; (void)rmt_inner;
2444 (void)rmt_outer6; (void)rmt_port; (void)id;
2445
2446 *err = kHelperErr_IPsecDisabled;
2447 #endif /* MDNS_NO_IPSEC */
2448 update_idle_timer();
2449 return KERN_SUCCESS;
2450 }
2451
2452
2453
2454