练习 26:网络:封包过滤配置,iptables

原文:Exercise 26. Networking: packet filter configuration, iptables

译者:飞龙

协议:CC BY-NC-SA 4.0

自豪地采用谷歌翻译

让我以引用维基百科上的iptables来开始:

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

为了使用它,你必须了解以下概念:

  • LINKTYPE_LINUX_SLL - tcpdump伪链路层协议。

  • 以太网帧头部 - 以太网链路上的数据包称为以太网帧。帧以前缀和起始分隔符开始。接下来,每个以太网帧都有一个头部,其特征为源和目标 MAC 地址。帧的中间部分是载荷数据,包含帧中携带的其他协议(例如,互联网协议)的任何头部。该帧以 32 位循环冗余校验(CRC)结束,用于检测传输中数据的任何损坏。

  • IPv4 头部 - IP 封包包括头部部分和数据部分。IPv4 封包头部由 14 个字段组成,其中 13 个是必需的。第十四个字段是可选的,适当地命名为:options

  • TCP 段结构 - 传输控制协议接受来自数据流的数据,将其分割成块,并添加 TCP 头部来创建 TCP 段。TCP 段然后被封装成互联网协议(IP)数据报。TCP 段是“信息封包,TCP 用于与对方交换数据”。

我会提醒你,让你获取一些指南:

  • 阅读相应的维基百科文章,直到你至少表面上理解了它(但是深入研究当然更好)。

    • 展开站点左侧的 IP 地址树节点,并通过它来以你的方式实现。

    • 展开 TCP 树节点并执行相同操作。

  • 阅读 Linux 网络概念介绍。这本指南很好,因为它甚至承认 互联网是为情欲而生的。

比起 Peter Harrison 的优秀指南,我没办法更好地描述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 协议和netcatvm1发送一个字符串Hello world!netcat就像cat一样,但是通过网络。起步:

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

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

这是我的vm1上的iptables规则集:

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

iptables-save字段如下所示:

字段
描述

(1)

表名称

(2)

链名称

(3)

链策略

(4)

封包计数

(5)

字节计数

3. 我启动nc来监听端口 80:

4. 我向vm1发送字符串:

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

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

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

| 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中,这个封包发生了什么:

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日志,并排(更多的是逐段)向你显示这个交换。你的任务是逐行浏览这个交换,了解会发生什么。我建议你打印这个交换,并使用笔和纸进行处理它,你可以从特殊页面打印它。你需要回答的问题是:

  • 每个字段的意思是什么?拿着铅笔,将字段从tcpdump的踪迹连接到原始数据包的十六进制数据,再到iptables日志。

  • 数据包以什么顺序进行处理?首先是哪个表,最后是哪个,为什么?

  • 为什么只有第一个数据包通过nat表进行处理?

这是输出,看看:

这样做

你会看到什么

解释

  1. 列出所有表中的所有iptables规则。你看不到任何东西。

  2. 允许lo环回)接口上的所有传入流量。

  3. 允许 TCP 端口 22 上的所有传入流量,这是ssh

  4. 将默认INPUT策略更改为DROP,禁止所有传入连接,除了 TCP 端口 22。如果在此丢失vm1的连接,则表示你做错了,在 VirtualBox 中重新启动并重试。

  5. 列出当前的过滤器规则。注意:你可以按号码删除规则,如下所示:sudo iptables -t filter -D INPUT 2。请注意策略与规则完全不一样。

  6. 尝试ping你的默认网关,失败了。为什么是这样,即使允许传出连接(Chain OUTPUT (policy ACCEPT))?传出的数据包被发送到网关,但是网关的回复不能进入。

  7. 添加一条规则,告诉iptables允许属于已建立连接的所有数据包,例如来自vm1的所有连接。

  8. 列出当前的过滤器规则。你可以看到我们的新规则。

  9. ping vm1的默认网关,这次成功了。

  10. 加载 Linux 内核模块,它允许使用包过滤日志功能。

  11. 添加规则,来记录所有发往vm1任何接口的 UDP 端口 1024 的传入数据包。

  12. 添加规则,来记录所有来自vm1任何接口的 UDP 端口 1024 的传出数据包。

  13. 列出raw表规则。

  14. 在后台启动tail,将打印写入/var/log/kern.log的所有新行。cut会在开头删除不必要的日志条目前缀。请注意后台进程如何写入终端。

  15. 以服务器模式启动nc,在vm1的所有接口上监听 UDP 端口 1024 。

  16. 以客户端模式启动nc,将字符串Hello there!发送到我们的服务器模式nctail打印出kern.log中的所有新行,你可以看到在 Linux 内核封包过滤器中,我们的单个 UDP 数据包从一个表到了另一个表。没有回复,所以只有一个数据包被发送和处理。

  17. 杀死客户端模式nc

  18. 将服务器模式nc带到前台。

  19. 杀死服务器模式nc

  20. sudo tail -n0 -f /var/log/kern.log | cut -c52-300 &带到前台。

  21. 杀死它。

附加题

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

Last updated