Articles July 17, 2005 at 5:20 pm

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:

<code>
&gt; list
  subKey &#91;0&#93; = DirectoryService:PID
  subKey &#91;1&#93; = Plugin:IPConfiguration
  subKey &#91;2&#93; = Setup:
  subKey &#91;3&#93; = Setup:/
  subKey &#91;4&#93; = Setup:/Network/Global/IPv4
  subKey &#91;5&#93; = Setup:/Network/HostNames
  subKey &#91;6&#93; = Setup:/Network/Interface/en1/AirPort
  subKey &#91;7&#93; = Setup:/Network/Service/0
  subKey &#91;8&#93; = Setup:/Network/Service/0/Ethernet
  subKey &#91;9&#93; = Setup:/Network/Service/0/IPv4
  subKey &#91;10&#93; = Setup:/Network/Service/0/IPv6
  subKey &#91;11&#93; = Setup:/Network/Service/0/Interface
  subKey &#91;12&#93; = Setup:/Network/Service/0/Proxies
  subKey &#91;13&#93; = Setup:/Network/Service/1FC12C91-7AA7-4EF7-9D55-1F913DF73EFE
  subKey &#91;14&#93; = Setup:/Network/Service/1FC12C91-7AA7-4EF7-9D55-1F913DF73EFE/IPv4
  subKey &#91;15&#93; = Setup:/Network/Service/1FC12C91-7AA7-4EF7-9D55-1F913DF73EFE/IPv6
  subKey &#91;16&#93; = Setup:/Network/Service/1FC12C91-7AA7-4EF7-9D55-1F913DF73EFE/Interface
  subKey &#91;17&#93; = Setup:/Network/Service/1FC12C91-7AA7-4EF7-9D55-1F913DF73EFE/PPP
  subKey &#91;18&#93; = Setup:/Network/Service/1FC12C91-7AA7-4EF7-9D55-1F913DF73EFE/Proxies
  subKey &#91;19&#93; = Setup:/Network/Service/72F822A6-BFB9-4235-B6AF-BB82F36CF481
  subKey &#91;20&#93; = Setup:/Network/Service/72F822A6-BFB9-4235-B6AF-BB82F36CF481/IPv4
  subKey &#91;21&#93; = Setup:/Network/Service/72F822A6-BFB9-4235-B6AF-BB82F36CF481/IPv6
  subKey &#91;22&#93; = Setup:/Network/Service/72F822A6-BFB9-4235-B6AF-BB82F36CF481/Interface
  subKey &#91;23&#93; = Setup:/Network/Service/72F822A6-BFB9-4235-B6AF-BB82F36CF481/Modem
  subKey &#91;24&#93; = Setup:/Network/Service/72F822A6-BFB9-4235-B6AF-BB82F36CF481/PPP
  subKey &#91;25&#93; = Setup:/Network/Service/72F822A6-BFB9-4235-B6AF-BB82F36CF481/Proxies
  subKey &#91;26&#93; = Setup:/Network/Service/9F1BE170-7AEC-4688-A99B-B00AC5D6317C
...
</code>

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:

<code>
&gt; show Setup:/Network/Global/IPv4
&lt;dictionary&gt; {
  PPPOverridePrimary : 0
  ServiceOrder : &lt;array&gt; {
    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
  }
}
&gt; show Setup:/Network/Service/9F1BE170-7AEC-4688-A99B-B00AC5D6317C/Interface
&lt;dictionary&gt; {
  UserDefinedName : Internal Modem
  Hardware : Modem
  SubType : PPPSerial
  Type : PPP
  SupportsModemOnHold : 1
  DeviceName : modem
}
</code>

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:

<code>
&gt; list State:/Network/Service/&#91;^/&#93;+/DNS
  subKey &#91;0&#93; = State:/Network/Service/FEAFA7DE-8BE5-49ED-A115-A3E113E8753B/DNS
</code>

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:

<code>
&gt; show State:/Network/Service/FEAFA7DE-8BE5-49ED-A115-A3E113E8753B/DNS
&lt;dictionary&gt; {
  ServerAddresses : &lt;array&gt; {
    0 : 192.168.XXX.XXX
  }
  DomainName : XXX.taglab.com
}
&gt; show State:/Network/Global/DNS
&lt;dictionary&gt; {
  ServerAddresses : &lt;array&gt; {
    0 : 192.168.XXX.XXX
  }
  DomainName : XXX.taglab.com
}
</code>

We can change the setting by doing:

<code>
&gt; get State:/Network/Service/FEAFA7DE-8BE5-49ED-A115-A3E113E8753B/DNS
&gt; d.show
&lt;dictionary&gt; {
  ServerAddresses : &lt;array&gt; {
    0 : 192.168.XXX.XXX
  }
  DomainName : XXX.taglab.com
}
&gt; d.add ServerAddresses * 130.240.19.2
&gt; d.show
&lt;dictionary&gt; {
  ServerAddresses : &lt;array&gt; {
    0 : 130.240.19.2
  }
  DomainName : XXX.taglab.com
}
&gt; set State:/Network/Service/FEAFA7DE-8BE5-49ED-A115-A3E113E8753B/DNS
  Permission denied
</code>

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:

<code>
banana&#36; echo "list State:/Network/Service/&#91;^/&#93;+/DNS" | scutil
  subKey &#91;0&#93; = State:/Network/Service/FEAFA7DE-8BE5-49ED-A115-A3E113E8753B/DNS


banana&#36; echo "list State:/Network/Service/&#91;^/&#93;+/DNS" | scutil | awk '{print &#36;4}' | while read f; do echo "show &#36;f" | scutil ; done
&lt;dictionary&gt; {
  ServerAddresses : &lt;array&gt; {
    0 : 192.168.XXX.XXX
  }
  DomainName : XXX.taglab.com
}
</code>

Making a script that then changes the DNS settings on the fly is elementary shell scripting – job done.

No Comments

  • As of 10.5, host and dig still use /etc/resolv.conf

    Very annoying if trying to diagnose DNS issues on a VPN

    scott morabito
    Tech Superpowers, Boston

Leave a reply

You must be logged in to post a comment.