2 * Copyright (c) 2002-2007, 2011, 2013, 2015, 2017, 2018 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * August 5, 2002 Allan Nathanson <ajn@apple.com>
35 #define s6_addr16 __u6_addr.__u6_addr16
38 #ifndef kSCPropNetIPv6ScopeID
39 #define kSCPropNetIPv6ScopeID SCSTR("ScopeID")
43 #ifndef kSCEntNetIPv6DuplicatedAddress
44 #define kSCEntNetIPv6DuplicatedAddress CFSTR("IPv6DuplicatedAddress")
45 #endif /* kSCEntNetIPv6DuplicatedAddress */
48 appendAddress(CFMutableDictionaryRef dict
, CFStringRef key
, struct sockaddr_in6
*sin6
)
52 CFMutableArrayRef newAddrs
;
53 char str
[INET6_ADDRSTRLEN
];
55 addrs
= CFDictionaryGetValue(dict
, key
);
57 newAddrs
= CFArrayCreateMutableCopy(NULL
, 0, addrs
);
59 newAddrs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
62 if (inet_ntop(AF_INET6
, (const void *)&sin6
->sin6_addr
, str
, sizeof(str
)) == NULL
) {
63 SC_log(LOG_INFO
, "inet_ntop() failed: %s", strerror(errno
));
67 addr
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%s"), str
);
68 CFArrayAppendValue(newAddrs
, addr
);
71 CFDictionarySetValue(dict
, key
, newAddrs
);
78 appendFlags(CFMutableDictionaryRef dict
, int flags6
)
81 CFMutableArrayRef newFlags
;
84 flags
= CFDictionaryGetValue(dict
, kSCPropNetIPv6Flags
);
86 newFlags
= CFArrayCreateMutableCopy(NULL
, 0, flags
);
88 newFlags
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
91 v6Flags
= CFNumberCreate(NULL
, kCFNumberIntType
, &flags6
);
92 CFArrayAppendValue(newFlags
, v6Flags
);
95 CFDictionarySetValue(dict
, kSCPropNetIPv6Flags
, newFlags
);
102 appendPrefixLen(CFMutableDictionaryRef dict
, struct sockaddr_in6
*sin6
)
104 register u_int8_t
*name
= &sin6
->sin6_addr
.s6_addr
[0];
105 CFNumberRef prefixLen
;
106 CFArrayRef prefixLens
;
107 CFMutableArrayRef newPrefixLens
;
109 register size_t byte
;
113 for (byte
= 0; byte
< sizeof(struct in6_addr
); byte
++, plen
+= 8) {
114 if (name
[byte
] != 0xff) {
119 if (byte
== sizeof(struct in6_addr
)) {
123 for (bit
= 7; bit
!= 0; bit
--, plen
++) {
124 if (!(name
[byte
] & (1 << bit
))) {
129 for (; bit
!= 0; bit
--) {
130 if (name
[byte
] & (1 << bit
)) {
137 for (; byte
< sizeof(struct in6_addr
); byte
++) {
146 prefixLens
= CFDictionaryGetValue(dict
, kSCPropNetIPv6PrefixLength
);
148 newPrefixLens
= CFArrayCreateMutableCopy(NULL
, 0, prefixLens
);
150 newPrefixLens
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
153 prefixLen
= CFNumberCreate(NULL
, kCFNumberIntType
, &plen
);
154 CFArrayAppendValue(newPrefixLens
, prefixLen
);
155 CFRelease(prefixLen
);
157 CFDictionarySetValue(dict
, kSCPropNetIPv6PrefixLength
, newPrefixLens
);
158 CFRelease(newPrefixLens
);
165 appendScopeID(CFMutableDictionaryRef dict
, struct sockaddr_in6
*sin6
)
169 CFMutableArrayRef newScopes
;
171 scopes
= CFDictionaryGetValue(dict
, kSCPropNetIPv6ScopeID
);
173 newScopes
= CFArrayCreateMutableCopy(NULL
, 0, scopes
);
175 newScopes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
178 scope
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &sin6
->sin6_scope_id
);
179 CFArrayAppendValue(newScopes
, scope
);
182 CFDictionarySetValue(dict
, kSCPropNetIPv6ScopeID
, newScopes
);
183 CFRelease(newScopes
);
189 static CFMutableDictionaryRef
190 copyIF(CFStringRef key
, CFMutableDictionaryRef oldIFs
, CFMutableDictionaryRef newIFs
)
192 CFDictionaryRef dict
= NULL
;
193 CFMutableDictionaryRef newDict
= NULL
;
195 if (CFDictionaryGetValueIfPresent(newIFs
, key
, (const void **)&dict
)) {
196 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
198 dict
= SCDynamicStoreCopyValue(store
, key
);
200 CFDictionarySetValue(oldIFs
, key
, dict
);
201 if (isA_CFDictionary(dict
)) {
202 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
203 CFDictionaryRemoveValue(newDict
, kSCPropNetIPv6Addresses
);
204 CFDictionaryRemoveValue(newDict
, kSCPropNetIPv6DestAddresses
);
205 CFDictionaryRemoveValue(newDict
, kSCPropNetIPv6Flags
);
206 CFDictionaryRemoveValue(newDict
, kSCPropNetIPv6PrefixLength
);
208 CFDictionaryRemoveValue(newDict
, kSCPropNetIPv6ScopeID
);
216 newDict
= CFDictionaryCreateMutable(NULL
,
218 &kCFTypeDictionaryKeyCallBacks
,
219 &kCFTypeDictionaryValueCallBacks
);
227 updateStore(const void *key
, const void *value
, void *context
)
229 CFDictionaryRef dict
;
230 CFDictionaryRef newDict
= (CFDictionaryRef
)value
;
231 CFDictionaryRef oldIFs
= (CFDictionaryRef
)context
;
233 dict
= CFDictionaryGetValue(oldIFs
, key
);
235 if (!dict
|| !CFEqual(dict
, newDict
)) {
236 if (CFDictionaryGetCount(newDict
) > 0) {
237 SC_log(LOG_DEBUG
, "Update interface configuration: %@: %@", key
, newDict
);
238 SCDynamicStoreSetValue(store
, key
, newDict
);
240 CFDictionaryRef oldDict
;
242 oldDict
= SCDynamicStoreCopyValue(store
, key
);
243 if (oldDict
!= NULL
) {
244 SC_log(LOG_DEBUG
, "Update interface configuration: %@: <removed>", key
);
247 SCDynamicStoreRemoveValue(store
, key
);
249 network_changed
= TRUE
;
258 interface_update_ipv6(struct ifaddrs
*ifap
, const char *if_name
)
261 struct ifaddrs
*ifap_temp
= NULL
;
262 CFStringRef interface
;
263 boolean_t interfaceFound
= FALSE
;
264 CFStringRef key
= NULL
;
265 CFMutableDictionaryRef oldIFs
;
266 CFMutableDictionaryRef newDict
= NULL
;
267 CFMutableDictionaryRef newIFs
;
270 oldIFs
= CFDictionaryCreateMutable(NULL
,
272 &kCFTypeDictionaryKeyCallBacks
,
273 &kCFTypeDictionaryValueCallBacks
);
274 newIFs
= CFDictionaryCreateMutable(NULL
,
276 &kCFTypeDictionaryKeyCallBacks
,
277 &kCFTypeDictionaryValueCallBacks
);
280 if (getifaddrs(&ifap_temp
) == -1) {
281 SC_log(LOG_NOTICE
, "getifaddrs() failed: %s", strerror(errno
));
287 for (ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
288 struct in6_ifreq ifr6
;
289 #define flags6 ifr6.ifr_ifru.ifru_flags6
290 struct sockaddr_in6
*sin6
;
292 if (ifa
->ifa_addr
->sa_family
!= AF_INET6
) {
293 continue; /* sorry, not interested */
296 /* check if this is the requested interface */
298 if (strncmp(if_name
, ifa
->ifa_name
, IFNAMSIZ
) == 0) {
299 interfaceFound
= TRUE
; /* yes, this is the one I want */
301 continue; /* sorry, not interested */
306 sock
= dgram_socket(AF_INET6
);
312 /* get the current cache information */
313 interface
= CFStringCreateWithCString(NULL
, ifa
->ifa_name
, kCFStringEncodingMacRoman
);
314 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
315 kSCDynamicStoreDomainState
,
318 CFRelease(interface
);
320 newDict
= copyIF(key
, oldIFs
, newIFs
);
322 /* ALIGN: ifa->ifa_addr aligned (getifaddrs), cast ok. */
323 sin6
= (struct sockaddr_in6
*)(void *)ifa
->ifa_addr
;
325 /* XXX: embedded link local addr check */
326 if (IN6_IS_ADDR_LINKLOCAL(&sin6
->sin6_addr
) || IN6_IS_ADDR_MC_LINKLOCAL(&sin6
->sin6_addr
)) {
329 index
= sin6
->sin6_addr
.s6_addr16
[1];
331 sin6
->sin6_addr
.s6_addr16
[1] = 0;
332 if (sin6
->sin6_scope_id
== 0) {
333 sin6
->sin6_scope_id
= ntohs(index
);
338 memset((char *)&ifr6
, 0, sizeof(ifr6
));
339 strlcpy(ifr6
.ifr_name
, ifa
->ifa_name
, sizeof(ifr6
.ifr_name
));
340 ifr6
.ifr_addr
= *sin6
;
341 if (ioctl(sock
, SIOCGIFAFLAG_IN6
, &ifr6
) == -1) {
342 /* if flags not available for this address */
343 SC_log((errno
!= EADDRNOTAVAIL
) ? LOG_NOTICE
: LOG_DEBUG
, "ioctl() failed: %s",
347 appendAddress (newDict
, kSCPropNetIPv6Addresses
, sin6
);
349 appendScopeID (newDict
, sin6
);
351 /* ALIGN: ifa should be aligned (from getifaddrs), cast ok.
352 * appendPrefixLen expect byte alignment */
353 appendPrefixLen(newDict
, (struct sockaddr_in6
*)(void *)ifa
->ifa_netmask
);
354 appendFlags (newDict
, flags6
);
357 if (ifa
->ifa_flags
& IFF_POINTOPOINT
358 && ifa
->ifa_dstaddr
!= NULL
) {
359 struct sockaddr_in6
*dst6
;
361 /* ALIGN: ifa should be aligned (from getifaddrs), cast ok. */
362 dst6
= (struct sockaddr_in6
*)(void *)ifa
->ifa_dstaddr
;
364 /* XXX: embedded link local addr check */
365 if (IN6_IS_ADDR_LINKLOCAL(&dst6
->sin6_addr
) || IN6_IS_ADDR_MC_LINKLOCAL(&dst6
->sin6_addr
)) {
368 index
= dst6
->sin6_addr
.s6_addr16
[1];
370 dst6
->sin6_addr
.s6_addr16
[1] = 0;
371 if (dst6
->sin6_scope_id
== 0) {
372 dst6
->sin6_scope_id
= ntohs(index
);
377 appendAddress(newDict
, kSCPropNetIPv6DestAddresses
, dst6
);
380 CFDictionarySetValue(newIFs
, key
, newDict
);
385 /* if the last address[es] were removed from the target interface */
386 if (if_name
&& !interfaceFound
) {
387 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
388 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
389 kSCDynamicStoreDomainState
,
392 CFRelease(interface
);
394 newDict
= copyIF(key
, oldIFs
, newIFs
);
396 CFDictionarySetValue(newIFs
, key
, newDict
);
401 CFDictionaryApplyFunction(newIFs
, updateStore
, oldIFs
);
405 if (ifap_temp
) freeifaddrs(ifap_temp
);
406 if (sock
!= -1) close(sock
);
415 ipv6_duplicated_address(const char * if_name
, const struct in6_addr
* addr
,
416 int hw_len
, const void * hw_addr
)
418 uint8_t * hw_addr_bytes
= (uint8_t *)hw_addr
;
420 CFStringRef if_name_cf
;
421 CFMutableStringRef key
;
422 char ntopbuf
[INET6_ADDRSTRLEN
];
425 if_name_cf
= CFStringCreateWithCString(NULL
, if_name
,
426 kCFStringEncodingASCII
);
427 prefix
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
428 kSCDynamicStoreDomainState
,
430 kSCEntNetIPv6DuplicatedAddress
);
432 (void)inet_ntop(AF_INET6
, addr
, ntopbuf
, sizeof(ntopbuf
));
433 key
= CFStringCreateMutableCopy(NULL
, 0, prefix
);
434 CFStringAppendFormat(key
, NULL
, CFSTR("/%s"), ntopbuf
);
435 for (i
= 0; i
< hw_len
; i
++) {
436 CFStringAppendFormat(key
, NULL
, CFSTR("%s%02x"),
437 (i
== 0) ? "/" : ":", hw_addr_bytes
[i
]);
439 SCDynamicStoreNotifyValue(store
, key
);
442 CFRelease(if_name_cf
);
447 nat64_prefix_request(const char *if_name
)
449 CFStringRef if_name_cf
;
452 if_name_cf
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingASCII
);
453 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
454 kSCDynamicStoreDomainState
,
456 kSCEntNetNAT64PrefixRequest
);
457 CFRelease(if_name_cf
);
458 SC_log(LOG_DEBUG
, "Post NAT64 prefix request: %@", key
);
459 SCDynamicStoreNotifyValue(store
, key
);
463 __private_extern__
void
464 ipv6_router_expired(const char *if_name
)
466 CFStringRef if_name_cf
;
469 if_name_cf
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingASCII
);
470 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
471 kSCDynamicStoreDomainState
,
473 kSCEntNetIPv6RouterExpired
);
474 CFRelease(if_name_cf
);
475 SC_log(LOG_DEBUG
, "Post IPv6 Router Expired: %@", key
);
476 SCDynamicStoreNotifyValue(store
, key
);