iptables的背后

每次修改iptables为子设备做转发上网都要瞎搜索很久,iptables太踏马的复杂了,这次搜索完我一定要写点东西记住哪条规则让子设备上了网。

背景:

一台独设备A,只连接B设备;

一台能上网设备B,有网卡与A连接;

B设备B1网卡与A设备连接;

B设备B2网卡上外网;

完毕。

目标:

A设备上外网;

完毕。

实施:

1. iptables的PREROUTING确保通常(一般默认ACCEPT)

2. FORWARD转发规则打开:iptables -A FORWARD -m state --state NEW,ESTABLISHED,RELATED -j ACCEP

3. POSTROUTING对A设备地址的转发打开,指定从出外网口NAT发出:iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o B2 -j MASQUERADE

碎碎念:

iptables的5个链PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING的用途在一个包的传递过程的意义,我大概还是知道些的;但是对于这几个链具体属于四个规则表NAT、FILTER、MANGL、RAW中的哪一个,就有待回忆了,在这儿记录一下查过之后认为自己还认识的规则:NAT就是映射,FILTER是过滤,MANGL和RAW不懂。其中,filter表还是主要针对需要本机处理的包,会使用FORWARD、INPUT、 OUTPUT三个链,控制INPUT、OUTPUT当然就可以控制本机主动生成的包,再控制FORWARD就能控制本机是否会为目标非本机包做转发。PREROUTING链位于包刚已进入本设备,进行过滤还言之过早,但是对于DNAT来说,却是刚好。下面给出各个表会使用的链:

filter FORWARD、INPUT、 OUTPUT

 nat PREROUTING、POSTROUTING、OUTPUT

 mangle PREROUTING、POSTROUTING、OUTPUT、INPUT、FORWARD

 raw PREROUTING、OUTPUT

然后对于上面的5个链,再拿出来复习复习(先上个图片意思意思):

五个链

1. PREROUTING链作用于包的目的还未清晰的阶段,所谓目的还未清晰的意思就是,这个包的目的IP可能是本机,也可能是过路包。所以PREROUTING的规则都是再说:对于收到的包的目的IP是xxx.xxx.xxx.xxx:xxxx的包,我们应该发给IP yyy.yyy.yyy.yyy:yyyy的机器。就回长成这个样子:iptables -t nat -A PREROUTING -d xxx.xxx.xxx.xxx -p tcp --dport xxxx -j DNAT --to-destination yyy.yyy.yyy.yyy:yyyy。这也算是NAT,不过是针对包目的IP的NAT,所以叫DNAT。如果iptables的FORWARD链被配置为ACCEPT(iptables -P FORWARD ACCEPT),或是设置了一条PREROUTING针对本机的指令,可能这样就算是生效了(当然,用的应该不是DNAT,应该是REDIRECT);但是!!!如果目标IP如果不是本机,也就是需要转发的话,这并不能使符合此规则的包顺利走出去,因为转发会继续落到FORWOARD规则,如果默认FORWARD规则一般都会是DROP,这样的话,经本机的过路包是不会被转发的。PREROUTING链站在是内核开始处理IP包的最前端,大多数情况下,它的默认规则都是ACCEPT的,我试过用iptables -P PREROUTING ACCEPT(没敢试DROP),执行结果提示出错,这是合理的,PREROUTING链被DROP的话,整台计算机对于网络就会变成一个没有意义的事务,所以只能是ACCEPT吧。PREROUTING链的规则都会是非常强力的,或者说是无脑的,最常用的场景就是做转发将发给设备A的端口a1的包转发到设备A的a2端口(向设备A转发包的规则可能在FORWARD链中已做配置):

iptables -t nat -A PREROUTING -p tcp -d 机器A的IP -dport a1 -j DNAT -to 机器A的IP:a2

在比如说做负载均衡这个事儿,通过把state NEW的包进行转发,使连接建立在不同的设备上,然后提供服务的也就会变成对应的设备:

iptables -A PREROUTING -i eth0 -p tcp –dport 443 -m state -state NEW -m nth -counter 0 -every 3 -packet 0 -j DNAT -to-destination 192.168.1.101:443

iptables -A PREROUTING -i eth0 -p tcp –dport 443 -m state -state NEW -m nth -counter 0 -every 3 -packet 1 -j DNAT -to-destination 192.168.1.102:443

iptables -A PREROUTING -i eth0 -p tcp –dport 443 -m state -state NEW -m nth -counter 0 -every 3 -packet 2 -j DNAT -to-destination 192.168.1.103:443

就会对eth0收的,目标是443端口的NEW包(差不多算是SYN包,下面有对NEW状态解释),均匀的分配给192.168.1.101、192.168.1.102、192.168.1.103三个设备。

假设我要在PREROUTING链设置这样一条规则,要配置来自192.168.100.100的包都发送给网关地址192.168.99.1,按照iptables的规则尿性,似乎应该是长成这样:

iptables -t nat -A PREROUTING -s 192.168.100.0/24 -j SNAT --to-source 192.168.99.1

似乎执行下去了,但是iptables用户态会报invalid agrument,然后dmesg就会看到:ip_tables: SNAT target: used from hooks PREROUTING, but only usable from INPUT/POSTROUTING

