上一篇 下一篇 分享链接 返回 返回顶部

CN2 GIA、CMI与9929按ASN分流不生效,如何检查路由表与回程路径?

发布人:Minchunlin 发布时间:2026-10-06 22:01 阅读量:1

客户端访问海外物理机时,电信、移动、联通的连接都能建立,但回包集中从同一张网卡出去;或者分流规则已经添加,ip route get 仍然显示主路由表的默认出口。这类现象首先要检查“目标地址是否进入分流集合、策略规则是否命中、专用路由表能否完成查找”,再通过抓包确认实际出口,而不是先修改默认网关。

CN2 GIA、CMI、9929 按 ASN 分流不生效,还可能发生在主机之外:Linux 已经选对出口,但上游不接受该源地址,或者该出口后面的实际路径与预期不符。排查必须把主机选路、上游转发、客户端到服务器的去程分开验证;服务器上的策略路由只能直接控制本机发出的流量,不能单方面决定客户端的去程。

一、先确认“不生效”发生在哪一层

把线路名称、目标 ASN 和出口对应关系分开

Linux 常规策略路由并不能直接识别“这个 IP 属于哪个 ASN”。实际配置通常是:

目标 ASN → IP 前缀集合 → 目标地址匹配或报文标记 → 策略规则 → 专用路由表 → 网卡与网关。

一、先确认“不生效”发生在哪一层配图

CN2 网络通常关联 AS4809,CMI 国际骨干通常关联 AS58453,联通相关的 9929 网络关联 AS9929。但这些是线路或网络身份线索,不能直接当成全部国内用户的目标 ASN。

例如,电信客户端地址可能来自 AS4134,移动客户端地址可能来自 AS9808,联通客户端地址可能来自 AS4837,也可能涉及其他接入网络。把 AS4809 的前缀全部送入 CN2 出口,并不等于“所有电信用户都走 CN2”。

应先核对以下对应关系:

核对对象要确认的内容不正确时的表现
客户端地址服务器实际看到的源 IP匹配了用户地址,但实际对端是 CDN 或负载均衡节点
ASN 数据使用地址前缀的起源 ASN,而非路径中任意 ASN前缀集合过大、遗漏或归类错误
出口对应哪个网关实际连接哪条线路表名叫 CN2,实际默认网关却连到其他上游
源地址权限该出口允许发送哪些源 IP本机抓到出包,对端却收不到
策略范围IPv4、IPv6、本机业务还是转发业务IPv4 测试成功,实际业务走 IPv6

按 ASN 分流的关键不是规则里出现了 ASN 名称,而是业务对端 IP 能否命中正确的前缀集合。

固定一个可复现的测试连接

不要同时拿不同客户端、不同协议和不同源地址比较。先记录一组固定条件:

  • 客户端公网 IP、地址族和所属网络。
  • 服务器被访问的公网 IP及监听端口。
  • 预期出口、实际出口和故障时间。
  • 使用直连业务,还是经过 CDN、负载均衡或容器转发。

检查监听与连接:

ss -lntp
ss -ntp

如果服务器看到的连接对端不是用户公网地址,分流对象就应改为实际对端,或者重新评估架构。主机无法根据一个已经被上游替换的源地址,恢复原始客户端的路由归属。

后文命令以 Debian 12、Ubuntu 22.04/24.04 常见的 Linux、iproute2、nftables 环境为例,重点检查物理机本地服务的 IPv4 回包。容器转发、IPv6 和策略持久化需要分别核验。

二、从外部路径和物理出口开始,只做观察

先保存现场,不刷新规则

修改前准备带外控制台,并保持一个管理会话。尤其不要通过唯一的 SSH 连接直接替换默认路由或清空防火墙。

以下命令只保存配置,不修改转发行为:

umask 077
BACKUP_DIR=$(mktemp -d /tmp/a5-route-check.XXXXXX)

