Update:较新的RouterOS v7.11已经带有了此功能(未测试),或许无需再使用该脚本
摘要:这篇文章给出了一种对于Router OS的更“优雅“的WireGuard Peer Endpoint(动态)域名自动刷新脚本,提出了一种在配置项的COMMENT中填写变量(比如域名)的方法,而不是hardcode在脚本中。这种思想也可用于其他对于RouterOS功能扩展的脚本。
背景:这个需求来源于Router OS的一个bug或者毛病,即当配置WireGuard Peer的连接地址(Endpoint)时,你虽然可以使用域名,但其仅会在启动时被解析,之后如果域名的IP发生变化,是不回重新解析的。这就导致如果你使用DDNS域名作为Endpoint,那在其IP变化后连接就会丢失,不会自动恢复,直到你重启接口或者机器。
解决上述问题的方式就是编写一个Router OS的脚本来解析域名,并将其IP更新到WireGuard Peer的Endpoint项中,然后将这个脚本添加在Schedule中,定时自动执行。由于Endpoint项会被脚本填写的IP覆盖,因此要在别的地方记录其域名。这个脚本目前网络上流传的版本如下:
# 网络上流传的版本,灵活性较差
:local wgInterface
:local wgPeerDns
:set wgInterface "wireguard1"
:set wgPeerDns "xxxxxxx.xxx-ddns.net"
:if ([interface wireguard peers get number=[find interface="$wgInterface"] value-name=endpoint-address] != [resolve $wgPeerDns]) do={
interface wireguard peers set number=[find interface="$wgInterface"] endpoint-address=[/resolve $wgPeerDns]
}
可以看出其WireGuard的接口和域名都hardcode(写死)在了脚本中,并且其默认一个接口只有一个Peer,无法适用于一个接口有多个Peer的情况。虽然我们很容易就能对其进行修改让其支持,但仍是繁琐的,比如要根据pubkey或设置特定的Comment用于区分不同Peer,并在脚本中对照配置项进行填写,带来了维护上的繁琐。
方法:既然这类脚本的目的是对Router OS本身的功能进行扩展,那么对于配置时最自然的方式,就是可以在配置项原有的界面中一并填写相关的变量(比如此处的域名),虽然Router OS中我们不能给配置项再添加一个字段,但我们其实可以充分利用Comment字段来存放我们的变量,有点像加在linux命令前的环境变量。并且Comment本身就和每个配置项直接关联,不需要我们再去维护其对应关系。
例如,我们就可以在Comment里写上DOMAIN_ENDPOINT=xxxxxxx.xxx-ddns.net
来表示域名,像下面这样:
相应的这种更优雅一些的脚本如下:
/interface/wireguard/peers
:local CommentPrefix "DOMAIN_ENDPOINT="
:foreach i in=[find where comment~"^$CommentPrefix.*\$"] do={
:local comment [get number=$i comment]
:local ip [:resolve [:pick $comment [:len $CommentPrefix] [:len $comment]]]
:if ([get number=$i endpoint-address] != $ip) do={
set number=$i endpoint-address=$ip
}
}
由于所有配置相关的信息都在Comment中填写了,哪怕之后还需要修改Peer的地址或者添加新的Peer和接口,也不需要对脚本进行任何更新。同时,如果Comment中没有“DOMAIN_ENDPOINT=”这样的字符串,脚本不回对其做任何操作;比起直接将整个Comment区域作为特定的变量值,这样不会有任何副作用,并且对于维护时该变量的含义是“自解释”的。
结论:这是对于WireGuard Peer动态域名的一个实用的脚本,但对于这种“通过Comment区的特定语法来配合一个通用的脚本来对Router OS的功能进行扩展”的思想,这只是一个简单的例子。实际上,还可以实现如:兼容与普通Comment一起使用,可以填写多个变量等,就“交给读者作为练习”了。
貌似这个路由器系统很好用,最近也在研究!