简单可靠的IPv6 DDNS
应用场景:在拥有IPv6地址的机器上,运行一个守护进程,当本机IPv6地址变化时,主动更新DNS解析记录,即实现了DDNS。
代码
/etc/systemd/system/ddns.service
[Unit]
Description=Monitor IPv6 changes and update DDNS
Wants=network.target
After=network-online.target
[Service]
Type=simple
Restart=always
ExecStart=/bin/bash /usr/local/bin/update-ddns.sh
WorkingDirectory=/tmp
User=ddns
Group=ddns
Restart=on-failure
[Install]
WantedBy=multi-user.target
/usr/local/bin/update-ddns.sh
#!/bin/bash
IFACE=enp6s0 # 这里修改为你的IPv6网卡接口名称
last_addr=''
# check if the interface exists
if ! ip link show $IFACE > /dev/null 2>&1; then
echo "Error: network interface $IFACE does not exist"
exit 1
fi
update_ddns() {
IP="$1"
if [[ "$IP" == "" ]]; then
echo 'no valid IPv6 address extracted from monitor, get from remote server'
IP=`curl --proxy '' -s https://ipv6.ddnspod.com`
fi
echo "New IP Address: '${IP}'"
# 在这里添加你的curl命令,更新AAAA记录的地址值为$IP
}
# 服务启动时立刻更新一次
update_ddns
# 只要以2开头的IPv6地址,过滤掉ULA和link-local地址
ip mon addr dev $IFACE | sed -nu -r "s/^2: $IFACE[[:space:]]+inet6 (2[0-9a-f:]+).+$/\\1/p" | while read this_addr; do
if [[ "$last_addr" != "$this_addr" ]]; then
echo "IPv6 address changed: '${this_addr}', previous one: '$last_addr'";
last_addr="$this_addr"
update_ddns "$this_addr"
fi
done
优缺点
优点:
- 部署简单:仅需要systemd、bash、net-tools(
ip
命令)和curl,很多Linux发行版都自带,无需其他依赖。systemd可换为SysVinit等其他替代品 - 最小化记录更新延迟:传统DDNS方案依赖定时器触发,极端情况下,需要等待一整个周期,解析记录才会被更新。主动监测+更新的方案解决了该问题
缺点:
- 后台服务需要常驻3个进程:程序主体依赖一条shell pipe,实现流式处理地址变化
- 使用bash编写:有人不喜欢bash/shell脚本