一条请求如何找到服务:用 Linux Network Namespace 看懂 IP、MAC、路由与端口

简介: 本文通过Linux网络命名空间搭建客户端-路由器-服务器三节点实验,直观演示`curl http://10.10.2.2:8080`背后涉及的四大关键环节:路由表选路、ARP解析下一跳MAC、二层帧转发、端口分发至进程。强调IP(跨网段寻址)、MAC(同链路交付)、端口(主机内分发)的分工本质,并提供抓包验证、排障顺序与常见问题解析。(239字)

一次看似简单的 curl http://10.10.2.2:8080,至少包含四类定位问题:目标主机是谁、下一跳设备在哪里、数据应该交给哪个进程,以及返回流量如何走回来。

初学网络时常见的误区,是把 IP 地址、MAC 地址和端口理解成三种层级不同但作用相同的“地址”。它们实际上解决的是不同范围的问题:

  • IP 地址用于跨网络确定源主机和目标主机,并参与路由选择。
  • MAC 地址用于当前二层链路上的帧交付。经过路由器后,帧头通常会被重新构造。
  • 端口号用于把到达主机的 TCP 或 UDP 数据交给具体套接字。
  • 路由表决定数据包从哪个接口发出,以及应交给哪个下一跳。

只背定义很难形成排障能力。下面使用 Linux Network Namespace 在一台机器内创建客户端、路由器和服务器,完整观察一次跨网段请求。实验不依赖容器平台,但需要 Linux、root 权限,以及 ippingcurlpython3tcpdump 等工具。

地址分工:从应用请求到链路帧

假设客户端地址为 10.10.1.2/24,服务器地址为 10.10.2.2/24,中间路由器分别使用 10.10.1.1/2410.10.2.1/24

客户端准备访问 10.10.2.2:8080 时,内核先用目标 IP 查询路由表。由于目标不在客户端直连的 10.10.1.0/24 网段内,匹配结果是默认路由 via 10.10.1.1。这意味着 IP 包的目标地址仍是 10.10.2.2,但当前以太网帧必须交给网关 10.10.1.1

如果邻居表中没有网关对应的 MAC 地址,客户端会通过 ARP 询问“谁拥有 10.10.1.1”。得到响应后,它可以构造第一段链路上的帧:

以太网目标 MAC = 路由器客户端侧接口的 MAC
IP 目标地址      = 10.10.2.2
TCP 目标端口     = 8080

路由器收到帧后移除二层头,根据目标 IP 再查自己的路由表。它发现 10.10.2.0/24 是直连网络,于是在服务器侧重新构造以太网帧。此时源、目标 MAC 都会变化,但在没有 NAT 的条件下,IP 源地址和目标地址保持不变。服务器内核最终根据 TCP 目标端口 8080 找到监听套接字。

这也解释了一个重要现象:MAC 地址通常只在当前二层广播域内有意义,而 IP 地址负责端到端寻址,端口负责主机内部的进程分发。

搭建三节点实验网络

以下命令会创建三个独立网络命名空间。请在临时测试环境中执行,并先确认名称 clientrouterserver 未被其他实验占用。

sudo ip netns add client
sudo ip netns add router
sudo ip netns add server

sudo ip link add c0 type veth peer name r0
sudo ip link add r1 type veth peer name s0

sudo ip link set c0 netns client
sudo ip link set r0 netns router
sudo ip link set r1 netns router
sudo ip link set s0 netns server

sudo ip -n client addr add 10.10.1.2/24 dev c0
sudo ip -n router addr add 10.10.1.1/24 dev r0
sudo ip -n router addr add 10.10.2.1/24 dev r1
sudo ip -n server addr add 10.10.2.2/24 dev s0

sudo ip -n client link set lo up
sudo ip -n router link set lo up
sudo ip -n server link set lo up
sudo ip -n client link set c0 up
sudo ip -n router link set r0 up
sudo ip -n router link set r1 up
sudo ip -n server link set s0 up

为客户端和服务器配置返回路径:

sudo ip -n client route add default via 10.10.1.1
sudo ip -n server route add default via 10.10.2.1

路由器拥有两个直连网段,但 Linux 默认未必转发不同接口之间的 IPv4 数据包,因此还要在路由器命名空间中启用转发:

sudo ip netns exec router sysctl -w net.ipv4.ip_forward=1

查看各节点的地址和路由,确认配置是否符合预期:

sudo ip -n client -br addr
sudo ip -n router -br addr
sudo ip -n server -br addr
sudo ip -n client route
sudo ip -n router route
sudo ip -n server route

