SO_REUSEADDR(setsockopt选项)是什么意思-Linux?

新手上路,请多包涵

从手册页:

SO_REUSEADDR 指定用于验证提供给 bind() 的地址的规则应该允许重用本地地址,如果协议支持的话。此选项采用 int 值。这是一个布尔选项

我应该什么时候使用它?为什么要“重用本地地址”?

原文由 Ray Templeton 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 513
1 个回答

TCP 的主要设计目标是在数据包丢失、数据包重新排序以及——这里的关键——数据包重复的情况下允许可靠的数据通信。

很明显 TCP/IP 网络堆栈在连接建立时如何处理所有这些,但在连接关闭后会发生边缘情况。如果在对话结束时发送的数据包被复制和延迟,这样 4 路关闭 数据包在延迟数据包之前到达接收器会发生什么?堆栈尽职尽责地关闭其连接。稍后,延迟的重复数据包出现。堆栈应该做什么?

更重要的是,如果一个在给定 IP 地址 + TCP 端口组合上打开套接字的程序关闭了它的套接字,然后不久之后,一个程序出现并想要监听相同的 IP 地址和 TCP 端口号,该怎么办? ? (典型情况:一个程序被杀死并迅速重新启动。)

有几个选择:

  1. 不允许重复使用该 IP/端口组合至少 2 倍于数据包可以在飞行中的最长时间。在 TCP 中,这通常称为 2× MSL 延迟。有时您还会看到 2× RTT ,大致相当。

这是所有常见 TCP/IP 堆栈的默认行为。 2×MSL 通常在 30 到 120 秒之间,它显示在 netstat 输出为 TIME_WAIT 周期。在那之后,堆栈假定由于 TTL 过期而在 途中 丢弃了任何恶意数据包,因此套接字离开 TIME_WAIT 状态,允许重用该 IP/端口组合。

  1. 允许新程序重新绑定到该 IP/端口组合。在带有 BSD 套接字 接口的堆栈中——基本上所有的 Unix 和类 Unix 系统,以及通过 Winsock 的 Windows——你必须在调用之前通过 setsockopt() 设置 SO_REUSEADDR 选项来请求这种行为 bind()

SO_REUSEADDR 最常在网络服务器程序中设置,因为常见的使用模式是进行配置更改,然后需要重新启动该程序才能使更改生效。如果没有 SO_REUSEADDR ,如果在您杀死前一个实例时打开了与前一个实例的连接,则重新启动程序的新实例中的 bind() 调用将失败。这些连接会将 TCP 端口保持在 TIME_WAIT 状态 30-120 秒,因此您属于上述情况 1。

设置 SO_REUSEADDR 的风险在于它会产生歧义:TCP 数据包标头中的元数据不够独特,以至于堆栈无法可靠地判断数据包是否过时,因此应该丢弃而不是传递到新侦听器的套接字,因为它显然是为现在已死的侦听器准备的。

如果您不认为这是真的,那么所有侦听机器的 TCP/IP 堆栈都必须与每个连接一起工作才能做出该决定:

  1. 本地 IP: 不是每个连接唯一的。事实上,我们这里的问题定义是故意重用本地 IP。

  2. 本地 TCP 端口: 同上。

  3. 远程 IP: 造成歧义的机器可能会重新连接,因此这无助于消除数据包正确目的地的歧义。

  4. 远程端口: 在行为良好的网络堆栈中,传出连接的远程端口不会很快重用,但它只有 16 位,因此您有 30-120 秒的时间来强制堆栈通过几万选择和重用端口。早在 1960 年代,计算机就可以这么快地完成工作。

如果您对此的回答是远程堆栈应该执行类似 TIME_WAIT 的操作以禁止 临时 TCP 端口 重用,则该解决方案假定远程主机是良性的。恶意行为者可以自由地重用该远程端口。

我想侦听器的堆栈可以选择仅严格禁止来自 TCP 4 元组的连接,以便在 TIME_WAIT 状态期间阻止给定的远程主机与相同的远程临时端口重新连接,但我不知道任何具有该特定改进的 TCP 堆栈。

  1. 本地和远程 TCP 序列号: 这些序列号也不够独特,以至于新的远程程序无法得出相同的值。

如果我们今天重新设计 TCP,我认为我们会将 TLS 或类似的东西作为非可选功能集成,其效果之一是使这种无意和恶意的连接劫持变得不可能。这需要添加大字段(128 位及以上),这在 1981 年根本不实用,当时发布了当前版本的 TCP ( RFC 793 ) 的文档。

如果没有这种硬化,允许在 TIME_WAIT 期间重新绑定所产生的歧义意味着您可以 a) 将用于旧侦听器的陈旧数据错误传递到属于新侦听器的套接字,从而破坏侦听器的协议或错误地将陈旧数据注入连接;或 b) 新侦听器套接字的新数据被错误地分配给旧侦听器的套接字,因此被无意丢弃。

安全的做法是等待 TIME_WAIT 期结束。

最终,它归结为成本选择:等待 TIME_WAIT 期间或承担不必要的数据丢失或无意数据注入的风险。

许多服务器程序冒着这种风险,决定最好立即备份服务器,以免错过任何不必要的传入连接。

这不是一个普遍的选择。许多程序——甚至需要重新启动以应用设置更改的服务器程序——都选择单独保留 SO_REUSEADDR 。程序员可能知道这些风险并选择不考虑默认设置,或者他们可能不知道这些问题但正在从明智的默认设置中受益。

一些网络程序为用户提供配置选项之间的选择,从而将责任推卸给最终用户或系统管理员。

原文由 Warren Young 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题