1

I am on ubuntu 18.04 server. I need to run a script that updates an IP address on CloudFlare (kind of DynDNS script). In previous versions I could do this with a DHCLIENT exit hooks for the interface enp1s0.

However, systemd now uses their own build-in DHCP client. How can I write a systemd unit that executes my bash script as soon as a new IP address is provided to the DCHP client?

Systemd is managing the interface enp1s0:

#sudo  systemctl status systemd-networkd
● systemd-networkd.service - Network Service
   Loaded: loaded (/lib/systemd/system/systemd-networkd.service; enabled-runtime; vendor preset: enabled)
   Active: active (running) since Tue 2018-09-18 01:54:16 +08; 10h ago
     Docs: man:systemd-networkd.service(8)
 Main PID: 878 (systemd-network)
   Status: "Processing requests..."
    Tasks: 1 (limit: 4915)
   CGroup: /system.slice/systemd-networkd.service
           └─878 /lib/systemd/systemd-networkd

Sep 18 01:54:27 xxx systemd-networkd[878]: enp1s0: Configured
3

I don't know of any systemd solution, but you can monitor changes to interfaces efficiently with ip monitor and pipe the output into a script that looks for the changes that interest you. For example, if I do

$ ip monitor address dev enp3s0

then add a new alias address to interface enp3s0 I get the line

2: enp3s0    inet 192.168.77.77/24 brd 192.168.77.255 scope global enp3s0:1
       valid_lft forever preferred_lft forever

I presume you would see something similar for dhcp changes.

If you prefer, you can write a C program to do the same, see this ipevent.c.

| improve this answer | |
1

Many packages do not work with systemd-networkd ... yet. (see bug Report on LaunchPad)

For now, ISC DHCP client (dhclient) still reign supreme, particularly in custom DHCP-Option needed by many ISP's DHCP servers (I'm looking at you, Juniper Networks), as well as supporting OS-scripting.

So, head over to /etc/systemd/network to edit the config file that deals with dynamic IP addressing and disable systemd's DHCP in the following:

[Match]
Name=eth1
[Network]
# Using ISC DHCP client (dhclient) instead of systemd-networkd
# Better support of DHCP-Options and OS-specific script supports
DHCP=no

Then ensure the following for ISC DHCP client (dhclient) in /etc/network/interfaces:

auto eth0
iface eth0 inet dhcp

And for /etc/dhcp/dhclient.conf:

send host-name "Wireless_Broadband_Router";
send domain-name "home";
request subnet-mask, broadcast-address, time-offset, routers,
    domain-name, domain-name-servers, time-servers, log-servers,
    default-ip-ttl, dhcp-requested-address, dhcp-lease-time,
    dhcp-server-identifier,dhcp-parameter-request-list,
    vendor-class-identifier,dhcp-client-identifier,
    www-server,
    dhcp6.name-servers, dhcp6.domain-search, dhcp6.fqdn, 
    dhcp6.sntp-servers,
    interface-mtu,
    ntp-servers;

Last step is to have systemd fire up the ISC DHCP client as a daemon. Create a file in /etc/systemd/system/dhclient@.service.

# cat /etc/systemd/system/dhclient@.service 
[Unit]
Description=dhclient on %I
Wants=network.target
Before=network.target
BindsTo=sys-subsystem-net-devices-%i.device
After=sys-subsystem-net-devices-%i.device

[Service]
# ExecStart=/sbin/dhclient -4 -q %I
ExecStart=/sbin/dhclient -4 -v -pf /run/dhclient.%I.pid -lf /var/lib/dhcp/dhclient.%I.leases %I

[Install]
WantedBy=multi-user.target

And make ISC DHCP client available to systemd daemon by executing from a shell:

sudo systemctl daemon-reload   #makes the dhclient@.service available
sudo systemctl enable dhclient@eth0.service
sudo systemctl start dhclient@eth0.service
| improve this answer | |
1

Take a look at networkd-dispatcher. It is a daemon which runs scripts from /etc/networkd-dispatcher/*.d on various network events. Details about the events are passed to the scripts via environment variables.

| improve this answer | |
0

networkd-dispatcher

Can be used for an even more granular control of when you want your script to execute.

Depending on what state you want state your script to execute, you'll have to decide which folder to put your script inside.

Example:

We'll be using the folder routable.d, which is when the link has carrier and routable address configured.

Copy a script file into /usr/lib/networkd-dispatcher/routable.d

cp path/to/my/ipchange_script.sh /usr/lib/networkd-dispatcher/routable.d

ipchange_script.sh

#!/bin/bash


if [[ $IFACE == "eth0" && $AdministrativeState == "configured" ]]; then
    echo "IP Address has changed to: $ADDR"  >> /tmp/iplog.txt
fi

exit 0

Refresh your IP (dhclient -r eth0 && dhclient -v eth0) then to see the output of your script or to see if your script had any errors you can check with the command:

sudo service networkd-dispatcher status

P.S. I have searched for months on and off and there's nowhere with examples on how to work with networkd-dispatcher. I was just able to figure it out today. Enjoy!

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.