Iptables

基本介绍

netfilter是位于Linux内核空间的防火墙安全框架, 主要功能有网络地址转化NAT数据包内容修改数据包过滤

基本概念

iptablesprerouting, forward, postrouting, input, output五大

分别对应着路由前, 转发, 路由后, 进入本机, 从本机出

iptables_1

规则

指定匹配条件, 符合匹配条件则执行规则对应的动作

匹配条件有源地址Source IP, 目标地址Destination IP, 源端口Source Port, 目标端口Destination Port

动作作用
ACCEPT允许数据包通过
DROP直接丢弃数据包, 不给任何回应信息
REJECT拒绝数据包通过
SNAT源地址转换, 解决内网上网问题
MASQUEREADSNAT的特殊形式, 适用于动态的、临时会变的ip上
DNAT目标地址转换
REDIRECT在本机做端口映射
LOG在/var/log/messages文件中记录日志信息, 然后将数据包传递给下一条规则

每个上均有不同规则, 将规则按照功能进行集合就形成了

iptables默认有filter, nat, mangle, raw四个

的优先级为raw > mangle > nat > filter

作用
filter负责过滤功能, 防火墙
nat网络地址转换功能
mangle拆解修改封装报文功能
raw关闭nat表上启用的连接追踪机制

由于不同的分工不同, 部分仅能使用在部分上(下表CentOS 7?)

preroutingraw, mangle, nat
inputmangle, filter
forwardmangle, filter
outputmangle, nat, mangle
postroutingnat, mangle
rawprerouting, output
mangleprerouting, input, forward,output, postrouting
natprerouting, output, postrouting
filterinput, forward, output

基本操作

iptables -t TABLE_NAME -nvL CHAIN_NAME --line
# -t 指定table, 若未指定默认使用filter
# -n 不对ip地址进行反解
# -v 查看详细信息
# -x 显示详细计数值
# -L 列出所有规则
# --line 显示序号
## policy 默认策略
pktsbytestargetprotoptinoutsourcedestination
匹配报文个数匹配报文大小总和规则对应动作规则对应协议规则对应选项数据包流入接口数据包流出接口规则源地址规则目标地址

# 清空TABLE_NAME在CHAIN_NAME的所有规则
iptables -t TABLE_NAME -F CHAIN_NAME

# 删除指定num条规则
iptables -t TABLE_NAME -D CHAIN_NAME num

iptables -t TABLE_NAME -D CHAIN_NAME -s IP -j TARGET
# 删除TABLE_NAME在CHAIN_NAME中符合所有条件的规则
# -s 指定源IP
# -j 指定动作

iptables -t TABLE_NAME -I/A CHAIN_NAME -s IP -j TARGET
# 向TABLE_NAME在CHAIN_NAME中添加一条规则
# -I [num] 将规则插在最前/第num条
# -A 将规则插在最后条
# -s 指定源IP
# -j 指定动作

iptables -t TABLE_NAME -R CHAIN_NAME num -s IP -j TARGET
# 修改TABLE_NAME在CHAIN_NAME中第num条规则, 注意, 若要修改规则必须将所有参数加上, 否则未指定参数全会被改为默认值

# 修改默认策略
iptables -t TABLE_NAME -P CHAIN_NAME TARGET

例1:

root@VM-4-6-ubuntu:~# iptables -t filter -nvL INPUT --line
Chain INPUT (policy ACCEPT 3800 packets, 327K bytes)
num pkts bytes target             prot opt in out source    destination
1   400K 66M   YJ-FIREWALL-INPUT  all  --  *  *   0.0.0.0/0 0.0.0.0/0

默认策略为ACCEPT, 已接受3800个包, 共计327Kb
INPUT里边有一条filter表的规则, 源地址和目的地址均为所有IP地址, 所有协议均可, 数据流入和流出所有接口都可以, 若匹配上述条件则执行YJ-FIREWALL-INPUT动作

例2:

iptables -t filter -I INPUT -s 192.168.1.146 -j DROP

在INPUT链中filter表里插入新规则, 对于所有192.168.1.146发来的报文一律执行DROP

保存及恢复配置

iptables-save    > filepath
iptables-restore < filepath

匹配条件

基础匹配条件
# source      源地址
-s 192.168.134.154                 # 指定单个IP
-s 192.168.134.154,192.168.134.155 # 指定多个IP
-s 192.168.134.0/24                # 指定整个网段
! -s 192.168.134.154               # 对匹配条件取反
# destination 目的地址
-d 192.168.134.154                 # 指定单个IP
-d 192.168.134.154,192.168.134.155 # 指定多个IP
-d 192.168.134.0/24                # 指定整个网段
! -d 192.168.134.154               # 对匹配条件取反
# prot        报文协议
-p tcp,udp,udplite,icmp,icmpv6,esp,ah,sctp,mh # 指定报文协议(CentOS 7)
# in          网卡接口
-i eth0
# out
-o wlan0



