15

Before marking as a duplicate: this is not about dynamic DNS or similar things.

I know how to run a script every time my networks goes up; it is a simple matter of adding a script in the directory /etc/NetworkManager/dispatcher.d like this one:

#!/bin/bash

IF=$1
STATUS=$2

case "$2" in
        up)
        logger -s "NM Script up $IF triggered"
        su rmano -c /home/romano/bin/myscript 
        ;;
        down)
        logger -s "NM Script down $IF triggered"
        ;;
        *)
        ;;
esac

In my case, myscript is a very simple ifconfig -a > ~/Dropbox/myifconfig.txt --- I use it because I need to know my local IP from everywhere in the University, and it will change often.

So far so good, the system works ok. But unfortunately the DHCP here is configured so that the IP sometime is changed without a down/up of the interface. In that case the script is (logically) not run, and the file is not updated.

I cannot use a DynDNS approach because the change is in the local IP, not the externally visible one.

I could poll, by simply putting the script in cron and execute it every minute or write a slightly more complex one (...if the IP is changed write the file otherwise do nothing) and putting it again as a background task, but it is not elegant. So the question is:

Is there any way to trigger a script when my local IP changes?

UPDATE 1

I tried to put a script in /etc/dhcp/dhclient-enter-hooks.d/ , based on the existing /etc/dhcp/dhclient-enter-hooks.d/resolvconf, but it will not be triggered. I suspect (confirmation needed) that NM (network manager) is doing the dhcp negotiation by itself, without calling the dhcp command...

2
  • 1
    it looks like it should be possible via a dhclient-enter-hooks.d script... but I've never tried it! The existing /etc/dhcp/dhclient-enter-hooks.d/resolvconf script might be helpful in terms of syntax and what signals to look for ("$reason" == "BOUND" maybe?) Mar 20, 2014 at 16:18
  • @steeldriver it seems that the script is not triggered. I suspect that NM takes care of DHCP handling... will look around. Thanks anyway.
    – Rmano
    Mar 20, 2014 at 17:07

5 Answers 5

12
+50

According to the man page for NetworkManager-dispatcher, one of the events is

dhcp4-change

  The DHCPv4 lease has changed (renewed, rebound, etc).

I think you can simply change

up) 

to

dhcp4-change|up)   
4
  • It (sort-of) works. The script is triggered even a bit too much; even a renew without changes in IP will trigger it. I imagine I will have to do a bit more bash scripting. Moral: read all the content of the man page!
    – Rmano
    Mar 26, 2014 at 15:53
  • Will wait a bit (you never know...) and then assign the bounty. Thanks!
    – Rmano
    Mar 26, 2014 at 15:54
  • in my experience on 14.04, I can only ever receive events for up and down that way. the other events never trigger scripts in update.d
    – init_js
    Sep 5, 2016 at 10:59
  • In recent versions of NetworkManager, there's also connectivity-change which can be used as the trigger for change => connectivity-change) in the case.
    – Samveen
    Nov 30, 2022 at 3:34
4

I am providing a script that listens on dbus signals, which will allow you to react faster than if you were to poll for changes on your current network configuration. It helps on systems where scripts /etc/ are not executed when you would like them to (like on my 14.04 system).

my enter/exit hooks.d don't work

NetworkManager starts dhclient with the flag -sf /usr/lib/NetworkManager/nm-dhcp-client.action which seems to override the normal enter/exit hook behaviour. The default behavior with dhclient is to call scripts in /etc/dhcp/dhclient-{enter,exit}-hooks.d. Those don't get called at all on my system.

my NetworkManager dispatcher.d scripts don't work either

NM does however invoke a different set of scripts, in /etc/NetworkManager/dispatcher.d, to inform of various events. The NetworkManager-dispatcher (8) man page defines dhcp4-change and dhcp6-change actions which would seem to do exactly what you want. Despite what the manpage says, on my system at least, only up and down actions get invoked. I can't get those scripts to fire on anything else. So this is not a great avenue to monitor IP changes either.

so, snoop directly on dbus signals emitted by NM

