]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/helper.c
mDNSResponder-1096.60.2.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / helper.c
1 /*
2 * Copyright (c) 2007-2019 Apple Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <sys/cdefs.h>
18 #include <arpa/inet.h>
19 #include <bsm/libbsm.h>
20 #include <net/if.h>
21 #include <net/route.h>
22 #include <net/if_dl.h>
23 #include <net/if_types.h>
24 #include <netinet/in.h>
25 #include <netinet/if_ether.h>
26 #include <netinet6/in6_var.h>
27 #include <netinet6/nd6.h>
28 #include <netinet6/ipsec.h>
29 #include <sys/ioctl.h>
30 #include <sys/param.h>
31 #include <sys/socket.h>
32 #include <ctype.h>
33 #include <dirent.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <signal.h>
37 #include <stdarg.h>
38 #include <stdbool.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <Security/Security.h>
42 #include <SystemConfiguration/SystemConfiguration.h>
43 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
44 #include <TargetConditionals.h>
45 #include <IOKit/pwr_mgt/IOPMLib.h>
46 #include <net/bpf.h>
47 #include <sys/sysctl.h>
48
49 #include "mDNSEmbeddedAPI.h"
50 #include "dns_sd.h"
51 #include "dnssd_ipc.h"
52 #include "helper.h"
53 #include "helper-server.h"
54 #include "P2PPacketFilter.h"
55
56 #include <netinet/ip.h>
57 #include <netinet/tcp.h>
58
59 #include <IOKit/pwr_mgt/IOPMLibPrivate.h>
60
61 #ifndef RTF_IFSCOPE
62 #define RTF_IFSCOPE 0x1000000
63 #endif
64
65 #if TARGET_OS_IPHONE
66 #define NO_CFUSERNOTIFICATION 1
67 #define NO_SECURITYFRAMEWORK 1
68 #endif
69
70 // Embed the client stub code here, so we can access private functions like ConnectToServer, create_hdr, deliver_request
71 #include "../mDNSShared/dnssd_ipc.c"
72 #include "../mDNSShared/dnssd_clientstub.c"
73
74 typedef struct sadb_x_policy *ipsec_policy_t;
75
76 uid_t mDNSResponderUID;
77 gid_t mDNSResponderGID;
78
79 void helper_exit()
80 {
81 os_log_info(log_handle,"mDNSResponderHelper exiting");
82 exit(0);
83 }
84
85 mDNSexport void RequestBPF()
86 {
87 DNSServiceRef ref;
88
89 DNSServiceErrorType err = ConnectToServer(&ref, 0, send_bpf, NULL, NULL, NULL);
90 if (err)
91 {
92 os_log(log_handle, "RequestBPF: ConnectToServer %d", err);
93 return;
94 }
95
96 char *ptr;
97 size_t len = sizeof(DNSServiceFlags);
98 ipc_msg_hdr *hdr = create_hdr(send_bpf, &len, &ptr, 0, ref);
99 if (!hdr)
100 {
101 os_log(log_handle, "RequestBPF: No mem to allocate");
102 DNSServiceRefDeallocate(ref);
103 return;
104 }
105
106 put_flags(0, &ptr);
107 deliver_request(hdr, ref); // Will free hdr for us
108 DNSServiceRefDeallocate(ref);
109 update_idle_timer();
110
111 os_log_info(log_handle,"RequestBPF: Successful");
112 }
113
114
115 void PowerRequest(int key, int interval, int *err)
116 {
117 *err = kHelperErr_DefaultErr;
118
119 os_log_info(log_handle,"PowerRequest: key %d interval %d, err %d", key, interval, *err);
120
121 CFArrayRef events = IOPMCopyScheduledPowerEvents();
122 if (events)
123 {
124 int i;
125 CFIndex count = CFArrayGetCount(events);
126 for (i=0; i<count; i++)
127 {
128 CFDictionaryRef dict = CFArrayGetValueAtIndex(events, i);
129 CFStringRef id = CFDictionaryGetValue(dict, CFSTR(kIOPMPowerEventAppNameKey));
130 if (CFEqual(id, CFSTR("mDNSResponderHelper")))
131 {
132 CFDateRef EventTime = CFDictionaryGetValue(dict, CFSTR(kIOPMPowerEventTimeKey));
133 CFStringRef EventType = CFDictionaryGetValue(dict, CFSTR(kIOPMPowerEventTypeKey));
134 IOReturn result = IOPMCancelScheduledPowerEvent(EventTime, id, EventType);
135 //os_log(log_handle, "Deleting old event %s");
136 if (result)
137 os_log(log_handle, "IOPMCancelScheduledPowerEvent %d failed %d", i, result);
138 }
139 }
140 CFRelease(events);
141 }
142
143 if (key < 0) // mDNSPowerRequest(-1,-1) means "clear any stale schedules" (see above)
144 {
145 *err = kHelperErr_NoErr;
146 }
147 else if (key == 0) // mDNSPowerRequest(0, 0) means "sleep now"
148 {
149 IOReturn r = IOPMSleepSystem(IOPMFindPowerManagement(MACH_PORT_NULL));
150 if (r)
151 {
152 usleep(100000);
153 os_log_info(log_handle, "IOPMSleepSystem %d", r);
154 }
155 *err = r;
156 }
157 else if (key > 0)
158 {
159 CFDateRef wakeTime = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent() + interval);
160 if (wakeTime)
161 {
162 CFMutableDictionaryRef scheduleDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
163
164 CFDictionaryAddValue(scheduleDict, CFSTR(kIOPMPowerEventTimeKey), wakeTime);
165 CFDictionaryAddValue(scheduleDict, CFSTR(kIOPMPowerEventAppNameKey), CFSTR("mDNSResponderHelper"));
166 CFDictionaryAddValue(scheduleDict, CFSTR(kIOPMPowerEventTypeKey), key ? CFSTR(kIOPMAutoWake) : CFSTR(kIOPMAutoSleep));
167
168 IOReturn r = IOPMRequestSysWake(scheduleDict);
169 if (r)
170 {
171 usleep(100000);
172 os_log_info(log_handle, "IOPMRequestSysWake(%d) %d %x", interval, r, r);
173 }
174 *err = r;
175 CFRelease(wakeTime);
176 CFRelease(scheduleDict);
177 }
178 }
179
180 update_idle_timer();
181 }
182
183 void SetLocalAddressCacheEntry(int ifindex, int family, const v6addr_t ip, const ethaddr_t eth, int *err)
184 {
185
186 #define IPv6FMTSTRING "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X"
187 #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]
188
189 if (family == 4)
190 {
191 os_log_info(log_handle,"SetLocalAddressCacheEntry %d IPv%d %d.%d.%d.%d %02X:%02X:%02X:%02X:%02X:%02X",
192 ifindex, family, ip[0], ip[1], ip[2], ip[3], eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
193 }
194 else
195 {
196 os_log_info(log_handle,"SetLocalAddressCacheEntry %d IPv%d " IPv6FMTSTRING " %02X:%02X:%02X:%02X:%02X:%02X",
197 ifindex, family, IPv6FMTARGS, eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
198 }
199
200 *err = kHelperErr_DefaultErr;
201
202 static int s = -1, seq = 0;
203 if (s < 0)
204 {
205 s = socket(PF_ROUTE, SOCK_RAW, 0);
206 if (s < 0)
207 os_log(log_handle, "SetLocalAddressCacheEntry: socket(PF_ROUTE, SOCK_RAW, 0) failed %d (%s)", errno, strerror(errno));
208 }
209
210 if (s >= 0)
211 {
212 struct timeval tv;
213 gettimeofday(&tv, 0);
214 if (family == 4)
215 {
216 struct { struct rt_msghdr hdr; struct sockaddr_inarp dst; struct sockaddr_dl sdl; } rtmsg;
217 memset(&rtmsg, 0, sizeof(rtmsg));
218
219 rtmsg.hdr.rtm_msglen = sizeof(rtmsg);
220 rtmsg.hdr.rtm_version = RTM_VERSION;
221 rtmsg.hdr.rtm_type = RTM_ADD;
222 rtmsg.hdr.rtm_index = ifindex;
223 rtmsg.hdr.rtm_flags = RTF_HOST | RTF_STATIC | RTF_IFSCOPE;
224 rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
225 rtmsg.hdr.rtm_pid = 0;
226 rtmsg.hdr.rtm_seq = seq++;
227 rtmsg.hdr.rtm_errno = 0;
228 rtmsg.hdr.rtm_use = 0;
229 rtmsg.hdr.rtm_inits = RTV_EXPIRE;
230 rtmsg.hdr.rtm_rmx.rmx_expire = tv.tv_sec + 30;
231
232 rtmsg.dst.sin_len = sizeof(rtmsg.dst);
233 rtmsg.dst.sin_family = AF_INET;
234 rtmsg.dst.sin_port = 0;
235 rtmsg.dst.sin_addr.s_addr = *(in_addr_t*)ip;
236 rtmsg.dst.sin_srcaddr.s_addr = 0;
237 rtmsg.dst.sin_tos = 0;
238 rtmsg.dst.sin_other = 0;
239
240 rtmsg.sdl.sdl_len = sizeof(rtmsg.sdl);
241 rtmsg.sdl.sdl_family = AF_LINK;
242 rtmsg.sdl.sdl_index = ifindex;
243 rtmsg.sdl.sdl_type = IFT_ETHER;
244 rtmsg.sdl.sdl_nlen = 0;
245 rtmsg.sdl.sdl_alen = ETHER_ADDR_LEN;
246 rtmsg.sdl.sdl_slen = 0;
247
248 // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h)
249 memcpy(rtmsg.sdl.sdl_data, eth, sizeof(ethaddr_t));
250
251 int len = write(s, (char *)&rtmsg, sizeof(rtmsg));
252 if (len < 0)
253 os_log(log_handle, "SetLocalAddressCacheEntry: write(%zu) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s)",
254 sizeof(rtmsg), ifindex, ip[0], ip[1], ip[2], ip[3], rtmsg.hdr.rtm_seq, len, errno, strerror(errno));
255 len = read(s, (char *)&rtmsg, sizeof(rtmsg));
256 if (len < 0 || rtmsg.hdr.rtm_errno)
257 os_log(log_handle, "SetLocalAddressCacheEntry: read (%zu) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s) %d",
258 sizeof(rtmsg), ifindex, ip[0], ip[1], ip[2], ip[3], rtmsg.hdr.rtm_seq, len, errno, strerror(errno), rtmsg.hdr.rtm_errno);
259
260 *err = kHelperErr_NoErr;
261 }
262 else
263 {
264 struct { struct rt_msghdr hdr; struct sockaddr_in6 dst; struct sockaddr_dl sdl; } rtmsg;
265 memset(&rtmsg, 0, sizeof(rtmsg));
266
267 rtmsg.hdr.rtm_msglen = sizeof(rtmsg);
268 rtmsg.hdr.rtm_version = RTM_VERSION;
269 rtmsg.hdr.rtm_type = RTM_ADD;
270 rtmsg.hdr.rtm_index = ifindex;
271 rtmsg.hdr.rtm_flags = RTF_HOST | RTF_STATIC | RTF_IFSCOPE;
272 rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
273 rtmsg.hdr.rtm_pid = 0;
274 rtmsg.hdr.rtm_seq = seq++;
275 rtmsg.hdr.rtm_errno = 0;
276 rtmsg.hdr.rtm_use = 0;
277 rtmsg.hdr.rtm_inits = RTV_EXPIRE;
278 rtmsg.hdr.rtm_rmx.rmx_expire = tv.tv_sec + 30;
279
280 rtmsg.dst.sin6_len = sizeof(rtmsg.dst);
281 rtmsg.dst.sin6_family = AF_INET6;
282 rtmsg.dst.sin6_port = 0;
283 rtmsg.dst.sin6_flowinfo = 0;
284 rtmsg.dst.sin6_addr = *(struct in6_addr*)ip;
285 rtmsg.dst.sin6_scope_id = ifindex;
286
287 rtmsg.sdl.sdl_len = sizeof(rtmsg.sdl);
288 rtmsg.sdl.sdl_family = AF_LINK;
289 rtmsg.sdl.sdl_index = ifindex;
290 rtmsg.sdl.sdl_type = IFT_ETHER;
291 rtmsg.sdl.sdl_nlen = 0;
292 rtmsg.sdl.sdl_alen = ETHER_ADDR_LEN;
293 rtmsg.sdl.sdl_slen = 0;
294
295 // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h)
296 memcpy(rtmsg.sdl.sdl_data, eth, sizeof(ethaddr_t));
297
298 int len = write(s, (char *)&rtmsg, sizeof(rtmsg));
299 if (len < 0)
300 os_log(log_handle, "SetLocalAddressCacheEntry: write(%zu) interface %d address " IPv6FMTSTRING " seq %d result %d errno %d (%s)",
301 sizeof(rtmsg), ifindex, IPv6FMTARGS, rtmsg.hdr.rtm_seq, len, errno, strerror(errno));
302 len = read(s, (char *)&rtmsg, sizeof(rtmsg));
303 if (len < 0 || rtmsg.hdr.rtm_errno)
304 os_log(log_handle, "SetLocalAddressCacheEntry: read (%zu) interface %d address " IPv6FMTSTRING " seq %d result %d errno %d (%s) %d",
305 sizeof(rtmsg), ifindex, IPv6FMTARGS, rtmsg.hdr.rtm_seq, len, errno, strerror(errno), rtmsg.hdr.rtm_errno);
306
307 *err = kHelperErr_NoErr;
308 }
309 }
310
311 update_idle_timer();
312 }
313
314
315 void UserNotify(const char *title, const char *msg)
316 {
317
318 #ifndef NO_CFUSERNOTIFICATION
319 static const char footer[] = "(Note: This message only appears on machines with 17.x.x.x IP addresses"
320 " or on debugging builds with ForceAlerts set — i.e. only at Apple — not on customer machines.)";
321 CFStringRef alertHeader = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8);
322 CFStringRef alertBody = CFStringCreateWithCString(NULL, msg, kCFStringEncodingUTF8);
323 CFStringRef alertFooter = CFStringCreateWithCString(NULL, footer, kCFStringEncodingUTF8);
324 CFStringRef alertMessage = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@\r\r%@"), alertBody, alertFooter);
325 CFRelease(alertBody);
326 CFRelease(alertFooter);
327 int err = CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL, alertHeader, alertMessage, NULL);
328 if (err)
329 os_log(log_handle, "CFUserNotificationDisplayNotice returned %d", err);
330 CFRelease(alertHeader);
331 CFRelease(alertMessage);
332 #else
333 (void)title;
334 (void)msg;
335 #endif /* NO_CFUSERNOTIFICATION */
336
337 update_idle_timer();
338 }
339
340
341 char usercompname[MAX_DOMAIN_LABEL+1] = {0}; // the last computer name the user saw
342 char userhostname[MAX_DOMAIN_LABEL+1] = {0}; // the last local host name the user saw
343 char lastcompname[MAX_DOMAIN_LABEL+1] = {0}; // the last computer name saved to preferences
344 char lasthostname[MAX_DOMAIN_LABEL+1] = {0}; // the last local host name saved to preferences
345
346 #ifndef NO_CFUSERNOTIFICATION
347 static CFStringRef CFS_OQ = NULL;
348 static CFStringRef CFS_CQ = NULL;
349 static CFStringRef CFS_Format = NULL;
350 static CFStringRef CFS_ComputerName = NULL;
351 static CFStringRef CFS_ComputerNameMsg = NULL;
352 static CFStringRef CFS_LocalHostName = NULL;
353 static CFStringRef CFS_LocalHostNameMsg = NULL;
354 static CFStringRef CFS_Problem = NULL;
355
356 static CFUserNotificationRef gNotification = NULL;
357 static CFRunLoopSourceRef gNotificationRLS = NULL;
358
359 static void NotificationCallBackDismissed(CFUserNotificationRef userNotification, CFOptionFlags responseFlags)
360 {
361 os_log_debug(log_handle,"entry");
362 (void)responseFlags; // Unused
363 if (userNotification != gNotification) os_log(log_handle, "NotificationCallBackDismissed: Wrong CFUserNotificationRef");
364 if (gNotificationRLS)
365 {
366 // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
367 // We need to explicitly specify the desired CFRunLoop from which we want to remove this event source.
368 CFRunLoopRemoveSource(gRunLoop, gNotificationRLS, kCFRunLoopDefaultMode);
369 CFRelease(gNotificationRLS);
370 gNotificationRLS = NULL;
371 CFRelease(gNotification);
372 gNotification = NULL;
373 }
374 // By dismissing the alert, the user has conceptually acknowleged the rename.
375 // (e.g. the machine's name is now officially "computer-2.local", not "computer.local".)
376 // If we get *another* conflict, the new alert should refer to the 'old' name
377 // as now being "computer-2.local", not "computer.local"
378 usercompname[0] = 0;
379 userhostname[0] = 0;
380 lastcompname[0] = 0;
381 lasthostname[0] = 0;
382 update_idle_timer();
383 unpause_idle_timer();
384 }
385
386 static void ShowNameConflictNotification(CFMutableArrayRef header, CFStringRef subtext)
387 {
388 CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
389 if (!dictionary) return;
390
391 os_log_debug(log_handle,"entry");
392
393 CFDictionarySetValue(dictionary, kCFUserNotificationAlertHeaderKey, header);
394 CFDictionarySetValue(dictionary, kCFUserNotificationAlertMessageKey, subtext);
395
396 CFURLRef urlRef = CFURLCreateWithFileSystemPath(NULL, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle, true);
397 if (urlRef) { CFDictionarySetValue(dictionary, kCFUserNotificationLocalizationURLKey, urlRef); CFRelease(urlRef); }
398
399 if (gNotification) // If notification already on-screen, update it in place
400 CFUserNotificationUpdate(gNotification, 0, kCFUserNotificationCautionAlertLevel, dictionary);
401 else // else, we need to create it
402 {
403 SInt32 error;
404 gNotification = CFUserNotificationCreate(NULL, 0, kCFUserNotificationCautionAlertLevel, &error, dictionary);
405 if (!gNotification || error) { os_log(log_handle, "ShowNameConflictNotification: CFUserNotificationRef: Error %d", error); return; }
406 gNotificationRLS = CFUserNotificationCreateRunLoopSource(NULL, gNotification, NotificationCallBackDismissed, 0);
407 if (!gNotificationRLS) { os_log(log_handle, "ShowNameConflictNotification: RLS"); CFRelease(gNotification); gNotification = NULL; return; }
408 // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
409 // We need to explicitly specify the desired CFRunLoop to which we want to add this event source.
410 CFRunLoopAddSource(gRunLoop, gNotificationRLS, kCFRunLoopDefaultMode);
411 os_log_debug(log_handle,"gRunLoop=%p gNotification=%p gNotificationRLS=%p", gRunLoop, gNotification, gNotificationRLS);
412 pause_idle_timer();
413 }
414
415 CFRelease(dictionary);
416 }
417
418 static CFMutableArrayRef CreateAlertHeader(const char* oldname, const char* newname, const CFStringRef msg, const char* suffix)
419 {
420 CFMutableArrayRef alertHeader = NULL;
421
422 const CFStringRef cfoldname = CFStringCreateWithCString(NULL, oldname, kCFStringEncodingUTF8);
423 // NULL newname means we've given up trying to construct a name that doesn't conflict
424 const CFStringRef cfnewname = newname ? CFStringCreateWithCString(NULL, newname, kCFStringEncodingUTF8) : NULL;
425 // We tag a zero-width non-breaking space at the end of the literal text to guarantee that, no matter what
426 // arbitrary computer name the user may choose, this exact text (with zero-width non-breaking space added)
427 // can never be one that occurs in the Localizable.strings translation file.
428 if (!cfoldname)
429 {
430 os_log(log_handle, "Could not construct CFStrings for old=%s", newname);
431 }
432 else if (newname && !cfnewname)
433 {
434 os_log(log_handle, "Could not construct CFStrings for new=%s", newname);
435 }
436 else
437 {
438 const CFStringRef s1 = CFStringCreateWithFormat(NULL, NULL, CFS_Format, cfoldname, suffix);
439 const CFStringRef s2 = cfnewname ? CFStringCreateWithFormat(NULL, NULL, CFS_Format, cfnewname, suffix) : NULL;
440
441 alertHeader = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
442
443 if (!s1)
444 {
445 os_log(log_handle, "Could not construct secondary CFString for old=%s", oldname);
446 }
447 else if (cfnewname && !s2)
448 {
449 os_log(log_handle, "Could not construct secondary CFString for new=%s", newname);
450 }
451 else if (!alertHeader)
452 {
453 os_log(log_handle, "Could not construct CFArray for notification");
454 }
455 else
456 {
457 // Make sure someone is logged in. We don't want this popping up over the login window
458 uid_t uid;
459 gid_t gid;
460 CFStringRef userName = SCDynamicStoreCopyConsoleUser(NULL, &uid, &gid);
461 if (userName)
462 {
463 if (!CFEqual(userName, CFSTR("_mbsetupuser")))
464 {
465 CFArrayAppendValue(alertHeader, msg); // Opening phrase of message, provided by caller
466 CFArrayAppendValue(alertHeader, CFS_OQ); CFArrayAppendValue(alertHeader, s1); CFArrayAppendValue(alertHeader, CFS_CQ);
467 CFArrayAppendValue(alertHeader, CFSTR(" is already in use on this network. "));
468 if (s2)
469 {
470 CFArrayAppendValue(alertHeader, CFSTR("The name has been changed to "));
471 CFArrayAppendValue(alertHeader, CFS_OQ); CFArrayAppendValue(alertHeader, s2); CFArrayAppendValue(alertHeader, CFS_CQ);
472 CFArrayAppendValue(alertHeader, CFSTR("."));
473 }
474 else
475 {
476 CFArrayAppendValue(alertHeader, CFSTR("All attempts to find an available name by adding a number to the name were also unsuccessful."));
477 }
478 }
479 CFRelease(userName);
480 }
481 }
482 if (s1) CFRelease(s1);
483 if (s2) CFRelease(s2);
484 }
485 if (cfoldname) CFRelease(cfoldname);
486 if (cfnewname) CFRelease(cfnewname);
487
488 return alertHeader;
489 }
490 #endif /* ndef NO_CFUSERNOTIFICATION */
491
492 static void update_notification(void)
493 {
494 #ifndef NO_CFUSERNOTIFICATION
495 os_log_debug(log_handle,"entry ucn=%s, uhn=%s, lcn=%s, lhn=%s", usercompname, userhostname, lastcompname, lasthostname);
496 if (!CFS_OQ)
497 {
498 // Note: The "\xEF\xBB\xBF" byte sequence (U+FEFF) in the CFS_Format string is the UTF-8 encoding of the zero-width non-breaking space character.
499 // By appending this invisible character on the end of literal names, we ensure the these strings cannot inadvertently match any string
500 // in the localization file -- since we know for sure that none of our strings in the localization file contain the ZWNBS character.
501 CFS_Format = CFStringCreateWithCString(NULL, "%@%s\xEF\xBB\xBF", kCFStringEncodingUTF8);
502
503 // The strings CFS_OQ, CFS_CQ and the others below are the localization keys for the “Localizable.strings” files,
504 // and MUST NOT BE CHANGED, or localization substitution will be broken.
505 // To change the text displayed to the user, edit the values in the appropriate “Localizable.strings” file, not the keys here.
506 // This includes making changes for adding appropriate directionality overrides like LRM, LRE, RLE, PDF, etc. These need to go in the values
507 // in the appropriate “Localizable.strings” entries, not in the keys here (which then won’t match *any* entry in the localization files).
508 // These localization keys here were broken in <rdar://problem/8629082> and then subsequently repaired in
509 // <rdar://problem/21071535> [mDNSResponder]: TA: Gala15A185: Incorrect punctuation marks when Change the host name to an exist one
510 CFS_OQ = CFStringCreateWithCString(NULL, "“", kCFStringEncodingUTF8); // DO NOT CHANGE THIS STRING
511 CFS_CQ = CFStringCreateWithCString(NULL, "”", kCFStringEncodingUTF8); // DO NOT CHANGE THIS STRING
512 CFS_ComputerName = CFStringCreateWithCString(NULL, "The name of your computer ", kCFStringEncodingUTF8);
513 CFS_ComputerNameMsg = CFStringCreateWithCString(NULL, "To change the name of your computer, "
514 "open System Preferences and click Sharing, then type the name in the Computer Name field.", kCFStringEncodingUTF8);
515 CFS_LocalHostName = CFStringCreateWithCString(NULL, "This computer’s local hostname ", kCFStringEncodingUTF8);
516 CFS_LocalHostNameMsg = CFStringCreateWithCString(NULL, "To change the local hostname, "
517 "open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field.", kCFStringEncodingUTF8);
518 CFS_Problem = CFStringCreateWithCString(NULL, "This may indicate a problem with the local network. "
519 "Please inform your network administrator.", kCFStringEncodingUTF8);
520 }
521
522 if (!usercompname[0] && !userhostname[0])
523 {
524 if (gNotificationRLS)
525 {
526 os_log_debug(log_handle,"canceling notification %p", gNotification);
527 CFUserNotificationCancel(gNotification);
528 unpause_idle_timer();
529 }
530 }
531 else
532 {
533 CFMutableArrayRef header = NULL;
534 CFStringRef* subtext = NULL;
535 if (userhostname[0] && !lasthostname[0]) // we've given up trying to construct a name that doesn't conflict
536 {
537 header = CreateAlertHeader(userhostname, NULL, CFS_LocalHostName, ".local");
538 subtext = &CFS_Problem;
539 }
540 else if (usercompname[0])
541 {
542 header = CreateAlertHeader(usercompname, lastcompname, CFS_ComputerName, "");
543 subtext = &CFS_ComputerNameMsg;
544 }
545 else
546 {
547 header = CreateAlertHeader(userhostname, lasthostname, CFS_LocalHostName, ".local");
548 subtext = &CFS_LocalHostNameMsg;
549 }
550 ShowNameConflictNotification(header, *subtext);
551 CFRelease(header);
552 }
553 #endif
554 }
555
556 void PreferencesSetName(int key, const char* old, const char* new)
557 {
558 SCPreferencesRef session = NULL;
559 Boolean ok = FALSE;
560 Boolean locked = FALSE;
561 CFStringRef cfstr = NULL;
562 char* user = NULL;
563 char* last = NULL;
564 Boolean needUpdate = FALSE;
565
566 os_log_info(log_handle,"PreferencesSetName: entry %s old=%s new=%s",
567 key==kmDNSComputerName ? "ComputerName" : (key==kmDNSLocalHostName ? "LocalHostName" : "UNKNOWN"), old, new);
568
569 switch ((enum mDNSPreferencesSetNameKey)key)
570 {
571 case kmDNSComputerName:
572 user = usercompname;
573 last = lastcompname;
574 break;
575 case kmDNSLocalHostName:
576 user = userhostname;
577 last = lasthostname;
578 break;
579 default:
580 os_log(log_handle, "PreferencesSetName: unrecognized key: %d", key);
581 goto fin;
582 }
583
584 if (!last)
585 {
586 os_log(log_handle, "PreferencesSetName: no last ptr");
587 goto fin;
588 }
589
590 if (!user)
591 {
592 os_log(log_handle, "PreferencesSetName:: no user ptr");
593 goto fin;
594 }
595
596 if (0 == strncmp(old, new, MAX_DOMAIN_LABEL+1))
597 {
598 // old and new are same means the config changed i.e, the user has set something in the preferences pane.
599 // This means the conflict has been resolved. We need to dismiss the dialogue.
600 if (last[0] && 0 != strncmp(last, new, MAX_DOMAIN_LABEL+1))
601 {
602 last[0] = 0;
603 user[0] = 0;
604 needUpdate = TRUE;
605 }
606 goto fin;
607 }
608 else
609 {
610 // old and new are not same, this means there is a conflict. For the first conflict, we show
611 // the old value and the new value. For all subsequent conflicts, while the dialogue is still
612 // up, we do a real time update of the "new" value in the dialogue. That's why we update just
613 // "last" here and not "user".
614 if (strncmp(last, new, MAX_DOMAIN_LABEL+1))
615 {
616 strncpy(last, new, MAX_DOMAIN_LABEL);
617 needUpdate = TRUE;
618 }
619 }
620
621 // If we are not showing the dialogue, we need to remember the first "old" value so that
622 // we maintain the same through the lifetime of the dialogue. Subsequent conflicts don't
623 // update the "old" value.
624 if (!user[0])
625 {
626 strncpy(user, old, MAX_DOMAIN_LABEL);
627 needUpdate = TRUE;
628 }
629
630 if (!new[0]) // we've given up trying to construct a name that doesn't conflict
631 goto fin;
632
633 cfstr = CFStringCreateWithCString(NULL, new, kCFStringEncodingUTF8);
634
635 session = SCPreferencesCreate(NULL, CFSTR(kHelperService), NULL);
636
637 if (cfstr == NULL || session == NULL)
638 {
639 os_log(log_handle, "PreferencesSetName: SCPreferencesCreate failed");
640 goto fin;
641 }
642 if (!SCPreferencesLock(session, 0))
643 {
644 os_log(log_handle,"PreferencesSetName: lock failed");
645 goto fin;
646 }
647 locked = TRUE;
648
649 switch ((enum mDNSPreferencesSetNameKey)key)
650 {
651 case kmDNSComputerName:
652 {
653 // We want to write the new Computer Name to System Preferences, without disturbing the user-selected
654 // system-wide default character set used for things like AppleTalk NBP and NETBIOS service advertising.
655 // Note that this encoding is not used for the computer name, but since both are set by the same call,
656 // we need to take care to set the name without changing the character set.
657 CFStringEncoding encoding = kCFStringEncodingUTF8;
658 CFStringRef unused = SCDynamicStoreCopyComputerName(NULL, &encoding);
659 if (unused)
660 {
661 CFRelease(unused);
662 unused = NULL;
663 }
664 else
665 {
666 encoding = kCFStringEncodingUTF8;
667 }
668
669 ok = SCPreferencesSetComputerName(session, cfstr, encoding);
670 }
671 break;
672
673 case kmDNSLocalHostName:
674 ok = SCPreferencesSetLocalHostName(session, cfstr);
675 break;
676
677 default:
678 break;
679 }
680
681 if (!ok || !SCPreferencesCommitChanges(session) ||
682 !SCPreferencesApplyChanges(session))
683 {
684 os_log(log_handle, "PreferencesSetName: SCPreferences update failed");
685 goto fin;
686 }
687 os_log_info(log_handle,"PreferencesSetName: succeeded");
688
689 fin:
690 if (NULL != cfstr)
691 CFRelease(cfstr);
692 if (NULL != session)
693 {
694 if (locked)
695 SCPreferencesUnlock(session);
696 CFRelease(session);
697 }
698 update_idle_timer();
699 if (needUpdate)
700 update_notification();
701
702 }
703
704
705 enum DNSKeyFormat
706 {
707 formatNotDNSKey,
708 formatDdnsTypeItem,
709 formatDnsPrefixedServiceItem,
710 };
711
712 // On Mac OS X on Intel, the four-character string seems to be stored backwards, at least sometimes.
713 // I suspect some overenthusiastic inexperienced engineer said, "On Intel everything's backwards,
714 // therefore I need to add some byte swapping in this API to make this four-character string backwards too."
715 // To cope with this we allow *both* "ddns" and "sndd" as valid item types.
716
717
718 #ifndef NO_SECURITYFRAMEWORK
719 static const char dnsprefix[] = "dns:";
720 static const char ddns[] = "ddns";
721 static const char ddnsrev[] = "sndd";
722
723 static enum DNSKeyFormat getDNSKeyFormat(SecKeychainItemRef item, SecKeychainAttributeList **attributesp)
724 {
725 static UInt32 tags[4] =
726 {
727 kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr, kSecLabelItemAttr
728 };
729 static SecKeychainAttributeInfo attributeInfo =
730 {
731 sizeof(tags)/sizeof(tags[0]), tags, NULL
732 };
733 SecKeychainAttributeList *attributes = NULL;
734 enum DNSKeyFormat format;
735 Boolean malformed = FALSE;
736 OSStatus status = noErr;
737 int i = 0;
738
739 *attributesp = NULL;
740 if (noErr != (status = SecKeychainItemCopyAttributesAndData(item, &attributeInfo, NULL, &attributes, NULL, NULL)))
741 {
742 os_log_info(log_handle,"getDNSKeyFormat: SecKeychainItemCopyAttributesAndData %d - skipping", status);
743 goto skip;
744 }
745 if (attributeInfo.count != attributes->count)
746 malformed = TRUE;
747 for (i = 0; !malformed && i < (int)attributeInfo.count; ++i)
748 if (attributeInfo.tag[i] != attributes->attr[i].tag)
749 malformed = TRUE;
750 if (malformed)
751 {
752 os_log(log_handle, "getDNSKeyFormat: malformed result from SecKeychainItemCopyAttributesAndData - skipping");
753 goto skip;
754 }
755
756 os_log_info(log_handle,"getDNSKeyFormat: entry (\"%.*s\", \"%.*s\", \"%.*s\")",
757 (int)attributes->attr[0].length, attributes->attr[0].data,
758 (int)attributes->attr[1].length, attributes->attr[1].data,
759 (int)attributes->attr[2].length, attributes->attr[2].data);
760
761 if (attributes->attr[1].length >= MAX_ESCAPED_DOMAIN_NAME +
762 sizeof(dnsprefix)-1)
763 {
764 os_log(log_handle, "getDNSKeyFormat: kSecServiceItemAttr too long (%u) - skipping",
765 (unsigned int)attributes->attr[1].length);
766 goto skip;
767 }
768 if (attributes->attr[2].length >= MAX_ESCAPED_DOMAIN_NAME)
769 {
770 os_log(log_handle, "getDNSKeyFormat: kSecAccountItemAttr too long (%u) - skipping",
771 (unsigned int)attributes->attr[2].length);
772 goto skip;
773 }
774 if (attributes->attr[1].length >= sizeof(dnsprefix)-1 && 0 == strncasecmp(attributes->attr[1].data, dnsprefix, sizeof(dnsprefix)-1))
775 format = formatDnsPrefixedServiceItem;
776 else if (attributes->attr[0].length == sizeof(ddns)-1 && 0 == strncasecmp(attributes->attr[0].data, ddns, sizeof(ddns)-1))
777 format = formatDdnsTypeItem;
778 else if (attributes->attr[0].length == sizeof(ddnsrev)-1 && 0 == strncasecmp(attributes->attr[0].data, ddnsrev, sizeof(ddnsrev)-1))
779 format = formatDdnsTypeItem;
780 else
781 {
782 os_log_info(log_handle,"getDNSKeyFormat: uninterested in this entry");
783 goto skip;
784 }
785
786 *attributesp = attributes;
787 os_log_info(log_handle,"getDNSKeyFormat: accepting this entry");
788 return format;
789
790 skip:
791 SecKeychainItemFreeAttributesAndData(attributes, NULL);
792 return formatNotDNSKey;
793 }
794
795 // Insert the attributes as defined by mDNSKeyChainAttributes
796 static CFPropertyListRef copyKeychainItemInfo(SecKeychainItemRef item, SecKeychainAttributeList *attributes, enum DNSKeyFormat format)
797 {
798 CFMutableArrayRef entry = NULL;
799 CFDataRef data = NULL;
800 OSStatus status = noErr;
801 UInt32 keylen = 0;
802 void *keyp = 0;
803
804 if (NULL == (entry = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)))
805 {
806 os_log(log_handle, "copyKeychainItemInfo: CFArrayCreateMutable failed");
807 goto error;
808 }
809
810 // Insert the Account attribute (kmDNSKcWhere)
811 switch ((enum DNSKeyFormat)format)
812 {
813 case formatDdnsTypeItem:
814 data = CFDataCreate(kCFAllocatorDefault, attributes->attr[1].data, attributes->attr[1].length);
815 break;
816 case formatDnsPrefixedServiceItem:
817 data = CFDataCreate(kCFAllocatorDefault, attributes->attr[1].data, attributes->attr[1].length);
818 break;
819 default:
820 os_log(log_handle, "copyKeychainItemInfo: unknown DNSKeyFormat value");
821 break;
822 }
823 if (NULL == data)
824 {
825 os_log(log_handle, "copyKeychainItemInfo: CFDataCreate for attr[1] failed");
826 goto error;
827 }
828 CFArrayAppendValue(entry, data);
829 CFRelease(data);
830
831 // Insert the Where attribute (kmDNSKcAccount)
832 if (NULL == (data = CFDataCreate(kCFAllocatorDefault, attributes->attr[2].data, attributes->attr[2].length)))
833 {
834 os_log(log_handle, "copyKeychainItemInfo: CFDataCreate for attr[2] failed");
835 goto error;
836 }
837
838 CFArrayAppendValue(entry, data);
839 CFRelease(data);
840
841 // Insert the Key attribute (kmDNSKcKey)
842 if (noErr != (status = SecKeychainItemCopyAttributesAndData(item, NULL, NULL, NULL, &keylen, &keyp)))
843 {
844 os_log(log_handle, "copyKeychainItemInfo: could not retrieve key for \"%.*s\": %d",
845 (int)attributes->attr[1].length, attributes->attr[1].data, status);
846 goto error;
847 }
848
849 data = CFDataCreate(kCFAllocatorDefault, keyp, keylen);
850 SecKeychainItemFreeAttributesAndData(NULL, keyp);
851 if (NULL == data)
852 {
853 os_log(log_handle, "copyKeychainItemInfo: 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, attributes->attr[3].data, attributes->attr[3].length)))
861 {
862 os_log(log_handle, "copyKeychainItemInfo: CFDataCreate for attr[3] failed");
863 goto error;
864 }
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 void KeychainGetSecrets(__unused unsigned int *numsecrets,__unused unsigned long *secrets, __unused unsigned int *secretsCnt, __unused int *err)
878 {
879 #ifndef NO_SECURITYFRAMEWORK
880 CFWriteStreamRef stream = NULL;
881 CFDataRef result = NULL;
882 CFPropertyListRef entry = NULL;
883 CFMutableArrayRef keys = NULL;
884 SecKeychainRef skc = NULL;
885 SecKeychainItemRef item = NULL;
886 SecKeychainSearchRef search = NULL;
887 SecKeychainAttributeList *attributes = NULL;
888 enum DNSKeyFormat format;
889 OSStatus status = 0;
890
891 os_log_info(log_handle,"KeychainGetSecrets: entry");
892 *err = kHelperErr_NoErr;
893 *numsecrets = 0;
894 *secrets = (vm_offset_t)NULL;
895
896 if (NULL == (keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)))
897 {
898 os_log(log_handle, "KeychainGetSecrets: CFArrayCreateMutable failed");
899 *err = kHelperErr_ApiErr;
900 goto fin;
901 }
902 if (noErr != (status = SecKeychainCopyDefault(&skc)))
903 {
904 *err = kHelperErr_ApiErr;
905 goto fin;
906 }
907 #pragma clang diagnostic push
908 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
909 if (noErr != (status = SecKeychainSearchCreateFromAttributes(skc, kSecGenericPasswordItemClass, NULL, &search)))
910 {
911 *err = kHelperErr_ApiErr;
912 goto fin;
913 }
914 for (status = SecKeychainSearchCopyNext(search, &item); noErr == status; status = SecKeychainSearchCopyNext(search, &item))
915 {
916 if (formatNotDNSKey != (format = getDNSKeyFormat(item, &attributes)) &&
917 NULL != (entry = copyKeychainItemInfo(item, attributes, format)))
918 {
919 CFArrayAppendValue(keys, entry);
920 CFRelease(entry);
921 }
922 SecKeychainItemFreeAttributesAndData(attributes, NULL);
923 CFRelease(item);
924 }
925 #pragma clang diagnostic pop
926 if (errSecItemNotFound != status)
927 os_log(log_handle, "KeychainGetSecrets: SecKeychainSearchCopyNext failed: %d", status);
928
929 if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorDefault, kCFAllocatorDefault)))
930 {
931 *err = kHelperErr_ApiErr;
932 os_log(log_handle, "KeychainGetSecrets:CFWriteStreamCreateWithAllocatedBuffers failed");
933 goto fin;
934 }
935
936 CFWriteStreamOpen(stream);
937 if (0 == CFPropertyListWrite(keys, stream, kCFPropertyListBinaryFormat_v1_0, 0, NULL))
938 {
939 *err = kHelperErr_ApiErr;
940 os_log(log_handle, "KeychainGetSecrets:CFPropertyListWriteToStream failed");
941 goto fin;
942 }
943 result = CFWriteStreamCopyProperty(stream, kCFStreamPropertyDataWritten);
944
945 if (KERN_SUCCESS != vm_allocate(mach_task_self(), secrets, CFDataGetLength(result), VM_FLAGS_ANYWHERE))
946 {
947 *err = kHelperErr_ApiErr;
948 os_log(log_handle, "KeychainGetSecrets: vm_allocate failed");
949 goto fin;
950 }
951
952 CFDataGetBytes(result, CFRangeMake(0, CFDataGetLength(result)), (void *)*secrets);
953 *secretsCnt = CFDataGetLength(result);
954 *numsecrets = CFArrayGetCount(keys);
955
956 os_log_info(log_handle,"KeychainGetSecrets: succeeded");
957
958 fin:
959 os_log_info(log_handle,"KeychainGetSecrets: returning numsecrets[%u] secrets[%lu] secrets addr[%p] secretscount[%u]",
960 *numsecrets, *secrets, secrets, *secretsCnt);
961
962 if (NULL != stream)
963 {
964 CFWriteStreamClose(stream);
965 CFRelease(stream);
966 }
967 if (NULL != result)
968 CFRelease(result);
969 if (NULL != keys)
970 CFRelease(keys);
971 if (NULL != search)
972 CFRelease(search);
973 if (NULL != skc)
974 CFRelease(skc);
975 update_idle_timer();
976
977 *err = KERN_SUCCESS;
978
979 #else
980
981 *err = KERN_FAILURE;
982
983 #endif
984
985 }
986
987
988 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
989 CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
990
991
992 void SendWakeupPacket(unsigned int ifid, const char *eth_addr, const char *ip_addr, int iteration)
993 {
994 int bpf_fd, i, j;
995 struct ifreq ifr;
996 char ifname[IFNAMSIZ];
997 char packet[512];
998 char *ptr = packet;
999 char bpf_device[12];
1000 struct ether_addr *ea;
1001 // (void) ip_addr; // unused
1002 // (void) iteration; // unused
1003
1004 os_log_info(log_handle,"SendWakeupPacket() ether_addr[%s] ip_addr[%s] if_id[%d] iteration[%d]",
1005 eth_addr, ip_addr, ifid, iteration);
1006
1007 if (if_indextoname(ifid, ifname) == NULL)
1008 {
1009 os_log(log_handle, "SendWakeupPacket: invalid interface index %u", ifid);
1010 return;
1011 }
1012
1013 ea = ether_aton(eth_addr);
1014 if (ea == NULL)
1015 {
1016 os_log(log_handle, "SendWakeupPacket: invalid ethernet address %s", eth_addr);
1017 return;
1018 }
1019
1020 for (i = 0; i < 100; i++)
1021 {
1022 snprintf(bpf_device, sizeof(bpf_device), "/dev/bpf%d", i);
1023 bpf_fd = open(bpf_device, O_RDWR, 0);
1024
1025 if (bpf_fd == -1)
1026 continue;
1027 else
1028 break;
1029 }
1030
1031 if (bpf_fd == -1)
1032 {
1033 os_log(log_handle, "SendWakeupPacket: cannot find a bpf device");
1034 return;
1035 }
1036
1037 memset(&ifr, 0, sizeof(ifr));
1038 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1039
1040 if (ioctl(bpf_fd, BIOCSETIF, (char *)&ifr) < 0)
1041 {
1042 os_log(log_handle, "SendWakeupPacket: BIOCSETIF failed %s", strerror(errno));
1043 return;
1044 }
1045
1046 // 0x00 Destination address
1047 for (i=0; i<6; i++)
1048 *ptr++ = ea->octet[i];
1049
1050 // 0x06 Source address (Note: Since we don't currently set the BIOCSHDRCMPLT option,
1051 // BPF will fill in the real interface address for us)
1052 for (i=0; i<6; i++)
1053 *ptr++ = 0;
1054
1055 // 0x0C Ethertype (0x0842)
1056 *ptr++ = 0x08;
1057 *ptr++ = 0x42;
1058
1059 // 0x0E Wakeup sync sequence
1060 for (i=0; i<6; i++)
1061 *ptr++ = 0xFF;
1062
1063 // 0x14 Wakeup data
1064 for (j=0; j<16; j++)
1065 for (i=0; i<6; i++)
1066 *ptr++ = ea->octet[i];
1067
1068 // 0x74 Password
1069 for (i=0; i<6; i++)
1070 *ptr++ = 0;
1071
1072 if (write(bpf_fd, packet, ptr - packet) < 0)
1073 {
1074 os_log(log_handle, "SendWakeupPacket: write failed %s", strerror(errno));
1075 return;
1076 }
1077 os_log(log_handle, "SendWakeupPacket: sent unicast eth_addr %s, ip_addr %s", eth_addr, ip_addr);
1078
1079 // Send a broadcast one to handle ethernet switches that don't flood forward packets with
1080 // unknown mac addresses.
1081 for (i=0; i<6; i++)
1082 packet[i] = 0xFF;
1083
1084 if (write(bpf_fd, packet, ptr - packet) < 0)
1085 {
1086 os_log(log_handle, "SendWakeupPacket: write failed %s", strerror(errno));
1087 return;
1088 }
1089 os_log(log_handle, "SendWakeupPacket: sent broadcast eth_addr %s, ip_addr %s", eth_addr, ip_addr);
1090
1091 close(bpf_fd);
1092
1093 }
1094
1095
1096 // Open the specified port for protocol in the P2P firewall.
1097 void PacketFilterControl(uint32_t command, const char * ifname, uint32_t count, pfArray_t portArray, pfArray_t protocolArray)
1098 {
1099 int error;
1100
1101 os_log_info(log_handle,"PacketFilterControl: command %d ifname %s, count %d",
1102 command, ifname, count);
1103 os_log_info(log_handle,"PacketFilterControl: portArray0[%d] portArray1[%d] portArray2[%d] portArray3[%d] protocolArray0[%d] protocolArray1[%d] protocolArray2[%d] protocolArray3[%d]", portArray[0], portArray[1], portArray[2], portArray[3], protocolArray[0], protocolArray[1], protocolArray[2], protocolArray[3]);
1104
1105 switch (command)
1106 {
1107 case PF_SET_RULES:
1108 error = P2PPacketFilterAddBonjourRuleSet(ifname, count, portArray, protocolArray);
1109 if (error)
1110 os_log(log_handle, "P2PPacketFilterAddBonjourRuleSet failed %s", strerror(error));
1111 break;
1112
1113 case PF_CLEAR_RULES:
1114 error = P2PPacketFilterClearBonjourRules();
1115 if (error)
1116 os_log(log_handle, "P2PPacketFilterClearBonjourRules failed %s", strerror(error));
1117 break;
1118
1119 default:
1120 os_log(log_handle, "PacketFilterControl: invalid command %d", command);
1121 break;
1122 }
1123
1124 }
1125
1126 static unsigned long in_cksum(unsigned short *ptr, int nbytes)
1127 {
1128 unsigned long sum;
1129 u_short oddbyte;
1130
1131 /*
1132 * Our algorithm is simple, using a 32-bit accumulator (sum),
1133 * we add sequential 16-bit words to it, and at the end, fold back
1134 * all the carry bits from the top 16 bits into the lower 16 bits.
1135 */
1136 sum = 0;
1137 while (nbytes > 1)
1138 {
1139 sum += *ptr++;
1140 nbytes -= 2;
1141 }
1142
1143 /* mop up an odd byte, if necessary */
1144 if (nbytes == 1)
1145 {
1146 /* make sure top half is zero */
1147 oddbyte = 0;
1148
1149 /* one byte only */
1150 *((u_char *)&oddbyte) = *(u_char *)ptr;
1151 sum += oddbyte;
1152 }
1153 /* Add back carry outs from top 16 bits to low 16 bits. */
1154 sum = (sum >> 16) + (sum & 0xffff);
1155
1156 /* add carry */
1157 sum += (sum >> 16);
1158
1159 return sum;
1160 }
1161
1162 static unsigned short InetChecksum(unsigned short *ptr, int nbytes)
1163 {
1164 unsigned long sum;
1165
1166 sum = in_cksum(ptr, nbytes);
1167 return (unsigned short)~sum;
1168 }
1169
1170 static void TCPCheckSum(int af, struct tcphdr *t, int tcplen, const v6addr_t sadd6, const v6addr_t dadd6)
1171 {
1172 unsigned long sum = 0;
1173 unsigned short *ptr;
1174
1175 /* TCP header checksum */
1176 sum = in_cksum((unsigned short *)t, tcplen);
1177
1178 if (af == AF_INET)
1179 {
1180 /* Pseudo header */
1181 ptr = (unsigned short *)sadd6;
1182 sum += *ptr++;
1183 sum += *ptr++;
1184 ptr = (unsigned short *)dadd6;
1185 sum += *ptr++;
1186 sum += *ptr++;
1187 }
1188 else if (af == AF_INET6)
1189 {
1190 /* Pseudo header */
1191 ptr = (unsigned short *)sadd6;
1192 sum += *ptr++;
1193 sum += *ptr++;
1194 sum += *ptr++;
1195 sum += *ptr++;
1196 sum += *ptr++;
1197 sum += *ptr++;
1198 sum += *ptr++;
1199 sum += *ptr++;
1200 ptr = (unsigned short *)dadd6;
1201 sum += *ptr++;
1202 sum += *ptr++;
1203 sum += *ptr++;
1204 sum += *ptr++;
1205 sum += *ptr++;
1206 sum += *ptr++;
1207 sum += *ptr++;
1208 sum += *ptr++;
1209 }
1210
1211 sum += htons(tcplen);
1212 sum += htons(IPPROTO_TCP);
1213
1214 while (sum >> 16)
1215 sum = (sum >> 16) + (sum & 0xFFFF);
1216
1217 t->th_sum = ~sum;
1218
1219 }
1220
1221 void SendKeepalive(const v6addr_t sadd6, const v6addr_t dadd6, uint16_t lport, uint16_t rport, uint32_t seq, uint32_t ack, uint16_t win)
1222 {
1223
1224 #define IPv6FMTSTRING "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X"
1225 #define IPv6FMTSARGS sadd6[0], sadd6[1], sadd6[2], sadd6[3], sadd6[4], sadd6[5], sadd6[6], sadd6[7], sadd6[8], sadd6[9], sadd6[10], sadd6[11], sadd6[12], sadd6[13], sadd6[14], sadd6[15]
1226 #define IPv6FMTDARGS dadd6[0], dadd6[1], dadd6[2], dadd6[3], dadd6[4], dadd6[5], dadd6[6], dadd6[7], dadd6[8], dadd6[9], dadd6[10], dadd6[11], dadd6[12], dadd6[13], dadd6[14], dadd6[15]
1227
1228 os_log_info(log_handle, "SendKeepalive: "IPv6FMTSTRING" :space: "IPv6FMTSTRING"",
1229 IPv6FMTSARGS, IPv6FMTDARGS);
1230
1231 struct packet4
1232 {
1233 struct ip ip;
1234 struct tcphdr tcp;
1235 } packet4;
1236 struct packet6
1237 {
1238 struct tcphdr tcp;
1239 } packet6;
1240 int sock, on;
1241 struct tcphdr *t;
1242 int af;
1243 struct sockaddr_storage ss_to;
1244 struct sockaddr_in *sin_to = (struct sockaddr_in *)&ss_to;
1245 struct sockaddr_in6 *sin6_to = (struct sockaddr_in6 *)&ss_to;
1246 void *packet;
1247 ssize_t packetlen;
1248 char ctlbuf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
1249 struct msghdr msghdr;
1250 struct iovec iov;
1251 ssize_t len;
1252
1253 os_log_info(log_handle,"SendKeepalive invoked: lport is[%d] rport is[%d] seq is[%d] ack is[%d] win is[%d]",
1254 lport, rport, seq, ack, win);
1255
1256 char buf1[INET6_ADDRSTRLEN];
1257 char buf2[INET6_ADDRSTRLEN];
1258
1259 buf1[0] = 0;
1260 buf2[0] = 0;
1261
1262 inet_ntop(AF_INET6, sadd6, buf1, sizeof(buf1));
1263 inet_ntop(AF_INET6, dadd6, buf2, sizeof(buf2));
1264
1265 os_log_info(log_handle,"SendKeepalive invoked: sadd6 is %s, dadd6 is %s", buf1, buf2);
1266
1267 // all the incoming arguments are in network order
1268 if ((*(unsigned *)(sadd6 +4) == 0) && (*(unsigned *)(sadd6 + 8) == 0) && (*(unsigned *)(sadd6 + 12) == 0))
1269 {
1270 af = AF_INET;
1271 memset(&packet4, 0, sizeof (packet4));
1272
1273 /* Fill in all the IP header information - should be in host order*/
1274 packet4.ip.ip_v = 4; /* 4-bit Version */
1275 packet4.ip.ip_hl = 5; /* 4-bit Header Length */
1276 packet4.ip.ip_tos = 0; /* 8-bit Type of service */
1277 packet4.ip.ip_len = 40; /* 16-bit Total length */
1278 packet4.ip.ip_id = 9864; /* 16-bit ID field */
1279 packet4.ip.ip_off = 0; /* 13-bit Fragment offset */
1280 packet4.ip.ip_ttl = 63; /* 8-bit Time To Live */
1281 packet4.ip.ip_p = IPPROTO_TCP; /* 8-bit Protocol */
1282 packet4.ip.ip_sum = 0; /* 16-bit Header checksum (below) */
1283 memcpy(&packet4.ip.ip_src.s_addr, sadd6, 4);
1284 memcpy(&packet4.ip.ip_dst.s_addr, dadd6, 4);
1285
1286 /* IP header checksum */
1287 packet4.ip.ip_sum = InetChecksum((unsigned short *)&packet4.ip, 20);
1288 t = &packet4.tcp;
1289 packet = &packet4;
1290 packetlen = 40; // sum of IPv4 header len(20) and TCP header len(20)
1291 }
1292 else
1293 {
1294 af = AF_INET6;
1295 memset(&packet6, 0, sizeof (packet6));
1296 t = &packet6.tcp;
1297 packet = &packet6;
1298 // We don't send IPv6 header, hence just the TCP header len (20)
1299 packetlen = 20;
1300 }
1301
1302 /* Fill in all the TCP header information */
1303 t->th_sport = lport; /* 16-bit Source port number */
1304 t->th_dport = rport; /* 16-bit Destination port */
1305 t->th_seq = seq; /* 32-bit Sequence Number */
1306 t->th_ack = ack; /* 32-bit Acknowledgement Number */
1307 t->th_off = 5; /* Data offset */
1308 t->th_flags = TH_ACK;
1309 t->th_win = win;
1310 t->th_sum = 0; /* 16-bit checksum (below) */
1311 t->th_urp = 0; /* 16-bit urgent offset */
1312
1313 TCPCheckSum(af, t, 20, sadd6, dadd6);
1314
1315 /* Open up a RAW socket */
1316 if ((sock = socket(af, SOCK_RAW, IPPROTO_TCP)) < 0)
1317 {
1318 os_log(log_handle, "SendKeepalive: socket %s", strerror(errno));
1319 return;
1320 }
1321
1322 if (af == AF_INET)
1323 {
1324 on = 1;
1325 if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &on, sizeof (on)))
1326 {
1327 close(sock);
1328 os_log(log_handle, "SendKeepalive: setsockopt %s", strerror(errno));
1329 return;
1330 }
1331
1332 memset(sin_to, 0, sizeof(struct sockaddr_in));
1333 sin_to->sin_len = sizeof(struct sockaddr_in);
1334 sin_to->sin_family = AF_INET;
1335 memcpy(&sin_to->sin_addr, sadd6, sizeof(struct in_addr));
1336 sin_to->sin_port = rport;
1337
1338 msghdr.msg_control = NULL;
1339 msghdr.msg_controllen = 0;
1340
1341 }
1342 else
1343 {
1344 struct cmsghdr *ctl;
1345
1346 memset(sin6_to, 0, sizeof(struct sockaddr_in6));
1347 sin6_to->sin6_len = sizeof(struct sockaddr_in6);
1348 sin6_to->sin6_family = AF_INET6;
1349 memcpy(&sin6_to->sin6_addr, dadd6, sizeof(struct in6_addr));
1350
1351 sin6_to->sin6_port = rport;
1352 sin6_to->sin6_flowinfo = 0;
1353
1354
1355 msghdr.msg_control = ctlbuf;
1356 msghdr.msg_controllen = sizeof(ctlbuf);
1357 ctl = CMSG_FIRSTHDR(&msghdr);
1358 ctl->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
1359 ctl->cmsg_level = IPPROTO_IPV6;
1360 ctl->cmsg_type = IPV6_PKTINFO;
1361 struct in6_pktinfo *pktinfo = (struct in6_pktinfo *) CMSG_DATA(ctl);
1362 memcpy(&pktinfo->ipi6_addr, sadd6, sizeof(struct in6_addr));
1363 pktinfo->ipi6_ifindex = 0;
1364 }
1365
1366 msghdr.msg_name = (struct sockaddr *)&ss_to;
1367 msghdr.msg_namelen = ss_to.ss_len;
1368 iov.iov_base = packet;
1369 iov.iov_len = packetlen;
1370 msghdr.msg_iov = &iov;
1371 msghdr.msg_iovlen = 1;
1372 msghdr.msg_flags = 0;
1373
1374 again:
1375 len = sendmsg(sock, &msghdr, 0);
1376 if (len == -1)
1377 {
1378 if (errno == EINTR)
1379 goto again;
1380 }
1381
1382 if (len != packetlen)
1383 {
1384 os_log(log_handle, "SendKeepalive: sendmsg failed %s", strerror(errno));
1385 }
1386 else
1387 {
1388 char source[INET6_ADDRSTRLEN], dest[INET6_ADDRSTRLEN];
1389
1390 inet_ntop(af, (void *)sadd6, source, sizeof(source));
1391 inet_ntop(af, (void *)dadd6, dest, sizeof(dest));
1392
1393 os_log(log_handle, "SendKeepalive: Success Source %s:%d, Dest %s:%d, %u, %u, %u",
1394 source, ntohs(lport), dest, ntohs(rport), ntohl(seq), ntohl(ack), ntohs(win));
1395
1396 }
1397 close(sock);
1398
1399 }
1400
1401
1402 void RetrieveTCPInfo(int family, const v6addr_t laddr, uint16_t lport, const v6addr_t raddr, uint16_t rport, uint32_t *seq, uint32_t *ack, uint16_t *win, int32_t *intfid, int *err)
1403 {
1404
1405 struct tcp_info ti;
1406 struct info_tuple itpl;
1407 int mib[4];
1408 unsigned int miblen;
1409 size_t len;
1410 size_t sz;
1411
1412 memset(&itpl, 0, sizeof(struct info_tuple));
1413 memset(&ti, 0, sizeof(struct tcp_info));
1414
1415 char buf1[INET6_ADDRSTRLEN];
1416 char buf2[INET6_ADDRSTRLEN];
1417
1418 buf1[0] = 0;
1419 buf2[0] = 0;
1420
1421 inet_ntop(AF_INET6, laddr, buf1, sizeof(buf1));
1422 inet_ntop(AF_INET6, raddr, buf2, sizeof(buf2));
1423
1424 os_log_info(log_handle, "RetrieveTCPInfo invoked: laddr is %s, raddr is %s", buf1, buf2);
1425
1426 os_log_info(log_handle,"RetrieveTCPInfo invoked: lport is[%d] rport is[%d] family is [%d]",
1427 lport, rport, family);
1428
1429 if (family == AF_INET)
1430 {
1431 memcpy(&itpl.itpl_local_sin.sin_addr, laddr, sizeof(struct in_addr));
1432 memcpy(&itpl.itpl_remote_sin.sin_addr, raddr, sizeof(struct in_addr));
1433 itpl.itpl_local_sin.sin_port = lport;
1434 itpl.itpl_remote_sin.sin_port = rport;
1435 itpl.itpl_local_sin.sin_family = AF_INET;
1436 itpl.itpl_remote_sin.sin_family = AF_INET;
1437 }
1438 else
1439 {
1440 memcpy(&itpl.itpl_local_sin6.sin6_addr, laddr, sizeof(struct in6_addr));
1441 memcpy(&itpl.itpl_remote_sin6.sin6_addr, raddr, sizeof(struct in6_addr));
1442 itpl.itpl_local_sin6.sin6_port = lport;
1443 itpl.itpl_remote_sin6.sin6_port = rport;
1444 itpl.itpl_local_sin6.sin6_family = AF_INET6;
1445 itpl.itpl_remote_sin6.sin6_family = AF_INET6;
1446 }
1447 itpl.itpl_proto = IPPROTO_TCP;
1448 sz = sizeof(mib)/sizeof(mib[0]);
1449 if (sysctlnametomib("net.inet.tcp.info", mib, &sz) == -1)
1450 {
1451 const int sysctl_errno = errno;
1452 os_log(log_handle, "RetrieveTCPInfo: sysctlnametomib failed %d, %s", sysctl_errno, strerror(sysctl_errno));
1453 *err = sysctl_errno;
1454 }
1455 miblen = (unsigned int)sz;
1456 len = sizeof(struct tcp_info);
1457 if (sysctl(mib, miblen, &ti, &len, &itpl, sizeof(struct info_tuple)) == -1)
1458 {
1459 const int sysctl_errno = errno;
1460 os_log(log_handle, "RetrieveTCPInfo: sysctl failed %d, %s", sysctl_errno, strerror(sysctl_errno));
1461 *err = sysctl_errno;
1462 }
1463
1464 *seq = ti.tcpi_snd_nxt - 1;
1465 *ack = ti.tcpi_rcv_nxt;
1466 *win = ti.tcpi_rcv_space >> ti.tcpi_rcv_wscale;
1467 *intfid = ti.tcpi_last_outif;
1468 *err = KERN_SUCCESS;
1469
1470 }