RouterOS更新dynv6脚本

国内ISP在PPPoE接入线上已经推广了很久IPv6,但国内DDNS供应商迟迟不怎么支持IPv6,当然也可以使用阿里云解析的办法,国外dynv6更新规则与国内供应商有很大不同,不允许未变更频繁请求,脚本上与国内供应商有所区别,仅在IPv6地址变化时发送请求。

使用第三方域名,避免back-to-home在更新的时候,连同端口上的IPv4地址一并更新以后,造成的错误,比如某些IPv4优先的协议,WireG之类。更新域名的时候限制为AAAA记录,这样的第三方域名是没有A记录的。

YDNS在国内页面不能正常打开,但脚本区别不大。

# 脚本前后的大括号用于限制脚本是本地范围,不加大括号是全局范围,具体区别可以查阅mikrotik的手册。
# 这个脚本不涉及上一级下一级脚本的互相嵌套调用,本地即可。“井”号是RouterOS的脚本注释,但有使用限制,具体限制可以查阅手册。
{

# 我设置的计划任务是开机以及每间隔5分钟执行一次,避免刚开机的时候地址获取延迟,等待10秒。
/delay 10

# 定义本地变量,以当前端口,从ISP以DHCP-PD获取到的地址赋值。如果IPv6地址是配置在bridge上,修改端口名称就可以,
# 我这里环境不是SLAAC或DHCPv6直接从ISP获取端口IPv6地址,如果是这两种情况,注意需要使用多个条件描述唯一地址,否则赋值会报错。
# 每个端口都可以有多个,而且至少有两个IPv6地址的原因不啰嗦了,不明白查阅IPv6相关教程。
:local currentv6addr [/ipv6/address/get [find interface=pppoe-out-ISP from-pool=ISP-pool-v6] address]

# 去掉获取到地址字符中前缀长度字符以及前面的“/”
:set $currentv6addr [:pick $currentv6addr 0 [:find $currentv6addr "/"]]

# 定义dynv6域名,替换示例中example,字符串赋值需要使用引号表达起止位置。
:local dynv6domain "example.dynv6.net"

# dynv6使用token认证,没什么可说明的。
:local dynv6token "1a2b3c4d5f6g7h8j9i0k"

# 利用fetch命令,DoH解析DDNS域名,国外的服务商嘛,懂得都懂。我只找出三个能支持name参数的DoH服务商。
# 除了示例中的cloudflare,还有quad9和0ms,有需要自己修改url变量。
# 后面的output=user as-value是把json内容作为变量值输出。
:local dynv6addr [/tool/fetch mode=https http-header-field="accept: application/dns-json" url="https://cloudflare-dns.com/dns-query?name=$dynv6domain&type=AAAA" output=user as-value]

# 转换变量类型,转换前应为array数组类型,没法进行字符串截取。
:local dynv6addr [:tostr $dynv6addr]

# 在字符串中查找特征字符/* "data":" */并截取字符串至末尾,这里是把所有特征字符以ASCII编码转义。
# 上一行借用C语言的注释,特征字符是包含引号在内的八个字符。
# 不同DDNS服务商似乎在DNS解析时,返回的json格式略有不同,为统一结果,分两步截取字符串。
:local dynv6addr [:pick $dynv6addr ([:find $dynv6addr "\22\64\61\74\61\22\3A\22"]+8) [:len $dynv6addr]]

# 在上一步基础上,将变量截取至第一个引号处。也就是获取json中/* "data":"..." */中间所描述的地址部分字符。
:local dynv6addr [:pick $dynv6addr 0 [:find $dynv6addr "\22"]]

# 定义dynv6更新的完整url
:local dynv6url "http://ipv6.dynv6.com/api/update?ipv6=auto&zone=$dynv6domain&token=$dynv6token&ipv6=$currentv6addr"

# 为图方便,我把接口地址后缀填写成了::1/64,没有使用EUI64,反正解析以后也是随时可以被任何人找到。
# 一个接口上可以生成的IPv6不止一个,如果脚本第一步获取条件描述不确切,发生错误,结果有可能为空。
:if ([:typeof $currentv6addr]!="nothing" and $currentv6addr!="::1") do={

    # 判断端口地址和域名记录不一致,才进行更新。
	:if ($currentv6addr!=$dynv6addr) do={

        # fetch指令模拟浏览器请求,但应答不写入存储器,当然也可以用https模式请求,记得修改url变量。
		/tool/fetch url="$dynv6url" mode=http output=none;

    # 端口当前地址和DNS记录一致,put屏显输出可以/log/info写入日志,有需要自行更改吧。
	} else={:put "no need update dynv6."}

# 端口上是个错误的地址,换句话说没找到前面要找的唯一地址,也可以写入日志。
} else={:put "bad IPv6 address for dynv6."}
}

YDNS的url是:https://ydns.io/api/v1/update/?host=$ydnsdomain&ip=$currentv6addr

fetch命令请求的时候还需要加上user和password两个参数,YDNS的API不可以匿名访问。

指令参考:/tool/fetch url="$ydnsurl" mode=https user=$ydnsuser password=$ydnspswd output=none

以上指令执行前,自行申明并赋值ydnsuser和ydnspswd两个变量。

RouterOS脚本中使用大括号的循环指令,大括号中间如果不止一行语句,每行结尾应添加分号,不清楚v7版本是不是还是必须的。

2024/8/21修正 typeof 变量获取为空的判断,值应为“nothing”,v6版本的“nil”已不作为“空”的返回值,但官方手册上未做修正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值