拓展匹配条件
# tcp/udp模块 + multiport模块
## dport destination-port 目标端口 要求指定使用协议
-p tcp -m tcp --dport 22 # -m 指定拓展模块名称 dport和sport均由tcp拓展模块实现
-p tcp -m tcp --dport 22:25 # 连续端口
-p tcp -m multiport --dport 22,25,80 # 离散端口
-p tcp -m multiport --dport 22,25:80 # multiport模块仅能给予tcp,udp使用
## sport source-port      源端口  要求指定使用协议
-p tcp -m tcp --sport 22 # 与上同

# iprange模块 指定一段连续IP地址范围
## src-range   源地址所在范围
-m iprange --src-range 192.168.1.1-192.168.1.5
## dst-range 目的地址所在范围
-m iprange --dst-range 192.168.1.1-192.168.1.5

# string模块 字符串匹配
-m string --algo bm --string "abc" # 使用bm算法匹配 bm/kmp

# time模块 根据时间段匹配报文
-m time --timestart 09:00:00 --timestop 18:00:00 # 早上9点到下午6点
-m time --weekdays 6,7                           # 周六周日
-m time ! --weekdays 6                           # 可取反
-m time --monthdays 26,27                        # 每月26, 27号
-m time ! --monthdays 26                         # 可取反
-m time --datestart 2024-09-10 --datestop 2025-09-09 # 起止日期

# connlimit模块 设置并发限制
-m connlimit --commlimit-above 2 # 连接数大于2时匹配
-m connlimit --commlimit-above 2 --connlimit-mask 24 # C类网段连接数大于2时匹配

# limit模块 限制报文速度
-m limit --limit 10/minute # 每分钟最多10个包
-m limit --limit 10/minute --limit-burst num # 每分钟最多10个包, 空闲时最多有num个包通过
## minute second hour day

# tcp-flags拓展匹配条件 对tcp头的标志位进行匹配
-m tcp --tcp-flags SYN,ACK,FIN,RST,URG,PSH SYN # 对SYN,ACK,FIN,RST,URG,PSH标志位进行匹配, 其中SYN必须为1, 其他部分必须为0
-m tcp --tcp-flags ALL SYN # 与上述等价
-m tcp --syn # 与上述等价

# icmp模块 可用sport和dport
-p icmp -m icmp --icmp-type 8/0 # 匹配type为8, code为0的报文, 即ping请求报文
-p icmp -m icmp --icmp-type "echo-request" # 与上述相同

# state模块 实现连接追踪
## 所有报文分为5种状态
## NEW           连接中第一个包
## ESTABLISHED   NEW后的包
## RELATED       与其他报文有关系的包
## INVALID       无法识别/无状态
## UNTRACKED     未被追踪
-m state --state RELATED,ESTABLISHED # 对ESTABLISHED和RELATED包进行匹配

例:

iptables -I INPUT -s 124.220.94.103 -p tcp -m tcp --dport 22 -j REJECT
对124.220.94.103向本机22口发来的tcp报文进行拒绝, 即拒绝ssh

iptables -I INPUT -m iprange --src-range 192.168.134.154-192.168.134.255 -j DROP
对192.168.134.154到192.168.134.255范围内ip发来的请求一律进行拒绝

iptables -I INPUT -m string --algo bm --string "abc" -j REJECT
对明文含有abc的报文进行拒绝

iptables -I OUTPUT -p tcp -m tcp --dport 80 -m time --weekdays 6 -j REJECT
对每周六向本机80端口发来的报文进行拒绝

iptables -I INPUT -p tcp --dport 22 -m connlimit --connlimit-above 5 -j REJECT
iptables -I INPUT -p tcp --dport 22 -m connlimit ! --connlimit-above 5 -j ACCEPT
每个IP地址最多同时占5个22口的连接(需考虑默认策略)

iptables -I INPUT -p icmp -m limit --limit 10/minute -j ACCEPT
期望每分钟最多10个包通过, 但注意令牌桶算法以及默认策略

iptables -I INPUT -p tcp -m tcp --dport 22 --tcp-flags ALL SYN -j REJECT
对tcp报文中的标志位进行匹配, 若SYN位为1, 其他位为0, 则执行拒绝

iptables -I INPUT -p icmp -m icmp --icmp-type 8/0 -j REJECT
拒绝所有type8 code0的icmp报文, 即拒绝别人的ping请求报文

iptables -A INPUT -j REJECT && \
iptables -I INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
仅通过RELATED包RELATED包, 其他包全部拒绝

iptables_2

