从路由器转发时,数据包在网络接口和 iptables 之间的某个地方被丢弃

从路由器转发时,数据包在网络接口和 iptables 之间的某个地方被丢弃

我有一台配置了多个接口和多个 VLAN 的服务器。它在所有本地网络上都运行良好,但由于某种原因,它会丢弃通过我的路由器转发的数据包。而且它甚至不稳定。有时我可以让它工作几天,然后它又开始丢包。我很想继续挖掘,但我从 Google 上得到的唯一结果就是需要帮助设置 iptables 的人。

配置

$ cat /etc/issue
Ubuntu 18.04.4 LTS \n \l
$ cat /etc/netplan/50-cloud-init.yaml
network:
    version: 2
    ethernets:
        enp10s0:
            dhcp4: true
            dhcp6: true
        enp6s0:
            dhcp4: false
            dhcp6: false
    vlans:
        vlan18:
            id: 18
            link: enp6s0
            dhcp4: true
            optional: true
        vlan150:
            id: 150
            link: enp6s0
            dhcp4: true
            optional: true
        vlan155:
            id: 155
            link: enp6s0
            dhcp4: true
            optional: true

有问题的接口是enp10s0。我在 VLAN 中启用了它enp6s0一段时间,但为了隔离变量,我将其移至单独的 NIC。这并没有改变任何东西。

$ netstat -s enp10s0
Ip:
    Forwarding: 2
    4207683 total packets received
    11 with invalid addresses
    0 forwarded
    0 incoming packets discarded
    4197424 incoming packets delivered
    2183348 requests sent out
    21 outgoing packets dropped
Tcp:
    1634 active connection openings
    1615 passive connection openings
    150 failed connection attempts
    1100 connection resets received
    43 connections established
    4207863 segments received
    2190261 segments sent out
    596 segments retransmitted
    0 bad segments received
    222 resets sent

测试

设置

我将以下第一行添加到我的 iptables INPUT 链中:

-p tcp -m tcp --dport 22 -j LOG --log-prefix "IPTABLES SEEN: "

我使用 tcpdump 观察流量:

tcpdump -n -e -vv -i enp10s0 port 22

步骤 1:证明它在本地有效

从我的路由器10.8.10.1telnet 到有问题的服务器10.8.10.11 port 22

iptables 日志:

Jul 15 23:58:04 meji kernel: IPTABLES SEEN: IN=enp10s0 OUT= MAC=60:a4:4c:60:ce:ce:e0:63:da:21:c1:a5:08:00 SRC=10.8.10.1 DST=10.8.10.11 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=44677 DF PROTO=TCP SPT=48770 DPT=22 WINDOW=14600 RES=0x00 SYN URGP=0

tcpdump 日志:

23:58:04.335447 e0:63:da:21:c1:a5 > 60:a4:4c:60:ce:ce, ethertype IPv4 (0x0800), length 74: (tos 0x0, ttl 64, id 44677, offset 0, flags [DF], proto TCP (6), length 60)
    10.8.10.1.48770 > 10.8.10.11.22: Flags [S], cksum 0xbb2d (correct), seq 978415077, win 14600, options [mss 1460,sackOK,TS val 25150304 ecr 0,nop,wscale 7], length 0

SYN ACK 按照您预期的那样进行,一切正常。

第 2 步:与路由器转发的连接进行比较

我使用nc -vz我的远程服务器(34.73.148.195)连接到同一个ip/端口。

tcpdump 日志:

00:54:44.427670 e0:63:da:21:c1:a5 > 60:a4:4c:60:ce:ce, ethertype IPv4 (0x0800), length 74: (tos 0x0, ttl 56, id 18829, offset 0, flags [DF], proto TCP (6), length 60)
    34.73.148.195.50176 > 10.8.10.11.22: Flags [S], cksum 0x8c20 (correct), seq 1566819019, win 65320, options [mss 1420,sackOK,TS val 1249821436 ecr 0,nop,wscale 6], length 0

iptables 日志:

沒有任何事。沒有任何事被記錄。

没有 SYN ACK,片刻之后又尝试重新传输。NIC 没有报告错误,iptables 什么也没看到,我只能挠头了。我该从哪里开始查找?开始深入研究内核?网络驱动程序?


额外要求的信息

$ ip route show
default via 10.8.8.1 dev vlan18 proto dhcp src 10.8.8.11 metric 100 
default via 10.8.50.1 dev vlan150 proto dhcp src 10.8.50.5 metric 100 
10.8.8.0/24 dev vlan18 proto kernel scope link src 10.8.8.11 
10.8.8.1 dev vlan18 proto dhcp scope link src 10.8.8.11 metric 100 
10.8.10.0/24 dev enp10s0 proto kernel scope link src 10.8.10.11 
10.8.50.0/24 dev vlan150 proto kernel scope link src 10.8.50.5 
10.8.50.1 dev vlan150 proto dhcp scope link src 10.8.50.5 metric 100 
10.8.55.0/24 dev vlan155 proto kernel scope link src 10.8.55.5 

