简单有状态防火墙
本页面解释了如何使用 iptables 设置有状态防火墙。 它还解释了规则的含义以及为什么需要这些规则。 为了简单起见,它分为两个主要部分。 第一部分介绍单机防火墙,第二部分在第一部分防火墙的基础上设置 NAT 网关。
先决条件
首先,安装用户空间实用程序 iptables 或验证它们是否已安装。
本文假设当前没有设置 iptables 规则。 要检查当前规则集并验证当前没有规则,请运行以下命令
# iptables-save
# Generated by iptables-save v1.4.19.1 on Thu Aug 1 19:28:53 2013 *filter :INPUT ACCEPT [50:3763] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [30:3472] COMMIT # Completed on Thu Aug 1 19:28:53 2013
或
# iptables -nvL --line-numbers
Chain INPUT (policy ACCEPT 156 packets, 12541 bytes) num pkts bytes target prot opt in out source destination Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 82 packets, 8672 bytes) num pkts bytes target prot opt in out source destination
如果有规则,您可以通过加载默认规则集来重置规则
# iptables-restore < /etc/iptables/empty.rules
否则,请参阅Iptables#重置规则。
单机防火墙
创建必要的链
对于此基本设置,我们将创建两个用户定义的链,我们将使用它们在防火墙中打开端口。
# iptables -N TCP # iptables -N UDP
链当然可以具有任意名称。 我们选择这些名称只是为了匹配我们稍后在规则中要处理的协议,这些协议使用协议选项指定,例如,始终使用 -p tcp
。
FORWARD 链
如果您想将您的机器设置为 NAT 网关,请查看#设置 NAT 网关。 但是,对于单机而言,我们只需将 FORWARD 链的策略设置为 DROP 并继续。
# iptables -P FORWARD DROP
OUTPUT 链
OUTPUT 链可以是过滤出站流量的强大工具,特别是对于不运行 Web 浏览器或需要连接到 Internet 上任意目的地的对等工具的服务器和其他设备。 但是,正确设置 OUTPUT 链需要有关系统预期用途的信息。 桌面系统、笔记本电脑系统、云服务器和家庭/本地服务器的安全规则集将非常不同。
在这个简单的示例中,我们将通过将 OUTPUT 链的默认策略设置为 ACCEPT 来允许所有出站流量。 这种方式安全性较低,但与许多系统高度兼容。
# iptables -P OUTPUT ACCEPT
INPUT 链
与之前的链类似,如果某些东西以某种方式绕过了我们的规则,我们将 INPUT 链的默认策略设置为 DROP。 丢弃所有流量并指定允许的内容是创建安全防火墙的最佳方法。
- 添加下面的第一个 INPUT 链规则(它将保持会话打开),
- 添加一个常规规则以允许入站 SSH(以便在连接断开时能够重新连接)并且
- 设置策略。
# iptables -P INPUT DROP
任何网络接口接收到的每个数据包都将首先通过 INPUT 链,如果它以这台机器为目标。 在此链中,我们确保只接受我们想要的数据包。 有关显示数据包如何遍历这些内置链的简化 ASCII 图,请参阅数据包如何遍历过滤器。
添加到 INPUT 链的第一个规则将允许属于已建立连接的流量,或与这些连接相关的新有效流量,例如 ICMP 错误或回显回复(主机在被 ping 时返回的数据包)。 ICMP 代表 Internet 控制消息协议。 一些 ICMP 消息非常重要,有助于管理拥塞和 MTU,并被此规则接受
# iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
连接状态 ESTABLISHED
意味着另一个规则先前允许了初始 (--ctstate NEW
) 连接尝试,或者连接已经处于活动状态(例如,活动的远程 SSH 连接)。
第二个规则将接受来自“环回”(lo) 接口的所有流量,这对于许多应用程序和服务是必需的。
# iptables -A INPUT -i lo -j ACCEPT
第三个规则将丢弃所有状态匹配为“INVALID”的流量。 流量可以分为四个“状态”类别:NEW、ESTABLISHED、RELATED 或 INVALID,这就是使其成为“有状态”防火墙而不是安全性较低的“无状态”防火墙的原因。 状态使用“nf_conntrack_*”内核模块进行跟踪,当您添加规则时,内核会自动加载这些模块。
- 此规则将丢弃所有具有无效标头或校验和、无效 TCP 标志、无效 ICMP 消息(例如,当我们没有向主机发送任何内容时,端口不可达)以及可能由序列预测或其他类似攻击引起的乱序数据包。 “DROP”目标将丢弃数据包而不进行任何响应,这与礼貌地拒绝数据包的 REJECT 相反。 我们使用 DROP 是因为对于 INVALID 数据包没有合适的“REJECT”响应,并且我们不想确认我们收到了这些数据包。
- ICMPv6 邻居发现数据包仍然未被跟踪,并且将始终被归类为“INVALID”,尽管它们没有损坏或其他问题。 请记住这一点,并在该规则之前接受它们! 以 root 身份运行
iptables -A INPUT -p 41 -j ACCEPT
。
# iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
下一个规则将接受所有新的传入 ICMP 回显请求,也称为 ping。 只有第一个数据包才算作 NEW,其他数据包将由 RELATED、ESTABLISHED 规则处理。 由于计算机不是路由器,因此不需要允许其他状态为 NEW 的 ICMP 流量。
# iptables -A INPUT -p icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT
现在,我们将 TCP 和 UDP 链附加到 INPUT 链,以处理所有新的传入连接。 一旦连接被 TCP 或 UDP 链接受,它将由 RELATED/ESTABLISHED 流量规则处理。 TCP 和 UDP 链将接受新的传入连接,或礼貌地拒绝它们。 新的 TCP 连接必须以 SYN 数据包开始。
# iptables -A INPUT -p udp -m conntrack --ctstate NEW -j UDP # iptables -A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP
NEW
不一定意味着 --syn
。 但是,匹配 “NEW
但不匹配 --syn
” 的数据包很少是恶意的,不应直接丢弃。 相反,它们只是被下一个规则使用 TCP RESET 拒绝。 此外,--syn
不等同于 --tcp-flags SYN SYN
。 有关详细信息,请参阅iptables-extensions(8)。如果端口未打开,我们使用 TCP RESET 数据包拒绝 TCP 连接,并使用 ICMP 端口不可达消息拒绝 UDP 流。 这模仿了 Linux 的默认行为(符合 RFC),并且允许发送者快速关闭连接并清理。
# iptables -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable # iptables -A INPUT -p tcp -j REJECT --reject-with tcp-reset
对于其他协议,我们在 INPUT 链中添加最终规则,以使用 icmp 协议不可达消息拒绝所有剩余的传入流量。 这模仿了 Linux 的默认行为。
# iptables -A INPUT -j REJECT --reject-with icmp-proto-unreachable
生成的 iptables.rules 文件
运行上述所有命令后,iptables.rules
文件的示例
/etc/iptables/iptables.rules
# Generated by iptables-save v1.4.18 on Sun Mar 17 14:21:12 2013 *filter :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] :TCP - [0:0] :UDP - [0:0] -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -m conntrack --ctstate INVALID -j DROP -A INPUT -p icmp -m icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT -A INPUT -p udp -m conntrack --ctstate NEW -j UDP -A INPUT -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j TCP -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable -A INPUT -p tcp -j REJECT --reject-with tcp-reset -A INPUT -j REJECT --reject-with icmp-proto-unreachable COMMIT # Completed on Sun Mar 17 14:21:12 2013
可以使用以下命令生成和保存此文件
# iptables-save -f /etc/iptables/iptables.rules
可用于继续以下部分。 如果您通过 SSH 远程设置防火墙,请在继续之前附加以下规则以允许新的 SSH 连接(根据需要调整端口)
# iptables -A TCP -p tcp --dport 22 -j ACCEPT
TCP 和 UDP 链
TCP 和 UDP 链包含用于接受到特定端口的新传入 TCP 连接和 UDP 流的规则。
开放端口以接受传入连接
要接受端口 80 上 Web 服务器的传入 TCP 连接
# iptables -A TCP -p tcp --dport 80 -j ACCEPT
要接受端口 443 上 Web 服务器 (HTTPS) 的传入 TCP 连接
# iptables -A TCP -p tcp --dport 443 -j ACCEPT
要允许远程 SSH 连接(在端口 22 上)
# iptables -A TCP -p tcp --dport 22 -j ACCEPT
要接受 DNS 服务器(端口 53)的传入 TCP/UDP 请求
# iptables -A TCP -p tcp --dport 53 -j ACCEPT # iptables -A UDP -p udp --dport 53 -j ACCEPT
有关更高级的规则,例如匹配多个端口,请参阅iptables(8)。
端口敲门
端口敲门是一种外部打开端口的方法,默认情况下,防火墙会保持端口关闭。 它的工作原理是要求连接尝试一系列预定义的关闭端口。 当接收到正确的端口“敲击”(连接尝试)序列时,防火墙会打开某些端口以允许连接。 有关更多信息,请参阅端口敲门。
防止欺骗攻击
rp_filter
当前在 /usr/lib/sysctl.d/50-default.conf
中默认设置为 2
,因此以下步骤不是必需的。阻止来自 Internet 或本地网络的保留本地地址通常通过将 sysctl 中的 rp_filter
(反向路径过滤器)设置为 1 来完成。 为此,请将以下行添加到您的 /etc/sysctl.d/90-firewall.conf
文件中(有关详细信息,请参阅sysctl),以启用 Linux 内核本身内置的源地址验证。 内核的验证将比每个案例的单个 iptables 规则更好地处理欺骗。
net.ipv4.conf.all.rp_filter=1
如果需要统计信息(和更好的日志记录),则可以使用 netfilter 代替
# iptables -t mangle -I PREROUTING -m rpfilter --invert -j DROP
对于使用非对称路由的特定设置,需要使用 rp_filter=2
sysctl 选项。向 rpfilter
模块传递 --loose
开关将使用 netfilter 完成相同的操作。
“隐藏”你的计算机
如果您正在运行桌面计算机,阻止一些传入请求可能是一个好主意。
阻止 ping 请求
“Ping” 请求是一个发送到目标地址的 ICMP 数据包,以确保设备之间的连通性。如果您的网络运行良好,您可以安全地阻止所有 ping 请求。重要的是要注意,这实际上并不会隐藏您的计算机 —— 发送给您的任何数据包都会被拒绝,因此您仍然会在对 IP 范围进行简单的 nmap “ping 扫描”中显示出来。
这是一种基本的“保护”,并且会在将来调试问题时使生活变得困难。这应该仅用于教育目的。
要阻止回显请求,请将以下行添加到您的 /etc/sysctl.d/90-firewall.conf
文件中(有关详细信息,请参阅 sysctl)
net.ipv4.icmp_echo_ignore_all = 1
更多信息请参见 iptables(8),或阅读网页上的文档和示例 http://www.snowman.net/projects/ipt_recent/
欺骗端口扫描器
- 这会使您面临一种 DoS 攻击形式。攻击者可以发送带有欺骗 IP 的数据包,并阻止它们连接到您的服务。
- 如果模块 conntrack 将来自此地址到目标端口的一些数据包视为 INVALID,则此技巧可能会阻止合法的 IP 地址。为了避免列入黑名单,一种解决方法是允许所有定向到该特定目标端口的数据包。
攻击者使用端口扫描来识别您计算机上的开放端口。这使他们能够识别和指纹识别您正在运行的服务,并可能针对它们发起漏洞利用。
INVALID 状态规则将处理除 UDP、ACK 和 SYN 扫描(在 nmap 中分别为 -sU
、-sA
和 -sS
)之外的所有类型的端口扫描。
ACK 扫描 不用于识别开放端口,而是用于识别被防火墙过滤的端口。由于对状态为 NEW 的所有 TCP 连接进行 SYN 检查,因此 ACK 扫描发送的每个数据包都将被 TCP RESET 数据包正确拒绝。一些防火墙会丢弃这些数据包,这允许攻击者绘制出防火墙规则。
recent 模块可用于欺骗剩余两种类型的端口扫描。recent 模块用于将主机添加到“最近”列表,该列表可用于指纹识别和阻止某些类型的攻击。当前的 recent 列表可以在 /proc/net/xt_recent/
中查看。
SYN 扫描
在 SYN 扫描中,端口扫描器向每个端口发送 SYN(同步)数据包以启动 TCP 连接。关闭的端口返回 TCP RESET 数据包,或被严格的防火墙丢弃,而开放的端口返回 SYN ACK 数据包。
recent
模块可用于跟踪连接尝试被拒绝的主机,并为其发送到开放端口的任何 SYN 数据包返回 TCP RESET,就好像该端口已关闭一样。如果开放端口是第一个被扫描的端口,则仍将返回 SYN ACK,因此需要运行非标准端口上的应用程序(如 ssh)才能使其始终如一地工作。
首先,在 TCP 链的顶部插入一条规则。此规则向过去 60 秒内进入 TCP-PORTSCAN
列表的任何主机响应 TCP RESET。--update
开关导致 recent 列表被更新,这意味着 60 秒计数器被重置。
# iptables -I TCP -p tcp -m recent --update --rsource --seconds 60 --name TCP-PORTSCAN -j REJECT --reject-with tcp-reset
接下来,需要修改拒绝 TCP 数据包的规则,以将具有被拒绝数据包的主机添加到 TCP-PORTSCAN
列表。
# iptables -D INPUT -p tcp -j REJECT --reject-with tcp-reset # iptables -A INPUT -p tcp -m recent --set --rsource --name TCP-PORTSCAN -j REJECT --reject-with tcp-reset
UDP 扫描
UDP 端口扫描类似于 TCP SYN 扫描,不同之处在于 UDP 是一种“无连接”协议。没有握手或确认。相反,扫描器向每个 UDP 端口发送 UDP 数据包。关闭的端口应返回 ICMP 端口不可达消息,而开放的端口不返回响应。由于 UDP 不是“可靠”的协议,因此扫描器无法知道数据包是否丢失,并且必须对每个未返回响应的端口进行多次检查。
Linux 内核发送 ICMP 端口不可达消息的速度非常慢,因此对 Linux 机器进行完整的 UDP 扫描将花费超过 10 个小时。但是,仍然可以识别常用端口,因此对 UDP 扫描应用与 SYN 扫描相同的对策是一个好主意。
首先,添加一条规则以拒绝来自 UDP-PORTSCAN
列表上的主机的 UDP 链顶端的数据包。
# iptables -I UDP -p udp -m recent --update --rsource --seconds 60 --name UDP-PORTSCAN -j REJECT --reject-with icmp-port-unreachable
接下来,修改 UDP 的拒绝数据包规则
# iptables -D INPUT -p udp -j REJECT --reject-with icmp-port-unreachable # iptables -A INPUT -p udp -m recent --set --rsource --name UDP-PORTSCAN -j REJECT --reject-with icmp-port-unreachable
恢复最终规则
如果使用了上述端口扫描技巧中的一个或两个,则最终的默认规则不再是 INPUT 链中的最后一条规则。它需要是最后一条规则,否则它会拦截您刚刚添加的欺骗端口扫描器规则,使其失效。只需删除 (-D
) 该规则,然后使用追加 (-A
) 再次添加它,这将把它放在链的末尾。
# iptables -D INPUT -j REJECT --reject-with icmp-proto-unreachable # iptables -A INPUT -j REJECT --reject-with icmp-proto-unreachable
防止其他攻击
有关相关的内核参数,请参阅 sysctl#TCP/IP 堆栈加固。
暴力破解攻击
不幸的是,对可通过外部 IP 地址访问的服务进行暴力破解攻击是很常见的。其中一个原因是,使用许多可用的工具可以轻松执行攻击。幸运的是,有很多方法可以保护服务免受攻击。一种是使用适当的 iptables
规则,该规则在一定数量的数据包尝试发起连接后激活 IP 并将其列入黑名单。另一种是使用专门的守护程序,这些守护程序监视日志文件以查找失败的尝试并相应地列入黑名单。
/var
的分区可能会变得已满,尤其是在攻击者猛烈攻击服务器的情况下)。此外,通过了解您的 IP 地址,攻击者可以发送带有欺骗源标头的数据包,并使您被服务器锁定。SSH 密钥 为暴力破解问题提供了一个优雅的解决方案,而没有这些问题。Fail2ban 或,特别是对于 sshd
,Sshguard 这两个软件包可以在密码失败次数过多后禁止 IP。这两个应用程序更新 iptables 规则以临时或永久拒绝来自攻击者的未来连接。
以下规则给出了一个示例配置,用于使用 iptables
缓解 SSH 暴力破解攻击。
# iptables -N IN_SSH # iptables -N LOG_AND_DROP # iptables -A INPUT -p tcp --dport ssh -m conntrack --ctstate NEW -j IN_SSH # iptables -A IN_SSH -m recent --name sshbf --rttl --rcheck --hitcount 3 --seconds 10 -j LOG_AND_DROP # iptables -A IN_SSH -m recent --name sshbf --rttl --rcheck --hitcount 4 --seconds 1800 -j LOG_AND_DROP # iptables -A IN_SSH -m recent --name sshbf --set -j ACCEPT # iptables -A LOG_AND_DROP -j LOG --log-prefix "iptables deny: " --log-level 7 # iptables -A LOG_AND_DROP -j DROP
大多数规则应该是自解释的:第一个规则允许在十秒内最多三个连接数据包,并丢弃来自此 IP 的进一步尝试。下一个规则增加了一个怪癖,允许在 30 分钟内最多四次命中。这样做是因为一些暴力破解攻击实际上执行缓慢,而不是突发尝试。这些规则采用了许多附加选项。要阅读有关它们的更多信息,请查看此示例的原始参考资料 compilefailure.blogspot.com。LOG_AND_DROP 链用于记录丢弃的连接。
上述规则可用于保护任何服务,尽管 SSH 守护程序可能是最常需要的服务。
在顺序方面,必须确保 -A INPUT -p tcp --dport ssh -m conntrack --ctstate NEW -j IN_SSH
在 iptables 序列中的正确位置:它应该在 TCP 链附加到 INPUT 之前,以便首先捕获新的 SSH 连接。如果已完成本 wiki 的所有先前步骤,则以下定位有效
... -A INPUT -m conntrack --ctstate INVALID -j DROP -A INPUT -p icmp -m icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j IN_SSH -A INPUT -p udp -m conntrack --ctstate NEW -j UDP -A INPUT -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j TCP ...
cat /proc/net/xt_recent/sshbf
观察传入的尝试。要在测试期间解除阻止自己的 IP,需要 root 权限 echo / > /proc/net/xt_recent/sshbf
IPv6
如果您不使用 IPv6,您可以考虑 禁用它,否则请按照以下步骤启用 IPv6 防火墙规则。
复制本示例中使用的 IPv4 规则作为基础,并将所有 IP 从 IPv4 格式更改为 IPv6 格式
# cp /etc/iptables/iptables.rules /etc/iptables/ip6tables.rules
本示例中的一些规则必须进行调整才能与 IPv6 一起使用。ICMP 协议已在 IPv6 中更新,取代了用于 IPv4 的 ICMP 协议。因此,拒绝错误返回代码 --reject-with icmp-port-unreachable
和 --reject-with icmp-proto-unreachable
必须转换为 ICMPv6 代码。
可用的 ICMPv6 错误代码在 RFC 4443 中列出,该 RFC 规定防火墙规则阻止的连接尝试应使用 --reject-with icmp6-adm-prohibited
。这样做基本上会告知远程系统连接被防火墙拒绝,而不是监听服务。
如果不想明确告知防火墙过滤器的存在,也可以在不发送消息的情况下拒绝数据包
-A INPUT -j REJECT
以上将使用默认返回错误 --reject-with icmp6-port-unreachable
进行拒绝。但是您应该注意,识别防火墙是端口扫描应用程序的基本功能,大多数应用程序无论如何都会识别它。
在下一步中,确保协议和扩展已更改为适合 IPv6 的规则,该规则涉及所有新的传入 ICMP 回显请求(ping)
# ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 128 -m conntrack --ctstate NEW -j ACCEPT
Netfilter conntrack 似乎不跟踪 ICMPv6 邻居发现协议(IPv6 中 ARP 的等效协议),因此我们需要允许 ICMPv6 流量,而无需考虑所有直接连接的子网的状态。以下内容应在删除 --ctstate INVALID
之后但在任何其他 DROP 或 REJECT 目标之前插入,并为每个直接连接的子网添加相应的行
# ip6tables -A INPUT -s fe80::/10 -p ipv6-icmp -j ACCEPT
如果您想启用 DHCPv6,您需要接受 UDP 端口 546 上的传入连接
# ip6tables -A INPUT -p udp --sport 547 --dport 546 -j ACCEPT
由于 IPv6 没有内核反向路径过滤器,因此您可能需要在 ip6tables 中使用以下命令启用一个
# ip6tables -t mangle -A PREROUTING -m rpfilter -j ACCEPT # ip6tables -t mangle -A PREROUTING -j DROP
保存规则
规则集现已完成,应将其保存到文件中,以便可以在每次启动时加载它们。
使用以下命令保存 IPv4 和 IPv6 规则
# iptables-save -f /etc/iptables/iptables.rules # ip6tables-save -f /etc/iptables/ip6tables.rules
生成的 ip6tables.rules 文件
运行上述所有命令后,ip6tables.rules
文件的示例
/etc/iptables/ip6tables.rules
# Generated by ip6tables-save v1.8.2 on Sat Apr 20 10:53:41 2019 *filter :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] :TCP - [0:0] :UDP - [0:0] -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -m conntrack --ctstate INVALID -j DROP -A INPUT -s fe80::/10 -p ipv6-icmp -j ACCEPT -A INPUT -p udp --sport 547 --dport 546 -j ACCEPT -A INPUT -p udp -m conntrack --ctstate NEW -j UDP -A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j TCP -A INPUT -p udp -j REJECT --reject-with icmp6-adm-prohibited -A INPUT -p tcp -j REJECT --reject-with tcp-reset -A INPUT -j REJECT --reject-with icmp6-adm-prohibited -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 128 -m conntrack --ctstate NEW -j ACCEPT COMMIT # Completed on Sat Apr 20 10:53:41 2019
然后启用和启动 iptables.service
和 ip6tables.service
。检查服务的状态以确保规则已正确加载。
设置 NAT 网关
本指南的这一部分介绍了 NAT 网关。假设您已经阅读了本指南的第一部分,并像上面描述的那样设置了 INPUT、OUTPUT、TCP 和 UDP 链。到目前为止,所有规则都是在 filter 表中创建的。在本节中,我们还将必须使用 nat 表。在 控制 NAT 的内容 中有一个关于这种情况的 ASCII 艺术图。
设置 filter 表
创建必要的链
在我们的设置中,我们将使用以下命令在 filter 表中创建两个新链,fw-interfaces 和 fw-open
# iptables -N fw-interfaces # iptables -N fw-open
设置 FORWARD 链
设置 FORWARD 链类似于第一部分中的 INPUT 链。
现在我们使用 conntrack 匹配设置一个规则,与 INPUT 链中的规则相同
# iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
下一步是为受信任的接口启用转发,并使所有数据包通过 fw-open 链。
# iptables -A FORWARD -j fw-interfaces # iptables -A FORWARD -j fw-open
其余数据包被拒绝,并显示 ICMP 消息
# iptables -A FORWARD -j REJECT --reject-with icmp-host-unreachable # iptables -P FORWARD DROP
设置 fw-interfaces 和 fw-open 链
fw-interfaces 和 fw-open 链的含义将在后面解释,当我们处理 nat 表中的 POSTROUTING 和 PREROUTING 链时。
设置 nat 表
在本节中,我们始终假设传出接口(具有公共互联网 IP 的接口)是 ppp0。请记住,如果您的传出接口有其他名称,则必须更改以下所有规则中的名称。
设置 POSTROUTING 链
现在,我们必须定义谁被允许连接到互联网。假设我们在 eth0 上有子网 192.168.0.0/24(这意味着所有形式为 192.168.0.* 的地址)。我们首先需要在 FORWARD 表中接受此接口上的计算机,这就是我们上面创建 fw-interfaces 链的原因
# iptables -A fw-interfaces -i eth0 -j ACCEPT
现在,我们必须更改所有传出数据包,使其具有我们的公共 IP 地址作为源地址,而不是本地 LAN 地址。为此,我们使用 MASQUERADE 目标
# iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o ppp0 -j MASQUERADE
不要忘记上面的 -o ppp0 参数。如果您省略它,您的网络将会搞砸。
假设我们在接口 eth1 上有另一个子网 10.3.0.0/16(这意味着所有地址 10.3.*.*)。我们再次添加与上面相同的规则
# iptables -A fw-interfaces -i eth1 -j ACCEPT # iptables -t nat -A POSTROUTING -s 10.3.0.0/16 -o ppp0 -j MASQUERADE
最后一步是启用数据包转发(如果尚未启用)。
来自这些子网的计算机现在可以使用您的新 NAT 计算机作为其网关。请注意,您可能需要设置 DNS 和 DHCP 服务器,例如 dnsmasq 或 BIND 和 dhcpd 的组合,以简化客户端计算机上的网络设置 DNS 解析。这不是本指南的主题。
设置 PREROUTING 链
有时,我们希望将从网关到 LAN 机器的传入数据包地址更改。为此,我们使用上面定义的 fw-open 链,以及 nat 表中的 PREROUTING 链,如以下两个简单示例所示。
首先,我们想将所有传入的 SSH 数据包(端口 22)更改为机器 192.168.0.5 的 ssh 服务器
# iptables -t nat -A PREROUTING -i ppp0 -p tcp --dport 22 -j DNAT --to 192.168.0.5 # iptables -A fw-open -d 192.168.0.5 -p tcp --dport 22 -j ACCEPT
第二个例子将向您展示如何将数据包更改为与传入端口不同的端口。我们想将端口 8000 上的任何传入连接更改为我们位于 192.168.0.6 的 Web 服务器,端口 80
# iptables -t nat -A PREROUTING -i ppp0 -p tcp --dport 8000 -j DNAT --to 192.168.0.6:80 # iptables -A fw-open -d 192.168.0.6 -p tcp --dport 80 -j ACCEPT
相同的设置也适用于 udp 数据包。
保存规则
保存规则
# iptables-save -f /etc/iptables/iptables.rules
这假设您已按照上面的步骤启用 iptables systemd 服务。