[Linux] Iptabels 核心概念及常用命令

16,895 阅读8分钟

1. Iptables 简介

  • iptables是防火墙吗 ?

    iptables 其实不是真正的防火墙,我们可以把它理解成一个客户端代理,用户通过iptables这个代理,将用户的安全设定执行到对应的"安全框架"中,这个"安全框架"才是真正的防火墙,这个框架的名字叫netfilter。后面会陆续推出使用golang调用 netfilternetlink 两个网络库的参考代码,有兴趣的可以点下关注;

1.1 IPtables核心概念之四表

表(table)是存储规则包规则的地方,类似于路由器存储路由表; 表是作用在链路节点上。

  • filter表:INPUT,FORWARD,OUTPUT (过滤数据)
  • nat表:PREROUTING,POSTROUTING INPUT OUTPUT (端口和地址映射,数据转发)
  • mangle表:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING 修改数据包的TOS(Type of Service,服务类型)等
  • raw表:PREROUTING,OUTPUT 设置raw时一般是为了不再让iptables做数据包处理

表的处理优先级:raw > mangle > nat > filter

1.2 IPtables核心概念之五链

链(chan)是包经过的路线,可以理解成包在系统中的一个生命周期需要经历的hook;

  • PREROUTING: 处理进来的包,等待路由决策
  • POSTROUTING: 路由决策之后,向外发送的数据包
  • INPUT: 外部进来的包,已经做完路由决策,发往本机的数据包
  • FORWARD: 外部进来的包,路由决策之后,需要转发的包.
  • OUTPUT: 本机产生需要向外部发送的数据包(未经路由决策);

1.3 一图胜千言

  • 上层协议栈指的是用户空间
  • 非本地IP需要经过FORWARD链转发时许开启linux转发功能echo 1 > /proc/sys/net/ipv4/ip_forward

image.png

2. 常用命令介绍及用途解析

2.1 Filter 表 Input 链

  • 基本操作
    # 默认显示的就是filter表
    > iptables -nvL
    # 查询filter表的链规则,并显示规则号码
    > iptables -t filter -nvL --line
    Chain INPUT (policy ACCEPT 120K packets, 244M bytes)
    num   pkts bytes target     prot opt in     out     source               destination
    1     369K  111M ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:22 /* test */
    
    Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
    num   pkts bytes target     prot opt in     out     source               destination
    
    Chain OUTPUT (policy ACCEPT 376K packets, 202M bytes)
    num   pkts bytes target     prot opt in     out     source               destination
    
    Chain CUSTOM_CHAIN (0 references)
    num   pkts bytes target     prot opt in     out     source               destination
    
    # 删除INPUT Chan的策略
    > iptables -t filter -D INPUT 1
    
  • 禁止与开放一条链(勿对INPUT链进行操作)
    # 禁止FORWARD链
    > iptables -t filter -P FORWARD DROP
    
    # 开启FORWARD链
    # 需一同开启linux内核转发功能, echo 1 > /proc/sys/net/ipv4/ip_forward 
    > iptables -t filter -P FORWARD ACCEPT
    
  • 插入一条规则到filter表的INPUT链
    • -p,--protocol [tcp|udp|icmp] 不同的协议有不同的参数如tcp有,--sport,--dport,--tcp-flags, --src, --dst 等。
    • -j,--jump [ACCEPT|DROP|REJECT|RETURN|DNAT|SNAT|MASQUERADE|CUSTOM_CHAIN] 目标动作或跳转到对应链
    • -A,--append 追加规则(规则是从上往下匹配)
    • -I,--insert 默认从1号插入,可以知道号码
    # 开放目标端口 3306
    > iptables -t filter -I INPUT -p tcp --dport 3306 -j ACCEPT
    
    # 开放目标端口 3000:3306
    > iptables -t filter -I INPUT -p tcp --dport 3000:3306 -j ACCEPT
    
    # 禁用来源192.168.0.0/24的网段对3306发起TCP链接
    # tcp-flasg SYN,FIN,ACK 因为tcp需要发起tcp syn包进行链接
    > iptables -t filter -I INPUT -p tcp -s 192.168.0.0/24 --dport 3306 --tcp-flags SYN,FIN,ACK -j DROP
    
    # 为规则加备注
    > iptables -t filter -I INPUT -p tcp --dport 3306 -m comment --comment "mysql" -j ACCEPT
    
    # 数据包用户空间的状态匹配
    # 留存现有访问3306端口的链接,禁止新链接访问3306端口
    > iptables -t filter -A INPUT -p tcp --dport 3306 -m state --state ESTABILISHED,RELATED -j ACCEPT
    > iptables -t filter -A INPUT -p tcp --dport 3306 -m state --state NEW -j REJECT
    
  • DROP 与 REJECT 的区别
    # 直接丢弃数据包,不给任何回应信息,这时候客户端会感觉自己的请求入海了,过了超时时间才会有反应。
    > iptable -t filter -I INPUT -p tcp --dport 3306 -j DROP
    # 拒绝数据包通过,必要时会给数据发送端一个响应的信息,客户端刚请求就会收到拒绝的信息。
    > iptable -t filter -I INPUT -p tcp --dport 3306 -j REJECT
    
    • REJECT 可选的返回响应,icmp-net-unreachable icmp-host-unreachable icmp-port-unreachable icmp-proto-unreachable icmp-net-prohibited icmp-host-prohibited tcp-reset port-unreachable(默认响应)
      > iptables -A FORWARD -p TCP --dport 22 -j REJECT --reject-with tcp-reset
      

