iptables 使用备忘

转自 http://www.zsythink.net/archives/1199,内容有删减。

一、防火墙

防火墙大体分为主机防火墙和网络防火墙。

主机防火墙:针对于单个主机进行防护。

网络防火墙:往往处于网络入口或边缘,针对于网络入口进行防护,服务于防火墙背后的本地局域网。

网络防火墙和主机防火墙并不冲突,可以理解为,网络防火墙主外(集体), 主机防火墙主内(个人)。

从物理上讲,防火墙可以分为硬件防火墙和软件防火墙。

硬件防火墙:在硬件级别实现部分防火墙功能,另一部分功能基于软件实现,性能高,成本高。

软件防火墙:应用软件处理逻辑运行于通用硬件平台之上的防火墙,性能低,成本低。

二、iptables 概念

Netfilter 是 Linux 操作系统核心层内部的一个数据包处理模块,它具有如下功能:

  • 网络地址转换(Network Address Translate)
  • 数据包内容修改
  • 数据包过滤的防火墙功能

iptables 是一个命令行工具,位于用户空间,我们用这个工具操作 netfilter。iptables并没有一个守护进程,所以不是真正意义上的服务。

2014041522224868618.jpg

iptables详解

iptables 有四表五链的概念。我一般这么去理解,表是逻辑上的分类(或简单理解成数据库的表),链是物理上的分类,在数据包生命周期各个阶段的处理。

报文在匹配iptables的规则的时候,是按照固定的顺序进行的,既不是按照表的顺序执行,也不是按照检查点的顺序执行。

structure-of-iptables中做了非常详细的说明。

五链(本机收到的请求报文的流向):

  • 到本机某进程的报文:PREROUTING –> INPUT,具体来说是:

    raw.PREROUTING -> mangle.PREROUTING -> nat.PREROUTING -> mangle.INPUT -> filter.INPUT
    
  • 由本机转发的报文:PREROUTING –> FORWARD –> POSTROUTING,具体来说是:

    raw.PREROUTING -> mangle.PREROUTING -> nat.PREROUTING -> mangle.FORWARD -> filter.FORWARD -> mangle.POSTROUTING -> nat.POSTROUTING
    
  • 由本机的某进程发出报文(通常为响应报文):OUTPUT –> POSTROUTING

    raw.OUTPUT -> mangle.OUTPUT -> nat.OUTPUT -> filter.OUTPUT -> mangle.POSTROUTING ->nat.POSTROUTING
    

四表:

  • filter表:控制本机数据包的进出,可看做防火墙(默认表);内核模块:iptables_filter
  • nat表:network address translation,网络地址转换功能;内核模块:iptable_nat
  • mangle表:拆包并修改标志位,重新封装;iptable_mangle
  • raw表:关闭nat表上启用的连接追踪机制;iptable_raw

表和链之间的包含关系如下:

filter: 
    Chain INPUT
    Chain FORWARD
    Chain OUTPUT

nat:
    Chain PREROUTING
    Chain INPUT
    Chain OUTPUT
    Chain POSTROUTING

mangle:
    Chain PREROUTING
    Chain INPUT
    Chain FORWARD
    Chain OUTPUT
    Chain POSTROUTING

raw:
    Chain PREROUTING
    Chain OUTPUT

image-20201010104549340

为了更方便的管理,我们还可以在某个表里面创建自定义链,将针对某个应用程序所设置的规则放置在这个自定义链中,但是自定义链接不能直接使用,只能被某个默认的链当做动作去调用才能起作用。

三、iptables 规则的增删查改

iptables命令的语法如下:

