【Linux网络系列】万字硬核解析网络层核心:IP协议到IP 分片重组、NAT技术及 RIP/OSPF 动态路由全景

【Linux 网络系列】万字硬核解析网络层核心:IP 协议到 IP 分片重组、NAT 技术及 RIP/OSPF 动态路由全景

嘿,重阳!纽约的3月周末(2026年3月7日晚9:27,估计你在家深挖内核源码或刷 Wireshark 抓包~),Linux 网络栈是操作系统灵魂之一,网络层(Layer 3)核心是 IP 协议——它像“快递员”,负责数据包跨网传输、路由和碎片处理。今天咱们来一场“万字硬核”详解,从 IP 基础到分片重组、NAT 技术,再到 RIP/OSPF 动态路由全景。基于 Linux 内核(net/ipv4 模块)和 RFC 标准(791/826 等),我会用表格、伪代码、Linux 命令和抓包示例,带你从原理到实战一步步拆解。内容超长,建议边读边试(用 iproute2/tc 工具)。走起!🚀

1. 网络层概述:IP 协议的“快递系统”角色

网络层是 OSI 模型的第三层,在 Linux 内核中由 net/ipv4 和 net/ipv6 实现。主要职责:逻辑寻址、路由选择、数据分片/重组、流量控制。IP(Internet Protocol)是其核心,无连接、不可靠(尽力而为),上层 TCP/UDP 补可靠性。

为什么 IP 是核心?

  • 全球互联:IP 地址唯一标识主机/网络,跨异构网(如 Ethernet/WiFi)。
  • 路由:静态/动态路由算法找最佳路径。
  • 痛点解决:链路层 MTU 限长,IP 分片适配;私有 IP 复用,NAT 穿透公网。
  • Linux 视角:内核用 sk_buff(skb)封装数据包,ip_forward() 处理转发。

IP 版本:IPv4(32 位地址,4.2 亿) vs IPv6(128 位,无限),本文焦点 IPv4(Linux 默认)。

2. IP 协议详解:头格式与字段硬核剖析

IP 数据报 = 头部(20-60 字节) + 数据。头部固定 20 字节,可选选项扩展。Linux 用 struct iphdr (include/uapi/linux/ip.h) 表示。

IP 头格式表格(核心 13 字段,基于 RFC 791):

字段位宽含义示例值Linux 处理
Version4协议版本(4=IPv4)。4skb->protocol = ETH_P_IP 检查。
IHL(Internet Header Length)4头部长度(单位 4 字节)。5(20 字节,无选项)。ip_hdr(skb)->ihl * 4 计算头长。
ToS/DSCP(Type of Service/Differentiated Services Code Point)8服务类型:优先级、延迟/吞吐/可靠性。现代用 DSCP/ECN(拥塞通知)。0x00(默认);0x10(高优先)。tc/qdisc 队列基于此 QoS。
Total Length16总长度(头+数据,max 65535)。1500(常见 MTU)。skb->len 验证。
Identification16分片 ID,唯一标识原包。随机(如 0x1234)。用于重组,ip_frag_reasm()。
Flags3标志位:DF(勿分片,bit1=1)、MF(更多分片,bit0=1)。0x02(DF=1)。DF=1 时 PMTU 发现(发 ICMP)。
Fragment Offset13分片偏移(单位 8 字节)。0(首片)。重组时排序。
TTL(Time To Live)8生存时间,每跳 -1,0 丢弃。64(Linux 默认)。ip_decrease_ttl(skb) 递减。
Protocol8上层协议。6(TCP);17(UDP);1(ICMP)。skb->transport_header 指向。
Header Checksum16头校验和(16 位补码和)。计算值。ip_fast_csum() 验证/计算。
Source Address32源 IP。192.168.1.1skb->saddr。
Destination Address32目的 IP。8.8.8.8skb->daddr,路由查找用。
Options(可选)变长(0-40 字节)扩展:RR(路由记录)、TS(时间戳)等。很少用。ip_options_compile() 处理。

IP 头伪代码(Linux 风格,简化 struct iphdr):

