14.7. IPsec 上的 VPN

互联网协议安全(IPsec)是一组位于互联网协议(IP)层之上的协议。它允许两个或多个主机通过对通信会话的每个 IP 数据包进行身份验证和加密,以安全的方式进行通信。FreeBSD IPsec 网络堆栈基于 http://www.kame.net/ 实现。同时支持 IPv4 和 IPv6 会话。

IPsec 由以下子协议组成:

  • 封装安全有效负载 (ESP):此协议通过使用对称加密算法(如 Blowfish 和 3DES)加密内容来保护 IP 数据包数据免受第三方干扰。
  • 身份验证标头 (AH):此协议通过计算加密校验和并使用安全哈希函数对 IP 数据包标头字段进行哈希处理来保护 IP 数据包标头免受第三方干扰和欺骗。然后,后面是包含哈希的附加标头,以允许对数据包中的信息进行身份验证。
  • IP 有效负载压缩协议 (IPComp):此协议尝试通过压缩 IP 有效负载来提高通信性能,以减少发送的数据量。

这些协议可以一起使用,也可以单独使用,具体取决于环境。

IPsec 支持两种操作模式。第一种模式(传输模式)保护两台主机之间的通信。第二种模式,隧道模式,用于构建虚拟隧道,通常称为虚拟专用网络(VPN)。请查阅 ipsec(4) 以获取有关 FreeBSD 中 IPsec 子系统的详细信息。

默认情况下,IPsec 支持在 FreeBSD 11 及更高版本上是启用的。对于更早的 FreeBSD版本。将这些选项添加到自定义内核配置文件中。然后按照 配置 FreeBSD 内核 中的说明重建内核:

  1. options IPSEC IP security
  2. device crypto

如果需要 IPsec 调试支持,还应添加以下内核选项:

  1. options IPSEC_DEBUG debug for IP security

本章的其余部分演示了在家庭网络和企业网络之间设置 IPsecVPN 的过程。在示例场景中:

  • 这两个站点都通过运行 FreeBSD 的网关连接到互联网。
  • 每个网络上的网关至少有一个外部 IP 地址。在这个例子中,公司局域网的外部 IP 地址是 172.16.5.4,家庭局域网的外部 IP 地址是 192.168.1.12
  • 两个网络的内部地址可以是公用或私有 IP 地址。但是,地址空间不得重叠。在此示例中,公司 LAN 的内部 IP 地址为 10.246.38.1 ,而家庭 LAN 的内部 IP 地址为 10.0.0.5
  1. corporate home
  2. 10.246.38.1/24 -- 172.16.5.4 <--> 192.168.1.12 -- 10.0.0.5/24

14.7.1. 在 FreeBSD 上配置 VPN

首先,必须从 Ports Collection 安装 security/ipsec-tools。该软件提供了许多支持该配置的应用程序。

下一个要求是创建两个 gif(4) 伪设备,它们将用于隧道数据包并允许两个网络正确通信。使用 root 账户,在每个网关上运行以下命令:

  1. corp-gw# ifconfig gif0 create
  2. corp-gw# ifconfig gif0 10.246.38.1 10.0.0.5
  3. corp-gw# ifconfig gif0 tunnel 172.16.5.4 192.168.1.12
  4. home-gw# ifconfig gif0 create
  5. home-gw# ifconfig gif0 10.0.0.5 10.246.38.1
  6. home-gw# ifconfig gif0 tunnel 192.168.1.12 172.16.5.4

使用 ifconfig gif0 验证每个网关上的设置。以下是家庭网关的输出:

  1. gif0: flags=8051 mtu 1280
  2. tunnel inet 172.16.5.4 --> 192.168.1.12
  3. inet6 fe80::2e0:81ff:fe02:5881%gif0 prefixlen 64 scopeid 0x6
  4. inet 10.246.38.1 --> 10.0.0.5 netmask 0xffffff00

下面是企业网关的输出:

  1. gif0: flags=8051 mtu 1280
  2. tunnel inet 192.168.1.12 --> 172.16.5.4
  3. inet 10.0.0.5 --> 10.246.38.1 netmask 0xffffff00
  4. inet6 fe80::250:bfff:fe3a:c1f%gif0 prefixlen 64 scopeid 0x4

