2 * Copyright (c) 2002-2007, 2011, 2013, 2015, 2017 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>
36 #define s6_addr16 __u6_addr.__u6_addr16
39 #ifndef kSCPropNetIPv6ScopeID
40 #define kSCPropNetIPv6ScopeID SCSTR("ScopeID")
44 #ifndef kSCEntNetIPv6DuplicatedAddress
45 #define kSCEntNetIPv6DuplicatedAddress CFSTR("IPv6DuplicatedAddress")
46 #endif /* kSCEntNetIPv6DuplicatedAddress */
49 appendAddress(CFMutableDictionaryRef dict
, CFStringRef key
, struct sockaddr_in6
*sin6
)
53 CFMutableArrayRef newAddrs
;
54 char str
[INET6_ADDRSTRLEN
];
56 addrs
= CFDictionaryGetValue(dict
, key
);
58 newAddrs
= CFArrayCreateMutableCopy(NULL
, 0, addrs
);
60 newAddrs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
63 if (inet_ntop(AF_INET6
, (const void *)&sin6
->sin6_addr
, str
, sizeof(str
)) == NULL
) {
64 SC_log(LOG_INFO
, "inet_ntop() failed: %s", strerror(errno
));
68 addr
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%s"), str
);
69 CFArrayAppendValue(newAddrs
, addr
);
72 CFDictionarySetValue(dict
, key
, newAddrs
);
79 appendFlags(CFMutableDictionaryRef dict
, int flags6
)
82 CFMutableArrayRef newFlags
;
85 flags
= CFDictionaryGetValue(dict
, kSCPropNetIPv6Flags
);
87 newFlags
= CFArrayCreateMutableCopy(NULL
, 0, flags
);
89 newFlags
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
92 v6Flags
= CFNumberCreate(NULL
, kCFNumberIntType
, &flags6
);
93 CFArrayAppendValue(newFlags
, v6Flags
);
96 CFDictionarySetValue(dict
, kSCPropNetIPv6Flags
, newFlags
);
103 appendPrefixLen(CFMutableDictionaryRef dict
, struct sockaddr_in6
*sin6
)
105 register u_int8_t
*name
= &sin6
->sin6_addr
.s6_addr
[0];
106 CFNumberRef prefixLen
;
107 CFArrayRef prefixLens
;
108 CFMutableArrayRef newPrefixLens
;
110 register size_t byte
;
114 for (byte
= 0; byte
< sizeof(struct in6_addr
); byte
++, plen
+= 8) {
115 if (name
[byte
] != 0xff) {
120 if (byte
== sizeof(struct in6_addr
)) {
124 for (bit
= 7; bit
!= 0; bit
--, plen
++) {
125 if (!(name
[byte
] & (1 << bit
))) {
130 for (; bit
!= 0; bit
--) {
131 if (name
[byte
] & (1 << bit
)) {
138 for (; byte
< sizeof(struct in6_addr
); byte
++) {
147 prefixLens
= CFDictionaryGetValue(dict
, kSCPropNetIPv6PrefixLength
);
149 newPrefixLens
= CFArrayCreateMutableCopy(NULL
, 0, prefixLens
);
151 newPrefixLens
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
154 prefixLen
= CFNumberCreate(NULL
, kCFNumberIntType
, &plen
);
155 CFArrayAppendValue(newPrefixLens
, prefixLen
);
156 CFRelease(prefixLen
);
158 CFDictionarySetValue(dict
, kSCPropNetIPv6PrefixLength
, newPrefixLens
);
159 CFRelease(newPrefixLens
);
166 appendScopeID(CFMutableDictionaryRef dict
, struct sockaddr_in6
*sin6
)
170 CFMutableArrayRef newScopes
;
172 scopes
= CFDictionaryGetValue(dict
, kSCPropNetIPv6ScopeID
);
174 newScopes
= CFArrayCreateMutableCopy(NULL
, 0, scopes
);
176 newScopes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
179 scope
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &sin6
->sin6_scope_id
);
180 CFArrayAppendValue(newScopes
, scope
);
183 CFDictionarySetValue(dict
, kSCPropNetIPv6ScopeID
, newScopes
);
184 CFRelease(newScopes
);
190 static CFMutableDictionaryRef
191 copyIF(CFStringRef key
, CFMutableDictionaryRef oldIFs
, CFMutableDictionaryRef newIFs
)
193 CFDictionaryRef dict
= NULL
;
194 CFMutableDictionaryRef newDict
= NULL
;
196 if (CFDictionaryGetValueIfPresent(newIFs
, key
, (const void **)&dict
)) {
197 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
199 dict
= cache_SCDynamicStoreCopyValue(store
, key
);
201 CFDictionarySetValue(oldIFs
, key
, dict
);
202 if (isA_CFDictionary(dict
)) {
203 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
204 CFDictionaryRemoveValue(newDict
, kSCPropNetIPv6Addresses
);
205 CFDictionaryRemoveValue(newDict
, kSCPropNetIPv6DestAddresses
);
206 CFDictionaryRemoveValue(newDict
, kSCPropNetIPv6Flags
);
207 CFDictionaryRemoveValue(newDict
, kSCPropNetIPv6PrefixLength
);
209 CFDictionaryRemoveValue(newDict
, kSCPropNetIPv6ScopeID
);
217 newDict
= CFDictionaryCreateMutable(NULL
,
219 &kCFTypeDictionaryKeyCallBacks
,
220 &kCFTypeDictionaryValueCallBacks
);
228 updateStore(const void *key
, const void *value
, void *context
)
230 CFDictionaryRef dict
;
231 CFDictionaryRef newDict
= (CFDictionaryRef
)value
;
232 CFDictionaryRef oldIFs
= (CFDictionaryRef
)context
;
234 dict
= CFDictionaryGetValue(oldIFs
, key
);
236 if (!dict
|| !CFEqual(dict
, newDict
)) {
237 if (CFDictionaryGetCount(newDict
) > 0) {
238 SC_log(LOG_DEBUG
, "Update interface configuration: %@: %@", key
, newDict
);
239 cache_SCDynamicStoreSetValue(store
, key
, newDict
);
241 CFDictionaryRef oldDict
;
243 oldDict
= cache_SCDynamicStoreCopyValue(store
, key
);
244 if (oldDict
!= NULL
) {
245 SC_log(LOG_DEBUG
, "Update interface configuration: %@: <removed>", key
);
248 cache_SCDynamicStoreRemoveValue(store
, key
);
250 network_changed
= TRUE
;
259 interface_update_ipv6(struct ifaddrs
*ifap
, const char *if_name
)
262 struct ifaddrs
*ifap_temp
= NULL
;
263 CFStringRef interface
;
264 boolean_t interfaceFound
= FALSE
;
265 CFStringRef key
= NULL
;
266 CFMutableDictionaryRef oldIFs
;
267 CFMutableDictionaryRef newDict
= NULL
;
268 CFMutableDictionaryRef newIFs
;
271 oldIFs
= CFDictionaryCreateMutable(NULL
,
273 &kCFTypeDictionaryKeyCallBacks
,
274 &kCFTypeDictionaryValueCallBacks
);
275 newIFs
= CFDictionaryCreateMutable(NULL
,
277 &kCFTypeDictionaryKeyCallBacks
,
278 &kCFTypeDictionaryValueCallBacks
);
281 if (getifaddrs(&ifap_temp
) == -1) {
282 SC_log(LOG_NOTICE
, "getifaddrs() failed: %s", strerror(errno
));
288 for (ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
289 struct in6_ifreq ifr6
;
290 #define flags6 ifr6.ifr_ifru.ifru_flags6
291 struct sockaddr_in6
*sin6
;
293 if (ifa
->ifa_addr
->sa_family
!= AF_INET6
) {
294 continue; /* sorry, not interested */
297 /* check if this is the requested interface */
299 if (strncmp(if_name
, ifa
->ifa_name
, IFNAMSIZ
) == 0) {
300 interfaceFound
= TRUE
; /* yes, this is the one I want */
302 continue; /* sorry, not interested */
307 sock
= dgram_socket(AF_INET6
);
313 /* get the current cache information */
314 interface
= CFStringCreateWithCString(NULL
, ifa
->ifa_name
, kCFStringEncodingMacRoman
);
315 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
316 kSCDynamicStoreDomainState
,
319 CFRelease(interface
);
321 newDict
= copyIF(key
, oldIFs
, newIFs
);
323 /* ALIGN: ifa->ifa_addr aligned (getifaddrs), cast ok. */
324 sin6
= (struct sockaddr_in6
*)(void *)ifa
->ifa_addr
;
326 /* XXX: embedded link local addr check */
327 if (IN6_IS_ADDR_LINKLOCAL(&sin6
->sin6_addr
) || IN6_IS_ADDR_MC_LINKLOCAL(&sin6
->sin6_addr
)) {
330 index
= sin6
->sin6_addr
.s6_addr16
[1];
332 sin6
->sin6_addr
.s6_addr16
[1] = 0;
333 if (sin6
->sin6_scope_id
== 0) {
334 sin6
->sin6_scope_id
= ntohs(index
);
339 bzero((char *)&ifr6
, sizeof(ifr6
));
340 strlcpy(ifr6
.ifr_name
, ifa
->ifa_name
, sizeof(ifr6
.ifr_name
));
341 ifr6
.ifr_addr
= *sin6
;
342 if (ioctl(sock
, SIOCGIFAFLAG_IN6
, &ifr6
) == -1) {
343 /* if flags not available for this address */
344 SC_log((errno
!= EADDRNOTAVAIL
) ? LOG_NOTICE
: LOG_DEBUG
, "ioctl() failed: %s",
348 appendAddress (newDict
, kSCPropNetIPv6Addresses
, sin6
);
350 appendScopeID (newDict
, sin6
);
352 /* ALIGN: ifa should be aligned (from getifaddrs), cast ok.
353 * appendPrefixLen expect byte alignment */
354 appendPrefixLen(newDict
, (struct sockaddr_in6
*)(void *)ifa
->ifa_netmask
);
355 appendFlags (newDict
, flags6
);
358 if (ifa
->ifa_flags
& IFF_POINTOPOINT
359 && ifa
->ifa_dstaddr
!= NULL
) {
360 struct sockaddr_in6
*dst6
;
362 /* ALIGN: ifa should be aligned (from getifaddrs), cast ok. */
363 dst6
= (struct sockaddr_in6
*)(void *)ifa
->ifa_dstaddr
;
365 /* XXX: embedded link local addr check */
366 if (IN6_IS_ADDR_LINKLOCAL(&dst6
->sin6_addr
) || IN6_IS_ADDR_MC_LINKLOCAL(&dst6
->sin6_addr
)) {
369 index
= dst6
->sin6_addr
.s6_addr16
[1];
371 dst6
->sin6_addr
.s6_addr16
[1] = 0;
372 if (dst6
->sin6_scope_id
== 0) {
373 dst6
->sin6_scope_id
= ntohs(index
);
378 appendAddress(newDict
, kSCPropNetIPv6DestAddresses
, dst6
);
381 CFDictionarySetValue(newIFs
, key
, newDict
);
386 /* if the last address[es] were removed from the target interface */
387 if (if_name
&& !interfaceFound
) {
388 interface
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingMacRoman
);
389 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
390 kSCDynamicStoreDomainState
,
393 CFRelease(interface
);
395 newDict
= copyIF(key
, oldIFs
, newIFs
);
397 CFDictionarySetValue(newIFs
, key
, newDict
);
402 CFDictionaryApplyFunction(newIFs
, updateStore
, oldIFs
);
406 if (ifap_temp
) freeifaddrs(ifap_temp
);
407 if (sock
!= -1) close(sock
);
416 ipv6_duplicated_address(const char * if_name
, const struct in6_addr
* addr
,
417 int hw_len
, const void * hw_addr
)
419 uint8_t * hw_addr_bytes
= (uint8_t *)hw_addr
;
421 CFStringRef if_name_cf
;
422 CFMutableStringRef key
;
423 char ntopbuf
[INET6_ADDRSTRLEN
];
426 if_name_cf
= CFStringCreateWithCString(NULL
, if_name
,
427 kCFStringEncodingASCII
);
428 prefix
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
429 kSCDynamicStoreDomainState
,
431 kSCEntNetIPv6DuplicatedAddress
);
433 (void)inet_ntop(AF_INET6
, addr
, ntopbuf
, sizeof(ntopbuf
));
434 key
= CFStringCreateMutableCopy(NULL
, 0, prefix
);
435 CFStringAppendFormat(key
, NULL
, CFSTR("/%s"), ntopbuf
);
436 for (i
= 0; i
< hw_len
; i
++) {
437 CFStringAppendFormat(key
, NULL
, CFSTR("%s%02x"),
438 (i
== 0) ? "/" : ":", hw_addr_bytes
[i
]);
440 cache_SCDynamicStoreNotifyValue(store
, key
);
443 CFRelease(if_name_cf
);
448 nat64_prefix_request(const char *if_name
)
450 CFStringRef if_name_cf
;
453 if_name_cf
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingASCII
);
454 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
455 kSCDynamicStoreDomainState
,
457 kSCEntNetNAT64PrefixRequest
);
458 CFRelease(if_name_cf
);
459 SC_log(LOG_DEBUG
, "Post NAT64 prefix request: %@", key
);
460 cache_SCDynamicStoreNotifyValue(store
, key
);
464 __private_extern__
void
465 ipv6_router_expired(const char *if_name
)
467 CFStringRef if_name_cf
;
470 if_name_cf
= CFStringCreateWithCString(NULL
, if_name
, kCFStringEncodingASCII
);
471 key
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
,
472 kSCDynamicStoreDomainState
,
474 kSCEntNetIPv6RouterExpired
);
475 CFRelease(if_name_cf
);
476 SC_log(LOG_DEBUG
, "Post IPv6 Router Expired: %@", key
);
477 cache_SCDynamicStoreNotifyValue(store
, key
);