iptables详解及应用(史上最全)

1.1 iptables概念

从逻辑上讲。防火墙可以大体分为主机防火墙和网络防火墙。
主机防火墙:针对于单个主机进行防护。
网络防火墙:往往处于网络入口或边缘,针对于网络入口进行防护,服务于防火墙背后的本地局域网。
网络防火墙和主机防火墙并不冲突,可以理解为,网络防火墙主外(集体), 主机防火墙主内(个人)。
从物理上讲,防火墙可以分为硬件防火墙和软件防火墙。
硬件防火墙:在硬件级别实现部分防火墙功能,另一部分功能基于软件实现,性能高,成本高。
软件防火墙:应用软件处理逻辑运行于通用硬件平台之上的防火墙,性能低,成本低
iptables其实不是真正的防火墙,我们可以把它理解成一个客户端代理,用户通过iptables这个代理,将用户的安全设定执行到对应的"安全框架"中,这个"安全框架"才是真正的防火墙,这个框架的名字叫netfilter
netfilter才是防火墙真正的安全框架(framework),netfilter位于内核空间。
iptables其实是一个命令行工具,位于用户空间,我们用这个工具操作真正的框架。
netfilter/iptables(下文中简称为iptables)组成Linux平台下的包过滤防火墙,与大多数的Linux软件一样,这个包过滤防火墙是免费的,它可以代替昂贵的商业防火墙解决方案,完成封包过滤、封包重定向和网络地址转换(NAT)等功能。
Netfilter是Linux操作系统核心层内部的一个数据包处理模块,它具有如下功能:
网络地址转换(Network Address Translate)
数据包内容修改
以及数据包过滤的防火墙功能
所以说,虽然我们使用service iptables start启动iptables"服务",但是其实准确的来说,iptables并没有一个守护进程,所以并不能算是真正意义上的服务,而应该算是内核提供的功能。

1.1.1 链的概念

现在,我们想象一下,这些"关卡"在iptables中为什么被称作"链"呢?我们知道,防火墙的作用就在于对经过的报文匹配"规则",然后执行对应的"动作",所以,当报文经过这些关卡的时候,则必须匹配这个关卡上的规则,但是,这个关卡上可能不止有一条规则,而是有很多条规则,当我们把这些规则串到一个链条上的时候,就形成了"链",所以,我们把每一个"关卡"想象成如下图中的模样 ,这样来说,把他们称为"链"更为合适,每个经过这个"关卡"的报文,都要将这条"链"上的所有规则匹配一遍,如果有符合条件的规则,则执行规则对应的动作。

1.1.2 表的概念

我们再想想另外一个问题,我们对每个"链"上都放置了一串规则,但是这些规则有些很相似,比如,A类规则都是对IP或者端口的过滤,B类规则是修改报文,那么这个时候,我们是不是能把实现相同功能的规则放在一起呢,必须能的。
我们把具有相同功能的规则的集合叫做"表",所以说,不同功能的规则,我们可以放置在不同的表中进行管理,而iptables已经为我们定义了4种表,每种表对应了不同的功能,而我们定义的规则也都逃脱不了这4种功能的范围,所以,学习iptables之前,我们必须先搞明白每种表 的作用。
表,可以理解成配置文件,把每个钩子函数的参数写在配置文件中,才能生效。钩子函数本身就是个函数。
iptables为我们提供了如下规则的分类,
filter表:负责过滤功能,防火墙;内核模块:iptables_filter
nat表:network address translation,网络地址转换功能;内核模块:iptable_nat
mangle表:拆解报文,做出修改,并重新封装 的功能;iptable_mangle
raw表:关闭nat表上启用的连接追踪机制;iptable_raw
也就是说,我们自定义的所有规则,都是这四种分类中的规则,或者说,所有规则都存在于这4张"表"中。

1.1.3 表链关系

但是我们需要注意的是,某些"链"中注定不会包含"某类规则",就像某些"关卡"天生就不具备某些功能一样,比如,A"关卡"只负责打击陆地敌人,没有防空能力,B"关卡"只负责打击空中敌人,没有防御步兵的能力,C"关卡"可能比较NB,既能防空,也能防御陆地敌人,D"关卡"最屌,海陆空都能防。
那让我们来看看,每个"关卡"都有哪些能力,或者说,让我们看看每个"链"上的规则都存在于哪些"表"中。
prerouting"链"只拥有nat表、raw表和mangle表所对应的功能,所以,prerouting中的规则只能存放于nat表、raw表和mangle表中。
那么,根据上述思路,我们来总结一下,每个"关卡"都拥有什么功能,
或者说,每个"链"中的规则都存在于哪些"表"中。
PREROUTING 的规则可以存在于:raw表,mangle表,nat表。
INPUT 的规则可以存在于:mangle表,filter表,(centos7中还有nat表,centos6中没有)。
FORWARD 的规则可以存在于:mangle表,filter表。
OUTPUT 的规则可以存在于:raw表mangle表,nat表,filter表。
POSTROUTING 的规则可以存在于:mangle表,nat表
但是,我们在实际的使用过程中,往往是通过"表"作为操作入口,对规则进行定义的,之所以按照上述过程介绍iptables,是因为从"关卡"的角度更容易从入门的角度理解,但是为了以便在实际使用的时候,更加顺畅的理解它们,此处我们还要将各"表"与"链"的关系罗列出来,
表(功能)<–> 链(钩子):
raw 表中的规则可以被哪些链使用:PREROUTING,OUTPUT
mangle 表中的规则可以被哪些链使用:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING
nat 表中的规则可以被哪些链使用:PREROUTING,OUTPUT,POSTROUTING(centos7中还有INPUT,centos6中没有)
filter 表中的规则可以被哪些链使用:INPUT,FORWARD,OUTPUT
其实我们还需要注意一点,因为数据包经过一个"链"的时候,会将当前链的所有规则都匹配一遍,但是匹配时总归要有顺序,我们应该一条一条的去匹配,而且我们说过,相同功能类型的规则会汇聚在一张"表"中,那么,哪些"表"中的规则会放在"链"的最前面执行呢,这时候就需要有一个优先级的问题
prerouting链中的规则存放于三张表中,而这三张表中的规则执行的优先级如下:
raw --> mangle --> nat
但是我们知道,iptables为我们定义了4张"表",当他们处于同一条"链"时,执行的优先级如下。
优先级次序(由高而低):
raw --> mangle --> nat --> filter
但是我们前面说过,某些链天生就不能使用某些表中的规则,所以,4张表中的规则处于同一条链的目前只有output链,它就是传说中海陆空都能防守的关卡。
为了更方便的管理,我们还可以在某个表里面创建自定义链,将针对某个应用程序所设置的规则放置在这个自定义链中,但是自定义链接不能直接使用,只能被某个默认的链当做动作去调用才能起作用,我们可以这样想象,自定义链就是一段比较"短"的链子,这条"短"链子上的规则都是针对某个应用程序制定的,但是这条短的链子并不能直接使用,而是需要"焊接"在iptables默认定义链子上,才能被IPtables使用,这就是为什么默认定义的"链"需要把"自定义链"当做"动作"去引用的原因。这是后话,后面再聊,在实际使用时我们即可更加的明白。

1.1.4 数据经过防火墙的流程

链的规则存放于哪些表中(从链到表的对应关系):
PREROUTING 的规则可以存在于:raw表,mangle表,nat表。
INPUT 的规则可以存在于:mangle表,filter表,(centos7中还有nat表,centos6中没有)。
FORWARD 的规则可以存在于:mangle表,filter表。
OUTPUT 的规则可以存在于:raw表mangle表,nat表,filter表。
POSTROUTING 的规则可以存在于:mangle表,nat表。
表中的规则可以被哪些链使用(从表到链的对应关系):
raw 表中的规则可以被哪些链使用:PREROUTING,OUTPUT
mangle 表中的规则可以被哪些链使用:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING
nat 表中的规则可以被哪些链使用:PREROUTING,OUTPUT,POSTROUTING(centos7中还有INPUT,centos6中没有)
filter 表中的规则可以被哪些链使用:INPUT,FORWARD,OUTPUT

1.1.5 规则的概念

先说说规则的概念,然后再通俗的解释它。
规则:根据指定的匹配条件来尝试匹配每个流经此处的报文,一旦匹配成功,则由规则后面指定的处理动作进行处理;
那么我们来通俗的解释一下什么是iptables的规则,之前打过一个比方,每条"链"都是一个"关卡",每个通过这个"关卡"的报文都要匹配这个关卡上的规则,如果匹配,则对报文进行对应的处理,比如说,你我二人此刻就好像两个"报文",你我二人此刻都要入关,可是城主有命,只有器宇轩昂的人才能入关,不符合此条件的人不能入关,于是守关将士按照城主制定的"规则",开始打量你我二人,最终,你顺利入关了,而我已被拒之门外,因为你符合"器宇轩昂"的标准,所以把你"放行"了,而我不符合标准,所以没有被放行,其实,“器宇轩昂"就是一种"匹配条件”,“放行"就是一种"动作”,"匹配条件"与"动作"组成了规则。
了解了规则的概念,那我们来聊聊规则的组成部分,此处只是大概的将规则的结构列出,后面的文章中会单独对规则进行总结。
规则由匹配条件和处理动作组成
匹配条件
匹配条件分为基本匹配条件与扩展匹配条件
基本匹配条件:
源地址Source IP,目标地址 Destination IP
上述内容都可以作为基本匹配条件。
扩展匹配条件:
除了上述的条件可以用于匹配,还有很多其他的条件可以用于匹配,这些条件泛称为扩展条件,这些扩展条件其实也是netfilter中的一部分,只是以模块的形式存在,如果想要使用这些条件,则需要依赖对应的扩展模块。
源端口Source Port, 目标端口Destination Port
上述内容都可以作为扩展匹配条件
处理动作
处理动作在iptables中被称为target(这样说并不准确,我们暂且这样称呼),动作也可以分为基本动作和扩展动作。
此处列出一些常用的动作,之后的文章会对它们进行详细的示例与总结:
ACCEPT:允许数据包通过。
DROP:直接丢弃数据包,不给任何回应信息,这时候客户端会感觉自己的请求泥牛入海了,过了超时时间才会有反应。
REJECT:拒绝数据包通过,必要时会给数据发送端一个响应的信息,客户端刚请求就会收到拒绝的信息。
SNAT:源地址转换,解决内网用户用同一个公网地址上网的问题。
MASQUERADE:是SNAT的一种特殊形式,适用于动态的、临时会变的ip上。
DNAT:目标地址转换。
REDIRECT:在本机做端口映射。
LOG:在/var/log/messages文件中记录日志信息,然后将数据包传递给下一条规则,也就是说除了记录以外不对数据包做任何其他操作,仍然让下一条规则去匹配

