服务器不响应 ping - 收到 ICMP,但没有任何反应

服务器不响应 ping - 收到 ICMP,但没有任何反应

我有一台服务器,有 2 个接口连接到dhcp两个不同的子网。这 2 个不同的子网通过 2 个不同的接口连接到同一交换机。

# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
23: enp10s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether c4:00:ad:a4:e3:38 brd ff:ff:ff:ff:ff:ff
    inet 192.168.201.232/24 brd 192.168.201.255 scope global enp10s0
       valid_lft forever preferred_lft forever
25: enp11s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether c4:00:ad:a4:e3:39 brd ff:ff:ff:ff:ff:ff
    inet 192.168.203.3/24 brd 192.168.203.255 scope global enp11s0
       valid_lft forever preferred_lft forever
    inet6 fe80::c600:adff:fea4:e339/64 scope link 
       valid_lft forever preferred_lft forever

路线:

# ip r
default via 192.168.201.1 dev enp10s0 
192.168.201.0/24 dev enp10s0 proto kernel scope link src 192.168.201.232 
192.168.203.0/24 dev enp11s0 proto kernel scope link src 192.168.203.3 

我从我的笔记本电脑上 ping 通,首先是192.168.201.232.通过该设备上的 tcpdump,我可以看到icmp请求和响应