黑白名单

  • 黑名单, 默认策略为ACCEPT, 对特定报文进行拦截
  • 白名单, 默认策略为DROP, 允许特定报文通过

自定义链

iptables -t filter -N CHAIN_NAME # 创建自定义链

iptables -t filter -I INPUT -j CHAIN_NAME # 引用自定义链

iptables -t filter -E CHAIN_NAME NEW_CHAIN_NAME # 修改自定义链名字

iptables -X NEW_CHAIN_NAME # 删除自定义chain, 要求没有被引用且其中无规则

例.

iptables -N IN_WEB # 创建名为IN_WEB的自定义链
iptables -I IN_WEB -s 192.168.134.154 -j REJECT # 对192.168.134.154发来的报文一律拒绝
iptables -I INPUT -p tcp --dport 80 -j IN_WEB # 对于发往80端口的tcp报文一律转交IN_WEB

拓展动作

# REJECT
## --reject-with选项 设置提示信息
### 可用参数:
#### icmp-net-unreachable
#### icmp-host-unreachable
#### icmp-port-unreachable 默认
#### icmp-proto-unreachable
#### icmp-net-prohibited
#### icmp-host-pro-hibited
#### icmp-admin-prohibited
-j REJECT --reject-with icmp-host-pro-hibited # 设置提示信息为icmp-host-pro-hibited

# LOG 对符合条件的报文相关信息记录到日志中, 继续交给下面报文处理
# 日志位置在/etc/syslog.conf, 配置kern.warning /var/log/iptables.log
## --log-level选项, 指定日志级别, 有emerg, alert, crit, error, warning, notice, info, debug
## --log-prefix选项, 给相关信息添加标签, 不超过29个字符
-j LOG --log-prefix "test"

# NAT 网络地址转换 
# Source Network Address Translation + Destinationnetwork address translation
# SNAT解决内网上网问题, DNAT解决内网穿透问题
-j SNAT --to-source 121.248.201.8 # 将符合条件的报文源地址改为121.248.201.8
-j DNAT --to-destination 192.168.134.154:80 # 将符合条件的报文目的地改为192.168.134.154:80

# MASQUERADE 动态地址转换, 与SNAT功能类似但不用指明明确IP

# REDIRECT 本机端口映射
-j REDIRECT --to-ports 8080 # 将报文重定向到本机8080端口

例.

iptables -t nat -A POSTROUTING -s 192.168.6.0/24 -j SNAT --to-source 121.248.201.8
将192.168.6.0/24网段发来的所有报文源地址改为121.248.201.8, iptables会自动维护NAT表, 将响应报文的目标地址转换回来

iptables -t nat -A POSTROUTING -d 121.248.201.8 -p tcp --dport 3389 -j DNAT --to-destination 192.168.6.1:3389
对于发往本机121.248.201.8的3389端口的请求, 将其一律转交给192.168.6.1:3389, 注意SNAT双向通讯

iptables -t nat -IPOSTROUTING -s 192.168.6.0/24 -o eth0 -j MASQUERADE
对于192.168.6.0/24网段发来的报文一律改为eth0的地址转发

详细样例

wlan分析

# 暂时开启网络转发功能
echo 1 > /proc/sys/net/ipv4/ip_forward
sysctl -w net.ipv4.ip_forward=1
# 永久开启网络转发功能
echo "net.ipv4.ip_forward = 1" > /etc/sysctl.conf

iptables -t nat -A POSTROUTING -o !wlan0 -s 192.168.6.0/24 -j MASQUERADE
# 对于源地址为192.168.6.0/24网段, 目标网卡不是wlan0的报文进行动态SNAT

docker网络分析

iptables -t nat -nvL

PREROUTING

  • Chain PREROUTING (policy ACCEPT 963 packets, 29576 bytes)
pktsbytestargetprotoptinoutsourcedestination
28M1065MDOCKERall--**0.0.0.0/00.0.0.0/0ADDRTYPE match dst-type LOCAL

OUTPUT

  • Chain OUTPUT (policy ACCEPT 1021 packets, 65958 bytes)
pktsbytestargetprotoptinoutsourcedestination
00DOCKERall--**0.0.0.0/0!127.0.0.0/8ADDRTYPE match dst-type LOCAL

POSTROUTING

  • Chain POSTROUTING (policy ACCEPT 1212 packets, 77070 bytes)
pktsbytestargetprotoptinoutsourcedestination
208131335KMASQUERADEall--*!docker0172.17.0.0/160.0.0.0/0
00MASQUERADEtcp--**172.17.0.2172.17.0.2tcp dpt:10100
00MASQUERADEtcp--**172.17.0.3172.17.0.3tcp dpt:443

DOCKER

  • Chain DOCKER (2 references)
