OpenVPN:如何在每个客户端的基础上缓解路径 MTU 问题?

Nil*_*ann 22 ip openvpn mtu ip-fragmentation

我们在客户处安装了数十个嵌入式设备,所有这些设备都可以使用我们的 OpenVPN 服务。一般情况下这很好,但我们的一些客户有严重的路径 MTU 问题。我们对客户修复网络的影响是有限的,因此我们需要 OpenVPN 来处理它。简而言之,我的问题是:

我如何在每个客户端的基础上减轻某些客户端的低路径 MTU,即不使用全局设置来适应所有客户端的最坏情况

请注意,我们的最坏情况非常糟糕:路径 MTU 576,丢弃所有碎片,不对自身进行碎片化,不尊重 DF 位。你明白为什么我不想在全球范围内解决这个问题。

OpenVPN的联机帮助提供了许多MTU的相关选项,最显着的--link-mtu, --tun-mtu, --fragment and --mssfix。但它也说

--link-mtu [...] 除非您知道自己在做什么,否则最好不要设置此参数。

--tun-mtu [...] 最好使用 --fragment 和/或 --mssfix 选项来处理 MTU 大小问题。

于是我开始尝试用--fragment--mssfix,但很快就意识到,至少前者必须设置不仅客户端,但也服务器端。然后我查看了服务器端每个客户端的配置,--client-config-dir但它说

以下选项在特定于客户端的上下文中是合法的:--push、--push-reset、--iroute、--ifconfig-push 和 --config。

没有提到 MTU 选项!

所以这里是我更具体的问题:

  • 为什么究竟是link-mtutun-mtu气馁?这些选项有哪些潜在问题?请注意,我对低级 IP 标头处理非常满意。
  • 哪些选项link-mtu tun-mtu fragment mssfix必须在服务器端镜像才能工作?
  • 哪些选项link-mtu tun-mtu fragment mssfix可以用于client-config-dir
  • 如果所有四个选项都必须在服务器端镜像,并且不能在内部使用client-config-dir:是否有任何替代方案来对抗每个客户端的低路径 MTU?

笔记:

  • 我的部分问题在 5 年前就已经在这里过了,但当时还没有真正得到回答,因此我敢于复制它们。
  • OpenVPN 服务器目前在 Ubuntu 12.04 上是 2.2.1。我们正在准备在 Ubuntu 14.04 上升级到 2.3.2
  • OpenVPN 客户端是 Debian 7.6 上的 2.2.1
  • 我很高兴自己手动确定客户的路径-MTU
  • 目前我们无法测试很多服务器端。但是我们正在建立一个完整的独立测试平台,应该很快就可以准备好。

我很感激任何有用的建议。

oz1*_*123 7

我通过mssfix 1300在配置文件中添加选项解决了客户端的问题。

从 openvpn 手册页:

--mssfix max
    Announce to TCP sessions running over the tunnel that they should limit their send packet sizes such that after OpenVPN has encapsulated them, the resulting UDP packet size that OpenVPN sends to its peer will not exceed max bytes. 
Run Code Online (Sandbox Code Playgroud)

我的解决方案的最初想法来自personalvpn.org

  • mssfix 可以添加到服务器和客户端。但是较小的值将用于协商 (5认同)

LL3*_*LL3 7

不确定这是否对嵌入式设备有帮助,但我正在分享我的经验,以防它可以帮助其他人。

\n

TL;DR:跳到最后一个问题/答案以获取可能的解决方案

\n
\n
\n
    \n
  • 为什么不鼓励使用 link-mtu 和 tun-mtu?这些选项有哪些潜在问题?请注意,我对低级 IP 标头修改非常满意。
  • \n
\n
\n

根据我作为 OpenVPN 用户的经验,对于大多数常见情况,实际上最好不要fragment修改和/或值,即与文档所述相反。mssfix

\n

link-mtutun-mtu值的计算彼此相关,具体取决于隧道使用的密码(如果有)。默认情况下,tun-mtu它是经典的 1500 字节,而link-mtu派生于此,但您可以设置其中一个,从而相应地重新计算另一个。在这方面,一个相当确定的经验法则永远不要同时设置:只设置其中一个,因为另一个会效仿。

\n

