概述

概述

是否可以将数据包从互联网转发到互联网上的另一个地址?

我发现的所有端口转发教程都侧重于 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。 (后者表示-dport作为目标 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.110) 添加两个新的 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 ufwman 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”。

相关内容