2.2 Nat 表 PreRouting / PostRouting 链

  • PreRouting / PostRouting 这两个链一般在防火墙上是非常常见。它们对应的场景如,包从外网进入内网,包从内网出外网,包从内网到内网的不同网段;

  • 示例一

    • 源地址(外网):111.1.1.1
    • 目标服务器(内网): 192.168.1.2:3306
    • 防火墙(内外网): eth0(111.1.1.2), eth1(192.168.1.1)
    # 开启转发,因为要把包的dst地址改变成非我们防火墙本机的地址
    > echo 1 > /proc/sys/net/ipv4/ip_forward 
    > iptables -t filter -P FORWARD ACCEPT
    
    # [包从外网进入内网]
    # 111.1.1.1 访问内网的目标服务器 192.168.1.2:3306
    # 把包的目标地址改成内网的地址 192.168.1.2
    > iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 3306 -j DNAT --to-destination 192.168.1.2:3306
    
    # [包从内网出外网]
    # 当目标服务响应后,想回包到外网 111.1.1.1。
    # 假设目标服务器的网关是我们本机的防火墙的内网地址 192.168.1.1,所以包会经过我们再回到外网 111.1.1.1
    # -d ! 192.168.0.0/24 , 表明目标地址非192.168.0.0/24网段的包
    > iptables -t nat -A POSTROUTING -i eth1 -d ! 192.168.0.0/24 -p tcp --sport 3306 -j SNAT --to-resource 111.1.1.2
    
    
  • 示例二

    • MASQUERADE 伪装一个连接意味着,我们自动获取网络接口的IP地址,而不使用--to-source。在动态的DHCP和拨号上网时有很好的效果。
    # 从eth0出去的包的源地址会伪装成eth0上的地址
    > iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
    
  • 说一个我困惑的知识点: 按照我以往的认识,认为回包的流量应该先后经过OUTPUT和POSTROUTING,所以我利用iptables -t nat -nvL去查看NAT表在OUTPUT链和POSTROUTING链上的packge计数器,结果发现没有上涨。最后寻找到一个解析,下面描述下大概意思。

    • NAT表只在连接状态是NEW的时候(也就是TCP的第一个握手包)才会执行计算,一旦改写关系存入了conntrack,那么这条连接后续的通讯就不会再过POSTROUTING和OUTPUT上面的NAT表了,而是直接换成了匹配conntrack来复原连接之前的改写状态。