ip -4 addr show > "$BACKUP_DIR/addr-v4.txt"
ip -4 rule show > "$BACKUP_DIR/rule-v4.txt"
ip -4 route show table all > "$BACKUP_DIR/route-v4.txt"
sudo nft list ruleset > "$BACKUP_DIR/nft-ruleset.txt"

printf '现场记录目录:%s\n' "$BACKUP_DIR"

这些文件是排查记录,并不意味着可以直接作为完整恢复脚本执行。路由恢复应针对本次改动逐条回退;防火墙也优先删除本次新增对象,避免覆盖其他业务规则。

同时核验系统与工具:

cat /etc/os-release
uname -r
ip -V
nft --version
ip -br link
ip -br -4 addr

若系统实际采用其他防火墙管理器,应沿用现有管理方式,不要临时引入另一套规则形成冲突。

从两端分别测路径

在国内客户端测试到服务器的路径,得到的是去程。在服务器测试到客户端的路径,观察的是服务器发起探测时的出站路径,不能直接当成原有业务回包的证据。

有 mtr 的环境可执行:

mtr -4 -r -w -c 20 -T -P 443 SERVER_IP

服务器侧可固定源地址:

mtr -4 -r -w -c 20 -T -P 443 -a SERVER_SOURCE_IP CLIENT_IP

将占位符替换为实际地址。TCP 端口应选择允许测试的业务端口;若客户端不接受入站连接,终点不响应不能单独证明线路故障。

结果要这样解释:

二、从外部路径和物理出口开始,只做观察配图

  • 中间节点不回应,但后续节点和终点正常,不代表该跳存在真实业务丢包。
  • 仅从主机名、少量 ASN 标签或单次探测,不能完整确认线路产品属性。
  • 去程与回程可以不同,不能用国内客户端的一张路由图证明服务器回程已经分流。
  • 固定源地址的探测也未必命中业务使用的标记规则,因此必须结合真实业务抓包。

确认三条线路是否真的有主机侧选择入口

多线路物理机不一定有三张网卡,也可能通过 VLAN、多个网关或服务商侧策略区分出口。检查:

ip -4 route show table main
ip -d link show
ip neigh show

如果主机只有一个可达网关,且服务商并未提供可选择的其他下一跳,那么增加三个路由表不会凭空产生三条线路。此时应先向服务商确认线路交付方式、网关和源地址授权范围。

邻居状态 REACHABLE、STALE 通常不属于故障;持续 INCOMPLETE 或 FAILED 才需要检查网关地址、VLAN、掩码及二层连通性。

三、进入主机:依次查前缀、规则和路由表

检查前缀集合,而不只检查更新脚本

如果按 ASN 生成地址集合,需要同时检查“生成结果”和“内核实际加载结果”。

常见问题包括:

  • ASN 数据更新成功,但加载脚本失败。
  • 只更新了磁盘文件,内核里仍是旧集合。
  • IPv4 与 IPv6 混用。
  • 集合只包含少量骨干前缀,遗漏实际接入用户地址。
  • 集合更新期间出现空窗,部分连接落到默认出口。

使用 nftables 时,先查看实际规则与集合:

sudo nft -a list ruleset
sudo nft list sets

找到分类集合后,再查看具体内容:

sudo nft list set inet a5_asn_test cn2_v4

上述表名、集合名只是后文示例;已有配置应使用实际名称。核验重点是测试客户端 IP 是否被某个前缀覆盖,不能用“文件中有这个 ASN”替代地址匹配检查。

查看策略规则的优先级

ip -4 rule show

Linux 策略规则的 priority 数值越小,越先检查。常见的默认规则中,local 表优先于 main 表。

需要重点寻找:

  • 分流规则是否排在 main 查询之后。
  • 是否存在更早的源地址规则,把流量送入另一张表。
  • fwmark 的值和掩码是否与打标规则一致。
  • 是否有 blackhole、unreachable、prohibit 或 VRF 相关规则。
  • 相同优先级或重复规则是否让行为难以判断。

