使用 OUTPUT 链中的 DNAT 重定向本地发起的流量无法按预期工作

使用 OUTPUT 链中的 DNAT 重定向本地发起的流量无法按预期工作

我有点傻了,我希望你们可爱的人能启动我的大脑。

我正在本地网络命名空间中运行服务。命名空间看起来像这样:

# ip -n ns1 addr
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
2: ns1-int@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 6e:35:ab:46:78:71 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.168.255.11/24 scope global ns1-int
       valid_lft forever preferred_lft forever
    inet6 fe80::6c35:abff:fe46:7871/64 scope link
       valid_lft forever preferred_lft forever

命名空间路由表如下所示:

$ ip -n ns1 route
default via 192.168.255.1 dev ns1-int
192.168.255.0/24 dev ns1-int proto kernel scope link src 192.168.255.11

其中接口是连接到主机上的ns1-int一对的一端。 192.168.255.1 是以下地址:vethbr0br0

# ip addr show br0
4: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether ce:10:da:46:71:fb brd ff:ff:ff:ff:ff:ff
    inet 192.168.255.1/24 scope global br0
       valid_lft forever preferred_lft forever
    inet6 fe80::cc10:daff:fe46:71fb/64 scope link
       valid_lft forever preferred_lft forever
# ip addr show master br0
5: ns1-ext@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br0 state UP group default qlen 1000
    link/ether d6:69:bd:06:9c:fa brd ff:ff:ff:ff:ff:ff link-netns ns1
    inet6 fe80::d469:bdff:fe06:9cfa/64 scope link
       valid_lft forever preferred_lft forever

我正在运行一个简单的网络服务在端口 80 上;我可以使用命名空间地址从主机访问它:

# curl 192.168.255.11
Hostname: node1
IP: 127.0.0.1
IP: ::1
IP: 192.168.255.11
IP: fe80::6c35:abff:fe46:7871
RemoteAddr: 192.168.255.1:58396
GET / HTTP/1.1
Host: 192.168.255.11
User-Agent: curl/8.0.1
Accept: */*

我想在主机端口 8080 上公开此服务,两者都用于远程发起流量对于本地发起的流量。

远程流量没问题:

iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 192.168.255.11:80

这很好用;现在,我可以从网络上的另一台主机访问端口 8080 上的同一 Web 端点:

anotherhost$ curl 192.168.121.67:8080
Hostname: node1
IP: 127.0.0.1
IP: ::1
IP: 192.168.255.11
IP: fe80::6c35:abff:fe46:7871
RemoteAddr: 192.168.121.1:47888
GET / HTTP/1.1
Host: 192.168.121.67:8080
User-Agent: curl/8.0.1
Accept: */*

我还希望能够使用例如 8080 端口本地访问该服务curl localhost:8080。理论上,要重定向本地生成的流量,我们只需要OUTPUT链中的一条规则:

iptables -t nat -A OUTPUT -p tcp --dport 8080 -j DNAT --to-destination 192.168.255.11:80

此时完整的网络文件配置如下所示:

# iptables-save
# Generated by iptables-save v1.8.9 on Sun Jun 11 00:47:49 2023
*filter
:INPUT ACCEPT [751:53502]
:FORWARD ACCEPT [10:937]
:OUTPUT ACCEPT [433:43385]
COMMIT
# Completed on Sun Jun 11 00:47:49 2023
# Generated by iptables-save v1.8.9 on Sun Jun 11 00:47:49 2023
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [21:1580]
:POSTROUTING ACCEPT [22:1640]
-A PREROUTING -p tcp -m tcp --dport 8080 -j DNAT --to-destination 192.168.255.11:80
-A OUTPUT -p tcp -m tcp --dport 8080 -j DNAT --to-destination 192.168.255.11:80
COMMIT
# Completed on Sun Jun 11 00:47:49 2023

尝试访问localhost:8080就会被卡住:

$ curl --connect-timeout 60 localhost:8080
curl: (28) Failed to connect to localhost port 8080 after 60001 ms: Timeout was reached

规则OUTPUT肯定是匹配的;当我运行该curl命令时,我可以看到点击计数器递增。我觉得我错过了一些简单的东西。会是什么呢?

答案1

为了使链DNAT中的规则OUTPUT正常工作,我们需要做两件事。

  1. 我们需要设置适当的route_localnetsysctl:

    sysctl -w net.ipv4.conf.br0.route_localnet
    

    通过这一更改,我们将看到命名空间内显示以下流量:

    03:23:02.984603 ns1-int In  IP 127.0.0.1.39656 > 192.168.255.11.80: Flags [S], seq 409674911, win 65495, options [mss 65495,sackOK,TS val 2257175047 ecr 0,nop,wscale 7], length 0
    

    这是有问题的,因为源地址 ( 127.0.0.1) 没有用,所以......

  2. 我们需要MASQUERADE制定交通规则 localhost 命名空间:

    iptables -t nat -A POSTROUTING -s 127.0.0.1/32 -d 192.168.255.0/24 -j MASQUERADE
    

有了这两条规则,事情就会按预期进行:

# curl localhost:8080
Hostname: node1
IP: 127.0.0.1
IP: ::1
IP: 192.168.255.11
IP: fe80::8054:55ff:fef7:3e76
RemoteAddr: 192.168.255.1:36676
GET / HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.0.1
Accept: */*

在命名空间内,我们看到传入的数据包现在如下所示:

03:26:38.660882 ns1-int In  IP 192.168.255.1.38500 > 192.168.255.11.80: Flags [S], seq 1141073629, win 65495, options [mss 65495,sackOK,TS val 2257390724 ecr 0,nop,wscale 7], length 0

相关内容