详解iptables命令及原理

Last Updated: 2023-03-31 05:45:17 Friday

-- TOC --

Linux系统中,防火墙(Firewall),网址转换(NAT),数据包(package)记录,流量统计,这些功能是由Netfilter子系统所提供的,而iptables是控制Netfilter的工具。

项目官方:https://www.netfilter.org/

检查系统中是否存在ip_tables模块:

$ lsmod | grep ip_tables

tables & chains

iptables内置了filter,nat,mangle和raw 4个table。

table包含chains,在chains中配置rule规则,所有规则配置后,立即生效,不需要重启服务。

4 tables

Tables are used by iptable to group rules based on their function. The 3 main table types available are Filter, NAT, and Mangle.

iptables命令行如果不指定table,默认就是使用filter table。

chains

iptables的结构是由表(tables)组成,而tables是由链(chain)组成,链又是由具体的规则(rule)组成。因此我们在编写iptables的规则时,要先指定表,再指定链。

Filter

A chain is essentially a collection of rules within a specific table. The Filter table for example has 3 default chains INPUT, OUTPUT, and FORWARD, these chains are used to process packets based on the type of packet.

Filter table有3条chain,分别是INPUT,OUTPUT和FORWARD。

下面的命令,查看filter table各条chain的规则:

-v,verbose

-L,List

-n,使用ip地址和port数字(这个参数跟很多其它命令一样,应该是--number的简写吧)

$ sudo iptables -vnL

In addition to the chains above custom chains can be created as well. You can add a rule within another chain (such as INPUT) that targets a custom chain. By placing such a rule in the beginning of a chain, you can save unnecessary rule processing.

也可以自定义chains,用-N参数。

NAT

用于网络地址转换(IP、端口),包括的规则链有:prerouting,postrouting 和 output

Mangle

主要应用在修改数据包、流量整形、给数据包打标识,默认的规则链有:INPUT,OUTPUT,FORWARD,POSTROUTING,PREROUTING。你可以使用mangle来改变包的一些属性,比如 TOS(type OF service),TTL (Time To Live),Mark(用于后续流量控制TC等)。

优先级:raw > mangle > nat > filter

4表5链

数据包流程图

此图清晰的表达了数据包从网卡收到后经过的环节:

iptables_chains.png

iptables_chains_kernel.png

这个图更好:

packet_flow.jpg

在同一个chain中,table只是定义了优先级。

设置Rule

Explicit Allow (Default Deny)

Explicit Allow uses a default deny policy, when creating these types of rules the base policy is a deny all rule. Once you have a base policy that denies all traffic you must add rules (in the proper order) that explicitly allow access.

Explicit Allow is by default more secure than Explicit Deny, because only traffic that you explicitly allow is allowed into the system. The trade off, however is that you must manage a sometimes complicated rule set. If the rule set is not correct you may even end up locking yourself out of the system. It is not that uncommon to lock yourself out of your system when creating a explicit allow policy.

只允许那些明确允许的流量,其它都是Deny,更安全,更容易将自己也lock out。

Explicit Deny (Default Allow)

Explicit Deny uses a default allow policy, when creating these types of rules the base policy is to allow all. Once you have a base policy that allows all traffic you can create additional rules that explicitly deny access.

When using Explicit Deny only traffic that you specifically block is denied, this means that your system is more vulnerable if you forget to block a port that should be blocked. However this also means that you are less likely to lock yourself out of the system.

只拒绝那些明确拒绝的流量,其它默认都是Allow。

kele_shuxia.png

配置iptables

$ iptables [-t table] command [链名] [条件匹配] [-j 目标动作]
$ man iptables

先配置一条允许SSH流量的规则

No matter if I am adding a explicit deny or explicit allow base policy I always add a rule that allows me access to port 22 (SSH) as the first rule. This allows me to ensure that SSH is always available to me even if I mess up the other rules.

$ sudo iptables -I INPUT -p tcp --dport 22 -j ACCEPT

-I INPUT:向INPUT chain做Insert,后面没有数字,表示Insert到最前面

-p:指定协议,如tcp, udp,icmp等

-s:指定source ip,可以是网段或域名,网段如203.0.113.0/24

-d:指定destination ip,可以是网段或域名

--dport:指定destination port,

--sport:指定source port,

端口配置可以有几种方式,(1)指定一个具体的端口;(2)12345:23456,指定端口范围;(3):12345,小于等于12345的端口;(4)12345:,大于等于12345的端口;

还有一种指定多端口的方式,比如:-m multiport --sport 12,23,34

