> For the complete documentation index, see [llms.txt](https://jiangpengfei.gitbook.io/open-vswitch/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://jiangpengfei.gitbook.io/open-vswitch/chang-yong-ming-ling-can-kao/iptables.md).

# iptables

### 简介

iptables 是 linux 上的一个很强大的工具，通过控制 Linux 内核中的 netfilter 模块，来管理网络数据包的处理和转发。

iptables 有几个基本的概念:

* 表（table）: 每个表都代表了不同的数据处理流程，比如 filter 表通常用来做数据包的过滤，nat 表通常用来对连接做地址转换。
* 链（chain）：链是存在表中的，每个表通过不同链的集合来完成不同的作用。比如 filter 表中有 `INPUT`,`OUTPUT`, `FORWARD` 链。
* 规则（rule）：规则是存在每个链中的，也是 iptables 操作的最小单位。通过对规则的增删改查，我们可以实现很多强大的功能。

### 表、链、规则

iptables 包含：

* 四个表：
  * filter：数据包过滤的表，包含的链有：INPUT，FORWARD，OUTPUT
  * nat：网络地址转换的表，包含的链有：PREROUTING，OUTPUT，POSTROUTING（centos7中还有INPUT，centos6中没有）
  * mangle：处理数据包的表，包含的链有：PREROUTING，INPUT，FORWARD，OUTPUT，POSTROUTING
  * raw：处理异常的表，包含的链有：PREROUTING，OUTPUT
* 五条链：
  * PREROUTING：路由前链，在处理路由规则前通过此链，通常用于目的地址转换（DNAT）。
  * INPUT：输入链。发往本机的数据包通过此链。
  * FORWARD：转发链。本机转发的数据包通过此链。
  * OUTPUT：输出链。从本机发出的数据包通过此链。
  * POSTROUTING：路由后链，完成路由规则后通过此链，通常用于源地址转换（SNAT）。

看一张整体的流程图：

![图片来自：http://www.zsythink.net/archives/1199](/files/-M9OOehHD533uI92Mp3K)

每个规则中都会包含一个动作，来表示如果匹配到了，就会执行什么动作，通常用 -j ACTION 来设置。常见的动作有：

* ACCEPT：接受
* DROP：丢弃
* REJECT: 拒绝，和 DROP 不同的是，REJECT 会返回响应。
* LOG：LOG 会记录匹配的报文日志
* SNAT：全称是 source network address translation。会修改报文的 src ip。
* DNAT：全称是 destination network address translation。会修改报文的 dst ip。
* MASQUERADE：和 SNAT 类型，只不过 SNAT 会将报文的 src ip 修改成设置好的值，而 MASQUERADE 会将报文的 src ip 设置成指定网卡上可用的值。
* REDIRECT：在本机上进行端口映射。

### 增删改查

既然要用 iptables，第一步是先了解它的增删查。

```
# 这里的在向 filter 表中的 OUTPUT 链添加规则。
# -A 是向链尾添加规则，改成 -I 是向链首添加规则。
iptables -t filter -A OUTPUT -d 192.168.50.203 -j DROP

# 查 filter 表的 OUTPUT 链
iptables -t filter -nL OUTPUT

# 删除 filter 表中的 OUTPUT 链的第一条规则
iptables -t filter -D OUTPUT 1

# 删除 filter 表中的所有规则
iptables -t filter -F
```

### 实例

下面通过几个常见的例子来展示：

#### 例子一：防火墙

这里我们配置一个只打开 22, 80 和 443 端口的防火墙，同时所有出去的流量都是正常的。因为是防火墙，我们很自然的想到用 filter 表。

```
# 先允许目标端口是 22 的请求，因为我现在是 ssh 连接的
iptables -t filter -A INPUT -p tcp --dport 22 -j ACCEPT

# 默认是 filter，所以可以不加 -t，修改 INPUT 表的默认 target 是 DROP
iptables -P INPUT DROP
# 允许所有出去的包
iptables -P OUTPUT ACCEPT
# 不允许转发包
iptables -P FORWARD DROP
# 允许从本机出去的流量建立连接
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

# 允许 ping
iptables -A INPUT -p icmp -j ACCEPT

# 允许 80, 443
iptables -t filter -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -t filter -A INPUT -p tcp --dport 443 -j ACCEPT

# 允许本地的连接
iptables -A INPUT -i lo -p all -j ACCEPT

# 监听本地80端口，测试 80 是否连通
nc -l 80

# 另外的机器
telnet 192.168.50.200 80

# 只允许特定 IP 的 ssh 连接
iptables -A INPUT -p tcp -s 10.0.2.2,192.168.50.201 --dport 22 -j ACCEPT

# 删除第一条的规则
iptables -D INPUT 1
```

#### NAT
