Run a SystemD service on IP Address Change

Ever needed to run a command anytime an IP address changes? IP addresses don’t change often on IPv4 networks, but IPv6 changes things and makes addresses more dynamic, so the ability to run a command every time your machine gets a new IP address can be very useful on dual stack networks. Here’s how I accomplished this with a simple SystemD service and target.

# /etc/systemd/system/ip-change-mon.service

[Unit]
Description=IP Change Monitor
Wants=network.target
After=network-online.target

[Service]
ExecStart=:/bin/bash -c "ip mon addr | sed -nu -r
\'s/.*[[:digit:]]+:[[:space:]]+([^[:space:]]+).*/\\1/p\' | while read iface; do
systemctl restart ip-changed@${iface}.target; done"

[Install]
WantedBy=multi-user.target default.target

That command is a little cryptic because of the layers of escaping to make it work well with systemd. Written as a bash script it’d look something like this:

#/bin/bash

ip mon addr | sed -nu -r 's/.*[[:digit:]]+:[[:space:]]+([^[:space:]]+).*/\1/p' | while read iface; do
  systemctl restart ip-changed@${iface}.target
done

ip monitor address is a the command watching for ip address changes. If you run this command by itself you get output that looks like this:

1: eth0    inet 192.168.10.15/24 scope global secondary eth0
       valid_lft forever preferred_lft forever
Deleted 7: eth0    inet 192.168.10.15/24 scope global secondary eth0
       valid_lft forever preferred_lft forever

The sed command strips out everything except the interface name. Then read loops over each event and restarts a target for that interface.

The target file is very simple and exists to be used by other units.

# /etc/systemd/system/ip-changed@.target 

[Unit]
Description=IP Address changed on %i

Now just enable and start the monitor:

# systemctl enable --now ip-change-mon.service

Now in any systemd unit you want to run when the IP changes simply add these options to the [Unit] section.

PartOf=ip-changed@eth0.target
Before=ip-changed@eth0.target

Whenever ip-change-mon detects and ip address change it will restart the target, and because the unit you want to run is PartOf that target, your unit will restart too.