# 练习 26：网络：封包过滤配置，`iptables`

> 原文：[Exercise 26. Networking: packet filter configuration, iptables](https://archive.fo/D3zbt)

> 译者：[飞龙](https://github.com/wizardforcel)

> 协议：[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)

> 自豪地采用[谷歌翻译](https://translate.google.cn/)

让我以引用维基百科上的[`iptables`](http://en.wikipedia.org/wiki/Iptables)来开始：

> `iptables`是一个用户态应用程序，允许系统管理员配置由 Linux 内核防火墙（实现为不同的 Netfilter 模块）提供的表，以及它存储的链和规则。不同的内核模块和程序目前用于不同的协议；`iptables`适用于 IPv4，`ip6tables`适用于 IPv6，`arptables`适用于 ARP，`ebtables`适用于以太网帧。

为了使用它，你必须了解以下概念：

+   [`LINKTYPE_LINUX_SLL`](http://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html) - `tcpdump`伪链路层协议。
+   [以太网帧头部](http://en.wikipedia.org/wiki/Ethernet_frame%23Header) - 以太网链路上的数据包称为以太网帧。帧以前缀和起始分隔符开始。接下来，每个以太网帧都有一个头部，其特征为源和目标 MAC 地址。帧的中间部分是载荷数据，包含帧中携带的其他协议（例如，互联网协议）的任何头部。该帧以 32 位循环冗余校验（CRC）结束，用于检测传输中数据的任何损坏。
+   [IPv4 头部](http://en.wikipedia.org/wiki/IPv4_header%23IPv4%20header) - IP 封包包括头部部分和数据部分。IPv4 封包头部由 14 个字段组成，其中 13 个是必需的。第十四个字段是可选的，适当地命名为：`options`。
+   [TCP 段结构](http://en.wikipedia.org/wiki/Transmission_Control_Protocol%23TCP_segment_structure) - 传输控制协议接受来自数据流的数据，将其分割成块，并添加 TCP 头部来创建 TCP 段。TCP 段然后被封装成互联网协议（IP）数据报。TCP 段是“信息封包，TCP 用于与对方交换数据”。

我会提醒你，让你获取一些指南：

+   阅读相应的维基百科文章，直到你至少表面上理解了它（但是深入研究当然更好）。
    +   展开站点左侧的 IP 地址树节点，并通过它来以你的方式实现。
    +   展开 TCP 树节点并执行相同操作。
+   阅读 [Linux 网络概念介绍](http://www.iptables.org/documentation/HOWTO//networking-concepts-HOWTO-3.html%23ss3.1)。这本指南很好，因为它甚至承认 互联网是为情欲而生的。

比起 [Peter Harrison 的优秀指南](http://www.linuxhomenetworking.com/wiki/index.php/Quick_HOWTO_:_Ch14_:_Linux_Firewalls_Using_iptables)，我没办法更好地描述`iptables`了。如果你从未使用过它，请先阅读本指南。

但是，我将会将理论付诸实践，并 在数据交换的一个非常简单的情况下，逐步展示出`iptalbes`内部的内容。第一件事情是主要概念：

`iptables` - 用于在 Linux 内核中设置，维护和检查 IPv4 包过滤规则表的程序。可以定义几个不同的表。每个表包含多个内置链，并且还可以包含用户定义的链。
`ip6tables` - 用于 IPv6 的相同东西。
链 - 可以匹配一组数据包的规则列表。每个规则规定了，如何处理匹配的数据包。这被称为目标，它可能是相同表中的，用户定义的链的跳转。
目标 - 防火墙规则为封包和目标指定了判别标准。如果数据包不匹配，就会检查的链中的下一个规则；如果它匹配，则下一个规则由目标的值指定，该值可以是用户定义链的名称或特殊值之一：

`ACCEPT` - 让包通过。
`DROP` - 将数据包丢弃。
`QUEUE` - 将数据包传递给用户空间。
`RETURN` - 停止遍历此链，并在上一个（调用）链中的下一个规则处恢复。如果达到了内置链的结尾，或者内置链中的一个带有`RETURN`的规则匹配它，链策略指定的目标决定了数据包的命运。

现在让我们看看有什么默认的表和内置的链：

| 表名 | 内置链 | 描述 |
| --- | --- | --- |
| `raw` |  | 该表主要用于配置与`NOTRACK`目标结合的连接跟踪的免除。它以较高的优先级在`netfilter`钩子中注册，因此在`ip_conntrack`或任何其他 IP 表之前调用。 |
| | PREROUTING | 用于经过任何网络接口到达的封包。 |
| | OUTPUT |  用于本地进程生成的封包。 |
| `mangle` |  | 该表用于专门的数据包更改。 |
| | PREROUTING |  用于在路由之前更改传入的数据包。 |
| | OUTPUT | 用于在路由之前更改本地生成的数据包。 |
| | INPUT |  用于进入本机的数据包。 |
| | FORWARD | 用于经过本机的数据包。 |
| | POSTROUTING | 用于当数据包打算出去时，更改它们。 |
| `nat` |  | 当遇到创建新连接的数据包时，将查看此表。 |
| | PREROUTING | 用于一旦数据包进来，就更改它们。 |
| | OUTPUT | 用于在路由之前更改本地生成的数据包。 |
| | POSTROUTING | 用于当数据包打算出去时，更改它们。 |
| `filter` |  | 这是默认表（如果没有传入`-t`选项）。 |
| | INPUT | 用于发往本地套接字的数据包。 |
| | FORWARD | 用于经过本机的数据包。 |
| | OUTPUT | 用于本地生成的数据包。 |

好的，我们准备看看它实际如何运作。我会从我的家用计算机，使用 TCP 协议和`netcat`向`vm1`发送一个字符串`Hello world!`，`netcat`就像`cat`一样，但是通过网络。起步：

1\.  我将另一个端口，80，转发到我运行 Linux 的家用 PC，所以我能象这样连接它：

```
(My home PC) --> vm1:80
```

2\.  我将这个规则添加到`iptables`，来记录`iptables`内部的数据包发生了什么。

```
sudo iptables -t raw -A PREROUTING -p tcp -m tcp --dport 80 -j TRACE
sudo iptables -t raw -A INPUT -p tcp -m tcp --sport 80 -j TRACE
```

这是我的`vm1`上的`iptables`规则集：

```
root@vm1:/home/user1# for i in raw mangle nat filter ; do echo -e "\n-----" TABLE: $i '-----' ; iptables -t $i -L ; done

----- TABLE: raw -----
Chain PREROUTING (policy ACCEPT)  target     prot opt source               destination
                                  TRACE      tcp  --  anywhere             anywhere            tcp dpt:www
Chain OUTPUT (policy ACCEPT)      target     prot opt source               destination
                                  TRACE      tcp  --  anywhere             anywhere            tcp spt:www
----- TABLE: mangle -----
Chain PREROUTING (policy ACCEPT)  target     prot opt source               destination
Chain INPUT (policy ACCEPT)       target     prot opt source               destination
Chain FORWARD (policy ACCEPT)     target     prot opt source               destination
Chain OUTPUT (policy ACCEPT)      target     prot opt source               destination
Chain POSTROUTING (policy ACCEPT) target     prot opt source               destination
 
----- TABLE: nat -----
Chain PREROUTING (policy ACCEPT)  target     prot opt source               destination
Chain POSTROUTING (policy ACCEPT) target     prot opt source               destination
Chain OUTPUT (policy ACCEPT)      target     prot opt source               destination
 
----- TABLE: filter -----
Chain INPUT (policy ACCEPT)       target     prot opt source               destination
Chain FORWARD (policy ACCEPT)     target     prot opt source               destination
Chain OUTPUT (policy ACCEPT)      target     prot opt source               destination
```

你可以看到，没有其它规则了。另一种查看`iptables`规则的方式，是使用`iptables-save`工具：

```
root@vm1:/home/user1# iptables-save
# Generated by iptables-save v1.4.8 on Fri Jul 13 08:09:04 2012
#(1)
*mangle
#(2)        (3)     (4)   (5)
:PREROUTING ACCEPT [15662:802240]
:INPUT ACCEPT [15662:802240]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [12756:3671974]
:POSTROUTING ACCEPT [12756:3671974]
COMMIT
# Completed on Fri Jul 13 08:09:04 2012
# Generated by iptables-save v1.4.8 on Fri Jul 13 08:09:04 2012
*nat
:PREROUTING ACCEPT [18:792]
:POSTROUTING ACCEPT [42:2660]
:OUTPUT ACCEPT [42:2660]
COMMIT
# Completed on Fri Jul 13 08:09:04 2012
# Generated by iptables-save v1.4.8 on Fri Jul 13 08:09:04 2012
*raw
:PREROUTING ACCEPT [15854:814892]
:OUTPUT ACCEPT [12855:3682054]
-A PREROUTING -p tcp -m tcp --dport 80 -j TRACE
-A OUTPUT -p tcp -m tcp --sport 80 -j TRACE
COMMIT
# Completed on Fri Jul 13 08:09:04 2012
# Generated by iptables-save v1.4.8 on Fri Jul 13 08:09:04 2012
*filter
:INPUT ACCEPT [35107:2459066]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [26433:10670628]
COMMIT
# Completed on Fri Jul 13 08:09:04 2012
```

` iptables-save`字段如下所示：

| 字段 | 描述 |
| --- | --- |
| (1) | 表名称 |
| (2) | 链名称 |
| (3) | 链策略 |
| (4) | 封包计数 |
| (5) | 字节计数 |

3\. 我启动`nc`来监听端口 80：

```
nc -l 80
```

4\. 我向`vm1`发送字符串：

```
echo 'Hello, world!' | nc localhost 80
```

下面的是我的家用 PC 和`vm1`之间的交换：

```
08:00:05.655339 IP 10.0.2.2.51534 > 10.0.2.15.80: Flags [S], seq 4164179969, win 65535, options [mss 1460], length 0
08:00:05.655653 IP 10.0.2.15.80 > 10.0.2.2.51534: Flags [S.], seq 4149908960, ack 4164179970, win 5840, options [mss 1460], length 0
08:00:05.655773 IP 10.0.2.2.51534 > 10.0.2.15.80: Flags [.], ack 1, win 65535, length 0
08:00:05.655868 IP 10.0.2.2.51534 > 10.0.2.15.80: Flags [P.], seq 1:15, ack 1, win 65535, length 14
08:00:05.655978 IP 10.0.2.15.80 > 10.0.2.2.51534: Flags [.], ack 15, win 5840, length 0
08:00:10.037978 IP 10.0.2.2.51534 > 10.0.2.15.80: Flags [F.], seq 15, ack 1, win 65535, length 0
08:00:10.038287 IP 10.0.2.15.80 > 10.0.2.2.51534: Flags [F.], seq 1, ack 16, win 5840, length 0
08:00:10.038993 IP 10.0.2.2.51534 > 10.0.2.15.80: Flags [.], ack 2, win 65535, length 0
```

让我们回忆，数据如何交换。为此，让我们拆开第一个封包。

```
#                  (13)     (15)    (14)      (16)      (20)     (17)            (25)            
08:00:05.655339 IP 10.0.2.2.51534 > 10.0.2.15.80: Flags [S], seq 4164179969, win 65535, 
#        (8)        (9)
options [mss 1460], length 0
#                (1)  (2)  (3)  (4)                 (5)    
#                ____ ____ ____ ___________________ ____
        0x0000:  0000 0001 0006 5254 0012 3502 0000 0800  ......RT..5.....
#                (6)  (7)  (8)  (9)(10,11)(12)  (13)
#                ____ ____ ____ ____ /\/\ ____ _________  
        0x0010:  4500 002c a006 0000 4006 c2b5 0a00 0202  E..,....@.......
#                (14)      (15) (16) (17)      (18)
#                _________ ____ ____ _________ __________ 
        0x0020:  0a00 020f c94e 0050 f834 5801 0000 0000  .....N.P.4X.....
#              (19,20)(21) (22) (23) (24) (25)
#                /\/\ ____ ____ ____ ____ ____ 
        0x0030:  6002 ffff 6641 0000 0204 05b4 0000       `...fA........
```

我们封包中的字段和描述：

| DOD 模型层 | OSI 模型层 | 位于 | 字段 | 描述 |
| --- | --- | --- | --- | --- | --- |
| 链路 | 物理/数据链路 | `LINUX_SLL` 头部 | (1) | 封包类型 |
| | | | (2) | `ARPHRD_` 类型 |
| | | | (3) | 链路层 (MAC) 地址长度 |
| | | | (4) | 链路层 (MAC) 源地址 |
| | | | (5) | 协议类型 (IP) |
| 互联网 | 网络 | IPv4 头部 | (6) | 版本，互联网头部长度，差分服务代码点，显式拥塞通知. |
| | | | (7) | 总长度 |
| | | | (8) | 身份，主要用于源 IP 数据报的段的唯一性鉴定 |
| | | | (9) | 标志，段的偏移 |
| | | | (10) | 生存时间 (TTL) |
| | | | (11) | 协议编号 |
| | | | (12) | 头部校验和 |
| | | | (13) | 源 IP 地址 |
| | | | (14) | 目标 IP 地址 |
| 传输 | 传输 | TCP 头部 | (15) | 源 TCP 端口 |
| | | | (16) | 目标 TCP 端口 |
| | | | (17) | TCP 初始序列号 |
| | | | (18) | ACK 编号字段 (空的，由于它是第一个封包) |
| | | | (19) |  |
| | | | (20) | SYN TCP 标志 |
| | | | (21) | TCP 窗口大小 |
| | | | (22) | TCP 校验和 |
| | | | (23) | 紧急指针 |
| | | | (24) | 可选字段的开始 |
| | | | (25) | TCP 最大段大小 (最大传输单元 - 40 字节) |

让我们看看`iptables`中，这个封包发生了什么：

```
#(1)(2)        (3)    (4)   (5)     (6)  (7) (8)               (9)               (10)  (11)         (12)
raw:PREROUTING:policy:2     IN=eth0 OUT= MAC=08:00:27:d4:45:68:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15
#                           (13)   (14)     (15)      (16)   (17)     (18)      (19)      (20)
                            LEN=44 TOS=0x00 PREC=0x00 TTL=64 ID=40966 PROTO=TCP SPT=51534 DPT=80
#                           (21)           (22)  (23)         (24)     (25)(26)   (27)
                            SEQ=4164179969 ACK=0 WINDOW=65535 RES=0x00 SYN URGP=0 OPT (020405B4)
mangle:PREROUTING:policy:1  IN=eth0 OUT= MAC=08:00:27:d4:45:68:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15
                            LEN=44 TOS=0x00 PREC=0x00 TTL=64 ID=40966 PROTO=TCP SPT=51534 DPT=80
                            SEQ=4164179969 ACK=0 WINDOW=65535 RES=0x00 SYN URGP=0 OPT (020405B4)
nat:PREROUTING:policy:1     IN=eth0 OUT= MAC=08:00:27:d4:45:68:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15
                            LEN=44 TOS=0x00 PREC=0x00 TTL=64 ID=40966 PROTO=TCP SPT=51534 DPT=80
                            SEQ=4164179969 ACK=0 WINDOW=65535 RES=0x00 SYN URGP=0 OPT (020405B4)
mangle:INPUT:policy:1       IN=eth0 OUT= MAC=08:00:27:d4:45:68:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15
                            LEN=44 TOS=0x00 PREC=0x00 TTL=64 ID=40966 PROTO=TCP SPT=51534 DPT=80
                            SEQ=4164179969 ACK=0 WINDOW=65535 RES=0x00 SYN URGP=0 OPT (020405B4)
filter:INPUT:policy:1       IN=eth0 OUT= MAC=08:00:27:d4:45:68:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15
                            LEN=44 TOS=0x00 PREC=0x00 TTL=64 ID=40966 PROTO=TCP SPT=51534 DPT=80
                            SEQ=4164179969 ACK=0 WINDOW=65535 RES=0x00 SYN URGP=0 OPT (020405B4)
```

`iptables`日志的字段的描述：

| 字段 | 描述 |
| --- | --- |
| (1) | 表名称 |
| (2) | 链名称 |
| (3) | 类型 (用于内建链的策略) |
| (4) | 规则编号 |
| (5) | 输入接口 |
| (6) | 输出接口 (空的，因为封包的目标是 vm1 自身) |
| (7) | MAC 地址 |
| (8) | 目标 (vm1) MAC |
| (9) | 源 MAC |
| (10) | 协议类型：IP |
| (11) | 源 IP 地址 |
| (12) | 目标 IP 地址 |
| (13) | IP 封包长度，以字节为单位 (不包括链路层头部) |
| (14) | IP 服务类型 |
| (15) | IP 优先级 |
| (16) | IP 生存时间 |
| (17) | IP 封包 ID |
| (18) | 协议类型：TCP |
| (19) | TCP 源端口 |
| (20) | TCP 目标端口 |
| (21) | TCP 序列号 |
| (22) | TCP 应答编号 |
| (23) | TCP 窗口大小 |
| (24) | TCP 保留位 |
| (25) | TCP SYN 标志已设置 |
| (25) | TCP 紧急指针未设置 |
| (25) | TCP 选项 |

现在我将使用`tcpdump`输出和`iptables`日志，并排（更多的是逐段）向你显示这个交换。你的任务是逐行浏览这个交换，了解会发生什么。我建议你打印这个交换，并使用笔和纸进行处理它，你可以从[特殊页面](http://nixsrv.com/llthw/ex26/log)打印它。你需要回答的问题是：

+   每个字段的意思是什么？拿着铅笔，将字段从`tcpdump`的踪迹连接到原始数据包的十六进制数据，再到`iptables`日志。
+   数据包以什么顺序进行处理？首先是哪个表，最后是哪个，为什么？
+   为什么只有第一个数据包通过`nat`表进行处理？

这是输出，看看：

```
08:00:05.655339 IP 10.0.2.2.51534 > 10.0.2.15.80: Flags [S], seq 4164179969, win 65535, options [mss 1460], length 0
        0x0000:  0000 0001 0006 5254 0012 3502 0000 0800  ......RT..5.....
        0x0010:  4500 002c a006 0000 4006 c2b5 0a00 0202  E..,....@.......
        0x0020:  0a00 020f c94e 0050 f834 5801 0000 0000  .....N.P.4X.....
        0x0030:  6002 ffff 6641 0000 0204 05b4 0000       `...fA........
`
raw:PREROUTING:policy:2     IN=eth0 OUT= MAC=08:00:27:d4:45:68:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15
                            LEN=44 TOS=0x00 PREC=0x00 TTL=64 ID=40966 PROTO=TCP SPT=51534 DPT=80
                            SEQ=4164179969 ACK=0 WINDOW=65535 RES=0x00 SYN URGP=0 OPT (020405B4)
mangle:PREROUTING:policy:1  IN=eth0 OUT= MAC=08:00:27:d4:45:68:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15
                            LEN=44 TOS=0x00 PREC=0x00 TTL=64 ID=40966 PROTO=TCP SPT=51534 DPT=80
                            SEQ=4164179969 ACK=0 WINDOW=65535 RES=0x00 SYN URGP=0 OPT (020405B4)
nat:PREROUTING:policy:1     IN=eth0 OUT= MAC=08:00:27:d4:45:68:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15
                            LEN=44 TOS=0x00 PREC=0x00 TTL=64 ID=40966 PROTO=TCP SPT=51534 DPT=80
                            SEQ=4164179969 ACK=0 WINDOW=65535 RES=0x00 SYN URGP=0 OPT (020405B4)
mangle:INPUT:policy:1       IN=eth0 OUT= MAC=08:00:27:d4:45:68:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15
                            LEN=44 TOS=0x00 PREC=0x00 TTL=64 ID=40966 PROTO=TCP SPT=51534 DPT=80
                            SEQ=4164179969 ACK=0 WINDOW=65535 RES=0x00 SYN URGP=0 OPT (020405B4)
filter:INPUT:policy:1       IN=eth0 OUT= MAC=08:00:27:d4:45:68:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15
                            LEN=44 TOS=0x00 PREC=0x00 TTL=64 ID=40966 PROTO=TCP SPT=51534 DPT=80
                            SEQ=4164179969 ACK=0 WINDOW=65535 RES=0x00 SYN URGP=0 OPT (020405B4)
 
08:00:05.655653 IP 10.0.2.15.80 > 10.0.2.2.51534: Flags [S.], seq 4149908960, ack 4164179970, win 5840, options [mss 1460], length 0
        0x0000:  0004 0001 0006 0800 27d4 4568 0000 0800  ........'.Eh....
        0x0010:  4500 002c 0000 4000 4006 22bc 0a00 020f  E..,..@.@.".....
        0x0020:  0a00 0202 0050 c94e f75a 95e0 f834 5802  .....P.N.Z...4X.
        0x0030:  6012 16d0 c224 0000 0204 05b4            `....$......
'
raw:OUTPUT:policy:2         IN= OUT=eth0 SRC=10.0.2.15 DST=10.0.2.2
                            LEN=44 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=80 DPT=51534
                            SEQ=4149908960 ACK=4164179970 WINDOW=5840 RES=0x00 ACK SYN URGP=0 OPT (020405B4) UID=0 GID=0
mangle:OUTPUT:policy:1      IN= OUT=eth0 SRC=10.0.2.15 DST=10.0.2.2
                            LEN=44 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=80 DPT=51534
                            SEQ=4149908960 ACK=4164179970 WINDOW=5840 RES=0x00 ACK SYN URGP=0 OPT (020405B4) UID=0 GID=0
filter:OUTPUT:policy:1      IN= OUT=eth0 SRC=10.0.2.15 DST=10.0.2.2
                            LEN=44 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=80 DPT=51534
                            SEQ=4149908960 ACK=4164179970 WINDOW=5840 RES=0x00 ACK SYN URGP=0 OPT (020405B4) UID=0 GID=0
mangle:POSTROUTING:policy:1 IN= OUT=eth0 SRC=10.0.2.15 DST=10.0.2.2
                            LEN=44 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=80 DPT=51534
                            SEQ=4149908960 ACK=4164179970 WINDOW=5840 RES=0x00 ACK SYN URGP=0 OPT (020405B4) UID=0 GID=0
 
08:00:05.655773 IP 10.0.2.2.51534 > 10.0.2.15.80: Flags [.], ack 1, win 65535, length 0
        0x0000:  0000 0001 0006 5254 0012 3502 0000 0800  ......RT..5.....
        0x0010:  4500 0028 a007 0000 4006 c2b8 0a00 0202  E..(....@.......
        0x0020:  0a00 020f c94e 0050 f834 5802 f75a 95e1  .....N.P.4X..Z..
        0x0030:  5010 ffff f0b1 0000 0000 0000 0000       P.............
 
raw:PREROUTING:policy:2     IN=eth0 OUT= MAC=08:00:27:d4:45:68:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15
                            LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=40967 PROTO=TCP SPT=51534 DPT=80
                            SEQ=4164179970 ACK=4149908961 WINDOW=65535 RES=0x00 ACK URGP=0
mangle:PREROUTING:policy:1  IN=eth0 OUT= MAC=08:00:27:d4:45:68:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15
                            LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=40967 PROTO=TCP SPT=51534 DPT=80
                            SEQ=4164179970 ACK=4149908961 WINDOW=65535 RES=0x00 ACK URGP=0
mangle:INPUT:policy:1       IN=eth0 OUT= MAC=08:00:27:d4:45:68:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15
                            LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=40967 PROTO=TCP SPT=51534 DPT=80
                            SEQ=4164179970 ACK=4149908961 WINDOW=65535 RES=0x00 ACK URGP=0
filter:INPUT:policy:1       IN=eth0 OUT= MAC=08:00:27:d4:45:68:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15
                            LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=40967 PROTO=TCP SPT=51534 DPT=80
                            SEQ=4164179970 ACK=4149908961 WINDOW=65535 RES=0x00 ACK URGP=0
 
08:00:05.655868 IP 10.0.2.2.51534 > 10.0.2.15.80: Flags [P.], seq 1:15, ack 1, win 65535, length 14
        0x0000:  0000 0001 0006 5254 0012 3502 0000 0800  ......RT..5.....
        0x0010:  4500 0036 a008 0000 4006 c2a9 0a00 0202  E..6....@.......
        0x0020:  0a00 020f c94e 0050 f834 5802 f75a 95e1  .....N.P.4X..Z..
        0x0030:  5018 ffff af45 0000 4865 6c6c 6f2c 2077  P....E..Hello,.w
        0x0040:  6f72 6c64 210a                           orld!.
 
raw:PREROUTING:policy:2     IN=eth0 OUT= MAC=08:00:27:d4:45:68:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15
                            LEN=54 TOS=0x00 PREC=0x00 TTL=64 ID=40968 PROTO=TCP SPT=51534 DPT=80
                            SEQ=4164179970 ACK=4149908961 WINDOW=65535 RES=0x00 ACK PSH URGP=0
mangle:PREROUTING:policy:1  IN=eth0 OUT= MAC=08:00:27:d4:45:68:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15
                            LEN=54 TOS=0x00 PREC=0x00 TTL=64 ID=40968 PROTO=TCP SPT=51534 DPT=80
                            SEQ=4164179970 ACK=4149908961 WINDOW=65535 RES=0x00 ACK PSH URGP=0
mangle:INPUT:policy:1       IN=eth0 OUT= MAC=08:00:27:d4:45:68:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15
                            LEN=54 TOS=0x00 PREC=0x00 TTL=64 ID=40968 PROTO=TCP SPT=51534 DPT=80
                            SEQ=4164179970 ACK=4149908961 WINDOW=65535 RES=0x00 ACK PSH URGP=0
filter:INPUT:policy:1       IN=eth0 OUT= MAC=08:00:27:d4:45:68:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15
                            LEN=54 TOS=0x00 PREC=0x00 TTL=64 ID=40968 PROTO=TCP SPT=51534 DPT=80
                            SEQ=4164179970 ACK=4149908961 WINDOW=65535 RES=0x00 ACK PSH URGP=0
 
08:00:05.655978 IP 10.0.2.15.80 > 10.0.2.2.51534: Flags [.], ack 15, win 5840, length 0
        0x0000:  0004 0001 0006 0800 27d4 4568 0000 0800  ........'.Eh....
        0x0010:  4500 0028 377c 4000 4006 eb43 0a00 020f  E..(7|@.@..C....
        0x0020:  0a00 0202 0050 c94e f75a 95e1 f834 5810  .....P.N.Z...4X.
        0x0030:  5010 16d0 d9d3 0000                      P.......
'
raw:OUTPUT:policy:2         IN= OUT=eth0 SRC=10.0.2.15 DST=10.0.2.2
                            LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=14204 DF PROTO=TCP SPT=80 DPT=51534
                            SEQ=4149908961 ACK=4164179984 WINDOW=5840 RES=0x00 ACK URGP=0
mangle:OUTPUT:policy:1      IN= OUT=eth0 SRC=10.0.2.15 DST=10.0.2.2
                            LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=14204 DF PROTO=TCP SPT=80 DPT=51534
                            SEQ=4149908961 ACK=4164179984 WINDOW=5840 RES=0x00 ACK URGP=0
filter:OUTPUT:policy:1      IN= OUT=eth0 SRC=10.0.2.15 DST=10.0.2.2
                            LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=14204 DF PROTO=TCP SPT=80 DPT=51534
                            SEQ=4149908961 ACK=4164179984 WINDOW=5840 RES=0x00 ACK URGP=0
mangle:POSTROUTING:policy:1 IN= OUT=eth0 SRC=10.0.2.15 DST=10.0.2.2
                            LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=14204 DF PROTO=TCP SPT=80 DPT=51534
                            SEQ=4149908961 ACK=4164179984 WINDOW=5840 RES=0x00 ACK URGP=0
 
08:00:10.037978 IP 10.0.2.2.51534 > 10.0.2.15.80: Flags [F.], seq 15, ack 1, win 65535, length 0
        0x0000:  0000 0001 0006 5254 0012 3502 0000 0800  ......RT..5.....
        0x0010:  4500 0028 a00e 0000 4006 c2b1 0a00 0202  E..(....@.......
        0x0020:  0a00 020f c94e 0050 f834 5810 f75a 95e1  .....N.P.4X..Z..
        0x0030:  5011 ffff f0a2 0000 0000 0000 0000       P.............
 
raw:PREROUTING:policy:2     IN=eth0 OUT= MAC=08:00:27:d4:45:68:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15
                            LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=40974 PROTO=TCP SPT=51534 DPT=80
                            SEQ=4164179984 ACK=4149908961 WINDOW=65535 RES=0x00 ACK FIN URGP=0
mangle:PREROUTING:policy:1  IN=eth0 OUT= MAC=08:00:27:d4:45:68:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15
                            LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=40974 PROTO=TCP SPT=51534 DPT=80
                            SEQ=4164179984 ACK=4149908961 WINDOW=65535 RES=0x00 ACK FIN URGP=0
mangle:INPUT:policy:1       IN=eth0 OUT= MAC=08:00:27:d4:45:68:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15
                            LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=40974 PROTO=TCP SPT=51534 DPT=80
                            SEQ=4164179984 ACK=4149908961 WINDOW=65535 RES=0x00 ACK FIN URGP=0
filter:INPUT:policy:1       IN=eth0 OUT= MAC=08:00:27:d4:45:68:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15
                            LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=40974 PROTO=TCP SPT=51534 DPT=80
                            SEQ=4164179984 ACK=4149908961 WINDOW=65535 RES=0x00 ACK FIN URGP=0
 
08:00:10.038287 IP 10.0.2.15.80 > 10.0.2.2.51534: Flags [F.], seq 1, ack 16, win 5840, length 0
        0x0000:  0004 0001 0006 0800 27d4 4568 0000 0800  ........'.Eh....
        0x0010:  4500 0028 377d 4000 4006 eb42 0a00 020f  E..(7}@.@..B....
        0x0020:  0a00 0202 0050 c94e f75a 95e1 f834 5811  .....P.N.Z...4X.
        0x0030:  5011 16d0 d9d1 0000                      P.......
'
raw:OUTPUT:policy:2         IN= OUT=eth0 SRC=10.0.2.15 DST=10.0.2.2
                            LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=14205 DF PROTO=TCP SPT=80 DPT=51534
                            SEQ=4149908961 ACK=4164179985 WINDOW=5840 RES=0x00 ACK FIN URGP=0 UID=0 GID=0
mangle:OUTPUT:policy:1      IN= OUT=eth0 SRC=10.0.2.15 DST=10.0.2.2
                            LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=14205 DF PROTO=TCP SPT=80 DPT=51534
                            SEQ=4149908961 ACK=4164179985 WINDOW=5840 RES=0x00 ACK FIN URGP=0 UID=0 GID=0
filter:OUTPUT:policy:1      IN= OUT=eth0 SRC=10.0.2.15 DST=10.0.2.2
                            LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=14205 DF PROTO=TCP SPT=80 DPT=51534
                            SEQ=4149908961 ACK=4164179985 WINDOW=5840 RES=0x00 ACK FIN URGP=0 UID=0 GID=0
mangle:POSTROUTING:policy:1 IN= OUT=eth0 SRC=10.0.2.15 DST=10.0.2.2
                            LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=14205 DF PROTO=TCP SPT=80 DPT=51534
                            SEQ=4149908961 ACK=4164179985 WINDOW=5840 RES=0x00 ACK FIN URGP=0 UID=0 GID=0
 
08:00:10.038993 IP 10.0.2.2.51534 > 10.0.2.15.80: Flags [.], ack 2, win 65535, length 0
        0x0000:  0000 0001 0006 5254 0012 3502 0000 0800  ......RT..5.....
        0x0010:  4500 0028 a00f 0000 4006 c2b0 0a00 0202  E..(....@.......
        0x0020:  0a00 020f c94e 0050 f834 5811 f75a 95e2  .....N.P.4X..Z..
        0x0030:  5010 ffff f0a1 0000 0000 0000 0000       P.............
 
raw:PREROUTING:policy:2     IN=eth0 OUT= MAC=08:00:27:d4:45:68:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15
                            LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=40975 PROTO=TCP SPT=51534 DPT=80
                            SEQ=4164179985 ACK=4149908962 WINDOW=65535 RES=0x00 ACK URGP=0
mangle:PREROUTING:policy:1  IN=eth0 OUT= MAC=08:00:27:d4:45:68:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15
                            LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=40975 PROTO=TCP SPT=51534 DPT=80
                            SEQ=4164179985 ACK=4149908962 WINDOW=65535 RES=0x00 ACK URGP=0
mangle:INPUT:policy:1       IN=eth0 OUT= MAC=08:00:27:d4:45:68:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15
                            LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=40975 PROTO=TCP SPT=51534 DPT=80
                            SEQ=4164179985 ACK=4149908962 WINDOW=65535 RES=0x00 ACK URGP=0
filter:INPUT:policy:1       IN=eth0 OUT= MAC=08:00:27:d4:45:68:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15
                            LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=40975 PROTO=TCP SPT=51534 DPT=80
                            SEQ=4164179985 ACK=4149908962 WINDOW=65535 RES=0x00 ACK URGP=0
```

## 这样做

```
 1: sudo iptables-save
 2: sudo iptables -t filter -A INPUT -i lo -j ACCEPT
 3: sudo iptables -t filter -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
 4: sudo iptables -t filter -P INPUT DROP
 5: sudo iptables -nt filter -L --line-numbers
 6: ping -c 2 -W 1 10.0.2.2
 7: sudo iptables -t filter -A INPUT --match state --state ESTABLISHED -j ACCEPT
 8: sudo iptables -nt filter -L --line-numbers
 9: ping -c 2 -W 1 10.0.2.2
10: sudo modprobe ipt_LOG
11: sudo iptables -nt raw -L --line-numbers
12: sudo iptables -t raw -A PREROUTING -p udp -m udp --dport 1024 -j TRACE
13: sudo iptables -t raw -A OUTPUT -p udp -m udp --sport 1024 -j TRACE
14: sudo tail -n0 -f /var/log/kern.log | cut -c52-300 &
15: nc -ulp 1024 &
16: echo 'Hello there!' | nc -u localhost 1000
17: <CTRL+C>
18: fg
19: <CTRL+C>
20: fg
21: <CTRL+C>
```

## 你会看到什么

```
user1@vm1:~$ sudo iptables-save
# Generated by iptables-save v1.4.8 on Mon Jul 16 09:01:32 2012
*mangle
:PREROUTING ACCEPT [45783:3411367]
:INPUT ACCEPT [45783:3411367]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [30409:9552110]
:POSTROUTING ACCEPT [30331:9543294]
COMMIT
# Completed on Mon Jul 16 09:01:32 2012
# Generated by iptables-save v1.4.8 on Mon Jul 16 09:01:32 2012
*nat
:PREROUTING ACCEPT [24:1056]
:POSTROUTING ACCEPT [755:41247]
:OUTPUT ACCEPT [817:45207]
COMMIT
# Completed on Mon Jul 16 09:01:32 2012
# Generated by iptables-save v1.4.8 on Mon Jul 16 09:01:32 2012
*raw
:PREROUTING ACCEPT [3171:197900]
:OUTPUT ACCEPT [1991:1294054]
-A PREROUTING -p udp -m udp --dport 80 -j TRACE
-A OUTPUT -p udp -m udp --sport 80 -j TRACE
COMMIT
# Completed on Mon Jul 16 09:01:32 2012
# Generated by iptables-save v1.4.8 on Mon Jul 16 09:01:32 2012
*filter
:INPUT ACCEPT [54:3564]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [28:2540]
COMMIT
# Completed on Mon Jul 16 09:01:32 2012
user1@vm1:~$ sudo iptables -t filter -A INPUT -i lo -j ACCEPT
user1@vm1:~$ sudo iptables -t filter -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
user1@vm1:~$ sudo iptables -t filter -P INPUT DROP
user1@vm1:~$ sudo iptables -nt filter -L --line-numbers
Chain INPUT (policy DROP)
num  target     prot opt source               destination
1    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0
2    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:22
 
Chain FORWARD (policy ACCEPT)
num  target     prot opt source               destination
 
Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination
 
user1@vm1:~$ ping -c 2 -W 1 10.0.2.2
PING 10.0.2.2 (10.0.2.2) 56(84) bytes of data.
 
--- 10.0.2.2 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1008ms
 
user1@vm1:~$ sudo iptables -t filter -A INPUT --match state --state ESTABLISHED -j ACCEPT
user1@vm1:~$ sudo iptables -nt filter -L --line-numbers
Chain INPUT (policy DROP)
num  target     prot opt source               destination
1    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0
2    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:22
3    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           state ESTABLISHED
 
Chain FORWARD (policy ACCEPT)
num  target     prot opt source               destination
 
Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination
 
user1@vm1:~$ ping -c 2 -W 1 10.0.2.2
PING 10.0.2.2 (10.0.2.2) 56(84) bytes of data.
64 bytes from 10.0.2.2: icmp_req=1 ttl=63 time=0.385 ms
64 bytes from 10.0.2.2: icmp_req=2 ttl=63 time=0.142 ms
 
--- 10.0.2.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.142/0.263/0.385/0.122 ms
user1@vm1:~$ sudo iptables -nt raw -L --line-numbers
Chain PREROUTING (policy ACCEPT)
num  target     prot opt source               destination
 
Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination
user1@vm1:~$ sudo iptables -t raw -A PREROUTING -p udp -m udp --dport 1024 -j TRACE
user1@vm1:~$ sudo iptables -t raw -A OUTPUT -p udp -m udp --sport 1024 -j TRACE
user1@vm1:~$ sudo iptables -nt raw -L --line-numbers
Chain PREROUTING (policy ACCEPT)
num  target     prot opt source               destination
1    TRACE      udp  --  0.0.0.0/0            0.0.0.0/0           udp dpt:1024
 
Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination
1    TRACE      udp  --  0.0.0.0/0            0.0.0.0/0           udp spt:1024
user1@vm1:~$ sudo tail -n0 -f /var/log/kern.log | cut -c52-300 &
[1] 10249
user1@vm1:~$ nc -ulp 1024 &
[2] 10251
user1@vm1:~$ echo 'Hello there!' | nc -u localhost 1024
Hello there!
raw:PREROUTING:policy:2 IN=lo OUT= MAC=00:00:00:00:00:00:00:00:00:00:00:00:08:00 SRC=127.0.0.1 DST=127.0.0.1 LEN=41 TOS=0x00 PREC=0x00 TTL=64 ID=57898 DF PROTO=UDP SPT=50407 DPT=1024 LEN=21
mangle:PREROUTING:policy:1 IN=lo OUT= MAC=00:00:00:00:00:00:00:00:00:00:00:00:08:00 SRC=127.0.0.1 DST=127.0.0.1 LEN=41 TOS=0x00 PREC=0x00 TTL=64 ID=57898 DF PROTO=UDP SPT=50407 DPT=1024 LEN=21
mangle:INPUT:policy:1 IN=lo OUT= MAC=00:00:00:00:00:00:00:00:00:00:00:00:08:00 SRC=127.0.0.1 DST=127.0.0.1 LEN=41 TOS=0x00 PREC=0x00 TTL=64 ID=57898 DF PROTO=UDP SPT=50407 DPT=1024 LEN=21
filter:INPUT:rule:1 IN=lo OUT= MAC=00:00:00:00:00:00:00:00:00:00:00:00:08:00 SRC=127.0.0.1 DST=127.0.0.1 LEN=41 TOS=0x00 PREC=0x00 TTL=64 ID=57898 DF PROTO=UDP SPT=50407 DPT=1024 LEN=21
 
^C
[2]+  Stopped                 nc -ulp 1024
user1@vm1:~$ fg
nc -ulp 1024
^C
user1@vm1:~$ fg
sudo tail -n0 -f /var/log/kern.log | cut -c52-300
^C
user1@vm1:~$
```

## 解释

1.  列出所有表中的所有`iptables`规则。你看不到任何东西。
1.  允许`lo`（[环回](http://en.wikipedia.org/wiki/Localhost)）接口上的所有传入流量。
1.  允许 TCP 端口 22 上的所有传入流量，这是`ssh`。
1.  将默认`INPUT`策略更改为`DROP`，禁止所有传入连接，除了 TCP 端口 22。如果在此丢失`vm1`的连接，则表示你做错了，在 VirtualBox 中重新启动并重试。
1.  列出当前的过滤器规则。注意：你可以按号码删除规则，如下所示：`sudo iptables -t filter -D INPUT 2`。请注意策略与规则完全不一样。
1.  尝试`ping`你的默认网关，失败了。为什么是这样，即使允许传出连接（`Chain OUTPUT (policy ACCEPT)`）？传出的数据包被发送到网关，但是网关的回复不能进入。
1.  添加一条规则，告诉`iptables`允许属于已建立连接的所有数据包，例如来自`vm1`的所有连接。
1.  列出当前的过滤器规则。你可以看到我们的新规则。
1.  `ping` `vm1`的默认网关，这次成功了。
1.  加载 Linux 内核模块，它允许使用包过滤日志功能。
1.  添加规则，来记录所有发往`vm1`任何接口的 UDP 端口 1024 的传入数据包。
1.  添加规则，来记录所有来自`vm1`任何接口的 UDP 端口 1024 的传出数据包。
1.  列出`raw`表规则。
1.  在后台启动`tail`，将打印写入`/var/log/kern.log`的所有新行。`cut`会在开头删除不必要的日志条目前缀。请注意后台进程如何写入终端。
1.  以服务器模式启动`nc`，在`vm1`的所有接口上监听 UDP 端口 1024 。
1.  以客户端模式启动`nc`，将字符串`Hello there!`发送到我们的服务器模式`nc`。`tail`打印出`kern.log`中的所有新行，你可以看到在 Linux 内核封包过滤器中，我们的单个 UDP 数据包从一个表到了另一个表。没有回复，所以只有一个数据包被发送和处理。
1.  杀死客户端模式`nc`。
1.  将服务器模式`nc`带到前台。
1.  杀死服务器模式`nc`。
1.  将`sudo tail -n0 -f /var/log/kern.log | cut -c52-300 &`带到前台。
1.  杀死它。

## 附加题

这个练习本身已经很大了。只需要打印出日志，并使用铅笔浏览它，直到理解了每一行的每个字段都发生了什么。如果你卡住了，去问别人：<http://nixsrv.com/llthw/ex26/log>。
