Using scutil to set DNS server
scutil can allow to change a number of OS X settings including the DNS servers.However it is more than a bit cryptic in it's use.
Ed. Note: It's easier to change the DNS settings by using the networksetup command. This comes standard on OS X Server, and is a part, albeit buried, of the ARD distribution that comes with OS X client. Learning about scutil is good though as it fosters understanding of configd.
I recently had the pleasure of turning the laptops in our company into roadwarriors. Since we only use plain ipsec, and no L2TP/PPTP, I couldn't use Internet Connect, but had to resort to a shell script that will start/stop the VPN.
Making racoon with X509 certificates working was a doodle; I had ip-routable traffic up and running in no time. However in order to get a smooth integration with our office infrastructure I needed to make it so that when the VPN is up, the DNS server setting needs to change to have our office DNS first.
A roadwarrior will typically connect to a wireless network in an internet cafe using DHCP. The DHCP response will provide a DNS server, however I needed to ensure that our office DNS would be made to resolve any name in preference to the DHCP supplied one.
Enter scutil
The man page tells us that scutil provides a command line interface to the "dynamic store" data maintained by configd(8). This store basically holds the runtime network configurations. To explore the database, type scutil which gives you an interactive prompt. help will give you a woefully inadequate explanation of its capabiities - true Apple style. On Panther before you can do anything else you need to type open to start a session against configd. On Tiger (which is used below) this is not needed:
> list
subKey [0] = DirectoryService:PID
subKey [1] = Plugin:IPConfiguration
subKey [2] = Setup:
subKey [3] = Setup:/
subKey [4] = Setup:/Network/Global/IPv4
subKey [5] = Setup:/Network/HostNames
subKey [6] = Setup:/Network/Interface/en1/AirPort
subKey [7] = Setup:/Network/Service/0
subKey [8] = Setup:/Network/Service/0/Ethernet
subKey [9] = Setup:/Network/Service/0/IPv4
subKey [10] = Setup:/Network/Service/0/IPv6
subKey [11] = Setup:/Network/Service/0/Interface
subKey [12] = Setup:/Network/Service/0/Proxies
subKey [13] = Setup:/Network/Service/1FC12C91-7AA7-4EF7-9D55-1F913DF73EFE
subKey [14] = Setup:/Network/Service/1FC12C91-7AA7-4EF7-9D55-1F913DF73EFE/IPv4
subKey [15] = Setup:/Network/Service/1FC12C91-7AA7-4EF7-9D55-1F913DF73EFE/IPv6
subKey [16] = Setup:/Network/Service/1FC12C91-7AA7-4EF7-9D55-1F913DF73EFE/Interface
subKey [17] = Setup:/Network/Service/1FC12C91-7AA7-4EF7-9D55-1F913DF73EFE/PPP
subKey [18] = Setup:/Network/Service/1FC12C91-7AA7-4EF7-9D55-1F913DF73EFE/Proxies
subKey [19] = Setup:/Network/Service/72F822A6-BFB9-4235-B6AF-BB82F36CF481
subKey [20] = Setup:/Network/Service/72F822A6-BFB9-4235-B6AF-BB82F36CF481/IPv4
subKey [21] = Setup:/Network/Service/72F822A6-BFB9-4235-B6AF-BB82F36CF481/IPv6
subKey [22] = Setup:/Network/Service/72F822A6-BFB9-4235-B6AF-BB82F36CF481/Interface
subKey [23] = Setup:/Network/Service/72F822A6-BFB9-4235-B6AF-BB82F36CF481/Modem
subKey [24] = Setup:/Network/Service/72F822A6-BFB9-4235-B6AF-BB82F36CF481/PPP
subKey [25] = Setup:/Network/Service/72F822A6-BFB9-4235-B6AF-BB82F36CF481/Proxies
subKey [26] = Setup:/Network/Service/9F1BE170-7AEC-4688-A99B-B00AC5D6317C
...
Use show to inspect any of the keys. The below seems to show in what order the network interfaces are being prioritised, the hex numbers are identifiers for the network interfaces. It's quite easy to figure out which one is which by using scutil:
> show Setup:/Network/Global/IPv4
<dictionary> {
PPPOverridePrimary : 0
ServiceOrder : <array> {
0 : 9F1BE170-7AEC-4688-A99B-B00AC5D6317C
1 : 72F822A6-BFB9-4235-B6AF-BB82F36CF481
2 : 0
3 : C7637493-F33B-44A2-9C33-8F1AC0238782
4 : FEAFA7DE-8BE5-49ED-A115-A3E113E8753B
5 : 1FC12C91-7AA7-4EF7-9D55-1F913DF73EFE
}
}
> show Setup:/Network/Service/9F1BE170-7AEC-4688-A99B-B00AC5D6317C/Interface
<dictionary> {
UserDefinedName : Internal Modem
Hardware : Modem
SubType : PPPSerial
Type : PPP
SupportsModemOnHold : 1
DeviceName : modem
}
Back to the plot
The help will tell you that list can take an argument [pattern]. After a bit of mucking around, turns out this is bog standard regular expressions:
> list State:/Network/Service/[^/]+/DNS
subKey [0] = State:/Network/Service/FEAFA7DE-8BE5-49ED-A115-A3E113E8753B/DNS
And it turns out the above will list exactly the keys that holds the DNS information for your current network configuration, note that this could return more than one key since you might have more than one network interface active. However the State:/Network/Global/DNS
reflects the used setting. You can't however change this value, it seems to only reflect what is configured on the separate interfaces:
> show State:/Network/Service/FEAFA7DE-8BE5-49ED-A115-A3E113E8753B/DNS
<dictionary> {
ServerAddresses : <array> {
0 : 192.168.XXX.XXX
}
DomainName : XXX.taglab.com
}
> show State:/Network/Global/DNS
<dictionary> {
ServerAddresses : <array> {
0 : 192.168.XXX.XXX
}
DomainName : XXX.taglab.com
}
We can change the setting by doing:
> get State:/Network/Service/FEAFA7DE-8BE5-49ED-A115-A3E113E8753B/DNS
> d.show
<dictionary> {
ServerAddresses : <array> {
0 : 192.168.XXX.XXX
}
DomainName : XXX.taglab.com
}
> d.add ServerAddresses * 130.240.19.2
> d.show
<dictionary> {
ServerAddresses : <array> {
0 : 130.240.19.2
}
DomainName : XXX.taglab.com
}
> set State:/Network/Service/FEAFA7DE-8BE5-49ED-A115-A3E113E8753B/DNS
Permission denied
This is the point we realise that we need to run scutil sudo. The get reads the value for the key given into a "working dictionary" d, that is subsequently used to manipulate the data before saving it back using set
Script it up
Though I like to, I'm not seriously suggesting that the execs of our company are going to change their DNS settings using scutil themselves. Turns out you can easily script it:
banana$ echo "list State:/Network/Service/[^/]+/DNS" | scutil
subKey [0] = State:/Network/Service/FEAFA7DE-8BE5-49ED-A115-A3E113E8753B/DNS
banana$ echo "list State:/Network/Service/[^/]+/DNS" | scutil | awk '{print $4}' | while read f; do echo "show $f" | scutil ; done
<dictionary> {
ServerAddresses : <array> {
0 : 192.168.XXX.XXX
}
DomainName : XXX.taglab.com
}
Making a script that then changes the DNS settings on the fly is elementary shell scripting - job done.
