2 * Copyright (c) 2019, 2020 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 * October 4, 2018 Allan Nathanson <ajn@apple.com>
32 #define USE_SC_LOG_OR_PRINT 1 // use '_sc_log' to control os_log, printf
34 #include "SCNetworkConfigurationInternal.h"
35 #include "SCPreferencesInternal.h"
36 #include <IOKit/IOBSD.h>
40 savePreferences(SCPreferencesRef prefs
,
41 CFStringRef save_prefsID
,
44 CFStringRef extra_key
,
45 CFPropertyListRef extra_value
)
47 const CFStringRef keys
[] = {
50 kSCPrefNetworkServices
,
54 kSCPrefVirtualNetworkInterfaces
57 SCPreferencesRef save_prefs
;
59 // open [companion] backup
60 save_prefs
= SCPreferencesCreateCompanion(prefs
, save_prefsID
);
62 for (CFIndex i
= 0; i
< (CFIndex
)(sizeof(keys
)/sizeof(keys
[0])); i
++) {
63 CFStringRef key
= keys
[i
];
67 src_key
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%@"), prefix
, key
);
68 val
= SCPreferencesGetValue(prefs
, src_key
);
70 SCPreferencesSetValue(save_prefs
, key
, val
);
72 SCPreferencesRemoveValue(prefs
, src_key
);
78 if (extra_key
!= NULL
) {
79 SCPreferencesSetValue(save_prefs
, extra_key
, extra_value
);
82 ok
= SCPreferencesCommitChanges(save_prefs
);
83 CFRelease(save_prefs
);
85 SC_log(LOG_ERR
, "could not save preferences (%@): %s",
87 SCErrorString(SCError()));
95 __SCNetworkConfigurationBackup(SCPreferencesRef prefs
)
98 CFStringRef save_prefsID
;
100 struct timeval tv_now
;
102 SC_log(LOG_NOTICE
, "creating [configuration] backup");
104 (void)gettimeofday(&tv_now
, NULL
);
105 (void)localtime_r(&tv_now
.tv_sec
, &tm_now
);
106 save_prefsID
= CFStringCreateWithFormat(NULL
,
108 CFSTR("preferences-%4d-%02d-%02d-%02d%02d%02d.plist"),
109 tm_now
.tm_year
+ 1900,
115 ok
= savePreferences(prefs
, save_prefsID
, CFSTR(""), FALSE
, NULL
, NULL
);
116 CFRelease(save_prefsID
);
122 __SCNetworkConfigurationSaveModel(SCPreferencesRef prefs
, CFStringRef model
)
125 CFStringRef save_prefsID
;
127 SC_log(LOG_NOTICE
, "creating [per-device] backup: %@", model
);
129 save_prefsID
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("preferences-%@.plist"), model
);
130 ok
= savePreferences(prefs
, save_prefsID
, CFSTR(""), TRUE
, MODEL
, model
);
131 CFRelease(save_prefsID
);
137 needsUpdate(SCPreferencesRef prefs
, int new_version
)
143 // if no prefs, no updated needed
147 num
= SCPreferencesGetValue(prefs
, kSCPrefVersion
);
148 if (!isA_CFNumber(num
) ||
149 !CFNumberGetValue(num
, kCFNumberIntType
, &old_version
)) {
152 if (old_version
== new_version
) {
153 // if no update is needed
162 lockWithSync(SCPreferencesRef prefs
)
166 assert(prefs
!= NULL
);
167 ok
= SCPreferencesLock(prefs
, TRUE
);
168 if (!ok
&& (SCError() == kSCStatusStale
)) {
169 SCPreferencesSynchronize(prefs
);
170 ok
= SCPreferencesLock(prefs
, TRUE
);
178 __SCNetworkConfigurationUpgrade(SCPreferencesRef
*prefs_p
,
179 SCPreferencesRef
*ni_prefs_p
,
182 SCPreferencesRef ni_prefs
= NULL
;
183 Boolean ni_prefs_added
= FALSE
;
184 const int new_version
= NETWORK_CONFIGURATION_VERSION
;
187 SCPreferencesRef prefs
= NULL
;
188 Boolean prefs_added
= FALSE
;
191 // The following table describes how the SPI is called (input parameters), what actions
192 // are performed, and whether any changes should be committed as part of the call.
194 // +====================+===========================+===========================+========+
195 // | | preferences.plist | NetworkInterfaces.plist | |
196 // | +=============+=============+=============+=============+ COMMIT |
197 // | | ptr | plist | ptr | plist | |
198 // +====================+=============+=============+=============+=============+========+
199 // | InterfaceNamer | NULL | CREATE, REL | &ni_prefs | USE | YES |
200 // +====================+=============+=============+=============+=============+========+
201 // | PreferencesMonitor | &prefs | USE | NULL | NO UPDATE | YES |
202 // +====================+=============+=============+=============+=============+========+
203 // | scutil | &prefs | USE | &ni_prefs | USE/CREATE | NO |
204 // +====================+=============+=============+=============+=============+========+
206 // For InterfaceNamer, we are passed a reference to the SCPreferences[Ref] for the
207 // NetworkInterfaces.plist. During the upgrade process we create (and then release)
208 // the companion preferences.plist. Any needed changes will be committed to both
211 // For PreferencesMonitor, we are passed a reference to the SCPreferences[Ref] for
212 // the preferences.plist. Any needed changes to the plist will be committed. The
213 // companion NetworkInterfaces.plist is not passed nor is it referenced/modified.
215 // For scutil, we are passed references to the SCPreferences[Ref] for both the
216 // preferences.plist and NetworkInterfaces.plist. The NetworkInterfaces.plist
217 // reference will be used, if already open. Else, the companion will be created
218 // and returned. Regardless, any changes made will not be committed (we expect
219 // one to use scutil's "commit" command).
222 if (prefs_p
!= NULL
) {
226 if (ni_prefs_p
!= NULL
) {
227 ni_prefs
= *ni_prefs_p
;
230 if ((prefs_p
== NULL
) && (ni_prefs_p
!= NULL
) && (ni_prefs
!= NULL
)) {
231 // Here, we have been called by InterfaceNamer and need to get the [companion]
232 // preferences.plist (we need to update both)
233 prefs
= SCPreferencesCreateCompanion(ni_prefs
, NULL
);
236 "__SCNetworkConfigurationUpgrade(): could not open [preferences.plist]: %s",
237 SCErrorString(SCError()));
243 if ((prefs_p
!= NULL
) && (prefs
!= NULL
) && (ni_prefs_p
!= NULL
) && (ni_prefs
== NULL
)) {
244 // Here, we have been called by scutil with the [companion] NetworkInterfaces.plist
245 // not yet open. Open the companion so that we can update both.
246 ni_prefs
= SCPreferencesCreateCompanion(prefs
, INTERFACES_DEFAULT_CONFIG
);
247 if (ni_prefs
== NULL
) {
249 "__SCNetworkConfigurationUpgrade(): could not open [NetworkInterfaces.plist]: %s",
250 SCErrorString(SCError()));
253 ni_prefs_added
= TRUE
;
256 if (!needsUpdate(prefs
, NETWORK_CONFIGURATION_VERSION
) &&
257 !needsUpdate(ni_prefs
, NETWORK_CONFIGURATION_VERSION
)) {
261 // lock [preferences.plist] changes while we are updating
262 ok
= lockWithSync(prefs
);
265 "__SCNetworkConfigurationUpgrade(): could not lock [preferences.plist]: %s",
266 SCErrorString(SCError()));
270 if (ni_prefs
!= NULL
) {
271 // lock [NetworkInterfaces.plist] changes while we are updating
272 ok
= lockWithSync(ni_prefs
);
275 "__SCNetworkConfigurationUpgrade(): could not lock [NetworkInterfaces.plist]: %s",
276 SCErrorString(SCError()));
277 SCPreferencesUnlock(prefs
);
282 // first, cleanup any leftover cruft from the configuration
283 __SCNetworkConfigurationClean(prefs
, ni_prefs
);
285 // update the version(s)
286 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &new_version
);
287 SCPreferencesSetValue(prefs
, kSCPrefVersion
, num
);
289 if (ni_prefs
!= NULL
) {
290 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &new_version
);
291 SCPreferencesSetValue(ni_prefs
, kSCPrefVersion
, num
);
296 // commit the [preferences.plist] changes
297 ok
= SCPreferencesCommitChanges(prefs
);
300 "__SCNetworkConfigurationUpgrade(): update not saved [preferences.plist]: %s",
301 SCErrorString(SCError()));
304 ok
= SCPreferencesApplyChanges(prefs
);
307 "__SCNetworkConfigurationUpgrade(): update not applied [preferences.plist]: %s",
308 SCErrorString(SCError()));
312 SCPreferencesUnlock(prefs
);
314 if (ni_prefs
!= NULL
) {
316 // commit the [NetworkInterfaces.plist] changes
318 ok
= SCPreferencesCommitChanges(ni_prefs
);
321 "__SCNetworkConfigurationUpgrade(): update not saved [NetworkInterfaces.plist]: %s",
322 SCErrorString(SCError()));
326 SCPreferencesUnlock(ni_prefs
);
332 // if (ok && (prefs_p != NULL)) {
333 // *prefs_p = CFRetain(prefs);
338 if (ni_prefs_added
) {
339 if (ok
&& (ni_prefs_p
!= NULL
)) {
340 *ni_prefs_p
= CFRetain(ni_prefs
);
350 #pragma mark Remove "Hidden" Interface Configurations
354 isThin(CFArrayRef interfaces
, CFStringRef bsdName
)
358 thin
= CFArrayContainsValue(interfaces
,
359 CFRangeMake(0, CFArrayGetCount(interfaces
)),
366 thinAdd(CFMutableArrayRef interfaces
, CFStringRef bsdName
)
368 if (!CFArrayContainsValue(interfaces
,
369 CFRangeMake(0, CFArrayGetCount(interfaces
)),
371 CFArrayAppendValue(interfaces
, bsdName
);
380 thinRemove(CFMutableArrayRef interfaces
, CFStringRef bsdName
)
384 n
= CFArrayGetFirstIndexOfValue(interfaces
,
385 CFRangeMake(0, CFArrayGetCount(interfaces
)),
387 if (n
!= kCFNotFound
) {
388 CFArrayRemoveValueAtIndex(interfaces
, n
);
396 static CF_RETURNS_RETAINED CFStringRef
397 serviceMatchesTemplate(SCPreferencesRef prefs
, SCNetworkServiceRef existingService
)
399 CFStringRef conflict
= NULL
;
400 SCNetworkInterfaceRef existingInterface
;
402 CFArrayRef protocols
;
403 CFMutableArrayRef protocolTypes
;
404 SCNetworkServiceRef templateService
;
406 // create a temporary network service (so that we can get the template configuration)
407 existingInterface
= SCNetworkServiceGetInterface(existingService
);
408 if (existingInterface
== NULL
) {
409 conflict
= CFStringCreateCopy(NULL
, CFSTR("could not get interface for service"));
413 templateService
= SCNetworkServiceCreate(prefs
, existingInterface
);
414 if (templateService
== NULL
) {
415 conflict
= CFStringCreateCopy(NULL
, CFSTR("could not create service for interface"));
419 (void) SCNetworkServiceEstablishDefaultConfiguration(templateService
);
421 protocolTypes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
423 // get protocol types from the existing service
424 protocols
= SCNetworkServiceCopyProtocols(existingService
);
425 if (protocols
!= NULL
) {
426 n
= CFArrayGetCount(protocols
);
428 for (CFIndex i
= 0; i
< n
; i
++) {
429 SCNetworkProtocolRef protocol
;
430 CFStringRef protocolType
;
432 protocol
= CFArrayGetValueAtIndex(protocols
, i
);
433 protocolType
= SCNetworkProtocolGetProtocolType(protocol
);
434 if (!CFArrayContainsValue(protocolTypes
,
435 CFRangeMake(0, CFArrayGetCount(protocolTypes
)),
437 CFArrayAppendValue(protocolTypes
, protocolType
);
441 CFRelease(protocols
);
444 // get protocol types from the template service
445 protocols
= SCNetworkServiceCopyProtocols(templateService
);
446 if (protocols
!= NULL
) {
447 n
= CFArrayGetCount(protocols
);
449 for (CFIndex i
= 0; i
< n
; i
++) {
450 SCNetworkProtocolRef protocol
;
451 CFStringRef protocolType
;
453 protocol
= CFArrayGetValueAtIndex(protocols
, i
);
454 protocolType
= SCNetworkProtocolGetProtocolType(protocol
);
455 if (!CFArrayContainsValue(protocolTypes
,
456 CFRangeMake(0, CFArrayGetCount(protocolTypes
)),
458 CFArrayAppendValue(protocolTypes
, protocolType
);
462 CFRelease(protocols
);
465 // compare the existing protocols with the template
466 n
= CFArrayGetCount(protocolTypes
);
467 for (CFIndex i
= 0; i
< n
; i
++) {
468 CFDictionaryRef existingConfiguration
= NULL
;
469 SCNetworkProtocolRef existingProtocol
;
471 CFStringRef protocolType
;
472 CFDictionaryRef templateConfiguration
= NULL
;
473 SCNetworkProtocolRef templateProtocol
;
475 protocolType
= CFArrayGetValueAtIndex(protocolTypes
, i
);
476 existingProtocol
= SCNetworkServiceCopyProtocol(existingService
, protocolType
);
477 templateProtocol
= SCNetworkServiceCopyProtocol(templateService
, protocolType
);
481 match
= ((existingProtocol
!= NULL
) &&
482 (templateProtocol
!= NULL
) &&
483 (SCNetworkProtocolGetEnabled(existingProtocol
) == SCNetworkProtocolGetEnabled(templateProtocol
)));
485 conflict
= CFStringCreateWithFormat(NULL
, NULL
,
486 CFSTR("conflicting %@ enable/disable"),
488 break; // if enable/disable conflict
491 if (existingProtocol
!= NULL
) {
492 existingConfiguration
= SCNetworkProtocolGetConfiguration(existingProtocol
);
494 if (templateProtocol
!= NULL
) {
495 templateConfiguration
= SCNetworkProtocolGetConfiguration(templateProtocol
);
497 match
= _SC_CFEqual(existingConfiguration
, templateConfiguration
);
499 conflict
= CFStringCreateWithFormat(NULL
, NULL
,
500 CFSTR("conflicting %@ configuration"),
502 break; // if configuration conflict
506 if (existingProtocol
!= NULL
) CFRelease(existingProtocol
);
507 if (templateProtocol
!= NULL
) CFRelease(templateProtocol
);
513 (void) SCNetworkServiceRemove(templateService
);
514 CFRelease(templateService
);
515 CFRelease(protocolTypes
);
521 effectivelyHiddenConfiguration(SCNetworkInterfaceRef interface
)
523 const CFStringRef known
[] = {
532 name
= SCNetworkInterfaceGetLocalizedDisplayName(interface
);
533 for (int i
= 0; i
< (int)(sizeof(known
) / sizeof(known
[0])); i
++) {
534 if (CFStringHasPrefix(name
, known
[i
])) {
544 __SCNetworkConfigurationCleanHiddenInterfaces(SCPreferencesRef prefs
, SCPreferencesRef ni_prefs
)
546 #pragma unused(prefs)
547 #pragma unused(ni_prefs)
549 Boolean changed
= FALSE
;
550 CFArrayRef interfaces
;
551 CFMutableArrayRef interfaces_thin
;
553 CFDictionaryRef nat_config
;
554 SCPreferencesRef nat_prefs
;
558 // build a list of interfaces we "could" remove
560 interfaces_thin
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
562 services
= SCNetworkServiceCopyAll(prefs
);
563 if (services
!= NULL
) {
564 n
= CFArrayGetCount(services
);
565 for (CFIndex i
= 0; i
< n
; i
++) {
566 CFStringRef conflict
;
567 SCNetworkInterfaceRef interface
;
568 SCNetworkServiceRef service
;
569 const char *thin
= NULL
;
571 service
= CFArrayGetValueAtIndex(services
, i
);
572 interface
= SCNetworkServiceGetInterface(service
);
573 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
575 if (bsdName
== NULL
) {
576 // if no interface name
577 if ((_sc_log
== 1) || _sc_debug
) {
579 "skipping service : %@ : %@ (no interface)",
580 SCNetworkServiceGetServiceID(service
),
581 SCNetworkServiceGetName(service
));
586 if (_SCNetworkInterfaceIsHiddenConfiguration(interface
)) {
588 } else if (effectivelyHiddenConfiguration(interface
)) {
589 thin
= "effectively hidden";
591 // if not HiddenConfiguration
592 if ((_sc_log
== 1) || _sc_debug
) {
594 "skipping service : %@ : %@ : %@ (not hidden)",
595 SCNetworkServiceGetServiceID(service
),
596 SCNetworkServiceGetName(service
),
602 conflict
= serviceMatchesTemplate(prefs
, service
);
603 if (conflict
!= NULL
) {
604 // if any part of the service's configuration was changed
605 if ((_sc_log
== 1) || _sc_debug
) {
607 "skipping service : %@ : %@ : %@ (%s, non-default, %@)",
608 SCNetworkServiceGetServiceID(service
),
609 SCNetworkServiceGetName(service
),
618 if ((_sc_log
== 1) || _sc_debug
) {
619 SC_log(LOG_INFO
, "candidate interface : %@ (%s)", bsdName
, thin
);
622 thinAdd(interfaces_thin
, bsdName
);
626 // remove any virtual interfaces from the list
628 #if !TARGET_OS_IPHONE
629 interfaces
= SCBondInterfaceCopyAll(prefs
);
630 if (interfaces
!= NULL
) {
633 n
= CFArrayGetCount(interfaces
);
634 for (CFIndex i
= 0; i
< n
; i
++) {
635 SCBondInterfaceRef bondInterface
;
639 bondInterface
= CFArrayGetValueAtIndex(interfaces
, i
);
640 members
= SCBondInterfaceGetMemberInterfaces(bondInterface
);
641 nn
= (members
!= NULL
) ? CFArrayGetCount(members
) : 0;
642 for (CFIndex ii
= 0; ii
< nn
; ii
++) {
643 SCNetworkInterfaceRef member
;
645 member
= CFArrayGetValueAtIndex(members
, ii
);
646 bsdName
= SCNetworkInterfaceGetBSDName(member
);
647 if ((bsdName
!= NULL
) &&
648 thinRemove(interfaces_thin
, bsdName
)) {
649 if ((_sc_log
== 1) || _sc_debug
) {
650 SC_log(LOG_INFO
, "skipping interface : %@ (bond member)", bsdName
);
656 CFRelease(interfaces
);
658 #endif // !TARGET_OS_IPHONE
660 interfaces
= SCBridgeInterfaceCopyAll(prefs
);
661 if (interfaces
!= NULL
) {
664 n
= CFArrayGetCount(interfaces
);
665 for (CFIndex i
= 0; i
< n
; i
++) {
666 SCBridgeInterfaceRef bridgeInterface
;
670 bridgeInterface
= CFArrayGetValueAtIndex(interfaces
, i
);
671 members
= SCBridgeInterfaceGetMemberInterfaces(bridgeInterface
);
672 nn
= (members
!= NULL
) ? CFArrayGetCount(members
) : 0;
673 for (CFIndex ii
= 0; ii
< nn
; ii
++) {
674 SCNetworkInterfaceRef member
;
676 member
= CFArrayGetValueAtIndex(members
, ii
);
677 bsdName
= SCNetworkInterfaceGetBSDName(member
);
678 if ((bsdName
!= NULL
) &&
679 thinRemove(interfaces_thin
, bsdName
)) {
680 if ((_sc_log
== 1) || _sc_debug
) {
681 SC_log(LOG_INFO
, "skipping interface : %@ (bridge member)", bsdName
);
687 CFRelease(interfaces
);
690 interfaces
= SCVLANInterfaceCopyAll(prefs
);
691 if (interfaces
!= NULL
) {
694 n
= CFArrayGetCount(interfaces
);
695 for (CFIndex i
= 0; i
< n
; i
++) {
696 SCBridgeInterfaceRef vlanInterface
;
697 SCNetworkInterfaceRef physicalInterface
;
699 vlanInterface
= CFArrayGetValueAtIndex(interfaces
, i
);
700 physicalInterface
= SCVLANInterfaceGetPhysicalInterface(vlanInterface
);
701 bsdName
= SCNetworkInterfaceGetBSDName(physicalInterface
);
702 if ((bsdName
!= NULL
) &&
703 thinRemove(interfaces_thin
, bsdName
)) {
704 if ((_sc_log
== 1) || _sc_debug
) {
705 SC_log(LOG_INFO
, "skipping interface : %@ (vlan physical)", bsdName
);
710 CFRelease(interfaces
);
713 // remove any "shared" interfaces from the list
715 nat_prefs
= SCPreferencesCreateCompanion(prefs
, CFSTR("com.apple.nat.plist"));
716 nat_config
= SCPreferencesGetValue(nat_prefs
, CFSTR("NAT"));
717 if (isA_CFDictionary(nat_config
)) {
718 CFStringRef sharedFrom
= NULL
;
719 CFArrayRef sharedTo
= NULL
;
721 if (CFDictionaryGetValueIfPresent(nat_config
,
722 CFSTR("PrimaryService"),
723 (const void **)&sharedFrom
) &&
724 isA_CFString(sharedFrom
)) {
725 SCNetworkInterfaceRef interface
;
726 SCNetworkServiceRef service
;
728 // if "Share your connection from" service configured
729 service
= SCNetworkServiceCopy(prefs
, sharedFrom
);
730 if (service
!= NULL
) {
731 interface
= SCNetworkServiceGetInterface(service
);
732 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
733 if ((bsdName
!= NULL
) &&
734 thinRemove(interfaces_thin
, bsdName
)) {
735 if ((_sc_log
== 1) || _sc_debug
) {
736 SC_log(LOG_INFO
, "skipping interface : %@ (Share your connection from)", bsdName
);
741 SC_log(LOG_INFO
, "keeping [not found] service : %@ (Share your connection from)", sharedFrom
);
745 if (CFDictionaryGetValueIfPresent(nat_config
,
746 CFSTR("SharingDevices"),
747 (const void **)&sharedTo
) &&
748 isA_CFArray(sharedTo
)) {
749 // if "To computers using" interfaces configured
750 n
= CFArrayGetCount(sharedTo
);
751 for (CFIndex i
= 0; i
< n
; i
++) {
752 bsdName
= CFArrayGetValueAtIndex(sharedTo
, i
);
753 if (thinRemove(interfaces_thin
, bsdName
)) {
754 if ((_sc_log
== 1) || _sc_debug
) {
755 SC_log(LOG_INFO
, "skipping interface : %@ (To computers using)", bsdName
);
761 CFRelease(nat_prefs
);
763 // thin preferences.plist
764 n
= (services
!= NULL
) ? CFArrayGetCount(services
) : 0;
768 for (CFIndex i
= 0; i
< n
; i
++) {
769 SCNetworkInterfaceRef interface
;
770 SCNetworkServiceRef service
;
772 service
= CFArrayGetValueAtIndex(services
, i
);
773 interface
= SCNetworkServiceGetInterface(service
);
774 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
775 if (bsdName
== NULL
) {
776 // if no interface name
780 if (!isThin(interfaces_thin
, bsdName
)) {
785 // remove this service associated with a "thinned" interface
786 if ((_sc_log
== 1) || _sc_verbose
) {
788 "thinned network service : %@ : %@ : %@",
789 SCNetworkServiceGetServiceID(service
),
790 SCNetworkServiceGetName(service
),
793 SCNetworkServiceRemove(service
);
798 if ((_sc_log
== 1) || _sc_debug
) {
800 "Updating \"preferences.plist\" (thinned %d service%s)",
802 (updated
!= 1) ? "s" : "");
808 // thin NetworkInterfaces.plist
809 interfaces
= SCPreferencesGetValue(ni_prefs
, INTERFACES
);
810 interfaces
= isA_CFArray(interfaces
);
811 n
= (interfaces
!= NULL
) ? CFArrayGetCount(interfaces
) : 0;
813 CFMutableArrayRef interfaces_new
;
817 interfaces_new
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
818 n
= CFArrayGetCount(interfaces
);
819 for (CFIndex i
= 0; i
< n
; i
++) {
820 CFDictionaryRef if_dict
;
822 if_dict
= CFArrayGetValueAtIndex(interfaces
, i
);
823 bsdName
= CFDictionaryGetValue(if_dict
, CFSTR(kIOBSDNameKey
));
824 if (isThin(interfaces_thin
, bsdName
)) {
825 if (CFDictionaryContainsKey(if_dict
, CFSTR(kSCNetworkInterfaceActive
))) {
826 if ((_sc_log
== 1) || _sc_debug
) {
827 SC_log(LOG_INFO
, "skipping interface : %@ (active)", bsdName
);
830 // remove this "thinned" interface
831 if ((_sc_log
== 1) || _sc_debug
|| _sc_verbose
) {
832 SC_log(LOG_INFO
, "thinned network interface : %@", bsdName
);
839 CFArrayAppendValue(interfaces_new
, if_dict
);
841 SCPreferencesSetValue(ni_prefs
, INTERFACES
, interfaces_new
);
842 CFRelease(interfaces_new
);
845 if ((_sc_log
== 1) || _sc_debug
) {
847 "Updating \"NetworkInterfaces.plist\" (thinned %d interface%s)",
849 (updated
!= 1) ? "s" : "");
855 if (services
!= NULL
) CFRelease(services
);
856 CFRelease(interfaces_thin
);
862 #pragma mark Remove [SCNetworkMigration] Inline Backups
866 thinInlineBackup(const void *value
, void *context
)
868 CFStringRef backup
= (CFStringRef
)value
;
870 SCPreferencesRef prefs
= (SCPreferencesRef
)context
;
871 CFStringRef save_prefix
;
872 CFStringRef save_prefsID
= NULL
;
874 SC_log(LOG_NOTICE
, "thinning [inline] backup: %@", backup
);
876 save_prefix
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@ : "), backup
);
877 backup_str
= _SC_cfstring_to_cstring(backup
, NULL
, 0, kCFStringEncodingASCII
);
878 if (backup_str
!= NULL
) {
879 struct tm save_tm
= { 0 };
881 if (strptime(backup_str
, "%Y-%m-%d %H:%M:%S", &save_tm
) != NULL
) {
882 save_prefsID
= CFStringCreateWithFormat(NULL
,
884 CFSTR("preferences-%4d-%02d-%02d-%02d%02d%02d.plist"),
885 save_tm
.tm_year
+ 1900,
892 CFAllocatorDeallocate(NULL
, backup_str
);
894 if (save_prefsID
== NULL
) {
895 save_prefsID
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("preferences-%@.plist"), backup
);
897 savePreferences(prefs
, save_prefsID
, save_prefix
, TRUE
, NULL
, NULL
);
898 CFRelease(save_prefsID
);
899 CFRelease(save_prefix
);
905 __SCNetworkConfigurationCleanInlineBackups(SCPreferencesRef prefs
)
907 CFMutableSetRef backups
= NULL
;
908 Boolean cleaned
= FALSE
;
913 keys
= SCPreferencesCopyKeyList(prefs
);
918 suffix
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR(" : %@"), kSCPrefSets
);
919 n
= CFArrayGetCount(keys
);
920 for (CFIndex i
= 0; i
< n
; i
++) {
921 CFStringRef key
= CFArrayGetValueAtIndex(keys
, i
);
922 CFMutableStringRef str
;
924 if (CFStringHasSuffix(key
, suffix
)) {
925 // if "<backup-date> : Sets"
926 if (backups
== NULL
) {
927 backups
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
929 str
= CFStringCreateMutableCopy(NULL
, 0, key
);
930 CFStringTrim(str
, suffix
);
931 CFSetAddValue(backups
, str
);
939 if (backups
!= NULL
) {
940 CFSetApplyFunction(backups
, thinInlineBackup
, (void *)prefs
);
950 #pragma mark Remove [new device type] Inline Backups
954 thinInlineModel(const void *value
, void *context
)
956 CFStringRef model
= (CFStringRef
)value
;
957 SCPreferencesRef prefs
= (SCPreferencesRef
)context
;
958 CFStringRef save_prefix
;
959 CFStringRef save_prefsID
;
961 SC_log(LOG_NOTICE
, "thinning [per-model] backup: %@", model
);
963 save_prefix
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@:"), model
);
964 save_prefsID
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("preferences-%@.plist"), model
);
965 savePreferences(prefs
, save_prefsID
, save_prefix
, TRUE
, MODEL
, model
);
966 CFRelease(save_prefsID
);
967 CFRelease(save_prefix
);
973 __SCNetworkConfigurationCleanInlineModels(SCPreferencesRef prefs
)
975 Boolean cleaned
= FALSE
;
977 CFMutableSetRef models
= NULL
;
981 keys
= SCPreferencesCopyKeyList(prefs
);
986 suffix
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR(":%@"), kSCPrefSets
);
987 n
= CFArrayGetCount(keys
);
988 for (CFIndex i
= 0; i
< n
; i
++) {
989 CFStringRef key
= CFArrayGetValueAtIndex(keys
, i
);
990 CFMutableStringRef str
;
992 if (CFStringHasSuffix(key
, suffix
)) {
993 // if "<backup-date> : Sets"
994 if (models
== NULL
) {
995 models
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
997 str
= CFStringCreateMutableCopy(NULL
, 0, key
);
998 CFStringTrim(str
, suffix
);
999 CFSetAddValue(models
, str
);
1007 if (models
!= NULL
) {
1008 CFSetApplyFunction(models
, thinInlineModel
, (void *)prefs
);
1018 #pragma mark Remove Orphaned Services
1023 __SCNetworkConfigurationCleanOrphanedServices(SCPreferencesRef prefs)
1025 #pragma unused(prefs)
1032 #pragma mark Cleanup network service order issues
1036 __SCNetworkConfigurationCleanServiceOrderIssues(SCPreferencesRef prefs
)
1038 #pragma unused(prefs)
1039 Boolean cleaned
= FALSE
;
1043 sets
= SCNetworkSetCopyAll(prefs
);
1044 nSets
= (sets
!= NULL
) ? CFArrayGetCount(sets
) : 0;
1045 for (CFIndex iSets
= 0; iSets
< nSets
; iSets
++) {
1047 CFMutableSetRef known
= NULL
;
1049 SCNetworkSetRef set
= CFArrayGetValueAtIndex(sets
, iSets
);
1050 CFStringRef setID
= SCNetworkSetGetSetID(set
);
1051 CFArrayRef order
= SCNetworkSetGetServiceOrder(set
);
1052 CFMutableArrayRef newOrder
= NULL
;
1055 nServices
= (order
!= NULL
) ? CFArrayGetCount(order
) : 0;
1056 if (nServices
> 0) {
1057 known
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
1058 newOrder
= CFArrayCreateMutableCopy(NULL
, 0, order
);
1061 while (iServices
< nServices
) {
1062 SCNetworkServiceRef service
;
1063 CFStringRef serviceID
= CFArrayGetValueAtIndex(newOrder
, iServices
);
1065 // check if serviceID already known/processed
1066 if (CFSetContainsValue(known
, serviceID
)) {
1067 // if duplicate/removed service, remove from serviceOrder
1068 if ((_sc_log
== 1) || _sc_debug
) {
1070 "set: %@, removing serviceID %@ (duplicate/removed)",
1074 CFArrayRemoveValueAtIndex(newOrder
, iServices
);
1080 // track this serviceID as known, already removed, or removed below
1081 CFSetAddValue(known
, serviceID
);
1083 // validate serviceID
1084 service
= SCNetworkServiceCopy(prefs
, serviceID
);
1085 if (service
== NULL
) {
1086 // if no service, remove from serviceOrder
1087 if ((_sc_log
== 1) || _sc_debug
) {
1089 "set: %@, removing serviceID %@ (no service)",
1093 CFArrayRemoveValueAtIndex(newOrder
, iServices
);
1099 if (!__SCNetworkServiceExists(service
)) {
1100 // if service already removed, remove from serviceOrder
1101 if ((_sc_log
== 1) || _sc_debug
) {
1103 "set: %@, removing serviceID %@ (service already removed)",
1107 CFArrayRemoveValueAtIndex(newOrder
, iServices
);
1118 if (known
!= NULL
) {
1122 if (newOrder
!= NULL
) {
1124 SCNetworkSetSetServiceOrder(set
, newOrder
);
1126 CFRelease(newOrder
);
1139 #pragma mark Cleanup Network Configuration(s)
1143 __SCNetworkConfigurationClean(SCPreferencesRef prefs
, SCPreferencesRef ni_prefs
)
1146 Boolean updated
= FALSE
;
1148 changed
= __SCNetworkConfigurationCleanInlineBackups(prefs
);
1150 SC_log(LOG_NOTICE
, "network configuration: unwanted inline backups removed");
1154 changed
= __SCNetworkConfigurationCleanInlineModels(prefs
);
1156 SC_log(LOG_NOTICE
, "network configuration: unwanted device backups removed");
1160 if (ni_prefs
!= NULL
) {
1161 changed
= __SCNetworkConfigurationCleanHiddenInterfaces(prefs
, ni_prefs
);
1163 SC_log(LOG_NOTICE
, "network configuration: hidden interface configurations removed");
1168 changed
= __SCNetworkConfigurationCleanServiceOrderIssues(prefs
);
1170 SC_log(LOG_NOTICE
, "network configuration: ServiceOrder cleaned");