启动服务并验证连通性

在服务器节点启动一个仅用于实验的 HTTP 服务:

sudo ip netns exec server \
  python3 -m http.server 8080 --bind 10.10.2.2 \
  >/tmp/netlab-http.log 2>&1 &
SERVER_PID=$!

先测试三层连通性,再访问应用端口:

sudo ip netns exec client ping -c 2 10.10.2.2
sudo ip netns exec client curl -v --max-time 5 http://10.10.2.2:8080/

ping 成功只能说明 ICMP 往返路径基本可用,不能证明 TCP 8080 端口存在监听。curl 成功则进一步验证了路由、TCP 握手和应用服务。排障时应区分这两个层次。

在服务器节点检查监听套接字:

sudo ip netns exec server ss -lntp

预期应能找到绑定到 10.10.2.2:8080 的监听项。实际进程信息是否完整显示,取决于执行命令时的权限。

用抓包验证每一层的变化

打开两个终端,分别监听路由器两侧接口:

sudo ip netns exec router \
  tcpdump -eni r0 'arp or icmp or tcp port 8080'
sudo ip netns exec router \
  tcpdump -eni r1 'arp or icmp or tcp port 8080'

清空客户端邻居缓存后重新请求,可以更容易看到 ARP:

sudo ip -n client neigh flush dev c0
sudo ip netns exec client curl --max-time 5 http://10.10.2.2:8080/

对比两个接口上的输出时,应关注以下字段,而不是机械比较整行文本:

  1. r0 上出现客户端查询网关 MAC 的 ARP 请求。
  2. TCP 包在两侧的目标 IP 都是 10.10.2.2,源 IP 都是 10.10.1.2
  3. r0r1 上的以太网源、目标 MAC 不同,因为路由器重新封装了二层帧。
  4. 客户端源端口通常由内核临时分配,目标端口固定为 8080。不要假设某次实验中的临时端口在下一次仍相同。
  5. TCP 三次握手依次表现为 SYN、SYN-ACK 和 ACK,之后才传输 HTTP 数据。

还可以直接检查 ARP/邻居学习结果:

sudo ip -n client neigh show
sudo ip -n router neigh show
sudo ip -n server neigh show

邻居项可能经历 INCOMPLETEREACHABLESTALE 等状态。具体状态会随访问时机和内核邻居子系统的状态机变化,因此不应把某个瞬间的状态当作固定结果。

内核实际如何选择路径

与其只查看完整路由表,更直接的方法是询问内核如何路由某个目标:

sudo ip -n client route get 10.10.2.2
sudo ip -n router route get 10.10.2.2
sudo ip -n server route get 10.10.1.2

客户端的结果应指向网关 10.10.1.1 和接口 c0;路由器访问服务器时应走直连接口 r1;服务器返回客户端时应通过网关 10.10.2.1。这里最容易遗漏的是返回路由:请求能够到达服务器,并不代表响应一定知道如何返回客户端。

本实验没有配置 NAT,所以抓包能直接看到原始源 IP。实际家庭网络或云网络中可能存在 SNAT、DNAT、负载均衡或代理,它们会改变观察结果。判断地址是否应当保持不变前,必须先确认路径中是否存在这些组件。

常见问题与排查顺序

客户端提示 Network is unreachable

通常意味着没有匹配的路由。先执行:

sudo ip -n client route
sudo ip -n client route get 10.10.2.2

检查默认路由是否存在、网关是否属于接口的直连网段,以及接口是否处于 UP 状态。

能到网关,但不能到服务器

依次检查路由器的两个接口、IPv4 转发开关和服务器返回路由:

sudo ip -n router -br link
sudo ip netns exec router sysctl net.ipv4.ip_forward
sudo ip -n server route get 10.10.1.2

如果主机或命名空间中额外配置了 nftables/iptables 规则,还需要确认转发链没有丢弃流量。本实验本身不主动修改防火墙规则。

ping 成功,但 curl 连接被拒绝

“连接被拒绝”通常表示目标主机可达,但目标地址和端口没有服务监听,或者防火墙明确拒绝了连接。使用 ss -lntp 检查服务是否启动、端口是否正确,以及服务是否只绑定到了 127.0.0.1

curl 一直超时

超时和拒绝不同:超时通常表示报文或响应被静默丢弃。应同时在客户端、路由器两侧和服务器抓包,确认 SYN 到达了哪一段,以及 SYN-ACK 是否成功返回。只在请求发起端抓包,往往无法定位丢包位置。