完成后,两个内部 IP 地址都应该可以使用 ping(8) 访问:

  1. home-gw# ping 10.0.0.5
  2. PING 10.0.0.5 (10.0.0.5): 56 data bytes
  3. 64 bytes from 10.0.0.5: icmp_seq=0 ttl=64 time=42.786 ms
  4. 64 bytes from 10.0.0.5: icmp_seq=1 ttl=64 time=19.255 ms
  5. 64 bytes from 10.0.0.5: icmp_seq=2 ttl=64 time=20.440 ms
  6. 64 bytes from 10.0.0.5: icmp_seq=3 ttl=64 time=21.036 ms
  7. --- 10.0.0.5 ping statistics ---
  8. 4 packets transmitted, 4 packets received, 0% packet loss
  9. round-trip min/avg/max/stddev = 19.255/25.879/42.786/9.782 ms
  10. corp-gw# ping 10.246.38.1
  11. PING 10.246.38.1 (10.246.38.1): 56 data bytes
  12. 64 bytes from 10.246.38.1: icmp_seq=0 ttl=64 time=28.106 ms
  13. 64 bytes from 10.246.38.1: icmp_seq=1 ttl=64 time=42.917 ms
  14. 64 bytes from 10.246.38.1: icmp_seq=2 ttl=64 time=127.525 ms
  15. 64 bytes from 10.246.38.1: icmp_seq=3 ttl=64 time=119.896 ms
  16. 64 bytes from 10.246.38.1: icmp_seq=4 ttl=64 time=154.524 ms
  17. --- 10.246.38.1 ping statistics ---
  18. 5 packets transmitted, 5 packets received, 0% packet loss
  19. round-trip min/avg/max/stddev = 28.106/94.594/154.524/49.814 ms

正如预期的那样,双方都能够从配置的私有地址发送和接收 ICMP 数据包。接下来,必须告知两个网关如何路由数据包,以便网关能够准确的转发来自网关之后的网络流量。使用下面的命令实现这一配置:

  1. corp-gw# route add 10.0.0.0 10.0.0.5 255.255.255.0
  2. corp-gw# route add net 10.0.0.0: gateway 10.0.0.5
  3. home-gw# route add 10.246.38.0 10.246.38.1 255.255.255.0
  4. home-gw# route add host 10.246.38.0: gateway 10.246.38.1

内部计算机应可从每个网关以及网关后面的计算机访问。同样,使用 ping(8) 确认:

  1. corp-gw# ping -c 3 10.0.0.8
  2. PING 10.0.0.8 (10.0.0.8): 56 data bytes
  3. 64 bytes from 10.0.0.8: icmp_seq=0 ttl=63 time=92.391 ms
  4. 64 bytes from 10.0.0.8: icmp_seq=1 ttl=63 time=21.870 ms
  5. 64 bytes from 10.0.0.8: icmp_seq=2 ttl=63 time=198.022 ms
  6. --- 10.0.0.8 ping statistics ---
  7. 3 packets transmitted, 3 packets received, 0% packet loss
  8. round-trip min/avg/max/stddev = 21.870/101.846/198.022/74.001 ms
  9. home-gw# ping -c 3 10.246.38.107
  10. PING 10.246.38.1 (10.246.38.107): 56 data bytes
  11. 64 bytes from 10.246.38.107: icmp_seq=0 ttl=64 time=53.491 ms
  12. 64 bytes from 10.246.38.107: icmp_seq=1 ttl=64 time=23.395 ms
  13. 64 bytes from 10.246.38.107: icmp_seq=2 ttl=64 time=23.865 ms
  14. --- 10.246.38.107 ping statistics ---
  15. 3 packets transmitted, 3 packets received, 0% packet loss
  16. round-trip min/avg/max/stddev = 21.145/31.721/53.491/12.179 ms

此时,流量在封装在 gif 隧道中的网络之间传输,但没有任何加密。接下来,使用 IPSec 使用预共享密钥 (PSK) 加密流量。除了 IP 地址之外,两个网关上的 /usr/local/etc/racoon/racoon.conf 将完全相同,并且看起来类似于:

  1. path pre_shared_key "/usr/local/etc/racoon/psk.txt"; #location of pre-shared key file
  2. log debug; #log verbosity setting: set to 'notify' when testing and debugging is complete
  3. padding # options are not to be changed
  4. {
  5. maximum_length 20;
  6. randomize off;
  7. strict_check off;
  8. exclusive_tail off;
  9. }
  10. timer # timing options. change as needed
  11. {
  12. counter 5;
  13. interval 20 sec;
  14. persend 1;
  15. # natt_keepalive 15 sec;
  16. phase1 30 sec;
  17. phase2 15 sec;
  18. }
  19. listen # address [port] that racoon will listen on
  20. {
  21. isakmp 172.16.5.4 [500];
  22. isakmp_natt 172.16.5.4 [4500];
  23. }
  24. remote 192.168.1.12 [500]
  25. {
  26. exchange_mode main,aggressive;
  27. doi ipsec_doi;
  28. situation identity_only;
  29. my_identifier address 172.16.5.4;
  30. peers_identifier address 192.168.1.12;
  31. lifetime time 8 hour;
  32. passive off;
  33. proposal_check obey;
  34. # nat_traversal off;
  35. generate_policy off;
  36. proposal {
  37. encryption_algorithm blowfish;
  38. hash_algorithm md5;
  39. authentication_method pre_shared_key;
  40. lifetime time 30 sec;
  41. dh_group 1;
  42. }
  43. }
  44. sainfo (address 10.246.38.0/24 any address 10.0.0.0/24 any) # address $network/$netmask $type address $network/$netmask $type ( $type being any or esp)
  45. { # $network must be the two internal networks you are joining.
  46. pfs_group 1;
  47. lifetime time 36000 sec;
  48. encryption_algorithm blowfish,3des;
  49. authentication_algorithm hmac_md5,hmac_sha1;
  50. compression_algorithm deflate;
  51. }