iptables -t [表名]  
         <-A | I | D | R> 链名 
         [规则编号] 
         [-i | o 网卡名称] 
         [-p 协议] 
         [-s 源ip地址 | 源子网] 
         [--sport 源端口] 
         [-d 目标ip地址 | 目标子网] 
         [--dport 目标端口] 
         <-j target> 
  • -A新增一条规则,该规则增加到规则列表的最后一行,使用该参数时不能使用规则编号

  • -I插入一条规则,如果指定了规则编号,原本该位置上的规则会向后顺序移动,如果没有指定规则编号,将在第一条规则前插入

  • -D从规则列表中删除一条规则,可以输入完整的规则进行删除,也可以直接指定规则编号进行删除

  • -R替换某条规则,规则被替换时不会改变其顺序,必须指定要替换的规则编号

  • 规则编号 规则列表的第一条规则的编号为1

  • -i指定数据包进入的网卡,-o指定数据包输出的网卡

  • -p指定规则应用的协议,可以是tcp, udp, udplite, icmp, icmpv6,esp, ah, sctp, mh

  • -s指定源主机的IP地址或子网地址,格式为address[/mask][,...]

  • -d指定指定目标主机的IP地址或子网地址,格式为address[/mask][,...]

  • -j target
    

    --jump target
    

    决定符合条件的包到何处去。target可以指定另一个链,常用的Target/Jumps包含:

    • ACCEPT表示允许包,即满足匹配条件的包被允许,并且不会再匹配当前链中的其他规则或同一个表内的其他规则,但这个包还会通过其他表中的链
    • DROP表示丢弃包,即将符合条件的包丢弃,不会再向下走。效果就是包被阻塞,不会像发送者返回任何信息。
    • REJECT表示拒绝包,REJECT和DROP类似,在阻塞包时会向发送者返回错误信息。
    • REDIRECT表示将数据包重定向到本机或另一台主机的某个端口,通常用来实现透明代理或对外开放内网的某些服务
    • SNAT源地址转换,即改变数据包的源地址
    • DNAT目标地址转换,即改变数据包的目标的地址
    • LOG将符合规则的数据包相关规则信息记录在日志中,便于管理员分析问题

在iptables的世界中,常用的匹配条件是报文的”源地址”、”目标地址”、”源端口”、”目标端口”等,常用的动作有ACCEPT(接受)、DROP(丢弃)、REJECT(拒绝)。

1 查询规则

标准用法:

iptables -t filter -L INPUT
  • -t: table,选择表,默认 filter表
  • -L: List,显示链,默认 全部链,区分大小写。

iptables详解

显示的信息为:

  • target:规则对应的target,往往表示规则对应的”动作”,即规则匹配成功后需要采取的措施。
  • prot:表示规则对应的协议,是否只针对某些协议应用此规则。
  • opt:表示规则对应的选项。
  • source:表示规则对应的源头地址,可以是一个IP,也可以是一个网段。
  • destination:表示规则对应的目标地址。可以是一个IP,也可以是一个网段。

其它常用参数:

  • -v: 显示更多属性信息
    • pkts:对应规则匹配到的报文的个数。
    • bytes:对应匹配到的报文包的大小总和。
    • in:表示数据包由哪个接口(网卡)流入,我们可以设置通过哪块网卡流入的报文需要匹配当前规则。
    • out:表示数据包由哪个接口(网卡)流出,我们可以设置通过哪块网卡流出的报文需要匹配当前规则。
  • -n: source和destination中不对 IP 地址进行解析,直接显示IP地址。
  • –line-numbers: 显示规则的编号

iptables详解

头部Chain INPUT后面有一串括号括起来的内容,具体含义为:

  • policy表示当前链的默认策略,上图的默认策略为ACCEPT
  • packets表示当前链(上图为INPUT链)默认策略匹配到的包的数量,0 packets表示默认策略匹配到0个包。
  • bytes表示当前链默认策略匹配到的所有包的大小总和。(使用 -x 参数可以显示精确计数值)

2 删除规则

清空 filter 表 INPUT 链的规则:

iptables -F INPUT
  • -F:Flush,清空某链条,默认全部链条。
iptables -t filter -D INPUT 3
  • -D: delete ,删除某行规则。

3 增加规则