nm-dhcp-client.action (source), from the command line, simply converts all the environment variables set by dhclient into a dbus signal. Those environment variables are defined in man dhclient-script (8). One of particular interest is $new_ip_address. What you could do, as suggested by @Bernhard, is to monitor the signal and act accordingly based on its contents.

Here is a program that will snoop all event data signalled by that binary:

#!/bin/bash -e

#
# This script listens for the org.freedesktop.nm_dhcp_client signal.
# The signal is emitted every time dhclient-script would execute.
# It has the same contents as the environment passed to
# dhclient-script (8). Refer to manpage for variables of interest.
#

# "org.freedesktop.nm_dhcp_client" is an undocumented signal name,
# as far as I could tell. it is emitted by nm-dhcp-client.action,
# which is from the NetworkManager package source code.
# 

# detail: todo cleanup subprocess on exit. if the parent exits, 
#       the subprocess will linger until it tries to print
#       at which point it will get SIGPIPE and clean itself.
#       trap on bash's EXIT signal to do proper cleanup.


mkfifo /tmp/monitor-nm-change

(
    dbus-monitor --system "type='signal',interface='org.freedesktop.nm_dhcp_client'"
) > /tmp/monitor-nm-change &

exec </tmp/monitor-nm-change
rm /tmp/monitor-nm-change

while read EVENT; do
    #change this condition to the event you're interested in
    if echo "$EVENT" | grep -q BOUND6; then
        # do something interesting
        echo "current ipv6 addresses:"
        ip addr show | grep inet6
    fi
done

The output of dbus-monitor is not straightforward to parse in scripts. Perhaps it is easier to trigger on the presence of a certain keyword(s), e.g. new_ip_address, and from there use different tools to get the information that changed (e.g. ip or ifconfig).

# example output data from dbus-monitor for that signal
...
dict entry(
string "new_routers"
variant             array of bytes "192.168.2.11"
)
dict entry(
string "new_subnet_mask"
variant             array of bytes "255.255.255.0"
)
dict entry(
string "new_network_number"
variant             array of bytes "192.168.2.0"
)
dict entry(
string "new_ip_address"
variant             array of bytes "192.168.2.4"
)
dict entry(
string "pid"
variant             array of bytes "12114"
)
dict entry(
string "reason"
variant             array of bytes "REBOOT"
)
dict entry(
string "interface"
variant             array of bytes "eth0"
)
...
1
  • Thanks a lot! Fortunately (for me) I am back at home where I can control my DHCP server... but I will give it a shot because learning about DBus is one of the thing in my queue, and yours is a wonderful start.
    – Rmano
    Sep 5, 2016 at 19:57
3

Polling approach with python script. Basic idea is to continuously parse output of ip -4 -o add show <INTERFACE> and compare current result with previous iteration

#!/usr/bin/env python3
import subprocess
import sys

def get_ip():
    # Simple function that parses output
    # of ip command and returns interface ip
    # replace wlan7 with your interface
    command = 'ip -4 -o addr show wlan7'.split()
    ip = None
    try:
        ip = subprocess.check_output(command).decode().split()[3]
    except IndexError:
        return
    finally:
        if ip:
           return ip

def main():
    # do while loop
    # Exits only when change occurs
    address = get_ip()
    while address == get_ip():
          address = get_ip()

    # Trigger script once we're out of loop
    subprocess.call(['zenity','--info','--text','IP CHANGED'])


if __name__ == '__main__':
    # use while loop if yout want this script to run
    # continuously
    while True:
        try:
            main()
        except KeyboardInterrupt:
            sys.exit()
1

Although NetworkManager is using dhclient, it provides its own binaries as a replacement for the dhclient-scripts. (For reference: you can find the NM binary at /usr/lib/NetworkManager/nm-dhcp-client.action).

Maybe you could take a different approach: NM is issuing an DBus signal on all events. You could listen on the system DBus for the appropiate event and trigger your script based on this...

-1

One could just have it on system cron to poll on every sec / 10 sec or so...

poll.sh:

#!/bin/bash/ 
ifconfig -a > ~/Dropbox/myifconfig.txt

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .