深入理解iptables防火墙

本文部分内容节选自:
netfilter/iptables 简介 – IBM developerWorks

0x00 Linux 安全性和 netfilter/iptables

  • Linux 因其健壮性、可靠性、灵活性以及好象无限范围的可定制性而在 IT 业界变得非常受欢迎。Linux 具有许多内置的能力, 使开发人员可以根据自己的需要定制其工具、行为和外观,而无需昂贵的第三方工具。 如果 Linux 系统连接到因特网或 LAN、服务器或连接 LAN 和因特网的代理服务器, 所要用到的一种内置能力就是针对网络上 Linux 系统的防火墙配置。 可以在 netfilter/iptables IP 信息包过滤系统(它集成在 2.4.x 版本的 Linux 内核中)的帮助下运用这种能力。
  • 在如 ipfwadm和 ipchains 这样的 Linux 信息包过滤解决方案中,netfilter/iptables IP 信息包过滤系统是最新的解决方案, 而且也是第一个集成到 Linux 内核的解决方案。 对于 Linux 系统管理员、网络管理员以及家庭用户(他们 想要根据自己特定的需求来配置防火墙、在防火墙解决方案上节省费用和对 IP 信息包过滤具有完全控制权)来说,netfilter/iptables 系统十分理想。

0x01 理解防火墙配置和信息包过滤

  • 对于连接到网络上的 Linux 系统来说,防火墙是必不可少的防御机制, 它只允许合法的网络流量进出系统,而禁止其它任何网络流量。为了确定网络流量是否合法, 防火墙依靠它所包含的由网络或系统管理员预定义的一组 规则。 这些规则告诉防火墙某个流量是否合法以及对于来自某个源、至某个目的地或具有某种协议类型的网络流量要做些什么。 术语“配置防火墙”是指添加、修改和除去这些规则。稍后,我将详细讨论这些规则。
  • 网络流量由 IP 信息包(或,简称 信息包)— 以流的形式从源系统传输到目的地系统的一些小块数据 — 组成。 这些信息包有头,即在每个包前面所附带的一些数据位,它们包含有关信息包的源、目的地和协议类型的信息。 防火墙根据一组规则检查这些头,以确定接受哪个信息包以及拒绝哪个信息包。我们将该过程称为信息包过滤。

0x02 为什么要配置自己的防火墙?

  • 出于各种因素和原因,需要根据特定需求来配置防火墙。 或许,最重要的原因是安全性。
  • 管理员可能想让他们的防火墙能够阻止未经授权的源访问其 Linux 系统,例如通过 Telnet。 他们可能还想限制进出其系统的网络流量,以便只有来自可信源的流量才可以进入其系统,以及只有授权的流量才可以出去。 家庭用户可能通过允许所有的出站信息包都可以通过,将防火墙配置成较低的安全性级别。
  • 另一个背后的原因是,通过阻塞来自类似广告站点之类的源的多余流量,可以节省带宽。

因而,可以定制防火墙配置来满足任何特定需求和任何安全性级别需求。 这就是 netfilter/iptables 系统的用武之处。