struct iphdr {
    __u8 ihl:4, version:4;  // 压缩字节
    __u8 tos;
    __be16 tot_len;
    __be16 id;
    __be16 frag_off;  // flags + offset
    __u8 ttl;
    __u8 protocol;
    __sum16 check;
    __be32 saddr;
    __be32 daddr;
    /* 选项... */
};

Linux 发送 IP 包过程(ip_output.c):

  1. ip_route_output_flow():路由查找(fib_lookup)。
  2. ip_make_skb():构建 skb。
  3. ip_local_out():校验和 + 输出。

抓包示例(用 tcpdump):sudo tcpdump -i eth0 -nn -vv ip 捕获 IP 包,Wireshark 解析头字段。

3. IP 分片与重组:MTU 适配的“切割重组”机制

为什么分片?:链路 MTU(Maximum Transmission Unit)不同(如 Ethernet 1500,PPP 576),大包需切片。Linux 默认 MTU 1500 (ifconfig)。

分片原理(RFC 791):

  • 入口:ip_fragment() 检查 skb->len > MTU && !DF → 分片。
  • 算法:按 MTU-头长切分,复制头(改 tot_len、offset、MF=1 除尾片)。
  • ID 共享:所有片用同一 Identification。
  • 偏移:首片 0,次片累加(单位 8 字节)。

伪代码(简化 ip_fragment):

int ip_fragment(struct sk_buff *skb, int mtu) {
    if (skb->len <= mtu || ip_hdr(skb)->frag_off & IP_DF) return;  // 无需分片
    int hlen = ip_hdrlen(skb);  // 头长
    int plen = mtu - hlen;  // 负载片长(8 字节对齐)
    while (skb->len > mtu) {
        struct sk_buff *frag = skb_clone(skb);  // 克隆片
        frag->len = plen + hlen;
        ip_hdr(frag)->tot_len = htons(frag->len);
        ip_hdr(frag)->frag_off = htons((offset >> 3) | IP_MF);  // MF=1
        skb_trim(skb, skb->len - plen);  // 剩余
        offset += plen;
        ip_send_check(ip_hdr(frag));  // 重新校验
        dev_queue_xmit(frag);  // 发送
    }
    ip_hdr(skb)->frag_off &= ~htons(IP_MF);  // 尾片 MF=0
    dev_queue_xmit(skb);
}

重组原理(ip_defrag()):

  • 出口:收集所有片(ID/源/目的/协议相同),用 frag_list 链表排序(offset)。
  • 条件:首片 offset=0、尾片 MF=0、全片到齐(总长匹配)。
  • 定时器:ip_frag_reasm() 超时丢弃(默认 30s,sysctl ipfrag_time)。

Linux 配置

  • sysctl -w net.ipv4.ipfrag_high_thresh=4194304(内存阈值)。
  • ip link set eth0 mtu 1400 调 MTU 测试分片。
  • 抓包:tcpdump -i eth0 'ip[6:2] & 0x1fff != 0' 捕分片包。

问题:分片易 DDoS(Teardrop 攻击,假片重组崩内核),现代用 PMTU(Path MTU Discovery,DF=1 + ICMP Fragmentation Needed)避免。

4. NAT 技术:私有 IP 的“公网穿透器”

NAT 定义(Network Address Translation,RFC 2663):改包源/目的 IP/端口,复用公网 IP。Linux 用 Netfilter/iptables 实现(nf_nat 模块)。

NAT 类型表格(基于连接跟踪 conntrack):

类型描述示例Linux 命令
SNAT(Source NAT)改源 IP/端口(内网 → 外网)。内网 192.168.1.10 → 公网 1.1.1.1。iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o eth0 -j MASQUERADE(动态 SNAT)。
DNAT(Destination NAT)改目的 IP/端口(外网 → 内网,端口转发)。公网 1.1.1.1:80 → 内网 192.168.1.10:80。iptables -t nat -A PREROUTING -d 1.1.1.1 -p tcp --dport 80 -j DNAT --to-destination 192.168.1.10:80
Full Cone NAT全锥形:任意外部主机可回包。安全低。iptables 默认类似。
Restricted Cone NAT限制锥形:仅发包外部主机可回。常见路由器。conntrack 跟踪。
Port Restricted Cone NAT端口限制:同端口回包。高安全。Linux 支持。
Symmetric NAT对称:不同外部端口不同映射。最严,P2P 难穿。nf_conntrack 实现。

