1. Linux当中的iptables介绍

我们一般把iptables称作防火墙,但是实际上防火墙并不是iptables,netfilter才是真正的防火墙,它工作在Linux内核当中,iptables则是操作netfilter的一个客户端,工作在用户态。

Linux的iptables当中目前支持的规则表有以下几类:

  • raw表,支持处理数据包连接跟踪。
  • filter表,支持处理流量是拦截还是放行,用于实现防火墙的功能。
  • nat表,用于实现地址转换的功能,支持处理对于ip和端口号的修改(包括源ip、源端口、目标ip和目标端口)。
  • mangle表,支持处理报文的拆包、经过处理之后重新封包的功能。

Linux网络数据包流转有很多的阶段,虽然iptables支持以上四种的规则表,但是并不是每个阶段都可以应用以上的所有规则。Linux当中的iptables执行流程一共有5个阶段,每个阶段都分别有一些支持的规则表,下面是各个阶段支持的规则表。

  • PREROUTING(支持raw表、mangle表、nat表)
  • INPUT(支持mangle表和filter表)
  • OUTPUT(支持mangle表、filter表、nat表)
  • POSTROUTING(支持mangle表和nat表)
  • FORWARD(支持mangle表和filter表)

对于防火墙的流量主要有三类:入流量、出流量和转发流量。入流量,也就是别人往你的服务器发请求;出流量也就是你往别人的服务器发请求;转发流量则是,别人往你的机器发流量,你需要将流量重新转发给别人。

对于入流量来说,数据包的流转情况如下图所示:

网络入口 -> PREROUTING -> ROUTING -> INPUT -> TCP/IP协议栈 -> NGINX/TOMCAT

对于出流量来说,数据包的流转情况如下图所示:

NGINX/TOMCAT -> TCP/IP协议栈 -> ROUTING -> OUTPUT -> POSTROUTING -> 网络出口

对于转发流量来说,数据包的流转情况如下图所示:

网络入口 -> PREROUTING -> ROUTING -> FORWARD -> POSTROUTING -> 网络出口

2.自定义服务器的iptables规则

2.1 新增iptables规则

我们可以通过iptables命令去新增iptables规则表,对于规则表的参数支持情况如下:

  • 通过-A参数(add)指定,要去进行干预的阶段(PREROUTING、POSTROUTING、INPUT、OUTPUT和FORWARD),往规则表最后新加一条规则,如果需要往最前面插入,可以使用-I命令(insert)。
  • 通过-p参数指定,要去进行匹配的协议类型(tcp、udp、icmp)。
  • 通过-s-d参数指定要匹配的源IP/目标IP,或者是源IP和目标IP的网段CIDR(例如192.168.1.0/24、10.0.0.0/8)。
  • 通过--sport--dport指定要匹配的源端口(--sport)/目标端口(--dport)。如果需要匹配多个端口,可以使用--sports--dports,多个端口号之前使用英文,分割就行,例如--sports 80,8080,18080
  • 通过-i指定要匹配的网卡接口,例如-i eth0用于匹配从eth0网卡进来的流量。
  • 通过-t参数指定,该阶段下要去进行干预的规则表,比如nat、filter、mangle,如果不指定的话默认是filter
  • 通过-j参数指定,在匹配上规则之后,我们要去进行的目标操作是什么,支持以下几种操作。
  • ACCEPT:允许数据包通过。
  • DROP:直接丢弃数据包(丢包,客户端没有任何响应,直到等到超时)。
  • REJECT:拒绝请求发送数据包并发送响应给客户端。
  • LOG:在/var/log/messages当中打印日志。
  • SNAT:修改源(Source)地址,包括源IP和源端口号。
  • DNAT:修改目标(Destination)地址,包括目标IP和目标端口号。
  • REDIRECT:重定向到本地端口(针对nat表),比如我们将443端口的流量转发到30777端口,就用到这个操作。
  • MASQUERADE:隐藏源IP,统一使用指定的网卡接口的IP进行流量的出栈,用于类似实现路由器的NAT地址转换功能。

例如,下面的命令用于操作filter表(默认),允许入流量的80端口,直接放行(ACCEPT)。

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

