代码改变世界

netfilter/iptables 防火墙

2019-01-26 14:18  云物互联  阅读(841)  评论(0编辑  收藏  举报

目录

iptables 与 netfilter

iptables 是运行在用户空间的防火墙配置工具,是 netfilter 项目的一部分,通过控制运行在 Linux 内核空间的 netfilter 模块,来管理网络数据包的处理和转发。之所以称之为配置工具是因为实际的防火墙过滤功能由内核模块 netfilter 提供,iptables 只是负责提供用户可操作的过滤 rules 配置接口。

简而言之,用户空间的 iptables 制定防火墙规则,内核空间的 netfilter 实现防火墙功能,iptables/netfilter(下文简称为 iptables)组合才是真防火墙。

NOTE:iptables 用于 ipv4,ip6tables 用于 ipv6。最新的 nftables 已经包含在 Linux kernel 3.13 中,以后会取代 iptables 成为主要的 Linux 防火墙配置工具。

Netfilter is a framework provided by the Linux kernel that allows various networking-related operations to be implemented in the form of customized handlers. Netfilter offers various functions and operations for packet filtering, network address translation, and port translation, which provide the functionality required for directing packets through a network and prohibiting packets from reaching sensitive locations within a network.

NOTE:Netfilter 是 Linux Kernel 的一个数据包处理模块,具有以下功能:

  • NAT(Network Address Translate,网络地址转换)
  • 数据包过滤
  • 基于协议类型的连接跟踪

在这里插入图片描述

工作机制

iptables 工作在 TCP/IP 的网络层,处理的是数据包(packet),具有五表五链
在这里插入图片描述
iptables 存在 “表(tables)”、“链(chain)” 和 “规则(rules)” 三个层面

其中表指的是不同类型的数据包处理流程,如:filter table 表示进行数据包过滤;nat table 则针对连接进行网络地址转换(NAT)操作。每个表中又可以存在多个链,系统按照预订的规则将数据包通过某个内建链,例如:将从本机发出的数据通过 OUTPUT 链。在链中可以存在若干规则,这些规则会被逐一进行匹配,如果匹配,则会执行相应的动作。如:修改数据包,或者跳转。跳转可以直接接受该数据包或拒绝该数据包,也可以跳转到其他链继续进行匹配,或者从当前链返回调用者链。当链中所有规则都执行完仍然没有跳转时,将根据该链的默认策略执行对应动作;如果也没有默认动作,则是返回调用者链。

规则(Rules)

规则(Rules)是用户预定义的,也是我们常说的防火墙规则,配置防火墙的主要工作就是添加、修改和删除这些规则

数据包的过滤基于规则。规则由一个 目标(target,数据包匹配所有条件后的动作)和很多 匹配(Xmatch,导致该规则可以应用的数据包所满足的条件)指定。iptables 根据规则的匹配条件来尝试匹配每个流经此规则的数据包,一旦匹配成功,则启用规则对应的动作来对数据包进行处理。

匹配

  • interface(e.g. eth0 或者 eth1)
  • 协议类型(e.g. ICMP、TCP 或者 UDP)
  • Source IP/Destination IP
  • Source Port/Destination Port

目标:可以是用户自定义的链、一个内置的特定目标或者是一个目标扩展。

  • ACCEPT:运行通过
  • DEOP:直接丢弃
  • REJECT:拒绝通过
  • SNAT:源地址转换
  • DNAT:目标地址转换
  • MASQUERADE:特殊的 SNAT,适用于动态变更的 IP
  • LOG:记录日志信息
  • QUEUE:将数据包移交到用户空间
  • RETURN:防火墙停止执行当前链中的后续规则,并返回到调用链
  • REDIRECT:端口重定向
  • MARK:做防火墙标记

链(chain)

**链(chain)**是由若干个顺序排列的规则组成的列表。默认的,链中不存在任何规则。用户可以向链中添加自己预期的防火墙规则。简单来说,链就是顺序执行规则的编排方式。在复杂的网络环境中,管理员需求这种可控的、有序执行的规则应用方式

链的默认规则通常设置为 ACCEPT,如果想确保任何包都不能通过规则集,则可以重置为 DROP。链中规则的次序非常关键,检查规则的时候,是按照从上往下的顺序进行的。所以谁的规则越严格,越应该放在靠前。默认的规则总是在一条链的最后生效,所以在默认规则生效前数据包需要通过所有存在的规则。

在这里插入图片描述

iptables 提供了以下 5 条链

  • INPUT 链:输入链。发往本机的数据报文通过此链。
  • OUTPUT 链:输出链。从本机发出的数据报文通过此链。
  • PORWARD 链:转发链。由本机转发的数据报文通过此链。
  • PREROUTING 链:路由前链(Pre-Routing),在处理路由规则(Routing)前通过此链,通常用于目的地址转换(DNAT)。
  • POSTOUTING 链:路由后链(Post-Routing),完成路由规则后通过此链,通常用于源地址转换(SNAT)。

NOTE:用户也可以加入自己定义的链,从而使规则集更有效并且易于修改。

表(tables)

当不同的链中的规则变得繁多而重复时,就会需求一种规则的分类方式。简单来说,表(tables)的本质就是规则集的组织形式。用户在实际的使用中,往往是通过表作为操作入口,对规则进行定义,将不同的表挂载到链上,实现了作用域更大的规则应用效果。

iptables 提供了以下五种表

  • filter 表:是默认表,提供数据包的过滤功能,用于防火墙规则。
  • nat 表:提供网络地址转换(NAT)功能,用于网关路由器。
  • mangle 表:提供数据包修改功能,拆解、修改、重新封装数据包。
  • raw 表:关闭 net 表启动的连接追踪机制。
  • security 表:用于强制访问控制网络规则。

每张表可挂载的链如下图所示:
在这里插入图片描述

网络数据包通过 iptables 的过程

                             ┏╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┓
 ┌───────────────┐           ┃    Network    ┃
 │ table: filter  │           ┗━━━━━━━┳━━━━━━━┛
 │ chain: INPUT  │◀────┐             │
 └───────┬───────┘     │             ▼
         │             │   ┌───────────────────┐
  ┌      ▼      ┐      │   │ table: nat        │
  │local process│      │   │ chain: PREROUTING │
  └             ┘      │   └─────────┬─────────┘
         │             │             │
         ▼             │             ▼              ┌─────────────────┐
┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅    │     ┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅      │table: nat       │
 Routing decision      └─────Routing decision ─────▶│chain: PREROUTING│
┅┅┅┅┅┅┅┅┅┳┅┅┅┅┅┅┅┅┅          ┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅      └────────┬────────┘
         │                                                   │
         ▼                                                   │
 ┌───────────────┐                                           │
 │ table: nat    │           ┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅               │
 │ chain: OUTPUT │    ┌─────▶Routing decision ◀──────────────┘
 └───────┬───────┘    │      ┅┅┅┅┅┅┅┅┳┅┅┅┅┅┅┅┅
         │            │              │
         ▼            │              ▼
 ┌───────────────┐    │   ┌────────────────────┐
 │ table: filter  │    │   │ chain: POSTROUTING │
 │ chain: OUTPUT ├────┘   └──────────┬─────────┘
 └───────────────┘                   │
                                     ▼
                             ┏╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┓
                             ┃    Network    ┃
                             ┗━━━━━━━━━━━━━━━┛

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

总结链、表和规则的关系

简单总结一下三者的关系。规则(rules)是数据包处理方式的描述、表(tables)是规则集的分类组织形式,链(chain)则是作为表的挂载点、以及表中规则集的有序执行的编排方式。

从网络数据包通过 iptables 的过程我们了解到,在 Linux 操作系统中 链的位置链与表的挂载关系 实际上是比较固定的。作为用户,我们需要关心的仅仅是如何在特定的表中添加、修改、删除规则来影响数据包在 Linux 操作系统中的流入、流出以及转发。

iptables 指令应用

制定 iptables 表规则思路

  1. 选择一张表(此表决定了数据包的处理方式,e.g. filter、nat)
  2. 选择一条链(此链决定了数据包的流经位置,e.g. INPUT、OUTPUT)
  3. 选择合适的条件(此条件决定了对数据包做何种条件匹配,e.g. Source IP、icmp)
  4. 选择处理数据包的动作,制定相应的防火墙规则(e.g. ACCEPT、DEOP)

iptables 语法格式

iptables [ -t 表名 ] 管理选项 [ 链名 ] [ 条件匹配 ] [ -j 目标动作或转发 ]

NOTE:不指定表名时,默认为 filter 表,不指定链名时,默认表示该表的所有链。除非设置了链的缺省策略,否则需要指定条件匹配。

在这里插入图片描述

help

Usage: iptables -[ACD] chain rule-specification [options]
       iptables -I chain [rulenum] rule-specification [options]
       iptables -R chain rulenum rule-specification [options]
       iptables -D chain rulenum [options]
       iptables -[LS] [chain [rulenum]] [options]
       iptables -[FZ] [chain] [options]
       iptables -[NX] chain
       iptables -E old-chain-name new-chain-name
       iptables -P chain target [options]
       iptables -h (print this help information)

Daemon

大多 Linux 发型版将 iptables 被做成了一个服务,启动,则将防火规则生效。反之,则将防火规则撤销。

systemctl enable iptables.service
systemctl start iptables.service

配置文件为 /etc/sysconfig/iptables/etc/iptables/iptables.rules

保存和加载规则

通过命令行添加规则,配置文件不会自动改变,所以必须手动保存:

# 备份与保存规则至指定文件
cp /etc/sysconfig/iptables /etc/sysconfig/iptables.bak
iptables-save > /etc/sysconfig/iptables

修改配置文件后,需要重新加载服务生效:

systemctl reload iptables

或者通过指定配置文件由 iptables 直接加载:

# 从指定文件加载规则
iptabls-restore < /PATH/FROM/SOME_RULE_FILE
    -n, --noflush:不清除原有规则    
    -t, --test:仅分析生成规则集,但不提交

查看规则

默认查看的是 filter 表的规则,可以指定表名或链名,也可以显示规则编号。

iptables -nvL [--line-numbers] [-t 表名] [链名] 

--line-numbers:列出规则编号
  • 五表:raw,nat,filter,mangle,security
  • 五链:INPUT、OUTPUT、FORWARD、PREROUTING、POSTROUTING

添加规则

添加规则有两种方式,一种是在链最后追加(-A)规则,另一种是将规则插入(-I)到链上的某个特定位置。

# 添加规则到指定的链中
iptables -A INPUT -s 192.168.1.5 -j DROP

# 插入规则到指定的链中,默认为插入到链首
iptables -I INPUT -p tcp --dport 17500 -s 10.0.0.85 -j ACCEPT -m comment --comment "Friendly Dropbox"

删除规则

# 通过编号删除链中的规则
iptables -D INPUT 8

修改规则

# 用新规则代替已存在的旧规则
iptables -R INPUT 2 -s 127.0.0.1 -d 127.0.0.1 -i lo -j ACCEPT

常规初始化配置流程

# 备份现有的规则
cp /etc/sysconfig/iptables /etc/sysconfig/iptables.bak

iptables -F  # 清空所有的防火墙规则
iptables -X  # 删除用户自定义的空链
iptables -Z  # 清空计数

# 开发所有向外出口
# NOTE:更加严格的安全规则,连出口也会严格限制
iptables -A OUTPUT -j ACCEPT

# 放行本地回环,本地回环 lo 地址 127.0.0.1 是仅在本机上使用的,它进、出都设置为允许
iptables -A  INPUT  -i lo -j ACCEPT

# 放行已建立的或相关的连接的
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# 允许被 ping
iptables -A INPUT -p icmp -j ACCEPT

# 放行 ssh 登录到本机
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# 配置默认链策略,拒绝所有
# NOTE:设置了默认策略,你将无法 ssh 连接到该机器。所以一般的会先设置 ssh 放行规则
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP

更多示例

放行所有网段的主机访问本机的 httpd 服务

# 入向规则
iptables -t filter -A INPUT -p tcp –dport 80 -m state –state NEW,ESTABLISHED -j ACCEPT
# 出向规则
iptables -t filter -A OUTPUT -p tcp –sport 80 -m state –state ESTABLISHED -j ACCEPT

端口重定向

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

NOTE:如果你在你的计算机上面运行了这个指令,它只会对连到你的机器上的外部 IP 产生效果。从本地端发起的连线不会遵循 nat 表上 PREROUTING 链的设置。如果你想让本地端也遵循规则,你需要将 lo 接口上的数据包输出由 80 端口转向到 8080 端口上面:

iptables -t nat -A OUTPUT -o lo -p tcp --dport 80 -j REDIRECT --to-port 8080

网络地址转换:假设办公室用小型局域网,由一台 Linux 主机作为路由器共享地址接入 Internet。局域网接口为 eth0,地址使用 192.168.0.0/24;Internet 接口为 eth1,使用的地址为 198.51.100.3。在局域网用户访问 Internet 时,源地址(SNAT)需要被转换为 198.51.100.3,若需要在局域网 192.168.0.2 上开启 HTTP 服务,将访问外部 TCP 80 端口的数据包重定向,则可以设置相应的目的地址(DNAT)转换。则使用规则:

# SNAT:由内到外的源地址转换 
iptables -t nat -I POSTROUTING -s 192.168.0.0/24 -o eth1 -j SNAT --to 198.51.100.3 

# DNAT:由外到内的目的地址转换
iptables -t nat -I PREROUTING -p tcp -d 198.51.100.3 --dport 80 -j DNAT --to 192.168.0.2 

NOTE:NAT 转发操作需要在 filter 表中 FORWARD 链中允许,并且打开系统的转发功能。

网络地址转换 && 端口重定向:本机的 2222 端口映射到内网虚拟机的 22 端口

iptables -t nat -A PREROUTING -d 210.14.67.127 -p tcp --dport 2222  -j DNAT --to-dest 192.168.188.115:22

指定数据包出去的网络接口
NOTE:该操作只对 OUTPUT,FORWARD,POSTROUTING 三个链起作用。

iptables -A FORWARD -o eth0

阻止 Windows 蠕虫的攻击

iptables -I INPUT -j DROP -p tcp -s 0.0.0.0/0 -m string --algo kmp --string "cmd.exe"

防止 SYN 洪水攻击

iptables -A INPUT -p tcp --syn -m limit --limit 5/second -j ACCEPT

指令选项解析

管理选项

  • 规则显示
-L, --list [chain]:列出规则;
-v, --verbose:详细信息; 
-vv 更详细的信息
-n, --numeric:数字格式显示主机地址和端口号;
-x, --exact:显示计数器的精确值,而非圆整后的数据;
--line-numbers:列出规则时,显示其在链上的相应的编号;
-S, --list-rules [chain]:显示指定链的所有规则;
  • 规则管理
-A, --append chain rule-specification:追加新规则于指定链的尾部; 
-I, --insert chain [rulenum] rule-specification:插入新规则于指定链的指定位置,默认为首部;
-R, --replace chain rulenum rule-specification:使用新的规则替换指定的旧规则;
-D, --delete chain rulenum:根据规则编号删除规则;
-D, --delete chain rule-specification:根据规则本身删除规则;
  • 链管理
-N, --new-chain chain:新建一个自定义链;
-X, --delete-chain [chain]:删除自定义的引用计数为 0 的空链;
-F, --flush [chain]:清空指定链上的规则;
-E, --rename-chain old-chain new-chain:重命名链;
-Z, --zero [chain [rulenum]]:置零计数器;
      NOTE:每条规则都有两个计数器
          1. packets:被本规则匹配到的数据包个数;
          2. bytes:被本规则匹配到的数据包大小之和;
-P, --policy chain target:制定链表的策略(ACCEPT | DROP | REJECT);

条件匹配(Xmatch)

条件匹配分为基本匹配和扩展匹配,扩展匹配又分为显示匹配和隐式匹配。

基本匹配:无需加载扩展模块,匹配规则生效

-p:指定规则协议,e.g. tcp/udp/icmp/all
-s:指定数据包的源地址,IP or Hostname
-d:指定数据包的目的地址
-i:输入接口,网卡设备
-o:输出接口                                              
!:取反

扩展匹配:需要加载扩展模块,匹配规则方可生效;

隐式匹配:使用 -p 选项指明协议时,无需同时使用 -m 选项指明扩展模块以及不需要手动加载扩展模块;

-p tcp
  --sport:匹配报文段的源端口;可以给出多个端口,但只能是连续的端口范围 
  --dport:匹配报文段的目标端口;可以给出多个端口,但只能是连续的端口范围
  --tcp-flags mask comp:匹配报文段的 tcp 标志位
-p udp
  --sport:匹配数据报端口;可以给出多个端口,但只能是连续的端口范围
  --dport:匹配数据报目标端口;可以给出多个端口,但只能是连续的端口范围
--icmp-type
  8:echo request,Ping 请求
  0:echo reply,接收 Ping 请求之后响应的 Ping 应答

显示匹配:必须使用 -m 选项指明要调用的扩展模块的扩展机制以及需要手动加载扩展模块;

  • multiport(多端口):以离散或连续的方式定义多端口匹配条件,最多 15 个。
iptables -I INPUT -d 172.16.100.7 -p tcp -m multiport --dports 22,80 -j ACCEPT
iptables -I OUTPUT -s 172.16.100.7 -p tcp -m multiport --sports 22,80 -j ACCEPT
  • iprange(IP 范围):以连续地址块的方式来指明多个 IP 地址匹配条件。
iptables -A INPUT -d 172.16.100.7 -p tcp --dport 23 -m iprange --src-range 172.16.100.1-172.16.100.100 -j ACCEPT
iptables -A OUTPUT -s 172.16.100.7 -p tcp --sport 23 -m iprange --dst-range 172.16.100.1-172.16.100.100 -j ACCEPT
  • time:指定时间范围。
iptables -A INPUT -d 172.16.100.7 -p tcp --dport 901 -m time --weekdays Mon,Tus,Wed,Thu,Fri --timestart 08:00:00 --time-stop 18:00:00 -j ACCEPT
iptables -A OUTPUT -s 172.16.100.7 -p tcp --sport 901 -j ACCEPT
  • string:对应用层的报文做字符串模式匹配检测。
--algo {bm|kmp}:字符匹配查找时使用算法
--string "STRING":要查找的字符串
--hex-string "HEX-STRING":要查找的字符,先编码成16进制格式
  • connlimit:根据每个客户端 IP 作并发连接数量限制。
--connlimit-upto n:连接数小于或等于 n 时匹配
--connlimit-above n:连接数大于 n 时匹配
  • limit:报文速率控制。
  • state:追踪本机上的请求和响应之间的数据报文的状态。
    • INVALID:无法识别的连接
    • ESTABLISHED:已建立的连接
    • NEW:新建立的连接
    • RELATED:相关联的连接,当前连接是一个新连接,但依附于某个已存在的连接
    • UNTRACKED:未追踪的连接

NOTE

  1. 对于进入的状态为 ESTABLISHED 都应该放行
  2. 对于出去的状态为 ESTABLISHED 都应该放行
  3. 严格检查进入的状态为 NEW 的连接
  4. 所有状态为 INVALIED 都应该拒绝

实战经验

为 OpenStack AIO 环境配置防火墙

  1. 让 AIO Ping 能通外网,但外网无法 Ping 通 AIO。
# 首先清空 AIO 的防火墙
iptables -F
iptables -X
iptables -Z

# 放行本机回环
iptables -A INPUT -i lo -j ACCPET
iptables -A OUTPUT -o lo -j ACCPET

# 放行本机发送 ICMP 8(echo request)请求数据包
iptables -A OUTPUT -p icmp --icmp-type 8 -j ACCEPT
# 放行接收 ICMP 0(echo reply)应答数据包
iptables -A INPUT -p icmp --icmp-type 0 -j ACCEPT

NOTE 1:如果不放行本机回环的话,无法 Ping 通外部网络,原因未明???
NOTE 2:如果希望只运行 Ping 通指定网段(e.g. 172.18.22.0/24)的话,需要指定目的 IP 网段。

iptables -R OUTPUT 1 -p icmp --icmp-type 8 -d 172.18.22.0/24 -j ACCEPT

在 host 172.18.22.220 抓包:

[root@localhost ~]# tcpdump -i ens160 -nnt src host 172.18.22.200
...
IP 172.18.22.200 > 172.18.22.220: ICMP echo request, id 49924, seq 1, length 64
  1. AIO 和外部可以互相 SSH
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT

NOTE 1:如果不放行 ssh 22 出口的话,外部无法 SSH 到本机,原因未明???
NOTE 2:因为 ssh 22 是一个 TCP 应用程序而非一个标准协议,所以是使用 -p tcp --dport/--sport 来指定的。
NOTE 3:如果希望指定网络的主机可以 SSH 到本机可以设定 INPUT 的 Source IP;如果希望指定本机只能 SSH 到指定网络的主机,可以设定 OUTPUT 的 Dest IP。e.g. 只允许 172.18.22.0/24 网段的主机可以 SSH 到本机:

iptables -R INPUT 3 -p tcp --dport 22 -s 172.18.22.0/24 -j ACCEPT
  1. AIO 的 80 端口(Dashboard)可以被指定的外部网络(172.18.128.0/24)访问
iptables -A INPUT -p tcp --dport 80 -s 10.8.8.201/24 -j ACCEPT

此时在 AIO 使用 tcpdump 抓包,有 172.18.128.0/24 => 10.8.8.201 => 172.18.22.200:80 的数据包:

但是没有 172.18.128.0/24 <= 10.8.8.201 <= 172.18.22.200:80 的数据包:
在这里插入图片描述
原因是没有添加 AIO tcp 80 的出口规则:

iptables -A OUTPUT -p tcp --sport 80 -d 10.8.8.201 -j ACCEPT

NOTE:一开始怎么都不通,是因为我将出口的 Dest IP 设置成为了 172.18.128.0/24,我没想到本地网络还有路由网关 10.8.8.201。全靠 tcpdump 抓包才能发现这个 GW,习惯使用 tcpdump 只有很多网络的问题都能有解决的思路了,非常棒的一个工具。

  1. 不开启本地回环的防火墙规则的话,openstack server list 指令无法执行,看来本地回环规则应该要默认开启才好。

参考文章

https://www.cnblogs.com/frankb/p/7427944.html
https://wangchujiang.com/linux-command/c/iptables.html
https://wiki.archlinux.org/index.php/Iptables_(简体中文)#表(Tables)