背景
mwan太傻逼了。受不了
使用iptables尝试实现一下。
架构
两个部分
第一部分是均匀的给流量打mark标记。
第二部分是根据打的流量分别走不同的路由表
两条链打标记
WAN1数据标记:
(这里的WAN1是在mangle表中的链的名字,可以自行命名)
1
2
3
4
5
|
iptables -t mangle -N WAN1
iptables -t mangle -A WAN1 -j MARK --set-mark 1
#标记数据包
iptables -t mangle -A WAN1 -j CONNMARK --save-mark
#把数据包中的mark设置到整个连接中
|
WAN2数据标记:
1
2
3
|
iptables -t mangle -N WAN2
iptables -t mangle -A WAN2 -j MARK --set-mark 2
iptables -t mangle -A WAN2 -j CONNMARK --save-mark
|
把已存在连接中的mark设置到数据包中:
1
2
3
|
iptables -t mangle -N RESTORE
iptables -t mangle -A RESTORE -j CONNMARK --restore-mark
iptables -t mangle -A PREROUTING -m conntrack --ctstate ESTABLISHED,RELATED -j RESTORE
|
分发数据包
使用NTH模块公平分发新数据包到WAN1和WAN2:
1
2
3
4
5
6
7
8
9
|
iptables -t mangle -A PREROUTING -m conntrack --ctstate NEW -m statistic --mode nth --every 2 --packet 0 -j WAN1
iptables -t mangle -A PREROUTING -m conntrack --ctstate NEW -m statistic --mode nth --every 2 --packet 1 -j WAN2
-A PREROUTING:将规则附加到 PREROUTING 链中。PREROUTING 链用于在数据包到达系统之前对它们进行处理。
-m conntrack --ctstate NEW:这是一个条件匹配,用于检查数据包的连接状态是否为 NEW。NEW 表示这是一个新的连接或会话请求数据包。这个条件通常用于限制规则只应用于新的连接请求。
--every 2:每第 2 个数据包匹配这个规则,即一个规则匹配一个数据包,然后跳过一个数据包。
--packet 0:这是规则的索引,表示这个规则适用于每第 2 个数据包中的第一个数据包。如果索引为 0,表示匹配第一个数据包。
-j WAN1 对应的是相应的第几个数据包走哪个链
|
不同标记走不同路由表
设置路由表:
1
2
3
4
5
6
7
8
|
cat /etc/iproute2/rt_tables
#http://www.haiyun.me
255 local
254 main
253 default
0 unspec
252 wan1
251 wan2
|
设置路由表默认路由:
1
2
3
4
5
6
7
8
|
以wan1为例
root@OpenWrt:~# ip route show table wan1
default via 183.169.79.254 dev vth1
10.20.0.0/16 dev eth0 proto kernel scope link src 10.20.20.22 #这个是与lan口的通信,不然就会不通
183.169.64.0/20 dev vth1 proto kernel scope link src 183.169.68.19
|
根据iptables标记应用路由:
1
2
3
4
5
|
ip rule del from all fwmark 2 2>/dev/null # fwmark 2代表标记为2的数据包
ip rule del from all fwmark 1 2>/dev/null
ip rule add fwmark 1 table wan1
ip rule add fwmark 2 table wan2
ip route flush cache
|
最后禁用源地址验证:
1
2
|
cat /etc/sysctl.conf
net.ipv4.conf.default.rp_filter = 0
|
实践
成功。
校园网一共5个wan口,每个限速20mbps。
聚合后。

设计
我这里wan的名字和路由表的名字默认一样。
假设有一个lan
打标记与分发
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
#!/bin/bash
# 设置循环次数
count=5
# 循环计数变量
i=1
# 循环开始
while [ $i -le $count ]; do
# 构建变量名
mangleChain_name="wan${i}_chain"
wan_name="wan${i}"
eth_name="vth$i"
gateway="183.169.79.254"
# 新增打标记的链
iptables -t mangle -N $mangleChain_name
iptables -t mangle -A $mangleChain_name -j MARK --set-mark $i
#标记数据包
iptables -t mangle -A $mangleChain_name -j CONNMARK --save-mark
#把数据包中的mark设置到整个连接中
# 打印变量值
echo "wan_name: $wan_name"
# 增加计数
i=$((i + 1))
done
# 存储标记值
iptables -t mangle -N RESTORE
iptables -t mangle -A RESTORE -j CONNMARK --restore-mark
iptables -t mangle -A PREROUTING -m conntrack --ctstate ESTABLISHED,RELATED -j RESTORE
i=1
# 循环开始
while [ $i -le $count ]; do
# 构建变量名
mangleChain_name="wan${i}_chain"
wan_name="wan${i}"
eth_name="vth$i"
gateway="183.169.79.254"
# 均分分发
iptables -t mangle -A PREROUTING -m conntrack --ctstate NEW -m statistic --mode nth --every $count --packet $((i - 1)) -j $mangleChain_name
# 打印变量值
echo "wan_name: $wan_name"
# 增加计数
i=$((i + 1))
done
|
要删除 mangle 表格中 PREROUTING 链上的所有规则,您可以使用以下命令:
1
|
iptables -t mangle -F PREROUTING
|
初始化路由表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
# !/bin/bash
i=1
while [ $i -lt 6 ]; do
wan_name="wan$i"
eth_name="vth$i"
lan_route_ip="10.20.20.22" # lan的路由器ip
lan_ip="10.20.0.0/16" # lan的范围ip
gateway="183.169.79.254"
# 删除该表
ip route flush table $wan_name
wan_ip=$(ip -4 -br addr show dev $eth_name | awk '{split($3,a,"/"); print a[1]}')
ip rule add from all iif $eth_name lookup $wan_name
ip route add default via $gateway dev $eth_name table $wan_name
ip route add $lan_ip dev eth0 proto kernel scope link src $lan_route_ip table $wan_name
ip route add 183.169.64.0/20 dev $eth_name proto kernel scope link src $wan_ip table $wan_name
echo $wan_ip
echo #wan_name
i=$((i + 1))
done
|
标记转发到路由表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
#!/bin/bash
# 设置循环次数
count=5
# 循环计数变量
i=1
# 循环开始
while [ $i -le $count ]; do
# 构建变量名
mangleChain_name="wan${i}_chain"
wan_name="wan${i}" # wan的名字就是表的名字
eth_name="vth$i"
gateway="183.169.79.254"
# 将指定数据包发送到指定路由表
ip rule del from all fwmark $i 2>/dev/null
ip rule add fwmark $i table $wan_name
# 打印变量值
echo "wan_name: $wan_name"
# 增加计数
i=$((i + 1))
done
ip route flush cache
|
三个部分依次执行
ref
[OpenWRT/Linux多WAN带宽叠加使用iptables标记策略路由负载均衡]