再比如,下面的命令用于操作filter表(默认),对入流量的源IP为192.168.1.100,并且访问当前服务器的端口12345流量,直接拒绝掉。

iptables -A INPUT -s 192.168.1.100 --dport=12345 -j REJECT

再比如,通过如下的命令实现本机的端口转发,比如我现有一个服务在30777端口启动,我需要通过HTTPS默认的443端口访问这个服务,此时我们就可以将443端口的流量转发给本机的30777端口。

# -d指定本机ip, --dport指定访问本机的443端口
iptables -t nat -A PREROUTING -p tcp -d 10.0.0.166 --dport 443 -j REDIRECT --to-port 30777

# (推荐)-i指定本机要添加的规则的网卡端口, --dport指定访问本机的443端口
iptables -t nat -A PREROUTING -p tcp -i eth0 --dport 443 -j REDIRECT --to-port 31889

# !!!! 请勿使用不指定ip和网卡的端口转发, 会出现容器的https请求都无法使用, 因为都被转发到30777端口
iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 30777

再比如,路由器的NAT地址转换,通过下面的命令,我们将10.0.8.0/24网段的地址,在流量流出服务器时,将IP修改成为eth0网卡的端口,比如eth0是公网IP,那么通过如下的命令,就代表我们将10.0.8.0/24网段的内网地址,转换成为公网IP地址。

iptables -t nat -A POSTROUTING -s 10.0.8.0/24 -o eth0 -j MASQUERADE

2.2 查看iptables规则

可以通过如下的命令去查看当前操作系统当中的iptables规则表

iptables -L -n -t nat  --line-numbers

参数介绍:

  • -L参数表达我们需要去查看iptables规则。
  • -n参数用于禁用DNS解析,如果不加-n参数,可能会对域名进行DNS解析,会将常见的端口进行映射成为对应的协议名称,比如将TCP的443端口解析成为https(通过cat /etc/services可以查看到对应的服务名称的映射关系)。
  • -t nat指定我们只想要查看nat表。
  • --line-number用于展示iptables规则表当中每一行的行号。

如果我们想要查看443端口的处理情况,可以尝试使用如下的命令:

iptables -L -n -t nat  --line-numbers | grep 443

2.3 删除iptables规则

如果想要删除iptables规则,可以通过iptables -D命令实现。

删除iptables的第一种使用方式:通过-t指定规则表,-D指定要删除的规则所处的阶段,并且按照行号进行删除。对于行号需要通过iptables -L -n -t nat --line-numbers命令的结果进行查看。

iptables -t nat -D PREROUTING ${line-number}

删除iptables的第二种使用方式:通过将新增时是用到的-A-I命令,换成-D命令,iptables会进行匹配表中的项的内容实现删除。

iptables -t nat -A PREROUTING -p tcp -d 10.0.0.166 --dport 443 -j REDIRECT --to-port 30777

# 对应删除命令
iptables -t nat -A PREROUTING -p tcp -d 10.0.0.166 --dport 443 -j REDIRECT --to-port 30777

3. iptables规则的持久化与自动加载

iptables的变化只针对机器的本次启动时生效,如果机器发生重启,那么规则就会丢失。如果我们需要对后续一直生效的话,此时我们就涉及到iptables的持久化。我们可以安装iptables-persistent工具实现iptables的持久化。

sudo apt install iptables-persistent

使用如下的命令,对当前的规则进行持久化保存到文件当中:

sudo netfilter-persistent save

执行上述命令的输出结果:

run-parts: executing /usr/share/netfilter-persistent/plugins.d/15-ip4tables save
run-parts: executing /usr/share/netfilter-persistent/plugins.d/25-ip6tables save

其实就是让它执行/usr/share/netfilter-persistent/plugins.d/15-ip4tables save脚本,将IPV4规则保存到/etc/iptables/rules.v4,IPV6规则保存到/etc/iptables/rules.v6,系统重启时netfilter-persistent会自动加载规则表。

本质上netfilter-persistent就是Linux系统的一个服务,基于Linux的服务去实现的启动时可以配置快照的自动加载。

sudo systemctl status netfilter-persistent