This article is about bringing up various facilities using Network Manager as one changes networks. We've already covered how to bring down systemd-timesyncd and samba. Bringing those and other things up is the subject of this article.
As usual, the script, 50ifupdown
, lives in /etc/NetworkManager/dispatcher.d
.
I started this before NetworkManager provided the pre-down.d
and pre-up.d
directories, and code to support them. Refactoring this script to take advantage of those would probably be a good idea, and is left to the student.
There are three possible states in which NetworkManager will come up, at least on my laptops. They are:
-
WiFi and at home. We are at home on a home network. Set up our home services.
-
WiFi and not at home. We are on a foreign network. Shut down (or don't bring up) any home services.
-
Ethernet. In that case assume we are on a foreign network. Shut down (or don't bring up) any home services.
The home services consist of Samba, Syncthing, our home Debian package proxy server, a DNS server, bind9, and a time server. Also, there are two firewalls defined, one for home and one for foreign networks.
The home network's Debian package proxy is indicated by the file 02proxy
, which normally lives in /etc/apt/apt.conf.d/
. However, I make it a file in /etc/apt/
. When at home, it is active, via a symlink in /etc/apt/apt.conf.d/
. You will see how we use that in lines 113-116, 131-134, and 169-172.
We detect the state for which we are setting up by examining our environment when the script runs.
Another problem is that I am lazy (in Larry Wall's sense). I want one script to run on several laptops. So I have to detect the wired and wireless interfaces at run time. This is what the variables WIREDUP, WIREDDOWN, WIRELESSUP, and WIRELESSDOWN are for. Those are set up in lines 41-45.
Another aspect of laziness is that I want the script to run successfully whether a given service is present on the laptop or not. So we test to be sure that one is present before we do anything with it.
We get the action NetworkManager is executing by examining our command line, and preserve it in the variable ACTION.
Setting up the home ESSIDs in an array might be more elegant than the current setup. We will leave that as an exercise for the student.
Most of the script is a big case statement based on the action to be taken. The two most significant are 'up' and 'down'. Within those two, we determine the network we are on, and act accordingly. One thing we don't act on is VPNs, since I don't use one.
We provide a log for debugging. Also, NetworkManager logs to var/log/syslog
, so you should watch both of those when debugging this script.
#!/bin/bash
# Custom actions for NetworkManager. This should run *after*
# 01ifupdown, so assume that's all been done. See "man NetworkManager"
# for the gory details.
# Virtual machines use bind. So we need it up regardless of the
# network. Bind comes up during normal startup. But since NM isn't
# running yet, we don't have a network. So bind comes up only
# listening to the loopback device, which doesn't help other
# computers. So we restart it.
# Emacs (and likely other editors) can create backup files, indicated
# by appending a tilde (~) to the file name. We don't want those to
# execute, but NM will blindly execute them. So we silently refuse to
# run if the last character in the name of the file is a tilde.
/bin/echo "${0}" | grep --quiet ~$ && exit 0
# Fake ifupdown environment
export IFACE="$1"
export LOGICAL="$1"
export ADDRFAM="NetworkManager"
export METHOD="NetworkManager"
export VERBOSITY="0"
ACTION=$2
ESSID=$(/sbin/iwgetid "${IFACE}" --raw)
# Our home samba mount point.
smbMount='/home/charles/samba'
# Specify our interfaces. Look at any ethx or wlanx. Debian on the
# T520 used to come up with wlan1, not wlan0. Go figure.
# We also support "Predictable Network Interface Names". See
# https://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames/
# and the code, at
# https://github.com/systemd/systemd/blob/master/src/udev/udev-builtin-net_id.c#L20
# Dragon: enp2s8, iorich, orca: enp0s25, jhegaala: eth0, personal
# hotspot: enp0s29v1v1c4i2
WIREDUP=$(ifconfig | grep -E '^e(th|n).*RUNNING' | cut -f1 -d:)
WIREDDOWN=$(ifconfig | grep -E '^e(th|n)' | cut -f1 -d:)
# dragon: wlp2s2, iorich, orca: wls3, jhegaala: wlp3s0
WIRELESSUP=$(ifconfig | grep -E '^wl(an)?.*RUNNING' | cut -f1 -d:)
WIRELESSDOWN=$(ifconfig | grep -E '^wl(an)?' | cut -f1 -d:)
LOG=/var/log/NetworkManager
HOMEESSID1=CurleyNet314159 # One home essid
HOMEESSID2=Curleynet2 # Another home essid
HOMEESSID3=Curleynet5 # Yet another home essid
# HOMEESSID=curleynet # Our home essid
FOREIGNFIREWALL='/etc/firewalls/shorewall.foreign'
HOMEFIREWALL='/etc/firewalls/shorewall.home'
# per https://www.theregister.co.uk/2019/06/17/linux_tcp_sack_kernel_crash/
echo 0 > /proc/sys/net/ipv4/tcp_sack
# If we have syncthing, set the name of the service to run.
if [ -x /usr/bin/syncthing ] ; then
SYNCTHINGSERVICE=syncthing@charles
fi
{ /bin/echo >> $LOG 2>&1
/bin/date
/bin/echo \$@ arguments: "$@"
/bin/echo ESSID is: "${ESSID}"
} >> $LOG 2>&1
if [ "$ACTION" = 'connectivity-change' ] ; then
echo Action is "${ACTION}". >> "${LOG}" 2>&1
exit 0
fi
# Bail if it is not an interface we are interested in, like one for
# the virtual machines. Or if it's an interface that's already shut
# down.
if [ "${IFACE}" != "$WIREDUP" ] \
&& [ "${IFACE}" != "$WIRELESSUP" ] \
&& [ "${IFACE}" != "$WIREDDOWN" ] \
&& [ "${IFACE}" != "$WIRELESSDOWN" ]
then
{ echo "${IFACE}" is not an interface of interest
ifconfig "${IFACE}"
route -n
} >> "${LOG}" 2>&1
exit 0
fi
case $ACTION in
'up' )
# /bin/echo Running UP code. IFACE is "${IFACE}" >> "${LOG}" 2>&1
if [ "${IFACE}" = "$WIREDUP" ] ; then
/bin/echo "Wired Interface $WIREDUP." >> "${LOG}" 2>&1
if [ -x /etc/init.d/bind9 ] ; then
/etc/init.d/bind9 restart >> "${LOG}" 2>&1
fi
# Use an appropriate firewall
echo $FOREIGNFIREWALL start >> "${LOG}" 2>&1
$FOREIGNFIREWALL start >> "${LOG}" 2>&1
# We can't use our home repo cache
if [ -e /etc/apt/apt.conf.d/02proxy ] ; then
rm /etc/apt/apt.conf.d/02proxy
fi
else
/bin/echo "Wireless Interface." >> "${LOG}" 2>&1
if [ "${ESSID}" = "$HOMEESSID1" ] ||
[ "${ESSID}" = "$HOMEESSID2" ] ||
[ "${ESSID}" = "$HOMEESSID3" ]; then
/bin/echo "Home network" >> "${LOG}" 2>&1
if [ -x /etc/init.d/bind9 ] ; then
/etc/init.d/bind9 restart >> "${LOG}" 2>&1
fi
# Use our home repo cache
if [ ! -e /etc/apt/apt.conf.d/02proxy ] ; then
ln -s /etc/apt/02proxy /etc/apt/apt.conf.d/02proxy ;
fi
echo $HOMEFIREWALL start >> "${LOG}" 2>&1
$HOMEFIREWALL start >> "${LOG}" 2>&1
# Syncthing only runs on the home wireless network
if [ -x /usr/bin/syncthing ] ; then
if [ "$(systemctl status ${SYNCTHINGSERVICE} \
| grep 'Active: active' >> /dev/null ; echo $?)" \
= '0' ] ; then
echo Syncthing is already running. >> "${LOG}" 2>&1
else
# Start it up.
echo Starting Syncthing. >> "${LOG}" 2>&1
systemctl start ${SYNCTHINGSERVICE} >> "${LOG}" 2>&1
fi
fi
if command -v mount.cifs >> /dev/null ; then
echo Mounting the Samba mount... >> "${LOG}" 2>&1
mount $smbMount >> "${LOG}" 2>&1
fi
else
/bin/echo "Foreign network" >> "${LOG}" 2>&1
if [ -x /etc/init.d/bind9 ] ; then
/etc/init.d/bind9 restart >> "${LOG}" 2>&1
fi
# Use an appropriate firewall
echo $FOREIGNFIREWALL start >> "${LOG}" 2>&1
$FOREIGNFIREWALL start >> "${LOG}" 2>&1
# We can't use our home repo cache
if [ -e /etc/apt/apt.conf.d/02proxy ] ; then
rm /etc/apt/apt.conf.d/02proxy
fi
fi
fi
ifconfig "${IFACE}" >> "${LOG}" 2>&1
route -n >> "${LOG}" 2>&1
;;
'down' )
/bin/echo "Lost network" >> "${LOG}" 2>&1
if [ -x /etc/init.d/bind9 ] ; then
/etc/init.d/bind9 restart >> "${LOG}" 2>&1
fi
if [ "${IFACE}" = "$WIRELESSDOWN" ] ; then
case $HOSTNAME in
'dragon' )
DEVICE=ipw2200;
;;
'jhegaala' )
DEVICE=rtl8192ce;
;;
'orca' | 'iorich')
DEVICE=iwl4965;
;;
* )
DEVICE='Bad device! Please fix!' >> "${LOG}" 2>&1
esac
echo Reloading device "${DEVICE}". >> "${LOG}" 2>&1
rmmod "${DEVICE}" && modprobe "${DEVICE}" >> "${LOG}" 2>&1
# reload flakey proprietary bits!
# rmmod ipw2200 && modprobe ipw2200 # R51 dragon
# rmmod rtl8192ce && modprobe rtl8192ce # t520: jhegaala
# rmmod iwl4965 && modprobe iwl4965 # t61: orca, iorich
fi
;;
'dhcp4-change' )
if [ "${ESSID}" = "$HOMEESSID1" ] ||
[ "${ESSID}" = "$HOMEESSID2" ] ||
[ "${ESSID}" = "$HOMEESSID3" ]; then
echo $HOMEFIREWALL start >> "${LOG}" 2>&1
$HOMEFIREWALL start >> "${LOG}" 2>&1
else
# Use an appropriate firewall
echo $FOREIGNFIREWALL start >> "${LOG}" 2>&1
$FOREIGNFIREWALL start >> "${LOG}" 2>&1
fi
;;
# Events we ignore.
'pre-up' | 'dhcp6-change' | 'vpn-up' | 'vpn-down' \
| 'hostname' | 'connectivity-change' | 'post-down' )
;;
* )
/bin/echo "!! Bad Input Action!!" >> "${LOG}" 2>&1
;;
esac
exit 0