啥意思腻,PREROUTING链不能用SNAT,只能在INPUT、POSTROUTING链使用;SNAT是基于源地址的NAT,然后--to-destination到某个地址,在PREROUTING链的位置,这会意味着什么?

2. INPUT链是在PREROUTING之后,认为是给本机的包所要适配的规则,比如iptables -A INPUT -i eth0 -p tcp -dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT就表示:如果是给朕80端口的包包,可以笑纳。上面这一句iptables规则是增给INPUT链的不假,但是这里面的-m state --state NEW,ESTABLISHED就比较有内涵了,-m state表示后面要说要匹配的包的状态,分为NEW、ESTABLISHED、RELATED,这几个状态就是iptables的connection tracking,用在INPUT链,就是根据经过INPUT点的包是TCP中新连接建立、连接数据传输中、已建立连接在新端口又建了连接等情况,构建连接的表,然后根据规则决定干掉哪些包,通过哪些包。对于NEW,应该是新连接建立的握手包通过,因为我试过只允许NEW,没有ESTABLISHED的话,curl不能拿到html的页面内容,而如果加入了ESTABLISHED的话,就可以拿到;然后仅有ESTABLISHED的话,也是拿不到html页面内容;RELATED就没有测试到了,不过仅开RELATED是不能得到html网页的。ESTABLISHED、NEW非常重要,而我总是忘掉,NEW是对TCP握手包如SYN的匹配,ESTABLISHED是对建立连接开始传输数据数据的包的匹配,也就是说NEW决定着是否允许某地址来的或去往某地址的主动握手包通过;而ESTABLISHED决定着是否允许完成连接建立并传输数据。INPUT的使用比较接地气,打开/关闭端口(掌握着打开端口的能力,也就是掌握着本机提供http、mysql等等依赖于端口提供服务的能力,实权部门儿)、是否允许指定方向的新连接建立(-m state --state NEW)、是否响应ICMP、是否允许lo回环等等一系列与本机提供服务息息相关的关键规则。INPUT链不适配NAT规则,这也可以理解,只有发给本机的包才会到INPUT,已经是发给本机了,还做SNAT、DNAT那不是骗鬼呢么。

比如说iptables -A INPUT -i eth0 -p tcp -dport 80 -m state -state NEW,ESTABLISHED -j ACCEPT就是用于打开从eth0来的从80端口建立新连接、保持连接的能力,当然还要确保响应包能从eth0再发回去,这就是通过OUTPUT链添加权限了iptables -A OUTPUT -o eth0 -p tcp -sport 80 -m state -state ESTABLISHED -j ACCEPT,显然作为提供服务的server,并不需要主动与client建立连接,所以OUTPUT链的state中没有new。

3. FORWARD链也是PREROUTING之后,认为不是给本机的包,决定是否需要转发做匹配;这就是转发控制、路由控制;比如说像这样iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT,-m state的问题之前已经提过,添加了这条ACCEPT规则,即指定iptables的FORWARD链允许三种状态的连接建立、通过;但这并不是表示对所有目标为非本机IP进行转发,默认规则DROP的情况下,还需要再指定哪个IP来的包(目标不是本机的包)允许转发,就像是这样:iptables -D FORWARD -s 192.168.100.100 -j ACCEPT;这其中的-s 192.168.100.100表示来自192.168.100.100的包会被转发(目标不是本机的),而如果是-d 192.168.100.100则表示目标到192.168.100.100的包会被转发。需要特别注意这样一个事儿,如果要使能192.168.100.100来的包的转发,不能写成iptables -A FORWARD -s 192.168.100.100 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT,这表示仅会路由从192.168.100.100来的NEW,ESTABLISHED,RELATED的包,其他的包还是会被干掉;那如果要为192.168.100.100构建一个访问网络的通道,再添加一条iptables -A FORWARD -d 192.168.100.100 -m state --state ESTABLISHED,RELATED -j ACCEPT够不够呢,经测发现curl拿html并不成功,但是之前存在的下载链路也没有被断开,然后这两句改成

iptables -A FORWARD -s 192.168.100.100 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT

iptables -A FORWARD -d 192.168.100.100 -m state --state ESTABLISHED,RELATED -j ACCEPT

curl成功拿到了html数据,很明显来自192.168.100.100需要发SYN包主动伸手到网络IP建立TCP连接,而网络IP却不需要向192.168.100.100发SYN包构建连接。

4. POSTROUTING链负责将要离开本机的数据包的规则,匹配完POSTROUTING的规则,数据包在本设备的声明周期也就完结了,可能发配其他设备、可能扔掉,就是说,所有本机离开的包必然是匹配POSTROUTING的,也就是说如果想要转发某IP的来包或是去某IP的包,配置了FORWARD链的规则且PREROUTING链并没有决定将这个包乱扔,这个包就可以到达POSTROUTING链,POSTROUTING链的规则决定是否将包真实的扔出去。POSTROUTING链的上游是FORWARD和OUTPUT链,就是说,不只是符合FORWARD链的包会到到POSTROUTING链,OUTPUT链的包也会送给POSTROUTING链,所以一般来说如果POSTROUTING链没有被配置为ACCEPT的话(黑名单禁止),OUTPUT链配置规则后,都需要在POSTROUTING链也添加规则,当然,发给本机回环lo的不需要POSTROUTING链的放行,INPUT链和OUTPUT链放行即可。