有关每个可用选项的说明,请参阅 racoon.conf 的手册页。

安全策略数据库 (SPD) 需要配置。以便 FreeBSD 和 racoon 能够加密和解密主机之间的网络流量。

这可以通过企业网关上的 shell 脚本(类似于以下内容)来实现。此文件将在系统初始化期间使用,并应另存为 /usr/local/etc/racoon/setkey.conf

  1. flush;
  2. spdflush;
  3. # To the home network
  4. spdadd 10.246.38.0/24 10.0.0.0/24 any -P out ipsec esp/tunnel/172.16.5.4-192.168.1.12/use;
  5. spdadd 10.0.0.0/24 10.246.38.0/24 any -P in ipsec esp/tunnel/192.168.1.12-172.16.5.4/use;

一旦应用,可以使用以下命令在两个网关上启动 racoon:

  1. # /usr/local/sbin/racoon -F -f /usr/local/etc/racoon/racoon.conf -l /var/log/racoon.log

输出应类似于以下内容:

  1. corp-gw# /usr/local/sbin/racoon -F -f /usr/local/etc/racoon/racoon.conf
  2. Foreground mode.
  3. 2006-01-30 01:35:47: INFO: begin Identity Protection mode.
  4. 2006-01-30 01:35:48: INFO: received Vendor ID: KAME/racoon
  5. 2006-01-30 01:35:55: INFO: received Vendor ID: KAME/racoon
  6. 2006-01-30 01:36:04: INFO: ISAKMP-SA established 172.16.5.4[500]-192.168.1.12[500] spi:623b9b3bd2492452:7deab82d54ff704a
  7. 2006-01-30 01:36:05: INFO: initiate new phase 2 negotiation: 172.16.5.4[0]192.168.1.12[0]
  8. 2006-01-30 01:36:09: INFO: IPsec-SA established: ESP/Tunnel 192.168.1.12[0]->172.16.5.4[0] spi=28496098(0x1b2d0e2)
  9. 2006-01-30 01:36:09: INFO: IPsec-SA established: ESP/Tunnel 172.16.5.4[0]->192.168.1.12[0] spi=47784998(0x2d92426)
  10. 2006-01-30 01:36:13: INFO: respond new phase 2 negotiation: 172.16.5.4[0]192.168.1.12[0]
  11. 2006-01-30 01:36:18: INFO: IPsec-SA established: ESP/Tunnel 192.168.1.12[0]->172.16.5.4[0] spi=124397467(0x76a279b)
  12. 2006-01-30 01:36:18: INFO: IPsec-SA established: ESP/Tunnel 172.16.5.4[0]->192.168.1.12[0] spi=175852902(0xa7b4d66)

要确保隧道正常工作,请切换到另一个控制台,并使用 tcpdump(1) 通过以下命令查看网络流量。根据需要更换为网络接口卡 em0

  1. corp-gw# tcpdump -i em0 host 172.16.5.4 and dst 192.168.1.12

类似于以下内容的数据应显示在控制台上。如果不是,则存在问题,需要调试返回的数据。

  1. 01:47:32.021683 IP corporatenetwork.com > 192.168.1.12.privatenetwork.com: ESP(spi=0x02acbf9f,seq=0xa)
  2. 01:47:33.022442 IP corporatenetwork.com > 192.168.1.12.privatenetwork.com: ESP(spi=0x02acbf9f,seq=0xb)
  3. 01:47:34.024218 IP corporatenetwork.com > 192.168.1.12.privatenetwork.com: ESP(spi=0x02acbf9f,seq=0xc)

此时,两个网络都应该可用,并且似乎是同一网络的一部分。很可能两个网络都受到防火墙的保护。若要允许流量在它们之间传输,需要添加规则来传递数据包。对于 ipfw(8) 防火墙。请将以下行添加到防火墙配置文件中:

  1. ipfw add 00201 allow log esp from any to any
  2. ipfw add 00202 allow log ah from any to any
  3. ipfw add 00203 allow log ipencap from any to any
  4. ipfw add 00204 allow log udp from any 500 to any
注意
规则编号可能需要更改,具体取决于当前的主机配置。

对于 pf(4)ipf(8) 的用户。以下规则应该可以解决问题:

  1. pass in quick proto esp from any to any
  2. pass in quick proto ah from any to any
  3. pass in quick proto ipencap from any to any
  4. pass in quick proto udp from any port = 500 to any port = 500
  5. pass in quick on gif0 from any to any
  6. pass out quick proto esp from any to any
  7. pass out quick proto ah from any to any
  8. pass out quick proto ipencap from any to any
  9. pass out quick proto udp from any port = 500 to any port = 500
  10. pass out quick on gif0 from any to any

最后,要允许计算机在系统初始化期间启动对 VPN 的支持,请将以下行添加到 /etc/rc.conf

  1. ipsec_enable="YES"
  2. ipsec_program="/usr/local/sbin/setkey"
  3. ipsec_file="/usr/local/etc/racoon/setkey.conf" # allows setting up spd policies on boot
  4. racoon_enable="yes"