1.2 iptables实际操作之规则查询

之前在iptables的概念中已经提到过,在实际操作iptables的过程中,是以"表"作为操作入口的,如果你经常操作关系型数据库,那么当你听到"表"这个词的时候,你可能会联想到另一个词----“增删改查”,当我们定义iptables规则时,所做的操作其实类似于"增删改查",那么,我们就先从最简单的"查"操作入手,开始实际操作iptables。
在之前的文章中,我们已经总结过,iptables为我们预定义了4张表,它们分别是raw表、mangle表、nat表、filter表,不同的表拥有不同的功能。
filter负责过滤功能,比如允许哪些IP地址访问,拒绝哪些IP地址访问,允许访问哪些端口,禁止访问哪些端口,filter表会根据我们定义的规则进行过滤,filter表应该是我们最常用到的表了,所以此处,我们以filter表为例,开始学习怎样实际操作iptables
INPUT链、FORWARD链、OUTPUT链,每条链中都有自己的规则,前文中,我们打过一个比方,把"链"比作"关卡",不同的"关卡"拥有不同的能力,
我们在理论总结中已经提到过,报文发往本机时,会经过PREROUTING链与INPUT链(如果你没有明白,请回顾前文),所以,如果我们想要禁止某些报文发往本机,我们只能在PREROUTING链和INPUT链中定义规则,但是PREROUTING链并不存在于filter表中,换句话说就是,PREROUTING关卡天生就没有过滤的能力,所以,我们只能在INPUT链中定义,当然,如果是其他工作场景,可能需要在FORWARD链或者OUTPUT链中定义过滤规则。
刚才提到,我们可以使用iptables -t filter -L命令列出filter表中的所有规则,那么举一反三,我们也可以查看其它表中的规则,示例如下。

iptables -t raw -L
iptables -t mangle -L
iptables -t nat -L

其实,我们可以省略-t filter,当没有使用-t选项指定表时,默认为操作filter表,即iptables -L表示列出filter表中的所有规则。
可以看到,使用-v选项后,iptables为我们展示的信息更多了,那么,这些字段都是什么意思呢?我们来总结一下,看不懂没关系,等到实际使用的时候,自然会明白,此处大概了解一下即可。
其实,这些字段就是规则对应的属性,说白了就是规则的各种信息,那么我们来总结一下这些字段的含义。
pkts:对应规则匹配到的报文的个数。
bytes:对应匹配到的报文包的大小总和。
target:规则对应的target,往往表示规则对应的"动作",即规则匹配成功后需要采取的措施。
prot:表示规则对应的协议,是否只针对某些协议应用此规则。
opt:表示规则对应的选项。
in:表示数据包由哪个接口(网卡)流入,我们可以设置通过哪块网卡流入的报文需要匹配当前规则。
out:表示数据包由哪个接口(网卡)流出,我们可以设置通过哪块网卡流出的报文需要匹配当前规则。
source:表示规则对应的源头地址,可以是一个IP,也可以是一个网段。
destination:表示规则对应的目标地址。可以是一个IP,也可以是一个网段。
当然,我们也可以只查看某个链的规则,并且不让IP进行反解,这样更清晰一些,比如 iptables -nvL INPUT
-line-numbers选项并没有对应的短选项,不过我们缩写成–line时,centos中的iptables也可以识别
policy表示当前链的默认策略,policy ACCEPT表示上图中INPUT的链的默认动作为ACCEPT,换句话说就是,默认接受通过INPUT关卡的所有请求,所以我们在配置INPUT链的具体规则时,应该将需要拒绝的请求配置到规则中,说白了就是"黑名单"机制,默认所有人都能通过,只有指定的人不能通过,当我们把INPUT链默认动作设置为接受(ACCEPT),就表示所有人都能通过这个关卡,此时就应该在具体的规则中指定需要拒绝的请求,就表示只有指定的人不能通过这个关卡,这就是黑名单机制,但是,你一定发现了,上图中所显示出的规则,大部分都是接受请求(ACCEPT),并不是想象中的拒绝请求(DROP或者REJECT),这与我们所描述的黑名单机制不符啊,按照道理来说,默认动作为接受,就应该在具体的规则中配置需要拒绝的人
packets表示当前链(上例为INPUT链)默认策略匹配到的包的数量,0 packets表示默认策略匹配到0个包。
bytes表示当前链默认策略匹配到的所有包的大小总和。
其实,我们可以把packets与bytes称作"计数器",上图中的计数器记录了默认策略匹配到的报文数量与总大小,"计数器"只会在使用-v选项时,才会显示出来。
当被匹配到的包达到一定数量时,计数器会自动将匹配到的包的大小转换为可读性较高的单位,如下图所示。
iptables详解(2):iptables实际操作之规则查询
如果你想要查看精确的计数值,而不是经过可读性优化过的计数值,那么你可以使用-x选项,表示显示精确的计数值,示例如下。
iptables详解(2):iptables实际操作之规则查询
每张表中的每条链都有自己的计数器,链中的每个规则也都有自己的计数器,没错,就是每条规则对应的pkts字段与bytes字段的信息。

1.2.1 命令小结

iptables -t 表名 -L
查看对应表的所有规则,-t选项指定要操作的表,省略"-t 表名"时,默认表示操作filter表,-L表示列出规则,即查看规则。
iptable -t 表名 -L链名
查看指定表的指定链中的规则
iptables --line-numbers -t 表名 -L
表示查看表的所有规则,并且显示规则的序号,–line-numbers选项表示显示规则的序号,注意,此选项为长选项,不能与其他短选项合并,不过此选项可以简写为–line,注意,简写后仍然是两条横杠,仍然是长选项
iptables -t FILTER -nvxL INPUT //-n不反解,显示数字,-v详细,-x详细计数,-L链

1.3 iptables规则管理

首先,我们来回顾一下什么是iptables的规则。
之前打过一个比方,每条"链"都是一个"关卡",每个通过这个"关卡"的报文都要匹配这个关卡上的规则,如果匹配,则对报文进行对应的处理,比如说,你我二人此刻就好像两个"报文",你我二人此刻都要入关,可是城主有命,只有器宇轩昂之人才能入关,不符合此条件的人不能入关,于是守关将士按照城主制定的"规则",开始打量你我二人,最终,你顺利入关了,而我已被拒之门外,因为你符合"器宇轩昂"的标准,所以把你"放行"了,而我不符合标准,所以没有被放行,其实,“器宇轩昂"就是一种"匹配条件”,“放行"就是一种"动作”,“匹配条件"与"动作"组成了规则
只不过,在iptables的世界中,最常用的匹配条件并不是"器宇轩昂”,而是报文的"源地址"、“目标地址”、“源端口”、"目标端口"等,在iptables的世界中,最常用的动作有ACCEPT(接受)、DROP(丢弃)、REJECT(拒绝),其中ACCEPT就与我们举例中的"放行"类似,但是,我们刚才提到的这些并不是全部的匹配条件与动作,只是最常用的一些罢了,具体的匹配条件与动作不是我们今天讨论的重点,我们会在以后的文章中再做总结
好了,我们已经回顾了规则的概念,并且已经明白了,规则大致由两个逻辑单元组成,匹配条件与动作,那么多说无益,我们来动手定义一条规则,此处仍然以filter表中的INPUT链为例,因为filter表负责"过滤"功能,而所有发往本机的报文如果需要被过滤,首先会经过INPUT链(PREROUTING链没有过滤功能),这与我们所比喻的"入关"场景非常相似,所以,使用filter表的INPUT链为例,有助于我们进行理解。
首先,查看一下filter表中的INPUT链中的规则,查看规则的相关命令在前文已经总结了,此处不再赘述,如果你忘了,请回顾前文。
使用如下命令查看filter表INPUT链的规则,下图中的规则为centos6默认添加的规则
为了准备一个从零开始的环境,以便我们进行实验,使用iptables -F INPUT命令清空filter表INPUT链中的规则,后面我们会单独对清除规则的相关命令进行总结,此处不用纠结此命令.
清空INPUT链以后,filter表中的INPUT链已经不存在任何的规则,但是可以看出,INPUT链的默认策略是ACCEPT,也就是说,INPUT链默认"放行"所有发往本机的报文,当没有任何规则时,会接受所有报文,当报文没有被任何规则匹配到时,也会默认放行报文
那么此刻,我们就在另外一台机器上,使用ping命令,向当前机器发送报文,如下图所示,ping命令可以得到回应,证明ping命令发送的报文已经正常的发送到了防火墙所在的主机,

1.3.1 增加规则

使用-I选项,指明将"规则"插入至哪个链中,-I表示insert,即插入的意思,所以-I INPUT表示将规则插入于INPUT链中,即添加规则之意。
使用-s选项,指明"匹配条件"中的"源地址",即如果报文的源地址属于-s对应的地址,那么报文则满足匹配条件,-s为source之意,表示源地址。
使用-j选项,指明当"匹配条件"被满足时,所对应的动作,上例中指定的动作为DROP,在上例中,当报文的源地址为192.168.1.146时,报文则被DROP(丢弃)。
再次查看filter表中的INPUT链,发现规则已经被添加了,在iptables中,动作被称之为"target",所以,上图中taget字段对应的动作为DROP。
还记得我们在前文中说过的"计数器"吗?此时,我们再次查看iptables中的规则,可以看到,已经有24个包被对应的规则匹配到,总计大小2016bytes。
现在INPUT链中已经存在了一条规则,它拒绝了所有来自192.168.1.146主机中的报文,如果此时,我们在这条规则之后再配置一条规则,后面这条规则规定,接受所有来自192.168.1.146主机中的报文,那么,iptables是否会接受来自146主机的报文呢?我们动手试试
使用-A选项,表示在对应的链中"追加规则",-A为append之意,所以,-A INPUT则表示在INPUT链中追加规则,而之前示例中使用的-I选项则表示在链中"插入规则",聪明如你一定明白了,它们的本意都是添加一条规则,只是-A表示在链的尾部追加规则,-I表示在链的首部插入规则而已。
使用-j选项,指定当前规则对应的动作为ACCEPT。
执行完添加规则的命令后,再次查看INPUT链,发现规则已经成功"追加"至INPUT链的末尾,那么现在,第一条规则指明了丢弃所有来自192.168.1.146的报文,第二条规则指明了接受所有来自192.168.1.146的报文,那么结果到底是怎样的呢?实践出真知,在146主机上再次使用ping命令向156主机发送报文,发现仍然是ping不通的,看来第二条规则并没有生效。
如果报文已经被前面的规则匹配到,iptables则会对报文执行对应的动作,即使后面的规则也能匹配到当前报文,很有可能也没有机会再对报文执行相应的动作了,就以上图为例,报文先被第一条规则匹配到了,于是当前报文被"放行"了,因为报文已经被放行了,所以,即使上图中的第二条规则即使能够匹配到刚才"放行"的报文,也没有机会再对刚才的报文进行丢弃操作了。这就是iptables的工作机制
之前在总结查看命令时提到过,使用–line-number选项可以列出规则的序号,如下图所示
iptables详解(3):iptables规则管理
我们也可以在添加规则时,指定新增规则的编号,这样我们就能在任意位置插入规则了,我们只要把刚才的命令稍作修改即可,如下。
iptables详解(3):iptables规则管理
仍然使用-I选项进行插入规则操作,-I INPUT 2表示在INPUT链中新增规则,新增的规则的编号为2,好了,自己动手试试吧。