pktsbytestargetprotoptinoutsourcedestination
00RETURNall--docker0*0.0.0.0/00.0.0.0/0
3023158KDNATtcp--!docker0*0.0.0.0/00.0.0.0/0tcp dpt:10100 to:172.17.0.2:10100
11602599KDNATtcp--!docker0*0.0.0.0/00.0.0.0/0tcp dpt:443 to:172.17.0.3:443

分析:

首先在PREROUTING, 若数据包的目标地址类型属于本机系统的本地网络地址, 则跳转到DOCKER

在DOCKER中判断, 若是从docker0网卡流入的, 则直接返回

若报文不是从docker0网卡流入, 且是发给本机的10100端口, 则进行DNAT, 将其ip地址转为172.17.0.2(相当于容器启动时-p 10100:10100)

若报文不是从docker0网卡流入, 且是发给本机的443端口, 则进行DNAT, 将其ip地址转为172.17.0.3(相当于容器启动时-p 443:443)


在OUTPUT中, 若数据包的目标地址不是127.0.0.1, 且目标地址类型属于本机系统的本地网络地址, 则跳转DOCKER

在DOCKER中被无条件捕获并返回?为啥要这么来一下


在POSTROUTING中, 若报文ip是172.17.0.0/16网段, 流向的网卡不是docker0, 则进行动态网络地址转换

若报文源ip和目的ip均是172.17.0.2, 且目的端口是10100, 则进行动态网络地址转换

若报文源ip和目的ip均是172.17.0.3, 且目的端口是443, 则进行动态网络地址转换

iptables -t filter -nvL

FORWARD

  • Chain FORWARD (policy DROP 0 packets, 0 bytes)
pktsbytestargetprotoptinoutsourcedestination
8125818MDOCKER-USERall--**0.0.0.0/00.0.0.0/0
8125818MDOCKER-ISOLATION-STAGE-1all--**0.0.0.0/00.0.0.0/0
103M27GACCEPTall--*docker00.0.0.0/00.0.0.0/0ctstate RELATED,ESTABLISHED
2297K135MDOCKERall--*docker00.0.0.0/00.0.0.0/0
115M31GACCEPTall--docker0!docker00.0.0.0/00.0.0.0/0
00ACCEPTall--docker0docker00.0.0.0/00.0.0.0/0

DOCKER

  • Chain DOCKER (2 references)
pktsbytestargetprotoptinoutsourcedestination
3023158KACCEPTtcp--!docker0docker00.0.0.0/0172.17.0.2tcp dpt:10100
11594598KACCEPTtcp--!docker0docker00.0.0.0/0172.17.0.3tcp dpt:443

DOCKER-ISOLATION-STAGE-1

  • Chain DOCKER-ISOLATION-STAGE-1 (1 references)
pktsbytestargetprotoptinoutsourcedestination
115M31GDOCKER-ISOLATION-STAGE-2all--docker0!docker00.0.0.0/00.0.0.0/0
246M61GRETURNall--**0.0.0.0/00.0.0.0/0

DOCKER-ISOLATION-STAGE-2

  • Chain DOCKER-ISOLATION-STAGE-2 (2 references)
pktsbytestargetprotoptinoutsourcedestination
00DROPall--*docker00.0.0.0/00.0.0.0/0
126M32GRETURNall--**0.0.0.0/00.0.0.0/0

DOCKER-USER

pktsbytestargetprotoptinoutsourcedestination
247M61GRETURNall--**0.0.0.0/00.0.0.0/0

分析:

首先报文进入FORWARD, 被FORWARD 1无条件捕获跳转DOCKER-USER(猜测可能是docker留给用户修改的)

随后从DOCKER-USER返回, 被FORWARD 2无条件捕获跳转DOCKER-ISOLATION-STAGE-1

若报文是由docker0网卡流入, 但目的地不是docker0网卡, 则被DOCKER-ISOLATION-STAGE-1 1捕获, 前往DOCKER-ISOLATION-STAGE-2, 否则返回

若报文目的地是docker0网卡, 则直接丢弃(与上文矛盾, 所以没有任何匹配), 否则返回

回到FORWARD, 所有发给docker0网卡的RELATED和ESTABLISHED类型报文全部接受

继续FORWARD, 所有发给docker0网卡的报文捕获跳转DOCKER

如果该报文是由非docker0网卡发往docker0网卡, 目的地为172.17.0.2, 目标端口是10100, 则进行接受

如果该报文是由非docker0网卡发往docker0网卡, 目的地为172.17.0.3, 目标端口是443, 则进行接受

返回FORWARD, 若报文是从docker0网卡发往非docker0网卡, 则直接接收

若报文是从docker0网卡发往docker0网卡, 则直接接收


有点云里雾里)

最后修改:2025 年 03 月 14 日
赛博讨口子