2 * Copyright (c) 2007-2019 Apple Inc. All rights reserved.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <sys/cdefs.h>
18 #include <arpa/inet.h>
19 #include <bsm/libbsm.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>
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>
47 #include <sys/sysctl.h>
49 #include "mDNSEmbeddedAPI.h"
51 #include "dnssd_ipc.h"
53 #include "helper-server.h"
54 #include "P2PPacketFilter.h"
56 #include <netinet/ip.h>
57 #include <netinet/tcp.h>
59 #include <IOKit/pwr_mgt/IOPMLibPrivate.h>
62 #define RTF_IFSCOPE 0x1000000
66 #define NO_CFUSERNOTIFICATION 1
67 #define NO_SECURITYFRAMEWORK 1
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"
74 typedef struct sadb_x_policy
*ipsec_policy_t
;
76 uid_t mDNSResponderUID
;
77 gid_t mDNSResponderGID
;
81 os_log_info(log_handle
,"mDNSResponderHelper exiting");
85 mDNSexport
void RequestBPF()
89 DNSServiceErrorType err
= ConnectToServer(&ref
, 0, send_bpf
, NULL
, NULL
, NULL
);
92 os_log(log_handle
, "RequestBPF: ConnectToServer %d", err
);
97 size_t len
= sizeof(DNSServiceFlags
);
98 ipc_msg_hdr
*hdr
= create_hdr(send_bpf
, &len
, &ptr
, 0, ref
);
101 os_log(log_handle
, "RequestBPF: No mem to allocate");
102 DNSServiceRefDeallocate(ref
);
107 deliver_request(hdr
, ref
); // Will free hdr for us
108 DNSServiceRefDeallocate(ref
);
111 os_log_info(log_handle
,"RequestBPF: Successful");
115 void PowerRequest(int key
, int interval
, int *err
)
117 *err
= kHelperErr_DefaultErr
;
119 os_log_info(log_handle
,"PowerRequest: key %d interval %d, err %d", key
, interval
, *err
);
121 CFArrayRef events
= IOPMCopyScheduledPowerEvents();
125 CFIndex count
= CFArrayGetCount(events
);
126 for (i
=0; i
<count
; i
++)
128 CFDictionaryRef dict
= CFArrayGetValueAtIndex(events
, i
);
129 CFStringRef id
= CFDictionaryGetValue(dict
, CFSTR(kIOPMPowerEventAppNameKey
));
130 if (CFEqual(id
, CFSTR("mDNSResponderHelper")))
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");
137 os_log(log_handle
, "IOPMCancelScheduledPowerEvent %d failed %d", i
, result
);
143 if (key
< 0) // mDNSPowerRequest(-1,-1) means "clear any stale schedules" (see above)
145 *err
= kHelperErr_NoErr
;
147 else if (key
== 0) // mDNSPowerRequest(0, 0) means "sleep now"
149 IOReturn r
= IOPMSleepSystem(IOPMFindPowerManagement(MACH_PORT_NULL
));
153 os_log_info(log_handle
, "IOPMSleepSystem %d", r
);
159 CFDateRef wakeTime
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent() + interval
);
162 CFMutableDictionaryRef scheduleDict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
164 CFDictionaryAddValue(scheduleDict
, CFSTR(kIOPMPowerEventTimeKey
), wakeTime
);
165 CFDictionaryAddValue(scheduleDict
, CFSTR(kIOPMPowerEventAppNameKey
), CFSTR("mDNSResponderHelper"));
166 CFDictionaryAddValue(scheduleDict
, CFSTR(kIOPMPowerEventTypeKey
), key
? CFSTR(kIOPMAutoWake
) : CFSTR(kIOPMAutoSleep
));
168 IOReturn r
= IOPMRequestSysWake(scheduleDict
);
172 os_log_info(log_handle
, "IOPMRequestSysWake(%d) %d %x", interval
, r
, r
);
176 CFRelease(scheduleDict
);
183 void SetLocalAddressCacheEntry(int ifindex
, int family
, const v6addr_t ip
, const ethaddr_t eth
, int *err
)
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]
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]);
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]);
200 *err
= kHelperErr_DefaultErr
;
202 static int s
= -1, seq
= 0;
205 s
= socket(PF_ROUTE
, SOCK_RAW
, 0);
207 os_log(log_handle
, "SetLocalAddressCacheEntry: socket(PF_ROUTE, SOCK_RAW, 0) failed %d (%s)", errno
, strerror(errno
));
213 gettimeofday(&tv
, 0);
216 struct { struct rt_msghdr hdr
; struct sockaddr_inarp dst
; struct sockaddr_dl sdl
; } rtmsg
;
217 memset(&rtmsg
, 0, sizeof(rtmsg
));
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;
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;
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;
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
));
251 int len
= write(s
, (char *)&rtmsg
, sizeof(rtmsg
));
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
);
260 *err
= kHelperErr_NoErr
;
264 struct { struct rt_msghdr hdr
; struct sockaddr_in6 dst
; struct sockaddr_dl sdl
; } rtmsg
;
265 memset(&rtmsg
, 0, sizeof(rtmsg
));
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;
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
;
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;
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
));
298 int len
= write(s
, (char *)&rtmsg
, sizeof(rtmsg
));
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
);
307 *err
= kHelperErr_NoErr
;
315 void UserNotify(const char *title
, const char *msg
)
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
);
329 os_log(log_handle
, "CFUserNotificationDisplayNotice returned %d", err
);
330 CFRelease(alertHeader
);
331 CFRelease(alertMessage
);
335 #endif /* NO_CFUSERNOTIFICATION */
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
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
;
356 static CFUserNotificationRef gNotification
= NULL
;
357 static CFRunLoopSourceRef gNotificationRLS
= NULL
;
359 static void NotificationCallBackDismissed(CFUserNotificationRef userNotification
, CFOptionFlags responseFlags
)
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
)
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
;
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"
383 unpause_idle_timer();
386 static void ShowNameConflictNotification(CFMutableArrayRef header
, CFStringRef subtext
)
388 CFMutableDictionaryRef dictionary
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
389 if (!dictionary
) return;
391 os_log_debug(log_handle
,"entry");
393 CFDictionarySetValue(dictionary
, kCFUserNotificationAlertHeaderKey
, header
);
394 CFDictionarySetValue(dictionary
, kCFUserNotificationAlertMessageKey
, subtext
);
396 CFURLRef urlRef
= CFURLCreateWithFileSystemPath(NULL
, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle
, true);
397 if (urlRef
) { CFDictionarySetValue(dictionary
, kCFUserNotificationLocalizationURLKey
, urlRef
); CFRelease(urlRef
); }
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
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
);
415 CFRelease(dictionary
);
418 static CFMutableArrayRef
CreateAlertHeader(const char* oldname
, const char* newname
, const CFStringRef msg
, const char* suffix
)
420 CFMutableArrayRef alertHeader
= NULL
;
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.
430 os_log(log_handle
, "Could not construct CFStrings for old=%s", newname
);
432 else if (newname
&& !cfnewname
)
434 os_log(log_handle
, "Could not construct CFStrings for new=%s", newname
);
438 const CFStringRef s1
= CFStringCreateWithFormat(NULL
, NULL
, CFS_Format
, cfoldname
, suffix
);
439 const CFStringRef s2
= cfnewname
? CFStringCreateWithFormat(NULL
, NULL
, CFS_Format
, cfnewname
, suffix
) : NULL
;
441 alertHeader
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
445 os_log(log_handle
, "Could not construct secondary CFString for old=%s", oldname
);
447 else if (cfnewname
&& !s2
)
449 os_log(log_handle
, "Could not construct secondary CFString for new=%s", newname
);
451 else if (!alertHeader
)
453 os_log(log_handle
, "Could not construct CFArray for notification");
457 // Make sure someone is logged in. We don't want this popping up over the login window
460 CFStringRef userName
= SCDynamicStoreCopyConsoleUser(NULL
, &uid
, &gid
);
463 if (!CFEqual(userName
, CFSTR("_mbsetupuser")))
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. "));
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("."));
476 CFArrayAppendValue(alertHeader
, CFSTR("All attempts to find an available name by adding a number to the name were also unsuccessful."));
482 if (s1
) CFRelease(s1
);
483 if (s2
) CFRelease(s2
);
485 if (cfoldname
) CFRelease(cfoldname
);
486 if (cfnewname
) CFRelease(cfnewname
);
490 #endif /* ndef NO_CFUSERNOTIFICATION */
492 static void update_notification(void)
494 #ifndef NO_CFUSERNOTIFICATION
495 os_log_debug(log_handle
,"entry ucn=%s, uhn=%s, lcn=%s, lhn=%s", usercompname
, userhostname
, lastcompname
, lasthostname
);
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
);
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
);
522 if (!usercompname
[0] && !userhostname
[0])
524 if (gNotificationRLS
)
526 os_log_debug(log_handle
,"canceling notification %p", gNotification
);
527 CFUserNotificationCancel(gNotification
);
528 unpause_idle_timer();
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
537 header
= CreateAlertHeader(userhostname
, NULL
, CFS_LocalHostName
, ".local");
538 subtext
= &CFS_Problem
;
540 else if (usercompname
[0])
542 header
= CreateAlertHeader(usercompname
, lastcompname
, CFS_ComputerName
, "");
543 subtext
= &CFS_ComputerNameMsg
;
547 header
= CreateAlertHeader(userhostname
, lasthostname
, CFS_LocalHostName
, ".local");
548 subtext
= &CFS_LocalHostNameMsg
;
550 ShowNameConflictNotification(header
, *subtext
);
556 void PreferencesSetName(int key
, const char* old
, const char* new)
558 SCPreferencesRef session
= NULL
;
560 Boolean locked
= FALSE
;
561 CFStringRef cfstr
= NULL
;
564 Boolean needUpdate
= FALSE
;
566 os_log_info(log_handle
,"PreferencesSetName: entry %s old=%s new=%s",
567 key
==kmDNSComputerName
? "ComputerName" : (key
==kmDNSLocalHostName
? "LocalHostName" : "UNKNOWN"), old
, new);
569 switch ((enum mDNSPreferencesSetNameKey
)key
)
571 case kmDNSComputerName
:
575 case kmDNSLocalHostName
:
580 os_log(log_handle
, "PreferencesSetName: unrecognized key: %d", key
);
586 os_log(log_handle
, "PreferencesSetName: no last ptr");
592 os_log(log_handle
, "PreferencesSetName:: no user ptr");
596 if (0 == strncmp(old
, new, MAX_DOMAIN_LABEL
+1))
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))
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))
616 strncpy(last
, new, MAX_DOMAIN_LABEL
);
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.
626 strncpy(user
, old
, MAX_DOMAIN_LABEL
);
630 if (!new[0]) // we've given up trying to construct a name that doesn't conflict
633 cfstr
= CFStringCreateWithCString(NULL
, new, kCFStringEncodingUTF8
);
635 session
= SCPreferencesCreate(NULL
, CFSTR(kHelperService
), NULL
);
637 if (cfstr
== NULL
|| session
== NULL
)
639 os_log(log_handle
, "PreferencesSetName: SCPreferencesCreate failed");
642 if (!SCPreferencesLock(session
, 0))
644 os_log(log_handle
,"PreferencesSetName: lock failed");
649 switch ((enum mDNSPreferencesSetNameKey
)key
)
651 case kmDNSComputerName
:
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
);
666 encoding
= kCFStringEncodingUTF8
;
669 ok
= SCPreferencesSetComputerName(session
, cfstr
, encoding
);
673 case kmDNSLocalHostName
:
674 ok
= SCPreferencesSetLocalHostName(session
, cfstr
);
681 if (!ok
|| !SCPreferencesCommitChanges(session
) ||
682 !SCPreferencesApplyChanges(session
))
684 os_log(log_handle
, "PreferencesSetName: SCPreferences update failed");
687 os_log_info(log_handle
,"PreferencesSetName: succeeded");
695 SCPreferencesUnlock(session
);
700 update_notification();
709 formatDnsPrefixedServiceItem
,
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.
718 #ifndef NO_SECURITYFRAMEWORK
719 static const char dnsprefix
[] = "dns:";
720 static const char ddns
[] = "ddns";
721 static const char ddnsrev
[] = "sndd";
723 static enum DNSKeyFormat
getDNSKeyFormat(SecKeychainItemRef item
, SecKeychainAttributeList
**attributesp
)
725 static UInt32 tags
[4] =
727 kSecTypeItemAttr
, kSecServiceItemAttr
, kSecAccountItemAttr
, kSecLabelItemAttr
729 static SecKeychainAttributeInfo attributeInfo
=
731 sizeof(tags
)/sizeof(tags
[0]), tags
, NULL
733 SecKeychainAttributeList
*attributes
= NULL
;
734 enum DNSKeyFormat format
;
735 Boolean malformed
= FALSE
;
736 OSStatus status
= noErr
;
740 if (noErr
!= (status
= SecKeychainItemCopyAttributesAndData(item
, &attributeInfo
, NULL
, &attributes
, NULL
, NULL
)))
742 os_log_info(log_handle
,"getDNSKeyFormat: SecKeychainItemCopyAttributesAndData %d - skipping", status
);
745 if (attributeInfo
.count
!= attributes
->count
)
747 for (i
= 0; !malformed
&& i
< (int)attributeInfo
.count
; ++i
)
748 if (attributeInfo
.tag
[i
] != attributes
->attr
[i
].tag
)
752 os_log(log_handle
, "getDNSKeyFormat: malformed result from SecKeychainItemCopyAttributesAndData - skipping");
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
);
761 if (attributes
->attr
[1].length
>= MAX_ESCAPED_DOMAIN_NAME
+
764 os_log(log_handle
, "getDNSKeyFormat: kSecServiceItemAttr too long (%u) - skipping",
765 (unsigned int)attributes
->attr
[1].length
);
768 if (attributes
->attr
[2].length
>= MAX_ESCAPED_DOMAIN_NAME
)
770 os_log(log_handle
, "getDNSKeyFormat: kSecAccountItemAttr too long (%u) - skipping",
771 (unsigned int)attributes
->attr
[2].length
);
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
;
782 os_log_info(log_handle
,"getDNSKeyFormat: uninterested in this entry");
786 *attributesp
= attributes
;
787 os_log_info(log_handle
,"getDNSKeyFormat: accepting this entry");
791 SecKeychainItemFreeAttributesAndData(attributes
, NULL
);
792 return formatNotDNSKey
;
795 // Insert the attributes as defined by mDNSKeyChainAttributes
796 static CFPropertyListRef
copyKeychainItemInfo(SecKeychainItemRef item
, SecKeychainAttributeList
*attributes
, enum DNSKeyFormat format
)
798 CFMutableArrayRef entry
= NULL
;
799 CFDataRef data
= NULL
;
800 OSStatus status
= noErr
;
804 if (NULL
== (entry
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
)))
806 os_log(log_handle
, "copyKeychainItemInfo: CFArrayCreateMutable failed");
810 // Insert the Account attribute (kmDNSKcWhere)
811 switch ((enum DNSKeyFormat
)format
)
813 case formatDdnsTypeItem
:
814 data
= CFDataCreate(kCFAllocatorDefault
, attributes
->attr
[1].data
, attributes
->attr
[1].length
);
816 case formatDnsPrefixedServiceItem
:
817 data
= CFDataCreate(kCFAllocatorDefault
, attributes
->attr
[1].data
, attributes
->attr
[1].length
);
820 os_log(log_handle
, "copyKeychainItemInfo: unknown DNSKeyFormat value");
825 os_log(log_handle
, "copyKeychainItemInfo: CFDataCreate for attr[1] failed");
828 CFArrayAppendValue(entry
, data
);
831 // Insert the Where attribute (kmDNSKcAccount)
832 if (NULL
== (data
= CFDataCreate(kCFAllocatorDefault
, attributes
->attr
[2].data
, attributes
->attr
[2].length
)))
834 os_log(log_handle
, "copyKeychainItemInfo: CFDataCreate for attr[2] failed");
838 CFArrayAppendValue(entry
, data
);
841 // Insert the Key attribute (kmDNSKcKey)
842 if (noErr
!= (status
= SecKeychainItemCopyAttributesAndData(item
, NULL
, NULL
, NULL
, &keylen
, &keyp
)))
844 os_log(log_handle
, "copyKeychainItemInfo: could not retrieve key for \"%.*s\": %d",
845 (int)attributes
->attr
[1].length
, attributes
->attr
[1].data
, status
);
849 data
= CFDataCreate(kCFAllocatorDefault
, keyp
, keylen
);
850 SecKeychainItemFreeAttributesAndData(NULL
, keyp
);
853 os_log(log_handle
, "copyKeychainItemInfo: CFDataCreate for keyp failed");
856 CFArrayAppendValue(entry
, data
);
859 // Insert the Name attribute (kmDNSKcName)
860 if (NULL
== (data
= CFDataCreate(kCFAllocatorDefault
, attributes
->attr
[3].data
, attributes
->attr
[3].length
)))
862 os_log(log_handle
, "copyKeychainItemInfo: CFDataCreate for attr[3] failed");
866 CFArrayAppendValue(entry
, data
);
877 void KeychainGetSecrets(__unused
unsigned int *numsecrets
,__unused
unsigned long *secrets
, __unused
unsigned int *secretsCnt
, __unused
int *err
)
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
;
891 os_log_info(log_handle
,"KeychainGetSecrets: entry");
892 *err
= kHelperErr_NoErr
;
894 *secrets
= (vm_offset_t
)NULL
;
896 if (NULL
== (keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
)))
898 os_log(log_handle
, "KeychainGetSecrets: CFArrayCreateMutable failed");
899 *err
= kHelperErr_ApiErr
;
902 if (noErr
!= (status
= SecKeychainCopyDefault(&skc
)))
904 *err
= kHelperErr_ApiErr
;
907 #pragma clang diagnostic push
908 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
909 if (noErr
!= (status
= SecKeychainSearchCreateFromAttributes(skc
, kSecGenericPasswordItemClass
, NULL
, &search
)))
911 *err
= kHelperErr_ApiErr
;
914 for (status
= SecKeychainSearchCopyNext(search
, &item
); noErr
== status
; status
= SecKeychainSearchCopyNext(search
, &item
))
916 if (formatNotDNSKey
!= (format
= getDNSKeyFormat(item
, &attributes
)) &&
917 NULL
!= (entry
= copyKeychainItemInfo(item
, attributes
, format
)))
919 CFArrayAppendValue(keys
, entry
);
922 SecKeychainItemFreeAttributesAndData(attributes
, NULL
);
925 #pragma clang diagnostic pop
926 if (errSecItemNotFound
!= status
)
927 os_log(log_handle
, "KeychainGetSecrets: SecKeychainSearchCopyNext failed: %d", status
);
929 if (NULL
== (stream
= CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorDefault
, kCFAllocatorDefault
)))
931 *err
= kHelperErr_ApiErr
;
932 os_log(log_handle
, "KeychainGetSecrets:CFWriteStreamCreateWithAllocatedBuffers failed");
936 CFWriteStreamOpen(stream
);
937 if (0 == CFPropertyListWrite(keys
, stream
, kCFPropertyListBinaryFormat_v1_0
, 0, NULL
))
939 *err
= kHelperErr_ApiErr
;
940 os_log(log_handle
, "KeychainGetSecrets:CFPropertyListWriteToStream failed");
943 result
= CFWriteStreamCopyProperty(stream
, kCFStreamPropertyDataWritten
);
945 if (KERN_SUCCESS
!= vm_allocate(mach_task_self(), secrets
, CFDataGetLength(result
), VM_FLAGS_ANYWHERE
))
947 *err
= kHelperErr_ApiErr
;
948 os_log(log_handle
, "KeychainGetSecrets: vm_allocate failed");
952 CFDataGetBytes(result
, CFRangeMake(0, CFDataGetLength(result
)), (void *)*secrets
);
953 *secretsCnt
= CFDataGetLength(result
);
954 *numsecrets
= CFArrayGetCount(keys
);
956 os_log_info(log_handle
,"KeychainGetSecrets: succeeded");
959 os_log_info(log_handle
,"KeychainGetSecrets: returning numsecrets[%u] secrets[%lu] secrets addr[%p] secretscount[%u]",
960 *numsecrets
, *secrets
, secrets
, *secretsCnt
);
964 CFWriteStreamClose(stream
);
988 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
989 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
992 void SendWakeupPacket(unsigned int ifid
, const char *eth_addr
, const char *ip_addr
, int iteration
)
996 char ifname
[IFNAMSIZ
];
1000 struct ether_addr
*ea
;
1001 // (void) ip_addr; // unused
1002 // (void) iteration; // unused
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
);
1007 if (if_indextoname(ifid
, ifname
) == NULL
)
1009 os_log(log_handle
, "SendWakeupPacket: invalid interface index %u", ifid
);
1013 ea
= ether_aton(eth_addr
);
1016 os_log(log_handle
, "SendWakeupPacket: invalid ethernet address %s", eth_addr
);
1020 for (i
= 0; i
< 100; i
++)
1022 snprintf(bpf_device
, sizeof(bpf_device
), "/dev/bpf%d", i
);
1023 bpf_fd
= open(bpf_device
, O_RDWR
, 0);
1033 os_log(log_handle
, "SendWakeupPacket: cannot find a bpf device");
1037 memset(&ifr
, 0, sizeof(ifr
));
1038 strlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
1040 if (ioctl(bpf_fd
, BIOCSETIF
, (char *)&ifr
) < 0)
1042 os_log(log_handle
, "SendWakeupPacket: BIOCSETIF failed %s", strerror(errno
));
1046 // 0x00 Destination address
1048 *ptr
++ = ea
->octet
[i
];
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)
1055 // 0x0C Ethertype (0x0842)
1059 // 0x0E Wakeup sync sequence
1064 for (j
=0; j
<16; j
++)
1066 *ptr
++ = ea
->octet
[i
];
1072 if (write(bpf_fd
, packet
, ptr
- packet
) < 0)
1074 os_log(log_handle
, "SendWakeupPacket: write failed %s", strerror(errno
));
1077 os_log(log_handle
, "SendWakeupPacket: sent unicast eth_addr %s, ip_addr %s", eth_addr
, ip_addr
);
1079 // Send a broadcast one to handle ethernet switches that don't flood forward packets with
1080 // unknown mac addresses.
1084 if (write(bpf_fd
, packet
, ptr
- packet
) < 0)
1086 os_log(log_handle
, "SendWakeupPacket: write failed %s", strerror(errno
));
1089 os_log(log_handle
, "SendWakeupPacket: sent broadcast eth_addr %s, ip_addr %s", eth_addr
, ip_addr
);
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
)
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]);
1108 error
= P2PPacketFilterAddBonjourRuleSet(ifname
, count
, portArray
, protocolArray
);
1110 os_log(log_handle
, "P2PPacketFilterAddBonjourRuleSet failed %s", strerror(error
));
1113 case PF_CLEAR_RULES
:
1114 error
= P2PPacketFilterClearBonjourRules();
1116 os_log(log_handle
, "P2PPacketFilterClearBonjourRules failed %s", strerror(error
));
1120 os_log(log_handle
, "PacketFilterControl: invalid command %d", command
);
1126 static unsigned long in_cksum(unsigned short *ptr
, int nbytes
)
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.
1143 /* mop up an odd byte, if necessary */
1146 /* make sure top half is zero */
1150 *((u_char
*)&oddbyte
) = *(u_char
*)ptr
;
1153 /* Add back carry outs from top 16 bits to low 16 bits. */
1154 sum
= (sum
>> 16) + (sum
& 0xffff);
1162 static unsigned short InetChecksum(unsigned short *ptr
, int nbytes
)
1166 sum
= in_cksum(ptr
, nbytes
);
1167 return (unsigned short)~sum
;
1170 static void TCPCheckSum(int af
, struct tcphdr
*t
, int tcplen
, const v6addr_t sadd6
, const v6addr_t dadd6
)
1172 unsigned long sum
= 0;
1173 unsigned short *ptr
;
1175 /* TCP header checksum */
1176 sum
= in_cksum((unsigned short *)t
, tcplen
);
1181 ptr
= (unsigned short *)sadd6
;
1184 ptr
= (unsigned short *)dadd6
;
1188 else if (af
== AF_INET6
)
1191 ptr
= (unsigned short *)sadd6
;
1200 ptr
= (unsigned short *)dadd6
;
1211 sum
+= htons(tcplen
);
1212 sum
+= htons(IPPROTO_TCP
);
1215 sum
= (sum
>> 16) + (sum
& 0xFFFF);
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
)
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]
1228 os_log_info(log_handle
, "SendKeepalive: "IPv6FMTSTRING
" :space: "IPv6FMTSTRING
"",
1229 IPv6FMTSARGS
, IPv6FMTDARGS
);
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
;
1248 char ctlbuf
[CMSG_SPACE(sizeof(struct in6_pktinfo
))];
1249 struct msghdr msghdr
;
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
);
1256 char buf1
[INET6_ADDRSTRLEN
];
1257 char buf2
[INET6_ADDRSTRLEN
];
1262 inet_ntop(AF_INET6
, sadd6
, buf1
, sizeof(buf1
));
1263 inet_ntop(AF_INET6
, dadd6
, buf2
, sizeof(buf2
));
1265 os_log_info(log_handle
,"SendKeepalive invoked: sadd6 is %s, dadd6 is %s", buf1
, buf2
);
1267 // all the incoming arguments are in network order
1268 if ((*(unsigned *)(sadd6
+4) == 0) && (*(unsigned *)(sadd6
+ 8) == 0) && (*(unsigned *)(sadd6
+ 12) == 0))
1271 memset(&packet4
, 0, sizeof (packet4
));
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);
1286 /* IP header checksum */
1287 packet4
.ip
.ip_sum
= InetChecksum((unsigned short *)&packet4
.ip
, 20);
1290 packetlen
= 40; // sum of IPv4 header len(20) and TCP header len(20)
1295 memset(&packet6
, 0, sizeof (packet6
));
1298 // We don't send IPv6 header, hence just the TCP header len (20)
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
;
1310 t
->th_sum
= 0; /* 16-bit checksum (below) */
1311 t
->th_urp
= 0; /* 16-bit urgent offset */
1313 TCPCheckSum(af
, t
, 20, sadd6
, dadd6
);
1315 /* Open up a RAW socket */
1316 if ((sock
= socket(af
, SOCK_RAW
, IPPROTO_TCP
)) < 0)
1318 os_log(log_handle
, "SendKeepalive: socket %s", strerror(errno
));
1325 if (setsockopt(sock
, IPPROTO_IP
, IP_HDRINCL
, &on
, sizeof (on
)))
1328 os_log(log_handle
, "SendKeepalive: setsockopt %s", strerror(errno
));
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
;
1338 msghdr
.msg_control
= NULL
;
1339 msghdr
.msg_controllen
= 0;
1344 struct cmsghdr
*ctl
;
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
));
1351 sin6_to
->sin6_port
= rport
;
1352 sin6_to
->sin6_flowinfo
= 0;
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;
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;
1375 len
= sendmsg(sock
, &msghdr
, 0);
1382 if (len
!= packetlen
)
1384 os_log(log_handle
, "SendKeepalive: sendmsg failed %s", strerror(errno
));
1388 char source
[INET6_ADDRSTRLEN
], dest
[INET6_ADDRSTRLEN
];
1390 inet_ntop(af
, (void *)sadd6
, source
, sizeof(source
));
1391 inet_ntop(af
, (void *)dadd6
, dest
, sizeof(dest
));
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
));
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
)
1406 struct info_tuple itpl
;
1408 unsigned int miblen
;
1412 memset(&itpl
, 0, sizeof(struct info_tuple
));
1413 memset(&ti
, 0, sizeof(struct tcp_info
));
1415 char buf1
[INET6_ADDRSTRLEN
];
1416 char buf2
[INET6_ADDRSTRLEN
];
1421 inet_ntop(AF_INET6
, laddr
, buf1
, sizeof(buf1
));
1422 inet_ntop(AF_INET6
, raddr
, buf2
, sizeof(buf2
));
1424 os_log_info(log_handle
, "RetrieveTCPInfo invoked: laddr is %s, raddr is %s", buf1
, buf2
);
1426 os_log_info(log_handle
,"RetrieveTCPInfo invoked: lport is[%d] rport is[%d] family is [%d]",
1427 lport
, rport
, family
);
1429 if (family
== AF_INET
)
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
;
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
;
1447 itpl
.itpl_proto
= IPPROTO_TCP
;
1448 sz
= sizeof(mib
)/sizeof(mib
[0]);
1449 if (sysctlnametomib("net.inet.tcp.info", mib
, &sz
) == -1)
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
;
1455 miblen
= (unsigned int)sz
;
1456 len
= sizeof(struct tcp_info
);
1457 if (sysctl(mib
, miblen
, &ti
, &len
, &itpl
, sizeof(struct info_tuple
)) == -1)
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
;
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
;