[root@node-101 ~]#iptables -t filter -A  INPUT -p icmp -s 192.168.122.103 -j REJECT   //-A默认添加在最后
#添加规则后从103 ping 192.168.122.101不通,但是可以用ssh
[root@node-103 ~]#ssh 192.168.122.101
Last login: Fri Oct 18 11:04:17 2019 from 172.18.43.4
 Waring ...,if you not root,Please get out! 
[root@node-101 ~]#iptables -t filter -vnxL INPUT --line
Chain INPUT (policy ACCEPT 229 packets, 17430 bytes)
num      pkts      bytes target     prot opt in     out     source               destination         
1          74     6216 REJECT     icmp --  *      *       192.168.122.103      0.0.0.0/0            reject-with icmp-port-unreachable
[root@node-101 ~]#iptables -S
-A INPUT -s 192.168.122.103/32 -p icmp -j REJECT --reject-with icmp-port-unreachable

可以查看当前的规则指令。

1.3.2 删除规则

此刻,如果我们想要删除filter表中INPUT中的一条规则,该怎么做呢?
有两种办法
方法一:根据规则的编号去删除规则
iptables --line -vnL INPUT //查看INPUT链。
比如像删除第二条规则,可用iptables -t filter -D INPUT 3 //-t filter是默认值,可以不写
删除规则用-D,-D INPUT表示删除INPUT链中的规则,-D INPUT 3表示删除第三条规则。
方法二:根据具体的匹配条件与动作删除规则
[root@node-101 ~]#iptables -S
-A INPUT -s 192.168.122.103/32 -p icmp -j REJECT //根据查询到的指定,进行匹配删除
[root@node-101 ~]#iptables -D INPUT -s 192.168.122.103 -p icmp -j REJECT
[root@node-101 ~]#iptables -vnxL INPUT
Chain INPUT (policy ACCEPT 102 packets, 7775 bytes)
pkts bytes target prot opt in out source destination
查看INPUT链规则已经没有了。
而删除指定表中某条链中的所有规则的命令,我们在一开始就使用到了,就是"iptables -t 表名 -F 链名"
-F选项为flush之意,即冲刷指定的链,即删除指定链中的所有规则,但是注意,此操作相当于删除操作,在没有保存iptables规则的情况下,请慎用。
其实,-F选项不仅仅能清空指定链上的规则,其实它还能清空整个表中所有链上的规则,不指定链名,只指定表名即可删除表中的所有规则,命令如下
iptables -t 表名 -F
不过再次强调,在没有保存iptables规则时,请勿随便清空链或者表中的规则,除非你明白你在干什么。

1.3.3 修改规则

-R选项表示修改指定的链,使用-R 需要把原来定义规则的语句重新写,跟定义一个新的规则一样,只不过是把原来插入-I的选项,变成了-R,
后面要跟具体详细的规则。-R其实相当于把原来的规则先删掉,然后在相同的位置,添加新的完整的规则。
使用-R选项修改规则时,必须指明规则原本的匹配条件,那么我们则可以理解为,只能通过-R选项修改规则对应的动作了,所以我觉得,如果你想要修改某条规则,还不如先将这条规则删除,然后在同样位置再插入一条新规则
其实,我们还可以修改指定链的"默认策略"。iptables -P INPUT DROP //修改默认规则。默认时允许,现在改成拒绝。
但是强烈建议不要这么做。因为如果清空了规则,那么远程的ssh就再也连不上了,如果想要实现相同的效果,可以在最后一行
添加默认的拒绝规则,那么以后每次添加规则用-I INPUT #N指定插入位置即可。

1.3.4 保存规则

在默认的情况下,我们对"防火墙"所做出的修改都是"临时的",换句话说就是,当重启iptables服务或者重启服务器以后,我们平常添加的规则或者对规则所做出的修改都将消失,为了防止这种情况的发生,我们需要将规则"保存"。
centos7与centos6中的情况稍微有些不同,我们先说centos6中怎样保存iptables规则
centos6中,使用"service iptables save"命令即可保存规则,规则默认保存在/etc/sysconfig/iptables文件中,如果你刚刚安装完centos6,在刚开始使用iptables时,会发现filter表中会有一些默认的规则,这些默认提供的规则
其实就保存在/etc/sysconfig/iptables中
当我们对规则进行了修改以后,如果想要修改永久生效,必须使用service iptables save保存规则,当然,如果你误操作了规则,但是并没有保存,那么使用service iptables restart命令重启iptables以后,规则会再次回到上次保存/etc/sysconfig/iptables文件时的模样
centos7中,已经不再使用init风格的脚本启动服务,而是使用unit文件,所以,在centos7中已经不能再使用类似service iptables start这样的命令了,所以service iptables save也无法执行,同时,在centos7中,使用firewall替代了原来的iptables service,不过不用担心,我们只要通过yum源安装iptables与iptables-services即可(iptables一般会被默认安装,但是iptables-services在centos7中一般不会被默认安装),在centos7中安装完iptables-services后,即可像centos6中一样,通过service iptables save命令保存规则了,规则同样保存在/etc/sysconfig/iptables文件中。

#配置好yum源以后安装iptables-service
# yum install -y iptables-services
#停止firewalld
# systemctl stop firewalld
#禁止firewalld自动启动
# systemctl disable firewalld
#启动iptables
# systemctl start iptables
#将iptables设置为开机自动启动,以后即可通过iptables-service控制iptables服务
# systemctl enable iptables

还可以使用另一种方法保存iptables规则,就是使用iptables-save命令
使用iptables-save并不能保存当前的iptables规则,但是可以将当前的iptables规则以"保存后的格式"输出到屏幕上。
所以,我们可以使用iptables-save命令,再配合重定向,将规则重定向到/etc/sysconfig/iptables文件中即可。
iptables-save > /etc/sysconfig/iptables
我们也可以将/etc/sysconfig/iptables中的规则重新载入为当前的iptables规则,但是注意,未保存入/etc/sysconfig/iptables文件中的修改将会丢失或者被覆盖。
使用iptables-restore命令可以从指定文件中重载规则,示例如下
iptables-restore < /etc/sysconfig/iptables
再次提醒:重载规则时,现有规则将会被覆盖

1.3.5 命令小结
命令语法:iptables -t 表名 -A 链名 匹配条件 -j 动作
示例:iptables -t filter -A INPUT -s 192.168.1.146 -j DROP
命令语法:iptables -t 表名 -I 链名 匹配条件 -j 动作
示例:iptables -t filter -I INPUT -s 192.168.1.146 -j ACCEPT
命令语法:iptables -t 表名 -I 链名 规则序号 匹配条件 -j 动作
示例:iptables -t filter -I INPUT 5 -s 192.168.1.146 -j REJECT
命令语法:iptables -t 表名 -P 链名 动作
示例:iptables -t filter -P FORWARD ACCEPT
#删除规则
命令语法:iptables -t 表名 -D 链名 规则序号
示例:iptables -t filter -D INPUT 3
命令语法:iptables -t 表名 -F 链名
示例:iptables -t filter -F INPUT
命令语法:iptables -t 表名 -F
示例:iptables -t filter -F
#修改规则
命令语法:iptables -t 表名 -R 链名 规则序号 规则原本的匹配条件 -j 动作
示例:iptables -t filter -R INPUT 3 -s 192.168.1.146 -j ACCEPT
命令语法:iptables -t 表名 -P 链名 动作
示例:iptables -t filter -P FORWARD ACCEPT
#保存规则
service iptables save
iptables-save > /etc/sysconfig/iptables
iptables-restore < /etc/sysconfig/iptables

1.4 iptables匹配条件

1.4.1 目标IP地址

除了可以通过-s选项指定源地址作为匹配条件,我们还可以使用-d选项指定"目标地址"作为匹配条件。
源地址表示报文从哪里来,目标地址表示报文要到哪里去。
除了127.0.0.1回环地址以外,当前机器有两个IP地址,IP如下。
iptables详解(4):iptables匹配条件总结之一
假设,我们想要拒绝146主机发来的报文,但是我们只想拒绝146向156这个IP发送报文,并不想要防止146向101这个IP发送报文,我们就可以指定目标地址作为匹配条件,示例如下。
iptables详解(4):iptables匹配条件总结之一
上例表示只丢弃从146发往156这个IP的报文,但是146发往101这个IP的报文并不会被丢弃,如果我们不指定任何目标地址,则目标地址默认为0.0.0.0/0,同理,如果我们不指定源地址,源地址默认为0.0.0.0/0,0.0.0.0/0表示所有IP,示例如下。
iptables详解(4):iptables匹配条件总结之一
上例表示,所有IP发送往101的报文都将被丢弃。
与-s选项一样,-d选项也可以使用"叹号"进行取反,也能够同时指定多个IP地址,使用"逗号"隔开即可。
但是请注意,不管是-s选项还是-d选项,取反操作与同时指定多个IP的操作不能同时使用。
需要明确的一点就是:当一条规则中有多个匹配条件时,这多个匹配条件之间,默认存在"与"的关系。
说白了就是,当一条规则中存在多个匹配条件时,报文必须同时满足这些条件,才算做被规则匹配。
我们除了能够使用-s选项和-d选项匹配源IP与目标IP以外,还能够匹配"源端口"与"目标端口"

1.4.2 协议类型

我们可以使用-p选项,指定需要匹配的报文的协议类型
假设,我们只想要拒绝来自203的tcp类型的请求,那么可以进行如下设置

[root@node-101 ~]#iptables -t filter -I INPUT -s 172.18.43.4 -j ACCEPT //把自己的windows加入允许
iptables -t filter -A INPUT -p tcp -j REJECT   //拒绝所有的tcp协议连接
[root@node-102 ~]#ping 192.168.122.101          //能ping通
PING 192.168.122.101 (192.168.122.101) 56(84) bytes of data.
64 bytes from 192.168.122.101: icmp_seq=1 ttl=64 time=0.316 ms
[root@node-102 ~]#ssh 192.168.122.101
ssh: connect to host 192.168.122.101 port 22: Connection refused    //ssh连接失败

