是否可以将数据包从互联网转发到互联网上的另一个地址?
我发现的所有端口转发教程都侧重于 NAT 端口转发,但我只想将连接重定向到另一个公共地址,而且我似乎无法为此目的调整防火墙设置。这可能吗?
我正在使用iptables
/ufw
并且尝试了以下内容(在/etc/ufw/before.rules中):
:PREROUTING ACCEPT [0:0]
-A PREROUTING -i eth0 -d $VPS_PUBLIC_IP -p tcp --dport 80 -j DNAT --to-destination $PUBLIC_WEB_SERVER_IP:80
(我也尝试过*nat
在此之前添加该行,但是也出现了错误Bad argument '*nat'
。)
但是当我启动 ufw 时,出现“RULE_APPEND 失败(无效参数):链 PREROUTING 中的规则”错误。
我的最终目标是能够去(例如)https://1.2.3.4在浏览器中访问(公开托管的)网站https://9.8.7.6无需 VPN。
更新:我正在尝试从我的 PC 连接到 VPS 并转发到公共 Web 服务器。我的 VPS 除了转发连接之外应该什么都不做。
答案1
这是可能的,尽管您还需要为相同的数据包设置 SNAT 或 MASQUERADE 规则,这样最终目标主机就会将连接视为来自您而不是来自原始客户端。(这与从 LAN 到 LAN 的端口转发完全相同 - “发夹 NAT”是必要的,以防止回复数据包绕过您的网关,这样网关就没有机会取消 NAT。)
请注意,“dport”选项写为--dport
,而不是-dport
。 (后者表示-d
以port
作为目标 IP 地址。)
答案2
如果您希望用户能够通过连接 VPS 来访问网站,如下图所示,其中每个网络接口都在 WAN(Internet)上:
e.g. 1.2.3.4
┌───────┐
│ VPS │
└───────┘
▲ WAN (Internet)
┌───────┴───────┐
▼ ▼
┌────────┐ ┌─────────┐
│ User │ │ Website │
└────────┘ └─────────┘
e.g. 9.8.7.6 ← example.com
那么以下两种解决方案中的任何一种都可以实现这一点。
概述
首先,根据 Rusty Russell 的NAT 操作指南和 数据包过滤指南。您可以跳过此部分或稍后阅读,这样可能会更有意义,因为我最后写了这个概述。
(D-NAT) (S-NAT)
Incoming ╭──────────╮ ╭───────────╮ Outgoing
──▶│PREROUTING│ │POSTROUTING│──▶
╰──────────╯ ╰───────────╯
│ ▲
▼ ╭───────╮ │
Routing ──▶│FORWARD│────┤
Decision ╰───────╯ │
│ │
▼ │
╭─────╮ Local ╭──────╮
│INPUT│─▶ Process ─▶│OUTPUT│
╰─────╯ ╰──────╯
您可以在以下五个“钩子”中添加规则:
预路由 | 输入 | 向前 | 输出 | 路由后 |
---|
每个钩子都提供了某些规则可以利用的功能/扩展,例如 D-NAT 和 S-NAT。(编辑:不同的功能集实际上因表而异,例如“过滤器”(包括 INPUT、FORWARD、OUTPUT)和“nat”(包括 PREROUTING、INPUT、OUTPUT、POSTROUTING)。我现在对这些表的理解还不够深入。)
每个传入数据包都经过 PREROUTING,每个传出数据包都经过 POSTROUTING。在 PREROUTING(在“路由决策”处)之后,发往本地计算机的数据包将经过 INPUT,而其他数据包将经过 FORWARD。进程创建的新数据包首先经过 OUTPUT,然后经过 POSTROUTING,与已通过 FORWARD 的数据包一起经过。(注意:默认情况下可能禁用转发。)
每条规则都是有序规则链的一部分,规则从上到下进行评估(可以通过运行iptables -L -t filter
和 查看链iptables -L -t nat
)。每条规则都可以尝试匹配数据包的某些特征,如果匹配,则可以选择修改数据包,并决定是接受它(让它继续前进)、丢弃它还是跳转到另一条链。如果没有匹配的规则,则默认策略将决定是接受还是丢弃数据包。
将数据包转发到原始网络似乎是一件罕见或不寻常的事情,但它是可能的(见目标 NAT 到同一网络 并与 MASQUERADE 选项相关联。(通常情况下,您似乎希望阻止对机器的直接访问,因此您会将其放在专用网络中,就像在反向代理的情况下一样)。
要点是您需要:(1) 启用转发,(2) 更改传入数据包的目标地址,以及 (3) 更改数据包上的源地址,以便目标不会直接回复用户(正常配置的防火墙会阻止此操作)。发往另一个方向(网站到 VPS)的数据包将自动转发回用户。
如果可能的话,为了获得最大的安全性,你可能需要收紧下面规则的数据包匹配。(如果你像我一样,主要是为了学习而这样做,那么这可能并不重要,但在使用时最好记住这一点火牆壁。
临时解决方案
运行以下命令(改编自 Rusty Russell 2002 年NAT 操作指南部分4.1 和10) 添加两个新的 NAT 规则,一个在 PREROUTING 阶段,另一个在 POSTROUTING 阶段。如果您没有将相关 IP 地址定义为变量,请替换它们。
iptables -t nat -A PREROUTING -d $VPS_PUBLIC_IP -p tcp --dport 443 -j DNAT --to $PUBLIC_WEB_SERVER_IP
iptables -t nat -A POSTROUTING -d $PUBLIC_WEB_SERVER_IP -p tcp --dport 443 -j MASQUERADE
为了实现此功能,必须启用转发:
echo 1 > /proc/sys/net/ipv4/ip_forward
(看数据包如何穿越过滤器)
iptables
此处使用的参数细目(man iptables
详情请参阅):
-t nat
说使用NAT数据包匹配表:当遇到创建新连接的数据包时,将查询此表。它由四个内置函数组成:PREROUTING(用于在数据包进入时立即更改数据包)、INPUT(用于更改发往本地套接字的数据包)、OUTPUT(用于在路由之前更改本地生成的数据包)和 POSTROUTING(用于在数据包即将发出时更改数据包)。
-A PREROUTING
将规则附加到PREROUTING链。-A POSTROUTING
将规则附加到POSTROUTING 链。-d $VPS_PUBLIC_IP
当数据包的目的地是 VPS 时应用该规则,即用户1.2.3.4
在其浏览器中输入了该规则。-d $PUBLIC_WEB_SERVER_IP
当数据包的目的地是 Web 服务器的公共 IP 时应用该规则。在用户的数据包到达 VPS 并经过 PREROUTING 链(更改了目标地址)和 FORWARD 链(未更改任何内容)后,情况确实如此。-p tcp
匹配世界著名的TCP协议的数据包。--dport 443
匹配前往端口 443 (HTTPS) 的数据包。-j DNAT
代表“跳转到 DNAT(目标 NAT)”。我无法解释,但man iptables
表示:这指定了规则的目标;即,如果数据包匹配该规则,该做什么。目标可以是用户定义的链(除了此规则所在的链),也可以是立即决定数据包命运的特殊内置目标之一,或者扩展(请参阅下面的扩展)。
以及来自
man iptables-extensions
基因转移酶虚拟状态,如果原始目的地与答复源不同则匹配。
--to $PUBLIC_WEB_SERVER_IP
改变数据包 目的地IP(因为德将网络地址转换 (NAT) 设置为 Web 服务器的 IP。-j MASQUERADE
将源 IP 更改为 VPS 的 IP,相当于-j SNAT --to $VPS_PUBLIC_IP
。这会使 Web 服务器响应 VPS,然后 VPS 解开数据包并将其转发给用户。如果没有这个,服务器将直接响应用户,而用户的防火墙很可能会拒绝它,因为这是防火墙无法识别的新连接。有关详细信息,请参阅 Netfilter 的连接跟踪系统 和说如何破坏数据包。
如果 VPS IP 未在证书中列为 SAN(主题备用名称),您将收到 SSL 证书警告。
永久解决方案
为了使其永久使用ufw
(不复杂的防火墙),请将以下内容添加到 /etc/ufw/before.rules(用 VPS 和 Web 服务器的实际 IP 地址替换)。
注意:默认情况下,ufw 将 FORWARD 策略设置为“拒绝”(在 中也显示为“DROP” iptables -L -t filter
)。这就是-A FORWARD ... -j ACCEPT
需要该规则的原因。如果您的默认策略是 ACCEPT(如 中所示ufw default allow routed
),则不需要该规则。
*nat
-A PREROUTING -d $VPS_PUBLIC_IP -p tcp --dport 443 -j DNAT --to $PUBLIC_WEB_SERVER_IP
-A POSTROUTING -d $PUBLIC_WEB_SERVER_IP -p tcp --dport 443 -j MASQUERADE
COMMIT
*filter
-A FORWARD -d $PUBLIC_WEB_SERVER_IP -p tcp --dport 443 -j ACCEPT
COMMIT
确保将其放在文件末尾,现有COMMIT
行之后。此外,请确保您不要因为阅读了此答案而将自己锁定在 SSH 之外。
然后打开 /etc/ufw/sysctl.conf 并取消注释“取消注释此内容以允许此主机在接口之间路由数据包”的行,因此结果应该是:
net/ipv4/ip_forward=1
net/ipv6/conf/default/forwarding=1
net/ipv6/conf/all/forwarding=1
然后启用 ufw:
ufw enable
如果您通过 SSH 连接,系统会要求您确认,以防启用 ufw 会阻止端口 22 并将您锁定。这种情况不会发生,因此只需输入“y”并按回车键即可。如果您担心,请先通过 VPS 控制面板进行备份/快照。
测试一下是否有效。运行后iptables -L -t filter
你会看到如下一行:
ACCEPT tcp -- 0.0.0.0/0 example.com tcp dpt:443
靠近顶部,在标题为“Chain FORWARD (policy DROP)”的部分下。如果您运行,iptables -L -t nat
您应该会在标题为“Chain PREROUTING (policy ACCEPT)”和“Chain POSTROUTING (policy ACCEPT)”的部分下看到您的规则。
有关详细信息,请参阅联邦水务局,man ufw
和man ufw-framework
。
做出改变
如果需要进行更改,您可能应该
iptables -F -t nat
首先运行以清除 PREROUTING 和 POSTROUTING 链中的规则,否则可能会得到重复的规则。如果您需要清除 FORWARD 链中的规则,
不跑步iptables -F -t filter
,因为你的 SSH 会话将会中断(如果 INPUT 链的默认策略是拒绝/DROP)我还没有找到防止这种情况发生的方法(即使您更改了默认策略,当您将其改回拒绝时,它也会中断)。如果reboot
您不介意的话,或者删除特定规则:首先使用列出它们
iptables -L --line-numbers -t filter
,然后使用删除iptables -D FORWARD 7
(例如删除第 7 条规则)。
然后重启 ufw:systemctl restart ufw
答案3
正如另一个答案中提到的那样,“无效参数”错误可能是因为您需要写--dport
而不是dport
。
修复此问题后,规则可能会被接受,但可能不会完全按照您的要求执行。我在此假设您在运行浏览器的同一台计算机上添加规则,并且它不是位于两者之间的单独防火墙计算机。在这种情况下,数据包将不会通过 PREROUTING 链,该链仅用于通过此机器路由的数据包。要使本地生成的数据包能够进行 NAT,您需要在 OUTPUT 链中添加 DNAT 规则(而不是 nat 表)。完整的命令将是:
iptables -t nat -A OUTPUT -i eth0 -d $VPS_PUBLIC_IP -p tcp -m tcp --dport 80 -j DNAT --to-destination $PUBLIC_WEB_SERVER_IP:80
请注意,您实际上不需要有逆 SNAT 规则,因为对于从您这边(例如在浏览器中)发起的连接,连接跟踪将知道对属于同一连接的返回数据包进行逆转换。
答案4
我不能代表 ufw 发言,但是直接使用 iptables 时,nat 规则必须在 nat 表中,这意味着您需要在“-A prerouting”之后在命令行中使用“-t nat”。