本文深入探讨 Linux 系统中强大的 `ip rule` 命令,解释其在策略路由中的核心作用。从传统路由的局限性出发,详细讲解 `ip rule` 的参数、如何与多路由表协同工作,并通过多出口链路绑定和基于 `fwmark` 的应用流量分流等实际案例,展示其在复杂网络环境中的巨大潜力,助你掌握 Linux 高级网络配置的核心技能。

引言:告别传统路由的束缚

在复杂的网络环境中,单一的基于目的地的路由策略往往显得力不不心。当我们需要根据源IP、应用程序、服务端口甚至数据包标记来决定流量走向时,Linux 的 ip rule 命令就如同瑞士军刀般闪耀登场。它为我们打开了策略路由(Policy Routing)的大门,让网络管理变得前所未有的灵活与强大。

本文将深入探讨 ip rule 的核心概念、工作原理及其在各种复杂场景下的应用,助你驾驭 Linux 的高级路由功能。

传统路由的局限与策略路由的崛起

在没有 ip rule 的世界里,Linux 路由表主要依赖目的 IP 地址来转发数据包。这意味着所有发往同一目的地的流量都将遵循相同的路径。然而,在以下场景中,这种模式捉襟见肘:

  • 一台服务器拥有多个公网 IP,每个 IP 对应不同的出口链路。如何确保从特定源 IP 发出的流量从对应的出口离开?
  • 某些特定应用(如 VPN 客户端)的流量需要通过加密隧道,而其他普通流量则直连互联网。
  • 根据数据包的 TOS (Type of Service) 或 Firewall Mark (fwmark) 来划分优先级或走向。

策略路由(Policy Routing)正是为了解决这些问题而生。它允许我们定义一套规则,这些规则可以根据数据包的更多属性(如源 IP、接口、FW mark 等)来决定使用哪个路由表进行查找,从而实现更加精细和灵活的流量控制。

ip rule 命令详解:构建你的路由策略

ip rule 命令是管理 Linux 策略路由规则的核心工具。它的基本语法和工作机制如下:

规则的结构与优先级

每条 ip rule 规则都包含一个优先级(priority)和一组匹配条件(selector),以及一个或多个动作(action)。系统会按照优先级从低到高(数字越小优先级越高)的顺序逐条匹配规则,一旦匹配成功,就执行相应的动作并停止查找。

ip rule add [SELECTOR] action [ACTION] [table TABLE_ID] [priority PRIORITY]

关键参数解析

  • priority PRIORITY:规则的优先级。数字越小,优先级越高。默认规则的优先级通常在 0 (local) 和 32766 (main) 之间。你可以为自定义规则选择一个合适的优先级。
  • from SOURCE_IP[/MASK]:匹配源 IP 地址。
  • to DEST_IP[/MASK]:匹配目的 IP 地址。
  • iif INTERFACE:匹配入站接口。
  • oif INTERFACE:匹配出站接口。
  • fwmark MARK[/MASK]:匹配由 iptables 设置的防火墙标记。这是策略路由中最强大的匹配条件之一,可以将应用层或传输层的特征映射到网络层。
  • uidrange START-END:匹配发起连接的用户 ID 范围。
  • lookup TABLE_ID:当规则匹配成功时,指定使用哪个路由表进行查找。这是最常用的动作。
  • prohibit:拒绝匹配的数据包,并发送 ICMP "Communication administratively prohibited" 错误。
  • blackhole:默默地丢弃匹配的数据包,不发送任何错误信息。
  • unreachable:拒绝匹配的数据包,并发送 ICMP "Destination Host Unreachable" 错误。

要查看当前系统中的所有策略路由规则,只需运行:

ip rule show

路由表:策略路由的基石