0x03 netfilter/iptables 系统是如何工作的?

  • netfilter/iptables IP 信息包过滤系统是一种功能强大的工具, 可用于添加、编辑和除去规则,这些规则是在做信息包过滤决定时,防火墙所遵循和组成的规则。这些规则存储在专用的信息包过滤表中, 而这些表集成在 Linux 内核中。 在信息包过滤表中,规则被分组放在我们所谓的链(chain)中。我马上会详细讨论这些规则以及如何建立这些规则并将它们分组在链中。
  • 虽然 netfilter/iptables IP 信息包过滤系统被称为单个实体,但它实际上由两个组件 netfilter和 iptables 组成。
  • netfilter 组件也称为 内核空间(kernelspace),是内核的一部分,由一些信息包过滤表组成, 这些表包含内核用来控制信息包过滤处理的规则集。
  • iptables 组件是一种工具,也称为 用户空间(userspace),它使插入、修改和除去信息包过滤表中的规则变得容易。 除非您正在使用 Red Hat Linux 7.1 或更高版本,否则需要从 netfilter.org 下载该工具并安装使用它。
  • 通过使用用户空间,可以构建自己的定制规则,这些规则存储在内核空间的信息包过滤表中。 这些规则具有 目标,它们告诉内核对来自某些源、前往某些目的地或具有某些协议类型的信息包做些什么。 如果某个信息包与规则匹配,那么使用目标 ACCEPT 允许该信息包通过。还可以使用目标 DROPREJECT 来阻塞并杀死信息包。对于可对信息包执行的其它操作,还有许多其它目标。
  • 根据规则所处理的信息包的类型,可以将规则分组在链中。处理入站信息包的规则被添加到 INPUT 链中。处理出站信息包的规则被添加到 OUTPUT 链中。处理正在转发的信息包的规则被添加到 FORWARD 链中。这三个链是基本信息包过滤表中内置的缺省主链。 另外,还有其它许多可用的链的类型(如 PREROUTINGPOSTROUTING ), 以及提供用户定义的链。每个链都可以有一个策略, 它定义“缺省目标”,也就是要执行的缺省操作,当信息包与链中的任何规则都不匹配时,执行此操作。
  • 建立规则并将链放在适当的位置之后,就可以开始进行真正的信息包过滤工作了。 这时内核空间从用户空间接管工作。当信息包到达防火墙时,内核先检查信息包的头信息,尤其是信息包的目的地。 我们将这个过程称为 路由。
  • 如果信息包源自外界并前往系统,而且防火墙是打开的,那么内核将它传递到内核空间信息包过滤表的 INPUT 链。如果信息包源自系统内部或系统所连接的内部网上的其它源,并且此信息包要前往另一个外部系统, 那么信息包被传递到 OUTPUT 链。类似的,源自外部系统并前往外部系统的信息包被传递到 FORWARD 链。
  • 接下来,将信息包的头信息与它所传递到的链中的每条规则进行比较,看它是否与某条规则完全匹配。 如果信息包与某条规则匹配,那么内核就对该信息包执行由该规则的目标指定的操作。 但是,如果信息包与这条规则不匹配,那么它将与链中的下一条规则进行比较。 最后,如果信息包与链中的任何规则都不匹配,那么内核将参考该链的策略来决定如何处理该信息包。 理想的策略应该告诉内核 DROP 该信息包。

0x04 建立规则和链

  • 通过向防火墙提供有关对来自某个源、到某个目的地或具有特定协议类型的信息包要做些什么的指令,规则控制信息包的过滤。 通过使用 netfilter/iptables 系统提供的特殊命令 iptables ,建立这些规则,并将其添加到内核空间的特定信息包过滤表内的链中。关于添加/除去/编辑规则的命令的一般语法如下:
iptables [-t table] command [match] [target]

0x05 表(table)

  • [-t table] 选项允许使用标准表之外的任何表。表是包含仅处理特定类型信息包的规则和链的信息包过滤表。 有三种可用的表选项: filternatmangle 。该选项不是必需的,如果未指定, 则 filter 用作缺省表。
  • filter 表用于一般的信息包过滤,它包含 INPUTOUTPUTFORWARD 链。nat 表用于要转发的信息包,它包含 PREROUTINGOUTPUTPOSTROUTING 链。 如果信息包及其头内进行了任何更改,则使用 mangle 表。 该表包含一些规则来标记用于高级路由的信息包,该表包含 PREROUTINGOUTPUT 链。
  • 注:PREROUTING 链由指定信息包一到达防火墙就改变它们的规则所组成,而 POSTROUTING 链由指定正当信息包打算离开防火墙时改变它们的规则所组成。

0x06 命令(command)

  • 上面这条命令中具有强制性的 command 部分是 iptables 命令的最重要部分。 它告诉 iptables 命令要做什么,例如,插入规则、将规则添加到链的末尾或删除规则。 以下是最常用的一些命令:
  • -A--append : 该命令将一条规则附加到链的末尾。
  • 示例:
