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)了。
服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# 禁止 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 |
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# 禁止 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调试
1 2 |
/system logging add topics=ipsec,!debug action=memory |
客户端动态更新IP
把以下脚本作为你PPPoE拨号端口对应PPP Profile的On Up触发脚本。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
: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隧道的配置就变得很简单:
服务端
1 |
/interface gre add local-address=<服务端隧道内网 IP> mtu=1382 name=gre-out1 remote-address=<客户端隧道内网 IP> |
客户端
1 |
/interface gre add local-address=<客户端隧道内网 IP> mtu=1382 name=gre-out1 remote-address=<服务器端隧道内网 IP> |
然后,你就可以把路由表里面的部分条目指向这个GRE隧道啦。
注:这边写死了MTU,你可以试试不填让路由器自动计算(提醒:RouterOS的MTU永远算不对)或者自己去算一个更优的值。
感谢LTY在撰写本文的过程中提供的帮助。
参考:
Pingback引用通告: 动态IP下的IOS XE用GRE/IKEv2连接RouterOS | Drown in Codes