感谢以下链接的博主或者相关人员。如有侵权,可以留言联系我删除。
主要思想来自于马哥教育内容;
重点翻译man手册为主;
以下是参考或者部分摘抄的博文链接:
https://blog.csdn.net/dhrainer/article/details/83411391#comments
https://blog.csdn.net/dhRainer
https://blog.csdn.net/dhRainer/article/details/83411296
https://www.jianshu.com/p/b9843ac9450c
https://blog.csdn.net/chengxuyuanyonghu/article/details/51898002
http://blog.51cto.com/minux/1727684
https://blog.csdn.net/adamska0104/article/details/44916597
https://baike.baidu.com/item/防火墙/52767?fr=aladdin
http://blog.51cto.com/laokaddk/496983
http://lib.ru/SECURITY/ipfwadm/ipfwadm.txt_with-big-pictures.html
http://www.xos.nl/resources/ipfwadm/
http://blog.sina.com.cn/s/blog_4c86552f0102wyfc.html
https://www.cnblogs.com/549294286/p/5172435.html
http://blog.51cto.com/minux/1727684
https://lwn.net/Articles/267140/
http://www.zsythink.net/archives/1199/
http://blog.jobbole.com/89936/
双网卡环境。eno16777736网卡是NAT出去的,可以上网,模拟的是外网网卡。ens37是仅主机模式,模拟的是内网网卡。(做NAT实验,这个内网网卡有用到)
[root@gateway ~]# ifconfig
eno16777736: flags=4163 mtu 1500
inet 172.16.0.10 netmask 255.255.0.0 broadcast 172.16.255.255
inet6 fe80::20c:29ff:fe85:868d prefixlen 64 scopeid 0x20
ether 00:0c:29:85:86:8d txqueuelen 1000 (Ethernet)
RX packets 53844 bytes 5057774 (4.8 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 56703 bytes 12869995 (12.2 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens37: flags=4163 mtu 1500
inet 192.168.10.254 netmask 255.255.255.0 broadcast 192.168.10.255
inet6 fe80::20c:29ff:fe85:8697 prefixlen 64 scopeid 0x20
ether 00:0c:29:85:86:97 txqueuelen 1000 (Ethernet)
RX packets 3684 bytes 539555 (526.9 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 4959 bytes 441220 (430.8 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73 mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10
loop txqueuelen 0 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@gateway ~]# ip addr show|sed -rn '/inet[[:space:]]+127/! s/^[[:space:]]+inet[[:space:]]+(.*)\/[[:digit:]]+[[:space:]]+.*$/\1/p'
172.16.0.10
192.168.10.254
Selinux是关闭的。本次讲解是关闭firewalld,直接使用iptables。其实firewalld无法是做了一些自定义的链,引入的区域的概念。学会
iptables,能看懂,firewalld无法只是选项理解和区域概念的问题。后边有时间会提供firewalld防火墙的专题。
中转服务器(路由服务器),双网卡:
(伪)外网:eno16777736 ip为:172.16.0.10
内网:ens37 ip为:192.168.10.254
内网环境的模拟服务一台:
内网:eno16777736 ip为:192.168.10.4
外网服务器的模拟环境一台:
(伪)外网:eno16777736 ip为:172.16.0.120
内网:没有,实际不同机房都会有内网接口。
摘自:https://baike.baidu.com/item/防火墙/52767?fr=aladdin
防火墙(Firewall),也称防护墙,是由Check Point创立者Gil Shwed于1993年发明并引入国际互联网(US5606668(A)1993-12-15)。防火墙是位于内部网和外部网之间的屏障,它按照系统管理员预先定义好的规则来控制数据包的进出。防火墙是系统的第一道防线,其作用是防止非法用户的进入。
防火墙,简单来理解就是一种隔离机制或者叫隔离工具。它主要工作在主机或网络边缘,对于进出主机或网络的报文根据事先定义的检查规则作匹配检测,对于能够被规则匹配到的报文作出相应的处理的组件。
根据防火墙所处的位置不同,可以分为:主机防火墙和网络防火墙。如下图所示:
参考:http://blog.51cto.com/laokaddk/496983
可以参考:
http://lib.ru/SECURITY/ipfwadm/ipfwadm.txt_with-big-pictures.html
http://www.xos.nl/resources/ipfwadm/
最早的防火墙实现框架是:ipfw,安装软件包应该是:ipfwadm。在linux内核1.2.x版本和2.0.x版本。
后面是:ipchains linux内核2.2.x之后,2.4.x之前。
接着是:netfilter(规则编写组件是iptables) ,linux内核2.4.x之后,3.13之前。
后边较新的内核版本:nftables,3.13版本之后。
CentOS 6和CnetOS7防火墙内核的实现都是netfiter,不过在CentOS6,iptables是一款防火墙策略编写工具,在CentOS7,利用firewalld实现了策略编写,不过它要去调用iptables编写规则。所以可以理解,你使用CentOS6和CentOS7,其实弄懂iptables就行了。
iptables的表的链以及规则的基本说明:
iptables/ip6tables ? administration tool for IPv4/IPv6 packet filtering and NAT。
iptables是IPv4/IPv6 的包过滤和网络地址转换的管理工具。
Iptables and ip6tables are used to set up, maintain, and inspect the tables of IPv4 and IPv6 packet filter rules in the Linux kernel.
Several different tables may be defined. Each table contains a number of built-in chains and may also contain user-defined chains.
iptables用来发起,维护以及检查linux内核中Ipv4包过滤规则表。(预设)定义了一些不同的表。每个表中可以包含一些内建的链,并且
可以包含用户自定义的链。(这里就不涉及ipv6了,所以ip6tables不注解)
Each chain is a list of rules which can match a set of packets. Each rule specifies what to do with a packet that matches.
This is called a `target', which may be a jump to a user-defined chain in the same table.
每一条链上都有一系列的可以用来匹配一组数据包的规则。每条规则指定了能够让匹配的报文做什么(比较常见的就是通过或者不通
过)。这个做什么通常叫做"动作,目标(target)",这个target可以实现在一个表的内建链跳转到一个用户自定义的链,并去匹配自定义链
上的规则。
目标,处理动作(target):
A firewall rule specifies criteria for a packet and a target. If the packet does not match, the next rule in the chain is examined;
if it does match, then the next rule is specified by the value of the target, which can be the name of a user-defined chain, one of the
targets described in iptables-extensions(8), or one of the special values ACCEPT, DROP or RETURN.
防火墙规则指定了数据包和处理动作的准则。如果数据报文不匹配(链上某条具体的规则),然后会依次检查链上接下来的规则;如果一
旦数据报文被链上的规则所匹配到,接下来会去检查对应链上对应规则的处理动作,这个动作可以是一个用户自定义链的名字。最终
的处理动作可能会是ACCEPT,DROP以及RETURAN还有高级扩展部分的中提到的target,详情请参考(man 8 iptables-extensions,
这个是CentOS 7上,如果是CentOS 6,直接man 8 iptables就行)。
ACCEPT means to let the packet through. DROP means to drop the packet on the floor. RETURN means stop traversing this chain
and resume at the next rule in the previous (calling) chain. If the end of a built-in chain is reached or a rule in a built-in chain with
target RETURN is matched, the target specified by the chain policy determines the fate of the packet.
ACCEPT动作表示让数据包通过. DROP表示直接在数据包通过的入口处丢弃掉。RETURN表示停止当前链上规则的遍历,返回到之前
调用链的地方,然后开始检测之前链上的下一条规则。如果在内建链上,策略匹配已经达到了结束或者在内建链中匹配到RETURN,
那么会去检查指定链的默认策略来决定报文的"宿命"。
关于netfilter框架所在位置和数据报文和链的基本框架图解如下图所示:
这张图引用自:https://blog.csdn.net/silent123go/article/details/52588518
通俗注解:
说了这么多,大概意思就是如图所示,为了实现一些功能,有定义一些表,这些表,每一张都能实现一个大的功能,为了实现这些表的功能,有事先定义一些函数,这些函数就是为了来完成这些所谓的表的功能而设计的,它们之间可能是多个函数一起工作的,这些函数,在防火墙领域,被称为钩子函数(hook function)。钩子函数,默认一共定义了5个,分别为prerouting,input,output,forward以及postrouting。而这些都只是内核中的功能接口,如果我们去调用这些钩子函数,需要通过系统调用,调用这些功能接口,这样未免让使用成本和难度变得更大。所以后来就开发了一个可以用来在用户空间完成策略编写,然后由这个工具给我们去处理这些底层复杂的调用。这就是iptables的功能,在iptables中为了让钩子函数的作用一目了然,有定义一些内建的与钩子函数同名的全大写字符。比如PREROUTING,INPUT,OUTPUT,FORWARD以及POSTROUTING,这些字符串分别对应同名的钩子函数,它们统称为链,叫做对应名字的链,这些链是内建的,默认就存在的。我们如果要让这些链或者说内核中钩子函数更好的完成工作,我们要自己给钩子函数定义一些策略,或者说给对应的链上编写一些策略,每条策略可以理解为检测规则,数据报文经过这些规则,要去检查是否可以通过。而编写策略是我们在用户空间使用iptables来编写到对应的链上,iptables会帮我们交给对应的钩子函数,数据报文最终还是由内核空间中的钩子函数来完成策略检测。这些策略可以分为检测和处理动作,可以从一个钩子函数跳转到另外一个钩子函数。
除了内建链,我们可以自己定义新的链,这类链叫做用户自定义链。在内建链或者自定义链中,会有很多条规则,即为我们说的防火墙策略,这些策略都编写在对应的链中。一旦数据报文经过对应钩子函数的时候,钩子函数会使用这些策略去匹配检测数据报文,看它是否能够通过,一条一条检测,每一条规则,都有一个动作。数据报文不管来或者不来,这些内核中的钩子函数总是会把这些策略放在那儿,就好像一直把这些策略勾着一样。
预先定义了实现特定功能的表,完成复杂功能的5张表的名字分别为:
raw
mangle
nat
filter
security
其中的security属于加入没多久的一张表(CentOS 6的iptables版本没有这个security表,CentOS 7的iptables版本有引入这个),可以暂时不用理会。不过另外四张表中常用的也只有nat,filter。除了security外(这个主要是与selinux有关的mac安全过滤相关的一张表),另外四张表实现的功能和优先级分别为(从上到下,优先级从高到低):
raw:主要功能是关闭nat表上启用的连接追踪机制;
mangle:主要功能是拆解报文,对报文进行修改,然后重新封装起来;
nat:主要功能是实现网络地址转换,用于修改通信报文的源ip或目标ip,或者源端口或目标端口;
filter:主要功能实现报文过滤的,也是我们要了解的重点。
那么这些对应的表与钩子函数或者说与链之间的关系是怎样的呢?
raw:PREROUTING,OUTPUT
mangle:PREROUTING,INPUT,FORWORD,OUTPUT,
nat:PREROUTING,[INPUT,]OUTPUT,POSTROUTIG #CentOS 7才支持INPUT,CentOS 6 不支持INPUT
filter:INPUT,FORWORD,OUTPUT
security:INPUT, FORWARD, OUTPUT
其中如果只是涉及单主机的话,filter是用到最多的,而且也是最基础的。可以说必须要掌握。对于多台主机之间的应用,涉及转发,路由之类的,nat和mangle可能会用的比较多,其中的nat应用特别广泛。我们来简单看看下面的图解数据报文在这些表和链中间的衔接工作关系:
这张图引用自:https://blog.csdn.net/silent123go/article/details/52588518
数据报文的流向,大概分为:
(1) 从外部进来,流入主机内部;
(2) 从外部经过本机,由本机转发;
(3) 从本机内部出来,即由本机流出;
报文到达本机后,会经过PREROUTING链后,然后路由后做判断(只有路由后才能拆解报文头的mac地址,看到内部封装的网络地址,判断目标网络地址是否是本机),如果报文的目标地址是本机,会通过INPUT链进入本机内部。通过PREROUTING链会发生一次路由。如果判断目标地址不是本机,会尝试让本机进行报文的转发(主机要开启核心转发功能才能做报文的转发,这是个根本条件,默认的主机的核心转发功能是关闭的),这个时候报文会通过FORWARD链。通过后,然后无法确认通过哪一个网络接口发出,还要做一次路由,路由后会通过POSTROUTING链。对于主机内部的网络报文,如果要出去,会通过OUTPUT,然后经过POSTROUTING出去。
来看看固定形式的命令语法结构:
SYNOPSIS
iptables [-t table] {-A|-C|-D} chain rule-specification
ip6tables [-t table] {-A|-C|-D} chain rule-specification
iptables [-t table] -I chain [rulenum] rule-specification
iptables [-t table] -R chain rulenum rule-specification
iptables [-t table] -D chain rulenum
iptables [-t table] -S [chain [rulenum]]
iptables [-t table] {-F|-L|-Z} [chain [rulenum]] [options...]
iptables [-t table] -N chain
iptables [-t table] -X [chain]
iptables [-t table] -P chain target
iptables [-t table] -E old-chain-name new-chain-name
rule-specification = [matches...] [target]
match = -m matchname [per-match-options]
target = -j targetname [per-target-options]
-t 用来显式指明操作或调用的的表是哪一张,默认是filter这个实现过滤功能的表。-t 后边可选参数有:filter,nat,mangle,raw,security;
常用命令选项:
-A, --append chain rule-specification:表示向指定的链中追加一条策略;
-C, --check chain rule-specification:检测链上是否有对应匹规则;
-D, --delete chain rule-specification或-D, --delete chain rulenum:删除指定链的一条或多条规则,可以根据指定规则名来删也可以根
据指定规则对应的编号来删;
-I, --insert chain [rulenum] rule-specificatio:向给定链的指定位置(默认是第一条)插入指定的一条或多条规则;
-R, --replace chain rulenum rule-specification:替换给定链的给定规则;
-S, --list-rules [chain]:打印指定链所有规则或打印所有的链的所有规则;
-F, --flush [chain]:清空(刷新)指定链或所有的链;
-L, --list [chain]:查看指定链的所有规则;
-Z, --zero [chain [rulenum]]:置零所有链或指定链的或给定链的给定规则的数据包和字节统计信息。
-P, --policy chain target:设置指定链的默认策略为给定的策略;
-N, --new-chain chain:自定义链;
-E, --rename-chain old-chain new-chain:重命名用户自定义的链;
-X, --delete-chain [chain]:删除用户自定义的链;
常用参数选项:
[!] -p, --protocol protocol:指定协议;
[!] -s, --source address[/mask][,...]:检查报文中的源IP地址是否符合此处指定的地址或范围;
[!] -d, --destination address[/mask][,...]:检查报文中的目标IP地址是否符合此处指定的地址或范围;
-m, --match match:指定使用的扩展匹配项(模块);扩展选项会在其他小结讲解。
[!] -i, --in-interface name:数据报文流入的接口;只能应用于数据报文流入的环节,只能应用于PREROUTING, INPUT 和 FORWARD链;
[!] -o, --out-interface name:数据报文流出的接口;只能应用于数据报文流出的环节,只能应用于FORWARD, OUTPUT 和 POSTROUTING链;
其他选项:
-v, --verbose:查看详细信息(-v使用多次,会显示更加详细的调试信息)
-vv
-vvv
-n, --numeric:以数字格式显示地址和端口号;
-x, --exact:显示技术结果的精确值;
--line-numbers:显示规则的序号;
其中的chain部分,表示需要用户自己指定的链名,可以是内建的链(PREROUTING, INPUT, FORWARD, OUTPUT, POSTROUTING)
或者用户自定义链;
rule-specification:表示规则指定部分。这部分由匹配和处理动作组成。匹配可以是基本条件匹配和扩展匹配
rulenum表示对应链的规则编号;
简化后的命令格式为:
iptables [-t tables] COMMAND chain [-m matchname [per-match-options]] -j target [per-target-options]
使用表说明:
-t table:CentOS 7后,内核默认支持使用5张表,分别是 filter、nat、mangle、raw、security
如果没有使用-t选项,默认操作的是filter表;(上文有介绍不同表的使用和区别)
iptables能识别的选项分为下面三个部分:
(1) 命令选项
说明:下面这部分的选项用来表明想要执行的动作。大部分情况,下面的选项每次使用只能使用其中的一个。如果使用短选项,
除了-h,其他短选项字母都是大写的英文字母,如果使用长选项,要把长选项表示的命令写全,不能省略。
-A, --append chain rule-specification:
向指定的链追加一条或多条规则。追加就是向链的规则列表的最后一条规则后面追加,如果链没有规则,追加的就是第一条。因为
链上规则默认是从上往下依次被检测,所以规则的前后顺序很关键。当指定源地址或目标地址,或者指定二者都指定时,如果地址被
解析成不止一个地址的时候,将会为每个可能的地址组合添加一条规则(就是写源地址和目标地址的时候要注意通配多个地址的情况);
命令使用频率:高
-C, --check chain rule-specification:
检测是否在对应链上存在指定的规则。iptables内部有个逻辑,下面-D选项也有用到,去寻找指定链上指定规则是否存在,然后返回
成功与否的状态。-D会调用前边这个判断逻辑,然后继续执行操作,而不是直接返回(要先查找是否指定链上是否存在要操作的规则)。
命令使用频率:不高
-D, --delete chain rule-specification
-D, --delete chain rulenum:
从指定链上删除一条或多条规则。默认在链上,规则会显示规则名字和规则的序列编号,编号从1开始往后依次递增。所以删除链上
的规则有两种情况,一个是直接指定规则名(上面的第一条语法),另外一个是直接指定规则所在的序号(上面的第二条语法)。规则的序号。
可以通过后边的其他选项或者叫辅助选项 --line-numbers查看。
命令使用频率:中等
-I, --insert chain [rulenum] rule-specification:
向指定链的指定位置或默认位置(省略插入编号位置表示默认的1)插入一条或多条规则。指定位置插入规则后,此位置后边的规则编
号依次向下平移插入规则的数量。
命令使用频率:高
-R, --replace chain rulenum rule-specification:
在指定链上,使用指定的规则替换指定规则编号处的规则。如果待替换的规则中的源地址或目标地址中任意有一个地址被解析成多
个地址,此替换命令将会失败。再次说明,规则是从第一条开始的,插入可以不指定规则编号,但是替换不可以,一定要显式指明要被替换的规则的编号。
命令使用频率:中等
-L, --list [chain]:
列出默认表或指定表的指定链或所有链的所有的规则。这个选项经常会配合-n选项一起使用,为了避免长时间的DNS的反向解析查
询(会被有些ip解析成对应的带有字符的字符串格式,还有端口解析成对应的默认协议等,简单来说就是DNS的反向解析,反向解析会
去查找DNS反向解析树,是非常消耗资源和服务性能的)。此选项还可以配合-Z选项一起使用,就是列出后,会把链上规则的计数器
统计数据(匹配到的报文个数和匹配到的所有报文的大小之和)置为零。如果配合后边的辅助选项,比如常常配合一起使用的除了-n之外,还有-v,-vv,-vvv,-x等等,那么输出结果可能都会有所差异。
命令使用频率:高
-S, --list-rules [chain]:
列出默认表或指定表的指定链或所有链的所有的规则。这个选项的输出结果,在没有指定链的情况下,和执行iptables-save命令的
结果一样。
命令使用频率:不高
-F, --flush [chain]:
清空指定链或所有链(没有给出链名的情况)的所有规则。如果有给定表选项,会清空指定表,如果没有情况的是默认的filter表。这个
命令要谨慎操作,这个命令的操作等价于一条一条的去删除链上的所有的规则。
命令使用频率:中等
-Z, --zero [chain [rulenum]]:
把报文个数计数和所有报文大小之和计数置为0,重新开始计数。如果没有给定链,会把默认表或指定表的所有链的统计数据置为0
可以指定链或指定链的指定规则。可以配-L选项一起使用(上边有提到过)。为了测试效果,你可以在执行置零操作前,先看看统计数据。
命令使用频率:中等
-N, --new-chain chain:
创建一个新的用户自定义的链。链的名字不能和已有target一样。
命令使用频率:中等
-X, --delete-chain [chain]:
删除任意用户自定义的链。如果不指定链的名字,会删除指定表或默认表所有可以被删除的自定义链。
要删除用户自定义链,这个链必须满足:
链没有被引用;
链上没有规则(链必须为空);
一句话总结:仅能删除 用户自定义的 引用计数为0的 空的 链
命令使用频率:不高
-P, --policy chain target:
设置对应链的默认策略为给定的策略。而且设置的策略不能是内建的链名或用户自定义链的名字。
常用的非扩展策略有:ACCEPT,REJECT,DROP,RETURN
-E, --rename-chain old-chain new-chain:
重命名用户自定义的链的名字。在表看来,内部结构没有变化,这个只是名字变化了。
-h
查看帮助信息。
(2) 参数(匹配条件)
[!] -p, --protocol protocol
设置用于检测报文时候的协议规则。可以指定的值有:tcp,udp,udplite,icmp,icmpv6,esp,ah,sctp,mh或者关键字all或者
数字值(特定数字有特定含义)。在配置文件/etc/protocols中指定的协议名是允许的。可以在指定协议的参数前边使用!,表示取反的意思。指定数字 0 表示 all(匹配所有协议),all也是在-p选项省略时候的默认值。常用的值有:tcp,udp,icmp以及all
参数使用频率:高
[!] -s, --source address[/mask][,...]
指定源地址。值address可以是一个网络名,一个主机名,一个带有子网掩码(/mask)的网络ip地址,或者是一个单独的文本IP地址。
在规则被提交给内核前,这个主机名只会被解析一次。使用远端主机(比如类似于让远程主机的DNS服务器去解析)去解析这个主机名
是不推荐的。掩码表示长格式(例如255.255.255.0)和短格式(24)。可以在参数选项前加上符号"!",取反。这个选项有另外一个等价表
示为--src 如果指定多个地址,要特别注意。可以在使用-A追加的时候追加多个规则,或者在使用-D的时候删除多个规则等。
一句话概括:检查报文中的源IP地址是否符合此处指定的地址或范围;
所有地址:0.0.0.0/0
参数使用频率:高
[!] -d, --destination address[/mask][,...]
指定目标地址。和-s时候的用法和含义一样。它的等价选项是--dst
一句话概括:检查报文中的目标IP地址是否符合此处指定的地址或范围;
参数使用频率:高
-m, --match match
指定要使用的匹配项,即测试特定属性的扩展模块(使用扩展模块要使用这个选项明确指定扩展模块名)。匹配集构成了调用目标的
条件。匹配首先根据命令行上的指定进行评估,然后以短路方式工作,即,如果一个扩展结果为false,则评估将停止。
参数使用频率:高
[!] -i, --in-interface name
数据报文流入的接口;只能应用于数据报文流入的环节,只能应用于PREROUTING,INPUT和FORWARD链;如果接口名字结尾
有个符号"+",表示匹配以name开头的所有的地址。
参数使用频率:中等
[!] -o, --out-interface name
数据报文流出的接口;只能应用于数据报文流出的环节,只能应用于FORWARD、OUTPUT和POSTROUTING链;如果接口名字结
尾有个符号"+"表示匹配以name开头的所有地址。
参数使用频率:中等
(3) 其他选项(辅助选项)
-v, --verbose:
信息信息。会显示接口名字,规则选项以及TOS标志。数据报文和所有数据报文的大小也会显式。默认单位是K,M,G等,换算进度
是1000,可以使用-x选项显式精确值。可以使用-v选项多次,显示更加具体的调试信息。比如-vv或-vvv
选项使用频率:高
-n, --numeric:
以数字格式显示IP地址和端口号。默认程序会尝试去显示主机名,网络名以及服务名。
选项使用频率:高
-x, --exact:
数据报文个数和所有数据报文的字节统计大小会以更加精确的值显示而不是换算过的带上单位的值。这个选项只有配合-L时候才有
意义的。
选项使用频率:中等
--line-numbers:
在每条规则的开头部分,显示每条规则的序列好或编号。
选项使用频率:高
--modprobe=command
当向链中添加或插入规则的时候,使用指定命令取加载任何所需的模块。
选项使用频率:不高
默认的firewalld服务时启动的:
[root@gateway ~]# systemctl status firewalld.service
● firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2018-12-27 22:36:09 CST; 3h 2min ago
Main PID: 3259 (firewalld)
CGroup: /system.slice/firewalld.service
└─3259 /usr/bin/python -Es /usr/sbin/firewalld --nofork --nopid
Dec 27 22:36:03 gateway systemd[1]: Starting firewalld - dynamic firewall daemon...
Dec 27 22:36:09 gateway systemd[1]: Started firewalld - dynamic firewall daemon.
先看一下默认firewalld启动的情况下iptables策略表中的东西:
[root@gateway ~]# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
426 34200 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
0 0 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0
1 52 INPUT_direct all -- * * 0.0.0.0/0 0.0.0.0/0
1 52 INPUT_ZONES_SOURCE all -- * * 0.0.0.0/0 0.0.0.0/0
1 52 INPUT_ZONES all -- * * 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0
0 0 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
0 0 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0
0 0 FORWARD_direct all -- * * 0.0.0.0/0 0.0.0.0/0
0 0 FORWARD_IN_ZONES_SOURCE all -- * * 0.0.0.0/0 0.0.0.0/0
0 0 FORWARD_IN_ZONES all -- * * 0.0.0.0/0 0.0.0.0/0
0 0 FORWARD_OUT_ZONES_SOURCE all -- * * 0.0.0.0/0 0.0.0.0/0
0 0 FORWARD_OUT_ZONES all -- * * 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0
0 0 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
Chain OUTPUT (policy ACCEPT 420 packets, 62882 bytes)
pkts bytes target prot opt in out source destination
420 62882 OUTPUT_direct all -- * * 0.0.0.0/0 0.0.0.0/0
Chain FORWARD_IN_ZONES (1 references)
pkts bytes target prot opt in out source destination
0 0 FWDI_public all -- ens37 * 0.0.0.0/0 0.0.0.0/0 [goto]
0 0 FWDI_public all -- eno16777736 * 0.0.0.0/0 0.0.0.0/0 [goto]
0 0 FWDI_public all -- + * 0.0.0.0/0 0.0.0.0/0 [goto]
Chain FORWARD_IN_ZONES_SOURCE (1 references)
pkts bytes target prot opt in out source destination
Chain FORWARD_OUT_ZONES (1 references)
pkts bytes target prot opt in out source destination
0 0 FWDO_public all -- * ens37 0.0.0.0/0 0.0.0.0/0 [goto]
0 0 FWDO_public all -- * eno16777736 0.0.0.0/0 0.0.0.0/0 [goto]
0 0 FWDO_public all -- * + 0.0.0.0/0 0.0.0.0/0 [goto]
Chain FORWARD_OUT_ZONES_SOURCE (1 references)
pkts bytes target prot opt in out source destination
Chain FORWARD_direct (1 references)
pkts bytes target prot opt in out source destination
Chain FWDI_public (3 references)
pkts bytes target prot opt in out source destination
0 0 FWDI_public_log all -- * * 0.0.0.0/0 0.0.0.0/0
0 0 FWDI_public_deny all -- * * 0.0.0.0/0 0.0.0.0/0
0 0 FWDI_public_allow all -- * * 0.0.0.0/0 0.0.0.0/0
Chain FWDI_public_allow (1 references)
pkts bytes target prot opt in out source destination
Chain FWDI_public_deny (1 references)
pkts bytes target prot opt in out source destination
Chain FWDI_public_log (1 references)
pkts bytes target prot opt in out source destination
Chain FWDO_public (3 references)
pkts bytes target prot opt in out source destination
0 0 FWDO_public_log all -- * * 0.0.0.0/0 0.0.0.0/0
0 0 FWDO_public_deny all -- * * 0.0.0.0/0 0.0.0.0/0
0 0 FWDO_public_allow all -- * * 0.0.0.0/0 0.0.0.0/0
Chain FWDO_public_allow (1 references)
pkts bytes target prot opt in out source destination
Chain FWDO_public_deny (1 references)
pkts bytes target prot opt in out source destination
Chain FWDO_public_log (1 references)
pkts bytes target prot opt in out source destination
Chain INPUT_ZONES (1 references)
pkts bytes target prot opt in out source destination
0 0 IN_public all -- ens37 * 0.0.0.0/0 0.0.0.0/0 [goto]
1 52 IN_public all -- eno16777736 * 0.0.0.0/0 0.0.0.0/0 [goto]
0 0 IN_public all -- + * 0.0.0.0/0 0.0.0.0/0 [goto]
Chain INPUT_ZONES_SOURCE (1 references)
pkts bytes target prot opt in out source destination
Chain INPUT_direct (1 references)
pkts bytes target prot opt in out source destination
省略很多内容。
iptables和firewalld的关系如下图所示:(引用的互联网的图片。)
其实firewalld无非也是写入的iptables策略,最终都是要被内核中的netfilter防火墙所处理。firewalld为了实现区域的概念,有定义了很多iptables中的链(自定义链),比如:
FORWARD_IN_ZONES
FORWARD_IN_ZONES_SOURCE
FORWARD_OUT_ZONES
FORWARD_OUT_ZONES_SOURCE
FORWARD_direct
FWDI_public
FWDI_public_allow
FWDI_public_deny
FWDI_public_log
FWDO_public
FWDO_public_allow
FWDO_public_deny
FWDO_public_log
INPUT_ZONES
INPUT_ZONES_SOURCE
INPUT_direct
IN_public
IN_public_allow
IN_public_deny
IN_public_log
OUTPUT_direct
关闭firewalld服务后,iptables默认策略:(可以简单印证每个表中所支持的链)
[root@gateway ~]# systemctl stop firewalld.service
[root@gateway ~]# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
[root@gateway ~]#
[root@gateway ~]# iptables -t nat -nvL
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
[root@gateway ~]# iptables -t mangle -nvL
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
[root@gateway ~]# iptables -t security -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
[root@gateway ~]# iptables -t raw -nvL
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
(1) 查看命令-L默认不带附属选项(为了查看策略,我先把firewalld启用,因为有一些默认策略)
[root@gateway ~]# iptables -t filter -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
ACCEPT all -- anywhere anywhere
INPUT_direct all -- anywhere anywhere
INPUT_ZONES_SOURCE all -- anywhere anywhere
INPUT_ZONES all -- anywhere anywhere
ACCEPT icmp -- anywhere anywhere
REJECT all -- anywhere anywhere reject-with icmp-host-prohibited
Chain FORWARD (policy ACCEPT)
target prot opt source destination
ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
ACCEPT all -- anywhere anywhere
FORWARD_direct all -- anywhere anywhere
FORWARD_IN_ZONES_SOURCE all -- anywhere anywhere
FORWARD_IN_ZONES all -- anywhere anywhere
FORWARD_OUT_ZONES_SOURCE all -- anywhere anywhere
FORWARD_OUT_ZONES all -- anywhere anywhere
ACCEPT icmp -- anywhere anywhere
REJECT all -- anywhere anywhere reject-with icmp-host-prohibited
......
(2) 加上以数字格式显示ip和地址的选项-n
[root@gateway ~]# iptables -t filter -L -n
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
INPUT_direct all -- 0.0.0.0/0 0.0.0.0/0
INPUT_ZONES_SOURCE all -- 0.0.0.0/0 0.0.0.0/0
INPUT_ZONES all -- 0.0.0.0/0 0.0.0.0/0
ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0
REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
Chain FORWARD (policy ACCEPT)
target prot opt source destination
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
FORWARD_direct all -- 0.0.0.0/0 0.0.0.0/0
FORWARD_IN_ZONES_SOURCE all -- 0.0.0.0/0 0.0.0.0/0
FORWARD_IN_ZONES all -- 0.0.0.0/0 0.0.0.0/0
FORWARD_OUT_ZONES_SOURCE all -- 0.0.0.0/0 0.0.0.0/0
FORWARD_OUT_ZONES all -- 0.0.0.0/0 0.0.0.0/0
ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0
REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
......
(3) 加上-v输出详细信息
[root@gateway ~]# iptables -t filter -L -n -v
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
141 10344 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
0 0 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0
0 0 INPUT_direct all -- * * 0.0.0.0/0 0.0.0.0/0
0 0 INPUT_ZONES_SOURCE all -- * * 0.0.0.0/0 0.0.0.0/0
0 0 INPUT_ZONES all -- * * 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0
0 0 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
0 0 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0
0 0 FORWARD_direct all -- * * 0.0.0.0/0 0.0.0.0/0
0 0 FORWARD_IN_ZONES_SOURCE all -- * * 0.0.0.0/0 0.0.0.0/0
0 0 FORWARD_IN_ZONES all -- * * 0.0.0.0/0 0.0.0.0/0
0 0 FORWARD_OUT_ZONES_SOURCE all -- * * 0.0.0.0/0 0.0.0.0/0
0 0 FORWARD_OUT_ZONES all -- * * 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0
0 0 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
Chain OUTPUT (policy ACCEPT 109 packets, 19876 bytes)
pkts bytes target prot opt in out source destination
109 19876 OUTPUT_direct all -- * * 0.0.0.0/0 0.0.0.0/0
Chain FORWARD_IN_ZONES (1 references)
pkts bytes target prot opt in out source destination
0 0 FWDI_public all -- ens37 * 0.0.0.0/0 0.0.0.0/0 [goto]
0 0 FWDI_public all -- eno16777736 * 0.0.0.0/0 0.0.0.0/0 [goto]
0 0 FWDI_public all -- + * 0.0.0.0/0 0.0.0.0/0 [goto]
(4) 显示规则编号
[root@gateway ~]# iptables -t filter -L -n -v --line-numbers
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 373 27964 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
2 0 0 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0
3 0 0 INPUT_direct all -- * * 0.0.0.0/0 0.0.0.0/0
4 0 0 INPUT_ZONES_SOURCE all -- * * 0.0.0.0/0 0.0.0.0/0
5 0 0 INPUT_ZONES all -- * * 0.0.0.0/0 0.0.0.0/0
6 0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0
7 0 0 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
2 0 0 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0
3 0 0 FORWARD_direct all -- * * 0.0.0.0/0 0.0.0.0/0
4 0 0 FORWARD_IN_ZONES_SOURCE all -- * * 0.0.0.0/0 0.0.0.0/0
5 0 0 FORWARD_IN_ZONES all -- * * 0.0.0.0/0 0.0.0.0/0
6 0 0 FORWARD_OUT_ZONES_SOURCE all -- * * 0.0.0.0/0 0.0.0.0/0
7 0 0 FORWARD_OUT_ZONES all -- * * 0.0.0.0/0 0.0.0.0/0
8 0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0
9 0 0 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
Chain OUTPUT (policy ACCEPT 305 packets, 97800 bytes)
num pkts bytes target prot opt in out source destination
1 305 97800 OUTPUT_direct all -- * * 0.0.0.0/0 0.0.0.0/0
Chain FORWARD_IN_ZONES (1 references)
num pkts bytes target prot opt in out source destination
1 0 0 FWDI_public all -- ens37 * 0.0.0.0/0 0.0.0.0/0 [goto]
2 0 0 FWDI_public all -- eno16777736 * 0.0.0.0/0 0.0.0.0/0 [goto]
3 0 0 FWDI_public all -- + * 0.0.0.0/0 0.0.0.0/0 [goto]
常见组合方式:
iptables -nvL #注意如果把短选项组合在一起,-L命令选项不能出现在最开始,例如iptables -Lnv就会报错
iptables -nvL --line-numbers
先关闭firewalld.service,然后去配置
(1) 允许原地址与我们系统ip在一个网络内的tcp报文通过
进来:
[root@gateway ~]# iptables -t filter -A INPUT -s 172.16.0.0/16 -p tcp -d 172.16.0.10 -j ACCEPT```
[root@gateway ~]# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
22 1712 ACCEPT tcp -- * * 172.16.0.0/16 172.16.0.10
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 16 packets, 1504 bytes)
pkts bytes target prot opt in out source destination
出去:
[root@gateway ~]# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
233 17932 ACCEPT tcp -- * * 172.16.0.0/16 172.16.0.10
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
4 544 ACCEPT tcp -- * * 172.16.0.10 172.16.0.0/16
(2) 把INPUT、OUTPUT以及FORWARD链的默认策略设置为DROP
#这里要注意,我们把所有filter表默认链设置为DROP后,这种修改是内存中实时生效的,而我们的ssh通常是远程
#连接的,所以要注意远程连接的问题,上面我们已经放行了我本地这个网段的权限。(这个是白名单机制,默认策略
#设置为禁止,然后放行指定部分)
[root@gateway ~]# iptables -P INPUT DROP
[root@gateway ~]# iptables -P OUTPUT DROP
[root@gateway ~]# iptables -P FORWARD DROP
[root@gateway ~]# iptables -nvL
Chain INPUT (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
472 36528 ACCEPT tcp -- * * 172.16.0.0/16 172.16.0.10
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
195 19148 ACCEPT tcp -- * * 172.16.0.10 172.16.0.0/16
添加内容:
[root@gateway ~]# iptables -t filter -A INPUT -d 172.16.0.10 -p icmp -j ACCEPT
[root@gateway ~]# iptables -t filter -A OUTPUT -s 172.16.0.10 -p icmp -j ACCEPT
[root@gateway ~]# iptables -vnL
Chain INPUT (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
765 59696 ACCEPT tcp -- * * 172.16.0.0/16 172.16.0.10
0 0 ACCEPT icmp -- * * 0.0.0.0/0 172.16.0.10
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
428 40980 ACCEPT tcp -- * * 172.16.0.10 172.16.0.0/16
0 0 ACCEPT icmp -- * * 172.16.0.10 0.0.0.0/0
(4) 只对主机所在网络开放ssh连接,假设默认端口是22
为了性能,我们把这条插入到第一条,后面把之前添加的开放整个网络段的所有协议会删掉。
[root@gateway ~]# iptables -t filter -I INPUT -s 172.16.0.0/16 -p tcp -d 172.16.0.10 --dport 22 -j ACCEPT
[root@gateway ~]# iptables -t filter -I OUTPUT -s 172.16.0.10 --sport 22 -p tcp -d 172.16.0.0/16 -j ACCEPT
iptables v1.4.21: unknown option "--sport"
Try `iptables -h' or 'iptables --help' for more information.
#这里有个注意事项,因为默认tcp是一个扩展模块,可以被隐式调用,也可以被显式调用,上面我们这种用法属于隐式调用。
#-p tcp这个参数要在--dport 和--sport前面,因为--dport和--sport都是-p tcp的子选项。
[root@gateway ~]# iptables -t filter -I OUTPUT -s 172.16.0.10 -p tcp --sport 22 -d 172.16.0.0/16 -j ACCEPT
[root@gateway ~]# iptables -nvL
Chain INPUT (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
330 26688 ACCEPT tcp -- * * 172.16.0.0/16 172.16.0.10 tcp dpt:22
1114 87353 ACCEPT tcp -- * * 172.16.0.0/16 172.16.0.10
4 240 ACCEPT icmp -- * * 0.0.0.0/0 172.16.0.10
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
23 2044 ACCEPT tcp -- * * 172.16.0.10 172.16.0.0/16 tcp spt:22
949 105K ACCEPT tcp -- * * 172.16.0.10 172.16.0.0/16
4 240 ACCEPT icmp -- * * 172.16.0.10 0.0.0.0/0
(5) 删除之前开放的允许整个网段的tcp协议通过的
[root@gateway ~]# iptables -nvL
Chain INPUT (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
374 29772 ACCEPT tcp -- * * 172.16.0.0/16 172.16.0.10 tcp dpt:22
1114 87353 ACCEPT tcp -- * * 172.16.0.0/16 172.16.0.10
4 240 ACCEPT icmp -- * * 0.0.0.0/0 172.16.0.10
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
68 15860 ACCEPT tcp -- * * 172.16.0.10 172.16.0.0/16 tcp spt:22
949 105K ACCEPT tcp -- * * 172.16.0.10 172.16.0.0/16
4 240 ACCEPT icmp -- * * 172.16.0.10 0.0.0.0/0
[root@gateway ~]# iptables -t filter -D INPUT 2
[root@gateway ~]# iptables -t filter -D OUTPUT 2
[root@gateway ~]# iptables -nvL
Chain INPUT (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
731 57144 ACCEPT tcp -- * * 172.16.0.0/16 172.16.0.10 tcp dpt:22
0 0 ACCEPT icmp -- * * 0.0.0.0/0 172.16.0.10
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
333 42888 ACCEPT tcp -- * * 172.16.0.10 172.16.0.0/16 tcp spt:22
4 240 ACCEPT icmp -- * * 172.16.0.10 0.0.0.0/0
(6) 调整一下策略,让默认策略允许,不过把入报文目标地址是本机,出报文,源地址是本机禁掉
先设置策略,然后再改默认策略。
[root@gateway ~]# iptables -t filter -A INPUT -d 172.16.0.10 -j REJECT
[root@gateway ~]# iptables -t filter -A OUTPUT -s 172.16.0.10 -j REJECT
[root@gateway ~]# iptables -nvL
Chain INPUT (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
979 76308 ACCEPT tcp -- * * 172.16.0.0/16 172.16.0.10 tcp dpt:22
0 0 ACCEPT icmp -- * * 0.0.0.0/0 172.16.0.10
0 0 REJECT all -- * * 0.0.0.0/0 172.16.0.10 reject-with icmp-port-unreachable
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
528 60076 ACCEPT tcp -- * * 172.16.0.10 172.16.0.0/16 tcp spt:22
4 240 ACCEPT icmp -- * * 172.16.0.10 0.0.0.0/0
0 0 REJECT all -- * * 172.16.0.10 0.0.0.0/0 reject-with icmp-port-unreachable
[root@gateway ~]# iptables -t filter -P INPUT ACCEPT
[root@gateway ~]# iptables -t filter -P OUTPUT ACCEPT
[root@gateway ~]# iptables -t filter -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
1122 87664 ACCEPT tcp -- * * 172.16.0.0/16 172.16.0.10 tcp dpt:22
0 0 ACCEPT icmp -- * * 0.0.0.0/0 172.16.0.10
0 0 REJECT all -- * * 0.0.0.0/0 172.16.0.10 reject-with icmp-port-unreachable
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
642 71560 ACCEPT tcp -- * * 172.16.0.10 172.16.0.0/16 tcp spt:22
4 240 ACCEPT icmp -- * * 172.16.0.10 0.0.0.0/0
0 0 REJECT all -- * * 172.16.0.10 0.0.0.0/0 reject-with icmp-port-unreachable
#这样一来,对于ssh协议和ping本机的icmp协议都可以分别被第一条和第二条链所匹配到,而且也允许出去。所以我们的远程
#ssh会话没有中断,而且外部也可以ping通本机。 而且这样做的好处是,之前ping本地会话不行,现在却可以了:
[root@gateway ~]# ping 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.056 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.056 ms
^C
--- 127.0.0.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.056/0.056/0.056/0.000 ms
(7) 使用一下接口参数
[root@gateway ~]# iptables -t filter -A INPUT -i eno16777736
[root@gateway ~]# iptables -t filter -A OUTPUT -o eno16777736
[root@gateway ~]# iptables -t filter -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
1446 112K ACCEPT tcp -- * * 172.16.0.0/16 172.16.0.10 tcp dpt:22
4 240 ACCEPT icmp -- * * 0.0.0.0/0 172.16.0.10
0 0 REJECT all -- * * 0.0.0.0/0 172.16.0.10 reject-with icmp-port-unreachable
0 0 all -- eno16777736 * 0.0.0.0/0 0.0.0.0/0
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
903 95812 ACCEPT tcp -- * * 172.16.0.10 172.16.0.0/16 tcp spt:22
8 480 ACCEPT icmp -- * * 172.16.0.10 0.0.0.0/0
0 0 REJECT all -- * * 172.16.0.10 0.0.0.0/0 reject-with icmp-port-unreachable
0 0 all -- * eno16777736 0.0.0.0/0 0.0.0.0/0
[root@gateway ~]# iptables -D INPUT 3
[root@gateway ~]# iptables -D OUTPUT 3
[root@gateway ~]# iptables -t filter -vnL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
1554 121K ACCEPT tcp -- * * 172.16.0.0/16 172.16.0.10 tcp dpt:22
4 240 ACCEPT icmp -- * * 0.0.0.0/0 172.16.0.10
0 0 all -- eno16777736 * 0.0.0.0/0 0.0.0.0/0
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
986 105K ACCEPT tcp -- * * 172.16.0.10 172.16.0.0/16 tcp spt:22
8 480 ACCEPT icmp -- * * 172.16.0.10 0.0.0.0/0
0 0 all -- * eno16777736 0.0.0.0/0 0.0.0.0/0
[root@gateway ~]# ping 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.037 ms
^C
--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.037/0.037/0.037/0.000 ms
(8) 清空指定表或默认表上链的所有规则
[root@gateway ~]# iptables -nvL
Chain INPUT (policy ACCEPT 2 packets, 168 bytes)
pkts bytes target prot opt in out source destination
2979 229K ACCEPT tcp -- * * 172.16.0.0/16 172.16.0.10 tcp dpt:22
8 480 ACCEPT icmp -- * * 0.0.0.0/0 172.16.0.10
0 0 all -- eno16777736 * 0.0.0.0/0 0.0.0.0/0
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 2 packets, 168 bytes)
pkts bytes target prot opt in out source destination
2401 167K ACCEPT tcp -- * * 172.16.0.10 172.16.0.0/16 tcp spt:22
12 720 ACCEPT icmp -- * * 172.16.0.10 0.0.0.0/0
0 0 all -- * eno16777736 0.0.0.0/0 0.0.0.0/0
[root@gateway ~]# iptables -F
[root@gateway ~]# iptables -nvL
Chain INPUT (policy ACCEPT 5 packets, 356 bytes)
pkts bytes target prot opt in out source destination
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 4 packets, 400 bytes)
pkts bytes target prot opt in out source destination
(9) 调整一下策略,让自己能ping通别人,别人不能ping通自己
之前规则有清空,先加一下ssh通过,以免断开。
[root@gateway ~]# iptables -A INPUT -d 172.16.0.10 -p tcp --dport 22 -j ACCEPT
[root@gateway ~]# iptables -A OUTPUT -s 172.16.0.10 -p tcp --sport 22 -j ACCEPT
[root@gateway ~]# iptables -A INPUT -i eno16777736 -j REJECT
[root@gateway ~]# iptables -A OUTPUT -o eno16777736 -j REJECT
#这几条代码,前面都解释过了,这里不再赘述
[root@gateway ~]# iptables -vnL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
270 20736 ACCEPT tcp -- * * 0.0.0.0/0 172.16.0.10 tcp dpt:22
0 0 REJECT all -- eno16777736 * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
127 11656 ACCEPT tcp -- * * 172.16.0.10 0.0.0.0/0 tcp spt:22
0 0 REJECT all -- * eno16777736 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable
#放行icmp协议代码
[root@gateway ~]# iptables -I OUTPUT 2 -s 172.16.0.10 -p icmp --icmp-type 8 -j ACCEPT
[root@gateway ~]# iptables -I INPUT 2 -d 172.16.0.10 -p icmp --icmp-type 0 -j ACCEPT
[root@gateway ~]# ping 114.114.114.114
PING 114.114.114.114 (114.114.114.114) 56(84) bytes of data.
64 bytes from 114.114.114.114: icmp_seq=1 ttl=128 time=22.3 ms
64 bytes from 114.114.114.114: icmp_seq=2 ttl=128 time=21.3 ms
^C
--- 114.114.114.114 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 21.392/21.854/22.317/0.485 ms
#这里有些知识点,我这里不特别说明。到下面讲到扩展模块的时候会重新提到tcp和udp以及icmp;
(10) 添加策略让别人也能ping通(基于第9例)
[root@gateway ~]# iptables -I INPUT 3 -d 172.16.0.10 -p icmp --icmp-type 8 -j ACCEPT
[root@gateway ~]# iptables -I OUTPUT 3 -s 172.16.0.10 -p icmp --icmp-type 0 -j ACCEPT
[root@gateway ~]# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
3207 181K ACCEPT tcp -- * * 0.0.0.0/0 172.16.0.10 tcp dpt:22
2 168 ACCEPT icmp -- * * 0.0.0.0/0 172.16.0.10 icmptype 0
0 0 ACCEPT icmp -- * * 0.0.0.0/0 172.16.0.10 icmptype 8
5 300 REJECT all -- eno16777736 * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
3449 2729K ACCEPT tcp -- * * 172.16.0.10 0.0.0.0/0 tcp spt:22
2 168 ACCEPT icmp -- * * 172.16.0.10 0.0.0.0/0 icmptype 8
0 0 ACCEPT icmp -- * * 172.16.0.10 0.0.0.0/0 icmptype 0
36435 3060K REJECT all -- * eno16777736 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable
(1) 自定义链
#在过滤表定义了一条名叫clearing的链。
[root@gateway ~]# iptables -N clearing
[root@gateway ~]# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
3353 192K ACCEPT tcp -- * * 0.0.0.0/0 172.16.0.10 tcp dpt:22
2 168 ACCEPT icmp -- * * 0.0.0.0/0 172.16.0.10 icmptype 0
4 240 ACCEPT icmp -- * * 0.0.0.0/0 172.16.0.10 icmptype 8
5 300 REJECT all -- eno16777736 * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
3573 2743K ACCEPT tcp -- * * 172.16.0.10 0.0.0.0/0 tcp spt:22
2 168 ACCEPT icmp -- * * 172.16.0.10 0.0.0.0/0 icmptype 8
4 240 ACCEPT icmp -- * * 172.16.0.10 0.0.0.0/0 icmptype 0
36435 3060K REJECT all -- * eno16777736 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable
Chain clearing (0 references)
pkts bytes target prot opt in out source destination
(2) 重命名自定义链和删除自定义链
[root@gateway ~]# iptables -E clearing input_clean
[root@gateway ~]# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
3477 201K ACCEPT tcp -- * * 0.0.0.0/0 172.16.0.10 tcp dpt:22
2 168 ACCEPT icmp -- * * 0.0.0.0/0 172.16.0.10 icmptype 0
4 240 ACCEPT icmp -- * * 0.0.0.0/0 172.16.0.10 icmptype 8
5 300 REJECT all -- eno16777736 * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
3673 2755K ACCEPT tcp -- * * 172.16.0.10 0.0.0.0/0 tcp spt:22
2 168 ACCEPT icmp -- * * 172.16.0.10 0.0.0.0/0 icmptype 8
4 240 ACCEPT icmp -- * * 172.16.0.10 0.0.0.0/0 icmptype 0
36435 3060K REJECT all -- * eno16777736 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable
Chain input_clean (0 references)
pkts bytes target prot opt in out source destination
[root@gateway ~]# iptables -X input_clean
基本匹配条件就上上文中提到的PARAMETERS(参数)选项。基本匹配条件尽量要先写。上文已经重点讲解过了,这里总结一下。
指定源地址:(核心)
[!] -s, --source address[/mask][,...]
指定目标地址:(核心)
[!] -d, --destination address[/mask][,...]
指定协议的:(核心)
[!] -p, --protocol protocol
指定输入接口:
[!] -i, --in-interface name
指定输出接口:
[!] -o, --out-interface name
跳转target:
-j, --jump target
跳转链:
-g, --goto chain
指定扩展模块:(重点)
-m, --match match
下面的扩展参考文档:man 8 iptables-extensions
或者:
iptables -m extension_module_name --help
iptables 可以通过基本选项(-m或–match)来使用扩展的报文匹配模块,简称扩展模块。-m 后边要加上扩展匹配
模块的名字,这样就表示显式调用了这个模块。在这个扩展模块选项指定后,后边可以使用各种额外的扩展模块
所支持的命令行选项(具体支持什么选项因模块而异,下文中会详细介绍)。在命令行可以指定多个扩展匹配模块,
规则生效顺序按照扩展模块指定的先后顺序。
扩展匹配模块中按照用法又分为隐式扩展和显式扩展,所谓隐式扩展,比如常见的tcp,udp以及icmp,这类本身属于协议,他们在使用的时候直接配合使用-p protocol_name,然后就好像调用-p protocol_name -m protocol_name一样,这样隐式调用也可以使用对应扩展模块的子选项。比如:
tcp属于可隐式调用模块,支持这样调用:
...... -p tcp [!] --sport port[:port] [!] --dport port[:port] ......
...... -p tcp -m tcp [!] --sport port[:port] [!] --dport port[:port] ......
该模块显式指定或隐式指定后,后边可以接着使用的选项以及含义简析:
[!] --source-port,--sport port[:port]:
指定源端口或源端口范围。这个port的值可以是一个服务名或一个(整数)数值端口。如果是指定的服务名,iptables在插入策略的时
候会去映射服务名对应的端口值而后插入(参考/etc/services配置文件),虽然可以通过修改/etc/services配置去改默认协议或服务的标
准映射端口值,这样修改后,iptables插入的时候确实可以做到插入修改后的值,不过不建议这样做。
指定端口范围的语法是first:last。如果省略起始端口(first),默认会以0来替代;如果省略结束端口(last),默认会以65535来替代。
虽然手册中写到,如果first端口大于last的端口值,那么会自行替换其实的端口,不过实际测试过程中,发现如果first的值大于last的
值,会报错。--sport是--source-port的等价的别名,通常都是用--sport,因为好记(要记住区别对待multiport扩展模块的子选项
--sports)。这个要么是单个指定值,要么是一个范围值,不支持离散值。
例如:
上面有提到port可以使用服务名:
-p tcp [-m tcp] --sport ssh #插入后默认值是22,中括号[]内的内容可以省略,因为这个模块可以隐式调用;
-p tcp [-m tcp] --sport http:https #插入后默认范围是80:443,中括号[]内的内容可以省略,因为这个模块可以隐式调用;
-p tcp [-m tcp] --sport :2048 #插入后默认范围是0:2048,中括号[]内的内容可以省略,因为这个模块可以隐式调用;
-p tcp [-m tcp] --sport 4000: #插入后默认范围是4000:65535;
PS:示例演示我就不贴出了,上面我都实际测试过了的。
[!] --destination-port,--dport port[:port]:
指定目标端口或端口范围。取值和源端口含义一样。这里就不说明了,通常也适用等价含义的别名--dport。同时要强调一点,要
区别multiport扩展模块的子选项--dports。这个要么是单个指定值,要么是一个范围值,不支持离散值。
[!] --tcp-flags mask comp:
当给定TCP报文标志位的时候的匹配。(Match when the TCP flags are as specified.)
选项的第一个参数mask是要检查的TCP报文标志位的列表,TCP报文一共可选的标志位有SYN, ACK, FIN, RST, URG, PSH。
这里可选的参数除了上面这6个标志位,还可以使用ALL来代表所有标志位,NONE来表示没有标志位。mask值的语法格式为,
如果值是以逗号分开的。 comp也是一个以逗号分隔的参数列表,这个参数必须要设置(设置的意思就是非0)。我们来看看下面的示例:
-p tcp [-m tcp] ---tcp-flags SYN,ACK,FIN,RST SYN
这句含义是,要检查的标志位一共有4个,分别是SYN,ACK,FIN,RST且SYN的值必须为1,其他三个ACK,FIN,RST必须为0.
这个示例其实就是TCP通信建立会话的第一次握手,就是新发起连接请求。
[!] --syn:
只匹配TCP报文中SYNC标志为被设置(值要为1),且ACK,RST以及FIN标志位被清除(值为0)的报文。这种报文是用去TCP连接请求的
初始连接状态(我们俗称的TCP的第一次握手)。这种等价于上面的选项--tcp-flags SYN,ACK,FIN,RST SYN。如果要表示第一次握手,
通常会使用这种简单的表示,而非上面那种复杂的表示法。
含义摘抄地址:http://www.cnblogs.com/liquan2005/p/9113369.html
TCP Header Format
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |U|A|P|R|S|F| |
| Offset| Reserved |R|C|S|S|Y|I| Window |
| | |G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
●源、目标端口号字段:占16比特。TCP协议通过使用"端口"来标识源端和目标端的应用进程。端口号可以使用0到65535之间的任何
数字。在收到服务请求时,操作系统动态地为客户端的应用程序分配端口号。在服务器端,每种服务在"众所周知的端口"(Well-Know
Port)为用户提供服务。
●顺序号字段:占32比特。用来标识从TCP源端向TCP目标端发送的数据字节流,它表示在这个报文段中的第一个数据字节。
●确认号字段:占32比特。只有ACK标志为1时,确认号字段才有效。它包含目标端所期望收到源端的下一个数据字节。
●头部长度字段:占4比特。给出头部占32比特的数目。没有任何选项字段的TCP头部长度为20字节(5x32=160比特);最多可以有
60字节的TCP头部。
●标志位字段(U、A、P、R、S、F):占6比特。各比特的含义如下:
◆URG:紧急指针(urgent pointer)有效。
◆ACK:确认序号有效。
◆PSH:接收方应该尽快将这个报文段交给应用层。
◆RST:重建连接。
◆SYN:发起一个连接。
◆FIN:释放一个连接。
●窗口大小字段:占16比特。此字段用来进行流量控制。单位为字节数,这个值是本机期望一次接收的字节数。
●TCP校验和字段:占16比特。对整个TCP报文段,即TCP头部和TCP数据进行校验和计算,并由目标端进行验证。
●紧急指针字段:占16比特。它是一个偏移量,和序号字段中的值相加表示紧急数据最后一个字节的序号。
●选项字段:占32比特。可能包括"窗口扩大因子"、"时间戳"等选项。
该模块显式指定或隐式指定后,后边可以接着使用的选项以及含义简析:
[!] --source-port,--sport port[:port]:
和TCP的选项含义一样。这里也是表示匹配udp报文的源端口;可以是端口范围;
[!] --destination-port,--dport port[:port]:
和TCP的选项含义一样,这里也是表示匹配udp报文的目标端口;可以是端口范围;
说明:学完之后要会放行本地的samba服务和dns服务中使用udp协议53号端口的部分。
samba涉及两个服务,一个是smb.service,涉及的端口和协议分别是:137/udp,138/udp
另一个是nmb.service,涉及的端口和协议分别是:139/tcp,445/tcp
DNS比较复杂,从网上摘录了一段比较经典的话:
https://www.cnblogs.com/549294286/p/5172435.html
DNS同时占用UDP和TCP端口53是公认的,这种单个应用协议同时使用两种传输协议的情况在TCP/IP栈也算是个另类。但很少有人知道DNS分别在什么情况下使用这两种协议。
如果用wireshark、sniffer或古老些的tcpdump抓包分析,会发现几乎所有的情况都是在使用UDP,使用TCP的情况非常罕见,神秘兮兮。其实当解析器发出一个request后,返回的response中的tc删节标志比特位被置1时,说明反馈报文因为超长而有删节。这是因为UDP的报文最大长度为512字节。解析器发现后,将使用TCP重发request,TCP允许报文长度超过512字节。既然TCP能将data stream分成多个segment,它就能用更多的segment来传送任意长度的数据。
另外一种情况是,当一个域的辅助域名服务器启动时,将从该域的主域名服务器primary DNS server执行区域传送。除此之外,辅域名服务器也会定时(一般时3小时)向PDS进行查询以便了解SOA的数据是否有变动。如有变动,也会执行一次区域传送。区域传送将使用TCP而不是UDP,因为传送的数据量比一个request或response多得多。
DNS主要还是使用UDP,解析器还是服务端都必须自己处理重传和超时。DNS往往需要跨越广域网或互联网,分组丢失率和往返时间的不确定性要更大些,这对于DNS客户端来说是个考验,好的重传和超时检测就显得更重要了。
关于DNS,网上这两篇博文有对DNS使用的协议端口进行比较剖析讲解:
http://blog.sina.com.cn/s/blog_4c86552f0102wyfc.html
https://www.cnblogs.com/549294286/p/5172435.html
该模块显式指定或隐式指定后,后边可以接着使用的选项以及含义简析:
下面这张图是icmp类型、代码以及含义对应表,图片摘自互联网:(下面设置时候有用到)
[!] --icmp-type {type[/code]|typename}:
指定ICMP协议的类型,可以使用数值表示也可以使用特定的类型名字表示。数值可能有type/code两种形式,第一个type的数值表示类
型,第二个数值code表示该类型下特定状态(可以理解为有些大类型下可以分为很多子类型),上面有一张表格有详细介绍这个对应值
的含义。typename的可选值下面有列出来。
一般这里的icmp类型常见的就两种,一个是8,表示发起的icmp协议请求(echo-request),另外一个0,表示icmp协议响应的报文。
例如,前面小结有讲到过的,要让别人能ping通你,这样的这一句话的含义是,首先ping通你,就是别人请求进来的icmp报文,
既然是进来的,就要设定echo-request允许。响应的icmp报文是服务器自己响应的,所以响应也要指定icmp协议的类型(echo-reply),即为0.
iptables [-t filter] -A INPUT -d 172.16.0.10 -p icmp [-m icmp] --icmp-type 8[/0] -j ACCEPT
iptables [-t filter] -A OUTPUT -s 172.16.0.10 -p icmp [-m icmp] --icmp-type 0[/0] -j ACCEPT
或者
iptables [-t filter] -A INPUT -d 172.16.0.10 -p icmp [-m icmp] --icmp-type echo-request -j ACCEPT
iptables [-t filter] -A OUTPUT -s 172.16.0.10 -p icmp [-m icmp] --icmp-type echo-reply -j ACCEPT
或者
iptables [-t filter] -A INPUT -d 172.16.0.10 -p icmp [-m icmp] --icmp-type ping -j ACCEPT
iptables [-t filter] -A OUTPUT -s 172.16.0.10 -p icmp [-m icmp] --icmp-type pong -j ACCEPT
参考iptables -p icmp -h之后的结果:
icmp match options:
[!] --icmp-type typename match icmp type
[!] --icmp-type type[/code] (or numeric type or type/code)
Valid ICMP Types:
any
echo-reply (pong)
destination-unreachable
network-unreachable
host-unreachable
protocol-unreachable
port-unreachable
fragmentation-needed
source-route-failed
network-unknown
host-unknown
network-prohibited
host-prohibited
TOS-network-unreachable
TOS-host-unreachable
communication-prohibited
host-precedence-violation
precedence-cutoff
source-quench
redirect
network-redirect
host-redirect
TOS-network-redirect
TOS-host-redirect
echo-request (ping)
router-advertisement
router-solicitation
time-exceeded (ttl-exceeded)
ttl-zero-during-transit
ttl-zero-during-reassembly
parameter-problem
ip-header-bad
required-option-missing
timestamp-request
timestamp-reply
address-mask-request
address-mask-reply
这个扩展模块用于匹配一组源端口或一组目标端口。单挑规则,15个端口是最大值。端口范围(port:port)算两个
端口。这个扩展模块只能配合协议为tcp,udp,udplite,dccp以及sctp一起使用。
[!] --source-ports,--sports port[,port|,port:port]...:
匹配是否源端口是给定的端口中的一部分。--sports是--source-ports等效的别名形式。多个离散的端口要使用逗号分隔符来分隔,一个
连续的端口范围使用冒号来分分隔,离散端口和端口范围可以一起结合使用。
例如:
-p tcp -m multiport --sports 80,443 #这个端口计数算两个。能匹配80和443端口;
-p tcp -m multiport --sports 4000:20000 #这个端口算2个,能匹配4000到20000这个范围内的端口,包括边界;
-p tcp -m multiport --sports 53,80,443,4000:20000 #这个端口算5个,能匹配53,80,443这三个离散端口以及4000到20000的端口范围,包括边界。
[!] --destination-ports,--dports port[,port|,port:port]...:
匹配是否目标端口是给定端口中的一部分。用法、取值和--sports一样。
[!] --ports port[,port|,port:port]...:
匹配是否源端口或目标端口是给定的端口中的一部分。用法、取值和--sports或--dports一样。
示例:修改之前的单个端口的,让22和80端口都能被正常访问
[root@gateway ~]# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
108 8708 ACCEPT tcp -- * * 0.0.0.0/0 172.16.0.10 tcp dpt:22
2 120 ACCEPT icmp -- * * 0.0.0.0/0 172.16.0.10 icmptype 8
44 5361 REJECT all -- * * 0.0.0.0/0 172.16.0.10 reject-with icmp-port-unreachable
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
16 1520 ACCEPT tcp -- * * 172.16.0.10 0.0.0.0/0 tcp spt:22
2 120 ACCEPT icmp -- * * 172.16.0.10 0.0.0.0/0 icmptype 0
0 0 REJECT all -- * * 172.16.0.10 0.0.0.0/0 reject-with icmp-port-unreachable
[root@gateway ~]# iptables -R INPUT 1 -d 172.16.0.10 -p tcp -m multiport --dports 22,80 -j ACCEPT
[root@gateway ~]# iptables -R OUTPUT 1 -s 172.16.0.10 -p tcp -m multiport --sports 22,80 -j ACCEPT
[root@gateway ~]# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
131 10252 ACCEPT tcp -- * * 0.0.0.0/0 172.16.0.10 multiport dports 22,80
2 120 ACCEPT icmp -- * * 0.0.0.0/0 172.16.0.10 icmptype 8
44 5361 REJECT all -- * * 0.0.0.0/0 172.16.0.10 reject-with icmp-port-unreachable
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
15 1412 ACCEPT tcp -- * * 172.16.0.10 0.0.0.0/0 multiport sports 22,80
2 120 ACCEPT icmp -- * * 172.16.0.10 0.0.0.0/0 icmptype 0
0 0 REJECT all -- * * 172.16.0.10 0.0.0.0/0 reject-with icmp-port-unreachable
#可以测试一下服务器上的httpd是否可以访问。测试就不截图了。
这个扩展匹配模块用来匹配任意的IP地址范围;
[!] --src-range from[-to]:
用指定的IP地址范围来匹配源IP地址;
[!] --dst-range from[-to]:
用指定的IP地址范围来匹配目标IP地址;
#只允许和我主机在一个网段内,源地址范围在172.16.0.1~172.16.0.20内的主机可以访问我的telnet服务
#修改前
[root@gateway ~]# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
31 2228 ACCEPT tcp -- * * 0.0.0.0/0 172.16.0.10 multiport dports 22,80
0 0 ACCEPT icmp -- * * 0.0.0.0/0 172.16.0.10 icmptype 8
0 0 REJECT all -- * * 0.0.0.0/0 172.16.0.10 reject-with icmp-port-unreachable
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
22 3192 ACCEPT tcp -- * * 172.16.0.10 0.0.0.0/0 multiport sports 22,80
0 0 ACCEPT icmp -- * * 172.16.0.10 0.0.0.0/0 icmptype 0
0 0 REJECT all -- * * 172.16.0.10 0.0.0.0/0 reject-with icmp-port-unreachable
#插入的策略
[root@gateway ~]# iptables -I INPUT 3 -d 172.16.0.10 -p tcp --dport 23 -m iprange --src-range 172.16.0.1-172.16.0.10 -j ACCEPT
[root@gateway ~]# iptables -I OUTPUT 3 -s 172.16.0.10 -p tcp --sport 23 -m iprange --dst-range 172.16.0.1-172.16.0.10 -j ACCEPT
#修改后
[root@gateway ~]# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
672 51740 ACCEPT tcp -- * * 0.0.0.0/0 172.16.0.10 multiport dports 22,80
0 0 ACCEPT icmp -- * * 0.0.0.0/0 172.16.0.10 icmptype 8
0 0 ACCEPT tcp -- * * 0.0.0.0/0 172.16.0.10 tcp dpt:23 source IP range 172.16.0.1-172.16.0.10
0 0 REJECT all -- * * 0.0.0.0/0 172.16.0.10 reject-with icmp-port-unreachable
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
507 52068 ACCEPT tcp -- * * 172.16.0.10 0.0.0.0/0 multiport sports 22,80
0 0 ACCEPT icmp -- * * 172.16.0.10 0.0.0.0/0 icmptype 0
0 0 ACCEPT tcp -- * * 172.16.0.10 0.0.0.0/0 tcp spt:23 destination IP range 172.16.0.1-172.16.0.10
0 0 REJECT all -- * * 172.16.0.10 0.0.0.0/0 reject-with icmp-port-unreachable
telnet服务要自己去安装(telnet-server软件包,telnet.socket),客户端也是,我现在拿已经弄好的环境测试一下telnet登录访问。一台客户端是172.16.0.4,一台客户端是172.16.0.120.
允许访问的测试过程:
[root@localhost ~]# ip addr list
1: lo: mtu 65536 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eno16777736: mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:57:46:83 brd ff:ff:ff:ff:ff:ff
inet 172.16.0.4/16 brd 172.16.255.255 scope global eno16777736
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe57:4683/64 scope link
valid_lft forever preferred_lft forever
[root@localhost ~]# telnet 172.16.0.10 23
Trying 172.16.0.10...
Connected to 172.16.0.10.
Escape character is '^]'.
Kernel 3.10.0-229.el7.x86_64 on an x86_64
gateway login: yanhui
Password:
Last login: Sat Dec 29 19:11:21 from ::ffff:172.16.0.1
[yanhui@gateway ~]$ who am i
yanhui pts/6 2018-12-29 19:31 (::ffff:172.16.0.4)
[yanhui@gateway ~]$ ip addr list
1: lo: mtu 65536 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eno16777736: mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:85:86:8d brd ff:ff:ff:ff:ff:ff
inet 172.16.0.10/16 brd 172.16.255.255 scope global eno16777736
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe85:868d/64 scope link
valid_lft forever preferred_lft forever
3: ens37: mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:85:86:97 brd ff:ff:ff:ff:ff:ff
inet 192.168.10.254/24 brd 192.168.10.255 scope global ens37
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe85:8697/64 scope link
valid_lft forever preferred_lft forever
不允许访问的测试过程:
[root@localhost ~]# telnet 172.16.0.10 23
Trying 172.16.0.10...
telnet: connect to address 172.16.0.10: Connection timed out
如果报文抵达的时间/日期在指定的范围内,则匹配。(This matches if the packet arrival time/date is within a given range.)所有下面的子选项都是可选的。默认使用UTC时间。
--datestart YYYY[-MM[-DD[Thh[:mm[:ss]]]]]
--datestop YYYY[-MM[-DD[Thh[:mm[:ss]]]]]:
仅仅匹配给定的时间范围内,时间格式必须要加上ISO 8601 的"T"标记。有效的时间范围为:
1970-01-01T00:00:00 to 2038-01-19T04:17:07
如果省略--datestart或省略--datestop,则会使用默认的1970-01-01和2038-01-19。
--timestart hh:mm[:ss]
--timestop hh:mm[:ss]:
仅仅匹配给定的时间范围内,与上面--datestart和--datestop区别是,这里只能指定时间,不能指定日期。可以的时间范围为:
00:00:00 ~ 23:59:59。允许数值带上前导0的形式,例如:上午6点半,可以写成6:30或06:30。这些时间数值都被识别成10进制。
[!] --monthdays day[,day...]:
Only match on the given days of the month. Possible values are 1 to 31. Note that specifying 31 will of course not match on months
which do not have a 31st day; the same goes for 28- or 29-day February.
只匹配每月指定的日期。可以使用的值为1到31.如果实际月份没有31天,如果指定了31就不会被匹配。2月的29天或28天也满足这种
定律。
[!] --weekdays day[,day...]:
Only match on the given weekdays. Possible values are Mon, Tue, Wed, Thu, Fri, Sat, Sun, or values from 1 to 7, respectively. You
may also use two-character variants (Mo, Tu, etc.).
值匹配给定的星期。可以设置的值Mon,Tue,Wed,Thu,Fri,Sat,Sun或1到7的值。也可以使用两个字符的缩写表示星期。
星期一:1或Mo或Mon
星期二:2或Tu或Tue
星期三:3或We或Wed
星期四:4或Th或Thu
星期五:5或Fr或Fri
星期六:6或Sa或Sat
星期天:7或Su或Sun
--contiguous:
When --timestop is smaller than --timestart value, match this as a single time period instead distinct intervals
如果--timestop的参数值小于--timestart的值,将其匹配为单个时间段,而不是不同的间隔。请参考下面文档中自己附带的实例。
这里文档中有个示例:
Matching across days might not do what is expected. For instance,
-m time --weekdays Mo --timestart 23:00 --timestop 01:00 Will match Monday, for one hour from midnight to 1 a.m., and then
again for another hour from 23:00 onwards. If this is unwanted, e.g. if you would like 'match for two hours from Monday 23:00
onwards' you need to also specify the --contiguous option in the example above.
跨天匹配可能无法达到预期的效果。例如,
-m time --weekdays Mo --timestart 23:00 --timestop 01:00
上面示例匹配的是周一的午夜(0点)到凌晨1点这一小时,以及周一的23点往前一小时。如果不是预期的,可能你只能想匹配从
周一的23:00往后推2小时,可以在上面示例选项中加上--contiguous:
-m time --weekdays Mo --timestart 23:00 --timestop 01:00 --contiguous
--kerneltz:
Use the kernel timezone instead of UTC to determine whether a packet meets the time regulations.
使用内核时区而不是通过UTC来决定是否一个报文满足时间规则。
示例:在前边telnet服务访问控制的基础上,再加一条规则,只有正常工作日(周一到周五)的上班期间(9:00~17:30)
才能访问。
[root@gateway ~]# iptables -R INPUT 3 -d 172.16.0.10 -p tcp --dport 23 -m iprange --src-range 172.16.0.1-172.16.0.10 -m time --timestart 9:00:00 --timestop 17:30 --weekdays 1,2,3,4,5 --kerneltz -j ACCEPT
[root@gateway ~]# iptables -R OUTPUT 3 -s 172.16.0.10 -p tcp --sport 23 -m iprange --dst-range 172.16.0.1-172.16.0.10 -m time --timestart 9:00:00 --timestop 17:30 --weekdays 1,2,3,4,5 --kerneltz -j ACCEPT
[root@gateway ~]# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
1471 113K ACCEPT tcp -- * * 0.0.0.0/0 172.16.0.10 multiport dports 22,80
0 0 ACCEPT icmp -- * * 0.0.0.0/0 172.16.0.10 icmptype 8
0 0 ACCEPT tcp -- * * 0.0.0.0/0 172.16.0.10 tcp dpt:23 source IP range 172.16.0.1-172.16.0.10 TIME from 09:00:00 to 17:30:00 on Mon,Tue,Wed,Thu,Fri
7 420 REJECT all -- * * 0.0.0.0/0 172.16.0.10 reject-with icmp-port-unreachable
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
1108 104K ACCEPT tcp -- * * 172.16.0.10 0.0.0.0/0 multiport sports 22,80
0 0 ACCEPT icmp -- * * 172.16.0.10 0.0.0.0/0 icmptype 0
0 0 ACCEPT tcp -- * * 172.16.0.10 0.0.0.0/0 tcp spt:23 destination IP range 172.16.0.1-172.16.0.10 TIME from 09:00:00 to 17:30:00 on Mon,Tue,Wed,Thu,Fri
23 1816 REJECT all -- * * 172.16.0.10 0.0.0.0/0 reject-with icmp-port-unreachable
#测试过程略,可以临时调整提供服务器的服务器上的日期和时间自行测试,我已验证。
This modules matches a given string by using some pattern matching strategy. It requires a linux kernel >= 2.6.14.
这个模块可以通过使用一些模式匹配策略来匹配给定的字符串。需要使用环境的linux内核版本高于或者等于2.6.14;
--algo {bm|kmp}
Select the pattern matching strategy. (bm = Boyer-Moore, kmp = Knuth-Pratt-Morris)
选择模式匹配策略。
PS:bm和kmp相差都不太,对于我们使用来讲不需要特别深入研究。可以理解为不同的实现算法。
--from offset:
Set the offset from which it starts looking for any matching. If not passed, default is 0.
设置查找指定模式开始的偏移量。如果没有指定,默认是0.表示从头开始搜寻。
PS:简单来说就是查找默认从第一个字符开始,如果指定其实偏移量后,会从offset个字符开始。
--to offset:
Set the offset up to which should be scanned. That is, byte offset-1 (counting from 0) is the last one that is scanned.
If not passed, default is the packet size.
指定结束偏移量。默认是整个报文的大小。
[!] --string pattern:
Matches the given pattern.
匹配给定的模式.
[!] --hex-string pattern:
Matches the given pattern in hex notation
匹配给定的16进制标记的模式。
默认示例:
Examples:
# The string pattern can be used for simple text characters.
iptables -A INPUT -p tcp --dport 80 -m string --algo bm --string 'GET /index.html' -j LOG
# The hex string pattern can be used for non-printable characters, like |0D 0A| or |0D0A|.
iptables -p udp --dport 53 -m string --algo bm --from 40 --to 57 --hex-string '|03|www|09|netfilter|03|org|00|'
这个模块允许你限制每个客户端IP地址(或客户端地址块)到服务器的并行连接数量。
--connlimit-upto n:
Match if the number of existing connections is below or equal n.
匹配现有连接数量是否小于或等于n。
--connlimit-above n:
Match if the number of existing connections is above n
匹配现有连接数量是否大于n。
--connlimit-mask prefix_length:
Group hosts using the prefix length. For IPv4, this must be a number between (including) 0 and 32. For IPv6, between 0 and 128.
If not specified, the maximum prefix length for the applicable protocol is used.
使用前缀长度对主机进行分组。对于IPv4,这个前缀长度值只是是0到32之前的。对于IPv6而言,只能指定0到128之间的。如果没有
指定,会使用适用协议最大长度的前缀。
--connlimit-saddr:
Apply the limit onto the source group. This is the default if --connlimit-daddr is not specified.
如果使用前缀长度对主机分组,对于源组应用限制。如果没有使用--connlimit-daddr选项,该参数就是默认的。
--connlimit-daddr:
Apply the limit onto the destination group.
对于目标组进行限制。
示例说明:
可以部署一个mysql或mariadb服务器。然后做连接并发限制。例如:
iptables -I INPUT 2 -d 172.16.0.10 -s 172.16.0.0/26 -p tcp --dport 3306 -m connlimit --connlimit-upto 2 -j ACCEPT
了解这个扩展模块的作用和原理,要先了解令牌通算法。请参考:
https://baike.baidu.com/item/令牌桶算法/6597000?fr=aladdin
This module matches at a limited rate using a token bucket filter. A rule using this extension will match until
this limit is reached.It can be used in combination with the LOG target to give limited logging
通过令牌桶过滤器来限制匹配的速率。
--limit rate[/second|/minute|/hour|/day]:
Maximum average matching rate: specified as a number, with an optional `/second', `/minute', `/hour', or `/day' suffix;
the default is 3/hour.
匹配限制的最大速率。可选后缀有/second表示每秒;/minute表示每分;/hour表示每小时,/day表示每天。
默认值是:每小时3。
--limit-burst number:
Maximum initial number of packets to match: this number gets recharged by one every time the limit specified above is not
reached, up to this number; the default is 5.
最多可以收集多少个令牌。默认值是5.
示例:
iptables -I INPUT 1 -d 172.16.0.10 -p icmp --icmp-type 8 -m limit --list-burst 5 --limit 20/minute -j ACCPET
iptables -I OUPUT 1 -s 172.16.0.10 -p icmp --icmp-type 0 -j ACCEPT
#限制http的新建连接并发。
iptables -I INPUT 4 -d 172.16.-.10 -p tcp --dport 80 -m tcp --syn -m limit --limit-burst 1000 -limit 800/second -j AACEPT
The “state” extension is a subset of the “conntrack” module. “state” allows access to the connection
tracking state for this packet.
state扩展模块是conntrack扩展模块的子集(子模块)。state允许去访问报文的连接追踪状态。
[!] --state state:
Where state is a comma separated list of the connection states to match. Only a subset of the states unterstood by "conntrack"
are recognized: INVALID, ESTABLISHED, NEW, RELATED or UNTRACKED.
指定要匹配的追踪状态的值,多个值组成的参数列表要使用逗号分隔。
这里指定的状态要能被conntrack扩展模块所识别,在state模块中可以使用的状态有:INVALID,ESTABLISHED,NEW,RELATED以及
UNTRACKED。其中每个状态的含义如下:(这里的连接千万不要和tcp的连接混用,这里的是针对不止tcp协议的,还针对udp,icmp等)
INVALID
The packet is associated with no known connection.
报文和未知连接有关系。简单来说就是异常报文或异常连接,无法识别的连接;
ESTABLISHED
The packet is associated with a connection which has seen packets in both directions.
已建立的连接。
NEW
The packet has started a new connection or otherwise associated with a connection which has not seen packets
in both directions.
新连接请求。
RELATED
The packet is starting a new connection, but is associated with an existing connection, such as an FTP data transfer or
an ICMP error.
相关联的连接,当前连接是一个新请求,但附属于某个已存在的连接;
UNTRACKED
The packet is not tracked at all, which happens if you explicitly untrack it by using -j CT --notrack in the raw table.
未追踪的连接,无法被追踪。如果在raw表中使用-j ct --notrack显式地取消跟踪,就会发生这种情况。
关于连接追踪,引用一段网上博文其他的话:
http://blog.51cto.com/minux/1727684
iptables/netfilter具有追踪连接状态功能,用于描述各会话连接之间的关系型。一般为四层协议:TCP,UDP,ICMP等;
为什么要追踪连接状态呢?iptables/netfilter默认规则为拒绝的情况下,当用户访问一个iptables/netfilter允许的服务(端口)的时候,服务器如果想要回复客户端则还需要为其设定一个放行的规则(如果有多个就要多个规则),然而这样每一个服务或应用都手动配置一条规则,规则表会非常多,而且处理效益不高,这是多余的。当防火墙允许客户端向服务器通信时,则认为此连接一定是负荷规则的,与之相对的通信都应该具备可靠性,可以对其他放行。这样就可以实现一条规则放行所有可信的通信,而不用多条规则。
iptables/netfilter的状态追踪由state模块,state模块底层依赖于nf_conntrack(2.6内核之前叫做ip_conntrack),nf_conntrack是内核功能,负责具体的连接追踪的实施。可以通过模块(lsmod)查看等命令来确认nf_conntrack是否有加载。
nf_conntrack是有限制的,其根据内部算法,会在内核空间所持有的内存区域中记录各个所追踪的连接的状态,并将其映射到/proc/net/nf_conntrack文件中。nf_conntrack连接追踪的限制由/proc/sys/net/nf_conntrack_max文件控制。
涉及几个比较重要的文件和目录:
目录:
/proc/sys/net
/proc/net
文本文件:
追踪到的连接:/proc/net/nf_conntrack
调整可记录的连接数量最大值:/proc/sys/net/nf_conntrack_max
超时时长:/proc/sys/net/netfilter/*timeout*
让我们来简单看看一个使用案例,对于ftp的主动模式和被动模式的应用可能会用到这个连接追踪功能。默认有个内核模块叫nf_conntrack_ftp没有导入,我们需要导入一下。linux有几个与模块管理相关的命令。
lsmod命令:显示linux内核的状态信息(被装载的模块),这个命令取得原始快照数据是/proc/modules的内容;
modinfo命令:显示linux内核的模块的说明信息
modinfo [-F field] [-k kernel] [modulename|filename...]
-F field:仅显示指定字段的信息;
-n:显示文件路径;
modprobe命令:(动态)装载或卸载linux内核模块
modprobe [-r] module_name
模块的动态状态:modprobe module_name
动态的卸载:modprobe -r module_name
depmod:内核模块依赖关系文件的生成工具
另外一组比较不好用的模块的装载和卸载工具(主要有时候装载模块有依赖关系,要手动解决依赖关系,即先手动挂载依赖的模块,
而且还要装载的时候还要指定模块文件全路径,具体应用请参考下面实际的例子):
insmod:装载指定模块路径下指定的模块;
insmod [filename] [module options...]
filename:模块文件的文件路径;
rmmod:卸载指定的模块(不需要指定全路径);
rmmod [module_name]
比如我们想要动态装载或卸载与ftp相关的内核的连接追踪模块:
a) 查看nf_conntrack_ftp模块是否状态
[root@gateway ~]# lsmod |grep 'nf_conntrack_ftp'
#没有结果就表示此模块并没有被装载。
b) 查看nf_conntrack_ftp模块说明信息
[root@gateway ~]# modinfo nf_conntrack_ftp
filename: /lib/modules/3.10.0-229.el7.x86_64/kernel/net/netfilter/nf_conntrack_ftp.ko
alias: nfct-helper-ftp
alias: ip_conntrack_ftp
description: ftp connection tracking helper
author: Rusty Russell
license: GPL
rhelversion: 7.1
srcversion: 13050F0A1E370983C87DEA6
depends: nf_conntrack
intree: Y
vermagic: 3.10.0-229.el7.x86_64 SMP mod_unload modversions
signer: CentOS Linux kernel signing key
sig_key: A6:2A:0E:1D:6A:6E:48:4E:9B:FD:73:68:AF:34:08:10:48:E5:35:E5
sig_hashalgo: sha256
parm: ports:array of ushort
parm: loose:bool
#此过程可以了解模块文件的绝对路径以及默认挂载所依赖的模块。如果使用insmod命令装载就要考虑这两个点,如果使用modprobe
不需要过度关心这两个点。
c) 使用传统命令(insmod/rmmod)实现模块的装载和卸载
装载:
[root@gateway ~]# insmod /lib/modules/3.10.0-229.el7.x86_64/kernel/net/netfilter/nf_conntrack_ftp.ko
[root@gateway ~]# lsmod |grep 'nf_conntrack_ftp'
nf_conntrack_ftp 18638 0
nf_conntrack 105702 3 xt_connlimit,nf_conntrack_ftp,nf_conntrack_ipv4
卸载:
[root@gateway ~]# rmmod nf_conntrack_ftp
[root@gateway ~]# lsmod |grep 'nf_conntrack_ftp'
d) 使用高效命令(modprobe)实现模块的状态和卸载
装载:
[root@gateway ~]# lsmod |grep 'nf_conntrack_ftp'
[root@gateway ~]# modprobe nf_conntrack_ftp
[root@gateway ~]# lsmod |grep 'nf_conntrack_ftp'
nf_conntrack_ftp 18638 0
nf_conntrack 105702 3 xt_connlimit,nf_conntrack_ftp,nf_conntrack_ipv4
卸载:
[root@gateway ~]# modprobe -r nf_conntrack_ftp
[root@gateway ~]# lsmod |grep 'nf_conntrack_ftp'
现在先简单的调整一下防火墙:
#先清空规则
[root@gateway ~]# iptables -F
#加入一些常见服务的端口
[root@gateway ~]# iptables -A INPUT -d 172.16.0.10 -p tcp -m multiport --dports 20:23,80,139,443,445,8080,10020:10540,13721 -m state --state NEW -j ACCEPT
[root@gateway ~]# iptables -I INPUT 1 -m state --state ESTABLISHED,RELATED -j ACCEPT
[root@gateway ~]# iptables -I INPUT 3 -d 172.16.0.10 -j REJECT
#INPUT链进来,第一条规则,对于ESTABLISHED和RELATED的状态,都允许。这样ftp的主动模式是在命令连接的基础上,主动
去连接客户端的,这种主动连接的发起是服务端,这样的数据连接与命令连接有关系,可以理解为RELATED状态的报文。
# 对于tcp协议的本机端口20到23(20默认ftp数据端口,21默认的ssh协议端口,23默认的telnet服务端口),80(默认的http协议的端口)
#139,445这两个是和samba相关的。443是https协议的端口。8080,10020到10540以及13721我是添加了给测试用的,测试服务使用
#非默认端口
[root@gateway ~]# iptables -A OUTPUT -s 172.16.0.10 -m state --state ESTABLISHED -j ACCEPT
[root@gateway ~]# iptables -A OUTPUT -s 172.16.0.10 -p udp -m multiport --dports 123,323 -m state --state NEW -j ACCEPT
[root@gateway ~]# iptables -A OUTPUT -s 172.16.0.10 -j REJECT
#对于从本机出去的报文,状态是ESTABLISHED允许。
#对于端口是123,323,协议是udp,这两个是与本机与外界时间服务器同步相关的,状态是NEW就是新发起的。
[root@gateway ~]# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
920 72157 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
0 0 ACCEPT tcp -- * * 0.0.0.0/0 172.16.0.10 multiport dports 20:23,80,139,443,445,8080,10020:10540,13721 state NEW
0 0 REJECT all -- * * 0.0.0.0/0 172.16.0.10 reject-with icmp-port-unreachable
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
417 58728 ACCEPT all -- * * 172.16.0.10 0.0.0.0/0 state ESTABLISHED
0 0 ACCEPT udp -- * * 172.16.0.10 0.0.0.0/0 multiport dports 123,323 state NEW
0 0 REJECT all -- * * 172.16.0.10 0.0.0.0/0 reject-with icmp-port-unreachable
服务端启动vsftpd,然后客户端去连接并测试上传数据:
vsftpd的按照下面配置,让匿名用户可以写和上传:
anonymous_enable=YES
anon_upload_enable=YES
anon_mkdir_write_enable=YES
anon_mkdir_write_enable=YES
connect_from_port_20=YES
port_enable=YES
pasv_enable=YES
pasv_min_port=10020
pasv_max_port=10540
并在匿名用户家目录创建一个目录,可以让匿名用户可写:
[root@gateway ~]# mkdir -pv /var/ftp/pub/uploads
mkdir: created directory ‘/var/ftp/pub/uploads’
[root@gateway ~]# setfacl -m u:ftp:rwx /var/ftp/pub/uploads
[root@gateway ~]# getfacl -p /var/ftp/pub/uploads
# file: /var/ftp/pub/uploads
# owner: root
# group: root
user::rwx
user:ftp:rwx
group::r-x
mask::rwx
other::r-x
[root@gateway ~]# systemctl start vsftpd.service
[root@gateway ~]# ss -tnl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 :::80 :::*
LISTEN 0 32 :::21 :::*
LISTEN 0 128 :::22 :::*
LISTEN 0 128 :::23 :::*
LISTEN 0 100 ::1:25 :::*
客户端测试(默认被动模式):
[root@localhost ~]# ftp 172.16.0.10 21
Connected to 172.16.0.10 (172.16.0.10).
220 (vsFTPd 3.0.2)
Name (172.16.0.10:root): ftp
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
227 Entering Passive Mode (172,16,0,10,39,182).
150 Here comes the directory listing.
drwxr-xr-x 3 0 0 20 Dec 29 10:28 pub
226 Directory send OK.
ftp> cd pub
250 Directory successfully changed.
ftp> ls
227 Entering Passive Mode (172,16,0,10,39,200).
150 Here comes the directory listing.
drwxrwxr-x 2 0 0 6 Dec 29 10:28 uploads
226 Directory send OK.
ftp> cd uploads
250 Directory successfully changed.
ftp> lcd /etc/
Local directory now /etc
ftp> put issue
local: issue remote: issue
227 Entering Passive Mode (172,16,0,10,40,227). #这里使用的是被动模式了
150 Ok to send data.
226 Transfer complete.
23 bytes sent in 0.000132 secs (174.24 Kbytes/sec)
ftp> ls
227 Entering Passive Mode (172,16,0,10,40,251).
150 Here comes the directory listing.
-rw------- 1 14 50 23 Dec 29 10:29 issue
226 Directory send OK.
后续步骤略。
#ftp涉及的东西很复杂,而且主动模式和被动模式不是涉猎的这么简单,我一直抓包分析都没有完全弄懂。
#希望后面有专门阅读过源码的人指定一番,特别是涉及到开启防火墙情况下,ftp主动模式传输数据通过
#的,并且能以抓包结果证明。(我线上一直都是用的被动模式,ftp主动模式在防火墙开启情况下,我一直
#没有调试通过,而且windows的cmd命令工具貌似不给力。)
(1) ACCEPT
这个ACCEPT原文注解是:ACCEPT means to let the packet through. ACCEPT意味着让报文通过;
(2) DROP
DROP means to drop the packet on the floor.DROP以为在入口或门口就把这个报文给删掉了。
(3) RETURN
RETURN means stop traversing this chain and resume at the next rule in the previous (calling) chain.
RETURN意味着停止遍历当前链的规则并且继续之前链(之前链有调用其他链)的下一下规则。
简单来说在遍历A链规则的时候有调用B链,然后遍历B链规则的时候使用RETURN可以返回掉A链,并继续开始
执行匹配A链上的规则。
(1) REJECT
This is used to send back an error packet in response to the matched packet: otherwise it is equivalent to DROP so it is a terminating TARGET,ending rule traversal.This target is only valid in the INPUT, FORWARD and OUTPUT chains, and user-defined chains which are only called from those chains.The following option controls
the nature of the error packet returned:
REJECT与DROP的区别就是,同样都是拒绝,DROP就是不给对方回应,REJECT就是给别人一个错误说明。
这个错误说明可以自己控制,建议有些场景要使用REJECT。(比如你喜欢一个女孩,你给她送一束花。DROP就
表示这个女孩收到后,什么都不说;而REJECT就是收到后,告诉你"老娘"已经名花有主了或者说告知你,你是一个好人,我不配你之类的云云)。
REJECT这个target只能用于INPUT,FORWARD,OUTPUT以及调用这三个链的用户自定义的链。下面的选项控制返回错误数据包的类型。
–reject-with type
The type given can be icmp-net-unreachable, icmp-host-unreachable, icmp-port-unreachable, icmp-proto-unreachable, icmp-net-prohibited, icmp-host-prohibited,or icmp-admin- prohibited (), which return the appropriate ICMP error message (icmp-port-unreachable is the default). The option tcp-reset can be used on rules which only match the TCP protocol: this causes a TCP RST packet to be sent back. This is mainly useful for blocking ident (113/tcp) probes which frequently occur when sending mail to broken mail hosts (which won’t accept your mail otherwise).
() Using icmp-admin-prohibited with kernels that do not support it will result in a plain DROP instead of REJECT
上面这一大段话,重点就说明了两个:
(1) 默认不指定REJECT返回错误类型就是 icmp-port-unreachable;
(2) 支持的错误类型有:
icmp-net-unreachable
icmp-host-unreachable
icmp-port-unreachable
icmp-proto-unreachable
icmp-net-prohibited
icmp-host-prohibited
icmp-admin- prohibited
(2) LOG
Turn on kernel logging of matching packets.When this option is set for a rule, the Linux kernel will print some
information on all matching packets (like most IP/IPv6 header fields) via the kernel log (where it can be read
with dmesg(1) or read in the syslog).
This is a “non-terminating target”, i.e. rule traversal continues at the next rule. So if you want to LOG the packets
you refuse, use two separate rules with the same matching criteria, first using target LOG then DROP (or REJECT).
打开内核记录匹配报文日志的功能。当这个选项被作为一个规则设置的时候或规则中调用这个LOG的时候,linux的内核会打印一些关于所有匹配报文的信息(像大多数的IP首部字段信息等),默认记录在内核日志/var/log/messages中,可以使用syslog和dmesg等程序去做日志查看(也可以直接是用文本编辑器查看messages日志)。
这个LOG不是一个终止的target,它只是对于被此规则所匹配到的报文记录到相应的内核日志中,然后报文会接着遍历对应链上接下来的规则。如果要想使用内核日志记录被拒绝的数据报文的信息,可以使用两聊独立的规则,第一条用来记录日志,第二条来指定被匹配到后的处理目标动作为DROP或REJECT。
支持的选项:
-log-level level:
Level of logging, which can be (system-specific) numeric or a mnemonic. Possible values are (in decreasing
order of priority): emerg, alert, crit, error, warning, notice, info or debug.
记录的日志级别。可以使用的值:
emerg,alert,crit,error,warning,notice,info以及debug。
PS:生产环境,建议记录warning或者notice即可。
--log-prefix prefix:
Prefix log messages with the specified prefix; up to 29 letters long, and useful for distinguishing messages in
the logs.
可以给记录的日志加上前缀信息,最长支持29个字符长度。加前缀的作用可以用来区别不同的日志记录。
--log-tcp-sequence:
Log TCP sequence numbers. This is a security risk if the log is readable by users.
--log-tcp-options:
Log options from the TCP packet header.
记录TCP报文首部的选项信息。
--log-ip-options:
Log options from the IP/IPv6 packet header.
记录IP报文首部的选项信息。
--log-uid:
Log the userid of the process which generated the packet.
记录产生数据报文的用户进程的id信息。
保存和载入规则:
保存:iptables-save > /PATH/TO/SOME_RULE_FILE
重载:iptabls-restore < /PATH/FROM/SOME_RULE_FILE
-n, --noflush:不清除原有规则
-t, --test:仅分析生成规则集,但不提交
比如:
#先查看策略
[root@gateway ~]# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
26 2080 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
0 0 ACCEPT tcp -- * * 0.0.0.0/0 172.16.0.10 multiport dports 20:23,80,139,443,445,8080,10020:10540,13721 state NEW
0 0 REJECT all -- * * 0.0.0.0/0 172.16.0.10 reject-with icmp-port-unreachable
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
23 2180 ACCEPT all -- * * 172.16.0.10 0.0.0.0/0 state ESTABLISHED
0 0 ACCEPT udp -- * * 172.16.0.10 0.0.0.0/0 multiport dports 123,323 state NEW
0 0 REJECT all -- * * 172.16.0.10 0.0.0.0/0 reject-with icmp-port-unreachable
#把策略备份
[root@gateway ~]# iptables-save >/tmp/iptables.back1
#清空策略
[root@gateway ~]# iptables -F
#确认策略
[root@gateway ~]# iptables -vnL
Chain INPUT (policy ACCEPT 21 packets, 1640 bytes)
pkts bytes target prot opt in out source destination
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 18 packets, 1532 bytes)
pkts bytes target prot opt in out source destination
#载入策略
[root@gateway ~]# iptables-restore
CentOS 6:
保存规则:
service iptables save
保存规则于/etc/sysconfig/iptables文件,覆盖保存;
重载规则:
service iptables restart
默认重载/etc/sysconfig/iptables文件中的规则
配置文件:/etc/sysconfig/iptables-config
CentOS 7:
(1) 自定义Unit File,进行iptables-restore;
(2) firewalld服务;
(3) 自定义脚本;
简单梳理一下防火墙的netfilter框架的流程:
四表五链(CentOS 6.x),五表五链(CentOS 7.x),按照从高到低的应用的优先顺序依次为:raw,mangle,nat,filter。这里没有给出security,是因为应用的不多,而且是为了selinux新增的一个表,selinux本身大部分公司都不会去用,所以这里没有给出来。
filter表示实现的功能是过滤,也是真正意义上的防火墙的核心意义之所在,只有它才算得上是防火墙,其他几个表实现的功能都已经是额外的其他功能了。这几个额外的功能是我们内核中用来实现操纵通信报文的其他几个功能,比如nat用来实现网络地址转换(源地址转换或目标地址转换都是可行的),mangle理解为做报文修改用的,除了地址转换、端口转换以外的报文首部的其他报文的信息的修改,都可以在mangle中实现,在mangle中应用比较多的是实际上是一种防火墙打标的功能,可以把任何报文经过防火墙之后,给它加一标记,分分类,通常用来做分类器,比如访问目标端口是TCP的80的给它标记为1,访问目标端口是TCP的21的标记为2的给,将来可以基于分类标识符来实现做报文识别而不要再基于所谓的端口和地址了。raw表所提供的主要功能主要是关闭nat表所打开的连接追踪功能,如果某些功能,我们不打算去追踪,只是做地址转换,而且转换后只有出去的报文没有回来的报文,此时,我们就不需要去做追踪。
进出本地netfilter框架的协议报文大概可以分为三个流程:
(1)进入本机
先经过PREROUTING,然后是INPUT
(2)经由本机转发的
先经过PREROUTING,然后是FORWARD,其次是POSTROUTING
(3)经由本机发出的
先是OUTPUT,然后是POSTROUTING
弄清上面三个协议报文的流程非常重要,因为我们写规则的时候要弄清楚谁是源,谁是目标以及规则添加该添加在何处。对于一个主机来讲,接口网卡可能有多个。任何时候,刚刚到达本机还没有进行路由之前的都要先经过PREROUTING处理,无论是经过OUTPUT还是FORWARD之后将要离开本机,还未路由决定经过哪一个网卡出去的,都会经过POSTROUTING处理。也就是所,报文的流向和网卡的前后左右,和网卡的数量没有关系,任何时候从一个网卡进来,也有可能从同一个网卡出去,我们要注意的都只是报文的流向,即我们上面强调的协议报文的流程。
刚刚进来,还未进入本机的是PREROUTING,快要出去,的经过是POSTROUTING。进入本机后,有三个比较核心的链,分别是INPUT,FORWARD以及OUTPUT,这些位置也是我们通常做报文深入控制的位置,不管怎么讲,这些链路上的控制无非是上文中提到的三个流程或者流向。
对于一台主机来讲,如果我们用来做单机防火墙,我们只需要管两个流程:
进入本机的和从本机发出的。对于这种情况,如果要阻断某些应用或服务,我们有两种方式,第一,直接在报文进入的入口处进行阻断,即在INPUT链上设置。第二,可以让报文进来,不然它出去,就是在报文的出口处进行阻断,即在OUTPUT链上设置。这两种方式,前一种比较高效,一般写规则的时候,我们会有一种习惯。如果是别人访问自己的,我们先写在INPUT链上写策略,如果是自己访问别人的,我们先在OUTPUT链上写规则。逻辑是:先去规划请求报文,再去规划响应报文。
对于过滤来讲,filter表上实现的链有INPUT,FORWARD以及OUTPUT;
对于网络地址来讲,nat表上实现的链有PREROUTING,INPUT(CentOS6上没有,CentOS7上引入的),OUTPUT以及POSTROUTING。如果主机既要实现单机防火墙,也要实现网络防火墙,就涉及上面的三个流程的,而且作为网络防火墙,要打开主机上的核心转发功能,对于路由条目,要先能实现主机自我学习,还要配合上对应的软件实现。通常来讲,如果是要做专业的网络防火或者是路由功能,建议购买专业的硬件,如果只是简单的实现网络报文控制,可以把主机作为防火墙或路由器。
所谓网关,任何非本地网络通信的报文都要经由网关设备来做转发。这个网关设备可能是一个硬件的路由器。
非本机主机通信,要把网络报文交给下一跳主机。TCP/IP通信有个前提,跨网络通信,报文必须要经过路由设备路由来完成把报文从一个网络转交给另外一个网络。这个网关可能也有连接到N个下一跳的网关,当报文抵达此网关时候,要把下一跳交给哪一个网关,是经由路由决策的。网关设备会有对应的路由条目。当报文抵达网关的时候,网关会先判断报文是不是就是请求我们本地网络的。如果对方访问报文的目标地址根本不是本地而是远程主机。根据报文的目标地址,去路由条目中选一个合适的路由条目来决定下一跳网关是谁,先找路由条目中的主机路由,如果没有主机路由,再找网络路由,网络路由网络匹配最小的优先被选择。这些都是基本的判断,其实路由决策过程远不止如此。
如果上面决策都没有符合的,会把网络报文交给默认网关。对于本地通信和跨网络通信还涉及一个子网掩码,会把请求报文的目标ip和所在网络的子网掩码做与运行,然后把本地网络的子网掩码与请求报文的目标ip做一个与运行,对二者结果进行比较,如果相同就表示是本地通信,如果不同就是跨网络通信,跨网络通信就涉及到网关和路由了。
X主机(只有内网):
[root@localhost ~]# ifconfig
eno16777736: flags=4163 mtu 1500
inet 192.168.10.4 netmask 255.255.255.0 broadcast 192.168.10.255
inet6 fe80::20c:29ff:fe64:344 prefixlen 64 scopeid 0x20
ether 00:0c:29:64:03:44 txqueuelen 1000 (Ethernet)
RX packets 487 bytes 44189 (43.1 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 278 bytes 33283 (32.5 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73 mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10
loop txqueuelen 0 (Local Loopback)
RX packets 152 bytes 11680 (11.4 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 152 bytes 11680 (11.4 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
#纯内网主机,其默认的网关指向的是C主机的内网网卡接口
[root@localhost ~]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.10.254 0.0.0.0 UG 100 0 0 eno16777736
192.168.10.0 0.0.0.0 255.255.255.0 U 100 0 0 eno16777736
C主机(内外网,路由主机):
#路由主机,eno16777736接口是外网接口,ens37接口是内网接口,也是内网主机的默认网关指向
[root@gateway ~]# ifconfig
eno16777736: flags=4163 mtu 1500
inet 172.16.0.10 netmask 255.255.0.0 broadcast 172.16.255.255
inet6 fe80::20c:29ff:fe85:868d prefixlen 64 scopeid 0x20
ether 00:0c:29:85:86:8d txqueuelen 1000 (Ethernet)
RX packets 693 bytes 64962 (63.4 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 618 bytes 81256 (79.3 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens37: flags=4163 mtu 1500
inet 192.168.10.254 netmask 255.255.255.0 broadcast 192.168.10.255
inet6 fe80::20c:29ff:fe85:8697 prefixlen 64 scopeid 0x20
ether 00:0c:29:85:86:97 txqueuelen 1000 (Ethernet)
RX packets 258 bytes 32050 (31.2 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 458 bytes 40547 (39.5 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73 mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10
loop txqueuelen 0 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Y主机(有外网环境):
#Y主机是和C主机外网在一个网络中的主机,正常情况,应该是Y主机属于额外一个网络。C主机到Y主机可以经过层层路由抵达,
#反之亦然,这里为了方便所以就直接把Y主机配置的和C主机外网互通(如果不这样做,要额外添加路由条目,使得C所在网络能
#抵达Y所在网络)。
[root@localhost ~]# ifconfig
eno16777736: flags=4163 mtu 1500
inet 172.16.0.120 netmask 255.255.0.0 broadcast 172.16.255.255
inet6 fe80::20c:29ff:fe4d:d522 prefixlen 64 scopeid 0x20
ether 00:0c:29:4d:d5:22 txqueuelen 1000 (Ethernet)
RX packets 102 bytes 10334 (10.0 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 112 bytes 11529 (11.2 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73 mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10
loop txqueuelen 0 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
实验步骤:
(1) 先清空三台主机的防火墙,做简单的icmp协议测试(如果默认的firewalld服务有启动,先关掉它)
iptables -F可以清空filter表的三条链INPUT,FORWARD以及OUTPUT上的策略。
systemctl stop firewalld.service #关掉firewalld服务
路由主机ping一下外网主机和内网主机:
默认的核心转发功能没有开启的。
[root@gateway ~]# cat /proc/sys/net/ipv4/ip_forward
0
[root@gateway ~]# ifconfig
eno16777736: flags=4163 mtu 1500
inet 172.16.0.10 netmask 255.255.0.0 broadcast 172.16.255.255
inet6 fe80::20c:29ff:fe85:868d prefixlen 64 scopeid 0x20
ether 00:0c:29:85:86:8d txqueuelen 1000 (Ethernet)
RX packets 1092 bytes 101367 (98.9 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 960 bytes 125270 (122.3 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens37: flags=4163 mtu 1500
inet 192.168.10.254 netmask 255.255.255.0 broadcast 192.168.10.255
inet6 fe80::20c:29ff:fe85:8697 prefixlen 64 scopeid 0x20
ether 00:0c:29:85:86:97 txqueuelen 1000 (Ethernet)
RX packets 408 bytes 53843 (52.5 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 734 bytes 63455 (61.9 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73 mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10
loop txqueuelen 0 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
#ping测试OK
[root@gateway ~]# ping 172.16.0.120
PING 172.16.0.120 (172.16.0.120) 56(84) bytes of data.
64 bytes from 172.16.0.120: icmp_seq=1 ttl=64 time=1.28 ms
^C
--- 172.16.0.120 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.285/1.285/1.285/0.000 ms
[root@gateway ~]# ping 192.168.10.4
PING 192.168.10.4 (192.168.10.4) 56(84) bytes of data.
64 bytes from 192.168.10.4: icmp_seq=1 ttl=64 time=64.9 ms
^C
--- 192.168.10.4 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 64.978/64.978/64.978/0.000 ms
内网主机ping一下路由主机的内网和外网接口ip以及另外一台有外网的主机:
[root@localhost ~]# ping 192.168.10.254
PING 192.168.10.254 (192.168.10.254) 56(84) bytes of data.
64 bytes from 192.168.10.254: icmp_seq=1 ttl=64 time=0.394 ms
64 bytes from 192.168.10.254: icmp_seq=2 ttl=64 time=0.449 ms
^C
--- 192.168.10.254 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.394/0.421/0.449/0.034 ms
#这里ping路由主机的外网网卡也通了,并不是实现了转发。因为内网主机的网关指向的是192.168.10.254,而172.16.0.10只是这个网关
#所在主机的另外一块不同的网卡而已,在内网中,当报文请求网关的其他接口的时候,也会正常返回请求的报文。
[root@localhost ~]# ping 172.16.0.10
PING 172.16.0.10 (172.16.0.10) 56(84) bytes of data.
64 bytes from 172.16.0.10: icmp_seq=1 ttl=64 time=0.349 ms
^C
--- 172.16.0.10 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.349/0.349/0.349/0.000 ms
#ping另外一台是ping不同的,默认情况
[root@localhost ~]# ping 172.16.0.120
PING 172.16.0.120 (172.16.0.120) 56(84) bytes of data.
^C
--- 172.16.0.120 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2000ms
外网主机ping一下路由主机的内外网以及只有内网环境的主机:
[root@localhost ~]# ping 172.16.0.10
PING 172.16.0.10 (172.16.0.10) 56(84) bytes of data.
64 bytes from 172.16.0.10: icmp_seq=1 ttl=64 time=0.362 ms
^C
--- 172.16.0.10 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.362/0.362/0.362/0.000 ms
#ping路由的内网接口不同。
[root@localhost ~]# ping 192.168.10.254
PING 192.168.10.254 (192.168.10.254) 56(84) bytes of data.
^C
--- 192.168.10.254 ping statistics ---
5 packets transmitted, 0 received, 100% packet loss, time 4000ms
#ping另外一台只有内网的主机不通
[root@localhost ~]# ping 192.168.10.4
PING 192.168.10.4 (192.168.10.4) 56(84) bytes of data.
^C
--- 192.168.10.4 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 999ms
(2) 现在要实现192.168.10.4主机能ping通172.16.0.120,抓包分析
在主机192.168.10.4上启动ping 172.16.0.120:
[root@localhost ~]# ping 172.16.0.120
PING 172.16.0.120 (172.16.0.120) 56(84) bytes of data.
......#这里默认是ping不通的
双网卡主机抓包,抓内网接口的icmp协议的包:
[root@gateway ~]# tcpdump -i ens37 -nn icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens37, link-type EN10MB (Ethernet), capture size 262144 bytes
00:39:43.257467 IP 192.168.10.4 > 172.16.0.120: ICMP echo request, id 4431, seq 88, length 64
00:39:44.257556 IP 192.168.10.4 > 172.16.0.120: ICMP echo request, id 4431, seq 89, length 64
00:39:45.257587 IP 192.168.10.4 > 172.16.0.120: ICMP echo request, id 4431, seq 90, length 64
00:39:46.257644 IP 192.168.10.4 > 172.16.0.120: ICMP echo request, id 4431, seq 91, length 64
00:39:47.257679 IP 192.168.10.4 > 172.16.0.120: ICMP echo request, id 4431, seq 92, length 64
^C
5 packets captured
5 packets received by filter
0 packets dropped by kernel
#这里被我中断了,这台主机会收到192.168.10.4到172.16.0.120的ping请求的报文。为啥不同还要看外网接口的回包情况。
双网卡主机抓包,抓外网接口的icmp协议的包:
[root@gateway ~]# tcpdump -i eno16777736 -nn icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eno16777736, link-type EN10MB (Ethernet), capture size 262144 bytes
#默认情况这里没有报文,因为核心转发没有启用的缘故,所以当主机接收到从192.168.10.4到172.16.0.120的报文的时候,不会处理。
#因为已经跨网络通信了。
开启核心转发:
[root@gateway ~]# echo 1 > /proc/sys/net/ipv4/ip_forward
[root@gateway ~]# cat /proc/sys/net/ipv4/ip_forward
1
开启核心转发后抓包效果:
[root@gateway ~]# tcpdump -i ens37 -nn icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens37, link-type EN10MB (Ethernet), capture size 262144 bytes
00:43:19.331513 IP 192.168.10.4 > 172.16.0.120: ICMP echo request, id 4431, seq 304, length 64
00:43:20.331656 IP 192.168.10.4 > 172.16.0.120: ICMP echo request, id 4431, seq 305, length 64
00:43:21.331724 IP 192.168.10.4 > 172.16.0.120: ICMP echo request, id 4431, seq 306, length 64
00:43:22.331749 IP 192.168.10.4 > 172.16.0.120: ICMP echo request, id 4431, seq 307, length 64
00:43:23.331812 IP 192.168.10.4 > 172.16.0.120: ICMP echo request, id 4431, seq 308, length 64
00:43:24.331752 IP 192.168.10.4 > 172.16.0.120: ICMP echo request, id 4431, seq 309, length 64
[root@gateway ~]# tcpdump -i eno16777736 -nn icmp #外网接口有抓到报文情况了。
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eno16777736, link-type EN10MB (Ethernet), capture size 262144 bytes
00:43:24.331811 IP 192.168.10.4 > 172.16.0.120: ICMP echo request, id 4431, seq 309, length 64
00:43:24.333248 IP 172.16.0.120 > 192.168.10.4: ICMP echo reply, id 4431, seq 309, length 64
00:43:25.332019 IP 192.168.10.4 > 172.16.0.120: ICMP echo request, id 4431, seq 310, length 64
00:43:25.334025 IP 172.16.0.120 > 192.168.10.4: ICMP echo reply, id 4431, seq 310, length 64
00:43:26.332994 IP 192.168.10.4 > 172.16.0.120: ICMP echo request, id 4431, seq 311, length 64
00:43:26.335054 IP 172.16.0.120 > 192.168.10.4: ICMP echo reply, id 4431, seq 311, length 64
00:43:27.333038 IP 192.168.10.4 > 172.16.0.120: ICMP echo request, id 4431, seq 312, length 64
抓包一下172.16.0.120外网主机外网接口的icmp协议报文情况:
[root@localhost ~]# tcpdump -i eno16777736 -nn icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eno16777736, link-type EN10MB (Ethernet), capture size 262144 bytes
00:46:00.351971 IP 192.168.10.4 > 172.16.0.120: ICMP echo request, id 4431, seq 465, length 64
00:46:00.352026 IP 172.16.0.120 > 192.168.10.4: ICMP echo reply, id 4431, seq 465, length 64
00:46:01.351916 IP 192.168.10.4 > 172.16.0.120: ICMP echo request, id 4431, seq 466, length 64
00:46:01.351963 IP 172.16.0.120 > 192.168.10.4: ICMP echo reply, id 4431, seq 466, length 64
00:46:02.352061 IP 192.168.10.4 > 172.16.0.120: ICMP echo request, id 4431, seq 467, length 64
00:46:02.352116 IP 172.16.0.120 > 192.168.10.4: ICMP echo reply, id 4431, seq 467, length 64
#看一下172.16.0.120的默认网关
[root@localhost ~]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 172.16.0.2 0.0.0.0 UG 100 0 0 eno16777736
172.16.0.0 0.0.0.0 255.255.0.0 U 100 0 0 eno16777736
#由于默认的网关指向的是172.16.0.2,当收到192.168.10.4的报文,从路由主机转过来之后,主机172.16.0.120有回包,不过默认是把
报文回给默认的网关了,现在如果要想192.168.10.4主机能正常收到请求,要先让172.16.0.120的默认回包会给172.16.0.10接口。
在外网主机上加一条网络路由,让到达192.168.10.0/24网络的报文的下一跳指向172.16.0.10,即路由主机的外网接口
命令:route add -net 192.168.10.0/24 gw 172.16.0.10
执行:
[root@localhost ~]# route add -net 192.168.10.0/24 gw 172.16.0.10
[root@localhost ~]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 172.16.0.2 0.0.0.0 UG 100 0 0 eno16777736
172.16.0.0 0.0.0.0 255.255.0.0 U 100 0 0 eno16777736
192.168.10.0 172.16.0.10 255.255.255.0 UG 0 0 0 eno16777736
然后再去看内网主机对172.16.0.120的ping请求就通了:
[root@localhost ~]# ifconfig
eno16777736: flags=4163 mtu 1500
inet 192.168.10.4 netmask 255.255.255.0 broadcast 192.168.10.255
inet6 fe80::20c:29ff:fe64:344 prefixlen 64 scopeid 0x20
ether 00:0c:29:64:03:44 txqueuelen 1000 (Ethernet)
RX packets 1581 bytes 135576 (132.3 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1385 bytes 160595 (156.8 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73 mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10
loop txqueuelen 0 (Local Loopback)
RX packets 300 bytes 23012 (22.4 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 300 bytes 23012 (22.4 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@localhost ~]# ping 172.16.0.120
PING 172.16.0.120 (172.16.0.120) 56(84) bytes of data.
64 bytes from 172.16.0.120: icmp_seq=1 ttl=63 time=3.96 ms
64 bytes from 172.16.0.120: icmp_seq=2 ttl=63 time=0.904 ms
^C
--- 172.16.0.120 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.904/2.434/3.965/1.531 ms
此时路由主机外网网卡抓包即有请求报文,也有响应报文:
[root@gateway ~]# tcpdump -i eno16777736 -nn icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eno16777736, link-type EN10MB (Ethernet), capture size 262144 bytes
00:59:13.562763 IP 192.168.10.4 > 172.16.0.120: ICMP echo request, id 4813, seq 1, length 64
00:59:13.563408 IP 172.16.0.120 > 192.168.10.4: ICMP echo reply, id 4813, seq 1, length 64
00:59:14.565239 IP 192.168.10.4 > 172.16.0.120: ICMP echo request, id 4813, seq 2, length 64
00:59:14.565611 IP 172.16.0.120 > 192.168.10.4: ICMP echo reply, id 4813, seq 2, length 64
00:59:15.566337 IP 192.168.10.4 > 172.16.0.120: ICMP echo request, id 4813, seq 3, length 64
00:59:15.566784 IP 172.16.0.120 > 192.168.10.4: ICMP echo reply, id 4813, seq 3, length 64
00:59:16.568321 IP 192.168.10.4 > 172.16.0.120: ICMP echo request, id 4813, seq 4, length 64
00:59:16.568691 IP 172.16.0.120 > 192.168.10.4: ICMP echo reply, id 4813, seq 4, length 64
00:59:17.570339 IP 192.168.10.4 > 172.16.0.120: ICMP echo request, id 4813, seq 5, length 64
00:59:17.570730 IP 172.16.0.120 > 192.168.10.4: ICMP echo reply, id 4813, seq 5, length 64
00:59:18.572441 IP 192.168.10.4 > 172.16.0.120: ICMP echo request, id 4813, seq 6, length 64
00:59:18.572907 IP 172.16.0.120 > 192.168.10.4: ICMP echo reply, id 4813, seq 6, length 64
^C
引用百科:
https://baike.baidu.com/item/nat/320024?fr=aladdin
NAT(Network Address Translation,网络地址转换)是1994年提出的。当在专用网内部的一些主机本来已经分配到了本地IP地址(即仅在本专用网内使用的专用地址),但现在又想和因特网上的主机通信(并不需要加密)时,可使用NAT方法。
这种方法需要在专用网连接到因特网的路由器上安装NAT软件。装有NAT软件的路由器叫做NAT路由器,它至少有一个有效的外部全球IP地址。这样,所有使用本地地址的主机在和外界通信时,都要在NAT路由器上将其本地地址转换成全球IP地址,才能和因特网连接。
另外,这种通过使用少量的公有IP 地址代表较多的私有IP 地址的方式,将有助于减缓可用的IP地址空间的枯竭。在RFC 2663中有对NAT的说明。
NAT的主要功能早期是用来隐藏主机的。任何内网主机之间进行通信,纯网关设备仅仅是将报文实现跨网络间转发的,纯网关设备不会修改报文的源ip和目标ip。当本地客户端请求互联网的时候,如果地址没有实现转换,就会
暴露客户的ip信息,下次你上网的时候,别人会利用你这个暴露的信息善加利用后,攻击你内部的主机。这样
本不是我们的本意,我们的本意就是为了访问互联网,而且大部分的终端用户都没有安全意思,他们使用的
用于请求互联网的终端设备大部分都没有做安全或者开启防火墙,所以为了上网而不得不把自己处于这样一个
尴尬的处境是我们本不想遇见的。
现在我们的NAT就可以实现这样的功能。都知道,如果本地客户端跨网络访问互联网,都要经过一个叫做网关的
设备,如果对于经过网关的设备,我们把都请求报文的源地址给它修改成网关设备的外网接口的地址,这样就可
做到隐藏客户端主机信息的目的。而网关设备,我们可以做到安全加强。
我们今天这里介绍的主要是两个,一个是SNAT,一个是DNAT,分别是源网络地址转换以及目标网络地址转换。
在了解NAT前,我们先来看看路由的简单图解:
因为本人网络知识水平有限,也只能理解到这种程度,后续如果学术提升,会过来补充不足。
This target is only valid in the nat table, in the POSTROUTING and INPUT chains, and user-defined chains which are only called from those chains. It specifies that the source address of the packet should be modified (and all future packets in this connection will also be mangled), and rules should cease being examined. It takes the following options:
SNAT这个target只有在nat表中使用才有效。在nat 的POSTROUTING以及INPUT链(当然包括从这两个链上调用的其他用户的自定义链。这个target指定应该去修改报文的源地址。(因为修改源地址的关系,这个链接中将来所有的报文都将被破坏),并且应该停止规则的检查。
以下是它选项以及含义:
--to-source [ipaddr[-ipaddr]][:port[-port]]
which can specify a single new source IP address, an inclusive range of IP addresses. Optionally a port range, if the rule also
specifies one of the following protocols: tcp, udp, dccp or sctp. If no port range is specified, then source ports below 512 will be
mapped to other ports below 512: those between 512 and 1023 inclusive will be mapped to ports below 1024, and other ports will
be mapped to 1024 or above. Where possible, no port alteration will occur. In Kernels up to 2.6.10, you can add several --to-source
options. For those kernels, if you specify more than one source address, either via an address range or multiple --to-source
options, a simple round-robin (one after another in cycle) takes place between these addresses. Later Kernels (>= 2.6.11-rc1)
don't have the ability to NAT to multiple ranges anymore.
指定单个新的源IP地址,也可以是一个地址范围。如果规则也指定了一下协议:tcp,udp,dccp或者sctp,可以使用端口范围。
如果没有指定端口范围,端口有3个边界值。对于源端口是512以下的会被映射成512以下的其他端口;对于在512到1023并包括1023
边界的这个范围内的端口,讲会被映射成1024以下的端口;对于其他端口,讲会被映射成1024以及1024以上的端口。
如果可能的话,不会有端口被转换。
对于linux的2.6.10内核以前,可以使用--to-source选项指定不止一个源地址。可以指定一个地址范围或者使用多次--to-source多次来
指定多个源地址。如果有多个源地址(不管是什么形式给出的),默认情况,每匹配一个报文,做源地址转换,要被转换成的源地址的
值按照依次轮循的方式从这个指定的多个源地址中去取得。
在2.6.11-rc1版本的内核之后,再也没有能力处理多个地址范围的能力(这里这句话我不太懂,我手册查看的是CentOS 7版本的
iptables,CentOS 7上内核版本是3.10,是大于2.6.11的。我理解这里的意思应该是之前内核版本可以使用多次--to-source选项,比如
--to-source=172.16.0.10 --to-source=172.16.0.11或--to-source=172.16.0.0/24。而2.6.11-rc1内核版本之后,不支持多个--to-source选
项,只能使用--to-source=netaddress/prefix这种形式来表示多个地址)。
--random
If option --random is used then port mapping will be randomized (kernel >= 2.6.21).
如果--random选项被使用,端口映射将会随机。(应用于2.6.21以及之后的内核版本)。
额外说明:
上文中有提到,做源地址转换,可以指定单个要转换成的源地址,也可以指定一个地址范围,一个地址范围就对应有多个地址。
对于多个地址,默认策略是轮循。每当一个报文被匹配后,去这个多个可选的源地址中取一个地址作为要被报文要被转换的源
地址,然后下一个报文过来并且符合匹配条件,然后会依次轮循去取指定的可选的其他源地址。如果配合--random选项后,会
随机从指定的可选的多个源地址中选择一个。
--persistent
Gives a client the same source-/destination-address for each connection. This supersedes the SAME target. Support for
persistent mappings is available from 2.6.29-rc2.Kernels prior to 2.6.36-rc1 don't have the ability to SNAT in the INPUT chain.
IPv6 support available since Linux kernels >= 3.7.
对于每一个来自于同一个客户端的连接,指定要转换的源地址或目标地址是固定的。它的作用会覆盖--random的效果。
实验说明。这里使用192.168.10.4来模拟内网环境。然后双网卡主机(192.168.10.254模拟路由的内网接口,
172.16.0.10模拟路由的外网接口)模拟路由设备,使用172.16.0.120来模拟互联网上的外网主机。
现在要求,从内网主机上网(这里就模拟请求172.16.0.120,icmp协议和http协议访问)。然后再172.16.0.120上抓
包看到对应请求报文的源地址应该是172.16.0.10.这样能简单模拟SNAT应用。
192.168.10.4主机的网关指向的是192.168.10.254接口。由于172.16.0.10和172.16.0.120都指向网关172.16.0.2.
而且它们是同一个网段,可以理解为从172.16.0.120向172.16.0.10的响应报文不会跨网络,也就是说不会涉及
172.16.0.2这个网关设备。现实生活中,web主机和路由主机外网几乎不可能在一个网段。
(1) 确认网关服务器的核心转发有开启
[root@gateway ~]# cat /proc/sys/net/ipv4/ip_forward
1
(2) 清空nat表的规则,还有过滤表的一并清空了,方便后边测试使用
[root@gateway ~]# iptables -F
[root@gateway ~]# iptables -t nat -F
[root@gateway ~]# iptables -nvL
Chain INPUT (policy ACCEPT 53 packets, 4521 bytes)
pkts bytes target prot opt in out source destination
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 44 packets, 3998 bytes)
pkts bytes target prot opt in out source destination
[root@gateway ~]# iptables -t nat -nvL
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
(3) 网关主机上添加防火墙规则
#这里做SNAT一定要在路由后做才比较合适。如果报文刚刚抵达主机,直接在路由前做了,如果请求报文刚好
访问的是本机,那么修改源地址后,这样会绕一大圈。所以是路由后,选定了要从哪个接口出去,然后再做源地址
修改比较合适。所以要在nat表的POSTROUTING链上做,上面有提到的nat表的的INPUT链也行,不过用的比较少。
通过INPUT链,也是路由后的报文了。
#这里在中转服务器的nat表的POSTROUTING链上添加了一条规则。凡是源地址是192.16.10.0/24这个网络的,请求目标主机
是任意主机,以及请求报文协议是任意协议的报文,统一做SNAT,然后修改请求报文后的源地址为172.16.0.10(网关主机的外网
接口地址)。这里因为网关接口只有一个外网地址,所以这里不涉及--to-source的参数为多个源地址。所以另外两个选项--random和
--persistent没有作用。
[root@gateway ~]# iptables -t nat -A POSTROUTING -s 192.168.10.0/24 -j SNAT --to-source=172.16.0.10
[root@gateway ~]# iptables -t nat -nvL
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 SNAT all -- * * 192.168.10.0/24 0.0.0.0/0 to:172.16.0.10
(4) 在内网主机192.168.10.4主机请求172.16.0.120提供的web服务
[root@localhost ~]# curl http://172.16.0.120
172.16.0.120 server
(5) 在172.16.0.120主机上抓取tcp协议的80的报文的数据包
[root@localhost ~]# tcpdump -i eno16777736 -nn tcp port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eno16777736, link-type EN10MB (Ethernet), capture size 262144 bytes
15:31:12.451262 IP 172.16.0.10.58940 > 172.16.0.120.80: Flags [S], seq 1675037329, win 14600, options [mss 1460,sackOK,TS val 143300578 ecr 0,nop,wscale 6], length 0
15:31:12.451335 IP 172.16.0.120.80 > 172.16.0.10.58940: Flags [S.], seq 165137782, ack 1675037330, win 14480, options [mss 1460,sackOK,TS val 143312619 ecr 143300578,nop,wscale 6], length 0
15:31:12.457888 IP 172.16.0.10.58940 > 172.16.0.120.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 143300583 ecr 143312619], length 0
15:31:12.458061 IP 172.16.0.10.58940 > 172.16.0.120.80: Flags [P.], seq 1:77, ack 1, win 229, options [nop,nop,TS val 143300584 ecr 143312619], length 76: HTTP: GET / HTTP/1.1
15:31:12.458098 IP 172.16.0.120.80 > 172.16.0.10.58940: Flags [.], ack 77, win 227, options [nop,nop,TS val 143312625 ecr 143300584], length 0
15:31:12.458825 IP 172.16.0.120.80 > 172.16.0.10.58940: Flags [P.], seq 1:271, ack 77, win 227, options [nop,nop,TS val 143312627 ecr 143300584], length 270: HTTP: HTTP/1.1 200 OK
15:31:12.462762 IP 172.16.0.10.58940 > 172.16.0.120.80: Flags [.], ack 271, win 245, options [nop,nop,TS val 143300589 ecr 143312627], length 0
15:31:12.462801 IP 172.16.0.10.58940 > 172.16.0.120.80: Flags [F.], seq 77, ack 271, win 245, options [nop,nop,TS val 143300590 ecr 143312627], length 0
15:31:12.462960 IP 172.16.0.120.80 > 172.16.0.10.58940: Flags [F.], seq 271, ack 78, win 227, options [nop,nop,TS val 143312631 ecr 143300590], length 0
15:31:12.465995 IP 172.16.0.10.58940 > 172.16.0.120.80: Flags [.], ack 272, win 245, options [nop,nop,TS val 143300592 ecr 143312631], length 0
注解寿命:
请求报文源地址是172.16.0.10,源端口是58940,目标地址是172.16.0.120,目标端口是80.在外网主机看来,请求报文的源地址已经
是中转服务器的外网地址,源地址已经做了转换。
响应报文源地址是172.16.0.120,源端口是80,目标地址是172.16.0.10,目标端口是58940.这里是我刚好让中转服务器的外网接口和
外网设备172.16.0.120在同一个网段,实际生活中。内部主机请求的外网与官关设备外网接口地址不在一个网络内。那么这个外网设
就要经过层层路由或者路由中继包请求报文转交给对应172.16.0.120所在网络内的路由。(这就是我们上问引入路由概念的时候的说
到过的。)
(6) 在192.168.10.4主机上抓取tcp协议的80的报文的数据包
[root@localhost ~]# tcpdump -i eno16777736 -nn tcp port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eno16777736, link-type EN10MB (Ethernet), capture size 65535 bytes
23:31:21.538381 IP 192.168.10.4.58940 > 172.16.0.120.80: Flags [S], seq 1675037329, win 14600, options [mss 1460,sackOK,TS val 143300578 ecr 0,nop,wscale 6], length 0
23:31:21.542391 IP 172.16.0.120.80 > 192.168.10.4.58940: Flags [S.], seq 165137782, ack 1675037330, win 14480, options [mss 1460,sackOK,TS val 143312619 ecr 143300578,nop,wscale 6], length 0
23:31:21.542740 IP 192.168.10.4.58940 > 172.16.0.120.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 143300583 ecr 143312619], length 0
23:31:21.544243 IP 192.168.10.4.58940 > 172.16.0.120.80: Flags [P.], seq 1:77, ack 1, win 229, options [nop,nop,TS val 143300584 ecr 143312619], length 76
23:31:21.548095 IP 172.16.0.120.80 > 192.168.10.4.58940: Flags [.], ack 77, win 227, options [nop,nop,TS val 143312625 ecr 143300584], length 0
23:31:21.549260 IP 172.16.0.120.80 > 192.168.10.4.58940: Flags [P.], seq 1:271, ack 77, win 227, options [nop,nop,TS val 143312627 ecr 143300584], length 270
23:31:21.549299 IP 192.168.10.4.58940 > 172.16.0.120.80: Flags [.], ack 271, win 245, options [nop,nop,TS val 143300589 ecr 143312627], length 0
23:31:21.550056 IP 192.168.10.4.58940 > 172.16.0.120.80: Flags [F.], seq 77, ack 271, win 245, options [nop,nop,TS val 143300590 ecr 143312627], length 0
23:31:21.552296 IP 172.16.0.120.80 > 192.168.10.4.58940: Flags [F.], seq 271, ack 78, win 227, options [nop,nop,TS val 143312631 ecr 143300590], length 0
23:31:21.552357 IP 192.168.10.4.58940 > 172.16.0.120.80: Flags [.], ack 272, win 245, options [nop,nop,TS val 143300592 ecr 143312631], length 0
注解说明:
请求报文源地址是192.168.10.4,源端口是随机端口58940,目标地址是172.16.0.120,目标端口是80;
响应报文源地址是172.168.10.4,,源端口是80,目标地址是192.168.10.4,目标端口是58940.
因为这台主机是内网主机,发起请求的时候,上面的源ip,源端口,目标ip,目标端口都是正常的。
(7) 在中转服务器的内外网接口上抓取tcp协议的80的报文的数据包
内网接口:
[root@gateway ~]# tcpdump -i ens37 -nn tcp port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens37, link-type EN10MB (Ethernet), capture size 262144 bytes
15:31:12.446798 IP 192.168.10.4.58940 > 172.16.0.120.80: Flags [S], seq 1675037329, win 14600, options [mss 1460,sackOK,TS val 143300578 ecr 0,nop,wscale 6], length 0
15:31:12.449705 IP 172.16.0.120.80 > 192.168.10.4.58940: Flags [S.], seq 165137782, ack 1675037330, win 14480, options [mss 1460,sackOK,TS val 143312619 ecr 143300578,nop,wscale 6], length 0
15:31:12.452460 IP 192.168.10.4.58940 > 172.16.0.120.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 143300583 ecr 143312619], length 0
15:31:12.452658 IP 192.168.10.4.58940 > 172.16.0.120.80: Flags [P.], seq 1:77, ack 1, win 229, options [nop,nop,TS val 143300584 ecr 143312619], length 76: HTTP: GET / HTTP/1.1
15:31:12.455071 IP 172.16.0.120.80 > 192.168.10.4.58940: Flags [.], ack 77, win 227, options [nop,nop,TS val 143312625 ecr 143300584], length 0
15:31:12.456843 IP 172.16.0.120.80 > 192.168.10.4.58940: Flags [P.], seq 1:271, ack 77, win 227, options [nop,nop,TS val 143312627 ecr 143300584], length 270: HTTP: HTTP/1.1 200 OK
15:31:12.458805 IP 192.168.10.4.58940 > 172.16.0.120.80: Flags [.], ack 271, win 245, options [nop,nop,TS val 143300589 ecr 143312627], length 0
15:31:12.458948 IP 192.168.10.4.58940 > 172.16.0.120.80: Flags [F.], seq 77, ack 271, win 245, options [nop,nop,TS val 143300590 ecr 143312627], length 0
15:31:12.459942 IP 172.16.0.120.80 > 192.168.10.4.58940: Flags [F.], seq 271, ack 78, win 227, options [nop,nop,TS val 143312631 ecr 143300590], length 0
15:31:12.461385 IP 192.168.10.4.58940 > 172.16.0.120.80: Flags [.], ack 272, win 245, options [nop,nop,TS val 143300592 ecr 143312631], length 0
内网接口抓包,请求报文的源地址没有转换,也就是说内核中抵达192.168.10.254网络接口后,报文还未提交给172.16.0.10网卡
接口的报文发送队列中。(应该在中转或叫路由服务器上的外网网卡抓包的结果,请求报文的源地址已经转换过了)。
外网接口:
[root@gateway ~]# tcpdump -i eno16777736 -nn tcp port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eno16777736, link-type EN10MB (Ethernet), capture size 262144 bytes
15:31:12.446889 IP 172.16.0.10.58940 > 172.16.0.120.80: Flags [S], seq 1675037329, win 14600, options [mss 1460,sackOK,TS val 143300578 ecr 0,nop,wscale 6], length 0
15:31:12.449623 IP 172.16.0.120.80 > 172.16.0.10.58940: Flags [S.], seq 165137782, ack 1675037330, win 14480, options [mss 1460,sackOK,TS val 143312619 ecr 143300578,nop,wscale 6], length 0
15:31:12.452555 IP 172.16.0.10.58940 > 172.16.0.120.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 143300583 ecr 143312619], length 0
15:31:12.452674 IP 172.16.0.10.58940 > 172.16.0.120.80: Flags [P.], seq 1:77, ack 1, win 229, options [nop,nop,TS val 143300584 ecr 143312619], length 76: HTTP: GET / HTTP/1.1
15:31:12.455017 IP 172.16.0.120.80 > 172.16.0.10.58940: Flags [.], ack 77, win 227, options [nop,nop,TS val 143312625 ecr 143300584], length 0
15:31:12.456821 IP 172.16.0.120.80 > 172.16.0.10.58940: Flags [P.], seq 1:271, ack 77, win 227, options [nop,nop,TS val 143312627 ecr 143300584], length 270: HTTP: HTTP/1.1 200 OK
15:31:12.458851 IP 172.16.0.10.58940 > 172.16.0.120.80: Flags [.], ack 271, win 245, options [nop,nop,TS val 143300589 ecr 143312627], length 0
15:31:12.458979 IP 172.16.0.10.58940 > 172.16.0.120.80: Flags [F.], seq 77, ack 271, win 245, options [nop,nop,TS val 143300590 ecr 143312627], length 0
15:31:12.459918 IP 172.16.0.120.80 > 172.16.0.10.58940: Flags [F.], seq 271, ack 78, win 227, options [nop,nop,TS val 143312631 ecr 143300590], length 0
15:31:12.461398 IP 172.16.0.10.58940 > 172.16.0.120.80: Flags [.], ack 272, win 245, options [nop,nop,TS val 143300592 ecr 143312631], length 0
#外网接口,请求报文的源地址也已经转换过了。
上面测试的是tcp协议的报文,对于icmp协议的报文应该也有做源地址转换。因为向中转服务器的nat表的POSTROUTING链上添加规则的时候,并没有指明协议,默认通配的协议是all表示匹配所有的协议。
(1) 192.168.10.4主机上请求172.16.0.120的icmp结果
[root@localhost ~]# ping 172.16.0.120
PING 172.16.0.120 (172.16.0.120) 56(84) bytes of data.
64 bytes from 172.16.0.120: icmp_seq=1 ttl=63 time=7.29 ms
^C
--- 172.16.0.120 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 7.293/7.293/7.293/0.000 ms
(2) 192.168.10.4主机上抓取icmp协议的报文
[root@localhost ~]# tcpdump -i eno16777736 -nn icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eno16777736, link-type EN10MB (Ethernet), capture size 65535 bytes
23:49:46.819267 IP 192.168.10.4 > 172.16.0.120: ICMP echo request, id 12239, seq 1, length 64
23:49:46.826512 IP 172.16.0.120 > 192.168.10.4: ICMP echo reply, id 12239, seq 1, length 64
(3) 172.16.0.120主机上抓取icmp协议的报文
[root@localhost ~]# tcpdump -i eno16777736 -nn icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eno16777736, link-type EN10MB (Ethernet), capture size 262144 bytes
15:49:37.764089 IP 172.16.0.10 > 172.16.0.120: ICMP echo request, id 12239, seq 1, length 64
15:49:37.764144 IP 172.16.0.120 > 172.16.0.10: ICMP echo reply, id 12239, seq 1, length 64
(4) 路由主机的内网和外网接口抓取icmp协议的报文
内网:
[root@gateway ~]# tcpdump -i ens37 -nn icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens37, link-type EN10MB (Ethernet), capture size 262144 bytes
15:49:37.762027 IP 192.168.10.4 > 172.16.0.120: ICMP echo request, id 12239, seq 1, length 64
15:49:37.768037 IP 172.16.0.120 > 192.168.10.4: ICMP echo reply, id 12239, seq 1, length 64
外网:
[root@gateway ~]# tcpdump -i eno16777736 -nn icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eno16777736, link-type EN10MB (Ethernet), capture size 262144 bytes
15:49:37.762175 IP 172.16.0.10 > 172.16.0.120: ICMP echo request, id 12239, seq 1, length 64
15:49:37.767957 IP 172.16.0.120 > 172.16.0.10: ICMP echo reply, id 12239, seq 1, length 64
This target is only valid in the nat table, in the PREROUTING and OUTPUT chains, and user-defined chains which are only called from those chains. It specifies that the destination address of the packet should be modified (and all future packets in this connection will also be mangled), and rules should cease being examined. It takes the following options:
和SNAT适用的表和链一样。这里是主要是修改报文的目标地址。
想象一下,为啥DNAT要在PREROUTING链或OUTPUT链上。比如INPUT或POSTROUTING为啥不行?
DNAT主要引用是为了隐藏提供服务器的主机的信息。比如我内网有个主机,有启动一个web服务器。就以
192.168.10.4为例,上面启动一个httpd服务,监听在80端口。中转服务器是172.16.0.10(模拟外网网卡),它
的内网网卡是192.168.10.254。现在有个172.16.0.120(模拟的外网)的外网主机。假设172.16.0.120要想请求
192.168.10.4的web服务,我们之前说的报文转发可以实现。现在有个要求,172.16.0.120直接对外宣称,我
这里有个web服务,因为涉及到域名,域名要解析到这个外网上。现在172.16.0.120请求172.16.0.10的web
服务,假设默认的80端口。现在请求报文的源ip是172.16.0.120,源端口随机。请求报文的目标端口是
172.16.0.10,目标端口是80.实际172.16.0.10上面用户空间并没有进程向内核注册使用80这个端口,所以当
请求报文抵达172.16.0.10后,DNAT的作用就是把请求报文的目标ip和端口转给成内网的ip和对应实际提供服务
进程注册使用的端口,这里即为192.168.10.4和80.
假设在报文进入本机,还没有做路由,假设路由后再去做DNAT,这样请求报文的MAC封装已经被拆解,会看到
报文的目标地址就是本机(比如中转服务器的172.16.0.10),此报文就会直接流经INPUT进入本机,这样就并没有
实现把报文转发给192.16.10.4的主机。如果是路由前,报文还没有拆解MAC封装,修改了请求报文的目标IP和
端口。这样一当路由后,发现请求报文目标地址不是本机,会通过FORWARD链把请求报文路由给对应的其他路由或主机。
--to-destination [ipaddr[-ipaddr]][:port[-port]]
which can specify a single new destination IP address, an inclusive range of IP addresses. Optionally a port range, if the rule also specifies one of the following protocols: tcp, udp, dccp or sctp. If no port range is specified, then the destination port will never be modified. If no IP address is specified then only the destination port will be modified. In Kernels up to 2.6.10 you can add several --to-destination options. For those kernels, if you specify more than one destination address, either via an address range or multiple --to-destination options, a simple round-robin (one after another in cycle) load balancing takes place between these addresses. Later Kernels (>= 2.6.11-rc1) don't have the ability to NAT to multiple ranges anymore.
--random
If option --random is used then port mapping will be randomized (kernel >= 2.6.22).
--persistent
Gives a client the same source-/destination-address for each connection. This supersedes the SAME target. Support for persistent mappings is available from 2.6.29-rc2.IPv6 support available since Linux kernels >= 3.7.
说明:还是上面这套环境。现在内网192.168.10.4上有启动一个web服务。现在有一个路由服务器,有两块网卡,
假设模拟的内网网卡是192.168.10.254,也是内网192.168.10.4主机所在内网环境的默认网关。模拟的外网网卡
是172.16.0.10。现在把192.168.10.4主机上的web服务提供对外。比如要让172.16.0.120访问。
实现就是,让172.16.0.120去访问172.16.0.10,然后转给把请求报文的目标地址和端口转成192.168.10.4主机。
想象一种场景,假设内网一台主机上即有一个web服务,又有一个ftp服务,还有一个samba服务,现在要web服务
压力逐渐加大,要把ftp和samba服务从一台主机剥离出来。然后这个时候只有一台主机有外网网卡,怎么办。
DNAT可以实现。把请求报文来自于互联网的任意地址,请求172.16.0.10的某个端口A,目标地址转成192.168.10.4,目标端口是80(这个是web服务),请求172.16.0.10的某个端口B,目标地址转成192.168.10.5,
目标端口是21(这个主机是ftp服务)等等。
(1) 清空中转服务的所有iptables策略,包括filter表以及nat表
[root@gateway ~]# iptables -t filter -F
[root@gateway ~]# iptables -t nat -F
[root@gateway ~]# iptables -t nat -nvL
Chain PREROUTING (policy ACCEPT 4 packets, 808 bytes)
pkts bytes target prot opt in out source destination
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
[root@gateway ~]#
(2) 中转服务添加防火墙策略
#向中转服务器的nat表的PREROUTING链上添加规则,对于请求报文,请求目标地址为172.16.0.10,协议为tcp协议,请求端口是80
的报文,然后把它们的报文的目标地址和端口转换成192.168.10.4和80
[root@gateway ~]# iptables -t nat -A PREROUTING -d 172.16.0.10 -p tcp --dport 80 -j DNAT --to-destination 192.168.10.4:80
[root@gateway ~]# iptables -t nat -nvL
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 DNAT tcp -- * * 0.0.0.0/0 172.16.0.10 tcp dpt:80 to:192.168.10.4:80
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
(3) 在172.16.0.120外网主机请求172.16.0.10的80(假设中转服务器对外宣称了我这里可以提供web服务)
[root@localhost ~]# curl http://172.16.0.10
192.168.10.4
中转服务自己其实并没有监听80端口:
[root@gateway ~]# ifconfig
eno16777736: flags=4163 mtu 1500
inet 172.16.0.10 netmask 255.255.0.0 broadcast 172.16.255.255
inet6 fe80::20c:29ff:fe85:868d prefixlen 64 scopeid 0x20
ether 00:0c:29:85:86:8d txqueuelen 1000 (Ethernet)
RX packets 30571 bytes 3022570 (2.8 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 27684 bytes 3455777 (3.2 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens37: flags=4163 mtu 1500
inet 192.168.10.254 netmask 255.255.255.0 broadcast 192.168.10.255
inet6 fe80::20c:29ff:fe85:8697 prefixlen 64 scopeid 0x20
ether 00:0c:29:85:86:97 txqueuelen 1000 (Ethernet)
RX packets 5356 bytes 755293 (737.5 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 6526 bytes 554510 (541.5 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73 mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10
loop txqueuelen 0 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@gateway ~]# ss -tnl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 :::22 :::*
LISTEN 0 100 ::1:25 :::*
(4) 在172.16.0.120主机上抓包的结果
[root@localhost ~]# tcpdump -i eno16777736 -nn tcp port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eno16777736, link-type EN10MB (Ethernet), capture size 262144 bytes
16:25:37.224996 IP 172.16.0.120.32965 > 172.16.0.10.80: Flags [S], seq 2414794746, win 14600, options [mss 1460,sackOK,TS val 146577392 ecr 0,nop,wscale 6], length 0
16:25:37.229355 IP 172.16.0.10.80 > 172.16.0.120.32965: Flags [S.], seq 4199406913, ack 2414794747, win 14480, options [mss 1460,sackOK,TS val 146565400 ecr 146577392,nop,wscale 6], length 0
16:25:37.229444 IP 172.16.0.120.32965 > 172.16.0.10.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 146577397 ecr 146565400], length 0
16:25:37.230998 IP 172.16.0.120.32965 > 172.16.0.10.80: Flags [P.], seq 1:76, ack 1, win 229, options [nop,nop,TS val 146577399 ecr 146565400], length 75: HTTP: GET / HTTP/1.1
16:25:37.236641 IP 172.16.0.10.80 > 172.16.0.120.32965: Flags [.], ack 76, win 227, options [nop,nop,TS val 146565408 ecr 146577399], length 0
16:25:37.237801 IP 172.16.0.10.80 > 172.16.0.120.32965: Flags [P.], seq 1:264, ack 76, win 227, options [nop,nop,TS val 146565409 ecr 146577399], length 263: HTTP: HTTP/1.1 200 OK
16:25:37.237831 IP 172.16.0.120.32965 > 172.16.0.10.80: Flags [.], ack 264, win 245, options [nop,nop,TS val 146577406 ecr 146565409], length 0
16:25:37.239273 IP 172.16.0.120.32965 > 172.16.0.10.80: Flags [F.], seq 76, ack 264, win 245, options [nop,nop,TS val 146577407 ecr 146565409], length 0
16:25:37.244770 IP 172.16.0.10.80 > 172.16.0.120.32965: Flags [F.], seq 264, ack 77, win 227, options [nop,nop,TS val 146565417 ecr 146577407], length 0
16:25:37.244808 IP 172.16.0.120.32965 > 172.16.0.10.80: Flags [.], ack 265, win 245, options [nop,nop,TS val 146577413 ecr 146565417], length 0
#这个结果没得说。172.16.0.10的80并不是作为监听注册使用的。
(5) 中转服务器的内网网卡和外网网卡抓包结果
内网:
[root@gateway ~]# tcpdump -i ens37 -nn tcp port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens37, link-type EN10MB (Ethernet), capture size 262144 bytes
16:25:37.228276 IP 172.16.0.120.32965 > 192.168.10.4.80: Flags [S], seq 2414794746, win 14600, options [mss 1460,sackOK,TS val 146577392 ecr 0,nop,wscale 6], length 0
16:25:37.231881 IP 192.168.10.4.80 > 172.16.0.120.32965: Flags [S.], seq 4199406913, ack 2414794747, win 14480, options [mss 1460,sackOK,TS val 146565400 ecr 146577392,nop,wscale 6], length 0
16:25:37.232633 IP 172.16.0.120.32965 > 192.168.10.4.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 146577397 ecr 146565400], length 0
16:25:37.236502 IP 172.16.0.120.32965 > 192.168.10.4.80: Flags [P.], seq 1:76, ack 1, win 229, options [nop,nop,TS val 146577399 ecr 146565400], length 75: HTTP: GET / HTTP/1.1
16:25:37.239354 IP 192.168.10.4.80 > 172.16.0.120.32965: Flags [.], ack 76, win 227, options [nop,nop,TS val 146565408 ecr 146577399], length 0
16:25:37.239661 IP 192.168.10.4.80 > 172.16.0.120.32965: Flags [P.], seq 1:264, ack 76, win 227, options [nop,nop,TS val 146565409 ecr 146577399], length 263: HTTP: HTTP/1.1 200 OK
16:25:37.241902 IP 172.16.0.120.32965 > 192.168.10.4.80: Flags [.], ack 264, win 245, options [nop,nop,TS val 146577406 ecr 146565409], length 0
16:25:37.242394 IP 172.16.0.120.32965 > 192.168.10.4.80: Flags [F.], seq 76, ack 264, win 245, options [nop,nop,TS val 146577407 ecr 146565409], length 0
16:25:37.246349 IP 192.168.10.4.80 > 172.16.0.120.32965: Flags [F.], seq 264, ack 77, win 227, options [nop,nop,TS val 146565417 ecr 146577407], length 0
16:25:37.249762 IP 172.16.0.120.32965 > 192.168.10.4.80: Flags [.], ack 265, win 245, options [nop,nop,TS val 146577413 ecr 146565417], length 0
#内网接口收到请求报文后,还没有做目标地址转换。这个能被防火墙策略那条所匹配到。所以路由前就应该把地址给修改了。所以
通过外网网卡抓包的结果,目标地址应该被修改了。
外网:
[root@gateway ~]# tcpdump -i eno16777736 -nn tcp port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eno16777736, link-type EN10MB (Ethernet), capture size 262144 bytes
16:25:37.228197 IP 172.16.0.120.32965 > 172.16.0.10.80: Flags [S], seq 2414794746, win 14600, options [mss 1460,sackOK,TS val 146577392 ecr 0,nop,wscale 6], length 0
16:25:37.231995 IP 172.16.0.10.80 > 172.16.0.120.32965: Flags [S.], seq 4199406913, ack 2414794747, win 14480, options [mss 1460,sackOK,TS val 146565400 ecr 146577392,nop,wscale 6], length 0
16:25:37.232601 IP 172.16.0.120.32965 > 172.16.0.10.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 146577397 ecr 146565400], length 0
16:25:37.236389 IP 172.16.0.120.32965 > 172.16.0.10.80: Flags [P.], seq 1:76, ack 1, win 229, options [nop,nop,TS val 146577399 ecr 146565400], length 75: HTTP: GET / HTTP/1.1
16:25:37.239385 IP 172.16.0.10.80 > 172.16.0.120.32965: Flags [.], ack 76, win 227, options [nop,nop,TS val 146565408 ecr 146577399], length 0
16:25:37.239680 IP 172.16.0.10.80 > 172.16.0.120.32965: Flags [P.], seq 1:264, ack 76, win 227, options [nop,nop,TS val 146565409 ecr 146577399], length 263: HTTP: HTTP/1.1 200 OK
16:25:37.241872 IP 172.16.0.120.32965 > 172.16.0.10.80: Flags [.], ack 264, win 245, options [nop,nop,TS val 146577406 ecr 146565409], length 0
16:25:37.242371 IP 172.16.0.120.32965 > 172.16.0.10.80: Flags [F.], seq 76, ack 264, win 245, options [nop,nop,TS val 146577407 ecr 146565409], length 0
16:25:37.246391 IP 172.16.0.10.80 > 172.16.0.120.32965: Flags [F.], seq 264, ack 77, win 227, options [nop,nop,TS val 146565417 ecr 146577407], length 0
16:25:37.249723 IP 172.16.0.120.32965 > 172.16.0.10.80: Flags [.], ack 265, win 245, options [nop,nop,TS val 146577413 ecr 146565417], length 0
#外网网卡的请求报文的目标地址已经被修改了。
(6) 192.168.10.4内网主机抓包结果
[root@localhost ~]# tcpdump -i eno16777736 -nn tcp port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eno16777736, link-type EN10MB (Ethernet), capture size 65535 bytes
00:25:46.359591 IP 172.16.0.120.32965 > 192.168.10.4.80: Flags [S], seq 2414794746, win 14600, options [mss 1460,sackOK,TS val 146577392 ecr 0,nop,wscale 6], length 0
00:25:46.359765 IP 192.168.10.4.80 > 172.16.0.120.32965: Flags [S.], seq 4199406913, ack 2414794747, win 14480, options [mss 1460,sackOK,TS val 146565400 ecr 146577392,nop,wscale 6], length 0
00:25:46.363311 IP 172.16.0.120.32965 > 192.168.10.4.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 146577397 ecr 146565400], length 0
00:25:46.367658 IP 172.16.0.120.32965 > 192.168.10.4.80: Flags [P.], seq 1:76, ack 1, win 229, options [nop,nop,TS val 146577399 ecr 146565400], length 75
00:25:46.367884 IP 192.168.10.4.80 > 172.16.0.120.32965: Flags [.], ack 76, win 227, options [nop,nop,TS val 146565408 ecr 146577399], length 0
00:25:46.369185 IP 192.168.10.4.80 > 172.16.0.120.32965: Flags [P.], seq 1:264, ack 76, win 227, options [nop,nop,TS val 146565409 ecr 146577399], length 263
00:25:46.376568 IP 172.16.0.120.32965 > 192.168.10.4.80: Flags [.], ack 264, win 245, options [nop,nop,TS val 146577406 ecr 146565409], length 0
00:25:46.376594 IP 172.16.0.120.32965 > 192.168.10.4.80: Flags [F.], seq 76, ack 264, win 245, options [nop,nop,TS val 146577407 ecr 146565409], length 0
00:25:46.376795 IP 192.168.10.4.80 > 172.16.0.120.32965: Flags [F.], seq 264, ack 77, win 227, options [nop,nop,TS val 146565417 ecr 146577407], length 0
00:25:46.380816 IP 172.16.0.120.32965 > 192.168.10.4.80: Flags [.], ack 265, win 245, options [nop,nop,TS val 146577413 ecr 146565417], length 0
#这里请求报文能看到真实请求地址是172.16.0.120.回应的时候也是从192.168.10.4回应给172.16.0.120.因为报文的源地址和目标地址
不在一个网络,所以跨网络通信,会去找192.168.10.4的路由条目。而192.168.10.4的网关指向的是192.168.10.254.所以报文就这样
给到了中转服务器。
扩展:
如果我现在要配合nat和filter的功能。比如192.168.10.4的web服务器要禁止源地址为172.168.0.23访问,因为它总是攻击我。这个时候既要做DNAT,又要做filter。
iptables -A FORWARD -s 172.16.0.23 -p tcp --dport 80 -d 192.168.10.4 -j REJECT
#上面这个-d参数指定的是192.168.10.4,这个是内网地址。这个很关键。因为DNAT是在PREROUTING上应用,是在路由前就已经
把请求报文的目标地址从172.16.0.10改成192.168.10.4.然后路由拆解了MAC部分,然后去判断报文的目标地址是否是本机来决定
是通过INPUT还是FORWARD,这个是过滤的功能,现在判断的结果是目标地址是192.168.10.4,要通过FORWARD链,所以在filter表
的FORWARD链上的规则的目标地址应该是192.168.10.4而非172.16.0.10。
This target is only valid in the nat table, in the POSTROUTING chain. It should only be used with dynamically assigned IP (dialup) connections: if you have a static IP address, you should use the SNAT target. Masquerading is equivalent to specifying a mapping to the IP address of the interface the packet is going out, but also has the effect that connections are forgotten when the interface goes down. This is the correct behavior when the next dialup is unlikely to have the same interface address (and hence any established connections are lost anyway).
此target仅仅是在nat表的POSTROUTING链上才能使用。它只能应用于动态分配的IP(拨号上网)的连接:如果你
有固定的静态的IP地址,你应该使用SNAT作为你规则的target。简单来说,现在有些公司是买的一个固定ip地址,
有些公司是拨号上网后动态分配的外网ip地址,外网ip会随时变化,使用SNAT无法指定–to-source的值,所以要
使用MASQUERADE这个target。
MASQUERADE比SNAT更消耗性能,因为每一条报文过来,它都要实现去检测实际的源地址。
--to-ports port[-port]
This specifies a range of source ports to use, overriding the default SNAT source port-selection heuristics (see above). This is only valid if the rule also specifies one of the following protocols: tcp, udp, dccp or sctp.
--random
Randomize source port mapping If option --random is used then port mapping will be randomized (kernel >= 2.6.21).
IPv6 support available since Linux kernels >= 3.7.
上面选项没有什么好说的。因为外网ip不固定,所以--to-source在这个target不存在。如果要修改端口可以使用--to-ports。
This target is only valid in the nat table, in the PREROUTING and OUTPUT chains, and user-defined chains which are only called from those chains. It redirects the packet to the machine itself by changing the destination IP to the primary address of the incoming interface (locally-generated packets are mapped to the localhost address, 127.0.0.1 for IPv4 and ::1 for IPv6).
这个target也是只在nat表的PREROUTING链以及OUTPUT链上才能使用。这个是与单机做端口转发有关的。
比如我本机有个非特权用户启动运行的web站点,默认肯定不能注册使用80这个特权端口。比如注册使用的
是8080,此时。如果我们对外提供服务器,要向浏览器不指定端口,就想要使用80这个默认端口,就可以通过
这个REDIRECT来实现。
--to-ports port[-port]
This specifies a destination port or range of ports to use: without this, the destination port is never altered. This is only valid if the rule also specifies one of the following protocols: tcp, udp, dccp or sctp.
--random
If option --random is used then port mapping will be randomized (kernel >= 2.6.22).
IPv6 support available starting Linux kernels >= 3.7.
实例:
把请求报文来自于任何互联网地址,然后请求的目标地址是192.168.10.4而且目标端口是80,给它转交给8080.实际监听的是
8080,然后80并没有在用户空间使用一个进程注册监听使用。
[root@localhost ~]# iptables -t nat -A PREROUTING -d 192.168.10.4 -p tcp --dport 80 -j REDIRECT --to-ports 8080
#上面这条规则在192.168.10.4这台内网主机执行。假设就是在之前做实验的基础上。然后使用网关服务器去访问这个80和8080.
#如果不配置此条策略,默认只能请求http://192.168.10.4:8080
#下面结果显示此内网机器,默认并没有监听在80端口。
eno16777736: flags=4163 mtu 1500
inet 192.168.10.4 netmask 255.255.255.0 broadcast 192.168.10.255
inet6 fe80::20c:29ff:fe64:344 prefixlen 64 scopeid 0x20
ether 00:0c:29:64:03:44 txqueuelen 1000 (Ethernet)
RX packets 6323 bytes 594502 (580.5 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 4118 bytes 536285 (523.7 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73 mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10
loop txqueuelen 0 (Local Loopback)
RX packets 8730 bytes 661548 (646.0 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 8730 bytes 661548 (646.0 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@localhost ~]# ss -tnl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 50 *:139 *:*
LISTEN 0 128 *:111 *:*
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 50 *:445 *:*
LISTEN 0 50 :::139 :::*
LISTEN 0 128 :::111 :::*
LISTEN 0 128 :::8080 :::*
LISTEN 0 32 :::21 :::*
LISTEN 0 128 :::22 :::*
LISTEN 0 128 :::23 :::*
LISTEN 0 100 ::1:25 :::*
LISTEN 0 50 :::445 :::*
#测试
[root@gateway ~]# curl http://192.168.10.4:8080
192.168.10.4
[root@gateway ~]# curl http://192.168.10.4:80
192.168.10.4