iptables -A INPUT -s 205.168.0.1 -j ACCEPT
  • 该示例命令将一条规则附加到 INPUT 链的末尾,确定来自源地址 205.168.0.1 的信息包可以 ACCEPT 。
  • -D--delete : 通过用 -D 指定要匹配的规则或者指定规则在链中的位置编号,该命令从链中删除该规则。 下面的示例显示了这两种方法。
  • 示例:
iptables -D INPUT --dport 80 -j DROP 
iptables -D OUTPUT 3
  • 第一条命令从 INPUT 链删除规则,它指定 DROP 前往端口 80 的信息包。第二条命令只是从 OUTPUT 链删除编号为 3 的规则。
  • -P--policy : 该命令设置链的缺省目标,即策略。 所有与链中任何规则都不匹配的信息包都将被强制使用此链的策略。
  • 示例:
iptables -P INPUT DROP
  • 该命令将 INPUT 链的缺省目标指定为 DROP 。这意味着,将丢弃所有与 INPUT 链中任何规则都不匹配的信息包。
  • -N--new-chain : 用命令中所指定的名称创建一个新链。
  • 示例:
iptables -N allowed-chain
  • -F--flush : 如果指定链名,该命令删除链中的所有规则, 如果未指定链名,该命令删除所有链中的所有规则。此参数用于快速清除。
  • 示例:
iptables -F FORWARD 
iptables -F
  • -X--delete-chain : 如果指定链名,该命令删除这条自定义的链, 如果未指定链名,该命令删除所有自定义的链。此参数用于快速清除所有自定义的链,当然,默认的链无法删除。
  • 示例:
iptables -X MY_OWN_INPUT 
iptables -X
  • -L--list : 列出指定链中的所有规则。
  • 示例:
iptables -L allowed-chain

0x07 匹配(match)

  • iptables 命令的可选 match 部分指定信息包与规则匹配所应具有的特征(如源和目的地地址、协议等)。 匹配分为两大类: 通用匹配和特定于协议的匹配。这里,我将研究可用于采用任何协议的信息包的通用匹配。 下面是一些重要的且常用的通用匹配及其示例和说明:
  • -p--protocol : 该通用协议匹配用于检查某些特定协议。 协议示例有 TCPUDPICMP 、用逗号分隔的任何这三种协议的组合列表以及 ALL (用于所有协议)。 ALL 是缺省匹配。可以使用 ! 符号,它表示不与该项匹配。
  • 示例:
iptables -A INPUT -p TCP, UDP 
iptables -A INPUT -p ! ICMP
  • 在上述示例中,这两条命令都执行同一任务 — 它们指定所有 TCPUDP 信息包都将与该规则匹配。 通过指定 ! ICMP ,我们打算允许所有其它协议(在这种情况下是 TCPUDP ), 而将 ICMP 排除在外。
  • -s--source : 该源匹配用于根据信息包的源 IP 地址来与它们匹配。该匹配还允许对某一范围内的 IP 地址进行匹配,可以使用 ! 符号,表示不与该项匹配。缺省源匹配与所有 IP 地址匹配。
  • 示例:
iptables -A OUTPUT -s 192.168.1.1 
iptables -A OUTPUT -s 192.168.0.0/24 
iptables -A OUTPUT -s ! 203.16.1.89
  • 第二条命令指定该规则与所有来自 192.168.0.0192.168.0.24 的 IP 地址范围的信息包匹配。第三条命令指定该规则将与 除来自源地址 203.16.1.89 外的任何信息包匹配。
  • -d--destination : 该目的地匹配用于根据信息包的目的地 IP 地址来与它们匹配。 该匹配还允许对某一范围内 IP 地址进行匹配,可以使用 ! 符号,表示不与该项匹配。
  • 示例:
iptables -A INPUT -d 192.168.1.1 
iptables -A INPUT -d 192.168.0.0/24 
iptables -A OUTPUT -d ! 203.16.1.89

