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

当本地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 命令...

答案1

根据手册页对于 NetworkManager-dispatcher,其中一个事件是

dhcp4-change

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

我认为你可以简单地改变

up) 

dhcp4-change|up)   

答案2

我提供了一个脚本,用于监听 dbus 信号,这样您就可以比轮询当前网络配置的变化更快地做出反应。它对脚本 /etc/ 未按您希望的方式执行的系统(例如在我的 14.04 系统上)很有帮助。

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

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

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

然而,NM 确实调用了一组不同的脚本,以/etc/NetworkManager/dispatcher.d通知各种事件。NetworkManager-dispatcher(8)手册页定义 dhcp4-changedhcp6-change操作似乎完全按照您的要求执行。尽管手册页上说了什么,但至少在我的系统上,只有updown操作被调用。我无法让这些脚本在其他任何操作上触发。所以这也不是监控 IP 变化的好方法。

因此,直接监听 NM 发出的 dbus 信号

nm-dhcp-client.action来源),从命令行简单地将 dhclient 设置的所有环境变量转换为 dbus 信号。这些环境变量在 (8) 中定义man dhclient-script。特别有趣的是$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 </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

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"
)
...

答案3

使用 Python 脚本进行轮询的方法。基本思想是不断解析输出ip -4 -o add show <INTERFACE>并将当前结果与上一次迭代进行比较

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

答案4

我们可以在系统 cron 上进行每秒/10 秒左右轮询...

轮询.sh:

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

相关内容