]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/helper.c
mDNSResponder-544.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / helper.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2007-2012 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 <asl.h>
34 #include <ctype.h>
35 #include <dirent.h>
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <signal.h>
39 #include <stdarg.h>
40 #include <stdbool.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <Security/Security.h>
44 #include <SystemConfiguration/SystemConfiguration.h>
45 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
46 #include <TargetConditionals.h>
47 #include <IOKit/pwr_mgt/IOPMLib.h>
48 #include <net/bpf.h>
49 #include <sys/sysctl.h>
50
51 #include "mDNSEmbeddedAPI.h"
52 #include "dns_sd.h"
53 #include "dnssd_ipc.h"
54 #include "libpfkey.h"
55 #include "helper.h"
56 #include "helpermsgServer.h"
57 #include "helper-server.h"
58 #include "ipsec_options.h"
59 #include "P2PPacketFilter.h"
60
61 #include <netinet/ip.h>
62 #include <netinet/tcp.h>
63
64 #ifndef RTF_IFSCOPE
65 #define RTF_IFSCOPE 0x1000000
66 #endif
67
68 #if TARGET_OS_EMBEDDED
69 #ifndef MDNS_NO_IPSEC
70 #define MDNS_NO_IPSEC 1
71 #endif
72 #define NO_CFUSERNOTIFICATION 1
73 #define NO_SECURITYFRAMEWORK 1
74 #endif
75
76 // Embed the client stub code here, so we can access private functions like ConnectToServer, create_hdr, deliver_request
77 #include "../mDNSShared/dnssd_ipc.c"
78 #include "../mDNSShared/dnssd_clientstub.c"
79
80 typedef struct sadb_x_policy *ipsec_policy_t;
81
82 unsigned short InetChecksum(unsigned short *ptr,int nbytes);
83 unsigned long in_cksum(unsigned short *ptr,int nbytes);
84 void TCPCheckSum(int af, struct tcphdr *t, int tcplen, v6addr_t sadd6, v6addr_t dadd6);
85
86 uid_t mDNSResponderUID;
87 gid_t mDNSResponderGID;
88
89 void
90 debug_(const char *func, const char *fmt, ...)
91 {
92 char buf[2048];
93 va_list ap;
94
95 va_start(ap, fmt);
96 vsnprintf(buf, sizeof(buf), fmt, ap);
97 va_end(ap);
98 helplog(ASL_LEVEL_DEBUG, "%s: %s", func, buf);
99 }
100
101 static int
102 authorized(audit_token_t *token)
103 {
104 int ok = 0;
105 pid_t pid = (pid_t)-1;
106 uid_t euid = (uid_t)-1;
107
108 audit_token_to_au32(*token, NULL, &euid, NULL, NULL, NULL, &pid, NULL,
109 NULL);
110 ok = (euid == mDNSResponderUID || euid == 0);
111 if (!ok)
112 helplog(ASL_LEVEL_NOTICE,
113 "Unauthorized access by euid=%lu pid=%lu",
114 (unsigned long)euid, (unsigned long)pid);
115 return ok;
116 }
117
118 kern_return_t
119 do_mDNSExit(__unused mach_port_t port, audit_token_t token)
120 {
121 debug("entry");
122 if (!authorized(&token))
123 goto fin;
124 helplog(ASL_LEVEL_INFO, "exit");
125 exit(0);
126
127 fin:
128 debug("fin");
129 return KERN_SUCCESS;
130 }
131
132 kern_return_t do_mDNSRequestBPF(__unused mach_port_t port, audit_token_t token)
133 {
134 if (!authorized(&token)) return KERN_SUCCESS;
135 DNSServiceRef ref;
136 DNSServiceErrorType err = ConnectToServer(&ref, 0, send_bpf, NULL, NULL, NULL);
137 if (err) { helplog(ASL_LEVEL_ERR, "do_mDNSRequestBPF: ConnectToServer %d", err); return err; }
138
139 char *ptr;
140 size_t len = sizeof(DNSServiceFlags);
141 ipc_msg_hdr *hdr = create_hdr(send_bpf, &len, &ptr, 0, ref);
142 if (!hdr) { DNSServiceRefDeallocate(ref); return kDNSServiceErr_NoMemory; }
143 put_flags(0, &ptr);
144 deliver_request(hdr, ref); // Will free hdr for us
145 DNSServiceRefDeallocate(ref);
146 update_idle_timer();
147 return KERN_SUCCESS;
148 }
149
150 kern_return_t do_mDNSPowerRequest(__unused mach_port_t port, int key, int interval, int *err, audit_token_t token)
151 {
152 *err = -1;
153 if (!authorized(&token)) { *err = kmDNSHelperNotAuthorized; goto fin; }
154
155 CFArrayRef events = IOPMCopyScheduledPowerEvents();
156 if (events)
157 {
158 int i;
159 CFIndex count = CFArrayGetCount(events);
160 for (i=0; i<count; i++)
161 {
162 CFDictionaryRef dict = CFArrayGetValueAtIndex(events, i);
163 CFStringRef id = CFDictionaryGetValue(dict, CFSTR(kIOPMPowerEventAppNameKey));
164 if (CFEqual(id, CFSTR("mDNSResponderHelper")))
165 {
166 CFDateRef EventTime = CFDictionaryGetValue(dict, CFSTR(kIOPMPowerEventTimeKey));
167 CFStringRef EventType = CFDictionaryGetValue(dict, CFSTR(kIOPMPowerEventTypeKey));
168 IOReturn result = IOPMCancelScheduledPowerEvent(EventTime, id, EventType);
169 //helplog(ASL_LEVEL_ERR, "Deleting old event %s");
170 if (result) helplog(ASL_LEVEL_ERR, "IOPMCancelScheduledPowerEvent %d failed %d", i, result);
171 }
172 }
173 CFRelease(events);
174 }
175
176 if (key < 0) // mDNSPowerRequest(-1,-1) means "clear any stale schedules" (see above)
177 *err = 0;
178 else if (key == 0) // mDNSPowerRequest(0, 0) means "sleep now"
179 {
180 IOReturn r = IOPMSleepSystem(IOPMFindPowerManagement(MACH_PORT_NULL));
181 if (r) { usleep(100000); helplog(ASL_LEVEL_ERR, "IOPMSleepSystem %d", r); }
182 *err = r;
183 }
184 else if (key > 0)
185 {
186 CFDateRef w = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent() + interval);
187 if (w)
188 {
189 IOReturn r = IOPMSchedulePowerEvent(w, CFSTR("mDNSResponderHelper"), key ? CFSTR(kIOPMAutoWake) : CFSTR(kIOPMAutoSleep));
190 if (r) { usleep(100000); helplog(ASL_LEVEL_ERR, "IOPMSchedulePowerEvent(%d) %d %x", interval, r, r); }
191 *err = r;
192 CFRelease(w);
193 }
194 }
195 fin:
196 update_idle_timer();
197 return KERN_SUCCESS;
198 }
199
200 kern_return_t do_mDNSSetLocalAddressCacheEntry(__unused mach_port_t port, int ifindex, int family, v6addr_t ip, ethaddr_t eth, int *err, audit_token_t token)
201 {
202 #define IPv6FMTSTRING "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X"
203 #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]
204 #if 0
205 if (family == 4)
206 helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry %d IPv%d %d.%d.%d.%d %02X:%02X:%02X:%02X:%02X:%02X",
207 ifindex, family, ip[0], ip[1], ip[2], ip[3], eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
208 else
209 helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry %d IPv%d " IPv6FMTSTRING " %02X:%02X:%02X:%02X:%02X:%02X",
210 ifindex, family, IPv6FMTARGS, eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
211 #endif
212
213 *err = -1;
214 if (!authorized(&token)) { *err = kmDNSHelperNotAuthorized; goto fin; }
215
216 static int s = -1, seq = 0;
217 if (s < 0)
218 {
219 s = socket(PF_ROUTE, SOCK_RAW, 0);
220 if (s < 0) helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: socket(PF_ROUTE, SOCK_RAW, 0) failed %d (%s)", errno, strerror(errno));
221 }
222
223 if (s >= 0)
224 {
225 struct timeval tv;
226 gettimeofday(&tv, 0);
227 if (family == 4)
228 {
229 struct { struct rt_msghdr hdr; struct sockaddr_inarp dst; struct sockaddr_dl sdl; } rtmsg;
230 memset(&rtmsg, 0, sizeof(rtmsg));
231
232 rtmsg.hdr.rtm_msglen = sizeof(rtmsg);
233 rtmsg.hdr.rtm_version = RTM_VERSION;
234 rtmsg.hdr.rtm_type = RTM_ADD;
235 rtmsg.hdr.rtm_index = ifindex;
236 rtmsg.hdr.rtm_flags = RTF_HOST | RTF_STATIC | RTF_IFSCOPE;
237 rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
238 rtmsg.hdr.rtm_pid = 0;
239 rtmsg.hdr.rtm_seq = seq++;
240 rtmsg.hdr.rtm_errno = 0;
241 rtmsg.hdr.rtm_use = 0;
242 rtmsg.hdr.rtm_inits = RTV_EXPIRE;
243 rtmsg.hdr.rtm_rmx.rmx_expire = tv.tv_sec + 30;
244
245 rtmsg.dst.sin_len = sizeof(rtmsg.dst);
246 rtmsg.dst.sin_family = AF_INET;
247 rtmsg.dst.sin_port = 0;
248 rtmsg.dst.sin_addr.s_addr = *(in_addr_t*)ip;
249 rtmsg.dst.sin_srcaddr.s_addr = 0;
250 rtmsg.dst.sin_tos = 0;
251 rtmsg.dst.sin_other = 0;
252
253 rtmsg.sdl.sdl_len = sizeof(rtmsg.sdl);
254 rtmsg.sdl.sdl_family = AF_LINK;
255 rtmsg.sdl.sdl_index = ifindex;
256 rtmsg.sdl.sdl_type = IFT_ETHER;
257 rtmsg.sdl.sdl_nlen = 0;
258 rtmsg.sdl.sdl_alen = ETHER_ADDR_LEN;
259 rtmsg.sdl.sdl_slen = 0;
260
261 // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h)
262 memcpy(rtmsg.sdl.sdl_data, eth, sizeof(ethaddr_t));
263
264 int len = write(s, (char *)&rtmsg, sizeof(rtmsg));
265 if (len < 0)
266 helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: write(%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s)",
267 sizeof(rtmsg), ifindex, ip[0], ip[1], ip[2], ip[3], rtmsg.hdr.rtm_seq, len, errno, strerror(errno));
268 len = read(s, (char *)&rtmsg, sizeof(rtmsg));
269 if (len < 0 || rtmsg.hdr.rtm_errno)
270 helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: read (%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s) %d",
271 sizeof(rtmsg), ifindex, ip[0], ip[1], ip[2], ip[3], rtmsg.hdr.rtm_seq, len, errno, strerror(errno), rtmsg.hdr.rtm_errno);
272
273 *err = 0;
274 }
275 else
276 {
277 struct { struct rt_msghdr hdr; struct sockaddr_in6 dst; struct sockaddr_dl sdl; } rtmsg;
278 memset(&rtmsg, 0, sizeof(rtmsg));
279
280 rtmsg.hdr.rtm_msglen = sizeof(rtmsg);
281 rtmsg.hdr.rtm_version = RTM_VERSION;
282 rtmsg.hdr.rtm_type = RTM_ADD;
283 rtmsg.hdr.rtm_index = ifindex;
284 rtmsg.hdr.rtm_flags = RTF_HOST | RTF_STATIC | RTF_IFSCOPE;
285 rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
286 rtmsg.hdr.rtm_pid = 0;
287 rtmsg.hdr.rtm_seq = seq++;
288 rtmsg.hdr.rtm_errno = 0;
289 rtmsg.hdr.rtm_use = 0;
290 rtmsg.hdr.rtm_inits = RTV_EXPIRE;
291 rtmsg.hdr.rtm_rmx.rmx_expire = tv.tv_sec + 30;
292
293 rtmsg.dst.sin6_len = sizeof(rtmsg.dst);
294 rtmsg.dst.sin6_family = AF_INET6;
295 rtmsg.dst.sin6_port = 0;
296 rtmsg.dst.sin6_flowinfo = 0;
297 rtmsg.dst.sin6_addr = *(struct in6_addr*)ip;
298 rtmsg.dst.sin6_scope_id = ifindex;
299
300 rtmsg.sdl.sdl_len = sizeof(rtmsg.sdl);
301 rtmsg.sdl.sdl_family = AF_LINK;
302 rtmsg.sdl.sdl_index = ifindex;
303 rtmsg.sdl.sdl_type = IFT_ETHER;
304 rtmsg.sdl.sdl_nlen = 0;
305 rtmsg.sdl.sdl_alen = ETHER_ADDR_LEN;
306 rtmsg.sdl.sdl_slen = 0;
307
308 // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h)
309 memcpy(rtmsg.sdl.sdl_data, eth, sizeof(ethaddr_t));
310
311 int len = write(s, (char *)&rtmsg, sizeof(rtmsg));
312 if (len < 0)
313 helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: write(%d) interface %d address " IPv6FMTSTRING " seq %d result %d errno %d (%s)",
314 sizeof(rtmsg), ifindex, IPv6FMTARGS, rtmsg.hdr.rtm_seq, len, errno, strerror(errno));
315 len = read(s, (char *)&rtmsg, sizeof(rtmsg));
316 if (len < 0 || rtmsg.hdr.rtm_errno)
317 helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: read (%d) interface %d address " IPv6FMTSTRING " seq %d result %d errno %d (%s) %d",
318 sizeof(rtmsg), ifindex, IPv6FMTARGS, rtmsg.hdr.rtm_seq, len, errno, strerror(errno), rtmsg.hdr.rtm_errno);
319
320 *err = 0;
321 }
322
323 }
324
325 fin:
326 update_idle_timer();
327 return KERN_SUCCESS;
328 }
329
330 kern_return_t do_mDNSNotify(__unused mach_port_t port, const char *title, const char *msg, audit_token_t token)
331 {
332 if (!authorized(&token)) return KERN_SUCCESS;
333
334 #ifndef NO_CFUSERNOTIFICATION
335 static const char footer[] = "(Note: This message only appears on machines with 17.x.x.x IP addresses — i.e. at Apple — not on customer machines.)";
336 CFStringRef alertHeader = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8);
337 CFStringRef alertBody = CFStringCreateWithCString(NULL, msg, kCFStringEncodingUTF8);
338 CFStringRef alertFooter = CFStringCreateWithCString(NULL, footer, kCFStringEncodingUTF8);
339 CFStringRef alertMessage = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@\r\r%@"), alertBody, alertFooter);
340 CFRelease(alertBody);
341 CFRelease(alertFooter);
342 int err = CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL, alertHeader, alertMessage, NULL);
343 if (err) helplog(ASL_LEVEL_ERR, "CFUserNotificationDisplayNotice returned %d", err);
344 CFRelease(alertHeader);
345 CFRelease(alertMessage);
346 #else
347 (void)title;
348 (void)msg;
349 #endif /* NO_CFUSERNOTIFICATION */
350
351 update_idle_timer();
352 return KERN_SUCCESS;
353 }
354
355 char usercompname[MAX_DOMAIN_LABEL+1] = {0}; // the last computer name the user saw
356 char userhostname[MAX_DOMAIN_LABEL+1] = {0}; // the last local host name the user saw
357 char lastcompname[MAX_DOMAIN_LABEL+1] = {0}; // the last computer name saved to preferences
358 char lasthostname[MAX_DOMAIN_LABEL+1] = {0}; // the last local host name saved to preferences
359
360 #ifndef NO_CFUSERNOTIFICATION
361 static CFStringRef CFS_OQ = NULL;
362 static CFStringRef CFS_CQ = NULL;
363 static CFStringRef CFS_Format = NULL;
364 static CFStringRef CFS_ComputerName = NULL;
365 static CFStringRef CFS_ComputerNameMsg = NULL;
366 static CFStringRef CFS_LocalHostName = NULL;
367 static CFStringRef CFS_LocalHostNameMsg = NULL;
368 static CFStringRef CFS_Problem = NULL;
369
370 static CFUserNotificationRef gNotification = NULL;
371 static CFRunLoopSourceRef gNotificationRLS = NULL;
372
373 static void NotificationCallBackDismissed(CFUserNotificationRef userNotification, CFOptionFlags responseFlags)
374 {
375 debug("entry");
376 (void)responseFlags; // Unused
377 if (userNotification != gNotification) helplog(ASL_LEVEL_ERR, "NotificationCallBackDismissed: Wrong CFUserNotificationRef");
378 if (gNotificationRLS)
379 {
380 // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
381 // We need to explicitly specify the desired CFRunLoop from which we want to remove this event source.
382 CFRunLoopRemoveSource(gRunLoop, gNotificationRLS, kCFRunLoopDefaultMode);
383 CFRelease(gNotificationRLS);
384 gNotificationRLS = NULL;
385 CFRelease(gNotification);
386 gNotification = NULL;
387 }
388 // By dismissing the alert, the user has conceptually acknowleged the rename.
389 // (e.g. the machine's name is now officially "computer-2.local", not "computer.local".)
390 // If we get *another* conflict, the new alert should refer to the 'old' name
391 // as now being "computer-2.local", not "computer.local"
392 usercompname[0] = 0;
393 userhostname[0] = 0;
394 lastcompname[0] = 0;
395 lasthostname[0] = 0;
396 update_idle_timer();
397 unpause_idle_timer();
398 }
399
400 static void ShowNameConflictNotification(CFMutableArrayRef header, CFStringRef subtext)
401 {
402 CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
403 if (!dictionary) return;
404
405 debug("entry");
406
407 CFDictionarySetValue(dictionary, kCFUserNotificationAlertHeaderKey, header);
408 CFDictionarySetValue(dictionary, kCFUserNotificationAlertMessageKey, subtext);
409
410 CFURLRef urlRef = CFURLCreateWithFileSystemPath(NULL, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle, true);
411 if (urlRef) { CFDictionarySetValue(dictionary, kCFUserNotificationLocalizationURLKey, urlRef); CFRelease(urlRef); }
412
413 if (gNotification) // If notification already on-screen, update it in place
414 CFUserNotificationUpdate(gNotification, 0, kCFUserNotificationCautionAlertLevel, dictionary);
415 else // else, we need to create it
416 {
417 SInt32 error;
418 gNotification = CFUserNotificationCreate(NULL, 0, kCFUserNotificationCautionAlertLevel, &error, dictionary);
419 if (!gNotification || error) { helplog(ASL_LEVEL_ERR, "ShowNameConflictNotification: CFUserNotificationRef: Error %d", error); return; }
420 gNotificationRLS = CFUserNotificationCreateRunLoopSource(NULL, gNotification, NotificationCallBackDismissed, 0);
421 if (!gNotificationRLS) { helplog(ASL_LEVEL_ERR,"ShowNameConflictNotification: RLS"); CFRelease(gNotification); gNotification = NULL; return; }
422 // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
423 // We need to explicitly specify the desired CFRunLoop to which we want to add this event source.
424 CFRunLoopAddSource(gRunLoop, gNotificationRLS, kCFRunLoopDefaultMode);
425 debug("gRunLoop=%p gNotification=%p gNotificationRLS=%p", gRunLoop, gNotification, gNotificationRLS);
426 pause_idle_timer();
427 }
428
429 CFRelease(dictionary);
430 }
431
432 static CFMutableArrayRef GetHeader(const char* oldname, const char* newname, const CFStringRef msg, const char* suffix)
433 {
434 CFMutableArrayRef alertHeader = NULL;
435
436 const CFStringRef cfoldname = CFStringCreateWithCString(NULL, oldname, kCFStringEncodingUTF8);
437 // NULL newname means we've given up trying to construct a name that doesn't conflict
438 const CFStringRef cfnewname = newname ? CFStringCreateWithCString(NULL, newname, kCFStringEncodingUTF8) : NULL;
439 // We tag a zero-width non-breaking space at the end of the literal text to guarantee that, no matter what
440 // arbitrary computer name the user may choose, this exact text (with zero-width non-breaking space added)
441 // can never be one that occurs in the Localizable.strings translation file.
442 if (!cfoldname)
443 helplog(ASL_LEVEL_ERR,"Could not construct CFStrings for old=%s", newname);
444 else if (newname && !cfnewname)
445 helplog(ASL_LEVEL_ERR,"Could not construct CFStrings for new=%s", newname);
446 else
447 {
448 const CFStringRef s1 = CFStringCreateWithFormat(NULL, NULL, CFS_Format, cfoldname, suffix);
449 const CFStringRef s2 = cfnewname ? CFStringCreateWithFormat(NULL, NULL, CFS_Format, cfnewname, suffix) : NULL;
450
451 alertHeader = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
452
453 if (!s1)
454 helplog(ASL_LEVEL_ERR, "Could not construct secondary CFString for old=%s", oldname);
455 else if (cfnewname && !s2)
456 helplog(ASL_LEVEL_ERR, "Could not construct secondary CFString for new=%s", newname);
457 else if (!alertHeader)
458 helplog(ASL_LEVEL_ERR, "Could not construct CFArray for notification");
459 else
460 {
461 // Make sure someone is logged in. We don't want this popping up over the login window
462 uid_t uid;
463 gid_t gid;
464 CFStringRef userName = SCDynamicStoreCopyConsoleUser(NULL, &uid, &gid);
465 if (userName)
466 {
467 CFRelease(userName);
468 CFArrayAppendValue(alertHeader, msg); // Opening phrase of message, provided by caller
469 CFArrayAppendValue(alertHeader, CFS_OQ); CFArrayAppendValue(alertHeader, s1); CFArrayAppendValue(alertHeader, CFS_CQ);
470 CFArrayAppendValue(alertHeader, CFSTR(" is already in use on this network. "));
471 if (s2)
472 {
473 CFArrayAppendValue(alertHeader, CFSTR("The name has been changed to "));
474 CFArrayAppendValue(alertHeader, CFS_OQ); CFArrayAppendValue(alertHeader, s2); CFArrayAppendValue(alertHeader, CFS_CQ);
475 CFArrayAppendValue(alertHeader, CFSTR("."));
476 }
477 else
478 CFArrayAppendValue(alertHeader, CFSTR("All attempts to find an available name by adding a number to the name were also unsuccessful."));
479 }
480 }
481 if (s1) CFRelease(s1);
482 if (s2) CFRelease(s2);
483 }
484 if (cfoldname) CFRelease(cfoldname);
485 if (cfnewname) CFRelease(cfnewname);
486
487 return alertHeader;
488 }
489 #endif /* ndef NO_CFUSERNOTIFICATION */
490
491 static void update_notification(void)
492 {
493 #ifndef NO_CFUSERNOTIFICATION
494 debug("entry ucn=%s, uhn=%s, lcn=%s, lhn=%s", usercompname, userhostname, lastcompname, lasthostname);
495 if (!CFS_OQ)
496 {
497 // Note: the "\xEF\xBB\xBF" byte sequence in the CFS_Format string is the UTF-8 encoding of the zero-width non-breaking space character.
498 // By appending this invisible character on the end of literal names, we ensure the these strings cannot inadvertently match any string
499 // in the localization file -- since we know for sure that none of our strings in the localization file contain the ZWNBS character.
500 //
501 // For languages that are written right to left, when we mix English (host names could be in english with brackets etc. and the
502 // rest in Arabic) we need unicode markups for proper formatting. The Unicode sequence 202C (UTF8 E2 80 AC), 200E (UTF8 E2 80 8E) and
503 // 202B (UTF8 E2 80 AB) helps with the formatting. See <rdar://problem/8629082> for more details.
504 CFS_OQ = CFStringCreateWithCString(NULL, "“\xE2\x80\xAB", kCFStringEncodingUTF8);
505 CFS_CQ = CFStringCreateWithCString(NULL, "\xE2\x80\xAC”", kCFStringEncodingUTF8);
506 CFS_Format = CFStringCreateWithCString(NULL, "%@%s\xEF\xBB\xBF\xE2\x80\x8E", kCFStringEncodingUTF8);
507 CFS_ComputerName = CFStringCreateWithCString(NULL, "The name of your computer ", kCFStringEncodingUTF8);
508 CFS_ComputerNameMsg = CFStringCreateWithCString(NULL, "To change the name of your computer, "
509 "open System Preferences and click Sharing, then type the name in the Computer Name field.", kCFStringEncodingUTF8);
510 CFS_LocalHostName = CFStringCreateWithCString(NULL, "This computer’s local hostname ", kCFStringEncodingUTF8);
511 CFS_LocalHostNameMsg = CFStringCreateWithCString(NULL, "To change the local hostname, "
512 "open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field.", kCFStringEncodingUTF8);
513 CFS_Problem = CFStringCreateWithCString(NULL, "This may indicate a problem with the local network. "
514 "Please inform your network administrator.", kCFStringEncodingUTF8);
515 }
516
517 if (!usercompname[0] && !userhostname[0])
518 {
519 if (gNotificationRLS)
520 {
521 debug("canceling notification %p", gNotification);
522 CFUserNotificationCancel(gNotification);
523 unpause_idle_timer();
524 }
525 }
526 else
527 {
528 CFMutableArrayRef header = NULL;
529 CFStringRef* subtext = NULL;
530 if (userhostname[0] && !lasthostname[0]) // we've given up trying to construct a name that doesn't conflict
531 {
532 header = GetHeader(userhostname, NULL, CFS_LocalHostName, ".local");
533 subtext = &CFS_Problem;
534 }
535 else if (usercompname[0])
536 {
537 header = GetHeader(usercompname, lastcompname, CFS_ComputerName, "");
538 subtext = &CFS_ComputerNameMsg;
539 }
540 else
541 {
542 header = GetHeader(userhostname, lasthostname, CFS_LocalHostName, ".local");
543 subtext = &CFS_LocalHostNameMsg;
544 }
545 ShowNameConflictNotification(header, *subtext);
546 CFRelease(header);
547 }
548 #endif
549 }
550
551 kern_return_t
552 do_mDNSPreferencesSetName(__unused mach_port_t port, int key, const char* old, const char* new, audit_token_t token)
553 {
554 SCPreferencesRef session = NULL;
555 Boolean ok = FALSE;
556 Boolean locked = FALSE;
557 CFStringRef cfstr = NULL;
558 char* user = NULL;
559 char* last = NULL;
560 Boolean needUpdate = FALSE;
561
562 debug("entry %s old=%s new=%s", key==kmDNSComputerName ? "ComputerName" : (key==kmDNSLocalHostName ? "LocalHostName" : "UNKNOWN"), old, new);
563 if (!authorized(&token)) goto fin;
564
565 switch ((enum mDNSPreferencesSetNameKey)key)
566 {
567 case kmDNSComputerName:
568 user = usercompname;
569 last = lastcompname;
570 break;
571 case kmDNSLocalHostName:
572 user = userhostname;
573 last = lasthostname;
574 break;
575 default:
576 debug("unrecognized key: %d", key);
577 goto fin;
578 }
579
580 if (!last)
581 {
582 helplog(ASL_LEVEL_ERR, "%s: no last ptr", __func__);
583 goto fin;
584 }
585
586 if (!user)
587 {
588 helplog(ASL_LEVEL_ERR, "%s: no user ptr", __func__);
589 goto fin;
590 }
591
592 if (0 == strncmp(old, new, MAX_DOMAIN_LABEL+1))
593 {
594 // old and new are same means the config changed i.e, the user has set something in the preferences pane.
595 // This means the conflict has been resolved. We need to dismiss the dialogue.
596 if (last[0] && 0 != strncmp(last, new, MAX_DOMAIN_LABEL+1))
597 {
598 last[0] = 0;
599 user[0] = 0;
600 needUpdate = TRUE;
601 }
602 goto fin;
603 }
604 else
605 {
606 // old and new are not same, this means there is a conflict. For the first conflict, we show
607 // the old value and the new value. For all subsequent conflicts, while the dialogue is still
608 // up, we do a real time update of the "new" value in the dialogue. That's why we update just
609 // "last" here and not "user".
610 if (strncmp(last, new, MAX_DOMAIN_LABEL+1))
611 {
612 strncpy(last, new, MAX_DOMAIN_LABEL);
613 needUpdate = TRUE;
614 }
615 }
616
617 // If we are not showing the dialogue, we need to remember the first "old" value so that
618 // we maintain the same through the lifetime of the dialogue. Subsequence conflicts don't
619 // update the "old" value.
620 if (!user[0])
621 {
622 strncpy(user, old, MAX_DOMAIN_LABEL);
623 needUpdate = TRUE;
624 }
625
626 if (!new[0]) // we've given up trying to construct a name that doesn't conflict
627 goto fin;
628
629 cfstr = CFStringCreateWithCString(NULL, new, kCFStringEncodingUTF8);
630
631 session = SCPreferencesCreate(NULL, CFSTR(kmDNSHelperServiceName), NULL);
632
633 if (cfstr == NULL || session == NULL)
634 {
635 debug("SCPreferencesCreate failed");
636 goto fin;
637 }
638 if (!SCPreferencesLock(session, 0))
639 {
640 debug("lock failed");
641 goto fin;
642 }
643 locked = TRUE;
644
645 switch ((enum mDNSPreferencesSetNameKey)key)
646 {
647 case kmDNSComputerName:
648 {
649 // We want to write the new Computer Name to System Preferences, without disturbing the user-selected
650 // system-wide default character set used for things like AppleTalk NBP and NETBIOS service advertising.
651 // Note that this encoding is not used for the computer name, but since both are set by the same call,
652 // we need to take care to set the name without changing the character set.
653 CFStringEncoding encoding = kCFStringEncodingUTF8;
654 CFStringRef unused = SCDynamicStoreCopyComputerName(NULL, &encoding);
655 if (unused) { CFRelease(unused); unused = NULL; }
656 else encoding = kCFStringEncodingUTF8;
657
658 ok = SCPreferencesSetComputerName(session, cfstr, encoding);
659 }
660 break;
661 case kmDNSLocalHostName:
662 ok = SCPreferencesSetLocalHostName(session, cfstr);
663 break;
664 default:
665 break;
666 }
667
668 if (!ok || !SCPreferencesCommitChanges(session) ||
669 !SCPreferencesApplyChanges(session))
670 {
671 debug("SCPreferences update failed");
672 goto fin;
673 }
674 debug("succeeded");
675
676 fin:
677 if (NULL != cfstr)
678 CFRelease(cfstr);
679 if (NULL != session)
680 {
681 if (locked)
682 SCPreferencesUnlock(session);
683 CFRelease(session);
684 }
685 update_idle_timer();
686 if (needUpdate) update_notification();
687 return KERN_SUCCESS;
688 }
689
690 enum DNSKeyFormat
691 {
692 formatNotDNSKey, formatDdnsTypeItem, formatDnsPrefixedServiceItem, formatBtmmPrefixedServiceItem
693 };
694
695 // On Mac OS X on Intel, the four-character string seems to be stored backwards, at least sometimes.
696 // I suspect some overenthusiastic inexperienced engineer said, "On Intel everything's backwards,
697 // therefore I need to add some byte swapping in this API to make this four-character string backwards too."
698 // To cope with this we allow *both* "ddns" and "sndd" as valid item types.
699
700
701 #ifndef NO_SECURITYFRAMEWORK
702 static const char btmmprefix[] = "btmmdns:";
703 static const char dnsprefix[] = "dns:";
704 static const char ddns[] = "ddns";
705 static const char ddnsrev[] = "sndd";
706
707 static enum DNSKeyFormat
708 getDNSKeyFormat(SecKeychainItemRef item, SecKeychainAttributeList **attributesp)
709 {
710 static UInt32 tags[4] =
711 {
712 kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr, kSecLabelItemAttr
713 };
714 static SecKeychainAttributeInfo attributeInfo =
715 {
716 sizeof(tags)/sizeof(tags[0]), tags, NULL
717 };
718 SecKeychainAttributeList *attributes = NULL;
719 enum DNSKeyFormat format;
720 Boolean malformed = FALSE;
721 OSStatus status = noErr;
722 int i = 0;
723
724 *attributesp = NULL;
725 if (noErr != (status = SecKeychainItemCopyAttributesAndData(item,
726 &attributeInfo, NULL, &attributes, NULL, NULL)))
727 {
728 debug("SecKeychainItemCopyAttributesAndData %d - skipping",
729 status);
730 goto skip;
731 }
732 if (attributeInfo.count != attributes->count)
733 malformed = TRUE;
734 for (i = 0; !malformed && i < (int)attributeInfo.count; ++i)
735 if (attributeInfo.tag[i] != attributes->attr[i].tag)
736 malformed = TRUE;
737 if (malformed)
738 {
739 debug(
740 "malformed result from SecKeychainItemCopyAttributesAndData - skipping");
741 goto skip;
742 }
743
744 debug("entry (\"%.*s\", \"%.*s\", \"%.*s\")",
745 (int)attributes->attr[0].length, attributes->attr[0].data,
746 (int)attributes->attr[1].length, attributes->attr[1].data,
747 (int)attributes->attr[2].length, attributes->attr[2].data);
748 if (attributes->attr[1].length >= MAX_ESCAPED_DOMAIN_NAME +
749 sizeof(dnsprefix)-1)
750 {
751 debug("kSecServiceItemAttr too long (%u) - skipping",
752 (unsigned int)attributes->attr[1].length);
753 goto skip;
754 }
755 if (attributes->attr[2].length >= MAX_ESCAPED_DOMAIN_NAME)
756 {
757 debug("kSecAccountItemAttr too long (%u) - skipping",
758 (unsigned int)attributes->attr[2].length);
759 goto skip;
760 }
761 if (attributes->attr[1].length >= sizeof(dnsprefix)-1 &&
762 0 == strncasecmp(attributes->attr[1].data, dnsprefix,
763 sizeof(dnsprefix)-1))
764 format = formatDnsPrefixedServiceItem;
765 else if (attributes->attr[1].length >= sizeof(btmmprefix)-1 &&
766 0 == strncasecmp(attributes->attr[1].data, btmmprefix, sizeof(btmmprefix)-1))
767 format = formatBtmmPrefixedServiceItem;
768 else if (attributes->attr[0].length == sizeof(ddns)-1 &&
769 0 == strncasecmp(attributes->attr[0].data, ddns, sizeof(ddns)-1))
770 format = formatDdnsTypeItem;
771 else if (attributes->attr[0].length == sizeof(ddnsrev)-1 &&
772 0 == strncasecmp(attributes->attr[0].data, ddnsrev, sizeof(ddnsrev)-1))
773 format = formatDdnsTypeItem;
774 else
775 {
776 debug("uninterested in this entry");
777 goto skip;
778 }
779 *attributesp = attributes;
780 debug("accepting this entry");
781 return format;
782
783 skip:
784 SecKeychainItemFreeAttributesAndData(attributes, NULL);
785 return formatNotDNSKey;
786 }
787
788 // Insert the attributes as defined by mDNSKeyChainAttributes
789 static CFPropertyListRef
790 getKeychainItemInfo(SecKeychainItemRef item,
791 SecKeychainAttributeList *attributes, enum DNSKeyFormat format)
792 {
793 CFMutableArrayRef entry = NULL;
794 CFDataRef data = NULL;
795 OSStatus status = noErr;
796 UInt32 keylen = 0;
797 void *keyp = 0;
798
799 if (NULL == (entry = CFArrayCreateMutable(NULL, 0,
800 &kCFTypeArrayCallBacks)))
801 {
802 debug("CFArrayCreateMutable failed");
803 goto error;
804 }
805
806 // Insert the Account attribute (kmDNSKcWhere)
807 switch ((enum DNSKeyFormat)format)
808 {
809 case formatDdnsTypeItem:
810 data = CFDataCreate(kCFAllocatorDefault,
811 attributes->attr[1].data, attributes->attr[1].length);
812 break;
813 case formatDnsPrefixedServiceItem:
814 case formatBtmmPrefixedServiceItem:
815 data = CFDataCreate(kCFAllocatorDefault,
816 attributes->attr[1].data, attributes->attr[1].length);
817 break;
818 default:
819 assert("unknown DNSKeyFormat value");
820 break;
821 }
822 if (NULL == data)
823 {
824 debug("CFDataCreate for attr[1] failed");
825 goto error;
826 }
827 CFArrayAppendValue(entry, data);
828 CFRelease(data);
829
830 // Insert the Where attribute (kmDNSKcAccount)
831 if (NULL == (data = CFDataCreate(kCFAllocatorDefault,
832 attributes->attr[2].data, attributes->attr[2].length)))
833 {
834 debug("CFDataCreate for attr[2] failed");
835 goto error;
836 }
837 CFArrayAppendValue(entry, data);
838 CFRelease(data);
839
840 // Insert the Key attribute (kmDNSKcKey)
841 if (noErr != (status = SecKeychainItemCopyAttributesAndData(item, NULL,
842 NULL, NULL, &keylen, &keyp)))
843 {
844 debug("could not retrieve key for \"%.*s\": %d",
845 (int)attributes->attr[1].length, attributes->attr[1].data,
846 status);
847 goto error;
848 }
849 data = CFDataCreate(kCFAllocatorDefault, keyp, keylen);
850 SecKeychainItemFreeAttributesAndData(NULL, keyp);
851 if (NULL == data)
852 {
853 debug("CFDataCreate for keyp failed");
854 goto error;
855 }
856 CFArrayAppendValue(entry, data);
857 CFRelease(data);
858
859 // Insert the Name attribute (kmDNSKcName)
860 if (NULL == (data = CFDataCreate(kCFAllocatorDefault,
861 attributes->attr[3].data, attributes->attr[3].length)))
862 {
863 debug("CFDataCreate for attr[3] failed");
864 goto error;
865 }
866 CFArrayAppendValue(entry, data);
867 CFRelease(data);
868 return entry;
869
870 error:
871 if (NULL != entry)
872 CFRelease(entry);
873 return NULL;
874 }
875 #endif
876
877 kern_return_t
878 do_mDNSKeychainGetSecrets(__unused mach_port_t port, __unused unsigned int *numsecrets,
879 __unused vm_offset_t *secrets, __unused mach_msg_type_number_t *secretsCnt, __unused int *err,
880 __unused audit_token_t token)
881 {
882 #ifndef NO_SECURITYFRAMEWORK
883 CFWriteStreamRef stream = NULL;
884 CFDataRef result = NULL;
885 CFPropertyListRef entry = NULL;
886 CFMutableArrayRef keys = NULL;
887 SecKeychainRef skc = NULL;
888 SecKeychainItemRef item = NULL;
889 SecKeychainSearchRef search = NULL;
890 SecKeychainAttributeList *attributes = NULL;
891 enum DNSKeyFormat format;
892 OSStatus status = 0;
893
894 debug("entry");
895 *err = 0;
896 *numsecrets = 0;
897 *secrets = (vm_offset_t)NULL;
898 if (!authorized(&token))
899 {
900 *err = kmDNSHelperNotAuthorized;
901 goto fin;
902 }
903 if (NULL == (keys = CFArrayCreateMutable(NULL, 0,
904 &kCFTypeArrayCallBacks)))
905 {
906 debug("CFArrayCreateMutable failed");
907 *err = kmDNSHelperCreationFailed;
908 goto fin;
909 }
910 if (noErr != (status = SecKeychainCopyDefault(&skc)))
911 {
912 *err = kmDNSHelperKeychainCopyDefaultFailed;
913 goto fin;
914 }
915 if (noErr != (status = SecKeychainSearchCreateFromAttributes(skc, kSecGenericPasswordItemClass, NULL, &search)))
916 {
917 *err = kmDNSHelperKeychainSearchCreationFailed;
918 goto fin;
919 }
920 for (status = SecKeychainSearchCopyNext(search, &item);
921 noErr == status;
922 status = SecKeychainSearchCopyNext(search, &item))
923 {
924 if (formatNotDNSKey != (format = getDNSKeyFormat(item,
925 &attributes)) &&
926 NULL != (entry = getKeychainItemInfo(item, attributes,
927 format)))
928 {
929 CFArrayAppendValue(keys, entry);
930 CFRelease(entry);
931 }
932 SecKeychainItemFreeAttributesAndData(attributes, NULL);
933 CFRelease(item);
934 }
935 if (errSecItemNotFound != status)
936 helplog(ASL_LEVEL_ERR, "%s: SecKeychainSearchCopyNext failed: %d",
937 __func__, status);
938 if (NULL == (stream =
939 CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorDefault,
940 kCFAllocatorDefault)))
941 {
942 *err = kmDNSHelperCreationFailed;
943 debug("CFWriteStreamCreateWithAllocatedBuffers failed");
944 goto fin;
945 }
946 CFWriteStreamOpen(stream);
947 if (0 == CFPropertyListWriteToStream(keys, stream,
948 kCFPropertyListBinaryFormat_v1_0, NULL))
949 {
950 *err = kmDNSHelperPListWriteFailed;
951 debug("CFPropertyListWriteToStream failed");
952 goto fin;
953 }
954 result = CFWriteStreamCopyProperty(stream,
955 kCFStreamPropertyDataWritten);
956 if (KERN_SUCCESS != vm_allocate(mach_task_self(), secrets,
957 CFDataGetLength(result), VM_FLAGS_ANYWHERE))
958 {
959 *err = kmDNSHelperCreationFailed;
960 debug("vm_allocate failed");
961 goto fin;
962 }
963 CFDataGetBytes(result, CFRangeMake(0, CFDataGetLength(result)),
964 (void *)*secrets);
965 *secretsCnt = CFDataGetLength(result);
966 *numsecrets = CFArrayGetCount(keys);
967 debug("succeeded");
968
969 fin:
970 debug("returning %u secrets", *numsecrets);
971 if (NULL != stream)
972 {
973 CFWriteStreamClose(stream);
974 CFRelease(stream);
975 }
976 if (NULL != result)
977 CFRelease(result);
978 if (NULL != keys)
979 CFRelease(keys);
980 if (NULL != search)
981 CFRelease(search);
982 if (NULL != skc)
983 CFRelease(skc);
984 update_idle_timer();
985 return KERN_SUCCESS;
986 #else
987 return KERN_FAILURE;
988 #endif
989 }
990
991 #ifndef MDNS_NO_IPSEC
992 typedef enum _mDNSTunnelPolicyWhich
993 {
994 kmDNSTunnelPolicySetup,
995 kmDNSTunnelPolicyTeardown,
996 kmDNSTunnelPolicyGenerate
997 } mDNSTunnelPolicyWhich;
998
999 // For kmDNSTunnelPolicySetup, you can setup IPv6-in-IPv6 tunnel or IPv6-in-IPv4 tunnel
1000 // kmDNSNoTunnel is used for other Policy types
1001 typedef enum _mDNSTunnelType
1002 {
1003 kmDNSNoTunnel,
1004 kmDNSIPv6IPv4Tunnel,
1005 kmDNSIPv6IPv6Tunnel
1006 } mDNSTunnelType;
1007
1008 static const uint8_t kWholeV6Mask = 128;
1009
1010 #endif /* ifndef MDNS_NO_IPSEC */
1011
1012 #ifndef MDNS_NO_IPSEC
1013
1014 static const char g_racoon_config_dir[] = "/var/run/racoon/";
1015 static const char g_racoon_config_dir_old[] = "/etc/racoon/remote/";
1016
1017 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
1018 CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
1019
1020 // Major version 6 is 10.2.x (Jaguar)
1021 // Major version 7 is 10.3.x (Panther)
1022 // Major version 8 is 10.4.x (Tiger)
1023 // Major version 9 is 10.5.x (Leopard)
1024 // Major version 10 is 10.6.x (SnowLeopard)
1025 static int MacOSXSystemBuildNumber(char* letter_out, int* minor_out)
1026 {
1027 int major = 0, minor = 0;
1028 char letter = 0, buildver[256]="<Unknown>";
1029 CFDictionaryRef vers = _CFCopySystemVersionDictionary();
1030 if (vers)
1031 {
1032 CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
1033 if (cfbuildver) CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8);
1034 sscanf(buildver, "%d%c%d", &major, &letter, &minor);
1035 CFRelease(vers);
1036 }
1037 else
1038 helplog(ASL_LEVEL_NOTICE, "_CFCopySystemVersionDictionary failed");
1039
1040 if (!major) { major=10; letter = 'A'; minor = 190; helplog(ASL_LEVEL_NOTICE, "Note: No Major Build Version number found; assuming 10A190"); }
1041 if (letter_out) *letter_out = letter;
1042 if (minor_out) *minor_out = minor;
1043 return(major);
1044 }
1045
1046 static int UseOldRacoon()
1047 {
1048 static int g_oldRacoon = -1;
1049
1050 if (g_oldRacoon == -1)
1051 {
1052 char letter = 0;
1053 int minor = 0;
1054 g_oldRacoon = (MacOSXSystemBuildNumber(&letter, &minor) < 10);
1055 debug("%s", g_oldRacoon ? "old" : "new");
1056 }
1057
1058 return g_oldRacoon;
1059 }
1060
1061 static int RacoonSignal()
1062 {
1063 return UseOldRacoon() ? SIGHUP : SIGUSR1;
1064 }
1065
1066 static const char* GetRacoonConfigDir()
1067 {
1068 return UseOldRacoon() ? g_racoon_config_dir_old : g_racoon_config_dir;
1069 }
1070
1071 static const char* GetOldRacoonConfigDir()
1072 {
1073 return UseOldRacoon() ? NULL : g_racoon_config_dir_old;
1074 }
1075
1076 static const char racoon_config_file[] = "anonymous.conf";
1077 static const char racoon_config_file_orig[] = "anonymous.conf.orig";
1078
1079 static const char configHeader[] = "# BackToMyMac\n";
1080
1081 static int IsFamiliarRacoonConfiguration(const char* racoon_config_path)
1082 {
1083 int fd = open(racoon_config_path, O_RDONLY);
1084 debug("entry %s", racoon_config_path);
1085 if (0 > fd)
1086 {
1087 helplog(ASL_LEVEL_NOTICE, "open \"%s\" failed: %s", racoon_config_path, strerror(errno));
1088 return 0;
1089 }
1090 else
1091 {
1092 char header[sizeof(configHeader)] = {0};
1093 ssize_t bytesRead = read(fd, header, sizeof(header)-1);
1094 close(fd);
1095 if (bytesRead != sizeof(header)-1) return 0;
1096 return (0 == memcmp(header, configHeader, sizeof(header)-1));
1097 }
1098 }
1099
1100 static void
1101 revertAnonymousRacoonConfiguration(const char* dir)
1102 {
1103 if (!dir) return;
1104
1105 debug("entry %s", dir);
1106
1107 char racoon_config_path[64];
1108 strlcpy(racoon_config_path, dir, sizeof(racoon_config_path));
1109 strlcat(racoon_config_path, racoon_config_file, sizeof(racoon_config_path));
1110
1111 struct stat s;
1112 int ret = stat(racoon_config_path, &s);
1113 debug("stat(%s): %d errno=%d", racoon_config_path, ret, errno);
1114 if (ret == 0)
1115 {
1116 if (IsFamiliarRacoonConfiguration(racoon_config_path))
1117 {
1118 helplog(ASL_LEVEL_INFO, "\"%s\" looks familiar, unlinking", racoon_config_path);
1119 unlink(racoon_config_path);
1120 }
1121 else
1122 {
1123 helplog(ASL_LEVEL_NOTICE, "\"%s\" does not look familiar, leaving in place", racoon_config_path);
1124 return;
1125 }
1126 }
1127 else if (errno != ENOENT)
1128 {
1129 helplog(ASL_LEVEL_NOTICE, "stat failed for \"%s\", leaving in place: %s", racoon_config_path, strerror(errno));
1130 return;
1131 }
1132
1133 char racoon_config_path_orig[64];
1134 strlcpy(racoon_config_path_orig, dir, sizeof(racoon_config_path_orig));
1135 strlcat(racoon_config_path_orig, racoon_config_file_orig, sizeof(racoon_config_path_orig));
1136
1137 ret = stat(racoon_config_path_orig, &s);
1138 debug("stat(%s): %d errno=%d", racoon_config_path_orig, ret, errno);
1139 if (ret == 0)
1140 {
1141 if (0 > rename(racoon_config_path_orig, racoon_config_path))
1142 helplog(ASL_LEVEL_NOTICE, "rename \"%s\" \"%s\" failed: %s", racoon_config_path_orig, racoon_config_path, strerror(errno));
1143 else
1144 debug("reverted \"%s\" to \"%s\"", racoon_config_path_orig, racoon_config_path);
1145 }
1146 else if (errno != ENOENT)
1147 {
1148 helplog(ASL_LEVEL_NOTICE, "stat failed for \"%s\", leaving in place: %s", racoon_config_path_orig, strerror(errno));
1149 return;
1150 }
1151 }
1152
1153 static void
1154 moveAsideAnonymousRacoonConfiguration(const char* dir)
1155 {
1156 if (!dir) return;
1157
1158 debug("entry %s", dir);
1159
1160 char racoon_config_path[64];
1161 strlcpy(racoon_config_path, dir, sizeof(racoon_config_path));
1162 strlcat(racoon_config_path, racoon_config_file, sizeof(racoon_config_path));
1163
1164 struct stat s;
1165 int ret = stat(racoon_config_path, &s);
1166 if (ret == 0)
1167 {
1168 if (IsFamiliarRacoonConfiguration(racoon_config_path))
1169 {
1170 helplog(ASL_LEVEL_INFO, "\"%s\" looks familiar, unlinking", racoon_config_path);
1171 unlink(racoon_config_path);
1172 }
1173 else
1174 {
1175 char racoon_config_path_orig[64];
1176 strlcpy(racoon_config_path_orig, dir, sizeof(racoon_config_path_orig));
1177 strlcat(racoon_config_path_orig, racoon_config_file_orig, sizeof(racoon_config_path_orig));
1178 if (0 > rename(racoon_config_path, racoon_config_path_orig)) // If we didn't write it, move it to the side so it can be reverted later
1179 helplog(ASL_LEVEL_NOTICE, "rename \"%s\" to \"%s\" failed: %s", racoon_config_path, racoon_config_path_orig, strerror(errno));
1180 else
1181 debug("successfully renamed \"%s\" to \"%s\"", racoon_config_path, racoon_config_path_orig);
1182 }
1183 }
1184 else if (errno != ENOENT)
1185 {
1186 helplog(ASL_LEVEL_NOTICE, "stat failed for \"%s\", leaving in place: %s", racoon_config_path, strerror(errno));
1187 return;
1188 }
1189 }
1190
1191 static int
1192 ensureExistenceOfRacoonConfigDir(const char* const racoon_config_dir)
1193 {
1194 struct stat s;
1195 int ret = stat(racoon_config_dir, &s);
1196 if (ret != 0)
1197 {
1198 if (errno != ENOENT)
1199 {
1200 helplog(ASL_LEVEL_ERR, "stat of \"%s\" failed (%d): %s",
1201 racoon_config_dir, ret, strerror(errno));
1202 return -1;
1203 }
1204 else
1205 {
1206 ret = mkdir(racoon_config_dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
1207 if (ret != 0)
1208 {
1209 helplog(ASL_LEVEL_ERR, "mkdir \"%s\" failed: %s",
1210 racoon_config_dir, strerror(errno));
1211 return -1;
1212 }
1213 else
1214 helplog(ASL_LEVEL_INFO, "created directory \"%s\"", racoon_config_dir);
1215 }
1216 }
1217 else if (!(s.st_mode & S_IFDIR))
1218 {
1219 helplog(ASL_LEVEL_ERR, "\"%s\" is not a directory!",
1220 racoon_config_dir);
1221 return -1;
1222 }
1223
1224 return 0;
1225 }
1226
1227 static int
1228 createAnonymousRacoonConfiguration(const char *fqdn)
1229 {
1230 static const char config1[] =
1231 "remote anonymous {\n"
1232 " exchange_mode aggressive;\n"
1233 " doi ipsec_doi;\n"
1234 " situation identity_only;\n"
1235 " verify_identifier off;\n"
1236 " generate_policy on;\n"
1237 " shared_secret keychain_by_id \"";
1238 static const char config2[] =
1239 "\";\n"
1240 " nonce_size 16;\n"
1241 " lifetime time 15 min;\n"
1242 " initial_contact on;\n"
1243 " support_proxy on;\n"
1244 " nat_traversal force;\n"
1245 " proposal_check claim;\n"
1246 " proposal {\n"
1247 " encryption_algorithm aes;\n"
1248 " hash_algorithm sha256;\n"
1249 " authentication_method pre_shared_key;\n"
1250 " dh_group 2;\n"
1251 " lifetime time 15 min;\n"
1252 " }\n"
1253 " proposal {\n"
1254 " encryption_algorithm aes;\n"
1255 " hash_algorithm sha1;\n"
1256 " authentication_method pre_shared_key;\n"
1257 " dh_group 2;\n"
1258 " lifetime time 15 min;\n"
1259 " }\n"
1260 "}\n\n"
1261 "sainfo anonymous { \n"
1262 " pfs_group 2;\n"
1263 " lifetime time 10 min;\n"
1264 " encryption_algorithm aes;\n"
1265 " authentication_algorithm hmac_sha256,hmac_sha1;\n"
1266 " compression_algorithm deflate;\n"
1267 "}\n";
1268 char tmp_config_path[64];
1269 char racoon_config_path[64];
1270 const char* const racoon_config_dir = GetRacoonConfigDir();
1271 const char* const racoon_config_dir_old = GetOldRacoonConfigDir();
1272 int fd = -1;
1273
1274 debug("entry");
1275
1276 if (0 > ensureExistenceOfRacoonConfigDir(racoon_config_dir))
1277 return -1;
1278
1279 strlcpy(tmp_config_path, racoon_config_dir, sizeof(tmp_config_path));
1280 strlcat(tmp_config_path, "tmp.XXXXXX", sizeof(tmp_config_path));
1281
1282 fd = mkstemp(tmp_config_path);
1283
1284 if (0 > fd)
1285 {
1286 helplog(ASL_LEVEL_ERR, "mkstemp \"%s\" failed: %s",
1287 tmp_config_path, strerror(errno));
1288 return -1;
1289 }
1290 write(fd, configHeader, sizeof(configHeader)-1);
1291 write(fd, config1, sizeof(config1)-1);
1292 write(fd, fqdn, strlen(fqdn));
1293 write(fd, config2, sizeof(config2)-1);
1294 close(fd);
1295
1296 strlcpy(racoon_config_path, racoon_config_dir, sizeof(racoon_config_path));
1297 strlcat(racoon_config_path, racoon_config_file, sizeof(racoon_config_path));
1298
1299 moveAsideAnonymousRacoonConfiguration(racoon_config_dir_old);
1300 moveAsideAnonymousRacoonConfiguration(racoon_config_dir);
1301
1302 if (0 > rename(tmp_config_path, racoon_config_path))
1303 {
1304 unlink(tmp_config_path);
1305 helplog(ASL_LEVEL_ERR, "rename \"%s\" \"%s\" failed: %s",
1306 tmp_config_path, racoon_config_path, strerror(errno));
1307 revertAnonymousRacoonConfiguration(racoon_config_dir_old);
1308 revertAnonymousRacoonConfiguration(racoon_config_dir);
1309 return -1;
1310 }
1311
1312 debug("successfully renamed \"%s\" \"%s\"", tmp_config_path, racoon_config_path);
1313 return 0;
1314 }
1315
1316 static int
1317 notifyRacoon(void)
1318 {
1319 debug("entry");
1320 static const char racoon_pid_path[] = "/var/run/racoon.pid";
1321 char buf[] = "18446744073709551615"; /* largest 64-bit integer */
1322 char *p = NULL;
1323 ssize_t n = 0;
1324 unsigned long m = 0;
1325 int fd = open(racoon_pid_path, O_RDONLY);
1326
1327 if (0 > fd)
1328 {
1329 debug("open \"%s\" failed, and that's OK: %s", racoon_pid_path,
1330 strerror(errno));
1331 return kmDNSHelperRacoonNotificationFailed;
1332 }
1333 n = read(fd, buf, sizeof(buf)-1);
1334 close(fd);
1335 if (1 > n)
1336 {
1337 debug("read of \"%s\" failed: %s", racoon_pid_path,
1338 n == 0 ? "empty file" : strerror(errno));
1339 return kmDNSHelperRacoonNotificationFailed;
1340 }
1341 buf[n] = '\0';
1342 m = strtoul(buf, &p, 10);
1343 if (*p != '\0' && !isspace(*p))
1344 {
1345 debug("invalid PID \"%s\" (around '%c')", buf, *p);
1346 return kmDNSHelperRacoonNotificationFailed;
1347 }
1348 if (2 > m)
1349 {
1350 debug("refusing to kill PID %lu", m);
1351 return kmDNSHelperRacoonNotificationFailed;
1352 }
1353 if (0 != kill(m, RacoonSignal()))
1354 {
1355 debug("Could not signal racoon (%lu): %s", m, strerror(errno));
1356 return kmDNSHelperRacoonNotificationFailed;
1357 }
1358 debug("Sent racoon (%lu) signal %d", m, RacoonSignal());
1359 return 0;
1360 }
1361
1362 static void
1363 closefds(int from)
1364 {
1365 int fd = 0;
1366 struct dirent entry, *entryp = NULL;
1367 DIR *dirp = opendir("/dev/fd");
1368
1369 if (dirp == NULL)
1370 {
1371 /* fall back to the erroneous getdtablesize method */
1372 for (fd = from; fd < getdtablesize(); ++fd)
1373 close(fd);
1374 return;
1375 }
1376 while (0 == readdir_r(dirp, &entry, &entryp) && NULL != entryp)
1377 {
1378 fd = atoi(entryp->d_name);
1379 if (fd >= from && fd != dirfd(dirp))
1380 close(fd);
1381 }
1382 closedir(dirp);
1383 }
1384
1385 static int
1386 startRacoonOld(void)
1387 {
1388 debug("entry");
1389 char * const racoon_args[] = { "/usr/sbin/racoon", "-e", NULL };
1390 ssize_t n = 0;
1391 pid_t pid = 0;
1392 int status = 0;
1393
1394 if (0 == (pid = fork()))
1395 {
1396 closefds(0);
1397 execve(racoon_args[0], racoon_args, NULL);
1398 helplog(ASL_LEVEL_ERR, "execve of \"%s\" failed: %s",
1399 racoon_args[0], strerror(errno));
1400 exit(2);
1401 }
1402 helplog(ASL_LEVEL_NOTICE, "racoon (pid=%lu) started",
1403 (unsigned long)pid);
1404 n = waitpid(pid, &status, 0);
1405 if (-1 == n)
1406 {
1407 helplog(ASL_LEVEL_ERR, "Unexpected waitpid failure: %s",
1408 strerror(errno));
1409 return kmDNSHelperRacoonStartFailed;
1410 }
1411 else if (pid != n)
1412 {
1413 helplog(ASL_LEVEL_ERR, "Unexpected waitpid return value %d",
1414 (int)n);
1415 return kmDNSHelperRacoonStartFailed;
1416 }
1417 else if (WIFSIGNALED(status))
1418 {
1419 helplog(ASL_LEVEL_ERR,
1420 "racoon (pid=%lu) terminated due to signal %d",
1421 (unsigned long)pid, WTERMSIG(status));
1422 return kmDNSHelperRacoonStartFailed;
1423 }
1424 else if (WIFSTOPPED(status))
1425 {
1426 helplog(ASL_LEVEL_ERR,
1427 "racoon (pid=%lu) has stopped due to signal %d",
1428 (unsigned long)pid, WSTOPSIG(status));
1429 return kmDNSHelperRacoonStartFailed;
1430 }
1431 else if (0 != WEXITSTATUS(status))
1432 {
1433 helplog(ASL_LEVEL_ERR,
1434 "racoon (pid=%lu) exited with status %d",
1435 (unsigned long)pid, WEXITSTATUS(status));
1436 return kmDNSHelperRacoonStartFailed;
1437 }
1438 debug("racoon (pid=%lu) daemonized normally", (unsigned long)pid);
1439 return 0;
1440 }
1441
1442 // constant and structure for the racoon control socket
1443 #define VPNCTL_CMD_PING 0x0004
1444 typedef struct vpnctl_hdr_struct
1445 {
1446 u_int16_t msg_type;
1447 u_int16_t flags;
1448 u_int32_t cookie;
1449 u_int32_t reserved;
1450 u_int16_t result;
1451 u_int16_t len;
1452 } vpnctl_hdr;
1453
1454 static int
1455 startRacoon(void)
1456 {
1457 debug("entry");
1458 int fd = socket(PF_UNIX, SOCK_STREAM, 0);
1459 if (0 > fd)
1460 {
1461 helplog(ASL_LEVEL_ERR, "Could not create endpoint for racoon control socket: %d %s",
1462 errno, strerror(errno));
1463 return kmDNSHelperRacoonStartFailed;
1464 }
1465
1466 struct sockaddr_un saddr;
1467 memset(&saddr, 0, sizeof(saddr));
1468 saddr.sun_family = AF_UNIX;
1469 saddr.sun_len = sizeof(saddr);
1470 static const char racoon_control_sock_path[] = "/var/run/vpncontrol.sock";
1471 strcpy(saddr.sun_path, racoon_control_sock_path);
1472 int result = connect(fd, (struct sockaddr*) &saddr, saddr.sun_len);
1473 if (0 > result)
1474 {
1475 helplog(ASL_LEVEL_ERR, "Could not connect racoon control socket %s: %d %s",
1476 racoon_control_sock_path, errno, strerror(errno));
1477 return kmDNSHelperRacoonStartFailed;
1478 }
1479
1480 u_int32_t btmm_cookie = 0x4d4d5442;
1481 vpnctl_hdr h = { htons(VPNCTL_CMD_PING), 0, btmm_cookie, 0, 0, 0 };
1482 size_t bytes = 0;
1483 ssize_t ret = 0;
1484
1485 while (bytes < sizeof(vpnctl_hdr))
1486 {
1487 ret = write(fd, ((unsigned char*)&h)+bytes, sizeof(vpnctl_hdr) - bytes);
1488 if (ret == -1)
1489 {
1490 helplog(ASL_LEVEL_ERR, "Could not write to racoon control socket: %d %s",
1491 errno, strerror(errno));
1492 return kmDNSHelperRacoonStartFailed;
1493 }
1494 bytes += ret;
1495 }
1496
1497 int nfds = fd + 1;
1498 fd_set fds;
1499 int counter = 0;
1500 struct timeval tv;
1501 bytes = 0;
1502 h.cookie = 0;
1503
1504 for (counter = 0; counter < 100; counter++)
1505 {
1506 FD_ZERO(&fds);
1507 FD_SET(fd, &fds);
1508 tv = (struct timeval){ 0, 10000 }; // 10 milliseconds * 100 iterations = 1 second max wait time
1509
1510 result = select(nfds, &fds, (fd_set*)NULL, (fd_set*)NULL, &tv);
1511 if (result > 0)
1512 {
1513 if (FD_ISSET(fd, &fds))
1514 {
1515 ret = read(fd, ((unsigned char*)&h)+bytes, sizeof(vpnctl_hdr) - bytes);
1516
1517 if (ret == -1)
1518 {
1519 helplog(ASL_LEVEL_ERR, "Could not read from racoon control socket: %d %s",
1520 strerror(errno));
1521 break;
1522 }
1523 bytes += ret;
1524 if (bytes >= sizeof(vpnctl_hdr)) break;
1525 }
1526 else
1527 {
1528 debug("select returned but fd_isset not on expected fd\n");
1529 }
1530 }
1531 else if (result < 0)
1532 {
1533 debug("select returned %d errno %d %s\n", result, errno, strerror(errno));
1534 if (errno != EINTR) break;
1535 }
1536 }
1537
1538 close(fd);
1539
1540 if (bytes < sizeof(vpnctl_hdr) || h.cookie != btmm_cookie) return kmDNSHelperRacoonStartFailed;
1541
1542 debug("racoon started");
1543 return 0;
1544 }
1545
1546 static int
1547 kickRacoon(void)
1548 {
1549 if ( 0 == notifyRacoon() )
1550 return 0;
1551 return UseOldRacoon() ? startRacoonOld() : startRacoon();
1552 }
1553
1554 #endif /* ndef MDNS_NO_IPSEC */
1555
1556 int
1557 do_mDNSConfigureServer(__unused mach_port_t port, int updown, const char *fqdn, audit_token_t token)
1558 {
1559 #ifndef MDNS_NO_IPSEC
1560 debug("entry");
1561 if (!authorized(&token)) goto fin;
1562
1563 switch ((enum mDNSUpDown)updown)
1564 {
1565 case kmDNSUp:
1566 if (0 != createAnonymousRacoonConfiguration(fqdn)) goto fin;
1567 break;
1568 case kmDNSDown:
1569 revertAnonymousRacoonConfiguration(GetOldRacoonConfigDir());
1570 revertAnonymousRacoonConfiguration(GetRacoonConfigDir());
1571 break;
1572 default:
1573 goto fin;
1574 }
1575
1576 if (0 != kickRacoon())
1577 goto fin;
1578 debug("succeeded");
1579
1580 fin:
1581 #else
1582 (void)port; (void)updown; (void)fqdn; (void)token;
1583 #endif
1584 update_idle_timer();
1585 return KERN_SUCCESS;
1586 }
1587
1588 #ifndef MDNS_NO_IPSEC
1589
1590 static unsigned int routeSeq = 1;
1591
1592 static int
1593 setupTunnelRoute(v6addr_t local, v6addr_t remote)
1594 {
1595 struct
1596 {
1597 struct rt_msghdr hdr;
1598 struct sockaddr_in6 dst;
1599 struct sockaddr_in6 gtwy;
1600 } msg;
1601 int err = 0;
1602 int s = -1;
1603
1604 if (0 > (s = socket(PF_ROUTE, SOCK_RAW, AF_INET)))
1605 {
1606 helplog(ASL_LEVEL_ERR, "socket(PF_ROUTE, ...) failed: %s",
1607 strerror(errno));
1608 err = kmDNSHelperRoutingSocketCreationFailed;
1609 goto fin;
1610 }
1611 memset(&msg, 0, sizeof(msg));
1612 msg.hdr.rtm_msglen = sizeof(msg);
1613 msg.hdr.rtm_type = RTM_ADD;
1614 /* The following flags are set by `route add -inet6 -host ...` */
1615 msg.hdr.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_HOST | RTF_STATIC;
1616 msg.hdr.rtm_version = RTM_VERSION;
1617 msg.hdr.rtm_seq = routeSeq++;
1618 msg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
1619 msg.hdr.rtm_inits = RTV_MTU;
1620 msg.hdr.rtm_rmx.rmx_mtu = 1280;
1621
1622 msg.dst.sin6_len = sizeof(msg.dst);
1623 msg.dst.sin6_family = AF_INET6;
1624 memcpy(&msg.dst.sin6_addr, remote, sizeof(msg.dst.sin6_addr));
1625
1626 msg.gtwy.sin6_len = sizeof(msg.gtwy);
1627 msg.gtwy.sin6_family = AF_INET6;
1628 memcpy(&msg.gtwy.sin6_addr, local, sizeof(msg.gtwy.sin6_addr));
1629
1630 /* send message, ignore error when route already exists */
1631 if (0 > write(s, &msg, msg.hdr.rtm_msglen))
1632 {
1633 int errno_ = errno;
1634
1635 debug("write to routing socket failed: %s", strerror(errno_));
1636 if (EEXIST != errno_)
1637 {
1638 err = kmDNSHelperRouteAdditionFailed;
1639 goto fin;
1640 }
1641 }
1642
1643 fin:
1644 if (0 <= s)
1645 close(s);
1646 return err;
1647 }
1648
1649 static int
1650 teardownTunnelRoute(v6addr_t remote)
1651 {
1652 struct
1653 {
1654 struct rt_msghdr hdr;
1655 struct sockaddr_in6 dst;
1656 } msg;
1657 int err = 0;
1658 int s = -1;
1659
1660 if (0 > (s = socket(PF_ROUTE, SOCK_RAW, AF_INET)))
1661 {
1662 helplog(ASL_LEVEL_ERR, "socket(PF_ROUTE, ...) failed: %s",
1663 strerror(errno));
1664 err = kmDNSHelperRoutingSocketCreationFailed;
1665 goto fin;
1666 }
1667 memset(&msg, 0, sizeof(msg));
1668
1669 msg.hdr.rtm_msglen = sizeof(msg);
1670 msg.hdr.rtm_type = RTM_DELETE;
1671 msg.hdr.rtm_version = RTM_VERSION;
1672 msg.hdr.rtm_seq = routeSeq++;
1673 msg.hdr.rtm_addrs = RTA_DST;
1674
1675 msg.dst.sin6_len = sizeof(msg.dst);
1676 msg.dst.sin6_family = AF_INET6;
1677 memcpy(&msg.dst.sin6_addr, remote, sizeof(msg.dst.sin6_addr));
1678 if (0 > write(s, &msg, msg.hdr.rtm_msglen))
1679 {
1680 int errno_ = errno;
1681
1682 debug("write to routing socket failed: %s", strerror(errno_));
1683 if (ESRCH != errno_)
1684 {
1685 err = kmDNSHelperRouteDeletionFailed;
1686 goto fin;
1687 }
1688 }
1689
1690 fin:
1691 if (0 <= s)
1692 close(s);
1693 return err;
1694 }
1695
1696 static int
1697 v4addr_to_string(v4addr_t addr, char *buf, size_t buflen)
1698 {
1699 if (NULL == inet_ntop(AF_INET, addr, buf, buflen))
1700 {
1701 helplog(ASL_LEVEL_ERR, "inet_ntop failed: %s",
1702 strerror(errno));
1703 return kmDNSHelperInvalidNetworkAddress;
1704 }
1705 else
1706 return 0;
1707 }
1708
1709 static int
1710 v6addr_to_string(v6addr_t addr, char *buf, size_t buflen)
1711 {
1712 if (NULL == inet_ntop(AF_INET6, addr, buf, buflen))
1713 {
1714 helplog(ASL_LEVEL_ERR, "inet_ntop failed: %s",
1715 strerror(errno));
1716 return kmDNSHelperInvalidNetworkAddress;
1717 }
1718 else
1719 return 0;
1720 }
1721
1722 /* Caller owns object returned in `policy' */
1723 static int
1724 generateTunnelPolicy(mDNSTunnelPolicyWhich which, mDNSTunnelType type, int in,
1725 v4addr_t src, uint16_t src_port,
1726 v4addr_t dst, uint16_t dst_port,
1727 v6addr_t src6, v6addr_t dst6,
1728 ipsec_policy_t *policy, size_t *len)
1729 {
1730 char srcs[INET_ADDRSTRLEN], dsts[INET_ADDRSTRLEN];
1731 char srcs6[INET6_ADDRSTRLEN], dsts6[INET6_ADDRSTRLEN];
1732 char buf[512];
1733 char *inOut = in ? "in" : "out";
1734 ssize_t n = 0;
1735 int err = 0;
1736
1737 *policy = NULL;
1738 *len = 0;
1739
1740 switch (which)
1741 {
1742 case kmDNSTunnelPolicySetup:
1743 if (type == kmDNSIPv6IPv4Tunnel)
1744 {
1745 if (0 != (err = v4addr_to_string(src, srcs, sizeof(srcs))))
1746 goto fin;
1747 if (0 != (err = v4addr_to_string(dst, dsts, sizeof(dsts))))
1748 goto fin;
1749 n = snprintf(buf, sizeof(buf),
1750 "%s ipsec esp/tunnel/%s[%u]-%s[%u]/require",
1751 inOut, srcs, src_port, dsts, dst_port);
1752 }
1753 else if (type == kmDNSIPv6IPv6Tunnel)
1754 {
1755 if (0 != (err = v6addr_to_string(src6, srcs6, sizeof(srcs6))))
1756 goto fin;
1757 if (0 != (err = v6addr_to_string(dst6, dsts6, sizeof(dsts6))))
1758 goto fin;
1759 n = snprintf(buf, sizeof(buf),
1760 "%s ipsec esp/tunnel/%s-%s/require",
1761 inOut, srcs6, dsts6);
1762 }
1763 break;
1764 case kmDNSTunnelPolicyTeardown:
1765 n = strlcpy(buf, inOut, sizeof(buf));
1766 break;
1767 case kmDNSTunnelPolicyGenerate:
1768 n = snprintf(buf, sizeof(buf), "%s generate", inOut);
1769 break;
1770 default:
1771 err = kmDNSHelperIPsecPolicyCreationFailed;
1772 goto fin;
1773 }
1774
1775 if (n >= (int)sizeof(buf))
1776 {
1777 err = kmDNSHelperResultTooLarge;
1778 goto fin;
1779 }
1780
1781 debug("policy=\"%s\"", buf);
1782 if (NULL == (*policy = (ipsec_policy_t)ipsec_set_policy(buf, n)))
1783 {
1784 helplog(ASL_LEVEL_ERR,
1785 "Could not create IPsec policy from \"%s\"", buf);
1786 err = kmDNSHelperIPsecPolicyCreationFailed;
1787 goto fin;
1788 }
1789 *len = ((ipsec_policy_t)(*policy))->sadb_x_policy_len * 8;
1790
1791 fin:
1792 return err;
1793 }
1794
1795 static int
1796 sendPolicy(int s, int setup,
1797 struct sockaddr *src, uint8_t src_bits,
1798 struct sockaddr *dst, uint8_t dst_bits,
1799 ipsec_policy_t policy, size_t len)
1800 {
1801 static unsigned int policySeq = 0;
1802 int err = 0;
1803
1804 debug("entry, setup=%d", setup);
1805 if (setup)
1806 err = pfkey_send_spdadd(s, src, src_bits, dst, dst_bits, -1,
1807 (char *)policy, len, policySeq++);
1808 else
1809 err = pfkey_send_spddelete(s, src, src_bits, dst, dst_bits, -1,
1810 (char *)policy, len, policySeq++);
1811 if (0 > err)
1812 {
1813 helplog(ASL_LEVEL_ERR, "Could not set IPsec policy: %s",
1814 ipsec_strerror());
1815 err = kmDNSHelperIPsecPolicySetFailed;
1816 goto fin;
1817 }
1818 else
1819 err = 0;
1820 debug("succeeded");
1821
1822 fin:
1823 return err;
1824 }
1825
1826 static int
1827 removeSA(int s, struct sockaddr *src, struct sockaddr *dst)
1828 {
1829 int err = 0;
1830
1831 debug("entry");
1832 err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, src, dst);
1833 if (0 > err)
1834 {
1835 helplog(ASL_LEVEL_ERR, "Could not remove IPsec SA: %s", ipsec_strerror());
1836 err = kmDNSHelperIPsecRemoveSAFailed;
1837 goto fin;
1838 }
1839 err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, dst, src);
1840 if (0 > err)
1841 {
1842 helplog(ASL_LEVEL_ERR, "Could not remove IPsec SA: %s", ipsec_strerror());
1843 err = kmDNSHelperIPsecRemoveSAFailed;
1844 goto fin;
1845 }
1846 else
1847 err = 0;
1848
1849 debug("succeeded");
1850
1851 fin:
1852 return err;
1853 }
1854
1855 static int
1856 doTunnelPolicy(mDNSTunnelPolicyWhich which, mDNSTunnelType type,
1857 v6addr_t loc_inner, uint8_t loc_bits,
1858 v4addr_t loc_outer, uint16_t loc_port,
1859 v6addr_t rmt_inner, uint8_t rmt_bits,
1860 v4addr_t rmt_outer, uint16_t rmt_port,
1861 v6addr_t loc_outer6, v6addr_t rmt_outer6)
1862 {
1863 struct sockaddr_in6 sin6_loc;
1864 struct sockaddr_in6 sin6_rmt;
1865 ipsec_policy_t policy = NULL;
1866 size_t len = 0;
1867 int s = -1;
1868 int err = 0;
1869
1870 debug("entry");
1871 if (0 > (s = pfkey_open()))
1872 {
1873 helplog(ASL_LEVEL_ERR,
1874 "Could not create IPsec policy socket: %s",
1875 ipsec_strerror());
1876 err = kmDNSHelperIPsecPolicySocketCreationFailed;
1877 goto fin;
1878 }
1879
1880 memset(&sin6_loc, 0, sizeof(sin6_loc));
1881 sin6_loc.sin6_len = sizeof(sin6_loc);
1882 sin6_loc.sin6_family = AF_INET6;
1883 sin6_loc.sin6_port = htons(0);
1884 memcpy(&sin6_loc.sin6_addr, loc_inner, sizeof(sin6_loc.sin6_addr));
1885
1886 memset(&sin6_rmt, 0, sizeof(sin6_rmt));
1887 sin6_rmt.sin6_len = sizeof(sin6_rmt);
1888 sin6_rmt.sin6_family = AF_INET6;
1889 sin6_rmt.sin6_port = htons(0);
1890 memcpy(&sin6_rmt.sin6_addr, rmt_inner, sizeof(sin6_rmt.sin6_addr));
1891
1892 int setup = which != kmDNSTunnelPolicyTeardown;
1893
1894 if (0 != (err = generateTunnelPolicy(which, type, 1,
1895 rmt_outer, rmt_port,
1896 loc_outer, loc_port,
1897 rmt_outer6, loc_outer6,
1898 &policy, &len)))
1899 goto fin;
1900 if (0 != (err = sendPolicy(s, setup,
1901 (struct sockaddr *)&sin6_rmt, rmt_bits,
1902 (struct sockaddr *)&sin6_loc, loc_bits,
1903 policy, len)))
1904 goto fin;
1905 if (NULL != policy)
1906 {
1907 free(policy);
1908 policy = NULL;
1909 }
1910 if (0 != (err = generateTunnelPolicy(which, type, 0,
1911 loc_outer, loc_port,
1912 rmt_outer, rmt_port,
1913 loc_outer6, rmt_outer6,
1914 &policy, &len)))
1915 goto fin;
1916 if (0 != (err = sendPolicy(s, setup,
1917 (struct sockaddr *)&sin6_loc, loc_bits,
1918 (struct sockaddr *)&sin6_rmt, rmt_bits,
1919 policy, len)))
1920 goto fin;
1921
1922 if (which == kmDNSTunnelPolicyTeardown)
1923 {
1924 if (rmt_port) // Outer tunnel is IPv4
1925 {
1926 if (loc_outer && rmt_outer)
1927 {
1928 struct sockaddr_in sin_loc;
1929 struct sockaddr_in sin_rmt;
1930 memset(&sin_loc, 0, sizeof(sin_loc));
1931 sin_loc.sin_len = sizeof(sin_loc);
1932 sin_loc.sin_family = AF_INET;
1933 memcpy(&sin_loc.sin_addr, loc_outer, sizeof(sin_loc.sin_addr));
1934
1935 memset(&sin_rmt, 0, sizeof(sin_rmt));
1936 sin_rmt.sin_len = sizeof(sin_rmt);
1937 sin_rmt.sin_family = AF_INET;
1938 memcpy(&sin_rmt.sin_addr, rmt_outer, sizeof(sin_rmt.sin_addr));
1939 if (0 != (err = removeSA(s, (struct sockaddr *)&sin_loc, (struct sockaddr *)&sin_rmt)))
1940 goto fin;
1941 }
1942 }
1943 else
1944 {
1945 if (loc_outer6 && rmt_outer6)
1946 {
1947 struct sockaddr_in6 sin6_lo;
1948 struct sockaddr_in6 sin6_rm;
1949
1950 memset(&sin6_lo, 0, sizeof(sin6_lo));
1951 sin6_lo.sin6_len = sizeof(sin6_lo);
1952 sin6_lo.sin6_family = AF_INET6;
1953 memcpy(&sin6_lo.sin6_addr, loc_outer6, sizeof(sin6_lo.sin6_addr));
1954
1955 memset(&sin6_rm, 0, sizeof(sin6_rm));
1956 sin6_rm.sin6_len = sizeof(sin6_rm);
1957 sin6_rm.sin6_family = AF_INET6;
1958 memcpy(&sin6_rm.sin6_addr, rmt_outer6, sizeof(sin6_rm.sin6_addr));
1959 if (0 != (err = removeSA(s, (struct sockaddr *)&sin6_lo, (struct sockaddr *)&sin6_rm)))
1960 goto fin;
1961 }
1962 }
1963 }
1964
1965
1966 debug("succeeded");
1967
1968 fin:
1969 if (s >= 0)
1970 pfkey_close(s);
1971 if (NULL != policy)
1972 free(policy);
1973 return err;
1974 }
1975
1976 #endif /* ndef MDNS_NO_IPSEC */
1977
1978 int
1979 do_mDNSAutoTunnelSetKeys(__unused mach_port_t port, int replacedelete,
1980 v6addr_t loc_inner, v6addr_t loc_outer6, uint16_t loc_port,
1981 v6addr_t rmt_inner, v6addr_t rmt_outer6, uint16_t rmt_port,
1982 const char *id, int *err, audit_token_t token)
1983 {
1984 #ifndef MDNS_NO_IPSEC
1985 static const char config[] =
1986 "%s"
1987 "remote %s [%u] {\n"
1988 " disconnect_on_idle idle_timeout 600 idle_direction idle_outbound;\n"
1989 " exchange_mode aggressive;\n"
1990 " doi ipsec_doi;\n"
1991 " situation identity_only;\n"
1992 " verify_identifier off;\n"
1993 " generate_policy on;\n"
1994 " my_identifier user_fqdn \"%s\";\n"
1995 " shared_secret keychain \"%s\";\n"
1996 " nonce_size 16;\n"
1997 " lifetime time 15 min;\n"
1998 " initial_contact on;\n"
1999 " support_proxy on;\n"
2000 " nat_traversal force;\n"
2001 " proposal_check claim;\n"
2002 " proposal {\n"
2003 " encryption_algorithm aes;\n"
2004 " hash_algorithm sha256;\n"
2005 " authentication_method pre_shared_key;\n"
2006 " dh_group 2;\n"
2007 " lifetime time 15 min;\n"
2008 " }\n"
2009 " proposal {\n"
2010 " encryption_algorithm aes;\n"
2011 " hash_algorithm sha1;\n"
2012 " authentication_method pre_shared_key;\n"
2013 " dh_group 2;\n"
2014 " lifetime time 15 min;\n"
2015 " }\n"
2016 "}\n\n"
2017 "sainfo address %s any address %s any {\n"
2018 " pfs_group 2;\n"
2019 " lifetime time 10 min;\n"
2020 " encryption_algorithm aes;\n"
2021 " authentication_algorithm hmac_sha256,hmac_sha1;\n"
2022 " compression_algorithm deflate;\n"
2023 "}\n\n"
2024 "sainfo address %s any address %s any {\n"
2025 " pfs_group 2;\n"
2026 " lifetime time 10 min;\n"
2027 " encryption_algorithm aes;\n"
2028 " authentication_algorithm hmac_sha256,hmac_sha1;\n"
2029 " compression_algorithm deflate;\n"
2030 "}\n";
2031 char path[PATH_MAX] = "";
2032 char li[INET6_ADDRSTRLEN], lo[INET_ADDRSTRLEN], lo6[INET6_ADDRSTRLEN],
2033 ri[INET6_ADDRSTRLEN], ro[INET_ADDRSTRLEN], ro6[INET6_ADDRSTRLEN];
2034 FILE *fp = NULL;
2035 int fd = -1;
2036 char tmp_path[PATH_MAX] = "";
2037 v4addr_t loc_outer, rmt_outer;
2038
2039 debug("entry");
2040 *err = 0;
2041 if (!authorized(&token))
2042 {
2043 *err = kmDNSHelperNotAuthorized;
2044 goto fin;
2045 }
2046 switch ((enum mDNSAutoTunnelSetKeysReplaceDelete)replacedelete)
2047 {
2048 case kmDNSAutoTunnelSetKeysReplace:
2049 case kmDNSAutoTunnelSetKeysDelete:
2050 break;
2051 default:
2052 *err = kmDNSHelperInvalidTunnelSetKeysOperation;
2053 goto fin;
2054 }
2055
2056 if (0 != (*err = v6addr_to_string(loc_inner, li, sizeof(li))))
2057 goto fin;
2058 if (0 != (*err = v6addr_to_string(rmt_inner, ri, sizeof(ri))))
2059 goto fin;
2060
2061 debug("loc_inner=%s rmt_inner=%s", li, ri);
2062 if (!rmt_port)
2063 {
2064 loc_outer[0] = loc_outer[1] = loc_outer[2] = loc_outer[3] = 0;
2065 rmt_outer[0] = rmt_outer[1] = rmt_outer[2] = rmt_outer[3] = 0;
2066
2067 if (0 != (*err = v6addr_to_string(loc_outer6, lo6, sizeof(lo6))))
2068 goto fin;
2069 if (0 != (*err = v6addr_to_string(rmt_outer6, ro6, sizeof(ro6))))
2070 goto fin;
2071 debug("IPv6 outer tunnel: loc_outer6=%s rmt_outer6=%s", lo6, ro6);
2072 if ((int)sizeof(path) <= snprintf(path, sizeof(path),
2073 "%s%s.conf", GetRacoonConfigDir(), ro6))
2074 {
2075 *err = kmDNSHelperResultTooLarge;
2076 goto fin;
2077 }
2078 }
2079 else
2080 {
2081 loc_outer[0] = loc_outer6[0];
2082 loc_outer[1] = loc_outer6[1];
2083 loc_outer[2] = loc_outer6[2];
2084 loc_outer[3] = loc_outer6[3];
2085
2086 rmt_outer[0] = rmt_outer6[0];
2087 rmt_outer[1] = rmt_outer6[1];
2088 rmt_outer[2] = rmt_outer6[2];
2089 rmt_outer[3] = rmt_outer6[3];
2090
2091 if (0 != (*err = v4addr_to_string(loc_outer, lo, sizeof(lo))))
2092 goto fin;
2093 if (0 != (*err = v4addr_to_string(rmt_outer, ro, sizeof(ro))))
2094 goto fin;
2095 debug("IPv4 outer tunnel: loc_outer=%s loc_port=%u rmt_outer=%s rmt_port=%u",
2096 lo, loc_port, ro, rmt_port);
2097
2098 if ((int)sizeof(path) <= snprintf(path, sizeof(path),
2099 "%s%s.%u.conf", GetRacoonConfigDir(), ro,
2100 rmt_port))
2101 {
2102 *err = kmDNSHelperResultTooLarge;
2103 goto fin;
2104 }
2105 }
2106
2107
2108
2109 if (kmDNSAutoTunnelSetKeysReplace == replacedelete)
2110 {
2111 if (0 > ensureExistenceOfRacoonConfigDir(GetRacoonConfigDir()))
2112 {
2113 *err = kmDNSHelperRacoonConfigCreationFailed;
2114 goto fin;
2115 }
2116 if ((int)sizeof(tmp_path) <=
2117 snprintf(tmp_path, sizeof(tmp_path), "%s.XXXXXX", path))
2118 {
2119 *err = kmDNSHelperResultTooLarge;
2120 goto fin;
2121 }
2122 if (0 > (fd = mkstemp(tmp_path)))
2123 {
2124 helplog(ASL_LEVEL_ERR, "mkstemp \"%s\" failed: %s",
2125 tmp_path, strerror(errno));
2126 *err = kmDNSHelperRacoonConfigCreationFailed;
2127 goto fin;
2128 }
2129 if (NULL == (fp = fdopen(fd, "w")))
2130 {
2131 helplog(ASL_LEVEL_ERR, "fdopen: %s",
2132 strerror(errno));
2133 *err = kmDNSHelperRacoonConfigCreationFailed;
2134 goto fin;
2135 }
2136 fd = -1;
2137 fprintf(fp, config, configHeader, (!rmt_port ? ro6 : ro), rmt_port, id, id, ri, li, li, ri);
2138 fclose(fp);
2139 fp = NULL;
2140 if (0 > rename(tmp_path, path))
2141 {
2142 helplog(ASL_LEVEL_ERR,
2143 "rename \"%s\" \"%s\" failed: %s",
2144 tmp_path, path, strerror(errno));
2145 *err = kmDNSHelperRacoonConfigCreationFailed;
2146 goto fin;
2147 }
2148 }
2149 else
2150 {
2151 if (0 != unlink(path))
2152 debug("unlink \"%s\" failed: %s", path,
2153 strerror(errno));
2154 }
2155
2156 if (0 != (*err = doTunnelPolicy(kmDNSTunnelPolicyTeardown, kmDNSNoTunnel,
2157 loc_inner, kWholeV6Mask, loc_outer, loc_port,
2158 rmt_inner, kWholeV6Mask, rmt_outer, rmt_port, loc_outer6, rmt_outer6)))
2159 goto fin;
2160 if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
2161 0 != (*err = doTunnelPolicy(kmDNSTunnelPolicySetup, (!rmt_port ? kmDNSIPv6IPv6Tunnel : kmDNSIPv6IPv4Tunnel),
2162 loc_inner, kWholeV6Mask, loc_outer, loc_port,
2163 rmt_inner, kWholeV6Mask, rmt_outer, rmt_port, loc_outer6, rmt_outer6)))
2164 goto fin;
2165
2166 if (0 != (*err = teardownTunnelRoute(rmt_inner)))
2167 goto fin;
2168 if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
2169 0 != (*err = setupTunnelRoute(loc_inner, rmt_inner)))
2170 goto fin;
2171
2172 if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
2173 0 != (*err = kickRacoon()))
2174 goto fin;
2175
2176 debug("succeeded");
2177
2178 fin:
2179 if (NULL != fp)
2180 fclose(fp);
2181 if (0 <= fd)
2182 close(fd);
2183 unlink(tmp_path);
2184 #else
2185 (void)replacedelete; (void)loc_inner; (void)loc_outer6; (void)loc_port; (void)rmt_inner;
2186 (void)rmt_outer6; (void)rmt_port; (void)id; (void)token;
2187
2188 *err = kmDNSHelperIPsecDisabled;
2189 #endif /* MDNS_NO_IPSEC */
2190 update_idle_timer();
2191 return KERN_SUCCESS;
2192 }
2193
2194 kern_return_t
2195 do_mDNSSendWakeupPacket(__unused mach_port_t port, unsigned ifid, const char *eth_addr, const char *ip_addr, int iteration, audit_token_t token)
2196 {
2197 int bpf_fd, i, j;
2198 struct ifreq ifr;
2199 char ifname[IFNAMSIZ];
2200 char packet[512];
2201 char *ptr = packet;
2202 char bpf_device[12];
2203 struct ether_addr *ea;
2204 (void) ip_addr; // unused
2205 (void) iteration; // unused
2206 (void) token; // unused
2207
2208 if (if_indextoname(ifid, ifname) == NULL)
2209 {
2210 helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket invalid interface index %u", ifid);
2211 return errno;
2212 }
2213
2214 ea = ether_aton(eth_addr);
2215 if (ea == NULL)
2216 {
2217 helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket invalid ethernet address %s", eth_addr);
2218 return errno;
2219 }
2220
2221 for (i = 0; i < 100; i++)
2222 {
2223 snprintf(bpf_device, sizeof(bpf_device), "/dev/bpf%d", i);
2224 bpf_fd = open(bpf_device, O_RDWR, 0);
2225 if (bpf_fd == -1)
2226 continue;
2227 else break;
2228 }
2229
2230 if (bpf_fd == -1)
2231 {
2232 helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket cannot find a bpf device");
2233 return ENXIO;
2234 }
2235
2236 memset(&ifr, 0, sizeof(ifr));
2237 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
2238
2239 if (ioctl(bpf_fd, BIOCSETIF, (char *)&ifr) < 0)
2240 {
2241 helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket BIOCSETIF failed %s", strerror(errno));
2242 return errno;
2243 }
2244
2245 // 0x00 Destination address
2246 for (i=0; i<6; i++) *ptr++ = ea->octet[i];
2247
2248 // 0x06 Source address (Note: Since we don't currently set the BIOCSHDRCMPLT option, BPF will fill in the real interface address for us)
2249 for (i=0; i<6; i++) *ptr++ = 0;
2250
2251 // 0x0C Ethertype (0x0842)
2252 *ptr++ = 0x08;
2253 *ptr++ = 0x42;
2254
2255 // 0x0E Wakeup sync sequence
2256 for (i=0; i<6; i++) *ptr++ = 0xFF;
2257
2258 // 0x14 Wakeup data
2259 for (j=0; j<16; j++) for (i=0; i<6; i++) *ptr++ = ea->octet[i];
2260
2261 // 0x74 Password
2262 for (i=0; i<6; i++) *ptr++ = 0;
2263
2264 if (write(bpf_fd, packet, ptr - packet) < 0)
2265 {
2266 helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket write failed %s", strerror(errno));
2267 return errno;
2268 }
2269 helplog(ASL_LEVEL_INFO, "do_mDNSSendWakeupPacket sent unicast eth_addr %s, ip_addr %s", eth_addr, ip_addr);
2270 // Send a broadcast one to handle ethernet switches that don't flood forward packets with
2271 // unknown mac addresses.
2272 for (i=0; i<6; i++) packet[i] = 0xFF;
2273 if (write(bpf_fd, packet, ptr - packet) < 0)
2274 {
2275 helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket write failed %s", strerror(errno));
2276 return errno;
2277 }
2278 helplog(ASL_LEVEL_INFO, "do_mDNSSendWakeupPacket sent broadcast eth_addr %s, ip_addr %s", eth_addr, ip_addr);
2279 close(bpf_fd);
2280 return KERN_SUCCESS;
2281 }
2282
2283 // Open the specified port for protocol in the P2P firewall.
2284 kern_return_t
2285 do_mDNSPacketFilterControl(__unused mach_port_t port, uint32_t command, const char * ifname, uint32_t count, pfArray_t portArray, pfArray_t protocolArray, audit_token_t token)
2286 {
2287 (void) token; // unused
2288 int error;
2289 kern_return_t result = KERN_SUCCESS;
2290
2291 helplog(ASL_LEVEL_INFO, "do_mDNSPacketFilterControl: command %d ifname %s, count %d",
2292 command, ifname, count);
2293
2294 switch (command)
2295 {
2296 case PF_SET_RULES:
2297 error = P2PPacketFilterAddBonjourRuleSet(ifname, count, portArray, protocolArray);
2298 if (error)
2299 {
2300 helplog(ASL_LEVEL_ERR, "P2PPacketFilterAddBonjourRuleSet failed %s", strerror(error));
2301 result = KERN_FAILURE;
2302 }
2303 break;
2304
2305 case PF_CLEAR_RULES:
2306 error = P2PPacketFilterClearBonjourRules();
2307 if (error)
2308 {
2309 helplog(ASL_LEVEL_ERR, "P2PPacketFilterClearBonjourRules failed %s", strerror(error));
2310 result = KERN_FAILURE;
2311 }
2312 break;
2313
2314 default:
2315 helplog(ASL_LEVEL_ERR, "do_mDNSPacketFilterControl: invalid command %d", command);
2316 result = KERN_INVALID_ARGUMENT;
2317 break;
2318 }
2319
2320 return result;
2321 }
2322
2323 unsigned long
2324 in_cksum(unsigned short *ptr,int nbytes)
2325 {
2326 unsigned long sum;
2327 u_short oddbyte;
2328
2329 /*
2330 * Our algorithm is simple, using a 32-bit accumulator (sum),
2331 * we add sequential 16-bit words to it, and at the end, fold back
2332 * all the carry bits from the top 16 bits into the lower 16 bits.
2333 */
2334 sum = 0;
2335 while (nbytes > 1) {
2336 sum += *ptr++;
2337 nbytes -= 2;
2338 }
2339
2340 /* mop up an odd byte, if necessary */
2341 if (nbytes == 1) {
2342 /* make sure top half is zero */
2343 oddbyte = 0;
2344
2345 /* one byte only */
2346 *((u_char *)&oddbyte) = *(u_char *)ptr;
2347 sum += oddbyte;
2348 }
2349 /* Add back carry outs from top 16 bits to low 16 bits. */
2350 sum = (sum >> 16) + (sum & 0xffff);
2351
2352 /* add carry */
2353 sum += (sum >> 16);
2354
2355 return sum;
2356 }
2357
2358 unsigned short
2359 InetChecksum(unsigned short *ptr,int nbytes)
2360 {
2361 unsigned long sum;
2362
2363 sum = in_cksum(ptr, nbytes);
2364 return (unsigned short)~sum;
2365 }
2366
2367 void TCPCheckSum(int af, struct tcphdr *t, int tcplen, v6addr_t sadd6, v6addr_t dadd6)
2368 {
2369 unsigned long sum = 0;
2370 unsigned short *ptr;
2371
2372 /* TCP header checksum */
2373 sum = in_cksum((unsigned short *)t, tcplen);
2374
2375 if (af == AF_INET)
2376 {
2377 /* Pseudo header */
2378 ptr = (unsigned short *)sadd6;
2379 sum += *ptr++;
2380 sum += *ptr++;
2381 ptr = (unsigned short *)dadd6;
2382 sum += *ptr++;
2383 sum += *ptr++;
2384 }
2385 else if (af == AF_INET6)
2386 {
2387 /* Pseudo header */
2388 ptr = (unsigned short *)sadd6;
2389 sum += *ptr++;
2390 sum += *ptr++;
2391 sum += *ptr++;
2392 sum += *ptr++;
2393 sum += *ptr++;
2394 sum += *ptr++;
2395 sum += *ptr++;
2396 sum += *ptr++;
2397 ptr = (unsigned short *)dadd6;
2398 sum += *ptr++;
2399 sum += *ptr++;
2400 sum += *ptr++;
2401 sum += *ptr++;
2402 sum += *ptr++;
2403 sum += *ptr++;
2404 sum += *ptr++;
2405 sum += *ptr++;
2406 }
2407
2408 sum += htons(tcplen);
2409 sum += htons(IPPROTO_TCP);
2410
2411 while (sum >> 16)
2412 sum = (sum >> 16) + (sum & 0xFFFF);
2413
2414 t->th_sum = ~sum;
2415
2416 }
2417
2418 kern_return_t do_mDNSSendKeepalive(__unused mach_port_t port, v6addr_t sadd6, v6addr_t dadd6, uint16_t lport, uint16_t rport, unsigned seq, unsigned ack, uint16_t win, audit_token_t token)
2419 {
2420 struct packet4 {
2421 struct ip ip;
2422 struct tcphdr tcp;
2423 } packet4;
2424 struct packet6 {
2425 struct tcphdr tcp;
2426 } packet6;
2427 int sock, on;
2428 struct tcphdr *t;
2429 int af;
2430 struct sockaddr_storage ss_to;
2431 struct sockaddr_in *sin_to = (struct sockaddr_in *)&ss_to;
2432 struct sockaddr_in6 *sin6_to = (struct sockaddr_in6 *)&ss_to;
2433 void *packet;
2434 ssize_t packetlen;
2435 char ctlbuf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
2436 struct msghdr msghdr;
2437 struct iovec iov;
2438 ssize_t len;
2439
2440 if (!authorized(&token))
2441 {
2442 helplog(ASL_LEVEL_ERR, "mDNSSendKeepalive: Not authorized");
2443 return kmDNSHelperNotAuthorized;
2444 }
2445
2446 helplog(ASL_LEVEL_ERR, "mDNSSendKeepalive: called");
2447
2448 // all the incoming arguments are in network order
2449 if ((*(unsigned *)(sadd6 +4) == 0) && (*(unsigned *)(sadd6 + 8) == 0) && (*(unsigned *)(sadd6 + 12) == 0))
2450 {
2451 af = AF_INET;
2452 memset(&packet4, 0, sizeof (packet4));
2453
2454 /* Fill in all the IP header information - should be in host order*/
2455 packet4.ip.ip_v = 4; /* 4-bit Version */
2456 packet4.ip.ip_hl = 5; /* 4-bit Header Length */
2457 packet4.ip.ip_tos = 0; /* 8-bit Type of service */
2458 packet4.ip.ip_len = 40; /* 16-bit Total length */
2459 packet4.ip.ip_id = 9864; /* 16-bit ID field */
2460 packet4.ip.ip_off = 0; /* 13-bit Fragment offset */
2461 packet4.ip.ip_ttl = 63; /* 8-bit Time To Live */
2462 packet4.ip.ip_p = IPPROTO_TCP; /* 8-bit Protocol */
2463 packet4.ip.ip_sum = 0; /* 16-bit Header checksum (below) */
2464 memcpy(&packet4.ip.ip_src.s_addr, sadd6, 4);
2465 memcpy(&packet4.ip.ip_dst.s_addr, dadd6, 4);
2466
2467 /* IP header checksum */
2468 packet4.ip.ip_sum = InetChecksum((unsigned short *)&packet4.ip, 20);
2469 t = &packet4.tcp;
2470 packet = &packet4;
2471 packetlen = 40; // sum of IPv4 header len(20) and TCP header len(20)
2472 }
2473 else
2474 {
2475 af = AF_INET6;
2476 memset(&packet6, 0, sizeof (packet6));
2477 t = &packet6.tcp;
2478 packet = &packet6;
2479 // We don't send IPv6 header, hence just the TCP header len (20)
2480 packetlen = 20;
2481 }
2482
2483 /* Fill in all the TCP header information */
2484 t->th_sport = lport; /* 16-bit Source port number */
2485 t->th_dport = rport; /* 16-bit Destination port */
2486 t->th_seq = seq; /* 32-bit Sequence Number */
2487 t->th_ack = ack; /* 32-bit Acknowledgement Number */
2488 t->th_off = 5; /* Data offset */
2489 t->th_flags = TH_ACK;
2490 t->th_win = win;
2491 t->th_sum = 0; /* 16-bit checksum (below) */
2492 t->th_urp = 0; /* 16-bit urgent offset */
2493
2494 TCPCheckSum(af, t, 20, sadd6, dadd6);
2495
2496 /* Open up a RAW socket */
2497 if ((sock = socket(af, SOCK_RAW, IPPROTO_TCP)) < 0)
2498 {
2499 helplog(ASL_LEVEL_ERR, "mDNSSendKeepalive: socket %s", strerror(errno));
2500 return errno;
2501 }
2502
2503
2504 if (af == AF_INET)
2505 {
2506 on = 1;
2507 if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &on, sizeof (on)))
2508 {
2509 close(sock);
2510 helplog(ASL_LEVEL_ERR, "mDNSSendKeepalive: setsockopt %s", strerror(errno));
2511 return errno;
2512 }
2513
2514 memset(sin_to, 0, sizeof(struct sockaddr_in));
2515 sin_to->sin_len = sizeof(struct sockaddr_in);
2516 sin_to->sin_family = AF_INET;
2517 memcpy(&sin_to->sin_addr, sadd6, sizeof(struct in_addr));
2518 sin_to->sin_port = rport;
2519
2520 msghdr.msg_control = NULL;
2521 msghdr.msg_controllen = 0;
2522
2523 }
2524 else
2525 {
2526 struct cmsghdr *ctl;
2527
2528 memset(sin6_to, 0, sizeof(struct sockaddr_in6));
2529 sin6_to->sin6_len = sizeof(struct sockaddr_in6);
2530 sin6_to->sin6_family = AF_INET6;
2531 memcpy(&sin6_to->sin6_addr, dadd6, sizeof(struct in6_addr));
2532
2533 sin6_to->sin6_port = rport;
2534 sin6_to->sin6_flowinfo = 0;
2535
2536
2537 msghdr.msg_control = ctlbuf;
2538 msghdr.msg_controllen = sizeof(ctlbuf);
2539 ctl = CMSG_FIRSTHDR(&msghdr);
2540 ctl->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
2541 ctl->cmsg_level = IPPROTO_IPV6;
2542 ctl->cmsg_type = IPV6_PKTINFO;
2543 struct in6_pktinfo *pktinfo = (struct in6_pktinfo *) CMSG_DATA(ctl);
2544 memcpy(&pktinfo->ipi6_addr, sadd6, sizeof(struct in6_addr));
2545 pktinfo->ipi6_ifindex = 0;
2546 }
2547
2548 msghdr.msg_name = (struct sockaddr *)&ss_to;
2549 msghdr.msg_namelen = ss_to.ss_len;
2550 iov.iov_base = packet;
2551 iov.iov_len = packetlen;
2552 msghdr.msg_iov = &iov;
2553 msghdr.msg_iovlen = 1;
2554 msghdr.msg_flags = 0;
2555 again:
2556 len = sendmsg(sock, &msghdr, 0);
2557 if (len == -1)
2558 {
2559 if (errno == EINTR)
2560 goto again;
2561 }
2562
2563 if (len != packetlen)
2564 {
2565 helplog(ASL_LEVEL_ERR, "mDNSSendKeepalive: sendmsg failed %s", strerror(errno));
2566 }
2567 else
2568 {
2569 char source[INET6_ADDRSTRLEN], dest[INET6_ADDRSTRLEN];
2570
2571 inet_ntop(af, (void *)sadd6, source, sizeof(source));
2572 inet_ntop(af, (void *)dadd6, dest, sizeof(dest));
2573
2574 helplog(ASL_LEVEL_ERR, "mDNSSendKeepalive: Success Source %s:%d, Dest %s:%d, %u, %u, %u", source, ntohs(lport), dest, ntohs(rport), ntohl(seq), ntohl(ack), ntohs(win));
2575
2576 }
2577 close(sock);
2578 return KERN_SUCCESS;
2579 }
2580
2581
2582 kern_return_t do_mDNSRetrieveTCPInfo(__unused mach_port_t port, int family, v6addr_t laddr, uint16_t lport, v6addr_t raddr, uint16_t rport,
2583 uint32_t *seq, uint32_t *ack, uint16_t *win, int32_t *intfid, audit_token_t token)
2584 {
2585 struct tcp_info ti;
2586 struct info_tuple itpl;
2587 int mib[4];
2588 unsigned int miblen;
2589 size_t len;
2590 size_t sz;
2591
2592 memset(&itpl, 0, sizeof(struct info_tuple));
2593 memset(&ti, 0, sizeof(struct tcp_info));
2594
2595 if (!authorized(&token))
2596 {
2597 helplog(ASL_LEVEL_ERR, "mDNSRetrieveTCPInfo: Not authorized");
2598 return kmDNSHelperNotAuthorized;
2599 }
2600
2601 if (family == AF_INET)
2602 {
2603 memcpy(&itpl.itpl_local_sin.sin_addr, laddr, sizeof(struct in_addr));
2604 memcpy(&itpl.itpl_remote_sin.sin_addr, raddr, sizeof(struct in_addr));
2605 itpl.itpl_local_sin.sin_port = lport;
2606 itpl.itpl_remote_sin.sin_port = rport;
2607 itpl.itpl_local_sin.sin_family = AF_INET;
2608 itpl.itpl_remote_sin.sin_family = AF_INET;
2609 }
2610 else
2611 {
2612 memcpy(&itpl.itpl_local_sin6.sin6_addr, laddr, sizeof(struct in6_addr));
2613 memcpy(&itpl.itpl_remote_sin6.sin6_addr, raddr, sizeof(struct in6_addr));
2614 itpl.itpl_local_sin6.sin6_port = lport;
2615 itpl.itpl_remote_sin6.sin6_port = rport;
2616 itpl.itpl_local_sin6.sin6_family = AF_INET6;
2617 itpl.itpl_remote_sin6.sin6_family = AF_INET6;
2618 }
2619 itpl.itpl_proto = IPPROTO_TCP;
2620 sz = sizeof(mib)/sizeof(mib[0]);
2621 if (sysctlnametomib("net.inet.tcp.info", mib, &sz) == -1)
2622 {
2623 helplog(ASL_LEVEL_ERR, "do_RetrieveTCPInfo: sysctlnametomib failed %d, %s", errno, strerror(errno));
2624 return errno;
2625 }
2626 miblen = (unsigned int)sz;
2627 len = sizeof(struct tcp_info);
2628 if (sysctl(mib, miblen, &ti, &len, &itpl, sizeof(struct info_tuple)) == -1)
2629 {
2630 helplog(ASL_LEVEL_ERR, "do_RetrieveTCPInfo: sysctl failed %d, %s", errno, strerror(errno));
2631 return errno;
2632 }
2633
2634 *seq = ti.tcpi_snd_nxt - 1;
2635 *ack = ti.tcpi_rcv_nxt;
2636 *win = ti.tcpi_rcv_space >> ti.tcpi_rcv_wscale;
2637 *intfid = ti.tcpi_last_outif;
2638 return KERN_SUCCESS;
2639 }
2640
2641 static int getMACAddress(int family, v6addr_t raddr, v6addr_t gaddr, int *gfamily, ethaddr_t eth)
2642 {
2643 struct
2644 {
2645 struct rt_msghdr m_rtm;
2646 char m_space[512];
2647 } m_rtmsg;
2648
2649 struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
2650 char *cp = m_rtmsg.m_space;
2651 int seq = 6367, sock, rlen, i;
2652 struct sockaddr_in *sin = NULL;
2653 struct sockaddr_in6 *sin6 = NULL;
2654 struct sockaddr_dl *sdl = NULL;
2655 struct sockaddr_storage sins;
2656 struct sockaddr_dl sdl_m;
2657
2658 #define NEXTADDR(w, s, len) \
2659 if (rtm->rtm_addrs & (w)) \
2660 { \
2661 bcopy((char *)s, cp, len); \
2662 cp += len; \
2663 }
2664
2665 bzero(&sins, sizeof(struct sockaddr_storage));
2666 bzero(&sdl_m, sizeof(struct sockaddr_dl));
2667 bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
2668
2669 sock = socket(PF_ROUTE, SOCK_RAW, 0);
2670 if (sock < 0)
2671 {
2672 helplog(ASL_LEVEL_ERR, "mDNSGetRemoteMAC: Can not open the socket - %s", strerror(errno));
2673 return errno;
2674 }
2675
2676 rtm->rtm_addrs |= RTA_DST | RTA_GATEWAY;
2677 rtm->rtm_type = RTM_GET;
2678 rtm->rtm_flags = 0;
2679 rtm->rtm_version = RTM_VERSION;
2680 rtm->rtm_seq = ++seq;
2681
2682 sdl_m.sdl_len = sizeof(sdl_m);
2683 sdl_m.sdl_family = AF_LINK;
2684 if (family == AF_INET)
2685 {
2686 sin = (struct sockaddr_in*)&sins;
2687 sin->sin_family = AF_INET;
2688 sin->sin_len = sizeof(struct sockaddr_in);
2689 memcpy(&sin->sin_addr, raddr, sizeof(struct in_addr));
2690 NEXTADDR(RTA_DST, sin, sin->sin_len);
2691 }
2692 else if (family == AF_INET6)
2693 {
2694 sin6 = (struct sockaddr_in6 *)&sins;
2695 sin6->sin6_len = sizeof(struct sockaddr_in6);
2696 sin6->sin6_family = AF_INET6;
2697 memcpy(&sin6->sin6_addr, raddr, sizeof(struct in6_addr));
2698 NEXTADDR(RTA_DST, sin6, sin6->sin6_len);
2699 }
2700 NEXTADDR(RTA_GATEWAY, &sdl_m, sdl_m.sdl_len);
2701 rtm->rtm_msglen = rlen = cp - (char *)&m_rtmsg;
2702
2703 if (write(sock, (char *)&m_rtmsg, rlen) < 0)
2704 {
2705 helplog(ASL_LEVEL_INFO, "do_mDNSGetRemoteMAC: writing to routing socket: %s", strerror(errno));
2706 close(sock);
2707 return errno;
2708 }
2709
2710 do
2711 {
2712 rlen = read(sock, (char *)&m_rtmsg, sizeof(m_rtmsg));
2713 }
2714 while (rlen > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != getpid()));
2715
2716 if (rlen < 0)
2717 helplog(ASL_LEVEL_ERR, "do_mDNSGetRemoteMAC: Read from routing socket failed");
2718
2719 if (family == AF_INET)
2720 {
2721 sin = (struct sockaddr_in *) (rtm + 1);
2722 sdl = (struct sockaddr_dl *) (sin->sin_len + (char *) sin);
2723 }
2724 else if (family == AF_INET6)
2725 {
2726 sin6 = (struct sockaddr_in6 *) (rtm +1);
2727 sdl = (struct sockaddr_dl *) (sin6->sin6_len + (char *) sin6);
2728 }
2729 // If the address is not on the local net, we get the IP address of the gateway.
2730 // We would have to repeat the process to get the MAC address of the gateway
2731 *gfamily = sdl->sdl_family;
2732 if (sdl->sdl_family == AF_INET)
2733 {
2734 struct sockaddr_in *new_sin = (struct sockaddr_in *)(sin->sin_len +(char*) sin);
2735 memcpy(gaddr, &new_sin->sin_addr, sizeof(struct in_addr));
2736 close(sock);
2737 return -1;
2738 }
2739 else if (sdl->sdl_family == AF_INET6)
2740 {
2741 struct sockaddr_in6 *new_sin6 = (struct sockaddr_in6 *)(sin6->sin6_len +(char*) sin6);
2742 memcpy(gaddr, &new_sin6->sin6_addr, sizeof(struct in6_addr));
2743 close(sock);
2744 return -1;
2745 }
2746
2747 unsigned char *ptr = (unsigned char *)LLADDR(sdl);
2748 for (i = 0; i < ETHER_ADDR_LEN; i++)
2749 (eth)[i] = *(ptr +i);
2750
2751 close(sock);
2752 return KERN_SUCCESS;
2753 }
2754
2755 kern_return_t do_mDNSGetRemoteMAC(__unused mach_port_t port, int family, v6addr_t raddr, ethaddr_t eth, audit_token_t token)
2756 {
2757 int ret = 0;
2758 v6addr_t gateway;
2759 int gfamily;
2760 int count = 0;
2761
2762 if (!authorized(&token))
2763 {
2764 helplog(ASL_LEVEL_ERR, "mDNSGetRemoteMAC: Not authorized");
2765 return kmDNSHelperNotAuthorized;
2766 }
2767
2768 do
2769 {
2770 ret = getMACAddress(family, raddr, gateway, &gfamily, eth);
2771 if (ret == -1)
2772 {
2773 memcpy(raddr, gateway, sizeof(family));
2774 family = gfamily;
2775 count++;
2776 }
2777 }
2778 while ((ret == -1) && (count < 5));
2779 return ret;
2780 }
2781
2782
2783 kern_return_t do_mDNSStoreSPSMACAddress(__unused mach_port_t port, int family, v6addr_t spsaddr, const char *ifname, audit_token_t token)
2784 {
2785 ethaddr_t eth;
2786 char spsip[INET6_ADDRSTRLEN];
2787 int ret = 0;
2788 CFStringRef sckey = NULL;
2789 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:StoreSPSMACAddress"), NULL, NULL);
2790 SCDynamicStoreRef ipstore = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetIPv6Addresses"), NULL, NULL);
2791 CFMutableDictionaryRef dict = NULL;
2792 CFStringRef entityname = NULL;
2793 CFDictionaryRef ipdict = NULL;
2794 CFArrayRef addrs = NULL;
2795
2796 if (!authorized(&token))
2797 {
2798 helplog(ASL_LEVEL_ERR, "mDNSStoreSPSMAC: Not authorized");
2799 return kmDNSHelperNotAuthorized;
2800 }
2801
2802 if ((store == NULL) || (ipstore == NULL))
2803 {
2804 helplog(ASL_LEVEL_ERR, "Unable to access SC Dynamic Store");
2805 return KERN_FAILURE;
2806 }
2807
2808 // Get the MAC address of the Sleep Proxy Server
2809 memset(eth, 0, sizeof(eth));
2810 ret = do_mDNSGetRemoteMAC(port, family, spsaddr, eth, token);
2811 if (ret != KERN_SUCCESS)
2812 {
2813 helplog(ASL_LEVEL_ERR, "mDNSStoreSPSMAC: Failed to determine the MAC address");
2814 goto fin;
2815 }
2816
2817 // Create/Update the dynamic store entry for the specified interface
2818 sckey = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname, "/BonjourSleepProxyAddress");
2819 dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2820 if (!dict)
2821 {
2822 helplog(ASL_LEVEL_ERR, "SPSCreateDict: Could not create CFDictionary dict");
2823 ret = KERN_FAILURE;
2824 goto fin;
2825 }
2826
2827 CFStringRef macaddr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%02x:%02x:%02x:%02x:%02x:%02x"), eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
2828 CFDictionarySetValue(dict, CFSTR("MACAddress"), macaddr);
2829 if (NULL != macaddr) CFRelease(macaddr);
2830
2831 if( NULL == inet_ntop(family, (void *)spsaddr, spsip, sizeof(spsip)))
2832 {
2833 helplog(ASL_LEVEL_ERR, "inet_ntop failed: %s", strerror(errno));
2834 ret = kmDNSHelperInvalidNetworkAddress;
2835 goto fin;
2836 }
2837
2838 CFStringRef ipaddr = CFStringCreateWithCString(NULL, spsip, kCFStringEncodingUTF8);
2839 CFDictionarySetValue(dict, CFSTR("IPAddress"), ipaddr);
2840 if (NULL != ipaddr) CFRelease(ipaddr);
2841
2842 // Get the current IPv6 addresses on this interface and store them so NAs can be sent on wakeup
2843 if ((entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/IPv6"), ifname)) != NULL)
2844 {
2845 if ((ipdict = SCDynamicStoreCopyValue(ipstore, entityname)) != NULL)
2846 {
2847 if((addrs = CFDictionaryGetValue(ipdict, CFSTR("Addresses"))) != NULL)
2848 {
2849 addrs = CFRetain(addrs);
2850 CFDictionarySetValue(dict, CFSTR("RegisteredAddresses"), addrs);
2851 }
2852 }
2853 }
2854 SCDynamicStoreSetValue(store, sckey, dict);
2855
2856 fin:
2857 if (store) CFRelease(store);
2858 if (ipstore) CFRelease(ipstore);
2859 if (sckey) CFRelease(sckey);
2860 if (dict) CFRelease(dict);
2861 if (ipdict) CFRelease(ipdict);
2862 if (entityname) CFRelease(entityname);
2863 if (addrs) CFRelease(addrs);
2864
2865 update_idle_timer();
2866 return ret;
2867 }