0x08 目标(target)

  • 我们已经知道,目标是由规则指定的操作,对与那些规则匹配的信息包执行这些操作。 除了允许用户定义的目标之外,还有许多可用的目标选项。下面是常用的一些目标及其示例和说明:
  • ACCEPT : 当信息包与具有 ACCEPT 目标的规则完全匹配时, 会被接受(允许它前往目的地),并且它将停止遍历链(虽然该信息包可能遍历另一个表中的其它链,并且有可能在那里被丢弃)。 该目标被指定为 -j ACCEPT
  • DROP : 当信息包与具有 DROP 目标的规则完全匹配时,会阻塞该信息包,并且不对它做进一步处理。 该目标被指定为 -j DROP
  • REJECT : 该目标的工作方式与 DROP 目标相同,但它比 DROP 好。和 DROP 不同, REJECT 不会在服务器和客户机上留下死套接字。 另外, REJECT 将错误消息发回给信息包的发送方。该目标被指定为 -j REJECT
  • 示例:
iptables -A FORWARD -p TCP --dport 22 -j REJECT
  • RETURN : 在规则中设置的 RETURN 目标让与该规则匹配的信息包停止遍历包含该规则的链。 如果链是如 INPUT 之类的主链,则使用该链的缺省策略处理信息包。 它被指定为 -jump RETURN 。示例:
iptables -A FORWARD -d 203.16.1.89 -jump RETURN
  • 还有许多用于建立高级规则的其它目标,如 LOGREDIRECTMARKMIRRORMASQUERADE 等。

0x09 保存规则

  • 现在,您已经学习了如何建立基本的规则和链以及如何从信息包过滤表中添加或删除它们。 但是,您应该记住:用上述方法所建立的规则会被保存到内核中,当重新引导系统时,会丢失这些规则。 所以,如果您将没有错误的且有效的规则集添加到信息包过滤表,同时希望在重新引导之后再次使用这些规则, 那么必须将该规则集保存在文件中。可以使用 iptables-save命令来做到这一点:
iptables-save > iptables-script
  • 现在,信息包过滤表中的所有规则都被保存在文件 iptables-script 中。无论何时再次引导系统, 都可以使用 iptables-restore 命令将规则集从该脚本文件恢复到信息包过滤表,如下所示:
iptables-restore iptables-script
  • 如果您愿意在每次引导系统时自动恢复该规则集,则可以将上面指定的这条命令放到任何一个初始化 shell 脚本中。

0x0A 仅使用包过滤的困境

  • 在FTP服务中,有主动方式和被动方式之分。其中主动模式比较简单,在主动方式中,FTP使用21和20端口,其中21端口用于传输控制指令,而20端口用于传输数据,主动方式所有报文都需要在20端口排队发送或者接收,这样就限制了服务器的并发性能;而被动方式中,FTP服务器会通过PASV命令通告客户端开放的端口(一般是一个大端口号),然后客户端就来连接。
  • 这样一来就出现了一个问题,因为一般情况下iptables是针对端口进行的防火墙包过滤。如果想使用FTP的被动方式,服务器就需要开放所有1024以上端口,否则客户端的连接会被DROP掉,这样就会变得不安全。但是如果不使用被动方式的话,主动方式的传输速率实在是太慢了。这类问题是iptables包过滤无法解决的问题。
  • 举个例子,我们首先将iptables在INPUT链和OUTPUT链的默认策略都设置为DROP:
iptables -P INPUT DROP
iptables -P OUTPUT DROP
  • 然后我们开放FTP服务器的21和20端口:
iptables -A INPUT -p tcp --dport 21 -j ACCEPT
iptables -A INPUT -p tcp --dport 20 -j ACCEPT
iptables -A OUTPUT -p tcp --sport 21 -j ACCEPT
iptables -A OUTPUT -p tcp --sport 20 -j ACCEPT
  • 这样一来,就可以使用FTP的主动方式来传输数据,我们使用FileZilla来连接这个FTP服务器(位于10.128.0.1):