NAT 工作原理(nf_nat_core.c):

  1. conntrack:nf_conn 表跟踪连接(5 元组:源/目的 IP/端口 + 协议)。
  2. 钩子:PREROUTING(DNAT)、POSTROUTING(SNAT)。
  3. 映射:改包 + 记录(nat_tuple),回包逆向改。

伪代码(简化 NAT 处理):

int nf_nat_packet(struct nf_conn *ct, struct sk_buff *skb) {
    if (ct->status & IPS_SRC_NAT) {  // SNAT
        ip_hdr(skb)->saddr = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip;
        // 端口改...
    } else if (ct->status & IPS_DST_NAT) {  // DNAT
        ip_hdr(skb)->daddr = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip;
    }
    ip_send_check(ip_hdr(skb));  // 重新校验
    return NF_ACCEPT;
}

Linux NAT 实战

  • 启用转发:sysctl -w net.ipv4.ip_forward=1
  • 查看 conntrack:conntrack -Lcat /proc/net/nf_conntrack
  • 问题:端口耗尽(65535),用 PAT(Port Address Translation,SNAT 变体)。

5. 动态路由协议:RIP vs OSPF 全景对比

动态路由用协议交换路由信息,适应拓扑变化。Linux 用 Quagga/FRR(bird)实现 RIP/OSPF。

RIP(Routing Information Protocol):距离向量协议,RFC 2453。

  • 版本:RIPv1(广播,classful);RIPv2(组播 224.0.0.9,支持 VLSM、认证)。
  • 度量:跳数(max 15,小网)。
  • 更新:每 30s 全表广播,超时 180s、垃圾 120s。
  • 防环:水平分割、毒性反转、触发更新。
  • Linux 配置(FRR):/etc/frr/ripd.conf
  router rip
  version 2
  network 192.168.1.0/24
  • 命令:vtysh -c 'show ip rip' 查看路由。

OSPF(Open Shortest Path First):链路状态协议,RFC 2328。

  • 区域:Backbone(Area 0)+ Standard/Stub/NSSA,分层防洪泛。
  • 度量:Cost(接口带宽倒数,默认 100M=1)。
  • 更新:洪泛 LSA(Link State Advertisement),Dijkstra 算法计算 SPF 树。
  • 类型:Router LSA(1)、Network LSA(2)、Summary(3/4)、External(5/7)。
  • 邻居:Hello(10s)、DD(数据库描述)、LSR/LSU(请求/更新)。
  • 防环:序列号 + 年龄字段。
  • Linux 配置(FRR):/etc/frr/ospfd.conf
  router ospf
  network 192.168.1.0/24 area 0
  • 命令:vtysh -c 'show ip ospf neighbor' 查看邻居。

RIP vs OSPF 对比表格

方面RIPOSPF
类型距离向量(Bellman-Ford)。链路状态(Dijkstra)。
收敛慢(全表更新,环路易)。快(增量 LSA,事件触发)。
规模小网(<15 跳)。大网(分区域)。
度量跳数。Cost(可自定义)。
组播RIPv2 是。是(224.0.0.5/6)。
认证MD5(RIPv2)。MD5/SHA。
Linux 工具ripd。ospfd。

动态路由实战:用 FRR 安装(apt install frr),启用 daemon,ip route show 查路由表。抓包:Wireshark 滤 rip 或 ospf。

结语:网络层硬核总结

从 IP 头到分片、NAT,再到 RIP/OSPF,网络层是 Linux 互联的基石——内核高效实现,工具如 iptables/frr 实战。掌握它,你的网络调试/优化如虎添翼。生产 tip:用 eBPF(tc-bpf)扩展 NAT/路由监控。想深挖?如“Linux 内核 IP 转发源码”或“OSPF LSDB 分析”?随时 ping 我!💪(参考:Linux 内核文档、RFC 系列)

文章已创建 4972

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部