# tcpdump -s 0 -i any -vvv -nn 'host 192.168.1.30 and not port 22'
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
11:42:05.240967 IP (tos 0x0, ttl 62, id 53809, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.1.30 > 192.168.201.232: ICMP echo request, id 55768, seq 1, length 64
11:42:05.240994 IP (tos 0x0, ttl 64, id 42288, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.201.232 > 192.168.1.30: ICMP echo reply, id 55768, seq 1, length 64

当我 ping 到时192.168.203.3没有得到任何响应,这是 tcpdump 输出

# tcpdump -s 0 -i any -vvv -nn 'host 192.168.1.30 and not port 22'
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
11:43:57.037535 IP (tos 0x0, ttl 62, id 19363, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.1.30 > 192.168.203.3: ICMP echo request, id 55808, seq 1, length 64
11:43:58.060756 IP (tos 0x0, ttl 62, id 19364, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.1.30 > 192.168.203.3: ICMP echo request, id 55808, seq 2, length 64

这个数据包会发生什么?
为什么没有icmp反应?
我希望icmp响应会转到默认的 gw ( 192.168.201.1),因为我的 ip 是192.168.1.30

中没有任何内容iptables,并且统计数据不会随 增加netstat -s

当我删除 dhcp 并且接口enp10s0没有获取 ip 时,所以我只有一条路由

# ip r
default via 192.168.203.1 dev enp11s0 
192.168.203.0/24 dev enp11s0 proto kernel scope link src 192.168.203.3 

从我的笔记本电脑进行 ping 操作192.168.203.3,确实有效。

答案1

您有一个多宿主服务器,这总是会带来额外的路由复杂性。

您的网络可能或多或少复杂,但可能如下所示:

                  ┏━━━━━━┓
                  ┃laptop┃
                  ┗━━━━━━┛
               192.168.1.30/24
                    lan1
               192.168.1.1/24
                 ┌─────────┐
                 │ clients │
                 │ router  │
                 └─────────┘
                   x.x.x.x
                   y.y.y.y 
                 ┌─────────┐
  192.168.201.1/24 servers 192.168.203.1/24
   ╭┄┄┄┄┄┄┄┄┄┄┄┄┄│ router  │┄┄┄┄┄┄┄┄┄┄┄┄┄╮
   ┆             └─────────┘             ┆
   ┆                                     ┆
 lan201                               lan203
   ┆                                     ┆
   ┆             ┏━━━━━━━━━┓             ┆
   ╰┄┄┄┄┄┄┄┄┄┄┄┄┄┃         ┃┄┄┄┄┄┄┄┄┄┄┄┄┄╯
192.168.201.232/24  server 192.168.203.3/24
                 ┃         ┃
                 ┗━━━━━━━━━┛

为什么数据包会被忽略?

您的问题很可能是由于服务器启用了名为“反欺骗保护”的功能严格反向路径转发(SRPF)。简而言之,只有当使用同一接口路由回其回复时,才允许传入数据包通过该接口。

当两个接口均已配置且默认路由使用 192.168.201.1 并且您从笔记本电脑 ping 192.168.201.232 时,数据包会通过“左路径”到达服务器,并同样通过“左路径”从服务器返回。服务器可以询问内核其路由决策是什么。

到达笔记本电脑的路线:

# ip route get from 192.168.201.232 192.168.1.30
192.168.1.30 from 192.168.201.232 via 192.168.201.1 dev enp10s0 uid 0 
    cache 

用途恩普10s0

我们告诉传入数据包从同一接口到达(恩普10s0)因为我们知道这就是服务器的路由器将要做的事情:

# ip route get from 192.168.1.30 iif enp10s0 192.168.201.232
local 192.168.201.232 from 192.168.1.30 dev lo table local 
    cache <local> iif enp10s0 

由于它与传出数据包位于同一侧,因此该传入数据包被接受(并路由到本地系统)。

如果现在您 ping 192.168.203.3,数据包将被路由并到达“正确的路径”,并且服务器的路由配置将指示以“左侧的路径”离开服务器。这是一条非对称路由,并且未通过之前的 SRPF 检查:不同的接口。

您可以再次询问内核对于这种情况的决定。虽然回复(如果存在)将按如下方式路由:

# ip route get from 192.168.203.3 192.168.1.30
192.168.1.30 from 192.168.203.3 via 192.168.201.1 dev enp10s0 uid 0 
    cache 

使用默认路由,因此恩普10s0,传入数据包:

# ip route get from 192.168.1.30 iif enp11s0 192.168.203.3
RTNETLINK answers: Invalid cross-device link

被 SRPF 拒绝,因为传入接口恩普11s0与出接口不匹配恩普10s0它将用于回复此 IP 地址。

如果您通过禁用“左路径”来更改默认路由,从而继承“右路径”上 DHCP 的默认路由,则一切都会转变为恩普11s0它会再次起作用。

如何让它发挥作用?

  • 什么可能没有多大帮助

    你可以告诉系统禁用支票或放松它到松散反向路径转发。当涉及默认路由时(存在),两种效果都是相似的(即:根本没有太多效果),但在 Linux 中放松它(设置 2)比在其他地方启用它时禁用它(设置 0)更容易,因为这此配置中的最大值获胜。它可能是在系统启动时启用的/etc/sysctl.d(YMMV) 并且可以在那里编辑。所以:

    sysctl -w net.ipv4.conf.enp11s0.rp_filter=2
    

    并且之前的查询不会再失败:

    # ip route get from 192.168.1.30 iif enp11s0 192.168.203.3
    local 192.168.203.3 from 192.168.1.30 dev lo table local 
        cache <local> iif enp11s0 
    

    现在有两个 tcpdump,每个服务器接口上的一个应该可以看到传入的数据包恩普11s0以及关于的传出答复恩普10s0

    如果笔记本电脑收到答案,您就完成了,可以到此为止。

    可能不会。因为沿着路径,下一个网络元素,服务器的路由器可能实施SRPF。或者它可以兼作防火墙,并可能认为来自仅允许 192.168.201.0/24 中的数据包的接口的数据包 192.168.203.3 可疑(反欺骗保护,这也是 SRPF 的目标)。因此,该数据包很可能会在一步后被丢弃。

  • 什么会起作用:策略路由

    每当涉及多归属时,基于策略的路由必须使用。它允许不仅使用目标地址作为决策选择器来选择路由,还可以使用各种其他标准(最常见的是源地址)来选择路由。这里还需要源地址。在 Linux 中,这是通过使用附加路由表(通常使用目标作为选择器)并使用规则(此处将使用源作为选择器)选择适当的路由表来完成的。由于设置取决于源地址,因此很难集成到 DHCP 这样的动态环境中。虽然这当然是可能的:守护进程就像dhclient或者网络管理器每个都有自己的一组挂钩来插入脚本,您可以通过使用静态 IP 地址配置并声明 DHCP 服务器上保留的这些地址来节省时间。

    主表中的路由应部分复制到附加表中。如果服务器也是路由器(例如:运行 LXC、Docker、VM...),则应考虑更多路由,并可能将其复制到其他路由表中。当然,如果这些路由是动态的(在容器运行时出现),配置就会变得更加复杂。像往常一样,ip route get这里有很大帮助。

    因此,为每一端创建一个路由表(我将为这些表使用不那么任意的值 201 和 203),并仅复制与这一端相关的所需内容。添加在每个其中一条默认路由。仍然只能使用一条默认路由...但每个路由表只有一条。这里只添加默认路由就足以解决路由问题(实际上只需要路由表203)。如果布局发生变化(例如:路由容器...),则应再次考虑之前认为不需要添加的路由。另外,即使不总是使用,主路由表中仍然必须保留默认路由:这将是“默认”默认路由。当服务器作为客户端连接时没有定义源IP地址时,默认路由会影响自动选择。

    ip route add table 201 default via 192.168.201.1
    ip route add table 203 default via 192.168.203.1
    

    使用基于源的规则选择它们:

    ip rule add from 192.168.201.232 lookup 201
    ip rule add from 192.168.203.3 lookup 203
    

    结果:

    # ip route get from 192.168.203.3 192.168.1.30
    192.168.1.30 from 192.168.203.3 via 192.168.203.1 dev enp11s0 table 203 uid 0 
        cache 
    

    出接口切换为恩普11s0通过使用路由表203。

    # ip route get from 192.168.1.30 iif enp11s0 192.168.203.3
    local 192.168.203.3 from 192.168.1.30 dev lo table local 
        cache <local> iif enp11s0 
    

    因此,同一接口上的传入数据包不再使 SRPF 失败:同一接口。

    服务器的路由器也不会再混乱了。笔记本电脑的 ping 对这两个地址都有效。

    在服务器上,能够选择源地址的客户端应用程序将间接改变其流量选择的路由(例如:curl --interface 192.168.203.3 192.168.1.30ping -I 192.168.203.3 192.168.1.30但通常ping -I enp11s0 192.168.1.30不会仅有的此设置的原因在此详细描述顺丰问答解答我的)并且它会起作用。


注意:UDP 服务

上面最后一个项目中的配置将使 TCP 服务正常工作。但这对于 UDP 来说还不够,因为 BSD 套接字 API 默认的工作方式。

当侦听 TCP 套接字绑定到所有地址 (INADDR_ANY: 0.0.0.0) 并接受客户端连接(使用accept(2))时,新的TCP 套接字会自动创建,并选择查询的(本地)目的地作为绑定地址。因为新的 TCP 套接字绑定到适当的地址,所以在回复时,该地址将作为源地址呈现给路由堆栈,选择如上所述的适当的路由规则:TCP 一切正常。

当绑定到 INADDR_ANY 时,UDP 就不是那么简单了。没有自动创建新的套接字默认情况下没有机制告知查询是在哪里进行的。因此,回复将无法像 TCP 那样选择正确的源地址。在 OP 的情况下,当从 192.168.1.30 到 192.168.203.3 进行查询时,应用程序将没有可用的(本地)目的地 192.168.203.3 信息。它将在不绑定源地址的情况下进行回复(即:将其保留为 INADDR_ANY / 0.0.0.0),以推迟路由堆栈对源地址的选择。上述路由规则不会被选择,并且将使用主路由表的默认路由:错误的路由选择 192.168.201.232 作为回复源,而不是 192.168.203.3。虽然此回复将到达笔记本电脑(从路由角度和 SRPF 的角度来看这很好),但笔记本电脑本身会拒绝它,因为它不是来自它选择执行查询的地址。

多宿主环境中的服务器应用程序在多个端都可用,需要 UDP 的特殊支持。有两种常用方法可以做到这一点:

  • 分别绑定到每个服务器的地址而不是INADDR_ANY

    回复将使用套接字的绑定地址。由于查询已达到套接字,这意味着它被发送到该套接字将用作回复源地址的相同目标地址:客户端进行查询并且应用程序套接字绑定到的地址。

    例如 DNS 服务器就是这样的绑定9行为:它将单独绑定到服务器上的所有现有地址。

    socat在端口 1313 上提供日期的示例:运行三个socat命令,每个命令对应一个要绑定到的地址:

    socat UDP4-LISTEN:1313,bind=127.0.0.1,fork EXEC:date &
    socat UDP4-LISTEN:1313,bind=192.168.201.232,fork EXEC:date &
    socat UDP4-LISTEN:1313,bind=192.168.203.3,fork EXEC:date &
    
  • 使用套接字选项IP_PKTINFO(或某些 *BSD 上的 IP_RCVDSTADDR)绑定到 INADDR_ANY 时

    这需要特定的应用程序支持:connect(2)read(2)或者write(2)不能再在此类 UDP 套接字上使用,而是recvmsg(2)需要sendmsg(2)能够处理套接字选项提供的辅助消息,并使用其他方法检索查询中使用的实际(本地)目标地址(中描述cmsg(3))。

    例如这就是 DNS 服务器要做的事情不受约束的当使用interface-automatic选项。

    socat示例(在 Linux 上:ip-pktinfo,*BSD 将使用ip-recvdstaddr):

    socat -u \
        UDP4-RECVFROM:1313,ip-pktinfo,reuseport,fork \
        SYSTEM:'exec socat -u EXEC\:date UDP4-DATAGRAM\:$SOCAT_PEERADDR\:$SOCAT_PEERPORT\,bind=$SOCAT_IP_DSTADDR\:1313\,reuseport'
    

    第一个socat是仅接收的,并分叉第二个仅发出的,并使用从 IP_PKTINFO 套接字选项检索到的正确源地址进行回复,该选项从第一个环境变量中socat可用。 (SO_REUSEPORT) 是一种解决方法,允许两个“不相关”套接字共享同一端口(在实际应用程序中,不需要这样做,因为 UDP 套接字将被复制或根本不复制并直接使用)。socatreuseportfork()dup2(2)

答案2

对于通过一个接口发送所有非链路本地流量但通过多个接口接收非链路本地流量的系统存在两个问题。

第一个问题(您在这里遇到的)是反向路径过滤(看sysctl -ar '\.rp_filter')。此功能默认启用,并丢弃来自非响应发送接口的数据包(甚至在它们到达防火墙之前)。所以你必须将其设置0为接收接口。

另一个问题可能是沿途的防火墙只看到一半的流量,因此会丢弃回复数据包,因为它们不知道连接。在这种情况下,您需要高级路由(策略路由),请参阅man ip-ruleman ip-route。您必须设置额外的路由表并使相应的流量(传出数据包的源地址)使用该路由表。完成此操作后,反向路径过滤问题就自动解决了。

相关内容