状态:     正在连接 10.128.0.1:21...
状态:     连接建立,等待欢迎消息...
状态:     不安全的服务器,不支持 FTP over TLS。
状态:     服务器不支持非 ASCII 字符。
状态:     已登录
状态:     开始上传 /Users/xiaolulwr/Documents/CAUC-Tec-Markdown/Linux/深入理解iptables防火墙.md
状态:     文件传输成功,传输了 16,532 字节 (用时1 秒)
状态:     读取“/root”的目录列表...
状态:     计算服务器时差...
状态:     列出“/root”的目录成功
  • 但是一旦我们切换到被动方式,就无法进行数据传输:
状态:     正在连接 10.128.0.1:21...
状态:     连接建立,等待欢迎消息...
状态:     不安全的服务器,不支持 FTP over TLS。
状态:     服务器不支持非 ASCII 字符。
状态:     已登录
状态:     读取目录列表...
命令:     PWD
响应:     257 "/root"
命令:     TYPE I
响应:     200 Switching to Binary mode.
命令:     PASV
响应:     227 Entering Passive Mode (10,128,0,1,230,163)
命令:     LIST
错误:     目录列表被用户终止
  • 当我们使用PASV尝试切换到被动模式之后,切换是可以成功的,但是切换之后再进行操作就无法成功了,原因也很好理解,因为除了关于20和21端口之外的报文都被DROP了。

0x0B 状态检查

  • 为了解决上面的情况,解决方式就是使用iptables的状态检查功能。
  • 状态检查功能,是指iptables除了可以按照IP地址、端口号、协议类型等条件对报文进行过滤之外,还具有一定的对报文的传输状态进行检查的功能,也就是说,iptables可以识别哪些报文属于新产生的连接,哪些报文属于伴随连接。在FTP的被动模式中,PASV协商之后,FTP服务器将通过一个大的随机端口和客户端通信,这些报文就是FTP控制连接的伴随连接的报文。这些报文不是平白无故产生的,如果没有之前的FTP控制连接,就不会产生这些连接和报文。如果黑客想直接连接到大的端口上的话,这些连接就属于新连接。这样一来,就不必开放所有大于1024的端口,同时也可以允许FTP的被动方式了。
  • 我们在上述配置规则之外,再配置下面的规则:
iptables -A INPUT -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT
  • 上面规则的意思是,在iptables的INPUTOUTPUT链上,允许ESTABLISHEDRELATED状态的TCP报文,那么何为连接状态呢?下面介绍四种连接的状态:

    • ESTABLISHED:第一个成功穿越防火墙的报文之后所有的报文;
    • NEW:一个连接的第一个报文,例如TCP连接中的SYN报文;
    • RELATED:伴随连接的报文,即某个已经处于ESTABLISHED的连接所产生的报文,这些报文不属于第一条连接,但是的确是由第一条连接产生的;
    • INVALID:无法判断状态的报文。
  • 当然值得注意的是,iptables的这种状态检查不是十分智能的,它只能识别到运输层的伴随连接,也就是说,对于FTP的协议伴随连接,这种方式并不能很好的进行检查。
  • 在配置之后,就可以正常使用被动方式了:
状态:     正在连接 10.128.0.1:21...
状态:     连接建立,等待欢迎消息...
状态:     不安全的服务器,不支持 FTP over TLS。
状态:     服务器不支持非 ASCII 字符。
状态:     已登录
状态:     开始上传 /Users/xiaolulwr/Documents/CAUC-Personal/个人博客/ssl.txt
状态:     文件传输成功,传输了 3,550 字节 (用时1 秒)
状态:     读取“/root”的目录列表...
状态:     列出“/root”的目录成功
状态:     开始下载 /root/ssl.txt
状态:     文件传输成功,传输了 3,550 字节 (用时1 秒)
状态:     已从服务器断开

0x0C 高级状态检查

