iptables的文章多如牛毛,但是,我读了一些,发现虽然成体系,但是不便理解,今天就结合自己的理解,好好讲解下,另外,我们也会使用iptables来实验一个nat地址转换的demo,nat转换,通俗地讲,一般是为了解决ipv4公网地址不够用的问题,因此在学校、公司等机构的有公网ip的服务器上,部署nat软件进行地址转换,如内网机器访问互联网时,将源地址转换为服务器的公网ip;在收到响应时,此时目的地址是公网ip,此时需要修改为内网机器的地址。
这个东西,教科书里学了很多年了,没想到还能走进现实,也是有点意思。
iptables运行在用户态,netfilter运行在linux内核中。iptables相当于一套界面,可以将防火墙规则写入内核中的一片内存区域,而netfilter会去读取这片内存区域中的规则,根据规则进行对应的网络包处理,如丢弃、放行等。
正因为如此,我们需要手动安装iptables,如yum install -y iptables-services
,但是,netfilter是linux内核本身自带的,无需安装。
简单来说,netfilter才是核心,你要觉得iptables不好用,可以换其他的命令行、图形界面工具,甚至自己写也可以。当然,netfilter和iptables都是同一个团队弄的,因为它不可能让大家直接写代码去操作netfilter,肯定还是得搞个好用的命令行工具给大家用吧,所以有了iptables。
而且,现在团队觉得iptables还是不够好,目前新搞了个nftables来取代iptables。
项目官网:https://www.netfilter.org/index.html
大概有这么几种网络包:
如果让你来设计,你应该也会引入几个时间点,在这个时间点,主动去查询用户定义的规则,看看规则中是要丢弃还是放行数据包。
时间点的考虑,也很重要。
比如,针对网卡收到的数据包的处理,第一个时间点,应该是在检查路由表之前(即检查目的地址是否是本机之前),此时,给用户提供一个介入的时机,用户甚至可以修改这个数据包,比如,本来是发给当前机器的,我可以将目的地址改为其他机器,这就是DNAT(nat分为修改源地址和目的地址,这里说的这种,就是修改目的地址)适用的场景;
第二个时间点,应该是在路由决定做出之后,在交给进程处理之前;
第三个时间点,应该是进程处理完成后,假如需要回应,即进程将数据包交给我们后,此时也可以进行处理
另外,针对那种路由转发的数据,在转发出去之前,应该也可以进行一些处理。
这些时间点呢,一般就是扩展点,就像spring里面一样,bean的创建过程中有很多时间点会回调用户的函数,用户就可以注册自己的回调函数,进行一些特殊的逻辑处理。
Netfifilter一共在内核的网络协议栈中,插入了5个扩展点(官网叫hook)。我参考了如下文章:
https://www.usenix.org/system/files/login/articles/892-neira.pdf
这个时间点,就是所有的网络包在做出路由决定前,就会调用本hook。一般来说,端口转换和重定向、DNAT(目标地址转换)就是在这里实现
在检查目的地址后,发现包是发给本机的,那么这些包在交给进程之前,就会调用本hook。
所有不是发往本机的包,即本机充当路由转发功能时(linux主机实现为路由器或防火墙等),会调用本hook
在做出路由决定后,调用本hook。源地址转换,基本就在这个hook阶段完成。所有要离开本机的数据包,就会触发本hook。
具体可以看下图:
image-20230723203225034
按照这篇文章的提法,主要有下面几种网络包流向:
“Therefore we can model three kind of traffific flflows, depending on the destination: ■ Traffific going through the fifirewall, in other words, traffific not going to the local machine. Such traffific follows the path: PREROUTING 、 FORWARD、 POSTROUTING. 仅仅穿越本机的流量包,即,目的地址不是本机,这样的网络包,会依次经历: PREROUTING 、FORWARD、POSTROUTING ■ Incoming traffific to the fifirewall, for example, traffific for the local machine. Such traffific follows the path: PREROUTING INPUT. 发给本机的流量包,路径为: PREROUTING 、LOCAL INPUT ■ Outgoing traffific from the fifirewall: OUTPUT POSTROUTING. 本机生成的,要出去的流量包(别管是回复别人的那种还是自己发起的,对机器来说都一样,都是要出去的),经历: OUTPUT 、POSTROUTING ”
几个时间点说清楚了,那么,这些时间点,回调我们的时候,是查询我们设置的防火墙规则对吧,那么,规则大概长啥样呢?
iptables -I INPUT -p tcp --dport 8080 -j ACCEPT
比如,上面这就是一个规则,其中,-p tcp --dport 8080
就是指定要筛选出哪些数据包来处理,如目标端口8080的,那么,怎么处理呢,这个-j ACCEPT
就表示放行。
另外,我们也不可能就一个规则吧,这个规则处理8080的,那我还有其他处理8081端口的规则,所以,最终是一堆规则,一个规则列表。
此时,我们就可以往每个hook点,注册上一个规则集合,即一个规则链,按链中顺序,依次处理。
那么,iptables是这样搞的吗,我们来看看。
此时,可以看下图:
image-20230723204335084
在每个hook点,如左下角的PREROUTING,按理说只需要有一个规则集合就够了,为啥有三个黄色方块(它们唯一指向了一堆PREROUTING阶段的规则集合),也就是说,怎么有三个规则集合呢?
其实,就是因为不同规则大相径庭:
Type of Service
字段然后,官方就大体根据这些规则,进行了分类,把一个大集合,分成了好几个集合,比如nat集合负责nat相关规则、mangle集合负责改报文字段的规则,如Type of Service
、raw集合呢,目前我接触到的有trace、log等规则、像filter呢,就负责对报文检查后进行筛选过滤。
另外呢,像一个报文的生命周期,可能会依次经过:
PREROUTING 、LOCAL INPUT
那么,在这两个阶段,我们都可以执行规则,比如,filter集合里的规则,在这两个hook点都可以执行,所以,filter表中,包含了多个hook点的规则集合;像nat集合里的规则呢,一般就在PREROUTING 、POSTROUTING这两个阶段发挥作用,所以呢,nat表,包含了PREROUTING 、POSTROUTING两个hook点的规则集合,两者互不影响,井水不犯河水。
我个人喜欢上面那张图,下面这张也可以参考:
image-20230723210256615
网上还有一张图,我觉得也很棒(https://upload.wikimedia.org/wikipedia/commons/3/37/Netfilter-packet-flow.svg):
image-20230723210446254
下图是只针对转发这种场景,也不错,图都是来源网络,侵删:
image-20230723214351472
比如,上图中,我想操作左下角的prerouting阶段的raw表:
// -t 指定表名,如raw,-I 表示插入,chain表示在哪个链插入,如PREROUTING,rulenum呢,是在PREROUTING链中插入到第几个,后面的rule-spe就是规则定义:筛选包+对包的操作
iptables [-t table] -I chain [rulenum] rule-specification
比如,我想trace一下发往8080端口的包:
iptables -t raw -I PREROUTING -p tcp -m tcp --dport 8080 -j TRACE
其他操作:
// -R,替换,即修改
iptables [-t table] -R chain rulenum rule-specification
// -D 删除
iptables [-t table] -D chain rulenum
// -L 查询,一般组合使用iptables -nvL,默认查看filter表
iptables [-t table] -L, --list [chain]
其他命令参考man iptables
、man iptables-extensions
(包含了各种目标操作的讲解)
image-20230723212111654
看我上面的图,server1没有实际监听8080端口,server2有监听,假设我客户端只能直接访问server1,那么,我想做的是,在server1上靠iptables的dnat,修改目的ip为server2,达成我访问server2的8080服务的目的。
// 没有持久化,临时修改
echo 1 >/proc/sys/net/ipv4/ip_forward
// 查看
[root@hx168-access ~]# sysctl -p
net.ipv4.ip_forward = 1
因为server1没有监听8080端口,那肯定不能自己处理,所以必须转发给server2,所以需要开启这个功能
iptables -t raw -I PREROUTING -p tcp -m tcp --dport 8080 -j TRACE
iptables -t raw -I PREROUTING -p tcp -m tcp --sport 8080 -j TRACE
目标端口为8080的,表示客户端发出来的;源端口为8080的,表示server2回复的。都加上trace
有问题就去看/var/log/messages日志
iptables -t nat -I PREROUTING 1 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 10.80.121.115
即,在网络包刚进来时,因为目标ip是server1,此时如果不进行目标ip修改,就会交给本机处理,所以,我们不能让这事发生,得改成server2.
iptables -t filter -I FORWARD 1 -p tcp -m tcp --dport 8080 -j ACCEPT
iptables -t filter -I FORWARD 1 -p tcp -m tcp --sport 8080 -j ACCEPT
正向的和反向的,各加一个,免得一会还要再加
iptables -t nat -I PREROUTING 1 -p tcp -m tcp --dport 8080 -j SNAT --to-source 10.80.121.114
因为此时发往server2的报文里,源ip还是客户端的ip,如果就这么发过去,server2就会返回报文给客户端,而不是server1,所以得改源ip为server1.
image-20230723213446750
可以看到,完全没问题。
在执行上述命令测试时,我在server1上抓包了:
tcpdump -i any tcp port 8080 -w 114.pcap
然后分析114.pcap时,发现就是如下这样,一个简单的三次握手也不简单:
image-20230723213700210
我一开始有疑问,当server2给server1返回时,目标ip为server1,我们也没有配置什么NAT规则,把目标ip改成客户端的ip,那么,服务器为啥不是把报文交给server1的进程处理,而是原路forward转发呢
这个其实还是因为NAT依赖了netfilter的会话跟踪功能,简单来说,netfilter是有状态的,以tcp举例,tcp连接的建立是因为客户端ip:客户端端口和服务端ip:服务端端口,这个四元组是有来有回的,就是我给你发了消息,你也回我了,此时,netfilter就认为这是一个会话。
所以,在server2给server1返回时,server1拿着server2和server1之间的四元组去查,查到有会话,因此,就按照之前的路径,原路回来。
另外,nat这个table里的链,只在检测到之前不存在会话时,才会进,后续就不会再进了;也就是只有首次报文的时候进nat的链
这个可以参考:
https://serverfault.com/questions/741104/iptables-redirect-works-only-for-first-packet/741108#741108
像上面这个案例,只要执行如下命令,关闭会话跟踪,就执行不成功了:
iptables -t raw -I PREROUTING -p tcp -m tcp -dport 8080 -j NOTRACK
[root@hx168-access ~]# cat /proc/net/nf_conntrack
ipv4 2 tcp 6 118 TIME_WAIT src=10.0.240.103 dst=10.80.121.114 sport=8922 dport=8080 src=10.80.121.115 dst=10.80.121.114 sport=8080 dport=8922 [ASSURED] mark=0 zone=0 use=2
yum install conntrack-tools
[root@hx168-access ~]# conntrack -L
tcp 6 118 TIME_WAIT src=10.0.240.103 dst=10.80.121.114 sport=9072 dport=8080 src=10.80.121.115 dst=10.80.121.114 sport=8080 dport=9072 [ASSURED] mark=0 use=1
https://www.jianshu.com/p/0fe6aeec8d79,图不错
https://www.linux.org/docs/man8/iptables-extensions.html
https://gist.github.com/tomasinouk/eec152019311b09905cd 关于nat
https://www.netfilter.org/documentation/
https://www.netfilter.org/documentation/HOWTO/netfilter-hacking-HOWTO-3.html#ss3.1
https://www.usenix.org/system/files/login/articles/892-neira.pdf