Imported Upstream version 878.70.2
[platform/upstream/mdnsresponder.git] / mDNSMacOSX / helper.c
1 /* -*- Mode: C; tab-width: 4 -*-
2  *
3  * Copyright (c) 2007-2015 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, formatDdnsTypeItem, formatDnsPrefixedServiceItem, formatBtmmPrefixedServiceItem
714 };
715
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.
720
721
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";
727
728 static enum DNSKeyFormat getDNSKeyFormat(SecKeychainItemRef item, SecKeychainAttributeList **attributesp)
729 {
730     static UInt32 tags[4] =
731     {
732         kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr, kSecLabelItemAttr
733     };
734     static SecKeychainAttributeInfo attributeInfo =
735     {
736         sizeof(tags)/sizeof(tags[0]), tags, NULL
737     };
738     SecKeychainAttributeList *attributes = NULL;
739     enum DNSKeyFormat format;
740     Boolean malformed = FALSE;
741     OSStatus status = noErr;
742     int i = 0;
743     
744     *attributesp = NULL;
745     if (noErr != (status = SecKeychainItemCopyAttributesAndData(item, &attributeInfo, NULL, &attributes, NULL, NULL)))
746     {
747         os_log_info(log_handle,"getDNSKeyFormat: SecKeychainItemCopyAttributesAndData %d - skipping", status);
748         goto skip;
749     }
750     if (attributeInfo.count != attributes->count)
751         malformed = TRUE;
752     for (i = 0; !malformed && i < (int)attributeInfo.count; ++i)
753         if (attributeInfo.tag[i] != attributes->attr[i].tag)
754             malformed = TRUE;
755     if (malformed)
756     {
757         os_log(log_handle, "getDNSKeyFormat: malformed result from SecKeychainItemCopyAttributesAndData - skipping");
758         goto skip;
759     }
760     
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);
765
766     if (attributes->attr[1].length >= MAX_ESCAPED_DOMAIN_NAME +
767         sizeof(dnsprefix)-1)
768     {
769         os_log(log_handle, "getDNSKeyFormat: kSecServiceItemAttr too long (%u) - skipping",
770               (unsigned int)attributes->attr[1].length);
771         goto skip;
772     }
773     if (attributes->attr[2].length >= MAX_ESCAPED_DOMAIN_NAME)
774     {
775         os_log(log_handle, "getDNSKeyFormat: kSecAccountItemAttr too long (%u) - skipping",
776               (unsigned int)attributes->attr[2].length);
777         goto skip;
778     }
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;
787     else
788     {
789         os_log_info(log_handle,"getDNSKeyFormat: uninterested in this entry");
790         goto skip;
791     }
792     
793     *attributesp = attributes;
794     os_log_info(log_handle,"getDNSKeyFormat: accepting this entry");
795     return format;
796     
797 skip:
798     SecKeychainItemFreeAttributesAndData(attributes, NULL);
799     return formatNotDNSKey;
800 }
801
802 // Insert the attributes as defined by mDNSKeyChainAttributes
803 static CFPropertyListRef copyKeychainItemInfo(SecKeychainItemRef item, SecKeychainAttributeList *attributes, enum DNSKeyFormat format)
804 {
805     CFMutableArrayRef entry = NULL;
806     CFDataRef data = NULL;
807     OSStatus status = noErr;
808     UInt32 keylen = 0;
809     void *keyp = 0;
810     
811     if (NULL == (entry = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)))
812     {
813         os_log(log_handle, "copyKeychainItemInfo: CFArrayCreateMutable failed");
814         goto error;
815     }
816     
817     // Insert the Account attribute (kmDNSKcWhere)
818     switch ((enum DNSKeyFormat)format)
819     {
820         case formatDdnsTypeItem:
821             data = CFDataCreate(kCFAllocatorDefault, attributes->attr[1].data, attributes->attr[1].length);
822             break;
823         case formatDnsPrefixedServiceItem:
824         case formatBtmmPrefixedServiceItem:
825             data = CFDataCreate(kCFAllocatorDefault, attributes->attr[1].data, attributes->attr[1].length);
826             break;
827         default:
828             os_log(log_handle, "copyKeychainItemInfo: unknown DNSKeyFormat value");
829             break;
830     }
831     if (NULL == data)
832     {
833         os_log(log_handle, "copyKeychainItemInfo: CFDataCreate for attr[1] failed");
834         goto error;
835     }
836     CFArrayAppendValue(entry, data);
837     CFRelease(data);
838     
839     // Insert the Where attribute (kmDNSKcAccount)
840     if (NULL == (data = CFDataCreate(kCFAllocatorDefault, attributes->attr[2].data, attributes->attr[2].length)))
841     {
842         os_log(log_handle, "copyKeychainItemInfo: CFDataCreate for attr[2] failed");
843         goto error;
844     }
845     
846     CFArrayAppendValue(entry, data);
847     CFRelease(data);
848     
849     // Insert the Key attribute (kmDNSKcKey)
850     if (noErr != (status = SecKeychainItemCopyAttributesAndData(item, NULL, NULL, NULL, &keylen, &keyp)))
851     {
852         os_log(log_handle, "copyKeychainItemInfo: could not retrieve key for \"%.*s\": %d",
853               (int)attributes->attr[1].length, attributes->attr[1].data, status);
854         goto error;
855     }
856     
857     data = CFDataCreate(kCFAllocatorDefault, keyp, keylen);
858     SecKeychainItemFreeAttributesAndData(NULL, keyp);
859     if (NULL == data)
860     {
861         os_log(log_handle, "copyKeychainItemInfo: CFDataCreate for keyp failed");
862         goto error;
863     }
864     CFArrayAppendValue(entry, data);
865     CFRelease(data);
866     
867     // Insert the Name attribute (kmDNSKcName)
868     if (NULL == (data = CFDataCreate(kCFAllocatorDefault, attributes->attr[3].data, attributes->attr[3].length)))
869     {
870         os_log(log_handle, "copyKeychainItemInfo: CFDataCreate for attr[3] failed");
871         goto error;
872     }
873     
874     CFArrayAppendValue(entry, data);
875     CFRelease(data);
876     return entry;
877     
878 error:
879     if (NULL != entry)
880         CFRelease(entry);
881     return NULL;
882 }
883 #endif
884
885 void KeychainGetSecrets(__unused unsigned int *numsecrets,__unused unsigned long *secrets, __unused unsigned int *secretsCnt, __unused int *err)
886 {
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;
897     OSStatus status = 0;
898    
899     os_log_info(log_handle,"KeychainGetSecrets: entry");
900     *err = kHelperErr_NoErr;
901     *numsecrets = 0;
902     *secrets = (vm_offset_t)NULL;
903
904     if (NULL == (keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)))
905     {
906         os_log(log_handle, "KeychainGetSecrets: CFArrayCreateMutable failed");
907         *err = kHelperErr_ApiErr;
908         goto fin;
909     }
910     if (noErr != (status = SecKeychainCopyDefault(&skc)))
911     {
912         *err = kHelperErr_ApiErr;
913         goto fin;
914     }
915 #pragma clang diagnostic push
916 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
917     if (noErr != (status = SecKeychainSearchCreateFromAttributes(skc, kSecGenericPasswordItemClass, NULL, &search)))
918     {
919         *err = kHelperErr_ApiErr;
920         goto fin;
921     }
922     for (status = SecKeychainSearchCopyNext(search, &item); noErr == status; status = SecKeychainSearchCopyNext(search, &item))
923     {
924         if (formatNotDNSKey != (format = getDNSKeyFormat(item, &attributes)) &&
925             NULL != (entry = copyKeychainItemInfo(item, attributes, format)))
926         {
927             CFArrayAppendValue(keys, entry);
928             CFRelease(entry);
929         }
930         SecKeychainItemFreeAttributesAndData(attributes, NULL);
931         CFRelease(item);
932     }
933 #pragma clang diagnostic pop
934     if (errSecItemNotFound != status)
935          os_log(log_handle, "KeychainGetSecrets: SecKeychainSearchCopyNext failed: %d", status);
936     
937     if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorDefault, kCFAllocatorDefault)))
938     {
939         *err = kHelperErr_ApiErr;
940         os_log(log_handle, "KeychainGetSecrets:CFWriteStreamCreateWithAllocatedBuffers failed");
941         goto fin;
942     }
943     
944     CFWriteStreamOpen(stream);
945     if (0 == CFPropertyListWrite(keys, stream, kCFPropertyListBinaryFormat_v1_0, 0, NULL))
946     {
947         *err = kHelperErr_ApiErr;
948         os_log(log_handle, "KeychainGetSecrets:CFPropertyListWriteToStream failed");
949         goto fin;
950     }
951     result = CFWriteStreamCopyProperty(stream, kCFStreamPropertyDataWritten);
952     
953     if (KERN_SUCCESS != vm_allocate(mach_task_self(), secrets, CFDataGetLength(result), VM_FLAGS_ANYWHERE))
954     {
955         *err = kHelperErr_ApiErr;
956         os_log(log_handle, "KeychainGetSecrets: vm_allocate failed");
957         goto fin;
958     }
959     
960     CFDataGetBytes(result, CFRangeMake(0, CFDataGetLength(result)), (void *)*secrets);
961     *secretsCnt = CFDataGetLength(result);
962     *numsecrets = CFArrayGetCount(keys);
963     
964     os_log_info(log_handle,"KeychainGetSecrets: succeeded");
965     
966 fin:
967     os_log_info(log_handle,"KeychainGetSecrets: returning numsecrets[%u] secrets[%lu] secrets addr[%p] secretscount[%u]",
968                    *numsecrets, *secrets, secrets, *secretsCnt);
969     
970     if (NULL != stream)
971     {
972         CFWriteStreamClose(stream);
973         CFRelease(stream);
974     }
975     if (NULL != result)
976         CFRelease(result);
977     if (NULL != keys)
978         CFRelease(keys);
979     if (NULL != search)
980         CFRelease(search);
981     if (NULL != skc)
982         CFRelease(skc);
983     update_idle_timer();
984     
985     *err = KERN_SUCCESS;
986     
987 #else
988     
989     *err = KERN_FAILURE;
990     
991 #endif
992     
993 }
994
995
996 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
997 CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
998
999
1000 void SendWakeupPacket(unsigned int ifid, const char *eth_addr, const char *ip_addr, int iteration)
1001 {
1002     int bpf_fd, i, j;
1003     struct ifreq ifr;
1004     char ifname[IFNAMSIZ];
1005     char packet[512];
1006     char *ptr = packet;
1007     char bpf_device[12];
1008     struct ether_addr *ea;
1009     // (void) ip_addr; // unused
1010     // (void) iteration; // unused
1011     
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);
1014     
1015     if (if_indextoname(ifid, ifname) == NULL)
1016     {
1017         os_log(log_handle, "SendWakeupPacket: invalid interface index %u", ifid);
1018         return;
1019     }
1020     
1021     ea = ether_aton(eth_addr);
1022     if (ea == NULL)
1023     {
1024         os_log(log_handle, "SendWakeupPacket: invalid ethernet address %s", eth_addr);
1025         return;
1026     }
1027     
1028     for (i = 0; i < 100; i++)
1029     {
1030         snprintf(bpf_device, sizeof(bpf_device), "/dev/bpf%d", i);
1031         bpf_fd = open(bpf_device, O_RDWR, 0);
1032         
1033         if (bpf_fd == -1)
1034             continue;
1035         else
1036             break;
1037     }
1038     
1039     if (bpf_fd == -1)
1040     {
1041         os_log(log_handle, "SendWakeupPacket: cannot find a bpf device");
1042         return;
1043     }
1044     
1045     memset(&ifr, 0, sizeof(ifr));
1046     strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1047     
1048     if (ioctl(bpf_fd, BIOCSETIF, (char *)&ifr) < 0)
1049     {
1050         os_log(log_handle, "SendWakeupPacket: BIOCSETIF failed %s", strerror(errno));
1051         return;
1052     }
1053     
1054     // 0x00 Destination address
1055     for (i=0; i<6; i++)
1056         *ptr++ = ea->octet[i];
1057     
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)
1060     for (i=0; i<6; i++)
1061         *ptr++ = 0;
1062     
1063     // 0x0C Ethertype (0x0842)
1064     *ptr++ = 0x08;
1065     *ptr++ = 0x42;
1066     
1067     // 0x0E Wakeup sync sequence
1068     for (i=0; i<6; i++)
1069         *ptr++ = 0xFF;
1070     
1071     // 0x14 Wakeup data
1072     for (j=0; j<16; j++)
1073         for (i=0; i<6; i++)
1074             *ptr++ = ea->octet[i];
1075     
1076     // 0x74 Password
1077     for (i=0; i<6; i++)
1078         *ptr++ = 0;
1079     
1080     if (write(bpf_fd, packet, ptr - packet) < 0)
1081     {
1082         os_log(log_handle, "SendWakeupPacket: write failed %s", strerror(errno));
1083         return;
1084     }
1085     os_log(log_handle, "SendWakeupPacket: sent unicast eth_addr %s, ip_addr %s", eth_addr, ip_addr);
1086     
1087     // Send a broadcast one to handle ethernet switches that don't flood forward packets with
1088     // unknown mac addresses.
1089     for (i=0; i<6; i++)
1090         packet[i] = 0xFF;
1091     
1092     if (write(bpf_fd, packet, ptr - packet) < 0)
1093     {
1094         os_log(log_handle, "SendWakeupPacket: write failed %s", strerror(errno));
1095         return;
1096     }
1097     os_log(log_handle, "SendWakeupPacket: sent broadcast eth_addr %s, ip_addr %s", eth_addr, ip_addr);
1098     
1099     close(bpf_fd);
1100
1101 }
1102
1103
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)
1106 {
1107     int error;
1108     
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]);
1112     
1113     switch (command)
1114     {
1115         case PF_SET_RULES:
1116             error = P2PPacketFilterAddBonjourRuleSet(ifname, count, portArray, protocolArray);
1117             if (error)
1118                 os_log(log_handle, "P2PPacketFilterAddBonjourRuleSet failed %s", strerror(error));
1119             break;
1120             
1121         case PF_CLEAR_RULES:
1122             error = P2PPacketFilterClearBonjourRules();
1123             if (error)
1124                 os_log(log_handle, "P2PPacketFilterClearBonjourRules failed %s", strerror(error));
1125             break;
1126             
1127         default:
1128             os_log(log_handle, "PacketFilterControl: invalid command %d", command);
1129             break;
1130     }
1131
1132 }
1133
1134 static unsigned long in_cksum(unsigned short *ptr, int nbytes)
1135 {
1136     unsigned long sum;
1137     u_short oddbyte;
1138     
1139     /*
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.
1143      */
1144     sum = 0;
1145     while (nbytes > 1)
1146     {
1147         sum += *ptr++;
1148         nbytes -= 2;
1149     }
1150     
1151     /* mop up an odd byte, if necessary */
1152     if (nbytes == 1)
1153     {
1154         /* make sure top half is zero */
1155         oddbyte = 0;
1156         
1157         /* one byte only */
1158         *((u_char *)&oddbyte) = *(u_char *)ptr;
1159         sum += oddbyte;
1160     }
1161     /* Add back carry outs from top 16 bits to low 16 bits. */
1162     sum = (sum >> 16) + (sum & 0xffff);
1163     
1164     /* add carry */
1165     sum += (sum >> 16);
1166     
1167     return sum;
1168 }
1169
1170 static unsigned short InetChecksum(unsigned short *ptr, int nbytes)
1171 {
1172     unsigned long sum;
1173     
1174     sum = in_cksum(ptr, nbytes);
1175     return (unsigned short)~sum;
1176 }
1177
1178 static void TCPCheckSum(int af, struct tcphdr *t, int tcplen, const v6addr_t sadd6, const v6addr_t dadd6)
1179 {
1180     unsigned long sum = 0;
1181     unsigned short *ptr;
1182     
1183     /* TCP header checksum */
1184     sum = in_cksum((unsigned short *)t, tcplen);
1185     
1186     if (af == AF_INET)
1187     {
1188         /* Pseudo header */
1189         ptr = (unsigned short *)sadd6;
1190         sum += *ptr++;
1191         sum += *ptr++;
1192         ptr = (unsigned short *)dadd6;
1193         sum += *ptr++;
1194         sum += *ptr++;
1195     }
1196     else if (af == AF_INET6)
1197     {
1198         /* Pseudo header */
1199         ptr = (unsigned short *)sadd6;
1200         sum += *ptr++;
1201         sum += *ptr++;
1202         sum += *ptr++;
1203         sum += *ptr++;
1204         sum += *ptr++;
1205         sum += *ptr++;
1206         sum += *ptr++;
1207         sum += *ptr++;
1208         ptr = (unsigned short *)dadd6;
1209         sum += *ptr++;
1210         sum += *ptr++;
1211         sum += *ptr++;
1212         sum += *ptr++;
1213         sum += *ptr++;
1214         sum += *ptr++;
1215         sum += *ptr++;
1216         sum += *ptr++;
1217     }
1218     
1219     sum += htons(tcplen);
1220     sum += htons(IPPROTO_TCP);
1221     
1222     while (sum >> 16)
1223         sum = (sum >> 16) + (sum & 0xFFFF);
1224     
1225     t->th_sum = ~sum;
1226     
1227 }
1228
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)
1230 {
1231     
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]
1235
1236     os_log_info(log_handle, "SendKeepalive:  "IPv6FMTSTRING" :space: "IPv6FMTSTRING"",
1237                 IPv6FMTSARGS, IPv6FMTDARGS);
1238     
1239     struct packet4
1240     {
1241         struct ip ip;
1242         struct tcphdr tcp;
1243     } packet4;
1244     struct packet6
1245     {
1246         struct tcphdr tcp;
1247     } packet6;
1248     int sock, on;
1249     struct tcphdr *t;
1250     int af;
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;
1254     void *packet;
1255     ssize_t packetlen;
1256     char ctlbuf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
1257     struct msghdr msghdr;
1258     struct iovec iov;
1259     ssize_t len;
1260     
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);
1263     
1264     char buf1[INET6_ADDRSTRLEN];
1265     char buf2[INET6_ADDRSTRLEN];
1266     
1267     buf1[0] = 0;
1268     buf2[0] = 0;
1269     
1270     inet_ntop(AF_INET6, sadd6, buf1, sizeof(buf1));
1271     inet_ntop(AF_INET6, dadd6, buf2, sizeof(buf2));
1272     
1273     os_log_info(log_handle,"SendKeepalive invoked: sadd6 is %s, dadd6 is %s", buf1, buf2);
1274     
1275     // all the incoming arguments are in network order
1276     if ((*(unsigned *)(sadd6 +4) == 0) && (*(unsigned *)(sadd6 + 8) == 0) && (*(unsigned *)(sadd6 + 12) == 0))
1277     {
1278         af = AF_INET;
1279         memset(&packet4, 0, sizeof (packet4));
1280         
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);
1293         
1294         /* IP header checksum */
1295         packet4.ip.ip_sum = InetChecksum((unsigned short *)&packet4.ip, 20);
1296         t = &packet4.tcp;
1297         packet = &packet4;
1298         packetlen = 40; // sum of IPv4 header len(20) and TCP header len(20)
1299     }
1300     else
1301     {
1302         af = AF_INET6;
1303         memset(&packet6, 0, sizeof (packet6));
1304         t = &packet6.tcp;
1305         packet = &packet6;
1306         // We don't send IPv6 header, hence just the TCP header len (20)
1307         packetlen = 20;
1308     }
1309     
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;
1317     t->th_win = win;
1318     t->th_sum = 0;              /* 16-bit checksum (below) */
1319     t->th_urp = 0;              /* 16-bit urgent offset */
1320     
1321     TCPCheckSum(af, t, 20, sadd6, dadd6);
1322     
1323     /* Open up a RAW socket */
1324     if ((sock = socket(af, SOCK_RAW, IPPROTO_TCP)) < 0)
1325     {
1326         os_log(log_handle, "SendKeepalive: socket %s", strerror(errno));
1327         return;
1328     }
1329     
1330     if (af == AF_INET)
1331     {
1332         on = 1;
1333         if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &on, sizeof (on)))
1334         {
1335             close(sock);
1336             os_log(log_handle, "SendKeepalive: setsockopt %s", strerror(errno));
1337             return;
1338         }
1339         
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;
1345         
1346         msghdr.msg_control = NULL;
1347         msghdr.msg_controllen = 0;
1348         
1349     }
1350     else
1351     {
1352         struct cmsghdr *ctl;
1353         
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));
1358         
1359         sin6_to->sin6_port = rport;
1360         sin6_to->sin6_flowinfo = 0;
1361         
1362         
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;
1372     }
1373     
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;
1381     
1382 again:
1383     len = sendmsg(sock, &msghdr, 0);
1384     if (len == -1)
1385     {
1386         if (errno == EINTR)
1387             goto again;
1388     }
1389     
1390     if (len != packetlen)
1391     {
1392         os_log(log_handle, "SendKeepalive: sendmsg failed %s", strerror(errno));
1393     }
1394     else
1395     {
1396         char source[INET6_ADDRSTRLEN], dest[INET6_ADDRSTRLEN];
1397         
1398         inet_ntop(af, (void *)sadd6, source, sizeof(source));
1399         inet_ntop(af, (void *)dadd6, dest, sizeof(dest));
1400         
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));
1403         
1404     }
1405     close(sock);
1406
1407 }
1408
1409
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)
1411 {
1412     
1413     struct tcp_info   ti;
1414     struct info_tuple itpl;
1415     int               mib[4];
1416     unsigned int      miblen;
1417     size_t            len;
1418     size_t            sz;
1419     
1420     memset(&itpl, 0, sizeof(struct info_tuple));
1421     memset(&ti,   0, sizeof(struct tcp_info));
1422     
1423     char buf1[INET6_ADDRSTRLEN];
1424     char buf2[INET6_ADDRSTRLEN];
1425     
1426     buf1[0] = 0;
1427     buf2[0] = 0;
1428     
1429     inet_ntop(AF_INET6, laddr, buf1, sizeof(buf1));
1430     inet_ntop(AF_INET6, raddr, buf2, sizeof(buf2));
1431
1432     os_log_info(log_handle, "RetrieveTCPInfo invoked: laddr is %s, raddr is %s", buf1, buf2);
1433     
1434     os_log_info(log_handle,"RetrieveTCPInfo invoked: lport is[%d] rport is[%d] family is [%d]",
1435                    lport, rport, family);
1436
1437     if (family == AF_INET)
1438     {
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;
1445     }
1446     else
1447     {
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;
1454     }
1455     itpl.itpl_proto = IPPROTO_TCP;
1456     sz = sizeof(mib)/sizeof(mib[0]);
1457     if (sysctlnametomib("net.inet.tcp.info", mib, &sz) == -1)
1458     {
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;
1462     }
1463     miblen = (unsigned int)sz;
1464     len    = sizeof(struct tcp_info);
1465     if (sysctl(mib, miblen, &ti, &len, &itpl, sizeof(struct info_tuple)) == -1)
1466     {
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;
1470     }
1471     
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;
1477     
1478 }
1479
1480 #ifndef MDNS_NO_IPSEC
1481
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/";
1485
1486 static int MacOSXSystemBuildNumber(char* letter_out, int* minor_out)
1487 {
1488     int major = 0, minor = 0;
1489     char letter = 0, buildver[256]="<Unknown>";
1490     CFDictionaryRef vers = _CFCopySystemVersionDictionary();
1491     if (vers)
1492     {
1493         CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
1494         if (cfbuildver) CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8);
1495         sscanf(buildver, "%d%c%d", &major, &letter, &minor);
1496         CFRelease(vers);
1497     }
1498     else
1499         os_log_info(log_handle, "_CFCopySystemVersionDictionary failed");
1500     
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;
1504     return(major);
1505 }
1506
1507 static int UseOldRacoon()
1508 {
1509     static int g_oldRacoon = -1;
1510     
1511     if (g_oldRacoon == -1)
1512     {
1513         char letter = 0;
1514         int minor = 0;
1515         g_oldRacoon = (MacOSXSystemBuildNumber(&letter, &minor) < 10);
1516         os_log_debug(log_handle, "%s", g_oldRacoon ? "old" : "new");
1517     }
1518     
1519     return g_oldRacoon;
1520 }
1521
1522 static int RacoonSignal()
1523 {
1524     return UseOldRacoon() ? SIGHUP : SIGUSR1;
1525 }
1526
1527 static int notifyRacoon(void)
1528 {
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 */
1532     char *p = NULL;
1533     ssize_t n = 0;
1534     unsigned long m = 0;
1535     int fd = open(racoon_pid_path, O_RDONLY);
1536     
1537     if (0 > fd)
1538     {
1539         os_log_debug(log_handle,"open \"%s\" failed, and that's OK: %s", racoon_pid_path,
1540               strerror(errno));
1541         return kHelperErr_RacoonNotificationFailed;
1542     }
1543     n = read(fd, buf, sizeof(buf)-1);
1544     close(fd);
1545     if (1 > n)
1546     {
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;
1550     }
1551     buf[n] = '\0';
1552     m = strtoul(buf, &p, 10);
1553     if (*p != '\0' && !isspace(*p))
1554     {
1555         os_log_debug(log_handle,"invalid PID \"%s\" (around '%c')", buf, *p);
1556         return kHelperErr_RacoonNotificationFailed;
1557     }
1558     if (2 > m)
1559     {
1560         os_log_debug(log_handle,"refusing to kill PID %lu", m);
1561         return kHelperErr_RacoonNotificationFailed;
1562     }
1563     if (0 != kill(m, RacoonSignal()))
1564     {
1565         os_log_debug(log_handle,"Could not signal racoon (%lu): %s", m, strerror(errno));
1566         return kHelperErr_RacoonNotificationFailed;
1567     }
1568     
1569     os_log_debug(log_handle, "Sent racoon (%lu) signal %d", m, RacoonSignal());
1570     return 0;
1571 }
1572
1573 static const char* GetRacoonConfigDir()
1574 {
1575     return UseOldRacoon() ? g_racoon_config_dir_old : g_racoon_config_dir;
1576 }
1577 /*
1578 static const char* GetOldRacoonConfigDir()
1579 {
1580     return UseOldRacoon() ? NULL : g_racoon_config_dir_old;
1581 }
1582 */
1583
1584 static void closefds(int from)
1585 {
1586     int fd = 0;
1587     struct dirent entry, *entryp = NULL;
1588     DIR *dirp = opendir("/dev/fd");
1589     
1590     if (dirp == NULL)
1591     {
1592         /* fall back to the erroneous getdtablesize method */
1593         for (fd = from; fd < getdtablesize(); ++fd)
1594             close(fd);
1595         return;
1596     }
1597     while (0 == readdir_r(dirp, &entry, &entryp) && NULL != entryp)
1598     {
1599         fd = atoi(entryp->d_name);
1600         if (fd >= from && fd != dirfd(dirp))
1601             close(fd);
1602     }
1603     closedir(dirp);
1604 }
1605
1606
1607 static int startRacoonOld(void)
1608 {
1609     os_log_debug(log_handle,"entry");
1610     char * const racoon_args[] = { "/usr/sbin/racoon", "-e", NULL   };
1611     ssize_t n = 0;
1612     pid_t pid = 0;
1613     int status = 0;
1614     
1615     if (0 == (pid = fork()))
1616     {
1617         closefds(0);
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));
1621         exit(2);
1622     }
1623     os_log_info(log_handle,"racoon (pid=%lu) started",
1624             (unsigned long)pid);
1625     n = waitpid(pid, &status, 0);
1626     if (-1 == n)
1627     {
1628         os_log(log_handle, "Unexpected waitpid failure: %s",
1629                 strerror(errno));
1630         return kHelperErr_RacoonStartFailed;
1631     }
1632     else if (pid != n)
1633     {
1634         os_log(log_handle, "Unexpected waitpid return value %d", (int)n);
1635         return kHelperErr_RacoonStartFailed;
1636     }
1637     else if (WIFSIGNALED(status))
1638     {
1639         os_log(log_handle,
1640                 "racoon (pid=%lu) terminated due to signal %d",
1641                 (unsigned long)pid, WTERMSIG(status));
1642         return kHelperErr_RacoonStartFailed;
1643     }
1644     else if (WIFSTOPPED(status))
1645     {
1646         os_log(log_handle,
1647                 "racoon (pid=%lu) has stopped due to signal %d",
1648                 (unsigned long)pid, WSTOPSIG(status));
1649         return kHelperErr_RacoonStartFailed;
1650     }
1651     else if (0 != WEXITSTATUS(status))
1652     {
1653         os_log(log_handle,
1654                 "racoon (pid=%lu) exited with status %d",
1655                 (unsigned long)pid, WEXITSTATUS(status));
1656         return kHelperErr_RacoonStartFailed;
1657     }
1658     os_log_debug(log_handle, "racoon (pid=%lu) daemonized normally", (unsigned long)pid);
1659     return 0;
1660 }
1661
1662 // constant and structure for the racoon control socket
1663 #define VPNCTL_CMD_PING 0x0004
1664 typedef struct vpnctl_hdr_struct
1665 {
1666     u_int16_t msg_type;
1667     u_int16_t flags;
1668     u_int32_t cookie;
1669     u_int32_t reserved;
1670     u_int16_t result;
1671     u_int16_t len;
1672 } vpnctl_hdr;
1673
1674 static int startRacoon(void)
1675 {
1676     os_log_debug(log_handle,"entry");
1677     int fd = socket(PF_UNIX, SOCK_STREAM, 0);
1678     if (0 > fd)
1679     {
1680         os_log(log_handle,"Could not create endpoint for racoon control socket: %d %s",
1681                 errno, strerror(errno));
1682         return kHelperErr_RacoonStartFailed;
1683     }
1684     
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);
1692     if (0 > result)
1693     {
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;
1697     }
1698     
1699     u_int32_t btmm_cookie = 0x4d4d5442;
1700     vpnctl_hdr h = { htons(VPNCTL_CMD_PING), 0, btmm_cookie, 0, 0, 0 };
1701     size_t bytes = 0;
1702     ssize_t ret = 0;
1703     
1704     while (bytes < sizeof(vpnctl_hdr))
1705     {
1706         ret = write(fd, ((unsigned char*)&h)+bytes, sizeof(vpnctl_hdr) - bytes);
1707         if (ret == -1)
1708         {
1709             os_log(log_handle, "Could not write to racoon control socket: %d %s", errno, strerror(errno));
1710             return kHelperErr_RacoonStartFailed;
1711         }
1712         bytes += ret;
1713     }
1714     
1715     int nfds = fd + 1;
1716     fd_set fds;
1717     int counter = 0;
1718     struct timeval tv;
1719     bytes = 0;
1720     h.cookie = 0;
1721     
1722     for (counter = 0; counter < 100; counter++)
1723     {
1724         FD_ZERO(&fds);
1725         FD_SET(fd, &fds);
1726         tv = (struct timeval){ 0, 10000 }; // 10 milliseconds * 100 iterations = 1 second max wait time
1727         
1728         result = select(nfds, &fds, (fd_set*)NULL, (fd_set*)NULL, &tv);
1729         if (result > 0)
1730         {
1731             if (FD_ISSET(fd, &fds))
1732             {
1733                 ret = read(fd, ((unsigned char*)&h)+bytes, sizeof(vpnctl_hdr) - bytes);
1734                 
1735                 if (ret == -1)
1736                 {
1737                     os_log(log_handle,"Could not read from racoon control socket: %d %s", errno, strerror(errno));
1738                     break;
1739                 }
1740                 bytes += ret;
1741                 if (bytes >= sizeof(vpnctl_hdr)) break;
1742             }
1743             else
1744             {
1745                 os_log_debug(log_handle, "select returned but fd_isset not on expected fd");
1746             }
1747         }
1748         else if (result < 0)
1749         {
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;
1753         }
1754     }
1755     
1756     close(fd);
1757     
1758     if (bytes < sizeof(vpnctl_hdr) || h.cookie != btmm_cookie)
1759         return kHelperErr_RacoonStartFailed;
1760     
1761     os_log_debug(log_handle, "racoon started");
1762     return 0;
1763 }
1764
1765 static int kickRacoon(void)
1766 {
1767     if ( 0 == notifyRacoon() )
1768         return 0;
1769     return UseOldRacoon() ? startRacoonOld() : startRacoon();
1770 }
1771
1772 typedef enum _mDNSTunnelPolicyWhich
1773 {
1774     kmDNSTunnelPolicySetup,
1775     kmDNSTunnelPolicyTeardown,
1776     kmDNSTunnelPolicyGenerate
1777 } mDNSTunnelPolicyWhich;
1778
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
1782 {
1783     kmDNSNoTunnel,
1784     kmDNSIPv6IPv4Tunnel,
1785     kmDNSIPv6IPv6Tunnel
1786 } mDNSTunnelType;
1787
1788 static const uint8_t kWholeV6Mask = 128;
1789
1790 static unsigned int routeSeq = 1;
1791
1792 static int setupTunnelRoute(const v6addr_t local, const v6addr_t remote)
1793 {
1794     struct
1795     {
1796         struct rt_msghdr hdr;
1797         struct sockaddr_in6 dst;
1798         struct sockaddr_in6 gtwy;
1799     } msg;
1800     int err = 0;
1801     int s = -1;
1802     
1803     if (0 > (s = socket(PF_ROUTE, SOCK_RAW, AF_INET)))
1804     {
1805         os_log(log_handle,"socket(PF_ROUTE, ...) failed: %s", strerror(errno));
1806         
1807         err = kHelperErr_RoutingSocketCreationFailed;
1808         goto fin;
1809     }
1810     
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;
1821     
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));
1825     
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));
1829     
1830     /* send message, ignore error when route already exists */
1831     if (0 > write(s, &msg, msg.hdr.rtm_msglen))
1832     {
1833         const int errno_ = errno;
1834         
1835         os_log_info(log_handle,"write to routing socket failed: %s", strerror(errno_));
1836         if (EEXIST != errno_)
1837         {
1838             err = kHelperErr_RouteAdditionFailed;
1839             goto fin;
1840         }
1841     }
1842     
1843 fin:
1844     if (0 <= s)
1845         close(s);
1846     return err;
1847 }
1848
1849 static int teardownTunnelRoute(const v6addr_t remote)
1850 {
1851     struct
1852     {
1853         struct rt_msghdr hdr;
1854         struct sockaddr_in6 dst;
1855     } msg;
1856     int err = 0;
1857     int s = -1;
1858     
1859     if (0 > (s = socket(PF_ROUTE, SOCK_RAW, AF_INET)))
1860     {
1861         os_log(log_handle, "socket(PF_ROUTE, ...) failed: %s", strerror(errno));
1862         err = kHelperErr_RoutingSocketCreationFailed;
1863         goto fin;
1864     }
1865     memset(&msg, 0, sizeof(msg));
1866     
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;
1872     
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))
1877     {
1878         const int errno_ = errno;
1879         
1880         os_log_debug(log_handle,"write to routing socket failed: %s", strerror(errno_));
1881         
1882         if (ESRCH != errno_)
1883         {
1884             err = kHelperErr_RouteDeletionFailed;
1885             goto fin;
1886         }
1887     }
1888     
1889 fin:
1890     if (0 <= s)
1891         close(s);
1892     return err;
1893 }
1894
1895 static int v4addr_to_string(v4addr_t addr, char *buf, size_t buflen)
1896 {
1897     if (NULL == inet_ntop(AF_INET, addr, buf, buflen))
1898     {
1899         os_log(log_handle, "v4addr_to_string() inet_ntop failed: %s", strerror(errno));
1900         return kHelperErr_InvalidNetworkAddress;
1901     }
1902     else
1903     {
1904         return 0;
1905     }
1906 }
1907
1908 static int v6addr_to_string(const v6addr_t addr, char *buf, size_t buflen)
1909 {
1910     if (NULL == inet_ntop(AF_INET6, addr, buf, buflen))
1911     {
1912         os_log(log_handle, "v6addr_to_string inet_ntop failed: %s", strerror(errno));
1913         return kHelperErr_InvalidNetworkAddress;
1914     }
1915     else
1916     {
1917         return 0;
1918     }
1919 }
1920
1921 static int ensureExistenceOfRacoonConfigDir(const char* const racoon_config_dir)
1922 {
1923     struct stat s;
1924     int ret = stat(racoon_config_dir, &s);
1925     if (ret != 0)
1926     {
1927         if (errno != ENOENT)
1928         {
1929             os_log(log_handle, "stat of \"%s\" failed (%d): %s",
1930                     racoon_config_dir, ret, strerror(errno));
1931             return -1;
1932         }
1933         else
1934         {
1935             ret = mkdir(racoon_config_dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
1936             if (ret != 0)
1937             {
1938                 os_log(log_handle, "mkdir \"%s\" failed: %s",
1939                         racoon_config_dir, strerror(errno));
1940                 return -1;
1941             }
1942             else
1943             {
1944                 os_log_info(log_handle, "created directory \"%s\"", racoon_config_dir);
1945             }
1946         }
1947     }
1948     else if (!(s.st_mode & S_IFDIR))
1949     {
1950         os_log(log_handle, "\"%s\" is not a directory!",
1951                 racoon_config_dir);
1952         return -1;
1953     }
1954     
1955     return 0;
1956 }
1957
1958
1959
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)
1966 {
1967     char srcs[INET_ADDRSTRLEN], dsts[INET_ADDRSTRLEN];
1968     char srcs6[INET6_ADDRSTRLEN], dsts6[INET6_ADDRSTRLEN];
1969     char buf[512];
1970     char *inOut = in ? "in" : "out";
1971     ssize_t n = 0;
1972     int err = 0;
1973     
1974     *policy = NULL;
1975     *len = 0;
1976     
1977     switch (which)
1978     {
1979         case kmDNSTunnelPolicySetup:
1980             if (type == kmDNSIPv6IPv4Tunnel)
1981             {
1982                 if (0 != (err = v4addr_to_string(src, srcs, sizeof(srcs))))
1983                     goto fin;
1984                 if (0 != (err = v4addr_to_string(dst, dsts, sizeof(dsts))))
1985                     goto fin;
1986                 n = snprintf(buf, sizeof(buf),
1987                              "%s ipsec esp/tunnel/%s[%u]-%s[%u]/require",
1988                              inOut, srcs, src_port, dsts, dst_port);
1989             }
1990             else if (type == kmDNSIPv6IPv6Tunnel)
1991             {
1992                 if (0 != (err = v6addr_to_string(src6, srcs6, sizeof(srcs6))))
1993                     goto fin;
1994                 if (0 != (err = v6addr_to_string(dst6, dsts6, sizeof(dsts6))))
1995                     goto fin;
1996                 n = snprintf(buf, sizeof(buf),
1997                              "%s ipsec esp/tunnel/%s-%s/require",
1998                              inOut, srcs6, dsts6);
1999             }
2000             break;
2001         case kmDNSTunnelPolicyTeardown:
2002             n = strlcpy(buf, inOut, sizeof(buf));
2003             break;
2004         case kmDNSTunnelPolicyGenerate:
2005             n = snprintf(buf, sizeof(buf), "%s generate", inOut);
2006             break;
2007         default:
2008             err = kHelperErr_IPsecPolicyCreationFailed;
2009             goto fin;
2010     }
2011     
2012     if (n >= (int)sizeof(buf))
2013     {
2014         err = kHelperErr_ResultTooLarge;
2015         goto fin;
2016     }
2017     
2018     os_log_info(log_handle, "policy=\"%s\"", buf);
2019     
2020     if (NULL == (*policy = (ipsec_policy_t)ipsec_set_policy(buf, n)))
2021     {
2022         os_log_info(log_handle, "Could not create IPsec policy from \"%s\"", buf);
2023         err = kHelperErr_IPsecPolicyCreationFailed;
2024         goto fin;
2025     }
2026     *len = ((ipsec_policy_t)(*policy))->sadb_x_policy_len * 8;
2027     
2028 fin:
2029     return err;
2030 }
2031
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)
2036 {
2037     static unsigned int policySeq = 0;
2038     int err = 0;
2039     
2040     os_log_debug(log_handle, "entry, setup=%d", setup);
2041     
2042     if (setup)
2043         err = pfkey_send_spdadd(s, src, src_bits, dst, dst_bits, -1,
2044                                 (char *)policy, len, policySeq++);
2045     else
2046         err = pfkey_send_spddelete(s, src, src_bits, dst, dst_bits, -1,
2047                                    (char *)policy, len, policySeq++);
2048     
2049     if (0 > err)
2050     {
2051         os_log(log_handle, "Could not set IPsec policy: %s", ipsec_strerror());
2052         err = kHelperErr_IPsecPolicySetFailed;
2053         goto fin;
2054     }
2055     else
2056     {
2057         err = 0;
2058     }
2059     
2060     os_log_debug(log_handle, "succeeded");
2061     
2062 fin:
2063     return err;
2064 }
2065
2066 static int removeSA(int s, struct sockaddr *src, struct sockaddr *dst)
2067 {
2068     int err = 0;
2069     
2070     os_log_debug(log_handle, "entry");
2071     
2072     err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, src, dst);
2073     if (0 > err)
2074     {
2075         os_log(log_handle, "Could not remove IPsec SA: %s", ipsec_strerror());
2076         err = kHelperErr_IPsecRemoveSAFailed;
2077         goto fin;
2078     }
2079     err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, dst, src);
2080     if (0 > err)
2081     {
2082         os_log(log_handle, "Could not remove IPsec SA: %s", ipsec_strerror());
2083         err = kHelperErr_IPsecRemoveSAFailed;
2084         goto fin;
2085     }
2086     else
2087         err = 0;
2088     
2089     os_log_debug(log_handle, "succeeded");
2090     
2091 fin:
2092     return err;
2093 }
2094
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)
2101 {
2102     struct sockaddr_in6 sin6_loc;
2103     struct sockaddr_in6 sin6_rmt;
2104     ipsec_policy_t policy = NULL;
2105     size_t len = 0;
2106     int s = -1;
2107     int err = 0;
2108     
2109     os_log_debug(log_handle,"entry");
2110     if (0 > (s = pfkey_open()))
2111     {
2112         os_log(log_handle, "Could not create IPsec policy socket: %s", ipsec_strerror());
2113         err = kHelperErr_IPsecPolicySocketCreationFailed;
2114         goto fin;
2115     }
2116     
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));
2122     
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));
2128     
2129     int setup = which != kmDNSTunnelPolicyTeardown;
2130     
2131     if (0 != (err = generateTunnelPolicy(which, type, 1,
2132                                          rmt_outer, rmt_port,
2133                                          loc_outer, loc_port,
2134                                          rmt_outer6, loc_outer6,
2135                                          &policy, &len)))
2136         goto fin;
2137     
2138     if (0 != (err = sendPolicy(s, setup,
2139                                (struct sockaddr *)&sin6_rmt, rmt_bits,
2140                                (struct sockaddr *)&sin6_loc, loc_bits,
2141                                policy, len)))
2142         goto fin;
2143     
2144     if (NULL != policy)
2145     {
2146         free(policy);
2147         policy = NULL;
2148     }
2149     
2150     if (0 != (err = generateTunnelPolicy(which, type, 0,
2151                                          loc_outer, loc_port,
2152                                          rmt_outer, rmt_port,
2153                                          loc_outer6, rmt_outer6,
2154                                          &policy, &len)))
2155         goto fin;
2156     if (0 != (err = sendPolicy(s, setup,
2157                                (struct sockaddr *)&sin6_loc, loc_bits,
2158                                (struct sockaddr *)&sin6_rmt, rmt_bits,
2159                                policy, len)))
2160         goto fin;
2161     
2162     if (which == kmDNSTunnelPolicyTeardown)
2163     {
2164         if (rmt_port)       // Outer tunnel is IPv4
2165         {
2166             if (loc_outer && rmt_outer)
2167             {
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));
2174                 
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)))
2180                     goto fin;
2181             }
2182         }
2183         else
2184         {
2185             if (loc_outer6 && rmt_outer6)
2186             {
2187                 struct sockaddr_in6 sin6_lo;
2188                 struct sockaddr_in6 sin6_rm;
2189                 
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));
2194                 
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)))
2200                     goto fin;
2201             }
2202         }
2203     }
2204     
2205     os_log_debug(log_handle,"succeeded");
2206     
2207 fin:
2208     if (s >= 0)
2209         pfkey_close(s);
2210     if (NULL != policy)
2211         free(policy);
2212     return err;
2213 }
2214
2215 #endif /* ndef MDNS_NO_IPSEC */
2216
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)
2219 {
2220 #ifndef MDNS_NO_IPSEC
2221     static const char config[] =
2222     "%s"
2223     "remote %s [%u] {\n"
2224     "  disconnect_on_idle idle_timeout 600 idle_direction idle_outbound;\n"
2225     "  exchange_mode aggressive;\n"
2226     "  doi ipsec_doi;\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"
2232     "  nonce_size 16;\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"
2238     "  proposal {\n"
2239     "    encryption_algorithm aes;\n"
2240     "    hash_algorithm sha256;\n"
2241     "    authentication_method pre_shared_key;\n"
2242     "    dh_group 2;\n"
2243     "    lifetime time 15 min;\n"
2244     "  }\n"
2245     "  proposal {\n"
2246     "    encryption_algorithm aes;\n"
2247     "    hash_algorithm sha1;\n"
2248     "    authentication_method pre_shared_key;\n"
2249     "    dh_group 2;\n"
2250     "    lifetime time 15 min;\n"
2251     "  }\n"
2252     "}\n\n"
2253     "sainfo address %s any address %s any {\n"
2254     "  pfs_group 2;\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"
2259     "}\n\n"
2260     "sainfo address %s any address %s any {\n"
2261     "  pfs_group 2;\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"
2266     "}\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];
2270     FILE *fp = NULL;
2271     int fd = -1;
2272     char tmp_path[PATH_MAX] = "";
2273     v4addr_t loc_outer, rmt_outer;
2274     
2275     os_log_debug(log_handle,"HelperAutoTunnelSetKeys: entry");
2276     *err = kHelperErr_NoErr;
2277
2278     char buf1[INET6_ADDRSTRLEN];
2279     char buf2[INET6_ADDRSTRLEN];
2280     char buf3[INET6_ADDRSTRLEN];
2281     char buf4[INET6_ADDRSTRLEN];
2282     
2283     buf1[0] = 0;
2284     buf2[0] = 0;
2285     buf3[0] = 0;
2286     buf4[0] = 0;
2287     
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));
2292     
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);
2295     
2296     switch ((enum mDNSAutoTunnelSetKeysReplaceDelete)replacedelete)
2297     {
2298         case kmDNSAutoTunnelSetKeysReplace:
2299         case kmDNSAutoTunnelSetKeysDelete:
2300             break;
2301         default:
2302             *err = kHelperErr_InvalidTunnelSetKeysOperation;
2303             goto fin;
2304     }
2305     
2306     if (0 != (*err = v6addr_to_string(loc_inner, li, sizeof(li))))
2307         goto fin;
2308     if (0 != (*err = v6addr_to_string(rmt_inner, ri, sizeof(ri))))
2309         goto fin;
2310     
2311     os_log_debug(log_handle, "loc_inner=%s rmt_inner=%s", li, ri);
2312     
2313     if (!rmt_port)
2314     {
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;
2317         
2318         if (0 != (*err = v6addr_to_string(loc_outer6, lo6, sizeof(lo6))))
2319             goto fin;
2320         if (0 != (*err = v6addr_to_string(rmt_outer6, ro6, sizeof(ro6))))
2321             goto fin;
2322         
2323         os_log_debug(log_handle, "IPv6 outer tunnel: loc_outer6=%s rmt_outer6=%s", lo6, ro6);
2324         
2325         if ((int)sizeof(path) <= snprintf(path, sizeof(path), "%s%s.conf", GetRacoonConfigDir(), ro6))
2326         {
2327             *err = kHelperErr_ResultTooLarge;
2328             goto fin;
2329         }
2330     }
2331     else
2332     {
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];
2337         
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];
2342         
2343         if (0 != (*err = v4addr_to_string(loc_outer, lo, sizeof(lo))))
2344             goto fin;
2345         if (0 != (*err = v4addr_to_string(rmt_outer, ro, sizeof(ro))))
2346             goto fin;
2347         
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);
2350         
2351         if ((int)sizeof(path) <= snprintf(path, sizeof(path), "%s%s.%u.conf", GetRacoonConfigDir(), ro, rmt_port))
2352         {
2353             *err = kHelperErr_ResultTooLarge;
2354             goto fin;
2355         }
2356     }
2357     
2358     if (kmDNSAutoTunnelSetKeysReplace == replacedelete)
2359     {
2360         if (0 > ensureExistenceOfRacoonConfigDir(GetRacoonConfigDir()))
2361         {
2362             *err = kHelperErr_RacoonConfigCreationFailed;
2363             goto fin;
2364         }
2365         if ((int)sizeof(tmp_path) <=
2366             snprintf(tmp_path, sizeof(tmp_path), "%s.XXXXXX", path))
2367         {
2368             *err = kHelperErr_ResultTooLarge;
2369             goto fin;
2370         }
2371         if (0 > (fd = mkstemp(tmp_path)))
2372         {
2373             os_log(log_handle, "mkstemp \"%s\" failed: %s", tmp_path, strerror(errno));
2374             *err = kHelperErr_RacoonConfigCreationFailed;
2375             goto fin;
2376         }
2377         if (NULL == (fp = fdopen(fd, "w")))
2378         {
2379             os_log(log_handle, "fdopen: %s", strerror(errno));
2380             *err = kHelperErr_RacoonConfigCreationFailed;
2381             goto fin;
2382         }
2383         
2384         fd = -1;
2385         fprintf(fp, config, configHeader, (!rmt_port ? ro6 : ro), rmt_port, id, id, ri, li, li, ri);
2386         fclose(fp);
2387         fp = NULL;
2388         
2389         if (0 > rename(tmp_path, path))
2390         {
2391             os_log(log_handle, "rename \"%s\" \"%s\" failed: %s", tmp_path, path, strerror(errno));
2392             *err = kHelperErr_RacoonConfigCreationFailed;
2393             goto fin;
2394         }
2395     }
2396     else
2397     {
2398         if (0 != unlink(path))
2399             os_log_debug(log_handle, "unlink \"%s\" failed: %s", path, strerror(errno));
2400     }
2401     
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)))
2405         goto fin;
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)))
2410         goto fin;
2411     
2412     if (0 != (*err = teardownTunnelRoute(rmt_inner)))
2413         goto fin;
2414     
2415     if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
2416         0 != (*err = setupTunnelRoute(loc_inner, rmt_inner)))
2417         goto fin;
2418     
2419     if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
2420         0 != (*err = kickRacoon()))
2421         goto fin;
2422     
2423     os_log_debug(log_handle, "succeeded");
2424     
2425 fin:
2426     if (NULL != fp)
2427         fclose(fp);
2428     if (0 <= fd)
2429         close(fd);
2430     unlink(tmp_path);
2431 #else
2432     (void)replacedelete; (void)loc_inner; (void)loc_outer6; (void)loc_port; (void)rmt_inner;
2433     (void)rmt_outer6; (void)rmt_port; (void)id;
2434     
2435     *err = kHelperErr_IPsecDisabled;
2436 #endif /* MDNS_NO_IPSEC */
2437     update_idle_timer();
2438     return KERN_SUCCESS;
2439 }
2440
2441
2442
2443