iptables(2)

很多事,从前与以后都不会相同,连意义甚至细究起来,都会变得模糊。人生,也许荒诞,但也许这种荒诞,正是我们苦苦探求的那种精神。

 

netfilter,一个框架,位于内核空间,可以做网络地址转换,数据包内容修改,数据包过滤(防火墙),至于原理嘛,很简单的,它嵌入协议栈了,然后提供hook,所以我们可以操作修改数据包。然后iptables,是一个用户空间的命令行工具,我们用它来操作规则,最终影响netfilter的行为。

简单来说就是四表raw、mangle、nat、filter,五链PREROUTING,INPUT,FORWORD,OUTPUT,POSTROUTING,三个数据流向,接收prerouting、input,发送output、postrouting,转发prerouting、forward、postrouting。一个链包含多张表,多表之间有顺序关系,一种表可以应用在多个链。

 

测试环境调整

上一节的测试环境还是有问题,继续调整,五台kvm虚拟机,新建两个独立的网桥,br1 包含 vm1 vm2,br2包含 vm1vm3 vm4 vm5,把vm1的net.ipv4.ip_forward打开,再设置为vm1的默认路由,然后vm1的另一个网卡vm3 vm5的默认网关为vm5,这样vm5相当于更高一级的路由了,同样,vm5的net.ipv4.ip_forward也打开。之后会在vm3 vm4运行测试程序,http server,8080端口,ping pong,vm2也会运行服务端,模拟反向代理。

vm1

192.168.11.1

12:00:00:00:00:00

内网路由 & 内网网关

192.168.22.2

12:00:00:00:00:01

外网接口

vm2

192.168.11.2

12:00:00:00:00:02

内网主机

vm3

192.168.22.3

12:00:00:00:00:03

外网主机

vm4

192.168.22.4

12:00:00:00:00:04

外网主机

vm5

192.168.22.1

12:00:00:00:00:05

外网主机 & 外网网关

vm1

vm1

vm2

vm3

vm4

vm5

tcpdump tcp port 8080 -vvv -n -S -e

 

外网直接交付

直接访问,clientserver处于同一网段。,三次握手、http请求响应、四次挥手,都是类似的,所以这里就只说三次握手,三次握手的三次交互,c->s s->c c->s,从地址上来说是相反的,你和谁握手,自然也和谁交互,最后和谁分手,所以也只说第一次交互吧,后面都这样。

vm4 client

vm3 server

vm5 网关 & 路由器router & gateway

由于处于同一个网络,所以属于直接交付,不需要经过router,只有client和server能抓到包,包的内容一模一样的(除了时间戳)。在数据链路层,client -> server,在网络层,client -> server,这个情况比较简单,和上一节一模一样。

 

内网直接请求外网

vm2 client

vm3 server

vm1 router 路由器

vm5 gateway 网关

这里模拟的是内网上网的问题,也就是正向代理,如果没有nat,内网是没办法上网的。通过路由转发,client server处于不同的子网,通过router连接起来,先说结果,不通,然后抓包看一下。

vm2 client的视角,在数据链路层,client -> router,在网络层,client -> server(router有两个ip和mac,只能用同一网段的mac,下文雷同)。网络层就是就是最最原始的client -> server,但是数据链路层的目的mac不是server的,而是router的,client发现目的地不在同一个网段,于是查找路由表,木有找到专用路由,走默认路由,通过router发送,目的mac就是router在当前网络下的mac。这里一直都在重试第一次握手。。。

然后去vm1 内网路由器的视角,可以理解为router就是一个中继。router抓到的包比较复杂一些,数量也多了一倍。依然只说三次握手的第一次交互,网络层依然是最最原始的client -> server,这个永远不变(这里也是可以变的,比如后面要说的nat模式)。在数据链路层,第一次握手,首先是client -> router,然后是router -> server,router出现了两次,但是两次的mac是不一样的,因为router有两个mac。嗯,这就是路由器,从数据链路层来看,相当于一个中继。但是这里也一直在重试。。。

然后去vm3 server的视角,input方向,在数据链路层,router -> server,在网络层,client -> server;output方向,在数据链路层,server -> gateway,在网络层,server ->gateway。网络层依然是最最原始的client -> server,但是在output方向,进入三次握手的第二阶段,SYN+ACK,由于client ip不在同一网段,所以交给server的默认网关,希望网关可以把这个包发出,然而网关拿到这个包之后一脸懵逼,因为这个目的IP它是不认识的,它属于层内网络的一个ip,这里gateway的ip_forward打开了,但是它并不是一个完整功能的路由。

既然把包送给vm5了,那我们再去vm5看看,vm5收到第二次握手的包,然后就没有然后了,因为它不知道应该把这个东西给谁了,所以前面一直在重试,最后到达这里。

那么,如果把vm5的ip_forward关闭会怎么样呢,结果一样的,vm5已经是一个顶级路由了,gateway收到SYN+ACK,依然一脸懵逼,不知道应该把包发到哪里,不断重试中。。。