注意,规则的前后顺序很重要!匹配到前一条,就会按照前一条的动作执行了,很有可能不会执行后面的规则条目了。

iptables详解

与查询规则类似:

iptables -t filter -I INPUT ! -s xxx.xxx.xxx.xxx/xx -j DROP
  • -t:table,选择表,默认为filter表
  • -I: Insert,插入链的头部
  • -A: Append,插入链的尾部
  • -s: source,源地址
  • -j: jump,条件匹配时的动作
  • !: 条件取反

4 修改规则

实际上修改规则命令我平时几乎不用,宁愿先删除规则,再添加。

iptables详解

iptables -t filter -R INPUT 1 -s xxx.xxx.xxx.xxx -j DROP
  • -R: replace,选择链条 第几条。

5 恢复、保存规则

上文中的iptables的修改都是临时性的,系统重启后就会失效。为了确保重启后规则和我们预设的一致,可以配置一个iptables的rules文件,基于这个文件进行配置变更,通过恢复再保存的方式,进行配置管理。

# 预先将规则写入/etc/iptables.test.rules 文件
echo "/sbin/iptables-restore < /etc/iptables.up.rules" > /etc/network/if-pre-up.d/iptables && chmod +x /etc/network/if-pre-up.d/iptables

iptables-restore < /etc/iptables.test.rules;
iptables-save > /etc/iptables.up.rules;

6、处理动作

处理动作在iptables中被称为target(这样说并不准确,我们暂且这样称呼),动作也可以分为基本动作和扩展动作。

此处列出一些常用的动作,之后的文章会对它们进行详细的示例与总结:

ACCEPT:允许数据包通过。

DROP:直接丢弃数据包,不给任何回应信息,这时候客户端会感觉自己的请求泥牛入海了,过了超时时间才会有反应。

REJECT:拒绝数据包通过,必要时会给数据发送端一个响应的信息,客户端刚请求就会收到拒绝的信息。

SNAT:源地址转换,解决内网用户用同一个公网地址上网的问题。

MASQUERADE:是SNAT的一种特殊形式,适用于动态的、临时会变的ip上。

DNAT:目标地址转换。

REDIRECT:在本机做端口映射。

LOG:在/var/log/messages文件中记录日志信息,然后将数据包传递给下一条规则,也就是说除了记录以外不对数据包做任何其他操作,仍然让下一条规则去匹配。

7. 匹配条件

