前言
当你的内网机器想对外提供服务时,这时候需要通过端口映射/转发的方式来实现,而你本地运营商给你分配的公网IP是动态变化的,想要根据变化触发修改动作,则需要DDNS
想通过端口转发/映射将内网服务提供给外网的前提是你运营商给你分配的是公网IP,如果是私网地址则不行,可以向运营商申请。
如何判断运营商给自己分配的是公网地址还是私网地址
点击Ros的IP
–>Address
,看第一条地址即可,网络地址是113.118,所以是公网
端口映射与端口转发
端口映射是将外网的一个端口完全映射给内网一个地址的指定端口,而端口转发是将发往外网的一个端口的通信完全转发给内网一个地址的指定端口。端口映射可以实现外网到内网和内网到外网双向通信,而转发只能实现外网到内网的单向通信 。在Ros上实现端口映射/转发
DDNS
DDNS是将用户的动态IP地址解析到一个固定的域名解析服务上,一旦用户的外网IP发生变化就可以通过触发或定时任务调用域名解析商提供的API修改对应的域名解析记录值。
一、Ros设置转发端口
1.打开IP
–>FireWall
–>NAT
,新增一条dstnat
规则,协议选择tcp,目标端口3389,入接口选择你的外网接口(通过PPPoE
拨号的接口)
2.Action
选项同样设置为dstnat
,地址设置为任何你想转发到的内网机器IP,端口还是选择3389,对应内网机器的服务端口,可随意设置,前面在General
配置的端口不一定要和这里的端口保持一致:
此时,在外部访问ISP给你分配的外网IP的3389端口,可以正常转发到你的内部机器3389端口上,前提是你的内部机器对应的端口有正常监听服务
注意:内网去访问该地址会造成回环包,你nat出去上网的IP和你要访问的外网IP是同一个地址,此时上层设备不知道要转发给谁,直接丢弃掉,这里有两种解决办法:
-
内部网络直接请求对应的内网主机,没必要出外网,如果设置了DDNS又想去请求这个域名,则设置hosts或内网劫持到内网主机IP
-
端口映射
二、端口映射
1.打开IP
–> Firewall
–>NAT
,新增一条dnat
规则,Dst.Address
填写你ADSL拨号获取的公网IP:
2.Action
的设置和端口转发的设置没有多大区别,点击comment
,设置规则别名,可自定义,稍后会在定时执行更新脚本用到
三、利用脚本定时更新公网IP
1.打开system
–>script
,新增一个脚本,Name可自定义,脚本内容的TEST10001
即我们刚刚自定义的dnat规则
代码作用:获取pppoe-out1
接口的ip地址,更新到TEST10001
的dst-address
参数中,这样一来IP即使变化只要执行脚本,我们添加的dnat
规则都能做相应调整,将最新IP对应的固定端口映射给我们的内网机器
:global ipaddr [/ip address get [/ip address find interface=pppoe-out1] address]
:set ipaddr [:pick $ipaddr 0 ([len $ipaddr] -3)]
:global oldip [/ip firewall nat get [/ip firewall nat find comment="TEST10001"] dst-address]
:if ($ipaddr != $oldip) do={
:log info [/ip firewall nat set [/ip firewall nat find comment="TEST10001"] dst-address=$ipaddr]
}
四、设置计划任务,定时执行一次脚本
1.打开system
–> schedule
,新增一条计划,Interval
表示间隔多久执行一次,设置为5分钟即可,最低可设置到秒级
:execute TEST10001 #将在约定间隔内执行一次TEST10001脚本
此时我们内网测试,可以正常通信,说明数据包并没有受到回环影响:
外网测试亦能正常通信:
到此,端口映射及定时更新配置完成
五、DDNS配置
DDNS则和上述定时更新公网IP逻辑一致,唯一的区别是执行的动作不一样,DDNS会将获取到的最新公网IP传参给域名解析商提供的API接口,用来更新域名解析记录最新的记录值IP
1.同样,打开system
–>script
,新增如下脚本
这里使用的是dnspod及阿里云的api接口,使用此接口调用的前提是你的域名解析在dnspod或阿里云管理
dnspod:
#PPPoE
:local pppoe "pppoe-out1"
#DNSPOD的秘钥Id+token
:local token "173031,95b457w9a41e0c1a159a1c74cdbcc10f"
#域名
:local domain "linux-code.com"
#域名主机名
:local subdomain "data"
#domain
:local dname ($subdomain.".".$domain)
#获取pppoe拨号ip
:local ipaddr [/ip address get [/ip address find interface=$pppoe] address]
:set ipaddr [:pick $ipaddr 0 ([len $ipaddr] -3)]
#获取域名列表
:local record [/tool fetch url="https://dnsapi.cn/Record.List" http-data="login_token=$token&format=json&domain=$domain&sub_domain=$subdomain&record_type=A" as-value output=user]
#获取id和ip
:set record ($record->"data")
:set record [:pick $record [:find $record "\"records\":"] [:len $record]]
:local recordid [:pick $record ([:find $record "\"id\":\""]+6) [:find $record "\",\"ttl"]]
:local recordip [:pick $record ([:find $record "\"value\":\""]+9) [:find $record "\",\"en"]]
#更新ip地址
:if ($recordip!=$ipaddr) do={
/tool fetch url="https://dnsapi.cn/Record.Ddns" http-data="login_token=$token&format=json&domain=$domain&sub_domain=$subdomain&record_id=$recordid&record_line_id=0&value=$ipaddr"
:log info ("[".$dname."] ip update")
} else={
:log info ("[".$dname."] ip not update")
}
阿里云:
#aliyun Access Key
:local id "AccessKeyId"
:local secret "AccessKeySecret"
#domain
:local domain "linux-code.com"
:local record "data"
#PPPoE-out
:local pppoe "pppoe-out1"
:local ipaddr [/ip address get [/ip address find interface=$pppoe] address]
:set ipaddr [:pick $ipaddr 0 ([len $ipaddr] -3)]
:global aliip
:if ($ipaddr != $aliip) do={
:local result [/tool fetch url="http://u.myxzy.com/alidns/\?id=$id&secret=$secret&domain=$domain&record=$record&ip=$ipaddr" as-value output=user];
:if ($result->"status" = "finished") do={
:if ($result->"data" = "0") do={
:set aliip $ipaddr
:log info "alidns update ok";
} else={
:log info "alidns update error";
}
}
}
2.新建定时任务,大约每5分钟定时执行一次脚本
使用dig
测试解析生效情况:
可以看到,配置的域名正常解析到我们的外网IP,即使外网IP发生变化,我们最低可设置为秒级执行一次更新(建议设置一分钟以上,间隔越短对ros负载压力越大),到此DDNS配置结束。