Apple - How to stop InternetSharing overwriting /etc/bootpd.plist

Source of the problem

By studying the processes spawned by InternetSharing (with the help of opensnoop and debugging shell scripts) I finally build a way to circumvent this systematic and stupid overwriting of /etc/bootpd.plist.

InternetSharing creates a minimal /etc/bootpd.plist and then spawns 2 processes:

/usr/libexec/bootpd
/usr/libexec/natpmpd

Solution

I replaced the original bootpd by a simple shell script in charge of putting my source of /etc/bootpd.plist in place before firing the original bootpd code. Of course most of these commands have to be ran as root.

/usr/bin/sudo -s    
cd /usr/libexec

# make a backup copy of the original binary bootpd
mv bootpd bootpd.orig

# create the shell script which will first install the wanted
# bootpd.plist and then fire the original bootpd with the
# correctly quoted original list of arguments "$@"
cat >bootpd <<eof
#!/bin/sh
cp /etc/bootpd.plist.src /etc/bootpd.plist
exec /usr/libexec/bootpd.orig "$@"
eof

# make this shell script executable
chmod 755 bootpd

cd /etc

# create the "source" bootpd.plist.src which will be copied every
# time by the above shell script and will cancel the copy made by
# "InternetSharing"
cat >bootpd.plist.src <<eof
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>allow</key>
    <array>
            <string>00:00:00:00:00:00</string>
            <string>...
    </array>
    <key>deny</key>
    <array>
            <string>...
    </array>
    <key>Subnets</key>
    <array>
            <dict>
                    <key>_creator</key>
                    <string>dan</string>
                    <key>allocate</key>
                    <true/>
                    <key>dhcp_router</key>
                    <string>10.0.2.1</string>
                    <key>lease_max</key>
                    <integer>86400</integer>
                    <key>lease_min</key>
                    <integer>86400</integer>
                    <key>name</key>
                    <string>10.0.2/24</string>
                    <key>net_address</key>
                    <string>10.0.2.0</string>
                    <key>net_mask</key>
                    <string>255.255.255.0</string>
                    <key>net_range</key>
                    <array>
                            <string>10.0.2.2</string>
                            <string>10.0.2.31</string>
                    </array>
            </dict>
    </array>
    <key>bootp_enabled</key>
    <false/>
    <key>detect_other_dhcp_server</key>
    <true/>
    <key>dhcp_enabled</key>
    <array>
            <string>en1</string>
    </array>
    <key>use_server_config_for_dhcp_options</key>
    <false/>
</dict>
</plist>
eof

The 2 arrays allow and deny let me define exactly which MAC addresses I will accept within my shared network and which one I will banish.

This protection is far from bullet proof, but is better than the total lack of protection provided by InternetSharing on a WEP Fi-fi network :).


Compatibility with OS upgrades

To avoid any trouble with any OS upgrade which might fix /usr/libexec/bootpd, here is the shell script I run before any OS upgrade:

/usr/bin/sudo -s    
cd /usr/libexec

# reset into place the backup copy of the original binary bootpd
mv bootpd.orig bootpd

# go back to a safe working uid
exit

Compatibility with OS versions

This shell script is working on:

  • Lion
  • Mountain Lion
  • Mavericks
  • Yosemite

Attack survey

With the option -v passed to bootpd, I have a logging of MAC addresses which attempted to request an IP address but were rejected.

To pass this option -v to bootpd I inserted it in my bootpd wrapper:

#!/bin/sh
cp /etc/bootpd.plist.src /etc/bootpd.plist
exec /usr/libexec/bootpd.orig -v "$@"