一个容易漏掉的区别是:规则匹配了,不代表这张表一定返回有效路由。 表里没有匹配路由时,通常还会继续查询后续规则;若表里存在默认路由,则可能直接结束本次查找。

对指定目的地址做完整路由查询

以下使用文档地址和实验地址展示逻辑,不应原样部署到公网:

出口示例网卡本机地址网关路由表
CN2eno1192.0.2.10/24192.0.2.1100
CMIeno2198.51.100.10/24198.51.100.1200
9929eno3203.0.113.10/24203.0.113.1300

测试目的地址用 198.18.0.10 代表 CN2 分类中的某个对端。执行:

ip -4 route show table 100
ip -4 route show table 200
ip -4 route show table 300

ip -4 route get 198.18.0.10
ip -4 route get 198.18.0.10 from 192.0.2.10
ip -4 route get 198.18.0.10 from 192.0.2.10 mark 0x100

这三个查询分别回答:

  1. 未指定源地址和标记时,内核如何选路。
  2. 已有连接以指定源地址回包时,如何选路。
  3. 报文带指定标记时,策略规则能否选择目标表。

ip route get 不会执行 nftables 规则。第三条显示正确,只能证明“已有这个标记时可以选对路”,不能证明真实报文被打上了标记。

如果带标记查询仍落入 main,先查规则和掩码;如果已经选中目标表,但出现不可达错误,则查表内路由、网关与接口状态。

三、进入主机:依次查前缀、规则和路由表配图

四、按结果分支修复,先隔离再扩大

分支一:目标表缺路由,或网关不可达

以下仅适用于表 100、200、300 尚未被其他业务使用,且三个接口地址已经正确配置的测试环境。正式环境应先替换为真实接口、地址和网关。

每张表同时放入网关所在网段和默认路由:

sudo ip -4 route add table 100 192.0.2.0/24 dev eno1 src 192.0.2.10
sudo ip -4 route add table 100 default via 192.0.2.1 dev eno1 src 192.0.2.10

sudo ip -4 route add table 200 198.51.100.0/24 dev eno2 src 198.51.100.10
sudo ip -4 route add table 200 default via 198.51.100.1 dev eno2 src 198.51.100.10

sudo ip -4 route add table 300 203.0.113.0/24 dev eno3 src 203.0.113.10
sudo ip -4 route add table 300 default via 203.0.113.1 dev eno3 src 203.0.113.10

采用 add 而不是直接 replace,是为了让已有配置冲突显式报错。出现 File exists 时应核对现有条目,不要直接覆盖。

这里的 src 是首选源地址,不会把已有 TCP 连接的回包源地址改成另一张网卡的 IP。客户端访问 192.0.2.10,业务回包仍可能以该地址为源,从 eno2 发出;如果 CMI 上游不允许这个源地址,主机选路正确也会失败。

需要回退时,只删除本次成功添加的默认路由和网段路由,例如:

sudo ip -4 route del table 100 default via 192.0.2.1 dev eno1
sudo ip -4 route del table 100 192.0.2.0/24 dev eno1

表 200、300 按对应条目回退,不要清空整张已被使用的表。

分支二:怀疑打标,先用单地址规则隔离

在确认优先级 10100 未被占用、且应位于相关主路由查询之前后,只对一个测试对端添加规则:

sudo ip -4 rule add priority 10100 to 198.18.0.10/32 lookup 100
ip -4 route get 198.18.0.10 from 192.0.2.10

随后建立一条新的测试连接并抓包。

  • 单地址规则有效,原来的 ASN 分流无效:重点检查集合、打标链和标记掩码。
  • 单地址规则也无效:继续检查更早规则、表内路由和上游源地址限制。
  • 只有指定源地址的查询异常:检查源地址规则或业务绑定方式。

测试完删除该规则,避免它长期绕过正常分类逻辑:

