Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing DNS settings using PyObjC

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.

like image 622
robertklep Avatar asked Aug 18 '15 13:08

robertklep


1 Answers

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.

like image 172
jaypb Avatar answered Oct 18 '22 16:10

jaypb