2.3 Filter表 Forward 链

  • 一般不属于自身的IP但需要转发到别的目标,必要时还需要配合nat表进行改变目的地址或者源地址。

    # 如10.8.0.2 需要访问 192.168.0.2 (eth0: 192.168.0.1)
    # 转发 10.8.0.0/24 网段的ip
    > iptables -A FORWARD -s 10.8.0.0/24 -j ACCEPT
    > iptables -t nat -A POSTROUTING -p tcp -d 192.168.0.0/24  -j SNAT --to-source 192.168.0.10
    
    # 如 192.168.0.2 需要访问 10.8.0.2(eth1: 10.8.0.1)
    # 转发 192.168.0.0/24 网段的ip
    > iptables -A FORWARD -s 192.168.0.0/24 -j ACCEPT
    > iptables -t nat -A POSTROUTING -p tcp -d 10.8.0.0/24 -j SNAT --to-source 10.8.0.1
    

3. 一些场景

3.1 自定义链

  • 自定义链是用于方便管理一类业务的网络规则;
    # 在filter表中创建自定义链
    > iptables -t filter -N CUSTOM_CHAIN
    # 建立自定义链规则,开放22端口
    > iptables -t filter -I CUSTOM_CHAIN -p tcp --dport 22 -j ACCEPT
    # 查看规则
    > iptables -t filter -nvL CUSTOM_CHAIN --line 
    Chain CUSTOM_CHAIN (0 references)
    num   pkts bytes target     prot opt in     out     source               destination
    1        0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:22
    # 在INPUT 链中引用自定义链规则,让目标端口是22的包jump to CUSTOM_CHAIN链
    > iptables -t filter -I INPUT -p tcp --dport 22 -j CUSTOM_CHAIN
    
    # 修改链名字
    > iptables -E CUSTOM_CHAIN NEW_CUSTOM_CHAIN
    # 删除自定义链: 1. 链没有被引用; 2. 链中没有任何规则
    > iptables -X NEW_CUSTOM_CHAIN
    

3.2 负载均衡

  • -m 使用扩展模块statistic(是一个统计模块)支持random 和nth 两种模式,这里仅介绍random模式

  • 示例一

    # 计算公式
    # probability 设置概率
    # probability =1/(n−i+1)
    # n: 后端数量
    # i: 序号(从1)开始
    # 访问 192.168.29.135:80 随机分发到 192.168.29.135:90-91
    > iptables -A PREROUTING -t nat -p tcp -d 192.168.29.135 --dport 80 -m statistic --mode random --probability 0.5  -j DNAT --to-destination 192.168.29.135:9090
    > iptables -A PREROUTING -t nat -p tcp -d 192.168.29.135 --dport 80 -m statistic --mode random --probability 1  -j DNAT --to-destination 192.168.29.135:9091
    
  • 示例二

    # 使用mark 进行ip包打标识
    > iptables -t mangle -A PREROUTING -p tcp --dport 80 -j MARK --set-mark 1
    # 通过匹配 mark 标识来匹配并进行负载均衡
    > iptables -t nat -A PREROUTING -m mark --mark 1 -m statistic --mode random --probability 0.5  -j DNAT --to-destination 192.168.29.135:9090
    > iptables -t nat -A PREROUTING -m mark --mark 1 -m statistic --mode random --probability 1  -j DNAT --to-destination 192.168.29.135:9091
    

3.3 限制流量

  • -m limit
    # 限制3306端口的包的数量,限制100个包,100 * 1500Bytes / 1024 = 146KB/s
    > iptables -A INPUT -m limit -p tcp --dport 3306 --limit 100/s
    # --limit-burst 是最大的包数量 
    > iptables -A INPUT -m limit -p tcp --dport 3306 --limit-burst 1000 
    

3.4 限制链接

  • -m connlimit 限制链接数
    # --connlimit-above n 限制为多少个
    # --connlimit-mask n  掩码,默认是connlimit-mask 32 ,即每个IP如设置为0 那就是所有客户端只能连 n个
    # --reject-with 也可以尝试 icmp-host-unreachable 、icmp-port-unreachable
    > iptables -A INPUT -p tcp --dport 22 -m connlimit --connlimit-above 2 -j REJECT --reject-with  tcp-reset
    

4.参考

5.写在最后

  • 您都看到这了,给个赞👍再走吧;