欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

Linux 防火墙与流量调控的实践

最编程 2024-08-11 15:15:12
...

一. Linux 网络总览

1.1 流量的路径

在 Linux 中无论是跨机流量还是本机内部的流量收发均需要一条完整的链路:

image-20221011185828277

Tips:Linux 内核知道所有的本机的 IP 地址,只要发现目的地址是本机的 IP 地址,均会走 Loopback 回环设备。

1.2 路径中控制

tc 的控制与接口的 qdisc 相关,netfilter 的控制贯穿了整个协议栈:

image-20221011190228571

二. 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 优先级

image-20221011192003170

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 算法步骤,详细:

  1. tree 中自 leaf 向 root 逐层查找 CAN_SEND 状态的且有包的 Queue ;
  2. 如该层有多个 Queue 处于 CAN_SEND 状态,那先发优先级小的,相同则轮询,单次最小发送字节数由 Quantum 参数决定;
  3. 如处于 CAN_SEND 状态的是非 leaf Queue,那 Queue 会按照上两条规则,查找处于 MAY_BORROW 的子 QUEUE,并借 token 给它们。

3.2.4 ingress

tc 主要实现了 exgress 方向的流控细节,在 ingress 没有重复的实现,但可以配合 ifb 实现:

  • ifb 是只用于 TC 过滤的虚拟网卡,流量手工重定向到 ifb 后,ifb 基于 tc queue 处理后自动放回原网卡继续处理;

    image-20221011195524876

# 举例
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/