RouterOS在一端动态IP情况下配置GRE over IPSec VPN

IPSec有两种模式:transport和tunnel。Transport模式双方仍然使用各自的公网IP互联,只不过传送的数据会被自动加密,必须两端的IP固定(否则服务器端也要动态更新客户端IP),tunnel模式则是建立一个类似VPN的点对点通道,需要给通道分配内网IP,在公网IP的要求上则相对比较宽松(只需要客户端更新自己的IP),缺点是浪费20MTU,传输效率稍低。本文讲解如何配置IPSec tunnel连接,以及在其上配置一个GRE隧道。

配置IPSec

这里我们统一把固定IP的一侧叫做服务端,动态IP的一侧叫做客户端。需要准备两组IP地址:

  • 服务端的公网IP
  • 客户端当前的公网IP
  • 服务端的隧道内网IP
  • 客户端的隧道内网IP(如果你有多个客户端,在服务器那侧可以填写一个IP段;而对于每台客户端需要填写准确IP)

注:请不要把这里所述隧道内网IP段加入OSPF等动态路由协议的网段。如果需要跑动态路由协议,可以在GRE隧道上另配一组IP。

在建立完IPSec隧道以后,两台设备就可以使用这里规定的内网IP互相通信(即建立VPN)了。

服务端

# 禁止 IPSec 隧道内部流量被 NAT
# (仅 RouterOS 6.42 之前)
/ip firewall nat add action=return chain=srcnat comment="IPSec Roadwarrior" src-address=<服务器隧道内网 IP 段> dst-address=<客户端隧道内网 IP> place-before=0

# 添加一个新的 policy group, 名字随便取,用默认那个 default 也行
/ip ipsec policy group add name=internal

# 添加一个新的 proposal,规定加密方式
/ip ipsec proposal add auth-algorithms=sha256 enc-algorithms=aes-128-cbc name=internal pfs-group=modp3072

# 添加一个通配符 peer
# 6.42 之前
/ip ipsec peer add dh-group=modp3072 enc-algorithm=aes-128 exchange-mode=ike2 generate-policy=port-strict hash-algorithm=sha256 policy-template-group=internal secret=<密码>
# 6.42 之后
/ip ipsec peer add dh-group=modp3072 enc-algorithm=aes-128 exchange-mode=ike2 generate-policy=port-strict hash-algorithm=sha256 policy-template-group=internal notrack-chain=prerouting secret=<密码> 
# 禁用默认的 policy 模板
/ip ipsec policy set 0 disabled=yes

# 添加一个 policy 模板
/ip ipsec policy add dst-address=<客户端隧道内网 IP 段> group=internal proposal=internal protocol=gre src-address=<服务器隧道内网 IP> template=yes

# 如果服务器隧道内网 IP 地址在 /ip addr 里面没有的话,需要手工配置到一个 loopback 端口上
/interface bridge add name=lo
/ip addr add address=<服务器隧道内网 IP> interface=lo

客户端

# 禁止 IPSec 隧道内部流量被 NAT 
# (仅 RouterOS 6.42 之前)
/ip firewall nat add action=return chain=srcnat comment="IPSec Roadwarrior" src-address=<客户端隧道内网 IP> dst-address=<服务器隧道内网 IP> place-before=0

# 添加一个新的 policy group(其实默认的那个也行)
/ip ipsec policy group add name=internal

# 添加一个新的 proposal
/ip ipsec proposal add auth-algorithms=sha256 enc-algorithms=aes-128-cbc name=internal pfs-group=modp3072

# 添加一个新的 peer
# RouterOS 6.42 以前:
/ip ipsec peer add address=<服务器公网 IP> dh-group=modp3072 enc-algorithm=aes-128 exchange-mode=ike2 hash-algorithm=sha256 policy-template-group=internal secret=<密码>
# 6.42 以后(可以在这里直接绕过 NAT,不需要显式增加防火墙规则)
/ip ipsec peer add address=<服务器公网 IP> dh-group=modp3072 enc-algorithm=aes-128 exchange-mode=ike2 hash-algorithm=sha256 policy-template-group=internal notrack-chain=prerouting secret=<密码> 
# 添加一个新的 policy
/ip ipsec policy add dst-address=<服务器的隧道内网 IP> proposal=internal protocol=gre sa-dst-address=<服务器的公网 IP> sa-src-address=<你的公网 IP> src-address=<你的隧道内网 IP> tunnel=yes

# 如果客户端隧道内网 IP 地址在 /ip addr 里面没有的话,需要手工配置到一个 loopback 端口上
/interface bridge add name=lo
/ip addr add address=<客户端隧道内网 IP> interface=lo

完成以上两部分设置以后,在任意一侧的IPSec Policies里应该可以看到一条连接,PH2 state为established,表示IPSec握手成功。

注:

  • 如果你使用图形界面方式来设置的话,在添加policy时protocol请填入数字47(GRE协议号);
  • 如果你在配置之前已有对该内网网段的NAT规则并且有设备尝试连接过该IP,NAT规则可能已被conntrack缓存;此时会出现IPSec Policy显示established但是GRE隧道不通的情况。清空conntrack缓存或者重启路由器即可解决。

IPSec调试

/system logging
add topics=ipsec,!debug action=memory

客户端动态更新IP

把以下脚本作为你PPPoE拨号端口对应PPP Profile的On Up触发脚本。

:local WANip [/ip address get [find interface="<你的 PPPoE interface 名字>"] address]
:global oldWANip
:set WANip [:pick "$WANip" 0 ([:len $WANip] - 3)]

if ($WANip != $oldWANip) do={

  :log info "WAN IP changed, fixing IPSec"

  # 如果有多个 IPSec 链接就多写几行
  /ip ipsec policy set [find sa-dst-address=<服务器公网 IP>] sa-src-address=$WANip

  :set oldWANip $WANip
}

建立GRE隧道

刚才的IPSec隧道只是点对点连接。如果我们要把点对点以外的流量也路由到隧道那头,就需要GRE协议的帮助。

因为已经建立了IPSec隧道,GRE隧道的配置就变得很简单:

服务端

/interface gre add local-address=<服务端隧道内网 IP> mtu=1382 name=gre-out1 remote-address=<客户端隧道内网 IP>

客户端

/interface gre add local-address=<客户端隧道内网 IP> mtu=1382 name=gre-out1 remote-address=<服务器端隧道内网 IP>

然后,你就可以把路由表里面的部分条目指向这个GRE隧道啦。

注:这边写死了MTU,你可以试试不填让路由器自动计算(提醒:RouterOS的MTU永远算不对)或者自己去算一个更优的值。


感谢LTY在撰写本文的过程中提供的帮助。

参考:

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据