返回首页

Linux 内核中的 ICMP 隧道:TCP/UDP 封装

本文详细介绍了在 Linux 内核中实现 ICMP 隧道,将 TCP/UDP 流量封装到 ICMP echo 请求中。涵盖 Netfilter hooks、使用 sk_buff、tasklets 和向 loopback 注入数据包。

深入内核:TCP/UDP 如何隐藏在 ICMP echo 中
Advertisement 728x90

在 Linux 内核中实现 ICMP 隧道:将 TCP/UDP 封装在回显请求中

在 Linux 内核层面的 ICMP 隧道可以将 TCP/UDP 流量封装在 ICMP 回显请求数据包中,从而绕过标准的网络过滤器。这种方法适用于研究网络协议栈、测试数据包拦截以及理解 Netfilter 的工作原理。本文详细分解了内核模块的架构,该模块通过 NF_INET_POST_ROUTING 和 NF_INET_LOCAL_IN 钩子实现流量转换,并使用 tasklet 进行异步发送。

Linux 内核中的 ICMP 隧道架构

该模块由三个关键组件组成:两个 Netfilter 钩子和一个用于发送数据包的 tasklet。NF_INET_POST_ROUTING 钩子在数据包发送到网络之前拦截传出的 TCP/UDP 数据包,将其转换为 ICMP 回显请求,并将控制权传递给 tasklet。第二个钩子 NF_INET_LOCAL_IN 捕获传入的 ICMP 数据包,提取原始流量,并将其路由到回环接口以交付给应用程序。tasklet 通过 dev_queue_xmit 处理延迟数据包发送,从而最小化中断上下文中的阻塞。

钩子注册使用 NF_IP_PRI_FIRST 优先级,以确保优先处理。这一点至关重要,因为之前其他模块的干扰可能会破坏封装或解封装的完整性。内存管理依赖于 sk_buff——Linux 网络协议栈的核心结构——需要在错误情况下通过 kfree_skb 正确释放,并仔细预留头部空间。

Google AdInline article slot

output_hook 和 create_packet_output 的详细分解

output_hook 函数针对每个传出数据包调用。它将 ICMP 封装创建委托给 create_packet_output 函数,该函数会:

  • 检查协议是否为 TCP 或 UDP——如果不是,则返回 NULL,数据包继续其原始路由。
  • 通过 __ipv4_neigh_lookup 获取接收方的 MAC 地址,以构建 Ethernet 头部。
  • 使用 skb_linearizesk_buff 线性化,因为后续数据复制操作需要连续缓冲区。
  • 确定传输协议类型(UDP 为 0,TCP 为 1)、头部长度和有效载荷大小。
  • 分配新的 sk_buff,考虑头部下的预留空间(LL_RESERVED_SPACE)和尾部数据(needed_tailroom)。
  • 依次构建头部:Ethernet、IPv4、ICMP,将传输头部和数据复制到 ICMP 主体中。
  • 使用 ip_fast_csumip_compute_csum 计算 IP 和 ICMP 的校验和。
  • 返回就绪的数据包以进行发送。

一个关键细节是使用 icmp->un.echo.id 字段传递关于原始协议类型和流标识符的服务信息。这允许接收方在不使用 ICMP 结构外部额外元数据的情况下正确重构原始数据包。

处理传入数据包和回环路由

在接收方,input_hook 分析每个传入的 ICMP 数据包。如果匹配隧道格式(回显请求且 ID 字段中有已知模式),模块会:

Google AdInline article slot
  • 从 ICMP 主体中提取传输头部和数据。
  • 创建一个新的 sk_buff,模拟传入的 TCP/UDP 数据包。
  • 将目标设备设置为回环接口(dev_set_name(skb, "lo"))。
  • 将 MAC 地址更改为本地主机,并调用 netif_rx_ni() 将数据包注入网络协议栈。

这使得内核将数据包视为从外部而来,但通过 lo 接口处理。应用程序会原样接收数据,而不知晓封装过程。重要的是,此处不使用 NF_STOLEN——数据包不是“窃取”而是替换,因此在成功注入后返回 NF_ACCEPT

关键技术细节和限制

该实现面临几个技术限制:

  • 分片:ICMP 数据包在传输途中可能分片,但当前实现不处理分片——假设 MTU 足以完整封装。
  • 安全性:缺少加密或认证使得隧道易受伪造和中间人攻击。
  • 性能:每个数据包都需要分配新的 sk_buff、复制数据并计算校验和——这会产生 CPU 开销。
  • 仅限 IPv4:模块不支持 IPv6,因为它使用 ip_hdr__ipv4_neigh_lookup
  • MAC 依赖:需要目标 IP 的 ARP 条目;否则数据包将被丢弃。

尽管存在这些限制,该项目仍非常适合学习:它涵盖了 Netfilter 操作、内核内存管理、网络头部构建以及 OSI 层的实时交互。

Google AdInline article slot

关键要点

  • ICMP 隧道将 TCP/UDP 封装在回显请求中,从而绕过某些网络过滤器。
  • 使用最大优先级的 Netfilter 钩子在路由前后拦截流量。
  • tasklet 实现异步发送,而不阻塞中断上下文。
  • 在接收方,数据包注入回环接口,实现无缝交付给应用程序。
  • 该实现具有教育意义——由于缺少安全性和分片处理,不适合生产环境。

— Editorial Team

Advertisement 728x90

继续阅读