0x0D 网络地址转换(NAT)

  • 网络地址转换(NAT)可以解决IPv4地址不足的问题,使用NAT之后,局域网可以对广域网隐藏内部的细节,让整个局域网在广域网上只表现为一个IP地址,这项技术广泛应用于企业网络、校园网络以及运营商的网络,因为并不是所有用户都需要一个广域网的地址,他们只需要一个私有网络的地址就可以了,虽然这个地址不能直接在广域网上使用,但是通过启用了NAT的路由器,这些拥有私有网络地址的设备也可以访问广域网上的资源。当然,随着IPv6的普及,NAT的使用将会逐渐减少。
  • iptables也支持NAT功能,如前所述,iptable上中包含一个NAT表,其中有两条缺省的链,也就是PREROUTINGPOSTROUTING 链,在这两条链上配置规则可以实现NAT功能。
  • 在配置NAT之前,首先回顾一下NAT的两种形式:

    • 源地址转换(SNAT):适用于由局域网中的主机发起连接的情况。报文在经过NAT路由器时,将IP报文中的源IP地址转换为一个有效的广域网地址;在服务器给一个在私有网络中的主机返回响应报文时,目的IP地址就是这个局域网对外的广域网地址。报文到达NAT路由器的时候,路由器要将该报文分发给对应的主机,将IP报文的目的IP地址转换为私有网络地址;
    • 目的地址转换(DNAT):又称为“端口转发”,适用于由广域网上的主机发起连接的情况。当广域网的主机访问NAT路由器的广域网端口时,可以将NAT路由器的广域网的端口映射到局域网内的某个IP地址的某个端口,这样就可以实现广域网主机访问局域网内的资源。
  • 这里需要注意一点就是,SNAT和DNAT的“源”和“目的”指的并不是“源地址转换”和“目的地址转换”,而是指的发起连接的过程中的那个转换,只考虑了请求包。其实可以简单的理解为SNAT就是局域网主机发起连接,DNAT就是广域网主机发起连接,要知道任何一个连接都是双向传输数据,所以在配置防火墙的时候要特别注意这一点。
  • 在iptables上配置NAT时,也可以配置SNAT和DNAT,我们的实验环境有三台主机,它们的基本网络情况如下(注意;这里的172.20.10.0网络仍然是局域网,只是模拟了广域网而已):
主机(作为广域网服务器)
接口名称:wlan
IP地址:172.20.10.4
子网掩码:255.255.255.240
默认网关:172.20.10.1


虚拟机A(作为NAT路由器)
接口名称:ens39(广域网接口)
IP地址:172.20.10.3
子网掩码:255.255.255.240
默认网关:172.20.10.1

接口名称:ens38(局域网接口)
IP地址:192.168.1.1
子网掩码:255.255.255.0
配置:
ifconfig ens38 192.168.1.1 netmask 255.255.255.0


虚拟机B(作为局域网主机)
接口名称:eth1
IP地址:192.168.1.100
子网掩码:255.255.255.0
默认网关:192.168.1.1
配置:
ifconfig eth1 192.168.1.100 netmask 255.255.255.0
route add default gw 192.168.1.1
  • 首先启用虚拟机A的路由转发功能,编辑/etc/sysctl.conf文件
vi /etc/sysctl.conf
  • 新增下面的条目:
net.ipv4.ip_forward=1
  • 使上面的更改立即生效
sysctl -p
  • 现在我们在虚拟机A中配置iptables的NAT表,使虚拟机B可以通过虚拟机A连接到主机的网络。
# 适用于广域网为固定IP地址的情况,本例是这种情况
iptables -t nat -A POSTROUTING -o ens38 -s 192.168.1.0/24 -j SNAT --to-source 172.20.10.3
# 适用于广域网为动态分配IP地址的情况,典型例子是PPPoE
iptables -t nat -A POSTROUTING –o ens38 –s 192.168.1.0/24 –j MASQUERADE
  • 命令的含义就是在路由操作之后,将从ens38接口上的192.168.1.0/24网络上的报文的源IP地址,转换为广域网地址172.20.10.3(或者通过PPPoE得到的动态广域网地址)并发送出去。这样一来,在局域网中的虚拟机2就可以访问广域网上的的资源了。
    原文作者:雾花_小路
    原文地址: https://segmentfault.com/a/1190000014740923
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