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
If you are running Mac OS 10.5 then check out LocationChanger. This project was the basis for the dynamic printer configuration introduced in version 0036 of PrinterSetup.