sudo ip -4 rule del priority 10100 to 198.18.0.10/32 lookup 100

这个方法比立即重写整套防火墙风险低,也更容易判断责任层。

分支三:规则存在,但本机回包没有被打标

物理机本地服务的回包经过 OUTPUT,不是转发业务的 FORWARD。如果只在入站 PREROUTING 设置报文标记,而没有适当保存、恢复连接标记,回复报文不会自动继承入站标记。

对“按回包目标 IP 分类”的本机服务,可以在 nftables 的 route 类型 output 链打标,使内核在标记变化后重新进行路由选择。

下面是独立测试配置。三组 198.18.* 前缀仅用于实验,不代表任何真实 ASN。部署前必须替换为审核后的前缀,并确认保留的标记位没有被其他组件使用。

table inet a5_asn_test {
    set cn2_v4 {
        type ipv4_addr
        flags interval
        elements = { 198.18.0.0/24 }
    }

    set cmi_v4 {
        type ipv4_addr
        flags interval
        elements = { 198.18.1.0/24 }
    }

    set unicom9929_v4 {
        type ipv4_addr
        flags interval
        elements = { 198.18.2.0/24 }
    }

    chain mark_local_reply {
        type route hook output priority mangle; policy accept;

        ip daddr @cn2_v4 counter meta mark set (meta mark & 0xfffff0ff) | 0x100
        ip daddr @cmi_v4 counter meta mark set (meta mark & 0xfffff0ff) | 0x200
        ip daddr @unicom9929_v4 counter meta mark set (meta mark & 0xfffff0ff) | 0x300
    }
}

将其保存为独立文件,先做语法检查:

sudo nft -c -f /root/a5-asn-test.nft

-c 仅检查,不应用。确认表名不存在、前缀互不冲突、已有规则不会覆盖这些标记后,再加载并添加规则:

sudo nft -f /root/a5-asn-test.nft

sudo ip -4 rule add priority 11000 fwmark 0x100/0xf00 lookup 100
sudo ip -4 rule add priority 11010 fwmark 0x200/0xf00 lookup 200
sudo ip -4 rule add priority 11020 fwmark 0x300/0xf00 lookup 300

这里仅修改 0xf00 对应的标记位,保留其他位。三个集合必须互斥,否则后匹配的规则可能覆盖前面的线路标记。

本例不实现“从哪条线进就从哪条线出”,也不覆盖容器转发。若需求是按入站线路保持回程,需要连接标记保存与恢复方案,不能把本例直接套用。

发生异常时,先撤销策略规则,再删除本次专用表:

sudo ip -4 rule del priority 11000 fwmark 0x100/0xf00 lookup 100
sudo ip -4 rule del priority 11010 fwmark 0x200/0xf00 lookup 200
sudo ip -4 rule del priority 11020 fwmark 0x300/0xf00 lookup 300
sudo nft delete table inet a5_asn_test

该回滚只适用于本次新建、无其他业务共用的测试表,不应使用 flush ruleset 清空全局规则。

五、出口正确仍失败:查源地址、反向校验和实际回程

用抓包确认真实报文,而不是只看查询结果

在预期出口和错误出口分别观察:

sudo tcpdump -ni eno1 'host 198.18.0.10 and tcp port 443'
sudo tcpdump -ni eno2 'host 198.18.0.10 and tcp port 443'

抓包需要权限,也可能包含业务信息,应缩小过滤范围和采集时间。

重点看四件事:

  • 请求从哪张接口进入。
  • 回复是否生成。
  • 回复从哪张接口离开。
  • 离开时的源 IP 是否属于上游允许的范围。

同时查看计数器:

sudo nft list chain inet a5_asn_test mark_local_reply
ip -s link show dev eno1
ip -s link show dev eno2

只有总网卡计数增长不足以证明测试流量命中,必须结合对端地址、端口和规则计数。