那么,-p选项都支持匹配哪些协议呢?我们总结一下
centos6中,-p选项支持如下协议类型
tcp,udp,udplite,icpm,esp,ah,sctp
udp-lite ,传统的udp协议传输会对载荷(Payload)进行完整的校验的,如果其中的一些位错了,那么整个数据包可能被
丢弃,但是udp-lite定义了是否需要对载荷进行校验,或者校验缩少位是由用户控制,可以用于一些对应用层对轻微差错不特别
敏感的情况,比如视频直播。
esp:封装安全载荷 stcp SCTP是一种面向消息的传输协议
tcp, udp, udplite, icmp, icmpv6,esp, ah, sctp, mh
当不使用-p指定协议类型时,默认表示所有类型的协议都会被匹配到,与使用-p all的效果相同

1.4.3 网卡接口

我们再来认识一个新的匹配条件,当本机有多个网卡时,我们可以使用 -i 选项去匹配报文是通过哪块网卡流入本机的
假设想要拒绝由网卡eth1流入的ping请求报文,则可以进行如下设置

[root@node-101 ~]#iptables -t filter -A INPUT -i eth1 -p icmp -j REJECT
[root@node-102 ~]#ping 172.18.43.101
PING 172.18.43.101 (172.18.43.101) 56(84) bytes of data.
From 172.18.43.101 icmp_seq=1 Destination Port Unreachable    //172地址过来已经不通
[root@node-101 ~]#tcpdump -i eth1 -p icmp -vv     //对eth1进行抓包分析
172.18.43.103 > node-101.centos76.com: ICMP echo request, id 15237, seq 53, length 64
14:50:47.989193 IP (tos 0xc0, ttl 64, id 41757, offset 0, flags [none], proto ICMP (1), length 112)
node-101.centos76.com > 172.18.43.103: ICMP node-101.centos76.com protocol 1 port 45978 unreachable, length 92
IP (tos 0x0, ttl 64, id 16569, offset 0, flags [DF], proto ICMP (1), length 84)
#可以看到收到了报文,但是回应的是unreachable,且每次回应都是随机端口。如果在102机器指定用192地址网卡ping呢?
[root@node-103 ~]#ping 172.18.43.101 -I eth0
PING 172.18.43.101 (172.18.43.101) from 192.168.122.103 eth0: 56(84) bytes of data.  //仍是不通。抓包无数据
[root@node-102 ~]#ping 192.168.122.101
PING 192.168.122.101 (192.168.122.101) 56(84) bytes of data.
64 bytes from 192.168.122.101: icmp_seq=1 ttl=64 time=0.284 ms
64 bytes from 192.168.122.101: icmp_seq=2 ttl=64 time=0.250 ms   //从eth0 192地址过来还是通的

以上设置还有个问题,由于eth1是访问公网的ip,所以ping 公网也是不通。可以想办法,自己能ping通别人,但是外部机器无法ping进来
既然-i选项是用于判断报文是从哪个网卡流入的,那么,-i选项只能用于上图中的PREROUTING链、INPUT链、FORWARD链,这是-i选项的特殊性,
因为它只是用于判断报文是从哪个网卡流入的,所以只能"数据流入流向"的链中与FORWARD链中存在,而"数据发出流向"经过的链中,
是不可能使用-i选项的,OTPUT链与POSTROUTING链,他们都不能使用-i选项。
当主机有多块网卡时,可以使用-o选项,匹配报文将由哪块网卡流出,没错,-o选项与-i选项是相对的,-i选项用于匹配报文从哪个网卡流入,-o选项用于匹配报文将从哪个网卡流出。
聪明如你,一定想到了,-i选项只能用于PREROUTING链、INPUT链、FORWARD链,那么-o选项只能用于FORWARD链、OUTPUT链、POSTROUTING链。
因为-o选项是用于匹配报文将由哪个网卡"流出"的,所以与上图中的"数据进入流向"中的链没有任何缘分,所以,-o选项只能用于FORWARD链、OUTPUT链、POSTROUTING链中。
看来,FORWARD链属于"中立国",它能同时使用-i选项与-o选项。

1.4.4 扩展匹配条件:

我们知道,sshd服务的默认端口为22,当我们使用ssh工具远程连接主机时,默认会连接服务端的22号端口,假设,我们现在想要使用iptables设置一条规则,拒绝来自192.168.1.146的ssh请求,
我们就可以拒绝146上的报文能够发往本机的22号端口,这个时候,就需要用到"目标端口"选项。
使用选项–dport可以匹配报文的目标端口,–dport意为destination-port,即表示目标端口。

[root@node-101 ~]#iptables -t filter -A INPUT -s 192.168.122.103 -p tcp -m tcp --dport 22 -j REJECT
[root@node-102 ~]#ssh 192.168.122.101
Last login: Fri Oct 18 14:19:25 2019 from 172.18.43.4
 Waring ...,if you not root,Please get out! 
[root@node-101 ~]#
[root@node-103 ~]#ssh 192.168.122.101
ssh: connect to host 192.168.122.101 port 22: Connection refused   //拒绝了103的ssh连接

注意,与之前的选项不同,–dport前有两条"横杠",而且,使用–dport选项时,必须事先指定了使用哪种协议,即必须先使用-p选项,示例如下
我们就使用了扩展匹配条件–dport,指定了匹配报文的目标端口,如果外来报文的目标端口为本机的22号端口(ssh默认端口),则拒绝之,而在使用–dport之前,我们使用-m选项,指定了对应
的扩展模块为tcp
注意,-p tcp与 -m tcp并不冲突,-p用于匹配报文的协议,-m 用于指定扩展模块的名称,正好,这个扩展模块也叫tcp。
当使用-p选项指定了报文的协议时,如果在没有使用-m指定对应的扩展模块名称的情况下,使用了扩展匹配条件, iptables默认会调用与-p选项对应的协议名称相同的模块。
上例中,我们使用-p选项指定了协议名称,使用扩展匹配条件–dport指定了目标端口,在使用扩展匹配条件的时候,如果没有使用-m指定使用哪个扩展模块,iptables会默认使用"-m 协议名",而协议名就是-p选项对应的协议名,上例中,-p 对应的值为tcp,所以默认调用的扩展模块就为-m tcp,如果-p对应的值为udp,那么默认调用的扩展模块就为-m udp。
所以,上例中,其实"隐式"的指定了扩展模块,只是没有表现出来罢了
使用–sport可以判断报文是否从指定的端口发出,即匹配报文的源端口是否与指定的端口一致,–sport表示source-port,即表示源端口之意
扩展匹配条件是可以取反的,同样是使用"!"进行取反,比如 “! --dport 22”,表示目标端口不是22的报文将会被匹配到
借助tcp扩展模块的–sport或者–dport都可以指定一个连续的端口范围,但是无法同时指定多个离散的、不连续的端口,如果想要同时指定多个离散的端口,需要借助另一个扩展模块,"multiport"模块。
我们可以使用multiport模块的–sports扩展条件同时指定多个离散的源端口。
我们可以使用multiport模块的–dports扩展条件同时指定多个离散的目标端口。
"-m multiport --dports 22,36,80"表示使用了multiport扩展模块的–dports扩展条件,以同时指定了多个离散的端口,每个端口之间用逗号隔开
其实,使用multiport模块的–sports与–dpors时,也可以指定连续的端口范围,并且能够在指定连续的端口范围的同时,指定离散的端口号

[root@node-101 ~]#iptables -t filter -A INPUT -p tcp -s 192.168.122.102 -m multiport --dports 22,23,80:88 -j REJECT 
[root@node-101 ~]#iptables -vnL INPUT 3 --line
3       12  2560 REJECT     tcp  --  *      *       192.168.122.102      0.0.0.0/0            multiport dports 22,23,80:88 reject-with icmp-port-unreachable
[root@node-102 ~]#ssh 192.168.122.101
ssh: connect to host 192.168.122.101 port 22: Connection refused  //ssh拒绝
[root@node-102 ~]#curl 192.168.122.101
curl: (7) Failed connect to 192.168.122.101:80; Connection refused //80拒绝
[root@node-102 ~]#telnet 192.168.122.101
Trying 192.168.122.101...
telnet: connect to address 192.168.122.101: Connection refused     //23拒绝
[root@node-103 ~]#telnet 192.168.122.101
Trying 192.168.122.101...
Connected to 192.168.122.101.
Escape character is '^]'.
Kernel 3.10.0-957.el7.x86_64 on an x86_64
node-101 login: 

上例中的命令表示拒绝来自192.168.1.146的tcp报文访问当前主机的22号端口以及80到88之间的所有端口号,是不是很方便?有没有很灵活?
不过需要注意,multiport扩展只能用于tcp协议与udp协议,即配合-p tcp或者-p udp使用。

1.4.5 小结
基础用法

-s用于匹配报文的源地址,可以同时指定多个源地址,每个IP之间用逗号隔开,也可以指定为一个网段。
#####示例如下

iptables -t filter -I INPUT -s 192.168.1.111,192.168.1.118 -j DROP
iptables -t filter -I INPUT -s 192.168.1.0/24 -j ACCEPT
iptables -t filter -I INPUT ! -s 192.168.1.0/24 -j ACCEPT

-d用于匹配报文的目标地址,可以同时指定多个目标地址,每个IP之间用逗号隔开,也可以指定为一个网段。
#####示例如下

iptables -t filter -I OUTPUT -d 192.168.1.111,192.168.1.118 -j DROP
iptables -t filter -I INPUT -d 192.168.1.0/24 -j ACCEPT
iptables -t filter -I INPUT ! -d 192.168.1.0/24 -j ACCEPT

-p用于匹配报文的协议类型,可以匹配的协议类型tcp、udp、udplite、icmp、esp、ah、sctp等(centos7中还支持icmpv6、mh)。
#示例如下

iptables -t filter -I INPUT -p tcp -s 192.168.1.146 -j ACCEPT
iptables -t filter -I INPUT ! -p udp -s 192.168.1.146 -j ACCEPT

-i用于匹配报文是从哪个网卡接口流入本机的,由于匹配条件只是用于匹配报文流入的网卡,所以在OUTPUT链与POSTROUTING链中不能使用此选项

#示例如下
iptables -t filter -I INPUT -p icmp -i eth4 -j DROP
iptables -t filter -I INPUT -p icmp ! -i eth4 -j DROP

-o用于匹配报文将要从哪个网卡接口流出本机,于匹配条件只是用于匹配报文流出的网卡,所以在INPUT链与PREROUTING链中不能使用此选项。

#示例如下
iptables -t filter -I OUTPUT -p icmp -o eth4 -j DROP
iptables -t filter -I OUTPUT -p icmp ! -o eth4 -j DROP
扩展模块用法

tcp扩展模块
常用的扩展匹配条件如下:
-p tcp -m tcp --sport 用于匹配tcp协议报文的源端口,可以使用冒号指定一个连续的端口范围
-p tcp -m tcp --dport 用于匹配tcp协议报文的目标端口,可以使用冒号指定一个连续的端口范围
#示例如下

