Performing Custom Actions when NetworkManager Goes On/Offline

658
NetworkManager is used by many Linux distributions to allow the machine to connect to wired and wireless networks automatically. NetworkManager can remember the credentials you need in order to authenticate with your wifi networks and can get online automatically when certain networks are detected.

It is often the case that you want to have different network configurations depending on if you are at home or not. For example, you might want to allow some services on a laptop to be accessed only if you are connected to your local wifi access point over WPA2. You might also like to have your laptop automatically mount a bunch of NFS filesystems when you connect to your home wifi access point.

When NetworkManager brings up a network connection it runs the scripts that are stored in /etc/NetworkManager/dispatcher.d starting with the lowest numerical file name prefix and working to the highest. For example, 00-netreport runs before 05-netfs on a Fedora machine. For this article I’ll use the 99-custom-scripts file to ensure my customizations run after the normal system scripts.

NetworkManager calls these scripts with the interface name as the first argument and the string “up” or “down” as the second argument. The first thing the 99-custom-scripts file does is to check if the wireless interface is being acted on and if so it determines the name and key of the wifi network being connected too. Based on the name and/or key of the wifi network, the iptables and NFS mounts are modified on bringing the interface up and down.

The first part of the script is shown below. The wireless interface on this laptop is eth1 which is declared at the top of the file. If NetworkManager is acting on $IFACE = eth1 then the script determines both the network name and the key that was used to connect. Using the later as a double check is a great additional precaution in case an attacker decides to offer an unencrypted network which happens to have the name your scripts expect for your home network. Paranoia is a virtue when it comes to security.

For those not too familiar with sed, the -r option turns on extended regular expressions, the -n option suppresses the normal printing of each line. A walk through of the sed script used to find the KEY is that it looks for a line containing Encryption, ignoring all non matching lines. Because of the -n option, lines that do not contain the string “Encryption” are silently ignored. If a line does contain “Encryption” then everything before the first colon is thrown away, and the hex key is extracted into a regular expression capture. The substitution will replace the entire line with just the hex key. The sed ‘p’ command is used to print the line (which is just the key now), and ‘q’ is used to quit immediately.

#!/bin/bash

IFACE="eth1"

if [ "x$1" = "x$IFACE" ]; then
# Figure out the wifi SSID
SSID=$(/sbin/iwconfig $IFACE | sed -r -n '/SSID/{s/.*SSID:"([^"]+)".*/1/g;p;q}' )
KEY=$(/sbin/iwconfig $IFACE | sed -r -n '/Encryption/{s/.*:([0-9A-F-]+).*/1/g;p;q}' )

The rest of the script is shown below. I choose to bring up and down network mounts based on the network name rather than the wifi key of the network. I would rather put a check to enforce that the wifi key is correct for the network name in the 99-custom-scripts than scatter the wifi key into the /etc/fstab file.

The first check is on the network name, for a more secure configuration, the KEY should also be checked to see that it is correct. If the network is being brought up then special iptables rules are loaded and they get reset back to the system defaults on log out. The fstab and awk line looks for a special marker for a mount “mount-on-wifi-net” which can appear in a comment at the end of the line. If mount-on-wifi-net is followed by the network name being connected too then the filesystem mentioned is mounted. The unmount line contains a -l to ensure that the script does not block during logout.

case "$SSID" in
"himitsu")
logger "starting wifi connection to $SSID"
if [ "$2" = "up" ]; then
iptables-restore < /etc/sysconfig/iptables.home

cat /etc/fstab | awk
'{ if (match($0,"mount-on-wifi-net.*" net)) { system( op " " $2 ) }}' op=mount net=$SSID

else
tac /etc/fstab | awk
'{ if (match($0,"mount-on-wifi-net.*" net)) { system( op " " $2 ) }}' op="umount -l" net=$SSID
iptables-restore < /etc/sysconfig/iptables

fi
;;
esac
fi

Notice that the tac command is used during unmount. The tac works like the cat command, except that the lines are printed from last to first. This allows you to specify NFS mounts that depend on each other, for example, /usr and /usr/local, as long as /usr appears before /usr/local in /etc/fstab it will be mounted before /usr/local and unmounted after /usr/local by virtue of the tac command.

An NFS share that would be automatically mounted and unmounted can then be described by adding it to /etc/fstab with the noauto filesystem option to prevent mount attempts at system boot.

foo:/bar  /bar nfs  defaults,noauto 0 0 # mount-on-wifi-net=himitsu

There are a few issues with the above scripts. If you have two wifi network names where one is a prefix of the other, for example foo and foobar, then mounts meant only for foobar will still have an attempt made when connecting to foo. Using comments in /etc/fstab also tends to make the lines for auto mounts quite long.

Teaching NetworkManager how you want to change your network presence depending on which wifi access point is used can make using a laptop much more convenient. Especially having your network shares automatically available when on trusted wifi access points takes a bit of the hassle out of frequently changing wifi access points with a laptop.