背景: 在部署一个服务时, 发现容器的网络行为总是有问题, 由此查阅资料才发现时本地交付机制搞的鬼, 于是做个笔记.
当一个数据包的目标 IP 是本机的一个 IP 地址时(不管是不是接收接口的地址),操作系统会将该数据包直接交给本地的应用程序处理,而不是转发出去或丢弃。这种行为称为:
- Local delivery(本地交付)
- 或者说是:IP 属于本机地址(local delivery decision)
这在 TCP/IP 协议栈中是一个标准的行为,不管是 Windows 还是 Linux 都支持。
🔍 举个例子说明#
假设你有一台 Linux 主机,它拥有两个网卡:
eth0
:192.168.1.4/24
eth1
:192.168.5.4/24
你在该主机上运行了一个 Web 服务,监听在 0.0.0.0:80
。
现在,从另一台机器 192.168.5.30
发送一个 HTTP 请求到 192.168.1.4:80
。但由于路由错误或不正确的 ARP 响应等原因,这个数据包实际上被发送到了主机的 eth1
接口(192.168.5.4
)上。
结果是:Linux 仍然可以正常处理这个请求。因为它检查数据包的目标 IP 192.168.1.4
,发现这个 IP 属于本机,于是就会将数据包直接交付给上层正在监听的 Web 服务。
这就是典型的“本地交付”。
⚙️ Linux 和 Windows 的区别在哪里?#
功能 | Windows | Linux |
---|---|---|
默认启用本地交付 | ✅ 是 | ✅ 是 |
默认启用 IP 转发 | ❌ 否 | ❌ 否(默认) |
控制方式 | 图形界面 / 注册表 / PowerShell | sysctl 参数(如 net.ipv4.ip_forward ) |
允许跨接口访问本机 IP | ✅ 是 | ✅ 是 |
所以,它们在“本地交付”这一点上核心行为是一致的。
🛠️ Linux 中影响本地交付的一些内核参数#
虽然本地交付是默认行为,但在某些特定场景下,你可以通过调整内核参数来改变它。
1. rp_filter
(反向路径过滤)#
如果启用了严格的 rp_filter
,Linux 可能会丢弃那些“从错误接口进入”的数据包。这是一种防止源 IP 欺骗的安全机制。
|
|
rp_filter 通常有几种模式:
strict (严格模式):要求数据包的入站接口必须是系统路由表中通往其源地址的最佳路径。在我们的例子中,这可能会导致数据包被丢弃。
loose (宽松模式):只要求源地址在路由表中可达即可,不关心从哪个接口进来。
disabled (禁用):完全禁用 rp_filter。
你可以通过以下命令查看当前设置: code Shell IGNORE_WHEN_COPYING_START IGNORE_WHEN_COPYING_END
sysctl net.ipv4.conf.all.rp_filter
- accept_local code Shell IGNORE_WHEN_COPYING_START IGNORE_WHEN_COPYING_END
net.ipv4.conf.all.accept_local = 1
这个参数明确允许接口接受那些目标 IP 是本机、但不属于该接口的 IP 地址的数据包。这个参数默认就是开启的,是实现本地交付的关键之一。