除了默认的 main 路由表之外,Linux 内核还支持多个路由表。这些路由表在 /etc/iproute2/rt_tables 文件中定义。常见的表包括:

  • 0 (unspec):未指定表。
  • 255 (local):存放本地路由,如本地 IP 地址、广播地址等,优先级最高。
  • 254 (main):默认路由表,存放所有非本地、非特殊路由。大多数用户配置的路由都在此表。
  • 253 (default):保留表,用于特殊的默认路由。
  • 以及用户自定义的表,通常 ID 大于 1。

ip rule 的核心就是根据匹配条件,将流量导向特定的路由表进行路由查找。

实战场景:ip rule 的魔法

场景一:多出口链路的源 IP 绑定

假设你的服务器有两块网卡 eth0 (IP: 192.168.1.100, 网关: 192.168.1.1) 和 eth1 (IP: 10.0.0.100, 网关: 10.0.0.1)。你希望从 192.168.1.100 发出的流量走 192.168.1.1 网关,从 10.0.0.100 发出的流量走 10.0.0.1 网关。

# 定义新的路由表
echo "100 isp1" >> /etc/iproute2/rt_tables
echo "101 isp2" >> /etc/iproute2/rt_tables

# 为 isp1 表添加路由
ip route add default via 192.168.1.1 dev eth0 table isp1
# 为 isp2 表添加路由
ip route add default via 10.0.0.1 dev eth1 table isp2

# 添加策略路由规则:源 IP 192.168.1.100 的流量查找 isp1 表
ip rule add from 192.168.1.100 table isp1 priority 10
# 添加策略路由规则:源 IP 10.0.0.100 的流量查找 isp2 表
ip rule add from 10.0.0.100 table isp2 priority 20

场景二:基于应用的流量分流(通过 fwmark)

假设你有一个 VPN 客户端,你希望它的流量通过 VPN 隧道,而其他所有流量直连。你可以通过 iptables 为 VPN 客户端的流量打上标记,然后 ip rule 根据这个标记进行路由。

# 定义 VPN 路由表
echo "200 vpn_table" >> /etc/iproute2/rt_tables

# 假设 VPN 隧道接口为 tun0,VPN 网关为 10.8.0.1
# 为 vpn_table 添加路由
ip route add default via 10.8.0.1 dev tun0 table vpn_table

# 使用 iptables 为特定用户(或进程)的流量打上 fwmark 10
# 这里以 UID 为例,实际中可以根据端口、目标IP等更复杂条件
iptables -t mangle -A OUTPUT -m owner --uid-owner 1000 -j MARK --set-mark 10

# 添加策略路由规则:fwmark 10 的流量查找 vpn_table
ip rule add fwmark 10 table vpn_table priority 50

这样,用户 ID 为 1000 的所有出站流量都会被标记为 10,然后根据 ip rule 规则,查找 vpn_table 并通过 VPN 隧道转发。

高级考量与持久化

  • 持久化配置: ip ruleip route table 命令在重启后会失效。
    • 在基于 Debian/Ubuntu 的系统上,可以使用 /etc/network/interfaces/etc/netplan/*.yaml 配置。
    • 在基于 RHEL/CentOS 的系统上,可以编辑 /etc/sysconfig/network-scripts/route-<interface>rule-<interface> 文件,或使用 NetworkManager。
    • 最通用的方法是编写启动脚本(例如放入 /etc/rc.local 或 systemd service unit)。
  • 调试技巧: 使用 ip rule showip route show table <TABLE_ID> 来检查规则和路由表。使用 tcpdump 结合 iptables LOG 规则可以帮助你追踪数据包的转发路径和标记。
  • 规则顺序: 仔细规划规则的优先级。一个宽松的规则放在高优先级可能会意外匹配并覆盖更具体的规则。

总结

ip rule 是 Linux 网络管理中一个极其强大且灵活的工具。通过理解策略路由的原理,并结合 ip routeiptables 的使用,你可以实现对网络流量的精细化控制,满足几乎所有复杂的路由需求,从简单的多出口负载均衡到高级的基于应用的安全隔离。掌握它,你就掌握了 Linux 高级网络配置的核心秘密。