source: rtems-libbsd/mDNSResponder/mDNSMacOSX/helper.c @ 2723609

55-freebsd-126-freebsd-12
Last change on this file since 2723609 was 2723609, checked in by Sebastian Huber <sebastian.huber@…>, on 09/19/18 at 06:57:22

mDNSResponder: Update to v878.30.4

The sources can be obtained via:

https://opensource.apple.com/tarballs/mDNSResponder/mDNSResponder-878.30.4.tar.gz

Close #3522.

  • Property mode set to 100644
File size: 83.4 KB
Line 
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
80typedef struct sadb_x_policy *ipsec_policy_t;
81
82uid_t mDNSResponderUID;
83gid_t mDNSResponderGID;
84
85void helper_exit()
86{
87    os_log_info(log_handle,"mDNSResponderHelper exiting");
88    exit(0);
89}
90
91mDNSexport 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
121void 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
189void 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
321void 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
347char usercompname[MAX_DOMAIN_LABEL+1] = {0}; // the last computer name the user saw
348char userhostname[MAX_DOMAIN_LABEL+1] = {0}; // the last local host name the user saw
349char lastcompname[MAX_DOMAIN_LABEL+1] = {0}; // the last computer name saved to preferences
350char lasthostname[MAX_DOMAIN_LABEL+1] = {0}; // the last local host name saved to preferences
351
352#ifndef NO_CFUSERNOTIFICATION
353static CFStringRef CFS_OQ = NULL;
354static CFStringRef CFS_CQ = NULL;
355static CFStringRef CFS_Format = NULL;
356static CFStringRef CFS_ComputerName = NULL;
357static CFStringRef CFS_ComputerNameMsg = NULL;
358static CFStringRef CFS_LocalHostName = NULL;
359static CFStringRef CFS_LocalHostNameMsg = NULL;
360static CFStringRef CFS_Problem = NULL;
361
362static CFUserNotificationRef gNotification    = NULL;
363static CFRunLoopSourceRef gNotificationRLS = NULL;
364
365static 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
392static 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
424static 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
498static 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
562void 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   
695fin:
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
711enum 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
723static const char btmmprefix[] = "btmmdns:";
724static const char dnsprefix[] = "dns:";
725static const char ddns[] = "ddns";
726static const char ddnsrev[] = "sndd";
727
728static 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   
797skip:
798    SecKeychainItemFreeAttributesAndData(attributes, NULL);
799    return formatNotDNSKey;
800}
801
802// Insert the attributes as defined by mDNSKeyChainAttributes
803static 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   
878error:
879    if (NULL != entry)
880        CFRelease(entry);
881    return NULL;
882}
883#endif
884
885void 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   
966fin:
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
996CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
997CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
998
999
1000void 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.
1105void 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
1134static 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
1170static 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
1178static 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
1229void 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   
1382again:
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
1410void 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
1482static const char configHeader[] = "# BackToMyMac\n";
1483static const char g_racoon_config_dir[] = "/var/run/racoon/";
1484static const char g_racoon_config_dir_old[] = "/etc/racoon/remote/";
1485
1486static 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
1507static 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
1522static int RacoonSignal()
1523{
1524    return UseOldRacoon() ? SIGHUP : SIGUSR1;
1525}
1526
1527static 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
1573static const char* GetRacoonConfigDir()
1574{
1575    return UseOldRacoon() ? g_racoon_config_dir_old : g_racoon_config_dir;
1576}
1577/*
1578static const char* GetOldRacoonConfigDir()
1579{
1580    return UseOldRacoon() ? NULL : g_racoon_config_dir_old;
1581}
1582*/
1583
1584static 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
1607static 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
1664typedef 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
1674static 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
1765static int kickRacoon(void)
1766{
1767    if ( 0 == notifyRacoon() )
1768        return 0;
1769    return UseOldRacoon() ? startRacoonOld() : startRacoon();
1770}
1771
1772typedef 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
1781typedef enum _mDNSTunnelType
1782{
1783    kmDNSNoTunnel,
1784    kmDNSIPv6IPv4Tunnel,
1785    kmDNSIPv6IPv6Tunnel
1786} mDNSTunnelType;
1787
1788static const uint8_t kWholeV6Mask = 128;
1789
1790static unsigned int routeSeq = 1;
1791
1792static 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   
1843fin:
1844    if (0 <= s)
1845        close(s);
1846    return err;
1847}
1848
1849static 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   
1889fin:
1890    if (0 <= s)
1891        close(s);
1892    return err;
1893}
1894
1895static 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
1908static 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
1921static 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' */
1961static 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   
2028fin:
2029    return err;
2030}
2031
2032static 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   
2062fin:
2063    return err;
2064}
2065
2066static 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   
2091fin:
2092    return err;
2093}
2094
2095static 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   
2207fin:
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
2217int 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   
2425fin:
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
Note: See TracBrowser for help on using the repository browser.