更多 iptables 内容。但是当我清除所有规则并将所有策略更改为“接受”时,我仍然遇到相同的问题。我确信我已经消除了 iptables 规则作为罪魁祸首的问题。

# iptables -vL
Chain INPUT (policy DROP 442K packets, 81M bytes)
 pkts bytes target     prot opt in     out     source               destination         
 348M  494G ACCEPT     all  --  any    any     anywhere             anywhere             state RELATED,ESTABLISHED
1692K  301M ACCEPT     all  --  lo     any     anywhere             anywhere             /* Loopback Interface */
 327K   24M ACCEPT     all  --  vlan18 any     anywhere             anywhere
 174K   14M ACCEPT     all  --  vlan155 any     anywhere             anywhere
    0     0 ACCEPT     tcp  --  enp10s0 any     anywhere             anywhere             tcp dpt:ssh state NEW,ESTABLISHED /* Ssh Passthrough */

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 190M packets, 17G bytes)
 pkts bytes target     prot opt in     out     source               destination  
# iptables --list --table raw
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
# iptables --list --table mangle
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
# iptables --list --table nat
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source    

答案1

系统默默丢弃数据包的原因有很多,但这种情况非常简单:你看到的结果是什么ip r g 34.73.148.195?由于除了 10.8.10.0/24 之外,你没有任何通过 enp10s0 的路由,因此你可以禁用 rp_filter ...或添加一些/正确的默认路由:

ip r a default via 10.8.10.1 dev enp10s0 metric 50

毕竟,是路由器,而不是当地的网络在 vlan18 或 vlan150 上,不是吗?为什么要通过 vlan18 或 vlan150 访问外部世界?

由于 enp10s0 也是 DHCP 配置的,因此问题在于您的路由器未在服务器上设置默认路由。这解释了缺乏一致性的原因 - 如果路由出现,则您获得连接,如果路由消失,则您没有连接。

需要说明的是:在这样的服务器上使用 DHCP 绝对不是一个好主意。即使默认路由配置为静态且度量值较低(如上所述),一个恶意 DHCP 服务器也可以轻松插入更具体的网络;请考虑在 vlan18/150 上提供的 10.8.10.0/31(或实际上任何不超过 /25 的地址)——这样的地址肯定会将您排除在外恰当的(?) 通过 enp10s0 的默认路由。如果路由器是你的,并且你想使用它作为默认路由,并仍保留其他(本地)接口上的 DHCP 配置,考虑使用 /31(或至少“经典”/30)连接地址。

无论如何,您的服务器是否应该通过 vlan18 或 vlan150 从外部世界访问,并通过其各自路由器上的某些其他转发规则进行访问?如果是这样,您将不得不应对基于策略的路由,因为响应数据包必须通过传入数据包的接口发送。毕竟,您在这里没有公共 IP,因此它不适用于非对称路由(一般不禁止)。

实际上,由于您无法进行非对称路由(没有公共 IP)并且没有基于策略的路由,因此您不应禁用 rp_filter - 这只会隐藏真正的问题。它无论如何都不起作用 - 您的路由器转发的数据包(可能是 DNAT 的)将被传送到您的服务器,但响应将传送到 vlan18 或 vlan150,而不是具有适当的 conntrack 条目并拥有发起连接的地址的路由器。

就这个问题而言 - 您可能会隐藏所有与 iptables 相关的内容。每次看到“静默”丢弃(即在 iptables 计数器中不可见)时,甚至不必费心进一步调查 netfilter 层中的问题。这可能是 NIC 丢弃(缓冲区问题、CPU 不足) - 可以使用 tcpdump、TTL 过期(转发时,对于具有非本地目的地的数据包)或某些内部过滤(如这里)(反向路径一)轻松验证。

答案2

在数据包到达 FILTER 表的 INPUT 链之前,它需要经过以下表/链:

表链

  1. 原始预路由
  2. mangle-PREROUTING
  3. nat-PREROUTING
  4. mangle-INPUT

默认情况下,即如果您省略 --table 参数,则您正在查看 FILTER 表。此外,在到达 filter-INPUT 之前,会在 nat-PREROUTING 和 mangle-INPUT 之间做出路由决策(即,如果路由决策得出结论认为数据包不是发往您的本地主机的,则它永远不会到达 filter-INPUT 链,而是进入 mangle-FORWARD / filter-FORWARD 链)。您可以尝试以下操作:

1.) 像上面一样为上述表和链添加日志条目。你能看到条目吗?它们在哪里停止?

2.)通过发出

iptables --list --table xxx
iptables --list-rules --table xxx

命令(其中 xxx 是 raw、mangle、nat)

3.) 仔细检查路由器 10.8.10.1 上的转发规则 => 它们是否确实到达了您的主机?

希望有所帮助。

(编辑)

我想到另一件事是,你的接口上唯一的路由是针对本地网络的,换句话说,如果路由器没有伪装从外界进入主机的数据包,那么这些数据包将被视为不可路由,因此会被反向路径过滤丢弃——你可能需要检查rp_filter 和 LPIC-3 Linux 安全

相关内容