iptables -t filter -I OUTPUT -d 192.168.1.146 -p tcp -m tcp --sport 22 -j REJECT
iptables -t filter -I INPUT -s 192.168.1.146 -p tcp -m tcp --dport 22:25 -j REJECT
iptables -t filter -I INPUT -s 192.168.1.146 -p tcp -m tcp --dport :22 -j REJECT
iptables -t filter -I INPUT -s 192.168.1.146 -p tcp -m tcp --dport 80: -j REJECT
iptables -t filter -I OUTPUT -d 192.168.1.146 -p tcp -m tcp ! --sport 22 -j ACCEPT

常用的扩展匹配条件如下:
-p tcp -m multiport --sports 用于匹配报文的源端口,可以指定离散的多个端口号,端口之间用"逗号"隔开
-p udp -m multiport --dports 用于匹配报文的目标端口,可以指定离散的多个端口号,端口之间用"逗号"隔开
#示例如下

iptables -t filter -I OUTPUT -d 192.168.1.146 -p udp -m multiport --sports 137,138 -j REJECT
iptables -t filter -I INPUT -s 192.168.1.146 -p tcp -m multiport --dports 22,80 -j REJECT
iptables -t filter -I INPUT -s 192.168.1.146 -p tcp -m multiport ! --dports 22,80 -j REJECT
iptables -t filter -I INPUT -s 192.168.1.146 -p tcp -m multiport --dports 80:88 -j REJECT
iptables -t filter -I INPUT -s 192.168.1.146 -p tcp -m multiport --dports 22,80:88 -j REJECT

1.5 常用扩展模块

1.5.1 iprange扩展模块

之前我们已经总结过,在不使用任何扩展模块的情况下,使用-s选项或者-d选项即可匹配报文的源地址与目标地址,
而且在指定IP地址时,可以同时指定多个IP地址,每个IP用"逗号"隔开,但是,-s选项与-d选项并不能一次性的指定一段连续的IP地址范围,如果我们需要指定一段连续的IP地址范围,可以使用iprange扩展模块。
使用iprange扩展模块可以指定"一段连续的IP地址范围",用于匹配报文的源地址或者目标地址。
iprange扩展模块中有两个扩展匹配条件可以使用
–src-range
–dst-range
没错,见名知意,上述两个选项分别用于匹配报文的源地址所在范围与目标地址所在范围。

iptables -t filter -A INPUT -m iprange --src-range 192.168.122.200-192.168.122.254 -j DROP
1.5.2 string扩展模块

使用string扩展模块,可以指定要匹配的字符串,如果报文中包含对应的字符串,则符合匹配条件。
比如,如果报文中包含字符"OOXX",我们就丢弃当前报文。
首先,我们在IP为101的主机上启动http服务,然后在默认的页面目录中添加两个页面,页面中的内容分别为"OOXX"和"Hello World",如下图所示,在没有配置任何规则时,103主机可以正常访问146主机上的这两个页面。

[root@node-101 ~]#echo "hello world " > /var/www/html/index.html
[root@node-101 ~]#echo "abc OOXX string  " > /var/www/html/index2.html
[root@node-103 ~]#curl 192.168.122.101
hello world 
[root@node-103 ~]#curl 192.168.122.101/index2.html
abc OOXX string  
[root@node-103 ~]#iptables -t filter -A INPUT -m string --algo bm --string "OOXX" -j REJECT   //注意在103设置规则
[root@node-103 ~]#curl 192.168.122.101
hello world 
[root@node-103 ~]#curl 192.168.122.101/index2.html   //卡住了
curl: (56) Recv failure: Connection reset by peer    //黄花菜都凉了以后。。才报错

那么,我们想要达到的目的是,如果报文中包含"OOXX"字符,我们就拒绝报文进入本机,所以,我们可以在126上进行如下配置。
上图中,’-m string’表示使用string模块,’–algo bm’表示使用bm算法去匹配指定的字符串,’ --string “OOXX” '则表示我们想要匹配的字符串为"OOXX"
设置完上图中的规则后,由于index.html中包含"OOXX"字符串,所以,146的回应报文无法通过126的INPUT链,所以无法获取到页面对应的内容。
那么,我们来总结一下string模块的常用选项
–algo:用于指定匹配算法,可选的算法有bm与kmp,此选项为必须选项,我们不用纠结于选择哪个算法,但是我们必须指定一个。
–string:用于指定需要匹配的字符串。

1.5.3 time扩展模块

我们可以通过time扩展模块,根据时间段区匹配报文,如果报文到达的时间在指定的时间范围以内,则符合匹配条件。
比如,“我想要自我约束,下午13点到16:31不能看网页”,多么残忍的规定,如果你想要这样定义,可以尝试使用如下规则

[root@node-103 ~]#iptables -t filter -A OUTPUT -p tcp -m multiport --dports 80,443 -m time --timestart 05:00:00 --timestop 08:31:00 -j REJECT 
[root@node-103 ~]#date
Fri Oct 18 16:29:55 CST 2019       //主意啊规则中定义的时间是UTC时间,所以要做时区转换
[root@node-103 ~]#curl 192.168.122.101
curl: (7) Failed connect to 192.168.122.101:80; Connection refused
[root@node-103 ~]#date
Fri Oct 18 16:32:04 CST 2019       //16:32对应UTC时间的08:32
[root@node-103 ~]#curl 192.168.122.101
hello world 
-m time --monthdays 22,23  //每月的22,23号
-m time --weekdays 5 //每周五
-m --datestart 2019-10-18 --datestop 1029-10-30  

"-m time"表示使用time扩展模块,–timestart选项用于指定起始时间,–timestop选项用于指定结束时间。控制不上网是作用在output链,
及不让出去。

1.5.4 connlimit模块

使用connlimit扩展模块,可以限制每个IP地址同时链接到server端的链接数量,注意:我们不用指定IP,其默认就是针对"每个客户端IP",即对单IP的并发连接数限制。
比如,我们想要限制,每个IP地址最多只能占用两个ssh链接远程到server端,我们则可以进行如下限制。

[root@node-101 ~]#iptables -t filter -A INPUT -p tcp --dport 22 -m connlimit --connlimit-above 2 -j REJECT
[root@node-103 ~]#ssh 192.168.122.101
ssh: connect to host 192.168.122.101 port 22: Connection refused    //第三个连接,被拒绝

使用"-m connlimit"指定使用connlimit扩展,使用"–connlimit-above 2"表示限制每个IP的链接数量上限为2,再配合-p tcp --dport 22,即表示限制每个客户端IP的ssh并发链接数量不能高于2。
刚才说过,–connlimit-above默认表示限制"每个IP"的链接数量,其实,我们还可以配合–connlimit-mask选项,去限制"某类网段"的链接数量,示例如下

1.5.5 limit扩展模块

刚才认识了connlimit模块,现在来认识一下limit模块。
connlimit模块是对连接数量进行限制的,limit模块是对"报文到达速率"进行限制的。
用大白话说就是,如果我想要限制单位时间内流入的包的数量,就能用limit模块。
我们可以以秒为单位进行限制,也可以以分钟、小时、天作为单位进行限制。
比如,限制每秒中最多流入3个包,或者限制每分钟最多流入30个包,都可以。
那么,我们来看一个最简单的示例,假设,我们想要限制,外部主机对本机进行ping操作时,本机最多每6秒中放行一个ping包,那么,我们可以进行如下设置(注意,只进行如下设置有可能无法实现限制功能,请看完后面的内容)

[root@node-101 ~]#iptables -t filter -A INPUT -p icmp -m limit --limit 10/minute -j ACCEPT

实测发现不管用,这是因为该规则动作是ACCEPT,然后没有被匹配到的会被默认的规则匹配,即允许放行。所以要在此规则后紧跟默认的拒绝规则。

root@node-101 ~]#iptables -t filter -A INPUT -p icmp -m limit --limit 10/minute -j ACCEPT 
[root@node-101 ~]#iptables -t filter  -A INPUT -p icmp -j REJECT 

两条规则配合才可以生效。另外还有指定默认初始值,即前多少个不做限制。如果通过一个机器的多个终端同时ping该主机,服务端则由的是按IP计算,由的终端可能会很久才能收到应答报文或者干脆收不到。

1.5.6 命令总结

iprange模块
包含的扩展匹配条件如下
–src-range:指定连续的源地址范围
–dst-range:指定连续的目标地址范围
#示例

iptables -t filter -I INPUT -m iprange --src-range 192.168.1.127-192.168.1.146 -j DROP
iptables -t filter -I OUTPUT -m iprange --dst-range 192.168.1.127-192.168.1.146 -j DROP
iptables -t filter -I INPUT -m iprange ! --src-range 192.168.1.127-192.168.1.146 -j DROP

string模块
常用扩展匹配条件如下
–algo:指定对应的匹配算法,可用算法为bm、kmp,此选项为必需选项。
–string:指定需要匹配的字符串
#示例

iptables -t filter -I INPUT -p tcp --sport 80 -m string --algo bm --string "OOXX" -j REJECT
iptables -t filter -I INPUT -p tcp --sport 80 -m string --algo bm --string "OOXX" -j REJECT

time模块
常用扩展匹配条件如下
–timestart:用于指定时间范围的开始时间,不可取反
–timestop:用于指定时间范围的结束时间,不可取反
–weekdays:用于指定"星期几",可取反
–monthdays:用于指定"几号",可取反
–datestart:用于指定日期范围的开始日期,不可取反
–datestop:用于指定日期范围的结束时间,不可取反
#示例

iptables -t filter -I OUTPUT -p tcp --dport 80 -m time --timestart 09:00:00 --timestop 19:00:00 -j REJECT
iptables -t filter -I OUTPUT -p tcp --dport 443 -m time --timestart 09:00:00 --timestop 19:00:00 -j REJECT
iptables -t filter -I OUTPUT -p tcp --dport 80  -m time --weekdays 6,7 -j REJECT
iptables -t filter -I OUTPUT -p tcp --dport 80  -m time --monthdays 22,23 -j REJECT
iptables -t filter -I OUTPUT -p tcp --dport 80  -m time ! --monthdays 22,23 -j REJECT
iptables -t filter -I OUTPUT -p tcp --dport 80  -m time --timestart 09:00:00 --timestop 18:00:00 --weekdays 6,7 -j REJECT
iptables -t filter -I OUTPUT -p tcp --dport 80  -m time --weekdays 5 --monthdays 22,23,24,25,26,27,28 -j REJECT
iptables -t filter -I OUTPUT -p tcp --dport 80  -m time --datestart 2017-12-24 --datestop 2017-12-27 -j REJECT

