Linux 路由表:默认网关、转发与回程实战
现有命令速查里的 ip route 只能展示路由。本篇通过一次应用访问另一网段后端的故障排查,理解主机如何选择下一跳、为什么有路由仍不通。实验仅操作隔离的网络命名空间,不改宿主机默认网关。
学习顺序与验收#
这是一组从基础到日常生产排障的实践文档;先完成每篇实验,再做综合考核。阅读不等于掌握,以能独立定位、修复、验证和回退为准。
| 顺序 | 文档 | 验收目标 |
|---|---|---|
| 1 | 本页基础实验 | 去程、转发、回程和最长前缀 |
| 2 | 多网卡与策略路由 | 根据源地址选择出口 |
| 3 | 反向路径检查 | 修好非对称回程后恢复严格检查 |
| 4 | 防火墙与 NAT | 区分路由、FORWARD 和地址转换 |
| 5 | IPv6 与 MTU | 双栈及报文大小相关故障 |
| 6 | 持久化与安全回退 | 目标发行版重启与恢复验收 |
| 7 | 综合故障考核 | 七类随机故障与取证记录 |
1. 先看懂一张路由表#
default via 10.10.0.1 dev eth0 metric 100
10.10.0.0/24 dev eth0 proto kernel scope link src 10.10.0.10
10.20.0.0/24 via 10.10.0.1 dev eth0 metric 200| 字段 | 含义 |
|---|---|
10.10.0.0/24 |
直连网段,直接通过 eth0 找到邻居 |
via 10.10.0.1 |
下一跳网关的地址,不是最终目标地址 |
dev eth0 |
从哪个接口发送 |
src 10.10.0.10 |
未指定源地址时,路由建议使用的源地址;不是源地址匹配条件 |
default |
IPv4 的 0.0.0.0/0,没有更具体匹配时才使用 |
metric |
在同一表、相同前缀等可比路由中通常优先较小值;不能盖过更具体的前缀 |
proto kernel / scope link |
由内核生成;目的网段直接在链路上 |
普通目标路由先比前缀长度:/32 > /24 > /0。下一跳通常必须在当前接口可直接到达的链路内;设置网关不会自动把它变成能转发流量的路由器。ip route get 计算本机选路,不发送探测包,也不证明对端可达。ip-route 手册
# 以下只读命令可以在普通 Linux 主机执行。
ip -br address
ip -4 route show
ip -4 route get 10.20.0.10
ip -4 rule show
ip -4 route show table allip route 默认显示 main 表;Linux 实际先按 ip rule 的优先级选择查表规则。默认常见顺序为 local → main → default;数字越小越先匹配。策略路由可按源地址、流量标记等选表,出现多网卡/VPN 时不要只检查 main。ip-rule 手册
2. 实验环境:三台逻辑主机#
使用一台可丢弃的 Ubuntu 24.04 Linux VM(虚拟机),具备 sudo 权限。macOS 不能直接执行 ip netns,需进入 Linux VM。Namespace(命名空间)各自拥有接口、路由及网络栈;veth 是成对的虚拟网卡。
lr-app lr-router lr-db
eth0:10.10.0.10/24 ── app0:10.10.0.1/24
db0:10.20.0.1/24 ── eth0:10.20.0.10/24
HTTP :8080lr-db 用 HTTP(超文本传输协议)健康端点模拟私网后端,重点验收实际 TCP(传输控制协议)连接,不以 ping 成功代替服务可达。这是 Linux 路由实验,不是模拟 AWS VPC 的内部实现,也不部署生产数据库。
sudo apt-get update
sudo apt-get install -y iproute2 curl python3 tcpdump
# 下载本页配套 lab.sh 到当前目录,检查内容后执行。
sudo bash lab.sh setup
sudo ip -n lr-app route
sudo ip -n lr-router route
sudo ip -n lr-db route下载 lab.sh。脚本创建两个直连网段和后端,故意不加跨网段路由,且关闭实验路由器的转发。名称已存在则拒绝覆盖;失败会清理本次已创建资源。ip-netns 手册
3. 修复三处问题,逐步打通#
第一处:应用不知道如何去后端网段。 初始 ip route get 应报不可达。
sudo ip -n lr-app route get 10.20.0.10
sudo ip -n lr-app route add 10.20.0.0/24 via 10.10.0.1 dev eth0
sudo ip -n lr-app route get 10.20.0.10
sudo ip netns exec lr-app curl --noproxy '*' --connect-timeout 2 --max-time 3 http://10.20.0.10:8080/health选路已正确,但请求仍失败:路由器没有开启转发。 --noproxy '*' 避免环境代理绕开实验路径。
sudo ip netns exec lr-router sysctl -w net.ipv4.ip_forward=1
sudo ip netns exec lr-app curl --noproxy '*' --connect-timeout 2 --max-time 3 http://10.20.0.10:8080/health仍应失败:后端没有回到 10.10.0.0/24 的路由。 中间路由器已直连两个网段,无需额外静态路由;两个端点却分别需要远端路由。
sudo ip -n lr-db route add 10.10.0.0/24 via 10.20.0.1 dev eth0
sudo ip netns exec lr-app curl --noproxy '*' --fail --max-time 3 http://10.20.0.10:8080/health预期返回 backend-ready。整个路径没有 NAT(网络地址转换),后端看到的来源仍是 10.10.0.10。转发开关只控制主机是否转发跨接口报文;不是访问控制授权。内核 ip_forward
4. 默认路由不能覆盖更具体的路由#
sudo ip -n lr-app route add default via 10.10.0.1 metric 100
sudo ip -n lr-app route get 203.0.113.10
# 仅证明默认路由选向 10.10.0.1;该地址用于文档,本实验没有互联网出口。
sudo ip -n lr-app route add blackhole 10.20.0.10/32 metric 999
sudo ip netns exec lr-app curl --noproxy '*' --connect-timeout 2 --max-time 3 http://10.20.0.10:8080/health
# 请求应失败:/32 比 /24 和 default 更具体,即使 metric=999。
sudo ip -n lr-app route del blackhole 10.20.0.10/32 metric 999
sudo ip netns exec lr-app curl --noproxy '*' --fail --max-time 3 http://10.20.0.10:8080/health删除后恢复成功。路由命中 blackhole 时不会因为失败自动尝试默认路由;默认网关也不一定通向互联网,它只代表未知目的的下一跳。
5. 实际排障怎么查#
两个终端配合:终端 A 抓后端接口,终端 B 重复第 3 节请求。还可删除 lr-db 的回程路由重现超时,再原样恢复。
# 终端 A:仅抓本实验的合成流量,Ctrl-C 结束。
sudo ip netns exec lr-router tcpdump -ni db0 'tcp port 8080'
# 终端 B:核对目标监听、回程选路与下一跳邻居。
sudo ip netns exec lr-db ss -lnt
sudo ip -n lr-db route get 10.10.0.10
sudo ip -n lr-app neigh show| 现象 | 优先检查 |
|---|---|
Network is unreachable |
本端路由与策略表;不要先改服务端防火墙 |
| 下一跳邻居长期 INCOMPLETE/FAILED | 接口状态、网关地址和二层可达性 |
| 本机可访问,远端超时 | 去程、回程、路由器转发、防火墙、服务绑定地址 |
| 路由都正确仍失败 | nftables/iptables 的 INPUT、OUTPUT、FORWARD 链;云上还需检查 SG/NACL |
| 多网卡下单向通 | ip rule、源地址选择、非对称回程,以及 rp_filter(反向路径检查);不要直接全局关闭 |
6. 与 AWS 路由表的区别,以及清理#
EC2 的 Linux 路由表先决定把包从哪块网卡发给哪个下一跳;AWS 子网路由表再决定 VPC 内如何转发到 local、NAT、Peering 等目标。Linux 的 local 表用于本机地址,并不等于 AWS 的“整个 VPC CIDR → local”路由。
上述 ip route add 是运行时变更,重启或网络管理器重载可能消失。正式主机应由其实际使用的 NetworkManager、systemd-networkd 或 Netplan 持久化;不要混用多个管理器,更不要在 SSH 会话里直接删除主机默认路由试验。
sudo bash lab.sh cleanup清理只删除脚本记录的三个命名空间及其中的测试进程。宿主机路由、网卡和转发开关保持原样。继续对照 AWS 三层子网 与 请求路径,即可区分“主机选路”和“云网络转发”。