抓不到 ARP

邻居缓存可能已经存在。可以查看 ip neigh,或在确认不会影响其他任务后刷新实验接口的邻居项。ARP 只用于同一二层链路上的 IPv4 邻居解析;客户端不会广播查询远端服务器的 MAC,而是查询下一跳网关的 MAC。

清理实验环境

结束后停止服务并删除命名空间。删除命名空间也会清理由其持有的虚拟接口:

sudo kill "$SERVER_PID" 2>/dev/null || true
sudo ip netns del client
sudo ip netns del router
sudo ip netns del server
rm -f /tmp/netlab-http.log

总结

定位一台主机上的服务不是单一地址完成的:路由表先根据目标 IP 选择出口和下一跳,ARP 把同链路的下一跳 IP 解析为 MAC,二层帧完成当前链路交付,路由器再为下一段链路重新封装,最终由 TCP 或 UDP 端口把数据交给目标套接字。

面对网络故障,可以按照“接口状态 → 路由选择 → 邻居解析 → 转发与防火墙 → 端口监听 → 应用协议”的顺序检查。这个顺序的价值在于把模糊的“网络不通”拆成可观测、可验证的具体环节,而抓包和 ip route get 正是连接理论与现场证据的关键工具。

相关文章
|
存储 缓存 网络协议
深入理解Linux网络——内核是如何接收到网络包的
一、相关实际问题 RingBuffer是什么,为什么会丢包 网络相关的硬中断、软中断是什么 Linux里的ksoftirqd内核线程是干什么
|
存储 缓存 网络协议
深入理解Linux网络——内核是如何发送网络包的
一、相关实际问题 1. 查看内核发送数据消耗的CPU时应该看sy还是si 2. 在服务器上查看/proc/softirqs,为什么NET_RX要比NET_TX大得多 3. 发送网络数据的时候都涉及那些内存拷贝操作 4. 零拷贝到底是怎么回事 5. 为什么Kafka的网络性能很突出
|
安全 Linux 定位技术
如何在CentOS中卸载LVM磁盘
综上,卸载LVM的过程就像是一场探险,需要小心翼翼地按照地图行动,不能偏离原定的路线。希望我手绘的这张地图对你有所帮助,让你能平安顺利地完成解除LVM的挑战。记住,整个过程中你都得小心谨慎,否则就可能会丢掉紧张刺激、惊险无比的宝石。在这个探险中,我为你解答了如何卸载LVM,提供了明确的指导和路线。人生就是一场探险,希望你在这个过程中学到的不仅仅是如何卸载LVM,更多的是如何在解决问题的过程中,认识自我,挑战自我,超越自我。那么,探险家们,还在等什么,让我们开始吧!
567 35
|
Linux C语言
教你在QEMU上运行RISC-V Linux
教你在QEMU上运行RISC-V Linux
|
网络协议 安全 网络安全
震惊!Python Socket竟能如此玩转网络通信,基础到进阶全攻略!
【9月更文挑战第12天】在网络通信中,Socket编程是连接不同应用与服务的基石。本文通过问答形式,从基础到进阶全面解析Python Socket编程。涵盖Socket的重要性、创建TCP服务器与客户端、处理并发连接及进阶话题如非阻塞Socket、IO多路复用等,帮助读者深入了解并掌握网络通信的核心技术。
604 6
|
Linux
Linux VXLAN小实验
该文介绍了如何在两台运行CentOS 7的Linux主机(T620和T630)之间建立VXLAN隧道。通过配置VXLAN ID、远程和本地IP,以及设置隧道接口和路由,实现10.0.10.12和10.0.10.13之间的通信。文中提供了详细的配置命令,并展示了成功ping通和抓包的验证结果。
452 4
|
机器学习/深度学习 算法 数据安全/隐私保护
两万多字诠释python经典基础算法之100题【内含思路、程序和答案】【python小白必备】
本文为最最基础的python基础算法题目、思路和答案,适合python初学者使用,可以当作python入门算法工具书,虽然不具有高深的算法,但是都是企业级算法用的频率最多的,这也是学好高级算法的必经之路。希望收藏、关注、点赞哦。
|
网络协议 安全 测试技术
ARP 神器:Macof 保姆级教程
ARP 神器:Macof 保姆级教程
|
负载均衡 算法 Java
【SpringCloud】Eureka原理分析、搭建Eureka服务、服务注册、服务发现
【SpringCloud】Eureka原理分析、搭建Eureka服务、服务注册、服务发现
598 3