connlimit 模块
常用的扩展匹配条件如下
–connlimit-above:单独使用此选项时,表示限制每个IP的链接数量。
–connlimit-mask:此选项不能单独使用,在使用–connlimit-above选项时,配合此选项,则可以针对"某类IP段内的一定数量的IP"进行连接数量的限制,如果不明白可以参考上文的详细解释。
#示例

iptables -I INPUT -p tcp --dport 22 -m connlimit --connlimit-above 2 -j REJECT
iptables -I INPUT -p tcp --dport 22 -m connlimit --connlimit-above 20 --connlimit-mask 24 -j REJECT
iptables -I INPUT -p tcp --dport 22 -m connlimit --connlimit-above 10 --connlimit-mask 27 -j REJECT

limit模块
常用的扩展匹配条件如下
–limit-burst:类比"令牌桶"算法,此选项用于指定令牌桶中令牌的最大数量,上文中已经详细的描述了"令牌桶"的概念,方便回顾。
–limit:类比"令牌桶"算法,此选项用于指定令牌桶中生成新令牌的频率,可用时间单位有second、minute 、hour、day。
#示例 #注意,如下两条规则需配合使用,具体原因上文已经解释过,忘记了可以回顾。

iptables -t filter -I INPUT -p icmp -m limit --limit-burst 3 --limit 10/minute -j ACCEPT
iptables -t filter -A INPUT -p icmp -j REJECT

1.6 iptables扩展匹配条件之’–tcp-flags’

见名知义,"–tcp-flags"指的就是tcp头中的标志位,看来,在使用iptables时,我们可以通过此扩展匹配条件,去匹配tcp报文的头部的标识位,然后根据标识位的实际情况实现访问控制的功能。
发起连接请求,tcp头的标志位中,只有SYN位被标识为1,其他标志位均为0
服务端回应刚才的请求,将自己的tcp头的SYN标志位也设置为1,同时将ACK标志位也设置为1
用于匹配报文tcp头部的标志位,“SYN,ACK,FIN,RST,URG,PSH SYN"是什么意思呢?这串字符就是用于配置我们要匹配的标志位的,
我们需要匹配报文tcp头中的6个标志位,这6个标志位分别为为"SYN、ACK、FIN、RST、URG、PSH”,我们可以把这一部分理解成需要匹配的标志位列表
–tcp-flags SYN,ACK,FIN,RST SYN 表示要检查的标志位为SYN,ACK,FIN,RST四个,其中SYN必须为1,余下的必须为0
–tcp-flags ALL ALL //全部位1
–tcp_flags ALL NONE //全部位0 .这两种其实是错误,正常情况没有这两种情况,所有这两种表示错误。
tcp扩展模块还为我们专门提供了一个选项,可以匹配上文中提到的"第一次握手",那就是–syn选项
使用"–syn"选项相当于使用"–tcp-flags SYN,RST,ACK,FIN SYN",也就是说,可以使用"–syn"选项去匹配tcp新建连接的请求报文。

小结

tcp扩展模块常用的扩展匹配条件如下:
–sport
用于匹配tcp协议报文的源端口,可以使用冒号指定一个连续的端口范围。
#示例

iptables -t filter -I OUTPUT -d 192.168.1.146 -p tcp -m tcp --sport 22 -j REJECT
iptables -t filter -I OUTPUT -d 192.168.1.146 -p tcp -m tcp --sport 22:25 -j REJECT
iptables -t filter -I OUTPUT -d 192.168.1.146 -p tcp -m tcp ! --sport 22 -j ACCEPT

–dport
用于匹配tcp协议报文的目标端口,可以使用冒号指定一个连续的端口范围
#示例

iptables -t filter -I INPUT -s 192.168.1.146 -p tcp -m tcp --dport 22:25 -j REJECT
iptables -t filter -I INPUT -s 192.168.1.146 -p tcp -m tcp --dport :22 -j REJECT
iptables -t filter -I INPUT -s 192.168.1.146 -p tcp -m tcp --dport 80: -j REJECT

-tcp-flags
用于匹配报文的tcp头的标志位
#示例

iptables -t filter -I INPUT -p tcp -m tcp --dport 22 --tcp-flags SYN,ACK,FIN,RST,URG,PSH SYN -j REJECT
iptables -t filter -I OUTPUT -p tcp -m tcp --sport 22 --tcp-flags SYN,ACK,FIN,RST,URG,PSH SYN,ACK -j REJECT
iptables -t filter -I INPUT -p tcp -m tcp --dport 22 --tcp-flags ALL SYN -j REJECT
iptables -t filter -I OUTPUT -p tcp -m tcp --sport 22 --tcp-flags ALL SYN,ACK -j REJECT

–syn
用于匹配tcp新建连接的请求报文,相当于使用"–tcp-flags SYN,RST,ACK,FIN SYN"
#示例
iptables -t filter -I INPUT -p tcp -m tcp --dport 22 --syn -j REJECT

1.7 iptables扩展之udp扩展与icmp扩展

1.7.1 udp扩展

我们先来说说udp扩展模块,这个扩展模块中能用的匹配条件比较少,只有两个,就是–sport与–dport,即匹配报文的源端口与目标端口。
没错,tcp模块中也有这两个选项,名称都一模一样。
只不过udp扩展模块的–sport与–dport是用于匹配UDP协议报文的源端口与目标端口,比如,放行samba服务的137与138这两个UDP端口,示例如下
iptables详解(7):iptables扩展之udp扩展与icmp扩展
前文说明过,当使用扩展匹配条件时,如果未指定扩展模块,iptables会默认调用与"-p"对应的协议名称相同的模块,所以,当使用"-p udp"时,可以省略"-m udp",示例如下。
udp扩展中的–sport与–dport同样支持指定一个连续的端口范围
但是udp中的–sport与–dport也只能指定连续的端口范围,并不能一次性指定多个离散的端口,没错,聪明如你一定想到,使用之前总结过的multiport扩展模块,即可指定多个离散的UDP端口,

1.7.2 icmp扩展

最常用的tcp扩展、udp扩展已经总结完毕,现在聊聊icmp扩展,没错,看到icmp,你肯定就想到了ping命令,因为ping命令使用的就是icmp协议。
ICMP协议的全称为Internet Control Message Protocol,翻译为互联网控制报文协议,它主要用于探测网络上的主机是否可用,目标是否可达,网络是否通畅,路由是否可用等
我们平常使用ping命令ping某主机时,如果主机可达,对应主机会对我们的ping请求做出回应(此处不考虑禁ping等情况),也就是说,我们发出ping请求,对方回应ping请求,虽然ping请求报文与ping回应报文都属于ICMP类型的报文,但是如果在概念上细分的话,它们所属的类型还是不同的,我们发出的ping请求属于类型8的icmp报文,而对方主机的ping回应报文则属于类型0的icmp报文,
ping回应报文,它的type为0,code也为0,从上图可以看出,ping回应报文属于查询类(query)的ICMP报文,从大类上分,ICMP报文还能分为查询类与错误类两大类,目标不可达类的icmp报文则属于错误类报文。
而我们发出的ping请求报文对应的type为8,code为0

[root@node-101 ~]#iptables -t filter -A INPUT -p icmp --icmp-type 8/0 -j REJECT 

使用"-m icmp"表示使用icmp扩展使用了"-p icmp",所以"-m icmp"可以省略,使用"–icmp-type"选项表示根据具体的type与code去匹配对应的icmp报文,而上图中的"–icmp-type 8/0"表示icmp报文的type为8,code为0才会被匹配到,也就是只有ping请求类型的报文才能被匹配到,所以,别人对我们发起的ping请求将会被拒绝通过防火墙,而我们之所以能够ping通别人,是因为别人回应我们的报文的icmp type为0,code也为0,所以无法被上述规则匹配到,所以我们可以看到别人回应我们的信息
因为type为8的类型下只有一个code为0的类型,所以我们可以省略对应的code
除了能够使用对应type/code匹配到具体类型的icmp报文以外,我们还能用icmp报文的描述名称去匹配对应类型的报文
使用的 --icmp-type "echo-request"与 --icmp-type 8/0的效果完全相同.

小结

udp扩展
常用的扩展匹配条件
–sport:匹配udp报文的源地址
–dport:匹配udp报文的目标地址
#示例

iptables -t filter -I INPUT -p udp -m udp --dport 137 -j ACCEPT
iptables -t filter -I INPUT -p udp -m udp --dport 137:157 -j ACCEPT

icmp扩展
常用的扩展匹配条件
–icmp-type:匹配icmp报文的具体类型
#示例

iptables -t filter -I INPUT -p icmp -m icmp --icmp-type 8/0 -j REJECT
iptables -t filter -I INPUT -p icmp --icmp-type 8 -j REJECT
iptables -t filter -I OUTPUT -p icmp -m icmp --icmp-type 0/0 -j REJECT
iptables -t filter -I OUTPUT -p icmp --icmp-type 0 -j REJECT
iptables -t filter -I INPUT -p icmp --icmp-type "echo-request" -j REJECT

1.8 iptables扩展模块之state扩展

