Hacker News 中文摘要

RSS订阅

Rust中的无根Ping -- Rootless Pings in Rust

文章摘要

这篇文章解释了如何在不需要root权限的情况下用Rust发送ICMP ping请求。通常发送ping需要root权限创建原始套接字,但可以通过创建带有ICMP协议标志的UDP套接字来实现。作者提供了Rust代码示例,展示了如何创建这种套接字并构造ping包,同时指出Linux和macOS在标识符和校验和字段处理上的差异。

文章总结

标题:Rust中无需root权限的ping实现

来源:https://bou.ke/blog/rust-ping/

通常创建ICMP套接字发送ping请求需要root权限,但命令行工具ping却能在无root权限下运行。这是通过创建带有特定协议标志的UDP套接字实现的。由于网络上缺乏简单示例,作者在GitHub上用Rust发布了示例代码

核心实现分为三个部分:

1. 创建ICMP协议UDP套接字

使用socket2库创建IPv4数据报套接字: ```rust use socket2::{Domain, Protocol, Socket, Type}; use std::net::UdpSocket;

let socket = Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::ICMPV4))?; let socket: UdpSocket = socket.into(); ```

2. 构造并发送ping数据包

注意: - Linux和macOS处理方式不同 - Linux内核会覆盖标识符和校验和字段 - macOS则需要正确的校验和

```rust let sequence: u16 = 1; let mut packet: Vec = vec![ 8, 0, 0, 0, 0, 1, // ICMP包头 (sequence >> 8) as u8, (sequence & 0xff) as u8, // 序列号 b'h', b'e', b'l', b'l', b'o' // 负载数据 ];

// macOS需要手动计算校验和 let checksum = calculate_checksum(&packet); packet[2] = (checksum >> 8) as u8; packet[3] = (checksum & 0xff) as u8;

socket.send_to(&packet, "1.1.1.1:0")?; ```

3. 接收并解析响应

系统差异: - macOS响应包含IP头(需去除前20字节) - Linux响应不包含IP头

```rust let mut buffer = vec![0u8; 64]; let (size, fromaddr) = socket.recvfrom(&mut buffer)?;

[cfg(target_os = "macos")]

const IPHEADERLEN: usize = 20;

[cfg(not(target_os = "macos"))]

const IPHEADERLEN: usize = 0;

let data = &buffer[IPHEADERLEN..size]; let replytype = data[0]; // 应为0(回显应答) let replysequence = ((data[6] as u16) << 8) | (data[7] as u16); // 应与发送序列号匹配 let payload = &data[8..]; // 应包含原始负载数据 ```

注:延迟计算、丢包统计等扩展功能可由读者自行实现。

2025年11月

评论总结

以下是评论内容的总结,涵盖主要观点和关键引用:

  1. Linux与macOS在ICMP实现上的差异

    • 作者N_Lens指出两者在标识符、校验和及IP头处理上的不同,认为这些细微差异容易导致程序员犯错。
      引用
      "Linux overwrites identifier and checksum fields... macOS requires correct checksum calculation"
      "这种细微差异即使对有经验的程序员也会造成困扰"
  2. 与Rust语言的关联性争议

    • dmitrygr质疑文章标题强行关联Rust,认为核心知识点(无root权限发送ICMP包)与语言无关。
      引用
      "I struggled in vain to see what this has to do with rust... is language agnostic"
      "是否现在所有文章标题都要加上'用C'或'用汇编'?"
  3. Linux无权限ping的替代方案

    • raesene9指出可通过CAP_NET_RAW能力或ping_group_range系统参数实现,无需修改代码。
      引用
      "add the capability CAPNETRAW... or use sysctl net.ipv4.pinggrouprange"
    • jackfranklyn提到该方法在容器环境中特别实用,避免了setuid需求。
      引用
      "a lifesaver for container environments... default ping binary has setuid"
  4. 技术细节的批评与补充

    • stavros认为文章未深入解释UDP与ICMP的关系;messe纠正了"UDP socket"的说法,强调实际创建的是IP层数据报套接字。
      引用
      "Why does UDP work for ICMP?... None of that is explained"
      "You're not creating a UDP socket... conflates datagram and UDP"
  5. 其他观点

    • 工具推荐:qwertox提到Python库icmplib支持特权模式管理;
    • 潜在滥用风险:jeden调侃"ideal for ddos";
    • 404问题:PaoloBarbolini指出仓库链接失效。

争议焦点:文章价值(是否过度关联Rust)与技术准确性(套接字类型描述)。实用建议集中在Linux权限管理方案和跨平台兼容性挑战。