blog advertising is good for you


blog advertising is good for you
User login

Hacking Kicker and configd to Run Your Scripts

Brian asks:

Question

I use dnsmasq running on my Intel Mac Mini to provide DNS and DHCP services to my home network. My internet connection went down briefly the other day, requiring a router reboot, and I discovered that dnsmasq does not handle losing its network connection well at all. I had to manually stop and restart the dnsmasq daemon before I could get any sort of DNS response. So I got to thinking, is there a proper way to set up a launchd or other sort of task that gets executed when an ethernet interface connects? Then I could cycle dnsmasq on and off automatically if (when) this happens again.

Answer

Mac OS X includes a System Configuration framework that executes a set of scripts every time various network properties change. This is handy for a wide variety of reasons which, I feel, will become apparent as I discuss how this works.

System Configuration

The System Configuration framework allows Mac OS X to dynamically update the various settings in the system in response to changes in software or hardware status. Lots of words for: event triggers for changes. When you remove your ethernet cable, the System Configuration getup will disable the interface, change your routes, change your DNS settings (if needed) to the new default route, and then tell everyone it made some changes so that others can make more changes.

The central process for this is configd. It’s the tie-in point for the Kernel Event Monitor and all of the userland processes that make this work. It has a configuration datastore that’s peek/pokable via the scutil utility (System Configuration Utility). By poking around in here, we can learn what keys can cause triggers to fire and then use those keys to hack around a little.

So, whip out Terminal and root thyself, then follow along:

# scutil
> list
  subKey [0] = DirectoryService:PID
  subKey [1] = Plugin:IPConfiguration
  subKey [2] = Setup:
  subKey [3] = Setup:/
  subKey [4] = Setup:/HostNames
  subKey [5] = Setup:/Network/Global/IPv4
  subKey [6] = Setup:/Network/HostNames
  subKey [7] = Setup:/Network/Interface/en0/AirPort
  subKey [8] = Setup:/Network/Interface/en1/AirPort
  subKey [9] = Setup:/Network/Service/0
  subKey [10] = Setup:/Network/Service/0/AirPort
  subKey [11] = Setup:/Network/Service/0/Ethernet
  subKey [12] = Setup:/Network/Service/0/IPv4
  subKey [13] = Setup:/Network/Service/0/IPv6
  subKey [14] = Setup:/Network/Service/0/Interface
  subKey [15] = Setup:/Network/Service/0/Proxies
...
>

Thus the list is spawned. Within this list you’ll note some familiar items, like DNS and IPv4 and so on. These are where the system stores its real network settings. Have you ever noticed how changes to ifconfig don’t stick very long? That’s because these settings will over-write them on network change events. They’re configured in the Network preference pane, normally, but some can be changed here. That’s another article. Here, take note of “State:/Network/Interface/en0/Link” as an option. This key flips when the link dies. Now we need a place to put this.

AirPort users use en1 to do things when you join a network.

It just so happens that Apple has a list of events that run on network change, too. They’re kept in the /System/Library/SystemConfiguration/Kicker.bundle/Contents/Resources/Kicker.xml file in the following format:

        <dict>
                <key>execCommand</key>
                <string>$BUNDLE/Contents/Resources/enable-network</string>
                <key>execUID</key>
                <integer>0</integer>
                <key>keys</key>
                <array>
                        <string>State:/Network/Global/IPv4</string>
                </array>
                <key>name</key>
                <string>enable-network</string>
        </dict>

Oh now that’s tempting. We can run a command whenever the interface changes, and that key there looks strangely like the key we found earlier. Well, two and two is four, for most cases of two, so here’s something fun:

        <dict>
                <key>execCommand</key>
                <string>/path/to/your/special/script.sh</string>
                <key>execUID</key>
                <integer>0</integer>
                <key>keys</key>
                <array>
                        <string>State:/Network/Interface/en0/Link</string>
                </array>
                <key>name</key>
                <string>fix-dns-and-dhcp-or-something-like-that</string>
        </dict>

Now you need to kill configd and restart it for the change to take effect.

$ sudo killall configd; sudo configd

Now, open Console and view the system.log file and pull the cable. You should see something like:

May 19 00:52:50 HeatSink configd[7826]: executing /path/to/your/special/script.sh

Backup this file. Upgrades, updates, and other random acts of file replacement will break this until Apple opens this up for system administrators to hack into. (Developers already have ways to watch this, but that’s coding and not general hackery.)

Further Reading

SambaX
Mac OS X Routing

Average rating
(0 votes)
About Adam Knight
Adam Knight's picture

Author Biography

Adam Knight is one of the founders of Mac Geekery and is a geek at heart. Programmer by day, hacker by night, his daily life revolves around the Macintosh platform, which he has been a user and programmer for since the early days of System 7 when his LCII replaced his Apple //c.

In-between tech jobs, he’s managed to learn the basics of any web hacker: PHP, MySQL, Perl, Apache, Linux, *BSD, and the intricacies of ./configure —prefix=~/bombshelter/. Today, codepoet is concentrating on blogging again, writing some software for the Mac by himself (including Notae) and for his company (such as Switchblade) and has a few other toys coming out soon.

Bug him over AIM or email [link fixed].

Post new comment
The content of this field is kept private and will not be shown publicly.
12 + 1 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.