比如说我最开始的目标,要让A设备经由B设备上网,这时候B设备如果已经配置有针对A设备的转发(3.FORWARD链中的两句),还需要打开POSTROUTING链针对A设备来的数据包的规则,使其放行:

iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o B2 -j MASQUERADE

这条规则的-s 192.168.100.0/24与之前一样,-s表示源地址,也就是网段192.168.100.0/24的来包都替换成自己的IP,然后-o到B2网卡进行外发,MASQUERADE表示本机的下一跳设备,下一跳IP的变化也不会使包扔错;与MASQUERADE对应的还有--to-destination xxx.xxx.xxx.xxx:xxxx,这就表示不论下一跳怎么变化,都要扔到xxx.xxx.xxx.xxx:xxxx。-o当然就是指定了从哪个网卡往外扔,这是无需多言的,另外还有-i表示从哪个网卡来的。着重要提出来的是-t nat这个东西,nat是我熟悉的,但并不深入,拆开理解一下:nat和filter等一样,都是基于表的,什么意思呢,就是说,他们是基于一个规则表来实现的,其实每一条iptables指令都是在配置这几个表,而PREROUTING、FORWARD、POSTROUTING、INPUT、OUTPUT表示在表中插入某个链的规则,为什么有时候没有指定nat或是filter呢,没有指定其实是插入了默认表,也就是filter表。nat和filter这两个表很重要,后面拆开说一下。

5. OUTPUT链是控制本机IP对外发送数据包时适配的规则,同INPUT链一样是实权部门,不过与INPUT不同的点在于,OUTPUT同时适配NAT规则表的DNAT,也就是说,本机的输出包,是可能根据规则替换目的地址的,大概也是代理方面的事情。

规则表

对于NAT,分为SNAT、DNAT,直白一点说,实现包的源、目的地址替换,放在nat表中。在5个链中的PREROUTING、POSTROUTING、OUTPUT链指定规则,为什么是在这3个链呢。

NAT的源、目的地址的替换本质上是一种欺骗这种欺骗首先就产生于内外网(没有内外网NAT也没有什么意义,注意内网并不就是子网,192.168.1.0/24是192.168.192.0/23一个子网)。

第1条应用便是将内网某端口的包包去掉子网的痕迹(替换掉源IP和端口),作为自己的包从动态端口发出去,就是SNAT,然后网关记住自己的这个端口收到的回包要再返回给子网的这个端口(记住的这条信息,就算是一条连接的建立,网关的一个端口也就分配使用),网关的下一跳只知道网关在往外发数据,而不能察觉其后的子网,但是这里面有一个问题就是:子网中的每一个设备都有65535个端口,而网关也有65535个端口;假设这样一个事儿,内网有100台设备,每台设备都向通过65535个端口与外面建立,似乎情况不妙呀;这其实就是传说中的SNAT网关端口耗尽,当然,如果不是机房,内网也很难凑够100台设备,也不太可能每台设备同时与外部建立,但是SNAT端口耗尽这个事儿是真实存在的,所以网关会通过连接老化,也就是对建立起的连接,如果时间长了没有新消息传输,这条连接就会被干掉,干掉之后端口也就得到了释放。嗯,这也是为什么内网里没有心跳的TCP长连接为啥总是连接不长。SNAT需要根据源地址、源端口记录一条连接,并将数据包转给下一跳,这很明显应该发生在POSTROUTING链,即包离开网关的时候替掉其源IP、源端口,假设这个事儿发生在PREROUTING节点,替掉源地址之后,PREROUTING后续的链都不会知道这是从哪儿来的包,自己骗自己很明显是没有什么意思的事情,所以PREROUTING不能设置SNAT。

NAT的第2条应用便将网关作为代理,进行外来数据包的转发分配,也就是DNAT,将来自外网来的数据包,偷梁换柱(替换掉目的IP和端口)发送给内网真实与外网沟通的设备,当然,还要记录这条连接为内网返回的包原路发还,DNAT可以掩蔽内网提供服务的设备,能对内网设备提供保护(内网设备仅有显式映射的端口才能接受外网的访问),同时也具有天然的负载均衡属性,假设内网中的两台设备均可提供相同的网页,在网关配置两条代理,对于新建立连接,也就是-m state --state NEW,通过将新连接请求分别均匀的分发给两台设备,于是每台设备就都可以提供网页,也就做到负载均衡。

FILTER表明面上是包过滤,其实就是为了控制路的通断。从这5个链的组合后包的流通路径来讲,包的通路有大概3条:

包->PREROUTING->INPUT->本机接收

包->PREROUTING->FORWARD->POSTROUTING->另一台设备

本机发出->OUTPUT->POSTROUTING->另一台设备

每一条通路必经filter表,filter能通、断每一条包的通路,这也是filter的地位。

其他的表我不会,所以就不说了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章