然后我们去抓一下icmp,这里有一个不可达包,网关的SYN+ACK包转发不出去了。

tcpdump icmp -vvv-n -S -e

 

然后,这种情况其实有一个办法可以解决,在server上加一条路由,把client网段的包发给router,而不是给gateway,这样配置可以让网络连通,但是并没有意义,想象这样一种场景,外网客户端收到一个源地址是本地ip的一个包,它有怎么知道应该把这个本地ip包交给谁呢,毕竟本地ip是不唯一的。这时候请求的方向是这样子的,client -> route-> server,但是响应的方向有点儿神奇,不是很明白怎么回事,server竟然能直接发给client包,而且router和client都收到了这个包,搞不懂,先过吧。

ip route和route命令不是很清楚,下面两条效果一样的。

client

router

server

 

iptables SNAT

只修改请求报文的源地址(只是相对于请求报文一方来说的,如果我们要考虑到响应的话,其实SNAT必然对应着DNAT,DNAT必然对应着SNAT,所以说SNAT是先修改源地址,后修改目的地址)

iptables -t nat -APOSTROUTING -s 192.168.11.0/24 ! -d 192.168.11.0/24 -j SNAT --to-source 192.168.22.2

添加一条snat,请求成功。先看client,client和router通信。

再看server,也比较简单,server和router通信,对client不感知。

所以router就比较复杂一些了,router还是一个中继的作用,不过它做了一些转换,由于内容太多,把http包内容删了一些,从数据链路层来看,做的是中转,和之前一样,但是从网络层看,从router出去的包,源地址改成了router的ip了,router拿到响应之后,改写目的ip,交给客户端。

 

外网直接请求内网

vm2 server

vm3 client

vm1 router 路由器

vm5 gateway 网关

网络拓扑不变,内网外网也不变,请求方向反一下。这里模拟的是反向代理,隐藏具体服务节点,对外暴露一个统一的入口,客户端不知道服务端具体部署。通过路由转发,client server处于不同的子网,通过router连接起来,这个就更不通了,这次和之前不一样,直接请求失败,然后抓包看一下。

vm3 client只发了一个包,发给忘关了,然后再看一下网关,也是只收到一个包,然后就木有然后了。

 

然后我们去抓一下icmp,这里有一个不可达的。

tcpdump icmp -vvv-n -S -e

 

和上面内网访问外网一样,在client上加一条路由,把client请求的包发给router,router知道serv认识client,自然可以路由包,这样配置可以让网络连通,但是更没有意义,相当于我们做反向代理的时候,向客户端暴露内部部署状态了,而且多个服务器集群内部是可以有一样的内网ip的,客户端指定了要发给这个集群,所以没有任何意义,只是测试。和上面一样内网请求外网配置路由一样(本来就一样,网络拓扑没变,只是请求方向变了),第一次握手,client同时发给了router和server,client可以直接交给router,第二次握手,server交给router,router再交给client,和之前一模一样的,还是不理解,它们俩竟然可以直接交互。。。

ip route和route命令不是很清楚,下面两条效果一样的。

client

router

server

 

iptables DNAT

只修改请求报文的目标地址(只是相对于请求报文一方来说的,如果我们要考虑到响应的话,其实DNAT必然对应着SNAT,SNAT必然对应着DNAT,所以说DNAT是先修改目的地址,后修改源地址)

网络拓扑不变,内网外网也不变,请求方向反一下。这次的请求和之前不太一样,这次是目的ip是服务端的公网ip,请求内网ip没用,而且也不知道人家的内网ip。这次抓的包有点儿复杂,一个一个看吧。

首先是客户端,和目的IP在同一个网段,所以直接交付。

然后是服务端,也很简单,和路由器交互。

最后就是路由器,做了一次中转,可以看到,对http请求,路由收到包之后,把目的地址改成真正服务器的内网ip,交付,收到http响应之后,再把源地址改成自己的地址,然后发给客户端。

但是还有一个问题,vm4和vm5都收到这样一个包,然后没有下文,之前也有个类似的问题,明明目的MAC不是自己,但是收到包了,可能是我这个桥接环境的问题吧。

 

SNAT & DNAT

SANT是为了隐藏客户端,也就是正向代理,只是附带了可以让内网用户上网,客户端知道服务端的地址,但是服务端不知道这个请求的真实客户端,SNAT之后要有一个DNAT的。

DNAT是为了隐藏服务端,也就是服务端常用的反向代理,客户端不知道真实的服务端地址,只知道服务端暴露出来的一个地址,DNAT之后同样也有一个SNAT。

真是的情况是,一个请求里面,SNAT和DNAT都有,客户端在内网,服务端需要反向代理。

 

netfilter,iptables,lvs关系,还有具体机制,这个还不是很清楚,好像是iptables和lvs都是基于netfilter的,然后好像iptables也可以做负载均衡,后面看完lvs再总结吧。

 

参考文章

http://www.zsythink.net/archives/1199

https://www.cnblogs.com/long-cnblogs/p/10711659.html