检查反向路径过滤,但不要直接关闭全部保护

多出口环境中,严格反向路径校验可能认为某个入站源地址应从另一张网卡到达,从而丢弃报文:

sysctl net.ipv4.conf.all.rp_filter
sysctl net.ipv4.conf.eno1.rp_filter
sysctl net.ipv4.conf.eno2.rp_filter
sysctl net.ipv4.conf.eno3.rp_filter

常见值为:0 关闭、1 严格模式、2 宽松模式。Linux 会结合 all 和对应接口的值判断,不能只修改一个值便认定检查已关闭。

确认严格校验与合法非对称流量冲突后,可以在维护窗口仅对相关接口测试宽松模式。先记录原值,再修改:

OLD_RPF_ENO2=$(sysctl -n net.ipv4.conf.eno2.rp_filter)
sudo sysctl -w net.ipv4.conf.eno2.rp_filter=2

测试结束按原值回退:

sudo sysctl -w "net.ipv4.conf.eno2.rp_filter=$OLD_RPF_ENO2"

放宽校验会改变源地址检查行为,应配合现有入口过滤评估。若反向查找依赖标记,还应核验 src_valid_mark 及入站标记是否实际存在,不能认为只在 OUTPUT 打标就解决了所有入站校验。

依据观测结果定位责任层

观测结果优先排查位置后续动作
分类计数不增长对端地址、前缀集合、链位置核对实际连接与集合覆盖
计数增长,仍走错误接口标记覆盖、掩码、规则优先级带 mark 查询并检查后续规则
查询选对表,真实报文走错网络命名空间、转发路径、已有连接确认业务是否真在主机 OUTPUT
入包可见,但无回复监听、应用、防火墙、反向校验先判断报文是否到达协议栈
回复从正确接口离开,对端收不到上游源地址限制、出口 ACL、下游路径提交五元组、时间与双端抓包
IPv4 正常,业务仍异常IPv6、DNS、连接复用分地址族测试并检查真实连接

本机选择正确网关,不等于端到端一定经过预期网络。 如果服务商统一接入后再做上游调度,主机路由表只能证明选择了交付的下一跳,后续路径还需要服务商侧和对端观测支持。

五、出口正确仍失败:查源地址、反向校验和实际回程配图

六、修复后复测,并观察配置是否再次漂移

验证至少包括三类客户端:分别选取实际属于电信、移动、联通接入网络的测试地址,核对其当前前缀分类,而不是只凭客户端名称分组。

每类都按相同顺序执行:

  1. 建立新连接,记录源地址、目的地址、协议和端口。
  2. 查看对应分类计数器是否增长。
  3. 检查带源地址、带标记的路由查询。
  4. 抓包确认实际出口和源 IP。
  5. 从客户端确认业务响应,再补充双向路径测试。

还要测试一个未归类地址,确认它仍走预期的默认出口;测试管理地址、内网和健康检查目标,确认没有被错误分流。不要为了让单个测试成功,把所有目标都划入某条线路。

运行验证通过后,再把配置交给现有网络管理工具持久化。先确认系统采用 Netplan、systemd-networkd、NetworkManager 还是其他方式,避免启动脚本和网络管理服务重复添加规则。网卡重连、服务重启与系统重启后的行为,都应安排带外条件下复测。

持续观察可围绕几项具体信号展开:ASN 前缀更新时间、每类规则计数、默认出口流量占比、接口错误、网关邻居状态,以及客户端网络变化后的路径差异。前缀更新应先校验非空、格式与重叠,再以事务方式更新集合,避免逐条删除再添加造成匹配空窗。

当三类测试连接都能证明“对端分类正确、标记正确、路由表正确、实际出口正确”,并且对端能够收到回包,才算完成主机侧闭环。此后若线路路径仍与预期不符,就应携带明确的测试时间、五元组、源地址和双向证据交由上游继续排查,而不是反复修改已经验证正确的本机规则。