基于 iptables 的防火墙方案
假设两台主机 A(172.29.100.100) 和 B(10.100.100.100), iptables 规则应用于 A 机器上.
-
允许两台主机互通
-A INPUT -s 10.100.100.100 -j ACCEPT -A INPUT -s 0.0.0.0/0 -j DROP
-
允许 A 访问 B, 反向禁止
-A INPUT -m state --state ESTABLISHED,RELATED -s 10.100.100.100 -j ACCEPT -A INPUT -s 0.0.0.0/0 -j DROP
-
允许 B 访问 A, 反向禁止
-A INPUT -m state --state NEW,ESTABLISHED,RELATED -s 10.100.100.100 -j ACCEPT -A OUTPUT -m state --state NEW -d 10.100.100.100 -j DROP -A INPUT -s 0.0.0.0/0 -j DROP
state 模块
在 iptables 中,state 参数用于根据连接的状态进行流量过滤。它通过 conntrack 模块来跟踪每个网络连接的状态,并基于这些状态来决定是否允许或阻止数据包。该功能主要用于实现有状态防火墙规则,可以有效控制连接的生命周期。
常见的连接状态(state 参数)
-
NEW:
- 表示数据包是属于一个新的连接,之前没有与任何连接相关联。
- 一般用于检测并控制新发起的连接请求。
-
ESTABLISHED:
- 表示数据包属于一个已经建立的连接。该连接之前已经成功建立并且通信已经开始。 - 用于允许已经建立的连接继续传输数据。
-
RELATED:
- 表示数据包与现有的连接相关。例如,FTP 数据连接是基于 FTP 控制连接的,属于 RELATED。
- 常用于允许与现有连接相关联的流量(比如一些协议的控制与数据连接的分离)。
- 示例:允许与现有连接相关联的数据包进入:
-
INVALID:
- 表示数据包不属于任何现有的连接,并且无法识别其状态。这些数据包可能存在问题或者被篡改。
- 通常要阻止此类数据包,因为它们可能是异常或恶意的。
state 连接与 tcp 连接
iptables 中的 state 参数和 TCP 连接有着直接的关系,但它不只局限于 TCP,还可以应用于其他协议(例如 UDP、ICMP)。state 参数依赖于 conntrack 模块,它跟踪系统中所有连接的状态,并根据这些状态来进行数据包的匹配和过滤。在 TCP 连接的情况下,state 参数尤其有用,因为 TCP 是一个面向连接的协议,具有明确的连接建立、数据传输和连接终止的过程。
state 参数和 TCP 连接的关系
在 TCP 连接中,有三个典型的状态阶段,iptables 的 state 参数正好与这些阶段相匹配:
- NEW(新连接):
- 对应于 TCP 的连接建立过程。当客户端发出 TCP SYN 数据包来开始连接时,iptables 会将这个数据包标记为 NEW 状态。
- 该状态表示这是一次新的连接请求,之前没有与任何现有连接相关联。
- 例如,TCP 三次握手的第一个 SYN 包就是属于 NEW 状态。
- ESTABLISHED(已建立连接):
- 对应于 TCP 连接已经成功建立并且正在进行数据传输的状态。这意味着三次握手已经完成,连接处于数据传输阶段。
- 当客户端和服务器之间已经完成 TCP 三次握手后,后续的所有 TCP 数据包都会标记为 ESTABLISHED。
- 该状态允许数据在两端之间双向传输,表示该连接已经处于稳定状态。
- RELATED(相关连接):
- 这与 TCP 的直接关系不大,更多地用于管理与现有连接有关联的流量。例如,FTP 的数据连接是由控制连接派生出来的。
- 在 TCP 的上下文中,可能某些协议在主连接上启动新的相关连接,这时相关的连接数据包会被标记为 RELATED。
- INVALID(无效连接):
- 如果 TCP 包不能被正确地与现有连接关联(例如由于数据包顺序错乱、某些参数不一致、数据包损坏等),这些包会被标记为 INVALID。
- 该状态通常用来处理可能的错误或恶意流量,应该丢弃这些包,因为它们不符合 TCP 连接的规范。
TCP 三次握手与 state 状态
让我们来看一下 TCP 三次握手和 state 状态之间的映射关系:
- SYN(客户端请求连接):
- 客户端发送 TCP SYN 包,向服务器发起连接请求。此时,iptables 会将该数据包标记为 NEW 状态。
- SYN-ACK(服务器响应连接请求):
- 服务器收到 SYN 包后,返回 SYN-ACK,确认收到连接请求.
- iptables 可以处理这个响应包并跟踪连接状态。
- ACK(客户端确认连接):
- 客户端发送 ACK 确认,三次握手完成。此时,连接进入 ESTABLISHED 状态,表明连接已经成功建立。
- 后续的数据包都属于 ESTABLISHED 状态.
TCP 四次挥手与 state 状态
- FIN(关闭连接请求):
- 客户端或服务器发送 TCP FIN 包来请求关闭连接。这个 FIN 包属于 ESTABLISHED 状态,因为连接尚未完全关闭。
- FIN-ACK(确认关闭请求):
- 对方收到 FIN 包后,返回 FIN-ACK 确认,这个包仍然属于 ESTABLISHED 状态。
- ACK(确认关闭):
最后,双方交换 ACK 确认连接已关闭。虽然连接已经关闭,但 conntrack 会继续跟踪连接直到完全完成.
state 连接与 udp
iptables 中的 state 参数和 TCP 连接的状态有着直接的映射关系,但 UDP 是一种无连接协议,没有像 TCP 那样明确的连接建立和终止过程。因此,UDP 与 iptables 的状态模型关联时,依赖于 Linux 内核的 conntrack 模块来进行状态跟踪。即使 UDP 不存在三次握手或四次挥手过程,conntrack 仍然会根据数据包的流动情况为其分配特定的状态。
UDP 与 state 状态的联系
conntrack 对 UDP 数据包也会追踪它们的状态,并将其映射到类似的连接状态。常见的状态解释如下:
- NEW(新连接):
- 当 UDP 数据包首次出现并且 conntrack 没有找到任何现有的关联,这个数据包将被标记为 NEW 状态。
- 由于 UDP 是无连接的,这通常意味着这个是新的 UDP 数据传输的开始(例如第一个 UDP 请求包)。
- 例如,如果你有一台服务器在监听 UDP 端口 53(DNS),当客户端第一次发送 DNS 请求时,这个请求包会被视为 NEW.
- ESTABLISHED(已建立连接):
- 虽然 UDP 本身没有连接的概念,但 conntrack 模块会追踪之前的数据包。如果一个 UDP 数据包对应的是已知的会话(即它是对之前数据包的响应),则它被标记为 ESTABLISHED。
- ESTABLISHED 状态表示该 UDP 数据包属于某个活动的会话,例如 DNS 查询的响应或者持续的数据流。
- 例如,当服务器收到客户端的第一个 UDP 数据包后,随后的响应包都属于 ESTABLISHED 状态:
- RELATED(相关连接):
- 如果一个 UDP 数据包与现有的连接或状态有关系,它将被标记为 RELATED。这通常发生在复杂的协议中,比如某些需要多个数据流的协议(如 FTP 数据流与控制流的关系)。
- 在 UDP 上,RELATED 可能用得较少,但在某些场景中,协议可能依赖于相关的流量,这时 conntrack 能够检测到并标记这些数据包。
- 例如,某些协议可能会使用不同的端口进行数据和控制通信,此时数据流可能会被标记为 RELATED。
- INVALID(无效连接):
- 如果 conntrack 无法将某个 UDP 数据包与任何已知连接或会话关联,它将被标记为 INVALID。这可能是由于数据包出错、到达顺序不正确或协议处理错误等原因。
- 通常情况下,INVALID 状态的数据包应该被丢弃,因为它们可能是错误的或恶意的流量。
- 示例:丢弃所有 INVALID 状态的 UDP 包:
UDP 与 conntrack 的工作机制
虽然 UDP 是无连接的协议,但 conntrack 会根据以下逻辑对其进行状态跟踪:
- 时间限制:
- UDP 数据包没有明确的“连接终止”标志(如 TCP 的 FIN 包)。因此,conntrack 使用超时时间来确定 UDP 会话的结束。通常,如果在一段时间内没有新的 UDP 数据包到达,则该会话会被标记为完成。
- 例如,DNS 请求和响应通常是短暂的通信,conntrack 会在一段时间内跟踪这些会话,然后标记为完成。
- 会话跟踪:
- 当两个主机之间有一系列的 UDP 数据包往来时,conntrack 会将它们关联起来,即使 UDP 没有明确的“连接”过程。这使得它能够将返回的数据包标记为 ESTABLISHED 或 RELATED,从而允许规则应用到无连接的流量上。