我在更改端点时遇到问题的唯一情况是,当我将端点设置为具有非常不同的值并且服务器的值非常低时,例如服务器上的值是 576,而客户端上的值是 1500 这些设置根本不握手,我从未进一步调查过,因为坦率地说,我只在人工实验室测试中进行过此类设置。相反的情况,即客户端上的值非常低,而服务器上的值正常/高,则效果很好。

\n

事实上,我发现设置link-mtutun-mtu(我最喜欢设置link-mtu)实际上可以巧妙地解决最常见的情况,即隧道的工作方式就像它应该包含任何非 TCP 流量一样。

\n

当然,设置fragment和/或mssfix值(如果也显式设置了这些值)必须考虑显式的 link-mtu/tun-mtu 值,但我发现仅保留它们(即在配置中甚至没有提及)通常是最好的做法是因为它们只是根据 link-mtu/tun-mtu 值自动调整。

\n

也就是说,确实 mssfix设置(因此留下 link-mtu/tun-mtu 以及fragment未指定)确实可以解决与 TCP 相关的所有问题,但所有其他协议必然会遇到问题,这是它们通常不这样做的唯一原因这只是因为大多数非 TCP 流量要么是 UDP 上的 DNS(通常尺寸较小),要么是 ICMP 回显请求/答复(默认情况下也是小数据包)。

\n

但请注意,我指的是 Linux 上的 OpenVPN;在其他操作系统上,特别是 Windows 系列和 iOS 设备上,情况可能有所不同,即更改 link-mtu/tun-mtu 可能无关紧要甚至具有破坏性,您可能必须按照文档的建议求助于更改fragment/mssfix 。特别不利的情况可能是当服务器或客户端(或两者)不支持 IP 分段/重组时,可能会通过人为降低 link-mtu/tun-mtu 来触发,因此在这种情况下,您只能求助于启用fragment启用打开VPN。

\n
\n
\n
    \n
  • 哪个选项 link-mtu tun-mtufragment mssfix 必须在服务器端镜像才能工作?
  • \n
\n
\n

根据当您设置 link-mtu/tun-mtu 但未将其镜像到端点时 OpenVPN 向其日志发出的警告消息,link-mtu 和 tun-mtu准确无误,无论是显式还是隐式。然而,在实际用例中,即使我最终在隧道端点之间得到了非常不同的值,我在更改任一值时也从未遇到过问题。

\n

fragment必须在两侧都存在两侧都不存在,因为它的存在使得 OpenVPN 本身可以使用其自己的内部算法(而不是 IP 分段)执行分段,因此必须得到两个端点的同意。然而,当它存在时,它可能具有不对称的值。

\n

mssfix不需要镜像,并且端点之间也可能具有不对称值。

\n
\n
\n
    \n
  • 哪个选项 link-mtu tun-mtu 片段 mssfix 可以在 client-config-dir 中使用?
  • \n
\n
\n

没有任何

\n
\n

一个可能的解决方案

\n
\n
    \n
  • 如果所有四个选项都必须在服务器端镜像,并且不能在 client-config-dir 内使用:是否有任何替代方案来应对每个客户端的低路径 MTU?
  • \n
\n
\n

一种方法是使用 Linux 的每路由设置,它允许任意设置 MTU 值,最高可达实际接口的 MTU。其过程如下:

\n

对于初学者,手动执行路径 MTU 发现(例如使用ping -M do -s xxxx <client\'s-*public*-address>从服务器到远程客户端的命令),以便找出服务器和每个特定远程客户端之间的正确 MTU 值。然后,

\n

在客户端,假设它只是一个客户端而不是 LAN 中其他主机的路由器,只需将 OpenVPN 的link-mtu值设置为实际 MTU 减去 28。例如,在实际 MTU 为 576 的远程客户端上link-mtu 548会成功的。

\n

请注意,它适用于源自客户端的所有link-mtu流量(不仅仅是 TCP),因为OpenVPN 使用 \xc2\xa0 值作为发送到远程端点的其自身(UDP 端口 1194)有效负载的上限大小,因此远程客户端的实际 MTU(手动发现)减 20(不带选项的外部 IP 标头大小)减 8(外部 UDP 标头大小)。

\n

OpenVPN 将自动钳位到隧道内 TCP 流量的 MSS 值将是link-mtuOpenVPN 自身的开销(根据所使用的密码而变化),负 20(不带选项的内部 IP 标头大小)负 20(内部 TCP 标头大小)没有选项)。