-j:jump to the action ACCEPT

-L:List

-n:直接使用ip地址和port number

-v:verbose

Allow Loopback Traffic

有可能有运行在localhost内的server需要通信,一般都要运行loopback接口的流量:

$ sudo iptables -I INPUT -i lo -j ACCEPT

-i:指定入接口;

-o:指定出接口;

这条规则将会排在最前面,当loopback接口的流量比较多的时候,放在最前面可以加速匹配。

流量越大,规则越要靠前!

Blocking IP

# iptables -I INPUT 3 -s 192.168.123.0/24 -j DROP

192.168.123.0/24整个网段作为源ip,都被DROP了。

-I INPUT 3:表示作为INPUT chain的第3条规则。

配置Default Deny

$ sudo iptables -P INPUT DROP

-P:配置policy。

The -P flag stands for policy, in this command we are setting the default policy of the INPUT chain to the target DROP.

chains默认的policy都是ACCEPT。

policy就是默认规则,当数据包没有被任何规则匹配时,按此policy处理。默认规则不会被-F清除。

DROP vs REJECT

The REJECT target will send a reply icmp packet to the source system telling that system that the packet has been rejected. By default the message will be port is unreachable.

If you want to reject the connection instead, which will respond to the connection request with a connection refused error, replace DROP with REJECT.

The DROP target simply drops the packet without sending any reply packets back.

The REJECT target is vulnerable to DoS style attacks as every packet that is rejected will cause iptables to send back an icmp reply, when an attack is at volume this causes your system to also send icmp replies in volume. In this scenario it is better to simply drop the packet and reduce traffic congestion as best you can.

对于防火墙来说,显然DROP是更好的选择!

Append Rule

# iptables -A INPUT -p tcp --dport 80 -j ACCEPT
# iptables -A INPUT -p tcp --dport 443 -j ACCEPT

-A INPUT:表示Append规则到INPUT chain

删除Rule

$ sudo iptables -vnL --line-number
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1       34  1768 ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0
2        0     0 ACCEPT     tcp  --  *      *       127.0.0.1            0.0.0.0/0            tcp dpt:22
$ sudo iptables -D INPUT 2

--line-number:显示规则的时候,提供数字编号,从1开始

-D INPUT 2:删除INPUT chain的第2条规则;

清空Rule

$ sudo iptables -F INPUT
$ sudo iptables -F
$ sudo iptables -F -t filter

-F INPUT:将INPUT chain清空

如果不写INPUT,整个filter table都会被清空!

-t,用来指定table,默认是filter table;

注意:-F是清空链中规则,但并不影响 -P 设置的policy默认规则。 因此在生产环境中,若指定默认规则为DROP,一旦执行iptables -F,很容易导致自己也无法连接服务器。

清空chain或rule的统计

$ sudo iptables -Z [chain [rulenum]]

It is legal to specify the -L, --list(list) option as well, to see the counters immediately before they are cleared. 可同时与-L参数并用。

阻止报文通过本机

# iptables -A FORWARD -s 10.10.10.10 -j DROP

阻止来自10.10.10.10的数据包通过本机。

本机可能被配置成了网关,有多个网口。(需要将网口设置为混杂模式吗?恐怕还跟这个系统参数net.ipv4.ip_forward有关系?)

# iptables -P FORWARD DROP

这是设置FORWARD链的policy为DROP。

按MAC地址匹配

# iptables -A INPUT -m mac --mac-source xx:xx:xx:xx:xx:xx -j DROP

拒绝来自某 MAC 地址的数据包进入本机

NAT配置

# iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -j SNAT --to 18.18.18.18

将内网 192.168.1.0/24 转换为公网18.18.18.18地址。SNAT,用于访问互联网。

# iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -j SNAT --to 18.18.18.18-18.18.18.28

同上,只不过是转换到一组IP地址池

# iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to 192.168.1.1

把从eth0口进来访问TCP/80端口的数据包目的地址改成192.168.1.1

# iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to 192.168.1.1-192.168.1.10
# iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE

将源地址是 192.168.1.0/24 的数据包进行地址伪装,转换成 eth0 上的 IP 地址。动态SNAT转换(适用于动态 IP 场景 )。

iptables的扩展模块

-m:指定使用哪个扩展;

https://ipset.netfilter.org/iptables-extensions.man.html

用iptables的limit限速

我对使用iptables的limit来限速的方法的理解,其实是直接将超过预设流量的报文直接DROP。这种直接丢弃报文的做法,在有些场景下并不是特别好。

