在Linux(可能还有* BSD)上的OpenVPN隧道上设置动态路由(特别是BGP)

为什么以及这篇文章是关于什么的?


如果您搜索“ openvpn bgp”主题,那么从实用的角度来看,您会发现一些有趣且有用的文章(例如, 一次两次 )。 但是开始从头开始解决问题,由于许多原因,我什至没有去谷歌搜索它。 这个想法是在与OpenVPN的长期合作中以某种方式本身产生的(通常是在非常典型的任务框架内,两侧都有固定的网络集),在MikroTik RouterOS系统上使用OpenVPN实施,并将Linux和RouterOS上的系统彼此对接。 实际上,在意识到在RouterOS中编写我们自己的OpenVPN实现的原因的过程中,“见解”是关于如何在功能齐全的OpenVPN版本的框架内解决此问题的。 然后进行了简短的实验检查,结果显示了该想法的全部工作能力,并且将该解决方案引入了“工业”运营。


考虑到这种情况对于不同的应用程序非常典型,并且尚未提供以下描述的解决方案,我决定与社区分享这个想法。



问题的实质(“谁来负责?”)


常规版本的OpenVPN与在RouterOS中实施的版本之间有什么区别? 可能会有一些差异,但是在本文中,我们将只考虑一件事:RouterOS以外的系统中的常规OpenVPN(可能还有其他一些)是一个包含传输部分的组合(即,数据包传输本身,它也在转发,它也是一个数据平面) )和路由(即交换有关路由的信息,它是路由,它也是一个控制平面),并且在RouterOS中,OpenVPN服务负责传输部分,并且路由是由不同的系统进程处理的,一方面,它不允许在以下情况下重复路由的功能 系统(此外,不要在不同的服务中保留几个相同的路由表,并使其彼此不断地进行同步),另一方面,允许在这些车辆上透明地传递路由表,并即时更改两侧的路由表。


此外,OpenVPN的常规实现还有一个缺点:路由的传输仅在一个方向上(从服务器到客户端)发生,并且仅在建立会话时(即,建立隧道)发生。 在隧道操作期间,没有常规的方法可以随时随地将路由添加到内部OpenVPN路由表中,以及将路由从一侧转移到另一侧。 而且,甚至不可能获得路由表本身。


解决问题的方法(“做什么”)


分析我的脚本以自动将路由分配给不同的客户端后,我注意到OpenVPN有两个不同的选项来指定路由:


  • i route -在OpenVPN进程的路由表设置路由。
  • route -route-设置OpenVPN进程传递到系统路由表的路由(即,在连接时通过其隧道接口将路由添加到表中,而在断开连接时将其删除)。

出现了一个明显的问题:如果i route使用i route在两侧添加路由0.0.0.0/0,然后在隧道接口本身上添加或删除必要的路由(包括那些动态出现或消失的路由),例如,使用路由服务,将会发生什么(路由,斑马/斑马,鸟等)?


实验表明,这种方案确实在工作上有一点限制带来的不便:只有一个客户端可以连接到一个服务器隧道。 电路的其余部分证明可以完全正常工作。


该方案以基于TCP的TLS模式运行,也就是说,对于配置,必须首先生成SSL密钥和证书。


下面,我为服务器和客户端提供了一个示例OpenVPN配置。


服务器端配置(每个客户端一个)。


server_dyn_rt.conf文件(服务器端)


 daemon compress ping-timer-rem persist-tun persist-key tls-server proto tcp-server topology net30 mode server script-security 3 keepalive 15 45 tun-mtu 1500 remote-cert-tls client verify-x509-name <CLIENT_DISTINGUISHED_NAME> name auth <TLS_AUTH_ALGORITHM> cipher <CIPHER_ALGORITHM> local <SERVER_PUBLIC_IP> lport <SERVER_PUBLIC_PORT> dev-type tun dev <TUNNEL_INTERFACE_NAME> ifconfig <TUNNEL_SERVER_SIDE_IP> <TUNNEL_CLIENT_SIDE_IP> client-connect client_connect.sh push "route-gateway <TUNNEL_SERVER_SIDE_IP>" push "topology net30" push&nbsp"persist-tun" push&nbsp"persist-key" <dh> ... Diffie-Hellman data <</dh> <ca> ... Certificate Authority certificate data </ca> <cert> ... Server certificate data </cert> <key> ... Server Private Key data </key> 

文件client_connect.sh (服务器端)


 #!/bin/sh echo 'ifconfig-push TUNNEL_CLIENT_SIDE_IP TUNNEL_SERVER_SIDE_IP' >> ${1} echo 'push "iroute 0.0.0.0 0.0.0.0"' >> ${1} echo 'iroute 0.0.0.0 0.0.0.0' >> ${1} exit 0 

client_dyn_rt.conf文件(客户端)


 daemon compress tls-client auth <TLS_AUTH_ALGORITHM> cipher <CIPHER_ALGORITHM> client dev-type tun dev <TUNNEL_INTERFACE_NAME> script-security 3 remote-cert-tls server verify-x509-name <SERVER_DISTINGUISHED_NAME> name remote <SERVER_PUBLIC_IP> <SERVER_PUBLIC_PORT> tcp <ca> ... Certificate Authority certificate data </ca> <cert> ... Client certificate data </cert> <key> ... Client Private Key data </key> 

由于数据包的多样性或设置本身的多样性,我没有引用数据包和路由协议的设置(实际上,作为配置示例的来源,您可以使用本文的第二篇,本文的开头提供了指向本文的链接)。 我只想指出,上述设置允许您使用特定的BGP(由于其“可控制性”和在同一会话中传输各种协议的路由的能力,我个人喜欢它)。 对于BGP,应将地址<TUNNEL_CLIENT_SIDE_IP>用作“服务器”侧上邻居的地址,并且应将地址<TUNNEL_SERVER_SIDE_IP>或各方的“内部”地址用于客户端,但随后需要在配置中添加相应的路由服务器和/或客户端。



上述解决方案的优缺点


缺点:

  1. 每个服务器必须恰好有一个客户端,因此对于多个客户端,您将必须保持多个OpenVPN进程处于活动状态。 结果-一些内存溢出等等。
  2. 您不能在OpenVPN中使用预共享密钥模式,因为在这种模式下,禁止将参数从服务器动态传递到客户端(推/拉)。 因此,需要更复杂的配置,包括生成一组密钥和证书,以及用于在服务器端生成客户端配置块的脚本(但是,可以通过将client-connect /path/to/script选项替换为client-connect-dir /path/to/config/dir option来用静态文件目录替换该client-connect /path/to/script client-connect-dir /path/to/config/dir ,这增加了服务器端的安全级别。

优点:

  1. 与GRE / IPIP等协议不同,OpenVPN隧道可以具有1500字节的MTU(因为OpenVPN进程通过向隧道接口发送全长数据包来“隐藏”所有隐藏/碎片整理的功能)。 这使得在OpenVPN隧道上配置各种辅助隧道变得容易。
  2. OpenVPN隧道同时支持IPv4和IPv6的传输,从而减少了节点对之间的隧道数量,它们的配置和管理成本,以及在与IPv4路由相同的BGP会话中传输IPv6路由。
  3. OpenVPN协议的所有优点,例如易于设置中间网络设备(或完全不需要它),能够在HTTPS下屏蔽流量,适用于大多数平台等的实现方式。

我希望有人会觉得上面的指南有用。

Source: https://habr.com/ru/post/zh-CN483740/


All Articles