I'm trying to change the DNS servers on my Mac (10.10.4) using PyObjC (3.0.4).
Everything seems to work: I get an authentication dialog prompting that my program is trying to change network settings, and the commit/apply commands return True
, which would indicate they were successful.
However, the system settings aren't actually changed: they remain the same as before. Any idea why they don't "stick"?
The code (standalone, should work if you have a recent version of PyObjC installed):
#!/usr/bin/env python
import objc
from SystemConfiguration import *
# Open dynamic store and get primary interface
store = SCDynamicStoreCreate(None, 'MyApp', None, None)
primaryif = SCDynamicStoreCopyValue(store, 'State:/Network/Global/IPv4')['PrimaryInterface']
if primaryif:
print "Using %s as primary interface" % primaryif
else:
raise "Can't find primary interface"
# Load SecurityInterface framework to provide SFAuthorization
objc.initFrameworkWrapper(
frameworkName = "SecurityInterface",
frameworkIdentifier = "com.apple.securityinterface",
frameworkPath = objc.pathForFramework("/System/Library/Frameworks/SecurityInterface.framework"),
globals = globals()
)
# Access system preferences
preferences = SCPreferencesCreateWithAuthorization(None, 'MyApp', None, SFAuthorization.authorization().authorizationRef())
# Lock preferences
SCPreferencesLock(preferences, True)
# Get list of network services
networkSet = SCNetworkSetCopyCurrent(preferences)
networkSetServices = SCNetworkSetCopyServices(networkSet)
# Find the network service that belongs to the primary interface
for networkService in networkSetServices:
interface = SCNetworkServiceGetInterface(networkService)
if primaryif != SCNetworkInterfaceGetBSDName(interface):
continue
# Load currently configured DNS servers
networkProtocol = SCNetworkServiceCopyProtocol(networkService, kSCNetworkProtocolTypeDNS)
DNSDict = SCNetworkProtocolGetConfiguration(networkProtocol) or {}
# Set new DNS servers
DNSDict[kSCPropNetDNSServerAddresses] = [ '192.168.23.12', '8.8.4.4' ]
SCNetworkProtocolSetConfiguration(networkService, DNSDict)
# Unlock, commit and apply preferences
print "UL", SCPreferencesUnlock(preferences)
print "CO", SCPreferencesCommitChanges(preferences)
print "AP", SCPreferencesApplyChanges(preferences)
EDIT: most of the above code is based on this page, which also suggests "touching" the dynamic store to make the settings stick (the code to do this is commented out right at the end). However, it doesn't seem to do anything.
EDIT #2: by disassembling /usr/sbin/networksetup
I'm getting the idea that I need a set of specific rights (system.services.systemconfiguration.network
) before any changes are accepted.
Looks like there are issues with PyObjC that cause this to not work, however you may be able to find a way around it by using a different solution. If I were you, and my situation allowed it, I would just call the system command line tools to set the DNS servers.
According to OSXDaily, you can do this with:
networksetup -setdnsservers (Network Service) (DNS IP)
If you have cross platform requirements this is obviously less than desirable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With