# iptables -I FORWARD 1 -p tcp -i eth0 -o eth1 -s 192.168.2.3 -d 192.168.3.3 --dport 80 -m limit --limit=500/s --limit-burst=1000  -j ACCEPT
# iptables -I FORWARD 2 -p tcp -i eth1 -o eth0 -s 192.168.3.3 -d 192.168.2.3 --dport 80 -m limit --limit=500/s --limit-burst=1000  -j ACCEPT
# iptables -A FORWARD -p tcp -i eth0 -o eth1 -s 192.168.2.3 -d 192.168.3.3 --dport 80 -j DROP
# iptables -A FORWARD -p tcp -i eth1 -o eth0 -s 192.168.3.3 -d 192.168.2.3 --dport 80 -j DROP 

这里的limit,表示按一定速率去匹配报文并采取行动!超过limit的报文,进入下一条规则,DROP。我看很多人写的文章,limit后面,都是DROP。

limit匹配的是报文数量,并不是带宽,要自己去换算一下,比如假设每个报文的大小是1500byte!这也是用limit来限速不好的一点。

limit的这种限制报文数量的方式,从我看到的资料看分析,应该是均匀的,比如在1秒内,按相同时间间隔,发出所谓的令牌,匹配到的报文得到令牌,有令牌的报文得ACCEPT,没有令牌的报文,进入下一条DROP规则。

这种匹配报文数量的机制,也有很适合的应用场景,比如限制icmp或ping报文的数量

# iptables -A INPUT -p icmp -m limit --limit 1/sec --limit-burst 10 -j ACCEPT
# iptables -A INPUT -p icmp -j DROP
# iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s --limit-burst 1 -j ACCEPT
iptables -A INPUT -p icmp --icmp-type echo-request -j DROP

下面的规则,使用了自定义chain,同样是达到显示ping报文数量的效果:

iptables -N pinglimit
iptables -A pinglimit -m limit --limit 1/s --limit-burst 1 -j ACCEPT
iptables -A pinglimit -j DROP
iptables -A INPUT -p icmp --icmp-type echo-request -j pinglimit

用iptables的connlimit限制tcp连接数

# 设置端口连接数为3
# iptables -I INPUT -p tcp --dport 10086 -m connlimit --connlimit-above 3 -j DROP

当连接数大于3时,DROP。

禁止ping

iptables -A INPUT -p icmp --icmp-type 8 -s 0/0 -j DROP

丢弃IPv4分片

iptables -A INPUT -f -j DROP

限制SYN并发数

iptables -A INPUT -p tcp --syn -m limit --limit 1/s -j ACCEPT

iptabes规则的备份和恢复

Linux系统中,基本都有一组与iptables相关的命令:

$ sudo ls -l /usr/sbin/iptables*
lrwxrwxrwx. 1 root root 26 Mar 24 10:43 /usr/sbin/iptables -> /etc/alternatives/iptables
lrwxrwxrwx. 1 root root 17 Aug  5  2021 /usr/sbin/iptables-nft -> xtables-nft-multi
lrwxrwxrwx. 1 root root 17 Aug  5  2021 /usr/sbin/iptables-nft-restore -> xtables-nft-multi
lrwxrwxrwx. 1 root root 17 Aug  5  2021 /usr/sbin/iptables-nft-save -> xtables-nft-multi
lrwxrwxrwx. 1 root root 34 Mar 24 10:43 /usr/sbin/iptables-restore -> /etc/alternatives/iptables-restore
lrwxrwxrwx. 1 root root 17 Aug  5  2021 /usr/sbin/iptables-restore-translate -> xtables-nft-multi
lrwxrwxrwx. 1 root root 31 Mar 24 10:43 /usr/sbin/iptables-save -> /etc/alternatives/iptables-save
lrwxrwxrwx. 1 root root 17 Aug  5  2021 /usr/sbin/iptables-translate -> xtables-nft-multi

iptables-save通过重定向到文件保存配置;

iptables-restore通过重定向文件恢复;

而设置开始自动恢复配置,就要用到systemd的一些工具了。

On Ubuntu

On Ubuntu, one way to save iptables rules is to use the iptables-persistent package. Install it with apt like this:

$ sudo apt install iptables-persistent

During the installation, you will be asked if you want to save your current firewall rules. If you update your firewall rules and want to save the changes, run this command:

$ sudo netfilter-persistent save

本文链接:https://cs.pynote.net/net/202205251/

-- EOF --

-- MORE --