前言
近些天培训都涉及到了iptables,万般无奈只能重新拿起别人的笔记恶补一波,不懂iptables就相当于不懂基础的通信安全,不懂tcpip协议栈,不懂nat,不懂系统内核,不懂一切。。。所以接下来就是从这些方面来阐述这个服务。
疑问
firewalld和iptables的区别
firewalld是centos7新增的,用来取代iptables,所以你会发现firewalld是自带的,而iptables需要额外安装。
iptables和netfilter的区别
iptables 只是管理控制 netfilter 的工具,可以使用该工具进行相关规则的制定以及其他的动作。这样看来十分明显iptables 是用户层的程序,netfilter 是内核空间的。也就是说,iptables 命令工具操作的 netfilter,真正起"防火"作用的是 netfilter。
防火墙(iptables)
概述:
防火墙是一个框架,它不仅仅是iptables,iptables作为数据包过滤机制只是防火墙这个框架中的一个部分,而防火墙包括了netfilter(包过滤)和tcpwrappers(程序管理机制)还有最强悍的selinux(内核级访问限制)等。
防火墙分类:
- 设备层面:软件防火墙、硬件防火墙、芯片级防火墙,软硬件区别不大,只是取决于防火墙是是否剥离成独立的服务器。
- 技术层面:数据包过滤型、应用代理型
必要性:
防火墙作为内部环境的第一道防线,能够通过一定的策略将一些不想要的或者是含有病毒的数据包拒之门外,不妨假设一条没有防火墙的线路,当收到对方的任何通信数据,我方都会照单全收,即便是可能危害到自身网络或者硬件设备的数据,不仅是如此,防火墙灵活的策略设计能够满足你许多定制化的需求,保障安全保障的同时提供了更多控制数据通信的方法。
火的类型:
- 什么是火,我们定义它是火他就是火,而这火的种类基于osi七层模型,好吧是因为数据包主要分为四种,应用层包(http/smtp/ftp/dns),传输层包(tcp/udp),网络层包(ip报文),链路层包(数据帧),除非编译内核源码,不然一般都是这四种。
- 识别火的依据,也就是防火墙的实现原理,根据火的类型分为四种实现原理
- 链路层包(数据帧)
-
- 实质就是控制MAC地址,这种控制细分到具体硬件设备上的
-
- 网络层包(ip报文)
-
- 实质就是ip报文(icmp),分为源ip和目的ip,访问的限制具有双向性
-
- 链路层包(数据帧)
c.传输层包(tcp/udp)
i.实质就是限制端口,分为源和目的端口,访问的限制基于服务来制定
d.应用层包
i.这一层属于应用代理型的防火墙,他需要解开数据包获得协议的类型等数据信息,对cpu和内存的占用高。
e.特殊的判断依据
i.根据数据包内容做限制,如dns解析包,将里面含有具体某个域名的dns请求丢弃掉,达到该域名解析失败同样是限制了上网目的
ii.根据关联状态做限制,如外网不能访问内网,而内网可以访问外网的需求,单单是对ip做限制是没办法完成需求的,又或者说针对端口做限制,但是无法事先得知我方连接的端口并做限制。关联状态便解决了这个问题,通过内网访问外网时生成的套接字,就能够得知数据回来时的走向,并且允许这部分数据通过,而其他的则丢弃。
数据传输方式
网络间
传统的网络结构就不多说了,按四层封包解包
进程间
对于现在愈发细粒度的网络架构,本机内部的路由决策,也就是进程间的数据传输更需要去了解,主要的方式:共享内存/命名管道/套接字/消息队列/信号量。
共同点
不管是哪种方式,他们传输的方式都是基于套接字(ip+port)来进行的,就算是进程间,虽然这些数据不用再通过路由策略和物理网卡(走的是loopback),但数据也是有流入和流出之分的,流入的数据从内核空间进入用户空间,当用户空间程序响应时,流出前会先判断该包是发给本机还是外部的从而判断流出网卡,而这恰恰是linux系统的短板,因为他不是路由器,并不是为了数据转发而生的,所以默认是没有开启ip_forward模式,如果发生跨网卡转发必然会被丢弃。
疑惑点
既然说linux系统跨网卡转发不可能发生,那我们来假设一个环境,某台linux主机有两张网卡,一张是192.168.1.1,一张是172.16.1.1,现在有一台用户设备192.168.1.2,网关指向192.168.1.1,当用户ping网关能通毋庸置疑,而ping另一张网卡也能通,我相信大家都会这么觉得,但是真的知道这其中的数据处理处理过程吗?现在看来,是不是觉得什么都不会,先等等后面更不会。
能不能ping通,要先知道ip是什么,大家都是到是一个网络层的标识,那它和系统是什么关系,可能都停留在网卡层面吧,其实ip是属于内核,就连tcpip协议栈也是内核的,也就是说当你ping另一张网卡时,数据是由内核进行判断属于本机地址,通过用户空间处理产生响应数据包根据路由策略从直连网卡出去,这个过程中并没有所说的数据转发,因为流出的数据是新产生的。而转发则是流入和流出的包是一样的或者是稍作修改,并且转发整个过程都是在内核空间进行的。
数据包过滤的详细过程
从上图不难看出,只要有数据流入就必定先经过内核进行处理,也就是进行路由判决,如果目标是本机的数据包,则流向用户空间进行处理,如果不是则直接由内核进行转发。而从用户空间流出的数据包可以是流入数据处理后的响应包也可以是本机应用产生的请求包,一份数据是没办法完完整整的走完这整条路,因为它会被处理掉并产生新的,这也是为什么用户空间流入流出是断开的。
防火墙设置的节点,其实就是ABCDE五个点,所以不难看出linux的netfiler是在内核空间进行的,这五个点的分别称为 PREROUTING 链、INPUT 链、FORWARD链、OUTPUT 链和 POSTROUTING 链
你真的懂TCP/IP吗
你认为的懂
除了tcp建立及断开的过程,你或许还知道数据传输的双向性,明白为什么建立握手要三次,断开握手要四次。但是对于内核来说它的那些过程需要用到这个协议栈,他是以什么形式和路径来保存这些连接的呢?
我认为的懂
- 三次握手
- 初始状态双方都处于closed状态,发起tcp请求的一方则为客户端,接受一端为服务端
- 服务端对应的端口开启监听,处于listen状态
- 客户端发起建立请求连接(SYN=1,ACK=0),此时客户端处于SYN-sent状态
- 服务端接收到后回复ACK报文,并且请求建立连接(SYN=1,ACK=1),此时服务端处于SYN-RCVD状态
- 客户端收到后回复ACK报文(ACK=1),进入ESTABLISHED状态
- 服务端收到ACK报文后也进入ESTABLISHED状态,也就是所谓的全连接状态
- 疑问点
- 之所以要三次握手,是为了防止因网络延迟导致已过期的连接请求传送到对端,造成通信错误或者资源浪费。另一方面也是为了防止确认报文在传输过程中丢失的情况下,请求方无法确认接收方是否准备好,这种情形下请求方会忽略对方发来的数据分组(只等待应答分组),而对方的数据分组发送超时后会重传,造成死锁。
- 三次握手能够携带数据,但是只有第三次的确认报文才能够携带(消耗序列号)
- 服务端之所以也要消耗一个seq是因为数据传输是双向的
- 四次挥手
- 双方都处于established状态,当客户端发起连接终止请求(FIN=1)后,客户端进入FIN-WAIT-1状态,等待服务端回复确认。
- 服务端收到后,回复ACK确认,表示同意断开,并且进入CLOSED-WAIT状态,直到自己也主动发起断开请求,此时这个tcp连接处于半连接状态
- 客户端收到后进入FIN-WAIT-2状态,等待服务端的断开请求到来
- 服务端确认没有信息要传输了之后,发送FIN表示我也这边传输通道也要断开,然后进入LAST-ACK状态,等待对方的确认
- 客户端收到后,回复ACK报文,表示我也同意断开,此时客户端进入TIME-WAIT状态,此时整个tcp连接算是完全关闭了,只要在等待2个MSL时间就会进入CLOSED状态
- 疑问点
- 之所以四次挥手,是因为数据传输通道都是单向的,但是数据的交互却是双向的,客户端和服务端各自建立的传输通道都要由他们自己来关闭,而当有一方数据还没传完就进入对方就请求断开连接,此时的ACK包和FIN包就会分开发送。
- 之所以要等待2个MLS时间再进入CLOSED状态
- 是为了确保对方收到我方发送的ACK包,然后顺利的进入CLOSED状态。如果ack报文丢失,那么2个MLS时间内对方会重新发起断开请求,那么我方就会重置2MLS计时器然后重传ack包。不难看出谁先发起断开请求,谁就晚断开。
- 另外也是为了防止出现像三次握手那样过期的连接请求,在这段时间内消化掉本次连接的所有数据传输,新连接中就不会再出现旧连接的请求报文。
- 与内核的关系
- 如果是客户端请求的断开,客户端就会保存大量的CLOSED-WAIT状态的连接,如果是服务端请求的断开,服务端就会保存大量的TIME-WAIT状态的连接,而这些连接都会以文件的形式(文件描述符)保存在系统中,如果在高并发高连接数的请况下,这些连接数资源就可能被耗尽,因为内核是由设定最大打开文件数的,具体可以通过修改内核配置文件/etc/sysctl.conf,来解决。
- SYN Flood攻击
- 是一种常见的DDOS攻击手段,攻击者通过工具在短时间内制造出大量的不存在ip向指定端口发送tcp连接请求,当服务端接收到后也会发起确认和请求连接报文,自己则进入SYN-RECV状态,等待接受对方的确认,然而对方是不存在的,数据包在路由器节点就会被丢弃掉,服务端以为是自己发送出错了,就会继续重发直到超时
- 这样大量的SYN请求得不到回应会造成资源队列的占用,正常的syn包无法被处理,而服务器也一直处于重传响应包的状态,消耗大量的cpu资源,使得服务器运行缓慢,甚至是网络堵塞引起系统瘫痪。
- 排查命令
netstat -tnlpa | grep tcp | awk '{print $6}' | sort | uniq -c
Linux防火墙(netfilter)
- iptables和netfilter的关系
- iptables 只是管理控制 netfilter 的工具,可以使用该工具进行相关规则的制定以及其他的动作。这样看来十分明显iptables 是用户层的程序,netfilter 是内核空间的。也就是说,iptables 命令工具操作的 netfilter,真正起"防火"作用的是 netfilter。
- 概述
- 特点 kernel是一个模块化的内核,netfilrer也是以模块的形式存在于内核中,每添加一个相关的模块,就意味着增加一个netfilter功能。
- 模块存放目录
/lib/modules/$kernel_ver/net/{netfilter,ipv4/netfilter,ipv6/netfilter}。 //$kernel_ver 代表内核版本号,/lib/modules/$kernel_net/kernel/netnetfilter/存放的是同时满足 ipv4 和 ipv6 的 netfilter。
- netfilter结构
- 内存块(想要netfilter工作需要将规则读入内存中,这是一个链表结构,内存块中有四张表,而规则的容器是链)
- filter表:这是最重要的表,用来过滤拦截流入流出本机的数据包,该表只有OUTPUT链、FORWARD链、INPUT链
- 当只有该表时,以ping本机的127.0.0.1为例,数据包从用户空间产生并流出经过output链,经过路由决策后从该回环口发出,由于ping的是主机,所以数据包仍然从回环口流入,并接受input链检查,最后返回ping信息。
- NAT表:实现网络地址转换,该表有PREROUTING链、POSTROUTING链、OUTPUT链
- mangle表:一张特殊表,可实现数据包的拆分和还原,如修改TTL或者TOS来实现Qos等功能,该表包含所有的链
- raw表:加速数据包穿过防火墙,增强防火墙性能,该表只有PREROUTING链、OUTPUT链
- filter表:这是最重要的表,用来过滤拦截流入流出本机的数据包,该表只有OUTPUT链、FORWARD链、INPUT链
- 内存块(想要netfilter工作需要将规则读入内存中,这是一个链表结构,内存块中有四张表,而规则的容器是链)
- 关于链
- 每条链对应同名称的一种数据包,input链就是为了保护本机,output链则是为了管制本机,forward链是在数据转发给后端机器的过程中提供保护,相对于linux自带的ip_forward功能来说,forward链能够自定义转发的数据类型,而ip_forward会转发所有,当然forward工作前提是要开启ip_forward功能。
- iptables命令书写规则
规则格式 Usage: iptables [-t TABLE] COMMAND [ option -j target ] 相关参数 COMMANDAS --append -A chain 链尾部追加一条规则 --delete -D chain 从链中删除能匹配到的规则 --delete -D chain rulenum 从链中删除第几条链,从 1 开始计算 --insert -I chain [rulenum] 向链中插入一条规则使其成为第rulenum 条规则,从 1 开始计算 --replace -R chain rulenum 替换链中的地 rulenum 条规则,从 1 开始计算 --list -L [chain [rulenum]] 列出某条链或所有链中的规则 --list-rules -S [chain [rulenum]] 打印出链中或所有链中的规则 --flush -F [chain] 删除指定链或所有链中的所有规则 --zero -Z [chain [rulenum]] 置零指定链或所有链的规则计数器 --new -N chain 创建一条用户自定义的链 --delete-chain -X [chain] 删除用户自定义的链 --policy -P chain target 设置指定链的默认策略(policy)为指定的target --rename-chain -E old new 重命名链名称,从old 到 new OPTION [!] --proto -p proto 指定要检查哪个协议的数据包:可以是协议代码或协议名称,如 tcp,udp,icmp 等。协议名和代码对应关系存放在 /etc/protocols 中,省略该选项时默认检查所有协议的数据包,等价于 all 和协议代码 0 [!] --source -s address[/mask][...] 指定检查数据包的源地址[!] --destination -d address[/mask][...] 指定检查数据包的目标地址 [!] --mac-source address 指定mac地址 [!] --source-port --sport port[:port] 指定源端口号或源端口范围 [!] --destination-port --dport port[:port] 指定目的端口号或目的端口范围 [!] --in-interface -i name[+] 指定数据包流入接口,若接口名后加"+",表示匹配该接口开头的所有接口 [!] --out-interface -o name[+] 指定数据包流出接口,若接口名后加"+",表示匹配该接口开头的所有接口 [!] --tcp-flags --tcp-flags [SYN,ACK,FIN,RST,URG,PSH,ALL,NONE] 匹配指定字段的数据包,第一个字段为1,后面的字段全为0 //[!] --syn 是"--tcp-flags SYN,ACK,FIN,RST SYN"的简写格式 [!] --state --state statename 状态扩展,结合ip_conntarck追踪会话的状态,是数据包的状态而非服务器连接状态 INVALID:非法连接(如 syn=1 fin=1),不属于以下三种基本都是非法数据包 ESTABLISHED:数据包处于已建立的连接中,过去和返回的数据包都属于该状态 NEW:新建连接请求的数据包,且该数据包没有和任何已有连接相关联,如果第一次连接失败了也不算new(不允许该状态则相当于禁止主动请求连接) RELATED:和当前连接无任何关联,完全是被动或者临时建立连接之间传输的数据包状态,如tracert过程中,每一跳返回的ttl为0的数据包。又或者是ftp的被动模式在21端口建立了连接,而在不确定的端口传输的数据包都属于该状态 --connlimit-above n 连接数量高于上限 n 个时就执行 TARGET TAEGET DROP 丢弃 REJECT 拒绝 ACCEPT 接受 DNAT 目标地址转换,后面跟--to-destination, SNAT 源地址转换,后面跟--to-source,指定去往前面地址的流量映射到该地址 REDIRECT 端口重定向 RETURN 用于自定义链,自定义链中匹配完毕后返回到自定义的前一个链中继续向下匹配 MASQUERADE 用于外网接口变动的情况下的源地址转换,如ADSL 相关命令 iptables -X [linkname] 清除自定义链 iptables -F [linkname] 清除规则 iptables -D [linkname] [linknum] 清除某一条规则 iptables -Z [linkname] 清除计数器 iptables -P [linkname] [target] 设置filter表默认规则 iptables -vnL 分别是查看流量统计、详细列表信息、规则列表,三者有依赖关系 其他命令 iptables-save -t tablesname 导出规则 service iptables save 之写入的规则都只是存放在内存当中,并没有生成文件永久的写在内核里,当服务重启时就是消失,该命令能够保存规则到/etc/sysconfig/iptables中。
- ip contrack
- nf_contrack也是nat表的基础,用来记录连接的映射关系
- 提供追踪功能,由nf_contrack模块提供,加载该模块后,就会在/proc/net/nf_contrack中记录追踪的链接状态,虽然会追踪tcp/udp/icmp的连接,但是只会保存tcp的连接状态。
- 这项功能监控时会消耗一定的资源,因此对追踪数量做了一定限制,由/proc/sys/net/filter/nf_contrack_max决定,在高并发的状态下,追踪可能会出现排队阻塞从而导致告警。
- iptstate命令能够查看相关连接
- 使用脚本来管理规则
- 好处就是能更易被读懂,并且当系统变量发生改变时(如ip地址),不用大量修改规则
- NAT实战
- 设置防火墙
开启转发 echo 1 > /proc/sys/net/ipv4/ip_forward 内网访问外网 iptables -t nat -A POSTROUTING -s 防火墙私网侧ip -o eth0 -j SNAT --to-source 防火墙公网侧ip 外网访问内网 iptables -t nat -A PREROUTING -p tcp -m tcp --dport 80 -j DNAT --to 内网服务器ip
-
- 设置中转机
echo 1 > /proc/sys/net/ipv4/ip_forward iptables -t nat -A PREROUTING -p tcp -m tcp --dport 20068 -j DNAT --to-destination 目的服务器ip端口 iptables -t nat -A POSTROUTING -d 目的服务器ip端口 -p tcp -j SNAT --to-source 中转机互联的ip