如何在本地IP发生变化时运行脚本?

在标记为重复之前:这不是关于动态DNS或类似的事情。

我知道每次网络运行时如何运行脚本; 在这个目录/etc/NetworkManager/dispatcher.d中添加脚本是一件简单的事情:

 #!/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 

在我的例子中, myscript是一个非常简单的ifconfig -a > ~/Dropbox/myifconfig.txt —我使用它是因为我需要从大学的各处知道我的本地IP,它会经常改变。

到目前为止一切顺利,系统运行正常。 但不幸的是,这里配置的DHCP是为了在改变接口的情况下改变IP。 在这种情况下,脚本(逻辑上)不运行,并且文件未更新。

我不能使用DynDNS方法,因为更改是在本地 IP中,而不是外部可见的IP。

我可以通过简单地将脚本放在cron中并每分钟执行一次或者写一个稍微复杂的脚本来进行轮询(如果IP被更改,则写入文件,否则什么都不做)并将其再次作为后台任务,但它不优雅。 所以问题是:

当我的本地IP发生变化时,有没有办法触发脚本?

更新1

我试图在/etc/dhcp/dhclient-enter-hooks.d/一个脚本,它基于现有的/etc/dhcp/dhclient-enter-hooks.d/resolvconf ,但不会被触发。 我怀疑(需要确认)NM(网络管理员)自己进行dhcp协商,而不调用dhcp命令…

根据NetmorkManager的手册页,其中一个事件是

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

我想你可以简单地改变

 up) 

 dhcp4-change|up) 

使用python脚本进行轮询。 基本思想是不断解析ip -4 -o add show ,并将当前结果与之前的迭代进行比较

 #!/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() 

我提供了一个侦听dbus信号的脚本,这将使您比在轮询当前网络配置的更改时更快地做出反应。 它可以帮助您在需要时执行脚本/ etc /的系统(比如我的14.04系统)。

我的进入/退出hooks.d不起作用

NetworkManager使用标志-sf /usr/lib/NetworkManager/nm-dhcp-client.action启动dhclient,这似乎会覆盖正常的进入/退出挂钩行为。 dhclient的默认行为是调用/etc/dhcp/dhclient-{enter,exit}-hooks.d脚本。 那些在我的系统上根本没有被调用。

我的NetworkManager dispatcher.d脚本也不起作用

但是,NM会在/etc/NetworkManager/dispatcher.d调用一组不同的脚本来通知各种事件。 NetworkManager(8)手册页定义了dhcp4-changedhcp6-change动作,它们似乎完全符合您的要求。 尽管manpage说的是,至少在我的系统上,只调用up down行动。 我不能让这些脚本触发其他任何东西。 因此,这也不是监控IP更改的好方法。

因此,直接窥探NM发出的dbus信号

来自命令行的nm-dhcp-client.action ( source )只是将dhclient设置的所有环境变量转换为dbus信号。 这些环境变量在man dhclient-script (8)中定义。 特别感兴趣的是$new_ip_address 。 正如@Bernhard所建议的那样,你可以做的是监控信号并根据其内容采取相应的行动。

这是一个程序,它将监听由该二进制文件发出的所有事件数据:

 #!/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  

dbus-monitor的输出在脚本中解析并不简单。 也许更容易触发某个关键字(例如new_ip_address )的存在,并从那里使用不同的工具来获取更改的信息(例如ip或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" ) ... 

试一试!

虽然NetworkManager使用的是dhclient,但它提供了自己的二进制文件来替代dhclient-scripts。 (供参考:您可以在/usr/lib/NetworkManager/nm-dhcp-client.action找到NM二进制文件)。

也许你可以采取不同的方法:NM正在对所有事件发出DBus信号。 您可以在系统DBus上侦听适当的事件,并根据此触发您的脚本…