在 《Cisco IOS IPsec 配置专题(3) – 使用 Crypto Map 时 Fragmentation 的问题》中我们介绍了 PMTUD 在避免 fragmentation 时的作用但是并没有深入的对 PMTUD 的实际部署进行分析,当我们在使用 IPsec 的时候这里有两类 PMTUD 需要讨论,第一种是普通的 Path PMTUD,另一种是 IPsec PMTUD。
在 RFC 4301 中规定了每一个 IPsec SA 都需要包含一个 Path MTU,这个 Path MTU 代表的是该 IPsec 可以承载的最大未加密载荷 (plaintext packet size)。该 MTU 可以被称为 IPsec Path MTU 或 SA Path MTU,它的计算方式是 IPsec 的源出站接口 MTU 减去最大的 IPsec overhead(IPsec 的 overhead 由配置的具体加密算法等决定),如下图:
如图所示,整条链路上的 Path MTU 是 1500,用于配置 IPsec 的路由器出站接口 MTU 也是 1500,经过路由器的计算 IPsec overhead 是 73,所以得出的 SA Path MTU 为 1500 – 73 = 1427。1427 就是该 IPsec 可以承载的最大载荷,也就是说这是用户端能够发送的最大 MTU,如果用户发送超过这个值的数据包就会面临 fragmentation 的问题。
下面的示例展示了普通的 PMTUD 和 IPsec PMTUD 结合在一起的情况:
- 一台开启了 PMTUD 的 PC (现在大部分操作系统都默认开启),由于其 Interface MTU 是 1500,所以第一次发出的数据包载荷是 1500 且 DF = 1 (我们前面的章节介绍过 DF = 1 是 PMTUD 可以工作的原理或者说前提条件)
- 该数据包到达路由器后被拒绝了,因为路由器计算出的 SA Path MTU 只有 1427,无法承载 1500 的数据包,由于该包 DF = 1,路由器反馈一个 ICMP Type 3 Code 4 (fragmentation needed but don’t fragment set) 并提示可以允许的 MTU 为 1427。到这里我们就进行了一次 IPsec PMTUD
- PC 再次发包,大小降为 1427 且 DF = 1,路由器对其进行 IPsec 加密,加密后大小刚好为 1500 (1427 + 之前算好的 IPsec overhead)
- 大小为 1500 的 IPsec 数据包转发到第二台路由器的时候被拒绝,因为第二台路由器的一个 Interface MTU 为 1400。由于该包 DF = 1,第二台路由器按照 PMTUD 的原则反馈一个 ICMP Type 3 Code 4 给第一台路由器,并提示最大 MTU 只能为 1400。这里进行的是一次普通的 PMTUD
- 第一台路由器收到反馈后将自己的 Path MTU 由 1500 降为 1400,并据此重新计算 SA Path MTU,1400 – 73 = 1327
- PC 继续发包,大小为 1427 且 DF = 1,这一次由于 SA Path MTU 只有 1327,所以该包被丢弃,路由器反馈 ICMP Type 3 Code 4,并提示最大 MTU 只能为 1327
- PC 将包大小调整为 1327,发送成功
我们用一个实验来验证以上的理论
R1 和 R4 之间使用 crypto map 的方式配置了 IPsec,R2 和 R3 之间 MTU 调整为 1400,参数如下
R1 IPsec
crypto isakmp policy 10 hash sha256 authentication pre-share group 2 ! crypto isakmp key cisco address 34.34.34.2 ! crypto ipsec transform-set TS esp-aes esp-sha256-hmac mode tunnel ! crypto map CP 10 ipsec-isakmp set peer 34.34.34.2 set transform-set TS match address 100 ! access-list 100 permit ip host 172.16.1.2 host 172.16.2.2
!
interface GigabitEthernet0/0
ip address 12.12.12.1 255.255.255.0
crypto map CP
R4 IPsec
crypto isakmp policy 10 hash sha256 authentication pre-share group 2 ! crypto isakmp key cisco address 12.12.12.1 ! crypto ipsec transform-set TS esp-aes esp-sha256-hmac mode tunnel ! crypto map CP 10 ipsec-isakmp set peer 12.12.12.1 set transform-set TS match address 100 ! access-list 100 permit ip host 172.16.2.2 host 172.16.1.2
!
interface GigabitEthernet0/0
ip address 34.34.34.2 255.255.255.0
crypto map CP
从 PC1 ping PC2 (数据包大小调整稍微大一点,DF = 1)
PC1#ping 172.16.2.2 size 500 df-bit Type escape sequence to abort. Sending 5, 500-byte ICMP Echos to 172.16.2.2, timeout is 2 seconds: Packet sent with the DF bit set !!!!! Success rate is 100 percent (5/5), round-trip min/avg/max = 18/24/36 ms
在 R1 上观察 Path MTU 和 SA Path MTU
R1#sh crypto ipsec sa | i mtu
plaintext mtu 1438, path mtu 1500, ip mtu 1500, ip mtu idb GigabitEthernet0/0
到目前为止 R1 认为整条链路的 Path MTU 是 1500,计算出的 SA Path MTU 是 1438。我们的真实 Path MTU 应该是 1400 (因为 R2 到 R3 网段之间我们调整为了 1400),但是由于刚才 PC1 发出的数据包较小,就算经过 IPsec 加密以后也未超过 1400 所以并未触发 R2 的 PMTUD 反馈。
我们将 PC1 的 ping 大小调整为 1439,这个大小超过了 R1 的 SA Path MTU,将会触发 R1 的 IPsec PMTUD,R1 将会反馈一个 ICMP Type 3 Code 4 给 PC1:
PC1#ping 172.16.2.2 size 1439 df-bit
Type escape sequence to abort.
Sending 5, 1439-byte ICMP Echos to 172.16.2.2, timeout is 2 seconds:
Packet sent with the DF bit set
M.M.M
Success rate is 0 percent (0/5)
Ping 回显 M 代表 Could not fragment,PC1 和 R1 之间抓包可以看到 ICMP 信息
我们继续将 Ping 的大小调整为 1438,这样 R1 刚好可以产生一个 1500 的 IPsec 数据包,该数据包到达 R2 后会触发一个普通的 PMTUD
PC1#ping 172.16.2.2 size 1438 df-bit
Type escape sequence to abort.
Sending 5, 1438-byte ICMP Echos to 172.16.2.2, timeout is 2 seconds:
Packet sent with the DF bit set
.M.M.
R1 收到该 ICMP 以后会对自己的 Path MTU 和 SA Path MTU (plaintext mtu) 进行调节
R1#sh crypto ipsec sa | i mtu
plaintext mtu 1326, path mtu 1400, ip mtu 1500, ip mtu idb GigabitEthernet0/0
PC1 将 Ping 大小降为 1326 就可以成功的 Ping 通
PC1#ping 172.16.2.2 size 1326 df-bit
Type escape sequence to abort.
Sending 5, 1326-byte ICMP Echos to 172.16.2.2, timeout is 2 seconds:
Packet sent with the DF bit set
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 15/18/30 ms
上述的示例是在 PMTUD 完全正常工作的情况下的情况,如果网络中有防火墙将 ICMP block 掉了 PMTUD 就无法让我们的 PC 自动调整 MTU 值了,这时候我们可以使用 ip mtu
在可以避开防火墙的地方提前将 MTU 降下来。
我们对 IPsec 进行重置以后 R1 的 Path MTU 和 SA Path MTU 恢复到了最初的设定
R1#show crypto ipsec sa | i mtu plaintext mtu 1438, path mtu 1500, ip mtu 1500, ip mtu idb GigabitEthernet0/0
在 R1 的接口上配置一个 ACL 过滤 ICMP 来模拟防火墙
access-list 100 deny icmp host 12.12.12.2 host 12.12.12.1 packet-too-big log access-list 100 permit ip any any log ! interface GigabitEthernet0/0 ip address 12.12.12.1 255.255.255.0 ip access-group 100 in
PC1 发送一个 1438 大小的 Ping,R2 的 PMTUD 反馈会被 ACL 过滤掉,从而导致 R1 无法自动调整 MTU
PC1#ping 172.16.2.2 size 1438 df-bit
Type escape sequence to abort.
Sending 5, 1438-byte ICMP Echos to 172.16.2.2, timeout is 2 seconds:
Packet sent with the DF bit set
.....
注意这里的 ICMP 回显不是 M,说明 R1 对 fragmentation 的信息并不知道
R1#show crypto ipsec sa | i mtu plaintext mtu 1438, path mtu 1500, ip mtu 1500, ip mtu idb GigabitEthernet0/0 R1#show ip access-lists 101 Extended IP access list 101 10 deny icmp host 12.12.12.2 host 12.12.12.1 packet-too-big (5 matches) 20 permit ip any any (89 matches)
我们在 R1 接口上手动配置 MTU 这样模拟避开防火墙使得 R1 可以利用 PMTUD 反馈给 PC1 要求其降低 MTU,修改 MTU 后 R1 会自动重新计算 Path MTU 和 SA Path MTU
interface GigabitEthernet0/0 ip address 12.12.12.1 255.255.255.0 ip access-group 101 in ip mtu 1400
R1#show crypto ipsec sa | i mtu
plaintext mtu 1326, path mtu 1400, ip mtu 1400, ip mtu idb GigabitEthernet0/0
再次用 PC1 进行 Ping,这次的回显变成 M 证明 R1 在提示它减低 MTU
PC1#ping 172.16.2.2 size 1438 df-bit
Type escape sequence to abort.
Sending 5, 1438-byte ICMP Echos to 172.16.2.2, timeout is 2 seconds:
Packet sent with the DF bit set
M.M.M
Success rate is 0 percent (0/5)
我们还可以结合ip tcp adjust-mss
来对 TCP 包进行 TCP MSS Clamping,如果按照上述示例 PC 可以发出的最大 IP 包为 1326,那么 MSS 值就应该配置为 1326 – 20 – 20 = 1286 (20 IP header,20 TCP header)。