Linux 防火墙与流量调控的实践
一. Linux 网络总览
1.1 流量的路径
在 Linux 中无论是跨机流量还是本机内部的流量收发均需要一条完整的链路:
Tips:Linux 内核知道所有的本机的 IP 地址,只要发现目的地址是本机的 IP 地址,均会走 Loopback 回环设备。
1.2 路径中控制
tc 的控制与接口的 qdisc 相关,netfilter 的控制贯穿了整个协议栈:
二. iptables/netfilter
2.1 简介
iptables 与 netfilter 构成了 linux 下的有状态包过滤防火墙,实现了基于流的包过滤、重定向与 DNAT/SNAT 转换:
- netfilter 存在于 Linux 内核中,实际对流量做控制;
- iptables 实际上是 netfilter 的管理工具,帮助用户与 netfilter 交互。
2.2 概念
2.2.1 链-chain
在 Linux 协议栈中存在 5 个 Hook 点,每个点可以执行一串"链"的操作:
- PREROUTING - NF_IP_PRE_ROUTING
- FORWARD - NF_IP_FORWARD
- POSTROUTING - NF_IP_POST_ROUTING
- INPUT - NF_IP_LOCAL_IN
- OUTPUT - NF_IP_LOCAL_OUT
Tips: 用户可以自定义chain,在系统的 Hook 点将包放入 chain, 然后处理完毕使用 return 返回主链。
2.2.2 表-table
iptables 对于各种类型的控制做了分类形成表:
- Filter_table: 用于包过滤,适用链:
- INPUT FORWARD OUTPUT
- Nat_table: 修改源目地址并保存 session 用于处理流的返回包,适用链:
- DNAT - PREROUTING OUTPUT
- SNAT - INPUT OUTPUT POSTROUTING
- Mangle_table: 更*的修改包,适用链:
- INPUT PREROUTING FORWARD POSTROUTING OUTPUT
- Raw_table: 让包跳过 ip_conntrack 的追踪,适用链:
- PREROUTING OUPUT
2.2.3 优先级
2.2.4 状态追踪
包进入协议栈后,检查 raw 和完整性后,会基于连接的上下文而非单个包来做出规则判断,而上下文由 ip_conntrack 生成:
- NEW: 包合法且没有匹配的连接,则创建新连接;
- ESTABLISHED: NEW 在收到连接反方向的包后,迁移至 ESTABLISHED 状态;
- RELATED: 包不属于已有连接,但和已有连接有一定关系,是 helper connection,比如 FTP 的数据传输连接;
- INVALID: 包不属于已有连接,且因一些原因无法用来创建新连接,如无法识别、无法路由等;
- UNTRACKED: 在 Raw 中标记为 UNTRACKED 的包;
- SNAT: 包的源地址被 NAT 修改后会进入的虚拟状态,连接跟踪系统会据此在收到反向包时对地址做转换;
- DNAT: 包的目的地址被 NAT 会进入的虚拟状态,连接跟踪系统具体做反向转换.
tips: ip_conntrack 是有代价的,过多的 track 会造成新 session 无法建立从而造成丢包。
2.3 配置
2.3.1 命令与说明
# 命令格式:
iptables [-t table] command [match pattern] [action]
# -t table 对特定的表 - filter/nat/mangle/raw
# command:
# -A 添加
# -D 删除
# -I 插入
# -L 查看 - 查看时可额外添加 n(不尝试解析域名) 和 v(verbose 详细信息) 参数,eq -nvL
# match pattern:
# chain 类型:INPUT/FORWARD/OUTPUT/PREROUTING/POSTROUTING
# 包特征:-s -d -i -o -p --sport --dport, 可用 !取反
# action:
# LOG 将数据包相关信息记录在 /var/log 中
# SNAT 变更封包的源地址,跳到下一规则链
# DNAT 变更封包的目的地址,跳到下一规则链
# MIRROR 将来源地址和目的地址对调,终端过滤操作
# QUEUE 将封包放入队列,终端过滤操作
# CLASSIFY 对包做分类与 tc 配合使用
# RETURN 结束目前规则链中的过滤程序
# MARK 对封包做标记,用于后续过滤条件,会继续对比其他规则
# 举例:
iptables -t mangle -A OUTPUT -d 192.168.1.2 -j CLASSIFY --set-class 1:20
# -t mangle 指定 table 为 mangle
# -A 动作添加
# OUTPUT 指定 chain 为 OUTPUT
# -d 192.168.1.2 匹配包特征为目的为 192.168.1.2
# -j CLASSIFY 指定 action 为 CLASSIFY
# --set-class 1:20 指定 CLASSIFY action 的额外参数 class=1:20
2.3.2 配置持久化
# 方法一:
iptables-save > aa.conf # 将目前的配置保存到文件
iptables-restore < aa.conf # 从配置中导出
# 方法二:
sudo apt install iptables-persistent
sudo iptables-save -f /etc/iptables/rules.v4 # iptables-persistent 默认会调用 rules.v[4|6]
sudo netfilter-persistent reload # 恢复上次保存状态
三. traffic control
3.1 简介
TC 是一个工作在 Linux 内核中的,基于(队列与规则抽象(queueing discipline)的流量控制框架:
- TC 主要实现了对 egress 的流量的控制,可以实现复杂控制;
- 在 ingress 上仅实现了简单的 police 和重定向;
tips: ingress 方向 tc 虽然没有冗余实现,但是可以结合 ifb 实现对 ingress 的复杂控制。
3.2 概念
3.2.1 队列
Classless 的队列 - 对需要使用网卡处理的数据流不做区分按照统一的规则放入队列,在基于一定的算法从队列取出:
- [p|b]fifo: 先入先出;
- pfifo_fast: 根据 TOS 将队列划分到 3 个 band,每个 band 内部先入先出;
- red: Random Early Detection:随机早期探测,带宽接近限制时随机丢包;
- sfq: Stochastic Fairness Queuing 随机公平队列,按照 session 对流量排序,并循环发送每个 session 的数据包;
- tbf: Token Bucket Filter 令牌桶过滤器,使用令牌桶算法限速且允许一定的突发;
- netem: Network emulator 网络仿真,可以模拟网络的带宽/延迟/丢包/抖动这些特征。
Classfull 的队列 - 内部很多子抽象队列,用 filter 对流量区分的放入各个抽象队列,然后再基于一定的的算法从队列中取出:
- cbq: Class Based Qeueing 基于类别排队,基于时间估算,有缺陷,被 htb 取代;
- htb: Hierarchy Token Bucket 分层令牌桶,基于类别排队,基于分层令牌桶相关算法出队。
3.2.2 入队
对 Classless 的队列-直接入队,对 Classfull 的队列,有多种方式:
-
cgroup: 基于资源组对流做分类, 例子戳这里;
-
iptables: 使用 iptables 对流量分类;
iptables -t mangle -A OUTPUT -d 192.168.1.2 -j CLASSIFY --set-class 1:20 iptables -t mangle -A OUTPUT -d 192.168.1.3 -j CLASSIFY --set-class 1:101 iptables -t mangle -A OUTPUT -d 192.168.1.4 -j CLASSIFY --set-class 1:10
-
tc filter: 可以基于多种特征对流量做过滤,常用的比如 u32 来匹配包头特征, 更多举例;
# 常用 tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 .. # 举例 tc filter add dev eth0 protocol ip parent 1:0 u32 match ip src 192.168.0.2 flowid 1:2 tc filter add dev eth0 protocol ip parent 1:0 u32 match ip src 192.168.0.1 flowid 1:3 # 联动 iptables -A PREROUTING -t mangle -i eth0 -j MARK --set-mark 6 tc filter add dev eth1 protocol ip parent 1:0 prio 1 handle 6 fw flowid 1:1
3.2.3 出队
htb 单个 QUEUE 的状态机有三个:
- CAN_SEND: 自身 token 充足,发送的量小于定义的 rate;
- MAY_BORROW: 自身没有 token,但可借用父 Queue 的 Token,发送的量大于 rate 但小于 ceil;
- CANT_SEND: 不可发包,发送的量大于 ceil。
htb 算法步骤,详细:
- tree 中自 leaf 向 root 逐层查找 CAN_SEND 状态的且有包的 Queue ;
- 如该层有多个 Queue 处于 CAN_SEND 状态,那先发优先级小的,相同则轮询,单次最小发送字节数由 Quantum 参数决定;
- 如处于 CAN_SEND 状态的是非 leaf Queue,那 Queue 会按照上两条规则,查找处于 MAY_BORROW 的子 QUEUE,并借 token 给它们。
3.2.4 ingress
tc 主要实现了 exgress 方向的流控细节,在 ingress 没有重复的实现,但可以配合 ifb 实现:
-
ifb 是只用于 TC 过滤的虚拟网卡,流量手工重定向到 ifb 后,ifb 基于 tc queue 处理后自动放回原网卡继续处理;
# 举例
modprobe ifb
ip link set dev ifb0 up txqueuelen 1000
tc qdisc add dev eth1 ingress
tc filter add dev eth1 parent ffff: protocol ip u32 match u32 0 0 flowid 1:1 action mirred egress redirect dev ifb0
tc qdisc add dev ifb0 root netem delay 50ms loss 1%
tips: ifb 除了可以用于辅助 tc 实现对 ingress 流量的控制外,还可以使 tc 的规则可以同时在多个接口上生效。
3.3 配置
# 创建分类
tc qdisc add dev eth0 root handle 1: htb default 20
tc class add dev eth0 parent 1: classid 1:1 htb rate 200kbit(速率) ceil 200kbit burst 20k(突发流量)
# 创建过滤
tc filter add dev eth0 parent 1: prio 1(优先级) protocol ip u32 match ip sport 80 0xfff flowid 1:1
详细举例:戳这里
参考:
本机网络通信:https://mp.weixin.qq.com/s/J5igDYTE6sFa2NU7kc4yYw
流量控制与排队规则:https://blog.****.net/qq_44577070/article/details/123967699
iptables 规则持久化:https://www.jianshu.com/p/34a858a3c675
Cgroup 流量控制:https://www.jianshu.com/p/37937c6c0a82
Linux网络流控-htb算法解析:https://www.cnblogs.com/acool/p/7779159.html
Linux 下 TC 命令详解:https://blog.****.net/hexf9632/article/details/118635257
TC Howto:https://tldp.org/HOWTO/Traffic-Control-HOWTO/
上一篇: Linux防火墙——Firewalld原理与实战操作
下一篇: Linux查看、开启、关闭防火墙操作
推荐阅读
-
Linux防火墙:iptables与firewalld的比较
-
linux防火墙(firewalld/iptables)的设置与修改
-
Linux防火墙状态的查看与开启关闭命令
-
Linux 防火墙与流量调控的实践
-
常见的防火墙配置命令和系统服务管理工具在CentOS 8的Linux系统中: systemctl与firewall
-
在Linux服务器上追踪网络流量的18个实用命令与工具指南
-
简单易懂!详解Linux系统中网卡流量Tx和Rx的含义与区别
-
Linux中的几种防火墙工具:ufw、firewalld与iptables简介
-
简易指南:遵循的Linux脚本执行规则与常用命令实践
-
简易讲解:Unix/Linux编程中运用system()函数执行Shell命令的原理与实践