当一条规则中存在多个匹配条件时,报文必须同时满足这些条件,才算做被规则匹配。

  1. IP地址 -s/-d

    可以使用”叹号”进行取反,也能够同时指定多个IP地址,使用”逗号”隔开。地址包括源地址 -s 和目的地址 -d

    iptables -t filter -I INPUT ! -s 10.0.0.0/16 -j DROP
    
  2. 协议类型 -p

    -p: 默认为全部,支持 tcp, udp, udplite, icmp, icmpv6,esp, ah, sctp, mh

  3. 网卡接口 -i/-o

    -i选项只能用于PREROUTING链、INPUT链、FORWARD链,它只是用于判断报文是从哪个网卡流入的,所以只能在上图中”数据流入流向”的链中与FORWARD链中存在,OUTPUT链与POSTROUTING链,都不能使用-i选项。

    当主机有多块网卡时,可以使用-o选项,匹配报文将由哪块网卡流出。-o选项只能用于FORWARD链、OUTPUT链、POSTROUTING链中。

  4. 扩展匹配

    基本匹配条件我们可以直接使用,而如果想要使用扩展匹配条件,需要指定相应的扩展模块。

    1. 端口 –dport/–sport,使用模块tcp。

      -p tcp -m tcp --dport 22:25
      

      -m tcp表示使用tcp扩展模块(模块同名可省)

    2. multiport 可指定多个离散的端口

      -p tcp -m kultiport --dports 22,36,88
      
    3. iprange 指定”一段连续的IP地址范围”

      iptables -t filter -I INPUT -m iprange --src-range 192.168.1.127-192.168.1.146 -j DROP
      iptables -t filter -I OUTPUT -m iprange --dst-range 192.168.1.127-192.168.1.146 -j DROP
      iptables -t filter -I INPUT -m iprange ! --src-range 192.168.1.127-192.168.1.146 -j DROP
      
    4. string 指定要匹配的字符串

      iptables -t flilter -I INPUT -m string --algo bm --string "ooxx" -j ACCEPT
      
    5. time 规定时间

      很少用

      iptables -t filter -I OUTPUT -p tcp --dport 80 -m time --timestart 09:00:00 --timestop 19:00:00 -j REJECT
      iptables -t filter -I OUTPUT -p tcp --dport 443 -m time --timestart 09:00:00 --timestop 19:00:00 -j REJECT
      iptables -t filter -I OUTPUT -p tcp --dport 80  -m time --weekdays 6,7 -j REJECT
      iptables -t filter -I OUTPUT -p tcp --dport 80  -m time --monthdays 22,23 -j REJECT
      iptables -t filter -I OUTPUT -p tcp --dport 80  -m time ! --monthdays 22,23 -j REJECT
      iptables -t filter -I OUTPUT -p tcp --dport 80  -m time --timestart 09:00:00 --timestop 18:00:00 --weekdays 6,7 -j REJECT
      iptables -t filter -I OUTPUT -p tcp --dport 80  -m time --weekdays 5 --monthdays 22,23,24,25,26,27,28 -j REJECT
      iptables -t filter -I OUTPUT -p tcp --dport 80  -m time --datestart 2017-12-24 --datestop 2017-12-27 -j REJECT
      
    6. connlimit,限制每个IP地址同时链接到server端的链接数量

      iptables -I INPUT -p tcp --dport 22 -m connlimit --connlimit-above 2 -j REJECT
      iptables -I INPUT -p tcp --dport 22 -m connlimit --connlimit-above 20 --connlimit-mask 24 -j REJECT
      iptables -I INPUT -p tcp --dport 22 -m connlimit --connlimit-above 10 --connlimit-mask 27 -j REJECT
      
      • connlimit-above 连接数
      • connlimit-mask 掩码
    7. limit,使用令牌桶算法,对”报文到达速率”限制。

      iptables -t filter -I INPUT -p icmp -m limit --limit-burst 3 --limit 10/minute -j ACCEPT
      iptables -t filter -A INPUT -p icmp -j REJECT
      
      • limit 10/minute: 1分钟生成10个令牌放行。
        • minute
        • second
        • hour
        • day
      • –limit-burst 3:最多同时存在3个令牌。
    8. tcp-flags,根据tcp请求头标志位限制。

      很少用,不解释了。

      iptables -t filter -I INPUT -p tcp -m tcp --dport 22 --tcp-flags SYN,ACK,FIN,RST,URG,PSH SYN -j REJECT
      iptables -t filter -I OUTPUT -p tcp -m tcp --sport 22 --tcp-flags SYN,ACK,FIN,RST,URG,PSH SYN,ACK -j REJECT
      iptables -t filter -I INPUT -p tcp -m tcp --dport 22 --tcp-flags ALL SYN -j REJECT
      iptables -t filter -I OUTPUT -p tcp -m tcp --sport 22 --tcp-flags ALL SYN,ACK -j REJECT
      
    9. udp 很少用,不解释了。

    10. icmp 很少用,不解释了。

    11. state 常用。

      iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
      

      对于state模块的连接而言,”连接”其中的报文可以分为5种状态,报文状态可以为NEW、ESTABLISHED、RELATED、INVALID、UNTRACKED

      NEW:连接中的第一个包,状态就是NEW,我们可以理解为新连接的第一个包的状态为NEW。

      ESTABLISHED:我们可以把NEW状态包后面的包的状态理解为ESTABLISHED,表示连接已建立

      RELATED:关联包

      INVALID:无法识别,或者这个包没有任何状态

      UNTRACKED:报文未被追踪,无法找到相关的连接。

    12. recent,用于限制一段时间内的连接数。recent模块在 iptables 里面维护了一个地址列表,这个地址列表可以通过”–set”、”–update”、”–rcheck”、”–remove”四种方法来修改列表。

      本部分参考链接

      –name 设定列表名称,即设置跟踪数据库的文件名. 默认DEFAULT; –rsource 源地址,此为默认。 只进行数据库中信息的匹配,并不会对已存在的数据做任何变更操作; –rdest 目的地址; –seconds 指定时间内. 当事件发生时,只会匹配数据库中前”几秒”内的记录,–seconds必须与–rcheck或–update参数共用; –hitcount 命中次数. hits匹配重复发生次数,必须与–rcheck或–update参数共用; –set 将地址添加进列表,并更新信息,包含地址加入的时间戳。 即将符合条件的来源数据添加到数据库中,但如果来源端数据已经存在,则更新数据库中的记录信息; –rcheck 检查地址是否在列表,以第一个匹配开始计算时间; –update 和rcheck类似,以最后一个匹配计算时间。 如果来源端的数据已存在,则将其更新;若不存在,则不做任何处理; –remove 在列表里删除相应地址,后跟列表名称及地址。如果来源端数据已存在,则将其删除,若不存在,则不做任何处理;

      例1:限制无法ssh直接连接服务器,需先用较大包ping一下,此时在15秒内才可以连接上:

      iptables -P INPUT DROP
      iptables -A INPUT -s 127.0.0.1/32 -j ACCEPT
      iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
      iptables -A INPUT -p icmp --icmp-type 8 -m length --length 128 -m recent --set --name SSHOPEN --rsource -j ACCEPT
      iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT
      iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --rcheck --seconds 15 --name SSHOPEN --rsource -j ACCEPT
      

      例2: 限制每ip在一分钟内最多对服务器只能有8个http连接

      iptables -I INPUT -p tcp --dport 80 -d 192.168.10.10 -m state --state NEW -m recent --name httpuser --set
      iptables -A INPUT -m recent --update --name httpuser --seconds 60 --hitcount 9 -j LOG --log-prefix 'HTTP attack: '
      iptables -A INPUT -m recent --update --name httpuser --seconds 60 --hitcount 9 -j DROP
      

      例3: SSH连接,每个IP每小时只限连接5次

      -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name SSHPOOL --rcheck --seconds 3600 --hitcount 5 -j DROP
      -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name SSHPOOL --set -j ACCEPT
      

      或:

      -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT                            //必须添加这个前提条件才能生效!
      -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name SSHPOOL --set
      -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name SSHPOOL --rcheck --seconds 3600 --hitcount 5 -j DROP
      

      例4: SSH 开门暗语

      # 记录日志,前缀SSHOPEN:
      iptables -A INPUT -p tcp --dport 50001 --syn -j LOG --log-prefix "SSHOPEN: "
             
      # 目标端口tcp 50001的新数据设定列表为sshopen返回TCP重置,并记录源地址。
      iptables -A INPUT -p tcp --dport 50001 --syn -m recent --set --name sshopen --rsource -j REJECT --reject-with tcp-reset
             
      # 开启SSH端口,15秒内允许记录的源地址登录SSH。
      iptables -A INPUT -p tcp --dport 22 --syn -m recent --rcheck --seconds 15 --name sshopen --rsource -j ACCEPT
             
      #开门钥匙
      nc host 50001
      telnet host 50001
      nmap -sS host 50001
      

      例5: SSH 开门暗语2

      #记录日志,前缀SSHOPEN:
      iptables -A INPUT -p icmp --icmp-type 8 -m length --length 78 -j LOG --log-prefix "SSHOPEN: "
             
      #指定数据包78字节,包含IP头部20字节,ICMP头部8字节
      iptables -A INPUT -p icmp --icmp-type 8 -m length --length 78 -m recent --set --name sshopen --rsource -j ACCEPT
             
      iptables -A INPUT -p tcp --dport 22 --syn -m recent --rcheck --seconds 15 --name sshopen --rsource -j ACCEPT
             
      #开门钥匙
      ping -s 50 ip    #linux主机的ip
      ping -l 50 ip     #windows主机的ip
      