\n

在服务器端,为每个“低 MTU”客户端安装一个路由,以便为每个客户端设置正确的 MTU。在每个路由设置上设置的每个正确值都必须是您在该远程客户端上设置的值link-mtu值(如之前确定的)减去 OpenVPN 自身的开销。后者可以从 link-mtu 值减去 OpenVPN 服务器为该特定隧道报告的 tun-mtu 值得出。例如,假设 OpenVPN 服务器报告的 link-mtu 为 1541,tun-mtu 为 1500,那么在托管 OpenVPN 服务器的计算机上,您将执行以下操作:

\n
ip route add <client\'s-*vpn*-address> via <your-openvpn-server\'s-*vpn*-address> mtu 507\n
Run Code Online (Sandbox Code Playgroud)\n

此类操作可以通过脚本方便地按需完成client-connect,该脚本接收由 OpenVPN 动态设置的环境变量中的这些值(以及许多其他值)。用 shell 脚本的话说就是:

\n
ip route add <client\'s-*vpn*-address> via <your-openvpn-server\'s-*vpn*-address> mtu 507\n
Run Code Online (Sandbox Code Playgroud)\n

从那时起,流向该特定客户端VPN地址的出站流量将遵循该 MTU,而不是 tun 接口的 MTU。

\n

此外,如果您的 OpenVPN 服务器还充当sysctl net.ipv4.ip_forward=1其 LAN 和远程客户端之间的路由器 ( ),则应用于 OpenVPN 服务器计算机(其 Linux 内核)的每条路由设置也将触发正确的 ICMP 消息(类型 3 代码 4,分段)当 LAN 中的计算机向远程客户端发送 DF 流量时,这些计算机必须遵守这些 ICMP 消息,在这种情况下,LAN 中的其他计算机必须遵守这些 ICMP 消息,并且当 LAN 中的计算机向远程客户端发送 DF 流量时,它还将代表 LAN 中的计算机在隧道内执行 IP 分段。这些发送非 DF 流量,在这种情况下,您的远程客户端必须支持对来自隧道的 IP 片段进行 IP 重组。

\n

另请注意,在 Ubuntu 14.04 HWE 及更新版本(或最高 v5.7.x 的等效内核)上,您还必须进行设置,sysctl net.ipv4.ip_forward_use_pmtu=1以便让 Linux 在转发其他计算机的流量时执行所述 ICMP/分段,而该附加功能sysctl是由服务器计算机本身发起的出站流量不需要。

\n

最后请注意,为了完全正确的配置,您还应该在服务器link-mtu 1472端进行设置(假设底层接口的 MTU 为 1500)。实际上,我随时随地都会这样做,作为基本配置,除了需要特定解决方法的特殊情况。这是因为 OpenVPN 不会将底层接口的 MTU 视为其 link-mtu/tun-mtu 的起始值,即使在支持它的操作系统上将其选项设置为,它也不执行 PMTU 发现。因此,对我来说,明确设置一个反映底层接口 MTU 的值(使用我上面描述的公式)是真正最好的默认值,至少在 Linux 上是这样。mtu-discyeslink-mtu

\n

华泰

\n


Nil*_*ann 3

鉴于缺乏答案,我现在发布一个不是很优雅但很简单的解决方案:为“坏客户端”在 TCP 上运行另一个 OpenVPN 实例

proto tcp
Run Code Online (Sandbox Code Playgroud)

并降低客户端上的 TCP MSS,例如

iptables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN -o ${OUT_DEV} -j TCPMSS --set-mss ${PATH-MTU-MINUS-40}
Run Code Online (Sandbox Code Playgroud)

该解决方案的优点是每个客户端都可以设置其单独的 MSS。

这无疑是 TCP-over-TCP,但在许多场景中应该表现得足够好

请注意,我仍然对不需要的解决方案非常感兴趣proto tcp,如果它们或多或少满足我概述的要求,我会将它们标记为有效答案。


归档时间:

查看次数:

21002 次

最近记录:

4 年,9 月 前