一、本方法优点:
1、零资源占用,不用添加监测IP地址变化后更新DDNS的后台程序。
2、不使用系统定时任务cron,更新DDNS的脚本执行一次就退出。
3、极速反应,ip地址变化立马更新至服务器(实测1秒内)。
二、环境要求:
1、支持无状态ipv6的路由器或光猫。
2、linux环境,网络管理程序为dhcpcd。
3、一个支持脚本更新DDNS的任意域名。
4、可以更新DDNS的业务代码脚本。
本文不讨论更新DDNS的具体代码。如果为腾讯云(DNSPOD),下面有两个参考脚本:
纯shell版:
GitHub – rehiy/dnspod-shell: 基于DNSPod用户API实现的纯Shell动态域名客户端
python版:
Python 用DNSpod官方库更新DNSpod记录_小辉辉的博客-CSDN博客_dnspod python
三、题外话,为什么选用dhcpcd作为网络管理客户端
1、Linux常用的网络管理客户端的缺点。
- networking.service和配置文件(/etc/network/interfaces)。缺点:灵活度差。
- 通常用于桌面环境的networkmanager+nm-applet等。缺点:内存占用大,平均60mb以上。
- systemd-networkd+systemd-resolved。缺点:灵活度差,两个服务内存占用也不小,24mb左右。
- netplan+后端(networkmanager或systemd-networkd),缺点:多个工具组合,内存占用相当大。
相比上述方案,dhcpcd采用单服务方案,内存占用相当轻量2mb左右,功能也相对完善,能满足常见的使用需求。
四、以dhcpcd hook机制更新DDNS[无状态IPV6]原理
dhcpcd客户端会根据特定网络事件(如地址租约到期)调用特定脚本(hook机制),相关事件的原因和相关环境变量名会以会传入被调入的脚本中。我们只需要在脚本中加入环境变量值的判断代码就可以捕捉这些事件(如路由是否委派了新的前缀)。
dhcpcd执行的hook脚本为:/usr/lib/dhcpcd/dhcpcd-hooks,并在/usr/lib/dhcpcd/dhcpcd-hooks这个脚本中执行/etc/dhcpcd.enter-hook和/etc/dhcpcd.exit-hook这两个脚本。
因此我们只需求在/etc/dhcpcd.enter-hook或/etc/dhcpcd.exit-hook这两个脚本中加入我们的捕获代码就可以实现上述功能了。
具体技术细节见下面这个网址:
dhcpcd-run-hooks(8) — Arch manual pages
ipv6无状态配置是基于ND协议(Neighbor Discovery,邻居发现)。当路由广播客户端指示生成新的IPV6地址时,会先发送一条当前前缀址优选生存时间(Preferred_Life_Time)为零和有效时间(valid_Life_Time)为零的RA消息。也就是告诉客户端,当前地址无效了,并在下次RA消息则发放新的地址前缀。
在dhcpcd客户端中,反映为hook脚本中变量nd1_prefix_information2_pltime和nd1_prefix_information2_vltime值为0,(上述变量名中的数字每个人可能不一样,需要结合自身实际查看),如下图所示:
在上面两张图片中,左侧图为ipv6地址更新前dhcpcd的hook脚本设置的环境变量,右侧图为更新时dhcpcd的hook脚本设置的环境变量,可以看出,nd1_prefix_information2_pltime和nd1_prefix_information2_vltime值变为0。
下面这两张图为更新时(左侧)和更新后hook脚本设置的环境变量(右侧)。可以看出,在右侧图中,接收新的更新RA消息后,环境变量中的前缀和优先时间和有效时间均已更新。
因些,只需要捕获这两条消息(更新时和更新后),并根据相关环境变量值的变化就可以第一时间拿到更新后的IPV6地址,通常在一秒内。
五、实现
第一步,获取相关环境变量名称。
为了准确获得ipv6地址更新前后的环境变量名。
执行编辑命令sudo nano /etc/dhcpcd.exit-hook,添加下面代码。并重启你的dhcp服务器(路由或光猫)。
下面代码执行后会生成/tmp/variup.txt。
我们就可以在/tmp/variup.txt中获取到相关变量名了。
#!/bin/sh
# ======================================================================
if [ "${interface}" = "eth0" ]; then
set >>/tmp/variup.txt
fi
# ======================================================================
第二步,获取到相关环境变量值以后,执行下面编辑命令sudo nano /etc/dhcpcd.exit-hook,替换掉dhcpcd.exit-hook的内容为如下代码,并替换掉代码中的环境变更名称。
在下面代码中
${interface}为你需要监测的网络接口名称。此时为eh0。
${nd1_prefix_information2_pltime}这个变量名称根据监测到的实际变量名替换(可能数字不一样)。
${nd1_addr0}这个变量为新生成的IPV6地址,变量名称中的数字根据监测到的实际变量名替换(可能数字不一样)。。
(python3 /home/pi/ipmail.py)& 括号中为具体更新DDNS的代码脚本的位置,要进行替换。根据需求,也可以把nd1_addr0作为更新参数传入。
#!/bin/sh # sed -i 's/\r//' dhcpcd.exit-hook # 只监测eth0接口 if [ "${interface}" = "eth0" ];then # 设置修改标记,为0时不更新DDNS,为1时才更新。 ModifyFlag=0 # 本文件的绝路径 mainpath="/etc/dhcpcd.exit-hook" # 如果收到的RA消息中优选时间为零,把标记值置为1. if [ "${nd1_prefix_information2_pltime}" = "0" ]; then # 用sed修改标志为1 sed -i 's/\(^\s*ModifyFlag=\)\S*/\11/' $mainpath fi # 第二次收到新的委派前缀RA的消息时,且标志已为1,执行更新DDNS代码, if [ "${ModifyFlag}" = "1" -a -n "${nd1_addr0}" ];then # ====================================================================== # 在子进程中后台执行括号中更新DDNS的业务代码 (python3 /home/pi/ipmail.py)& # ====================================================================== # 更新后,把修改标志值改为0,等待下次地址变化时重复。 sed -i 's/\(^\s*ModifyFlag=\)\S*/\10/' $mainpath fi fi
说明:更新DDNS的业务代码以子进程的形式放入后台运行,当前进程继续执行并退出后,且不影响子进程。
到此,实现了最轻量化,不用添加后台服务,监控进程和定时任务,不用频繁读取SD卡,并最快时间获取到最新IPV6地址,执行一次更新业务代码就退出的预期目标。
原文链接:https://blog.csdn.net/luzze__123/article/details/121607303?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522168510975416800192245729%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=168510975416800192245729&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~times_rank-14-121607303-null-null.268%5Ev1%5Econtrol&utm_term=NAS%E3%80%81%E7%BE%A4%E6%99%96%E3%80%81%E9%98%BF%E9%87%8C%E4%BA%91%E3%80%81%E5%9F%9F%E5%90%8D%E8%A7%A3%E6%9E%90%E3%80%81%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F%E3%80%81ipv6%E3%80%81ddns%E3%80%81%E8%BD%BB%E9%87%8F%E7%BA%A7%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8%E3%80%81%E9%93%81%E5%A8%81%E9%A9%AC%E3%80%81%E5%A8%81%E8%81%94%E9%80%9A%E3%80%81DSM%E3%80%81DSM6.0%E3%80%81%E7%BE%A4%E6%99%96nas%E3%80%81%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8%E3%80%81%E8%9C%97%E7%89%9B%E6%98%9F%E9%99%85%E3%80%81%E9%BB%91%E7%BE%A4%E6%99%96%E3%80%81docker%E3%80%81%E5%AE%B9%E5%99%A8%E9%95%9C%E5%83%8F%E3%80%81%E5%9F%9F%E5%90%8D%E6%B3%A8%E5%86%8C%E3%80%81%E5%AE%9D%E5%A1%94%E3%80%81%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86%E3%80%81nginx%E3%80%81frp%E3%80%81%E5%8A%A8%E6%80%81%E5%9F%9F%E5%90%8D%E8%A7%A3%E6%9E%90