从字面上理解,state可以译为状态,但是我们也可以用一个高大上的词去解释它,state模块可以让iptables实现"连接追踪"机制。
那么,既然是"连接追踪",则必然要有"连接"。
咱们就来聊聊什么是连接吧,一说到连接,你可能会下意识的想到tcp连接,但是,对于state模块而言的"连接"并不能与tcp的"连接"画等号,在TCP/IP协议簇中,UDP和ICMP是没有所谓的连接的,但是对于state模块来说,tcp报文、udp报文、icmp报文都是有连接状态的,我们可以这样认为,对于state模块而言,只要两台机器在"你来我往"的通信,就算建立起了连接
对于state模块的连接而言,“连接"其中的报文可以分为5种状态,报文状态可以为NEW、ESTABLISHED、RELATED、INVALID、UNTRACKED
NEW:连接中的第一个包,状态就是NEW,我们可以理解为新连接的第一个包的状态为NEW。
ESTABLISHED:我们可以把NEW状态包后面的包的状态理解为ESTABLISHED,表示连接已建立。
RELATED:从字面上理解RELATED译为关系,但是这样仍然不容易理解,我们举个例子。
比如FTP服务,FTP服务端会建立两个进程,一个命令进程,一个数据进程。
命令进程负责服务端与客户端之间的命令传输(我们可以把这个传输过程理解成state中所谓的一个"连接”,暂称为"命令连接")。
数据进程负责服务端与客户端之间的数据传输 ( 我们把这个过程暂称为"数据连接" )。
但是具体传输哪些数据,是由命令去控制的,所以,"数据连接"中的报文与"命令连接"是有"关系"的。
那么,"数据连接"中的报文可能就是RELATED状态,因为这些报文与"命令连接"中的报文有关系。
(注:如果想要对ftp进行连接追踪,需要单独加载对应的内核模块nf_conntrack_ftp,如果想要自动加载,可以配置/etc/sysconfig/iptables-config文件)
INVALID:如果一个包没有办法被识别,或者这个包没有任何状态,那么这个包的状态就是INVALID,我们可以主动屏蔽状态为INVALID的报文
UNTRACKED:报文的状态为untracked时,表示报文未被追踪,当报文的状态为Untracked时通常表示无法找到相关的连接。
刚才举例中的问题即可使用state扩展模块解决,我们只要放行状态为ESTABLISHED的报文即可,因为如果报文的状态为ESTABLISHED,那么报文肯定是之前发出的报文的回应,如果你还不放心,可以将状态为RELATED或ESTABLISHED的报文都放行,这样,就表示只有回应我们的报文能够通过防火墙,如果是别人主动发送过来的新的报文,则无法通过防火墙,示例如下

[root@node-101 ~]#iptables -t filter -S INPUT
-P INPUT ACCEPT
-A INPUT -s 172.18.43.4/32 -p tcp -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-port-unreachable

针对tcp连接,实现所有的外来访问都被拒绝,主动访问的除外。

1.9 自定义链

你可能会问,iptables的默认链就已经能够满足我们了,为什么还需要自定义链呢?
原因如下:
当默认链中的规则非常多时,不方便我们管理。
想象一下,如果INPUT链中存放了200条规则,这200条规则有针对httpd服务的,有针对sshd服务的,有针对私网IP的,有针对公网IP的,假如,我们突然想要修改针对httpd服务的相关规则,难道我们还要从头看一遍这200条规则,找出哪些规则是针对httpd的吗?这显然不合理。
所以,iptables中,可以自定义链,通过自定义链即可解决上述问题。
假设,我们自定义一条链,链名叫IN_WEB,我们可以将所有针对80端口的入站规则都写入到这条自定义链中,当以后想要修改针对web服务的入站规则时,就直接修改IN_WEB链中的规则就好了,即使默认链中有再多的规则,我们也不会害怕了,因为我们知道,所有针对80端口的入站规则都存放在IN_WEB链中,同理,我们可以将针对sshd的出站规则放入到OUT_SSH自定义链中,将针对Nginx的入站规则放入到IN_NGINX自定义链中,这样,我们就能想改哪里改哪里,再也不同担心找不到规则在哪里了
自定义链创建完成后,查看filter表中的链,如上图所示,自定义链已经被创建,而且可以看到,这条自定义链的引用计数为0 (0 references),也就是说,这条自定义链还没有被任何默认链所引用,所以,即使IN_WEB中配置了规则,也不会生效,我们现在不用在意它,继续聊我们的自定义链

root@node-101 ~]#iptables -t filter -N IN_WEB
[root@node-101 ~]#iptables -vnL IN_WEB 
Chain IN_WEB (0 references)
 pkts bytes target     prot opt in     out     source               destination 

自定义链好比自己写的函数,创建自定义链好比声明了函数,是不能直接使用的,如要使用必须先定义才行。赋予具体内容
自定义链也是需要赋予内容即规则。