四、自定义链

自定义链是为了更好管理iptables规则而存在的。自定义链并不能直接使用,被默认链引用才能够使用。

  1. 创建自定义链

    iptables -t filter -N KELU
    
  2. 引用自定义链

    iptables -t filter -I INPUT -p tcp --dport 80 -j KELU
    
  3. 重命名自定义链

    iptables -E KELU YUKI
    
  4. 删除自定义链

    删除自定义链需要满足两个条件

    1、自定义链没有被引用

    2、自定义链中没有任何规则

    iptables -X KELU
    

五、iptables 动作

ACCEPT、DROP、REJECT、LOG、SNAT、DNAT、MASQUERADE、REDIRECT

前三个没什么好记录的。如果想要NAT功能能够正常使用,需要开启Linux主机的核心转发功能。

echo 1 > /proc/sys/net/ipv4/ip_forward

LOG

LOG动作会将报文的相关信息记录在/var/log/message文件中,LOG动作只负责记录匹配到的报文的相关信息,不负责对报文的其他处理。一般放到链条的最后,记录被拒绝的请求。

LOG动作也有自己的选项

  • –log-level选项可以指定记录日志的日志级别,可用级别有emerg,alert,crit,error,warning,notice,info,debug。
  • –log-prefix选项可以给记录到的相关信息添加”标签”之类的信息,以便区分各种记录到的报文信息,方便在分析时进行过滤。
  • 注:–log-prefix对应的值不能超过29个字符。
