![关于nat表格](https://linux22.com/image/802127/%E5%85%B3%E4%BA%8Enat%E8%A1%A8%E6%A0%BC.png)
我目前已在服务器上设置了 IPTables,以将特定接口 (venet0:1) 上的某些端口转发到另一台 IP 上的服务器。我的配置文件如下所示:
# Generated by iptables-save v1.4.12 on Sat Jun 8 08:36:54 2013
*mangle
:PREROUTING ACCEPT [480:39372]
:INPUT ACCEPT [480:39372]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [339:44328]
:POSTROUTING ACCEPT [339:44328]
COMMIT
# Completed on Sat Jun 8 08:36:54 2013
# Generated by iptables-save v1.4.12 on Sat Jun 8 08:36:54 2013
*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A PREROUTING -i venet0:1 -p tcp -m state --state NEW,RELATED,ESTABLISHED -m tcp --dport 51315 -j DNAT --to-destination 76.xxx.xxx.xxx
-A PREROUTING -i venet0:1 -p tcp -m state --state NEW,RELATED,ESTABLISHED -m tcp --dport 27015:27020 -j DNAT --to-destination 76.xxx.xxx.xxx
-A PREROUTING -i venet0:1 -p tcp -m state --state NEW,RELATED,ESTABLISHED -m tcp --dport 25565:25570 -j DNAT --to-destination 76.xxx.xxx.xxx
-A PREROUTING -i venet0:1 -p tcp -m state --state NEW,RELATED,ESTABLISHED -m tcp --dport 7777 -j DNAT --to-destination 76.xxx.xxx.xxx
COMMIT
# Completed on Sat Jun 8 08:36:54 2013
# Generated by iptables-save v1.4.12 on Sat Jun 8 08:36:54 2013
*filter
:INPUT ACCEPT [86:6572]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [66:6912]
-A INPUT -i venet0:1 -j LOG
-A INPUT -i venet0:1 -p tcp -m tcp --dport 51315 -j ACCEPT
-A INPUT -i venet0:1 -p tcp -m tcp --dport 27015:27020 -j ACCEPT
-A INPUT -i venet0:1 -p tcp -m tcp --dport 25565:25570 -j ACCEPT
-A INPUT -i venet0:1 -p tcp -m tcp --dport 7777 -j ACCEPT
COMMIT
# Completed on Sat Jun 8 08:36:54 2013
(隐藏 IP 地址)
我已确保启用了 IPv4 转发,但是当我执行 时lsmod
,什么都没有显示。
我也尝试过modprobe
添加 iptables 内核模块,但是没有找到任何东西。
会不会是 IPTables 模块没有安装,而我需要重新编译内核才能安装它们?
当我尝试连接这些端口时,连接被拒绝,就好像 iptables 根本没有运行一样。
我在 OpenVZ VPS(主机名实际上不是hostname
)上运行 Ubuntu 12.04 LTS。
Linux hostname 2.6.32-042stab076.7 #1 SMP Thu Apr 25 13:35:47 MSK 2013 x86_64 x86_64 x86_64 GNU/Linux
编辑:好的,根据其中一个答案的建议,我将其更改为venet0:1
。venet0
行为仍然相同。端口的 tcpdump 显示以下内容:
23:15:34.940437 IP 76.yyy.yyy.yyy.53802 > 192.xxx.xxx.xxx.51315: Flags [S], seq 3804882566, win 65535, options [mss 1460,nop,wscale 0,nop,nop,sackOK], length 0
23:15:34.940485 IP 76.yyy.yyy.yyy.53802 > 76.xxx.xxx.xxx.51315: Flags [S], seq 3804882566, win 65535, options [mss 1460,nop,wscale 0,nop,nop,sackOK], length 0
在上面的代码中,76.yyy.yyy.yyy 是我用来测试连接的计算机,192.xxx.xxx.xxx 是服务器的 IP,76.xxx.xxx.xxx 是它应该转发到的服务器的地址。它似乎以某种方式转发了流量,只是数据包的长度为零,而且从未得到回复。我还在接收机器上运行了 tcpdump,但什么也没出现。
答案1
我已确保启用了 IPv4 转发,但是当我执行 lsmod 时,什么都没有显示。
lsmod
仅显示已加载的模块。这与 几乎没有关系iptables
。iptables
在插入规则时会自动加载所需的模块,如果失败,它会通过漂亮的错误消息通知您。如果您的规则已成功加载,iptables
正在运行并且没有缺少任何模块。
此外,没有显示任何内容也是完全正常的lsmod
:这意味着该功能被编译到内核中。所以的输出lsmod
在这里完全不相关。
当我尝试连接这些端口时,连接被拒绝,就好像 iptables 根本没有运行一样。
-A 预路由 -ivenet0:1-p tcp -m state --state 新、相关、已建立 -m tcp --dport 51315 -j DNAT --to-destination 76.xxx.xxx.xxx
这里的问题很可能是venet0:1
不存在的。iptables
有这个限制,它接受任何接口名称,甚至是不存在的接口名称或看起来甚至不像接口名称的字符串(您甚至可以输入 IP 地址,只是为了好玩,它不起作用)。如果没有与给定名称匹配的接口,则规则将不匹配。当您的网络接口尚未准备好,或者您的网络接口是热插拔时,这很有用,但大多数时候,无法验证接口名称是否确实存在是一件很麻烦的事。很容易打错字。
相反,使用:
-A PREROUTING -i venet0 -p tcp -m state --state NEW,RELATED,ESTABLISHED -m tcp --dport 51315 -j DNAT --to-destination 76.xxx.xxx.xxx
现在,您可能会回答“但venet0:1
存在,ifconfig
表明它!”。
Exceptifconfig
是错误的。原因是什么?Linuxifconfig
已经过时、弃用、过时且糟糕。请使用ip addr
。和 以及可能还有其他的也一样route
。netstat
全部brctl
替换ip
它们。
ip addr
不要伪造或向内核隐藏任何信息。您看到的是网络堆栈的真实状态。现在您可以看到没有这样的venet0:1
接口。相反,venet0
有多个 IP 地址。这是自 Linux 2.2 时代以来一直支持的功能。
但是ifconfig
(或者实际上,它用于与内核通信的 BSD API)不支持一个接口有多个 IP 地址。因此,您可以使用这个称为“接口别名”的旧 BSD 技巧,您可以使用它ifconfig venet0:1
为配置额外的 IP 地址venet0
,它将显示为venet0:1
接口。除非venet0:1
不是接口。差得远。
实际上,ip addr
它会向您显示venet0:1
IP 地址的标签,手册页会告诉您:
In order to preserve compatibility with Linux-2.0 net aliases, this string
must coincide with the name of the device or must be prefixed with the
device name followed by colon.
手册页iptables
曾经告诉您不要使用接口别名或任何带有冒号的内容,但那行一定已经消失了。
答案2
关于nat
表格
您可以在iptables 手册页:
当遇到创建新连接的数据包时,就会查阅此表。
因此您不必在那里检查连接状态,因为该表仅检查NEW
连接。
让我们谈谈你的问题
基本上,您的虚拟机是一个简单的文件夹,其中设置并包含一个 Linux 系统树,让您感觉自己身处一个真正独立的系统中。这种虚拟化方法的独创性在于所有容器都在运行有且仅有一个Linux内核实例,主持人的一个。
现在您遇到了一个问题,因为您没有运行自己的内核实例,所以您无法完全控制,这解释了很多事情。
lsmod
是空的,因为出于安全原因,他们不会让您知道哪些模块正在运行系统,当然,他们也不会让您通过添加新模块来更改系统配置。想象一下,每个客户端都修改运行其他客户端的相同内核。即使你可以允许使用iptables对于容器来说,
nat
可能尚未启用。