[root@node-101 ~]#iptables -t filter -A IN_WEB -p tcp --dport 80 -j ACCEPT
[root@node-101 ~]#iptables -t filter -A IN_WEB -p tcp --dport 443 -j ACCEPT 
[root@node-101 ~]#iptables -vnL IN_WEB 
Chain IN_WEB (0 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:80
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:443

为了举例我们添加两条规则给IN_WEB,接下来可以使用该自定义链IN_WEB

[root@node-101 ~]#iptables -t filter -A IN_WEB -p tcp --dport 80 -j ACCEPT   #定义IN_WEB第一条规则
[root@node-101 ~]#iptables -t filter -A IN_WEB -p tcp --dport 443 -j ACCEPT  #定义IN_WEB第二条规则
[root@node-101 ~]#iptables -t filter -A INPUT -s  192.168.122.103 -j IN_WEB  #使用自定义连IN_WEB
[root@node-101 ~]#iptabels -t filter -I  INPUT -s 172.18.43.4 -j ACCEPT      #把管理机ip加入允许
[root@node-101 ~]#iptables -t filter -A INPUT -j REJECT						 #决绝其他所有
[root@node-103 ~]#curl 192.168.122.101										 #101在允许规则,可以访问
hello world 
[root@node-102 ~]#curl 192.168.122.101
curl: (7) Failed connect to 192.168.122.101:80; Connection refused           #101没有在允许规则,所以被拒绝

过了一段时间,我们发现IN_WEB这个名字不太合适,我们想要将这条自定义链重命名,把名字改成WEB,可以吗?必须能啊

[root@node-101 ~]#iptables -t filter  -E IN_WEB WEB
[root@node-101 ~]#iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-N WEB                                                 #已经改名
-A INPUT -s 172.18.43.4/32 -j ACCEPT
-A INPUT -s 192.168.122.103/32 -j WEB
-A INPUT -j REJECT --reject-with icmp-port-unreachable
-A WEB -p tcp -m tcp --dport 80 -j ACCEPT
-A WEB -p tcp -m tcp --dport 443 -j ACCEPT

使用"-X"选项可以删除自定义链,但是删除自定义链时,需要满足两个条件:
1、自定义链没有被任何默认链引用,即自定义链的引用计数为0。
2、自定义链中没有任何规则,即自定义链为空。

1.9.1 小结

创建自定义链 #示例:在filter表中创建IN_WEB自定义链
iptables -t filter -N IN_WEB
引用自定义链# 示例:在INPUT链中引用刚才创建的自定义链
iptables -t filter -I INPUT -p tcp --dport 80 -j IN_WEB
重命名自定义链 #示例:将IN_WEB自定义链重命名为WEB
iptables -E IN_WEB WEB #示例:删除引用计数为0并且不包含任何规则的WEB链
iptables -X WEB
删除自定义链

1.10 iptables之网络防火墙

我们一起来回顾一下之前的知识,在第一篇介绍iptables的文章中,我们就描述过防火墙的概念,我们说过,防火墙从逻辑上讲,可以分为主机防火墙与网络防火墙。
主机防火墙:针对于单个主机进行防护。
网络防火墙: 往往处于网络入口或边缘,针对于网络入口进行防护,服务于防火墙背后的本地局域网
在前文的举例中,iptables都是作为主机防火墙的角色出现的,那么,iptables怎样作为网络防火墙呢?这就是我们今天要聊的话题。
回到刚才的概念,网络防火墙往往处于网络的入口或者边缘,那么,如果想要使用iptables充当网络防火墙,iptables所在的主机则需要处于网络入口处
当外部网络中的主机与网络内部主机通讯时,不管是由外部主机发往内部主机的报文,还是由内部主机发往外部主机的报文,都需要经过iptables所在的主机,由iptables所在的主机进行"过滤并转发",所以,防火墙主机的主要工作就是"过滤并转发",
iptables的角色变为"网络防火墙"时,规则只能定义在FORWARD链中。

1.10.1 网络防火墙实列

我已经准备了3台主机,A、B、C。
假设A处于公网,172.18.43.101
B也有公网地址,172.18.43.102,同时有私网地址192.168.122.102
C,只是局域网地址192.168.122.103.
我们用主机A与B通过交换机连接,模拟互联网直接通讯。而C与B也有单独交换机连接,但是C只有私网地址。

主机公网IP私网IP
A172.18.43.101
B172.18.43.102192.168.122.202
C192.168.122.203

环境准备:

[root@node-101 ~]#ip link set eth0 down     #//A只允许外网172.18.43.0/16
[root@node-101 ~]#ip route del default via 172.18.0.1 dev eth1   #//删除所有网关
[root@node-101 ~]#ip route  add 192.168.122.0/24 via 172.18.43.102 #//增加指向192.168.122.0/24网关
[root@node-101 ~]#ip route  add 192.168.122.0/24 via 172.18.43.102 #//增加指向192.168.122.0/24网关
[root@node-101 ~]#ping 192.168.122.103
PING 192.168.122.103 (192.168.122.103) 56(84) bytes of data.
[root@node-103 ~]#ip link set eth1 down     //C只允许内网192.168.122.0/24
[root@node-103 ~]#ping 172.18.43.101
connect: Network is unreachable
[root@node-103 ~]#ping 172.18.43.102
connect: Network is unreachable
[root@node-102 ~]#ip route del default via 192.168.122.1 dev eth0  #//删除所有网关
[root@node-102 ~]#ip route del default via 172.18.0.1 dev eth1     #//删除所有网关
[root@node-102 ~]#echo 1 > /proc/sys/net/ipv4/ip_forward            #//打开B机核心转发
[root@node-102 ~]#cat /proc/sys/net/ipv4/ip_forward
1
[root@node-102 ~]#vim /usr/lib/sysctl.d/00-system.conf              #//想要永久生效则修改
net.ipv4.ip_forward = 1
[root@node-103 ~]#ip route add default via 192.168.122.102  #//给C增加默认网关,指向B
[root@node-103 ~]#ip route 
default via 192.168.122.102 dev eth0 
192.168.122.0/24 dev eth0 proto kernel scope link src 192.168.122.103 metric 100 
[root@node-103 ~]#ping 172.18.43.101
PING 172.18.43.101 (172.18.43.101) 56(84) bytes of data.
64 bytes from 172.18.43.101: icmp_seq=115 ttl=63 time=0.704 ms

此时已经可以访问A,
通过在A抓包,可以明确看到是C机器在访问

[root@node-101 ~]#tcpdump -i eth1 -p icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes
21:01:45.061883 IP 192.168.122.103 > node-101.centos76.com: ICMP echo request, id 16063, seq 21, length 64
[root@node-101 ~]#ping 192.168.122.103
PING 192.168.122.103 (192.168.122.103) 56(84) bytes of data.
64 bytes from 192.168.122.103: icmp_seq=1 ttl=63 time=0.512 ms		//实现双向访问。
[root@node-102 ~]#iptables -t filter -A FORWARD -j REJECT            //瞬间都挂了,AC不能互访

另外配合其他选项可以实现端口转发、源地址、目标地址的转发

iptables -I FORWARD -s 192.168.122.0/24 -p tcp --dport 80 -j ACCEPT
iptables -I FORWARD -d 1192.168.122.0/24 -p tcp --sport 80 -j ACCEPT
iptables -I FORWARD -s 192.168.122.0/24 -p tcp --dport 22 -j ACCEPT
iptables -I FORWARD -d 192.168.122.0/24 -p tcp --sport 22 -j ACCEPT
#可以使用state扩展模块,对上述规则进行优化,使用如下配置可以省略许多"回应报文放行规则"。
iptables -A FORWARD -j REJECT
iptables -I FORWARD -s 192.168.122.0/24 -p tcp --dport 80 -j ACCEPT
iptables -I FORWARD -s 192.168.122.0/24 -p tcp --dport 22 -j ACCEPT
iptables -I FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

一些注意点:
1、当测试网络防火墙时,默认前提为网络已经正确配置。
2、当测试网络防火墙时,如果出现问题,请先确定主机防火墙规则的配置没有问题

1.11 iptables动作总结

之前的举例中已经用到了一些常用动作,比如ACCEPT、DROP、REJECT等。
其实,"动作"与"匹配条件"一样,也有"基础"与"扩展"之分。
同样,使用扩展动作也需要借助扩展模块,但是,扩展动作可以直接使用,不用像使用"扩展匹配条件"那样指定特定的模块。
之前用到的ACCEPT与DROP都属于基础动作。而REJECT则属于扩展动作。

1.11.1动作REJECT

REJECT动作的常用选项为–reject-with
使用–reject-with选项,可以设置提示信息,当对方被拒绝时,会提示对方为什么被拒绝。
可用值如下
icmp-net-unreachable
icmp-host-unreachable
icmp-port-unreachable,
icmp-proto-unreachable
icmp-net-prohibited
icmp-host-pro-hibited
icmp-admin-prohibited
当没有明确设置–reject-with的值时,默认提示信息为icmp-port-unreachable,即端口不可达之意
使用了–reject-with选项,将提示信息设置为icmp-host-unreachable

1.11.2 动作LOG

使用LOG动作,可以将符合条件的报文的相关信息记录到日志中,但当前报文具体是被"接受",还是被"拒绝",都由后面的规则控制,换句话说,LOG动作只负责记录匹配到的报文的相关信息,不负责对报文的其他处理,如果想要对报文进行进一步的处理,可以在之后设置具体规则,进行进一步的处理
在使用LOG动作时,匹配条件应该尽量写的精确一些,匹配到的报文数量也会大幅度的减少,这样冗余的日志信息就会变少,同时日后分析日志时,日志中的信息可用程度更高
我们已经了解到,LOG动作会将报文的相关信息记录在/var/log/message文件中,当然,我们也可以将相关信息记录在指定的文件中,以防止iptables的相关信息与其他日志信息相混淆,修改/etc/rsyslog.conf文件(或者/etc/syslog.conf),在rsyslog配置文件中添加如下配置即可。
#vim /etc/rsyslog.conf
kern.warning /var/log/iptables.log
加入上述配置后,报文的相关信息将会被记录到/var/log/iptables.log文件中。
完成上述配置后,重启rsyslog服务(或者syslogd)
#service rsyslog restart
服务重启后,配置即可生效,匹配到的报文的相关信息将被记录到指定的文件中
LOG动作也有自己的选项,常用选项如下(先列出概念,后面有示例)
–log-level选项可以指定记录日志的日志级别,可用级别有emerg,alert,crit,error,warning,notice,info,debug。
–log-prefix选项可以给记录到的相关信息添加"标签"之类的信息,以便区分各种记录到的报文信息,方便在分析时进行过滤。
注:–log-prefix对应的值不能超过29个字符
除了ACCEPT、DROP、REJECT、LOG等动作,还有一些其他的常用动作,比如DNAT、SNAT等

1.11.3 SNAT

前文中,我们已经了解了如下动作

ACCEPT、DROP、REJECT、LOG

今天,我们来认识几个新动作,它们是:

SNAT、DNAT、MASQUERADE、REDIRECT
NAT是Network Address Translation的缩写,译为"网络地址转换",NAT说白了就是修改报文的IP地址,NAT功能通常会被集成到路由器、防火墙、或独立的NAT设备中。

为什么要修改报文的IP地址呢?我们来描述一些场景,即可知道为什么有这方面的需求了。
1 SNAT
假设,网络内部有10台主机,它们有各自的IP地址,当网络内部的主机与其他网络中的主机通讯时,则会暴露自己的IP地址,如果我们想要隐藏这些主机的IP地址,该怎么办呢?可以这样办,如下。

当网络内部的主机向网络外部主机发送报文时,报文会经过防火墙或路由器,当报文经过防火墙或路由器时,将报文的源IP修改为防火墙或者路由器的IP地址,当其他网络中的主机收到这些报文时,显示的源IP地址则是路由器或者防火墙的,而不是那10台主机的IP地址,这样,就起到隐藏网络内部主机IP的作用,当网络内部主机的报文经过路由器时,路由器会维护一张NAT表,表中记录了报文来自于哪个内部主机的哪个进程(内部主机IP+端口),当报文经过路由器时,路由器会将报文的内部主机源IP替换为路由器的IP地址,把源端口也映射为某个端口,NAT表会把这种对应关系记录下来。
于是,外部主机收到报文时,源IP与源端口显示的都是路由的IP与端口,当外部网络中的主机进行回应时,外部主机将响应报文发送给路由器,路由器根据刚才NAT表中的映射记录,将响应报文中的目标IP与目标端口再改为内部主机的IP与端口号,然后再将响应报文发送给内部网络中的主机。整个过程中,外部主机都不知道内部主机的IP地址,内部主机还能与外部主机通讯,于是起到了隐藏网络内主机IP的作用。
上述整个过程中,就用到了NAT功能,准确的说是用到了NAPT功能,NAPT是NAT的一种,全称为Network Address Port Translation,说白了就是映射报文IP地址的同时还会映射其端口号,就像刚才描述的过程一样。

刚才描述的过程中,"IP地址的转换"一共发生了两次。

内部网络的报文发送出去时,报文的源IP会被修改,也就是源地址转换:Source Network Address Translation,缩写为SNAT。

外部网络的报文响应时,响应报文的目标IP会再次被修改,也就是目标地址转换:Destinationnetwork address translation,缩写为DNAT
但是,上述"整个过程"被称为SNAT,因为"整个过程"的前半段使用了SNAT,如果上述"整个过程"的前半段使用了DNAT,则整个过程被称为DNAT,也就是说,整个过程被称为SNAT还是DNAT,取决于整个过程的前半段使用了SNAT还是DNAT。
实验:
准备如下机器:
A 172.18.43.102/16 eth1,配置网卡,删掉所有路由条目。安装httpd充当web服务器。
B 172.18.43.103/16 eth1,192.168.122.103/24 删掉所有路由条目。
C 192.168.122.104/24 企业内部主机。配置网关指向B的192.168.122.103
B机器开启ip_forward转发。
echo 1 > /proc/sys/net/ipv4/ip_forward
或者写配置文件
[root@node-103 ~]#vim /etc/sysctl.conf
net.ipv4.ip_forward=1
//只要打开了核心转发,其实此时B机器如能访问互联网,则会转发A的请求,不会对数据包修改,原装转发给A,因为是转发,所以是私网地址,不会被互联网机器路由,也就不能代理上网,
下面还要添加SDAT功能,把源地址修改成代理网关的IP,这样的公网IP才能在互联网路由。本次实验只要保证BC同属172.18.0.0/16即可。
在B配置SNAT后,无需给A添加路由。可实现C访问A
打开B机器的SNAT功能
iptables -t nat -A POSTROUTING -s 192.168.122.0/24 -j SNAT --to-source 172.18.43.103
在POSTROUTING链上增加 源地址为192.168.122.0/24 指定网关及172.18.43.103地址的snat规则。
当我们拨号网上时,每次分配的IP地址往往不同,不会长期分给我们一个固定的IP地址,如果这时,我们想要让内网主机共享公网IP上网,就会很麻烦,因为每次IP地址发生变化以后,我们都要重新配置SNAT规则,这样显示不是很人性化,我们通过MASQUERADE即可解决这个问题,MASQUERADE会动态的将源地址转换为可用的IP地址,其实与SNAT实现的功能完全一致,都是修改源地址,只不过SNAT需要指明将报文的源地址改为哪个IP,而MASQUERADE则不用指定明确的IP,会动态的将报文的源地址修改为指定网卡上可用的IP地址
通过外网网卡出去的报文在经过POSTROUTING链时,会自动将报文的源地址修改为外网网卡上可用的IP地址,这时,即使外网网卡中的公网IP地址发生了改变,也能够正常的、动态的将内部主机的报文的源IP映射为对应的公网IP。
可以把MASQUERADE理解为动态的、自动化的SNAT,如果没有动态SNAT的需求,没有必要使用MASQUERADE,因为SNAT更加高效。
2 DNAT
公司有自己的局域网,网络中有两台主机作为服务器,主机1提供web服务,主机2提供数据库服务,但是这两台服务器在局域网中使用私有IP地址,只能被局域网内的主机访问,互联网无法访问到这两台服务器,整个公司只有一个可用的公网IP,怎样通过这个公网IP访问到内网中的这些服务呢?我们可以将这个公网IP配置到公司的某台主机或路由器上,然后对外宣称,这个IP地址对外提供web服务与数据库服务,于是互联网主机将请求报文发送给这公网 IP地址,也就是说,此时报文中的目标IP为公网IP,当路由器收到报文后,将报文的目标地址改为对应的私网地址,比如,如果报文的目标IP与端口号为:公网IP+3306,我们就将报文的目标地址与端口改为:主机2的私网IP+3306,同理,公网IP+80端口映射为主机1的私网IP+80端口,当私网中的主机回应对应请求报文时,再将回应报文的源地址从私网IP+端口号映射为公网IP+端口号,再由路由器或公网主机发送给互联网中的主机。

上述过程也牵扯到DNAT与SNAT,但是由于整个过程的前半段使用了DNAT,所以上述过程被称为DNAT
上述过程也牵扯到DNAT与SNAT,但是由于整个过程的前半段使用了DNAT,所以上述过程被称为DNAT
iptables -t nat -A PREROUTING -d 172.18.43.103 -p tcp --dport 80 -j DNAT --to-destination 192.168.122.105:8080
在PREROUTING链上 目标地址指向172.18.43.103的 tcp 80 端口的访问都会被修改目标地址,转发到192.168.122.105的8080/tcp
3 REDIRECT
使用REDIRECT动作可以在本机上进行端口映射

比如,将本机的80端口映射到本机的8080端口上

iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080

经过上述规则映射后,当别的机器访问本机的80端口时,报文会被重定向到本机的8080端口上。

REDIRECT规则只能定义在PREROUTING链或者OUTPUT链中。

小结

开启核心转发:
SNAT相关
配置SNAT可以隐藏局域网地址,可以代理访问互联网,配置如下
iptables -t nat -A POSTROUTING -s 192.168.122.0/24 -j SNAT --to-source 172.18.43.103
iptables -t nat -A POSTROUTING -s 192.168.122.0/24 !-d 192.168.122.0/24 -j SNAT --to-source -j MASQUERADE
如果公网IP是拨号上网,不固定,则可以使用MASQUERADE进行SNAT操作,
DNAT相关
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080

  • 28
    点赞
  • 257
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值