# log iptables denied calls (access via 'dmesg' command)
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables input denied: " --log-level 7
-A FORWARD -m limit --limit 5/min -j LOG --log-prefix "iptables forward denied: " --log-level 7

SNAT

网络内部的主机可以借助SNAT隐藏自己的IP地址,共享公网IP

iptables -t nat -A POSTROUTING -s 10.1.0.0/16 -j  SNAT --to-source 192.168.1.146

DNAT

配置DNAT,可以通过公网IP访问局域网内的服务。

iptables -t nat -I PREROUTING -d 公网IP -p tcp --dport 公网端口 -j DNAT --to-destination 私网IP:端口号
iptables -t nat -I PREROUTING -d 公网IP -p tcp --dport 8080 -j DNAT --to-destination 10.1.0.1:80
iptables -t nat -A POSTROUTING -s 10.1.0.0/16 -j SNAT --to-source 公网IP

MASQUERADE

可以把MASQUERADE理解为动态的、自动化的SNAT,如果没有动态SNAT的需求,没有必要使用MASQUERADE,因为SNAT更加高效。

当我们拨号网上时,每次分配的IP地址往往不同,不会长期分给我们一个固定的IP地址,如果这时,我们想要让内网主机共享公网IP上网,就会很麻烦,因为每次IP地址发生变化以后,我们都要重新配置SNAT规则,这样显示不是很人性化,我们通过MASQUERADE即可解决这个问题,MASQUERADE会动态的将源地址转换为可用的IP地址,其实与SNAT实现的功能完全一致,都是修改源地址,只不过SNAT需要指明将报文的源地址改为哪个IP,而MASQUERADE则不用指定明确的IP,会动态的将报文的源地址修改为指定网卡上可用的IP地址

iptables -t nat -I POSTROUTING -s 10.1.0.0/16 -o eth0 -j MASQUERADE

REDIRECT

使用REDIRECT动作可以在本机上进行端口映射

iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080

参考资料


如何获取容器的 pid 信息 半藏森林 - 阅读修身