Linux 策略路由深度解析 📅 2026/6/26 7:47:11 默认路由只能不知道去哪就走这条而策略路由Policy Routing能“HTTP 走这条、SSH 走那条、来自办公室的流量走 VPN”。本文从 Linux 内核路由框架出发系统解析ip rule、多路由表、iptables打标联动及相应场景示例。一、内核路由框架1.1 为什么需要策略路由普通路由决策只依赖目标 IP 地址查路由表数据包 → 查 main 路由表 → 匹配目标网段 → 送出策略路由则可以在查路由表之前先根据多种条件选择用哪张路由表数据包 → 查 RPDB规则库→ 命中规则 → 查指定路由表 → 送出 │ ├── 条件可以是源 IP、fwmark、TOS、入接口... └── 每条规则指向一张独立的路由表1.2 内核路由查找流程是否: 转发/本机发出否是否是是数据包到达是本地入站?查 local 表优先级 0遍历 RPDB 规则按优先级从小到大规则条件匹配?查规则指向的路由表找到路由?按该路由转发所有规则都不匹配?返回不可达1.3 三张默认路由表Linux 启动后自动创建三张路由表定义在/etc/iproute2/rt_tables$cat/etc/iproute2/rt_tables# reserved values255local# 本地地址和广播地址路由内核维护勿手动修改254main# 主路由表ip route 命令默认操作的表253default# 默认路由表通常为空可被 ip rule 引用0unspec# 未指定优先级关系数值越小优先级越高表名表号用途是否可自定义local255本地接口 IP、loopback、广播否内核自动管理main254用户添加的常规路由是default253备用默认路由是自定义1-252策略路由专用表是二、ip rule路由策略数据库2.1 核心概念ip rule管理的是RPDBRouting Policy DataBase路由策略数据库它决定每个数据包用哪张路由表。每条规则的组成优先级 : 匹配条件 → 动作查哪张路由表2.2 查看当前规则$iprule show0: from all lookuplocal# 本地流量优先32766: from all lookup main# 默认走 main 表32767: from all lookup default# 最后兜底走 default 表字段解读字段含义0/32766优先级priority数字越小越优先from all匹配条件来自所有地址lookup local/main/default动作查哪张表2.3 匹配条件一览策略路由的强大之处在于多维度的匹配能力# 按源地址 ipruleaddfrom192.168.1.0/24 table100ipruleaddfrom10.0.0.5 table200# 按目标地址 ipruleaddto8.8.8.8 table300# 按入接口 ipruleaddiif eth0 table100ipruleaddiif ppp0 table vpn# VPN 拨号接口# 按 fwmark防火墙标记ipruleaddfwmark1table100ipruleaddfwmark2table200# 按 TOS服务类型ipruleaddtos 0x10 table100# 低延迟流量# 按 fwmark 源地址组合 ipruleaddfwmark1from192.168.1.0/24 table100# 按 UID用户ipruleadduidrange1000-1000 table user_table# 按协议端口需要 iptables 配合# 先用 iptables 按端口打 fwmark再用 fwmark 匹配2.4 规则管理# 添加规则指定优先级ipruleaddfrom192.168.2.0/24 table200priority100# 删除规则iprule del from192.168.2.0/24 table200iprule del priority100# 清空所有规则危险操作会删掉默认规则iprule flush# 仅在指定优先级处插入ipruleaddfrom192.168.3.0/24 table300pref5000三、多路由表场景3.1 HTTP 走专线其余走默认需求本机192.168.0.36HTTP(80端口) 走网关192.168.0.3其余流量走192.168.0.1。网络拓扑默认流量HTTP 80本机 192.168.0.36网关 .1普通出口网关 .3专线/代理互联网互联网完整配置# Step 1: 查看当前路由和规则基准对比iproute showiprule show# Step 2: 注册自定义路由表# 向 /etc/iproute2/rt_tables 追加echo100 out_http/etc/iproute2/rt_tables# Step 3: 给自定义表添加路由# 注意不仅要加默认路由还要加直连网段路由iprouteadd192.168.0.0/24 dev eth0 table out_http# 直连网段iprouteadddefault via192.168.0.3 table out_http# 默认走 .3# Step 4: main 表保持默认路由iprouteadddefault via192.168.0.1# 或者已有则跳过# Step 5: 用 iptables 给 80 端口出站流量打上 fwmark 3iptables-tmangle-AOUTPUT-ptcp--dport80-jMARK --set-mark3# Step 6: 创建规则——fwmark3 的包查 out_http 表ipruleaddfwmark3table out_http# Step 7: 验证配置iprule showiproute show table out_http iptables-tmangle-LOUTPUT-n-v关键细节自定义路由表必须包含直连网段路由192.168.0.0/24 dev eth0否则本机发出的包在查out_http表时找不到到网关192.168.0.3的 ARP 路径导致目标不可达。3.2 双出口负载均衡需求两个 ISP 出口按源 IP 分流——办公室网段走 ISP-A服务器网段走 ISP-B。# 注册两张自定义表echo100 isp_a/etc/iproute2/rt_tablesecho200 isp_b/etc/iproute2/rt_tables# ISP-A 出口配置eth0, 网关 192.168.1.1iprouteadd192.168.1.0/24 dev eth0 table isp_aiprouteadddefault via192.168.1.1 table isp_a# ISP-B 出口配置eth1, 网关 10.0.0.1iprouteadd10.0.0.0/24 dev eth1 table isp_biprouteadddefault via10.0.0.1 table isp_b# 策略规则按源 IP 选择出口ipruleaddfrom192.168.1.0/24 table isp_a# 办公室走 ISP-Aipruleaddfrom10.0.0.0/24 table isp_b# 服务器走 ISP-B验证出站路径# 从不同源 IP 发起请求观察走的网关curl--interface192.168.1.100 https://ifconfig.me# 应显示 ISP-A 的公网 IPcurl--interface10.0.0.50 https://ifconfig.me# 应显示 ISP-B 的公网 IP3.3 VPN 分流目标直连其他走 VPN# VPN 拨号后产生 ppp0 接口echo50 vpn/etc/iproute2/rt_tables# VPN 表的路由iprouteadddefault dev ppp0 table vpn# 目标 IP 段走 main 表直连其余走 VPN# 需要配合 ipset iptables 做批量打标ipset create china hash:net# 把目标 IP 段加入 ipset省略通常借助脚本批量导入# ipset add china 1.0.1.0/24# ...# iptables: 目标不是目标 IP 的打上 fwmark 50iptables-tmangle-AOUTPUT-mset!--match-set china dst-jMARK --set-mark50# 规则: fwmark 50 → 走 VPN 表ipruleaddfwmark50table vpn四、iptables 打标联动4.1 为什么需要 iptables 配合ip rule本身只能匹配 IP 层元数据源/目标 IP、TOS、入接口无法看端口。需要通过 Netfilter 框架在数据包上打出 fwmark 标记ip rule再根据标记选路。4.2 fwmark 的工作流路由表RPDB(ip rule)Netfilter(iptables)应用程序路由表RPDB(ip rule)Netfilter(iptables)应用程序发出 HTTP 请求 (dport80)mangle/OUTPUT 链匹配 dport 80 → 打 fwmark3包进入路由决策规则 fwmark 3 命中→ 查表 out_http查 out_http 表default via 192.168.0.3从 eth0 送出下一跳 192.168.0.34.3 打标位置选择# PREROUTING: 所有入站包含本机接收和转发iptables-tmangle-APREROUTING-ptcp--dport80-jMARK --set-mark3# OUTPUT: 本机发出的包最常用iptables-tmangle-AOUTPUT-ptcp--dport80-jMARK --set-mark3# FORWARD: 经过本机转发的包iptables-tmangle-AFORWARD-ptcp--dport80-jMARK --set-mark3链适用场景PREROUTING本机作为路由器为转发流量做策略路由OUTPUT本机作为客户端发出流量最常用FORWARD本机作为网关转发其他主机的流量4.4 高级打标组合条件# 按端口 目标 IPiptables-tmangle-AOUTPUT-ptcp--dport443-d10.0.0.0/8-jMARK --set-mark10# 按用户 UIDiptables-tmangle-AOUTPUT-mowner --uid-owner1000-jMARK --set-mark20# 按进程 GIDiptables-tmangle-AOUTPUT-mowner --gid-owner2000-jMARK --set-mark30# 按连接状态iptables-tmangle-AOUTPUT-mstate--stateNEW-ptcp--dport22-jMARK --set-mark40# 恢复已有的 connmarkiptables-tmangle-AOUTPUT-jCONNMARK --restore-markCONNMARK连接级别的标记。配合--save-mark可以在连接的首包打标后自动应用到该连接的所有后续包避免每个包都重新匹配规则。4.5 持久化配置# iptables 规则持久化aptinstalliptables-persistent iptables-save/etc/iptables/rules.v4# ip rule/route 持久化# 方法一写入 /etc/network/interfacescat/etc/network/interfacesEOF auto eth0 iface eth0 inet static address 192.168.0.36 netmask 255.255.255.0 gateway 192.168.0.1 up ip route add default via 192.168.0.3 table out_http up ip rule add fwmark 3 table out_http EOF# 方法二systemd networkd 或 NetworkManager dispatcher 脚本cat/etc/NetworkManager/dispatcher.d/10-policy-routeEOF #!/bin/bash if [ $2 up ]; then ip route add 192.168.0.0/24 dev eth0 table out_http ip route add default via 192.168.0.3 table out_http ip rule add fwmark 3 table out_http fi EOFchmodx /etc/NetworkManager/dispatcher.d/10-policy-route五、复杂场景5.1 多出口故障切换Failover使用ip route的多跳multipath或检测脚本# 方案 A: 基于 metric 的静态备份iprouteadddefault via192.168.0.1 metric100# 主线路metric 低优先iprouteadddefault via192.168.0.3 metric200# 备线路metric 更高# 方案 B: 静态多路径加权负载 故障检测# 需要内核开启 CONFIG_IP_ROUTE_MULTIPATHiprouteadddefault nexthop via192.168.0.1 weight1\nexthop via192.168.0.3 weight1# 方案 C生产推荐: keepalived 检测脚本# 检测主线路通断自动切换路由5.2 基于 cgroup 的进程级路由# 创建 cgroupmkdir-p/sys/fs/cgroup/net_cls/viagw3echo0x00100003/sys/fs/cgroup/net_cls/viagw3/net_cls.classid# iptables 匹配 cgroupiptables-tmangle-AOUTPUT-mcgroup--cgroup0x00100003-jMARK --set-mark3# 将进程加入 cgroupecho$PID/sys/fs/cgroup/net_cls/viagw3/tasks# 至此该进程所有出站流量走 out_http 表5.3 命名空间级路由隔离# 创建独立网络命名空间ipnetnsaddns1# 在 ns1 中配置独立的路由策略ipnetnsexecns1ipruleaddfrom10.0.0.2 table100ipnetnsexecns1iprouteadddefault via10.0.0.1 table100# 在 ns1 中运行程序ipnetnsexecns1curlhttps://example.com六、nftables 现代替代iptables正在被nftables取代。同样的策略路由nftables 写法更简洁# nftables 替代 iptablesnftaddtable inet mangle nftaddchain inet mangle OUTPUT{typeroute hook output priority mangle\;}nftaddrule inet mangle OUTPUT tcp dport80meta markset3# 保存nft list ruleset/etc/nftables.confnftables vs iptables 对比维度iptablesnftables语法每个表/链独立命令统一层级语法性能每个规则独立内核模块单个nf_tables内核模块IPv4/IPv6分别管理inet族统一管理动态更新需替换整条规则支持原子规则添加七、排障方法7.1 策略路由排障三步法Step 1确认规则匹配# 查看规则优先级顺序iprule show|sort# 确认打标是否生效iptables-tmangle-LOUTPUT-n-v# 看 pkts 计数器是否增长Step 2确认路由表可达# 模拟查指定表iproute get8.8.8.8 mark3# 输出: 8.8.8.8 via 192.168.0.3 dev eth0 table out_http mark 3# 确认下一跳 ARP 可达ipneigh show|grep192.168.0.3Step 3确认接口和逆向路由# 数据包实际走的接口对不对iproute get8.8.8.8 from192.168.0.36# 抓包验证tcpdump-ieth0-nhost192.168.0.3 and port807.2 常见问题问题现象根因解决办法策略路由不生效优先级比 main 表默认规则低调整优先级确认ip rule顺序标记后依然走错出口自定义路由表缺少直连网段路由添加ip route add 192.168.0.0/24 dev eth0 table xxxiptables 打标无效果打在了错误链上如在 PREROUTING 打本机出站包本机出站用OUTPUT链重启后规则丢失未持久化使用 iptables-persistent 启动脚本反向路径过滤rp_filter丢包内核认为包从来路不对sysctl net.ipv4.conf.all.rp_filter0八、命令手册命令速查# ip rule iprule show# 查看所有规则ipruleaddfrom SRC table TABLE# 按源 IPipruleaddfwmark MARK table TABLE# 按防火墙标记ipruleaddiif IFACE table TABLE# 按入接口iprule del priority N# 按优先级删除# ip route iproute show table TABLE# 查看指定路由表iprouteaddNETWORK dev IFACE table TABLE# 添加网段路由iprouteadddefault via GW table TABLE# 添加默认路由iproute get DST[mark MARK][from SRC]# 模拟路由查找# iptables (mangle) iptables-tmangle-L-n-v# 查看 mangle 表带计数器iptables-tmangle-AOUTPUT-ptcp--dportPORT-jMARK --set-mark N iptables-tmangle-AOUTPUT-mowner --uid-ownerUID-jMARK --set-mark N# 持久化 iptables-save/etc/iptables/rules.v4路由表号约定1-252 : 用户自定义策略路由表 253 : default 表 254 : main 表默认 255 : local 表内核保留