前言
防火墙,说白了就是实现linux下访问控制功能的;从逻辑上大致可以分为主机防火墙和网络防火墙;
- 主机防火墙:针对于单个主机进行防护;
- 网络防火墙:处于网络入口或边缘,针对于网络入口防护,服务于防火墙背后的局域网
从物理上,可以分为硬件防火墙和软件防火墙;
- 硬件防火墙:在硬件级别实现部分防火墙功能,另一部分由软件实现,性能强,成本高;
- 软件防火墙:应用软件处理逻辑运行于通用硬件平台上的防火墙,性能低,成本低;
iptables 历史
iptables的前身叫ipfirewall (核1.x时代),一个作者从freeBSD上移植过来的,能够工作在内核当中的,对数据包进行检测的一款简易访问控制工具。但是ipfirewall工作功能极其有限(它需要将所有的规则都放进内核当中,这样规则才能够运行起来,而放进内核,这个做法一般是极其困难的)。
当内核发展到2.x系列的时候,软件更名为ipchains,它可以定义多条规则,将他们串起来,共同发挥作用,而现在,它叫做iptables,可以将规则组成一个列表,实现绝对详细的访问控制功能。
但对于ipfirewall /ipchains以及iptables而言,它们工作在用户空间中,只是定义规则的工具,不是真正的防火墙;而在内核空间中的netfilter会读取它们定义的规则,并实现让防火墙工作;
netfilter/iptables(下文中简称为iptables)组成Linux平台下的包过滤防火墙,完成封包过滤、封包重定向和网络地址转换(NAT)等功能。
iptables 基础
iptables是按照规则来办事的,那么就先来说说规则(rules),规则其实就是网络管理员预定义的条件,一般定义为”如果数据包头符合这样的条件,就这样处理这个数据包”。
规则存储在内核空间的信息包过滤表中,这些规则分别指定了源地址、目的地址、传输协议(如TCP、UDP、ICMP)和服务类型(如HTTP、FTP和SMTP)等。
当数据包与规则匹配时,iptables就根据规则所定义的方法来处理这些数据包,如放行(accept)、拒绝(reject)和丢弃(drop)等。配置防火墙的主要工作就是添加、修改和删除这些规则;
这样说可能不太好理解,我们来举个例子:
当客户端访问服务器的web服务时,客户端发送报文到网卡,而tcp/ip协议栈是属于内核的一部分,所以,客户端的信息会通过内核的TCP协议传输到用户空间中的web服务中,此时客户端报文的目标终点为web服务所监听的套接字(IP:Port)上;
而当web服务需要响应客户端请求时,web服务发出的响应报文的目标终点则为客户端,这个时候,web服务所监听的IP与端口反而变成了原点;
我们说过,netfilter才是真正的防火墙,它是内核的一部分,所以,如果我们想要防火墙能够达到”防火”的目的,就需要在内核中设置关卡,所有进出的报文都要通过这些关卡,经过检查后,符合放行条件的才能放行,符合阻拦条件的则需要被阻止,于是,就出现了input关卡和output关卡,而这些关卡在iptables中不被称为‘关卡’,而被称为‘链’。
我们上面描述的场景并不完善,因为客户端发来的报文访问的目标地址可能并不是本机,而是其他服务器,当本机的内核支持IP_FORWARD时,我们可以将报文转发给其他服务器,所以,这个时候,我们就会需要iptables中的其他”关卡”。
也就是说,当我们启用了防火墙功能时,报文需要经过如下关卡,也就是说,根据实际情况的不同,报文经过”链”可能不同。如果报文需要转发,那么报文则不会经过input链发往用户空间,而是直接在内核空间中经过forward链和postrouting链转发出去的。
所以,根据上图,我们能够想象出某些常用场景中,报文的流向:
- 到本机某进程的报文:PREROUTING –> INPUT
- 从本机发出的报文(多为响应):OUTPUT –> POSTROUTING
- 由本机转发的报文:PREROUTING –> FORWARD –> POSTROUTING
链的概念
现在,我们思考一下,这些‘关卡’为什么在iptables中被称作”链”呢?
我们知道,防火墙的作用就在于对经过的报文匹配‘规则’,然后执行对应的‘动作’,所以当报文经过这些关卡的时候,必须匹配这个关卡上的规则,但是这些关卡上可能不止有一条规则,而是有很多条规则,当我们把这些规则串到一个链条上的时候,就形成了“链”;
所以把他们称为“链”就更为合适啦,每个经过这个”关卡”的报文,都要将这条“链”上的所有规则匹配一遍,如果有符合条件的规则,则执行规则对应的动作。
表的概念
我们在思考另外一个问题,每个“链”上我们都放置了一串规则,但是这些规则有些很相似,比如,A类规则都是对IP或者端口的过滤,B类规则是修改报文,那么这个时候,我们是不是能把实现相同功能的规则放在一起呢àà必须能的。
所以这边‘表’就出现了,‘表’是具有相同功能的规则的集合;不同功能的规则,我们可以放置在不同的表中进行管理;
iptables已经为我们定义了4种表,每种表对应了不同的功能,而我们定义的规则也都逃脱不了这4种功能的范围,所以学习iptables之前,我们必须先搞明白每种表的作用。
- filter表:负责过滤功能,防火墙;内核模块:iptables_filter
- nat表:网络地址转换功能;内核模块:iptable_nat
- mangle表:拆解报文,做出修改,并重新封装的功能;iptable_mangle
- raw表:关闭nat表上启用的连接追踪机制;iptable_raw
表链关系
但是我们需要注意的是,某些“链”中注定不会包含“某类规则”,某些“关卡”也天生就不具备某些功能;
简单举个例子,A‘关卡’只负责打击陆地敌人,没有防空能力,B‘关卡’只负责打击空中敌人,没有防御步兵的能力,C‘关卡’可能比较NB,既能防空,也能防御陆地敌人,D‘关卡’最屌,海陆空都能防。
那让我们来看看,每个‘关卡’都有哪些能力,或者说,让我们看看每个“链”上的规则都存在于哪些“表”中。
另外我们还需要注意一点,因为数据包经过一个”链”的时候,会将当前链的所有规则都匹配一遍,但是匹配时总归要有顺序,我们应该一条一条的去匹配,而且我们说过,相同功能类型的规则会汇聚在一张”表”中,那么,哪些”表”中的规则会放在”链”的最前面执行呢,这时候就需要有一个优先级的问题;
这里iptables已经为我们制定好了,执行的优先级如下。
优先级次序(由高而低):raw –> mangle –> nat –> filter
为了更方便的管理,我们还可以在某个表里面创建自定义链,将针对某个应用程序所设置的规则放置在这个自定义链中,但是自定义链接不能直接使用,只能被某个默认的链当做动作去调用才能起作用,我们可以这样理解,自定义链就是一段比较”短”的链子,这条”短”链子上的规则都是针对某个应用程序制定的,但是这条短的链子并不能直接使用,而是需要”焊接”在iptables默认定义链子上,才能被IPtables使用,这就是为什么默认定义的”链”需要把”自定义链”当做”动作”去引用的原因。这是后话,后面再聊,在实际使用时我们即可更加的明白。
数据经防火墙流程
结合上述所有的描述,我们可以将数据包通过防火墙的流程总结为下图:
我们在写Iptables规则的时候,要时刻牢记这张路由次序图,灵活配置规则。
iptables规则
说了一圈又说回来了,在上述描述中我们一直在提规则,可是没有细说,现在说说它。
先说说规则的概念,然后再通俗的解释它。
规则:根据指定的匹配条件来尝试匹配每个流经此处的报文,一旦匹配成功,则由规则后面指定的处理动作进行处理;
了解了规则的这个概念,我们也就知道规则由匹配条件和处理动作组成。
匹配条件
匹配条件分为基本匹配条件与扩展匹配条件
- 基本匹配条件:例如-源地址Source IP,目标地址 Destination IP
- 扩展匹配条件:例如-源端口Source Port, 目标端口Destination Port
注:扩展条件其实也是netfilter中的一部分,只是以模块的形式存在,如果想要使用这些条件,则需要依赖对应的扩展模块。
处理动作
处理动作在iptables中被称为target(这样说并不准确,我们暂且这样称呼),动作也可以分为基本动作和扩展动作。
此处列出一些常用的动作,之后的文章会对它们进行详细的示例与总结:
- ACCEPT:允许数据包通过。
- DROP:直接丢弃数据包,不给任何回应信息,这时候客户端会感觉自己的请求泥牛入海了,过了超时时间才会有反应。
- REJECT:拒绝数据包通过,必要时会给数据发送端一个响应的信息,客户端刚请求就会收到拒绝的信息。
- SNAT:源地址转换,解决内网用户用同一个公网地址上网的问题。
- MASQUERADE:是SNAT的一种特殊形式,适用于动态的、临时会变的ip上。
- DNAT:目标地址转换。
- REDIRECT:在本机做端口映射。
- LOG:在/var/log/messages文件中记录日志信息,然后将数据包传递给下一条规则,也就是说除了记录以外不对数据包做任何其他操作,仍然让下一条规则去匹配。
iptables规则操作
之前在iptables的概念中已经提到过,在实际操作iptables的过程中,是以”表”作为操作入口的,那么对于”表”,就会有“增删改查”的操作,当我们定义iptables规则时,所做的操作其实类似于”增删改查”。
查看规则
iptables定义了4张表,它们分别是raw表、mangle表、nat表、filter表,不同的表拥有不同的功能。
filter负责过滤功能,比如允许哪些IP地址访问,拒绝哪些IP地址访问,允许访问哪些端口,禁止访问哪些端口,filter表会根据我们定义的规则进行过滤,filter表应该是我们最常用到的表了,所以此处,我们以filter表为例,开始学习怎样实际操作iptables。
怎样查看filter表中的规则呢?使用如下命令即可查看。
# iptables -t filter -L |
上例中,我们使用-t选项,指定要操作的表,使用-L选项,查看-t选项对应的表的规则,-L选项的意思是,列出规则;
所以,上述命令的含义为列出filter表的所有规则,上图中,显示出了3条链:INPUT链、FORWARD链、OUTPUT链,每条链中都有自己的规则;
前文中,我们打过一个比方,把”链”比作”关卡”,不同的”关卡”拥有不同的能力,所以,从上图中可以看出,INPUT链、FORWARD链、OUTPUT链都拥有”过滤”的能力。所以,当我们要定义某条”过滤”的规则时,我们会在filter表中定义,但是具体在哪条”链”上定义规则呢?这取决于我们的工作场景[s1] 。
刚才提到,我们可以使用iptables -t filter -L命令列出filter表中的所有规则,举一反三,我们也可以查看其它表中的规则,示例如下。
iptables -t raw -L iptables -t mangle -L iptables -t nat -L |
其实,我们可以省略-t filter,当没有使用-t选项指定表时,默认为操作filter表,即iptables -L表示列出filter表中的所有规则。
我们还可以只查看指定表中的指定链的规则,比如,我们只查看filter表中INPUT链的规则,示例如下(注意大小写)。
# iptables -L INPUT |
上图中只显示了filter表中INPUT链中的规则(省略-t选项默认为filter表,也可以指定查看其他链),可以看到信息很少,我们可以使用-v选项,查看出更多的、更详细的信息,示例如下。
# iptables -vL INPUT |
可以看到,使用-v选项后,iptables为我们展示的信息更多了,那么,这些字段都是什么含义呢?这些字段起始就是规则对应的属性,说白了就是规则的各种信息,那么我们来总结一下这些字段的含义。
- pkts :对应规则匹配到的报文的个数。
- bytes:对应匹配到的报文包的大小总和。
- target:规则对应的target,往往表示规则对应的”动作”,即规则匹配成功后需要采取的措施。
- prot:表示规则对应的协议,是否只针对某些协议应用此规则。
- opt:表示规则对应的选项。
- in:表示数据包由哪个接口(网卡)流入,即从哪个网卡来。
- out:表示数据包将由哪个接口(网卡)流出,即到哪个网卡去。
- source:表示规则对应的源头地址,可以是一个IP,也可以是一个网段。
- destination:表示规则对应的目标地址。可以是一个IP,也可以是一个网段。
不过此命令iptables默认为我们进行了名称解析(对地址),但是在规则非常多的情况下如果进行名称解析,效率会比较低,所以,在没有此需求的情况下,我们可以使用-n选项,表示不对IP地址进行名称反解,直接显示IP地址,命令如下。
# iptables -nvL INPUT |
如果你习惯了查看有序号的列表,你在查看iptables表中的规则时肯定会很不爽,没有关系,满足你,使用–line-numbers即可显示规则的编号,示例如下。
# iptables --line-number -nvL INPUT |
我知道你目光如炬,可能早就发现了,表中的每个链的后面都有一个括号,括号里面有一些信息,如上图,那么这些信息都代表了什么呢?我们来看看。
上图中INPUT链后面的括号中包含policy ACCEPT ,2048k packets,176M bytes 三部分。
- policy表示当前链的默认策略,policy ACCEPT表示上图中INPUT的链的默认动作为ACCEPT;
- packets表示当前链(上例为INPUT链)默认策略匹配到的包的数量。
- bytes表示当前链默认策略匹配到的所有包的大小总和。
其实,我们可以把packets与bytes称作”计数器”,上图中的计数器记录了默认策略匹配到的报文数量与总大小,”计数器”只会在使用-v选项时,才会显示出来。
当被匹配到的包达到一定数量时,计数器会自动将匹配到的包的大小转换为可读性较高的单位。但如果你想要查看精确的计数值,而不是经过可读性优化过的计数值,那么你可以使用-x选项,表示显示精确的计数值,示例如下。
# iptables --line-number -nvxL INPUT |
每张表中的每条链都有自己的计数器,链中的每个规则也都有自己的计数器,没错,就是每条规则对应的pkts字段与bytes字段的信息。
所以存在清除计数的选项-Z,根据需要进行使用;示例如下:
# iptables --line-number -nvxL INPUT # iptables -Z # iptables --line-number -nvxL INPUT |
增加规则
由上一章节可以看到,当前filter表中的INPUT链已经不存在任何的规则,但是可以看出,INPUT链的默认策略是ACCEPT,也就是说,INPUT链默认“放行”所有发往本机的报文,当没有任何规则时,会接受所有报文,当报文没有被任何规则匹配到时,也会默认放行报文。
那么此刻,我们就在另外一台机器上,使用ping命令,向当前机器发送报文,如下图所示,ping命令可以得到回应,证明ping命令发送的报文已经正常的发送到了防火墙所在的主机,ping命令所在机器IP地址为192.168.30.136,当前测试防火墙主机的IP地址为192.168.30.61,我们就用这样的环境,对iptables进行操作演示。
那么此处,我们就在61上配置一条规则,拒绝192.168.30.136上的所有报文访问当前机器,之前一直在说,规则由匹配条件与动作组成,那么“拒绝192.168.30.136上的所有报文访问当前机器”这条规则中,报文的“源地址为192.168.30.136″则属于匹配条件,如果满足匹配条件,而“拒绝”这个报文,就属于对应的动作,那么怎样用命令去定义这条规则呢?使用如下命令即可:
# iptables -t filter -I INPUT -s 192.168.30.136 -j DROP # iptables --line-number -nvL INPUT |
上图中,使用 -t选项指定了要操作的表,此处指定了操作filter表,与之前的查看命令一样,不使用-t选项指定表时,默认为操作filter表。
使用-I选项,指明将“规则”插入至哪个链中,-I表示insert,即插入的意思,所以-I INPUT表示将规则插入于INPUT链中,即添加规则之意。
使用-s选项,指明“匹配条件”中的“源地址”,即如果报文的源地址属于-s对应的地址,那么报文则满足匹配条件,-s为source之意,表示源地址。
使用-j选项,指明当“匹配条件”被满足时,所对应的动作,上例中指定的动作为DROP,在上例中,当报文的源地址为192.168.30.136时,报文则被DROP(丢弃)。
再次查看filter表中的INPUT链,发现规则已经被添加了,在iptables中,动作被称之为”target”,所以上图中taget字段对应的动作为DROP。
那么此时,我们再通过192.168.30.136去ping主机61,看看能否ping通。
如上图所示,ping 61主机时,PING命令一直没有得到回应,看来我们的iptables规则已经生效了,ping发送的报文压根没有被61主机接受,而是被丢弃了,所以更不要说什么回应了,好了,我们已经成功的配置了一条iptables规则,看来,我们已经入门了。
还记得我们在前文中说过的”计数器”吗?此时,我们再次查看iptables中的规则,可以看到,已经有13个包被对应的规则匹配到,总计大小1092 bytes。
此时我有个想法,如果我们在这条规则之后再配置一条规则,后面这条规则规定,接受所有来自192.168.30.136主机中的报文,那么,iptables是否会接受来自136主机的报文呢?我们动手试试。
使用如下命令在filter表的INPUT链中追加一条规则,这条规则表示接受所有来自192.168.30.136的发往本机的报文。
# iptables -t filter -A INPUT -s 192.168.30.136 -j ACCEPT # iptables --line-number -nvL INPUT |
上图中,使用-A选项,表示在对应的链中”追加规则”,-A为append之意,所以,-A INPUT则表示在INPUT链中追加规则,而之前示例中使用的-I选项则表示在链中”插入规则”,它们的本意都是添加一条规则,-A表示在链的尾部追加规则,-I表示在链的首部插入规则而已。
执行完添加规则的命令后,再次查看INPUT链,发现规则已经成功”追加”至INPUT链的末尾,那么现在,第一条规则指明了丢弃所有来自192.168.30.136的报文,第二条规则指明了接受所有来自192.168.30.136的报文,那么结果到底是怎样的呢?
实践出真知,在136主机上再次使用ping命令向61主机发送报文,发现仍然是ping不通的,看来第二条规则并没有生效。
而且从图中第二条规则的计数器可以看到,根本没有任何报文被第二条规则匹配到。
聪明如你一定在猜想,发生上述情况,会不会与规则的先后顺序有关呢?那我们再来测试一下:再添加一条规则,新规则仍然规定接受所有来自192.168.30.136主机中的报文,只是这一次,我们将新规则添加至INPUT链的最前面试试。
# iptables -t filter -I INPUT -s 192.168.30.136 -j ACCEPT # iptables --line-number -nvL INPUT |
好了,现在第一条规则就是接受所有来自192.168.30.136的报文,而且此时计数是0,此刻,我们再从136上向61发起ping请求。
136上已经可以正常的收到响应报文了,那么回到61查看INPUT链的规则,第一条规则的计数器已经显示出了匹配到的报文数量。
所以,规则的顺序很重要,如果报文已经被前面的规则匹配到,iptables则会对报文执行对应的动作,此时报文就不会在对后面的规则进行匹配了。
所以我们可以在添加规则时,指定新增规则的编号,这样我们就能在任意位置插入规则了,命令如下。
# iptables -t filter -I INPUT 2 -s 192.168.30.146 -j DROP # iptables --line-number -nvL INPUT |
删除规则
如果我们想要删除filter表中INPUT中的一条规则,该怎么做呢?有两种办法:
- 方法一:根据规则的编号去删除规则
- 方法二:根据具体的匹配条件与动作删除规则
那么我们先看看方法一,首先查看一下filter表中INPUT链中的规则
假如我们想要删除上图中的第3条规则,则可以使用如下命令。
# iptables -t filter -D INPUT 3 # iptables --line-number -nvL INPUT |
上例中,使用-D选项表示删除指定链中的某条规则,-D INPUT 3表示删除INPUT链中的第3条规则。
当然,我们也可以根据具体的匹配条件与动作去删除规则,比如,源地址为192.168.30.136,动作为ACCEPT的规则,于是,删除规则的命令如下。
# iptables --line-number -nvL INPUT # iptables -t filter -D INPUT -s 192.168.30.136 -j ACCEPT # iptables --line-number -nvL INPUT |
上图中,删除对应规则时,仍然使用-D选项,-D INPUT表示删除INPUT链中的规则,剩下的选项与我们添加规则时一毛一样,-s表示以对应的源地址作为匹配条件,-j ACCEPT表示对应的动作为接受。
但我们同时也看到正如报文匹配时一样,当前面的规则被匹配到,就不对后面的规则进行匹配了。
删除指定表中某条链中的所有规则的命令,就是“iptables -t 表名 -F 链名”,-F选项为flush之意,即冲刷指定的链,即删除指定链中的所有规则,但是注意,此操作相当于删除操作,在没有保存iptables规则的情况下,请慎用。
# iptables --line-number -nvL INPUT # iptables -t filter -F INPUT # iptables --line-number -nvL INPUT |
其实,-F选项不仅仅能清空指定链上的规则,它还能清空整个表中所有链上的规则,不指定链名,只指定表名即可删除表中的所有规则,命令:iptables -t 表名 -F
不过再次强调,在没有保存iptables规则时,请勿随便清空链或者表中的规则,除非你明白你在干什么。
修改规则
那么,接下来就到修改操作了,我们怎样修改某条规则中的动作呢?比如,我想把规则中的动作从DROP改为ACCEPT,该怎么办呢?
这时可以使用-R选项修改指定的链中的规则,示例命令如下
# iptables --line-number -nvL INPUT # iptables -t filter -R INPUT 1 -s 192.168.30.136 -j ACCEPT # iptables --line-number -nvL INPUT |
上例中,-R选项表示修改指定的链,使用-R INPUT 1表示修改INPUT链的第1条规则,使用-j ACCEPT表示将INPUT链中的第一条规则的动作修改为REJECT;
注意:上例中-s选项以及对应的源地址不可省略,即使我们已经指定了规则对应的编号,但是在使用-R选项修改某个规则时,必须指定规则对应的原本的匹配条件(如果有多个匹配条件,都需要指定)。
如果上例中的命令没有使用-s指定对应规则中原本的源地址,那么在修改完成后,你修改的规则中的源地址会自动变为0.0.0.0/0(此IP表示匹配所有网段的IP地址),所以与预期就会有差异,当前只是DROP改为ACCEPT还好,如果是ACCEPT改为REJECT,就会造成所有报文都丢弃的情况。
使用-R选项修改规则时,必须指明规则原本的匹配条件,那么我们则可以理解为,只能通过-R选项修改规则对应的动作了;所以我觉得,如果你想要修改某条规则,还不如先将这条规则删除,然后在同样位置再插入一条新规则,这样更好,当然,如果你只是为了修改某条规则的动作,那么使用-R选项时,不要忘了指明规则原本对应的匹配条件。
另外我们提到REJECT,那么DROP与REJECT有什么不同呢?从字面上理解,DROP表示丢弃,REJECT表示拒绝,REJECT表达的意思好像更坚决一点,如果我们将行为改为REJECT后,再次从136主机上向61主机上发起ping请求,看看与之前动作为DROP时有什么不同哪?
如上图所示,当61主机中的iptables规则对应的动作为REJECT时,从136上进行ping操作时,直接就提示”目标不可达”,并没有像之前那样卡在那里,看来,REJECT比DROP更加”干脆”。
其实,我们还可以修改指定链的”默认策略”,当报文没有被链中的任何规则匹配到时,或者,当链中没有任何规则时,防火墙会按照默认动作处理报文,我们可以修改指定链的默认策略,使用如下命令即可。
# iptables -t filter -P INPUT DROP # iptables --line-number -nvL INPUT |
使用-t指定要操作的表,使用-P选项指定要修改的链,上例中,-P INPUT DROP表示将表中INPUT链的默认策略改为DROP。
保存规则
在默认的情况下,我们对”防火墙”所做出的修改都是”临时的”,换句话说就是,当重启iptables服务或者重启服务器以后,我们平常添加的规则或者对规则所做出的修改都将消失,为了防止这种情况的发生,我们需要将规则“保存”,比如使用iptables-save命令。
直接使用‘iptables-save’并不能保存当前的iptables规则,但是可以将当前的iptables规则以”保存后的格式”输出到屏幕上。
# iptables-save |
所以,我们使用iptables-save命令,需要配合重定向,将规则重定向到/etc/sysconfig/iptables-config文件中即可。
# iptables-restore /etc/sysconfig/iptables-config |
我们也可以将/etc/sysconfig/iptables-config中的规则重新载入为当前的iptables规则,但是注意,未保存入/etc/sysconfig/iptables文件中的修改将会丢失或者被覆盖。
使用iptables-restore命令可以从指定文件中重载规则,示例如下
# iptables --line-number -nvL INPUT # iptables-restore < /etc/sysconfig/iptables-config # iptables --line-number -nvL INPUT |
再次提醒:重载规则时,现有规则将会被覆盖。
从现在开始养成及时保存规则的好习惯。
iptables匹配条件
经过前文的理解尝试,我们已经能够熟练的管理规则了,但是我们使用过的“匹配条件”少得可怜,之前的示例中,都只使用过一种匹配条件,就是将”源地址”作为匹配条件。
那么接下来,我们就来了解一下更多的匹配条件,以及匹配条件的更多用法。
匹配条件的更多用法
还是从我们最常用的“源地址”说起吧,我们知道,使用-s选项作为匹配条件,可以匹配报文的源地址,但是之前的示例中,我们每次指定源地址,都只是指定单个IP;
我们也可以在指定源地址时,一次指定多个,用”逗号”隔开即可,示例如下:
# iptables -t filter -I INPUT -s 192.168.30.136,192.168.30.137 -j ACCEPT # iptables --line-number -nvL INPUT |
可以看出,上例中,一次添加了两条规则,两条规则只是源地址对应的IP不同;(注:上例中的”逗号”两侧均不能包含空格,多个IP之间必须与逗号相连)
除了能指定具体的IP地址,还能指定某个网段,示例如下:
# iptables -t filter -I INPUT -s 192.168.30.0/24 -j ACCEPT # iptables --line-number -nvL INPUT |
上例表示,如果报文的源地址IP在192.168.30.0/24网段内,当报文经过INPUT链时允许通过。
其实,我们还可以对匹配条件取反,示例如下:
# iptables -t filter -I INPUT ! -s 192.168.30.135 -j ACCEPT # iptables --line-number -nvL INPUT |
上图中,使用“! -s 192.168.30.135”表示对 -s 192.168.30.135这个匹配条件取反,即报文源地址IP只要不为192.168.30.135即满足条件,那么,上例中规则表达的意思就是,只要发往本机的报文的源地址不是192.168.30.135,就接受报文。
那么此时有个思考,按照上例中的配置,如果此时从135主机上向防火墙所在的主机发送ping请求,135主机能得到回应吗?[s2] (此处不考虑其他链,只考虑filter表的INPUT链);
匹配条件:目的IP
除了可以通过 -s 选项指定源地址作为匹配条件,我们还可以使用-d选项指定“目的地址”作为匹配条件。源地址表示报文从哪里来,目的地址表示报文要到哪里去。
假设当前主机有两个IP地址:192.168.30.61和192.168.30.62;我们只想拒绝30.136向30.61这个发送报文,不想防止30.136向30.62发送,这时就可以指定目的地址作为匹配条件,示例如下:
# iptables -t filter -I INPUT -s 192.168.30.136 -d 192.168.30.61 -j DROP # iptables --line-number -nvL INPUT |
上例表示只丢弃从136发往61这个IP的报文,但是136发往62这个IP的报文并不会被丢弃,如果我们不指定任何目标地址,则目标地址默认为0.0.0.0/0,同理,如果我们不指定源地址,源地址默认为0.0.0.0/0,0.0.0.0/0表示所有IP,示例如下。
# iptables -t filter -I INPUT -d 192.168.30.61 -j DROP # iptables --line-number -nvL INPUT |
上例表示,所有IP发送往30.61的报文都将被丢弃。
与 -s选项一样,-d选项也可以使用“!”进行取反,也能够同时指定多个IP地址,使用“,”隔开即可。
注意:不管是 -s选项还是-d选项,取反操作与同时指定多个IP的操作不能同时用。
另外需要明确的一点就是:当一条规则中有多个匹配条件时,这多个匹配条件之间,默认存在”与”的关系。说白了就是,当一条规则中存在多个匹配条件时,报文必须同时满足这些条件,才算做被规则匹配。
思考一下:有了源IP和目的IP,是不是还有源端口和目的端口的匹配呐?答案是有的,但当前卖个关子,下一章在细说。
匹配条件:协议类型
我们可以使用-p选项,指定需要匹配的报文的协议类型。
假设,我们只想要拒绝来自30.136的tcp类型的请求,那么可以进行如下设置:
# iptables -t filter -I INPUT -s 192.168.30.136 -p tcp -j REJECT # iptables --line-number -nvL INPUT |
上图中,防火墙拒绝了来自30.136的tcp报文,那么我们来测试一下,我们在30.136上使用ssh连接30.61这个IP试试(ssh协议的传输层协议属于tcp协议类型)
如上图所示,ssh连接被拒绝了,那么我们使用ping命令试试 (ping命令使用icmp协议),看看能不能ping通30.61。
可以看到,PING命令可以ping通30.61,证明icmp协议并没有被规则匹配到,只有tcp类型的报文被匹配到了。
那么,-p选项都支持匹配哪些协议呢?我们总结一下
tcp, udp, udplite, icmp, icmpv6,esp, ah, sctp, mh
当不使用-p指定协议类型时,默认表示所有类型的协议都会被匹配到,与使用-p all的效果相同。
匹配条件:网口接口
我们再来认识一个新的匹配条件,当本机有多个网卡时,我们可以使用 -i 选项去匹配报文是通过哪块网卡流入本机的。
我们先动手做个小例子,对-i选项有一个初步的了解以后,再结合理论去看。
当前主机的网卡名称为eth0,如下图:
假设想要拒绝由网卡eth0流入的ping请求报文,则可以进行如下设置:
# iptables -t filter -I INPUT -i eth0 -p icmp -j REJECT # iptables --line-number -nvL INPUT |
上图中,使用-i选项,指定网卡名称,使用-p选项,指定了需要匹配的报文协议类型,上例表示丢弃由eth4网卡流入的icmp类型的报文。
是不是很好理解,但是,我们需要考虑一个问题,-i选项是用于匹配报文流入的网卡的,也就是说,从本机发出的报文是不可能会使用到-i选项的,因为这些由本机发出的报文压根不是从网卡流入的,而是要通过网卡发出的,从这个角度考虑,-i选项的使用是有限制的。
所以还有-o选项,当主机有多块网卡时,可以使用-o选项,匹配报文将由哪块网卡流出,-o选项与-i选项是相对的,-i选项用于匹配报文从哪个网卡流入,-o选项用于匹配报文将从哪个网卡流出。
聪明如你,一定联想到了3.4章节的《数据经防火墙的流程图》,是的-i选项只能用于PREROUTING链、INPUT链、FORWARD链,那么-o选项只能用于FORWARD链、OUTPUT链、POSTROUTING链。
FORWARD链属于”中立国”,它能同时使用-i选项与-o选项。
扩展匹配条件
首先了解一下,什么是扩展匹配条件:不是基本匹配条件的就是扩展匹配条件,这样说好像是句废话;
我们可以这样理解,基本匹配条件我们可以直接使用,而如果想要使用扩展匹配条件,则需要依赖一些扩展模块,或者说,在使用扩展匹配条件之前,需要指定相应的扩展模块才行。
前文中,我们总结了“源地址”与“目的地址”以后,就顺便提到了“源端口”与“目标端口”,但是,为什么刚才不介绍“源端口”与“目标端口”,非要在这里介绍呢?
这是因为“源端口”与“目标端口”属于扩展匹配条件,要想使用“源端口”与“目标端口”,必须先指定协议:比如tcp 或 udp;
匹配条件:目的端口
这里举个例子:我们知道,sshd服务的默认端口为22,当我们使用ssh工具远程连接主机时,默认会连接服务端的22号端口,假设,我们现在想要使用iptables设置一条规则,拒绝来自192.168.30.146的ssh请求,我们就可以拒绝146上的报文能够发往本机的22号端口,这个时候,就需要用到“目标端口”选项。
使用选项--dport可以匹配报文的目标端口,--dport意为destination-port,即表示目标端口。注意,与之前的选项不同,--dport前有两条”横杠”,而且,使用--dport选项时,必须事先指定了使用哪种协议,即必须先使用-p选项,示例如下:
# iptables -t filter -I INPUT -s 192.168.30.136 -p tcp –m tcp --dport 22 -j REJECT # iptables --line-number -nvL INPUT |
上图中,我们就使用了扩展匹配条件--dport,指定了匹配报文的目标端口,如果外来报文的目标端口为本机的22号端口(ssh默认端口),则拒绝之
而在使用--dport之前,我们使用-m选项,指定了对应的扩展模块为tcp,也就是说,如果想要使用--dport这个扩展匹配条件,则必须依靠某个扩展模块完成,上例中,这个扩展模块就是tcp扩展模块,最终,我们使用的是tcp扩展模块中的dport扩展匹配条件。
现在你明白了吗? -m tcp表示使用tcp扩展模块,–dport表示tcp扩展模块中的一个扩展匹配条件,可用于匹配报文的目标端口。
注意,-p tcp与 -m tcp并不冲突,-p用于匹配报文的协议,-m 用于指定扩展模块的名称,正好,这个扩展模块也叫tcp。
其实,上例中,我们可以省略-m选项,示例如下:
# iptables -t filter -I INPUT -s 192.168.30.136 -p tcp --dport 22 -j REJECT # iptables --line-number -nvL INPUT |
当使用-p选项指定了报文的协议时,如果在没有使用-m指定对应的扩展模块名称的情况下,但使用了扩展匹配条件,iptables默认会调用与-p选项对应的协议名称相同的模块。所以,上例中,其实“隐式”的指定了扩展模块 –m tcp,只是没有表现出来罢了。
所以,在使用扩展匹配条件时,一定要注意,如果这个扩展匹配条件所依赖的扩展模块名正好与-p对应的协议名称相同,那么则可省略-m选项,否则则不能省略-m选项,必须使用-m选项指定对应的扩展模块名称。
匹配条件:源端口
有“目的端口”,就有“源端口”,代表“源端口”的扩展匹配条件为--sport
使用--sport可以判断报文是否从指定的端口发出,即匹配报文的源端口是否与指定的端口一致,--sport表示source-port,即表示源端口之意。
因为我们已经搞明白了dport,那么sport我就不再赘述了,示例如下:
# iptables -t filter -I INPUT -s 192.168.30.136 -p tcp --sport 22 -j REJECT # iptables --line-number -nvL INPUT |
上例中,隐含了“-m tcp”之意,表示使用了tcp扩展模块的--sport扩展匹配条件。
扩展匹配条件是可以取反的,同样是使用“!”进行取反,比如 “! --dport 22″,表示目标端口不是22的报文将会被匹配到。
另外不管是--sport还是--dsport,都能够指定一个端口范围,比如,--sport 22:25表示源端口为22到25之间的所有端口,即22端口、23端口、24端口、25端口,示例如下:
# iptables -t filter -I INPUT -s 192.168.30.136 -p tcp --sport 22:25 -j REJECT # iptables --line-number -nvL INPUT |
也可以写成如下图中的模样,下图中第一条规则表示匹配0号到22号之间的所有端口,下图中的第二条规则表示匹配80号端口以及其以后的所有端口(直到65535);
# iptables -t filter -I INPUT -s 192.168.30.136 -p tcp --sport :25 -j REJECT # iptables -t filter -I INPUT -s 192.168.30.136 -p tcp --dport 80: -j REJECT # iptables --line-number -nvL INPUT |
借助tcp扩展模块的--sport或者--dport都可以指定一个连续的端口范围,但是无法同时指定多个离散的、不连续的端口,如果想要同时指定多个离散的端口,需要借助另一个扩展模块,“multiport”模块。
我们可以使用multiport模块的–sports扩展条件同时指定多个离散的源端口。
也可以使用multiport模块的–dports扩展条件同时指定多个离散的目标端口。
示例如下:
# iptables -t filter -I INPUT -s 192.168.30.136 -p tcp -m multiport --dports 22,36,80 -j DROP |
上图示例表示,对来自136的主机上的tcp报文访问本机的22号端口、36号端口以及80号端口的报文进行丢弃。
上图中,“-m multiport --dports 22,36,80″表示使用了multiport扩展模块的–dports扩展条件,以同时指定了多个离散的端口,每个端口之间用逗号隔开。
上图中的-m multiport是不能省略的,如果你省略了-m multiport,就相当于在没有指定扩展模块的情况下,使用了扩展条件(“--dports”),那么上例中,iptables会默认调用“-m tcp”,但是,“--dports扩展条件”并不属于”tcp扩展模块”,而是属于”multiport扩展模块”,所以,这时就会报错。
同样,使用multiport模块的--sports与--dpors时,也可以指定连续的端口范围,并且能够在指定连续的端口范围的同时,指定离散的端口号,示例如下。
# iptables -t filter -I INPUT -s 192.168.30.136 -p tcp -m multiport --dports 22,36:80 -j DROP |
上例中的命令表示拒绝来自192.168.30.136的tcp报文访问当前主机的22号端口以及36到88之间的所有端口号,是不是很方便?有没有很灵活?
不过需要注意,multiport扩展只能用于tcp协议与udp协议,即配合-p tcp或者-p udp使用。
扩展模块
前文已经总结了iptables中的基本匹配条件,以及简单的扩展匹配条件,此处,我们来认识一些新的扩展模块。
iprange扩展模块
之前我们已经总结过,在不使用任何扩展模块的情况下,使用-s选项或者-d选项即可匹配报文的源地址与目标地址,而且在指定IP地址时,可以同时指定多个IP地址,每个IP用”逗号”隔开,但是,-s选项与-d选项并不能一次性的指定一段连续的IP地址范围,如果我们需要指定一段连续的IP地址范围,可以使用iprange扩展模块。
使用iprange扩展模块可以指定”一段连续的IP地址范围”,用于匹配报文的源地址或者目标地址。
iprange扩展模块中有两个扩展匹配条件可以使用
- --src-range
- --dst-range
没错,见名知意,上述两个选项分别用于匹配报文的源地址所在范围与目标地址所在范围。
# iptables -t filter -I INPUT -m iprange --src-range 192.168.30.136-192.168.30.141 -j DROP # iptables -t filter -I INPUT -m iprange --dst-range 192.168.30.150-192.168.30.160 -j DROP |
上例表示如果报文的源IP地址如果在192.168.30.136到192.168.30.141之间,则丢弃报文,IP段的始末IP使用“横杠”连接,--src-range与--dst-range和其他匹配条件一样,能够使用”!”取反,有了前文中的知识作为基础,此处就不再赘述了。
其他扩展模块
这里不一一进行赘述,详细可参考: iptables-朱双印博客
iptables黑白名单机制
前文中一直在强调一个概念:报文在经过iptables的链时,会匹配链中的规则,遇到匹配的规则时,就执行对应的动作,如果链中的规则都无法匹配到当前报文,则使用链的默认策略(默认动作),链的默认策略通常设置为ACCEPT或者DROP。
“黑名单”机制:就是当链的默认策略为ACCEPT时,链中的规则对应的动作应该为DROP或者REJECT,表示只有匹配到规则的报文才会被拒绝,没有被规则匹配到的报文都会被默认接受;
而“白名单”机制则反过来,即当链的默认策略为DROP时,链中的规则对应的动作应该为ACCEPT,表示只有匹配到规则的报文才会被放行,没有被规则匹配到的报文都会被默认拒绝。
当然在默认策略为ACCEPT时,我们也可以在设置规则时,设置对应动作为ACCEPT,那么所有报文都会被放行了,因为不管报文是否被规则匹配到都会被ACCEPT,所以就失去了访问控制的意义。同理默认策略为DROP时,置对应动作为DROP时一个道理。
总结:
- 如果使用白名单机制,我们就要把所有人都当做坏人,只放行好人。
- 如果使用黑名单机制,我们就要把所有人都当成好人,只拒绝坏人。
白名单机制似乎更加安全一些,黑名单机制似乎更加灵活一些。
但使用白名单时还是有坑的,比如我已修改默认策略为DROP了,但不小心执行了“iptables -F”操作,根据我们之前学到的知识去判断,我们无法通过ssh工具远程到服务器上了;不止ssh远程请求会被拒绝,其他报文也会被拒绝;
所以,我们如果想要使用“白名单”机制时,最好还是将链的默认策略保持“ACCEPT”,然后在链的尾部加上“拒绝所有请求”的规则,将必备的“放行规则”放在前面,这样做,既能实现”白名单”机制,又能保证在规则被清空时,管理员还有机会连接到主机,示例如下:
# iptables -I INPUT -p tcp --dport 22 -j ACCEPT # iptables -I INPUT -p tcp --dport 23 -j ACCEPT # iptables -A INPUT -j ACCEPT # iptables --line-number -nvL INPUT |
上图中的设置,既将INPUT链的默认策略设置为了ACCEPT,同时又使用了白名单机制,因为如果报文符合放行条件,则会被前面的放行规则匹配到,如果报文不符合放行条件,则会被最后一条拒绝规则匹配到,此刻,即使我们误操作,执行了”iptables -F”操作,也能保证管理员能够远程到主机上进行维护,因为默认策略仍然是ACCEPT。
iptables 自启动设置
将iptables报文规则的位置在OS启动时,进行加载即可;一般在使能iptables时,就会有此启动脚本,如果没有可创建一个;
打开此脚本进行查看确认iptables保存规则的文件位置:
后续我们进行添加和修改iptables都保存一下,在OS自启动时就会按照最新的设计进行下发规则;
iptables 命令总结
iptables语法:
iptables (选项) (参数) |
选项:
-t <表> | 指定要操纵的表 |
-A | 向规则链中添加条目(从尾部添加) |
-D | 向规则链中删除条目 |
-I | 向规则链中插入条目(默认从头部,也可指定line num) |
-R | 向规则链中替换条目(需指定规则对应的原本的匹配条件) |
-L | 显示规则链中已有的条目 |
-F | 清除规则链中已有的条目 |
-N | 创建新的用户自定义规则链(这个没有详细介绍,有兴趣参考链接) |
-P | 修改特定链的默认策略,例:-P INPUT DROP |
-Z | 清除计数统计 |
-h | 提示信息 |
-p | 指定协议,可以是all、tcp、udp等 |
-s | 指定源地址 |
-d | 指定目的地址 |
-i | 指定数据包的输入网卡 |
-o | 指定数据包的输出网卡 |
-j | 指定动作选择,如:ACCEPT、DROP、REJECT |
-v | 显示详细信息,通常与-L一起使用 |
-n | 显示行号信息,通常与-vL一起使用 |
-x | 显示详细统计信息,通信与-L一起使用 |
-m | 指定扩展模块,如tcp、udp |
--sport | 指定源端口,需要扩展模块:-m tcp/udp,才可使用 |
--dport | 指定目的端口,需要扩展模块:-m tcp/udp,才可使用 |
参考链接
[s1]比如,我们需要禁止某个IP地址访问我们的主机,我们则需要在INPUT链上定义规则。因为,我们在前文已经提到过,报文发往本机时,会经过PREROUTING链与INPUT链,所以我们想要禁止某些报文发往本机,我们只能在PREROUTING链和INPUT链中定义规则,但是PREROUTING链并不存在于filter表中,所以,我们只能在INPUT链中定义,当然,如果是其他工作场景,可能需要在FORWARD链或者OUTPUT链中定义过滤规则。
[s2]能,为什么呢?
1)上例中,filter表的INPUT链中只有一条规则,这条规则要表达的意思就是:
只要报文的源IP不是192.168.30.135,那么就接受此报文;
2)192.168.30.135的ping,是不会命中此规则,且也没有其他的规则命中,所以会使用默认规则,即通过;
对于第一点某些小伙伴可能会误会,把上例中的规则理解成如下含义:只要报文的源IP是192.168.1.146,那么就不接受此报文,这样理解是错误的,上述第一点的理解才是正确的。
换句话说就是,报文的源IP不是192.168.1.146时,会被接收,并不能代表,报文的源IP是192.168.1.146时,会被拒绝。