#packet-header #packet-parser #ipv6 #udp-packet #ipv4 #tcp #udp

无std etherparse

一个用于解析和写入一系列基于数据包的协议(EthernetII、IPv4、IPv6、UDP、TCP ...)的库。

26个版本 (14个重大更改)

0.15.0 2024年5月26日
0.14.2 2024年2月5日
0.13.0 2022年12月5日
0.12.0 2022年7月24日
0.1.4 2018年3月1日

#10 in 网络编程

Download history 11736/week @ 2024-05-03 12136/week @ 2024-05-10 12413/week @ 2024-05-17 11498/week @ 2024-05-24 12228/week @ 2024-05-31 11176/week @ 2024-06-07 12754/week @ 2024-06-14 12758/week @ 2024-06-21 13002/week @ 2024-06-28 13614/week @ 2024-07-05 15554/week @ 2024-07-12 14555/week @ 2024-07-19 17421/week @ 2024-07-26 14225/week @ 2024-08-02 14724/week @ 2024-08-09 11569/week @ 2024-08-16

每月60,743次下载
用于 57 个crates (47个直接使用)

MIT/Apache

2.5MB
49K SLoC

Crates.io docs.rs Build Status Github Build Status Gitlab Codecov

etherparse

一个用于解析和写入一系列基于数据包的协议(EthernetII、IPv4、IPv6、UDP、TCP ...)的无分配库。

目前支持的有

  • Ethernet II
  • IEEE 802.1Q VLAN标签头部
  • IPv4
  • IPv6(支持最常见的扩展头部,但不全部支持)
  • UDP
  • TCP
  • ICMP & ICMPv6(不支持所有消息类型)

使用方法

将以下内容添加到您的 Cargo.toml

[dependencies]
etherparse = "0.15"

etherparse是什么?

Etherparse旨在提供基本网络解析功能,以便轻松分析、转换或生成记录的网络数据。

一些关键点包括

  • 它完全用Rust编写并经过彻底测试。
  • 特别关注不使用分配或系统调用。
  • 该包仍在开发中,并将继续发生变化。
  • 当前开发重点是互联网和传输层中最流行的协议。

如何解析网络数据包?

Etherparse提供了两种自动解析网络数据包的选项

切片数据包

在这里,数据包的不同组件被分离,而不解析它们的全部字段。为每个头部生成一个切片,允许访问头部的字段。

match SlicedPacket::from_ethernet(&packet) {
    Err(value) => println!("Err {:?}", value),
    Ok(value) => {
        println!("link: {:?}", value.link);
        println!("vlan: {:?}", value.vlan);
        println!("net: {:?}", value.net); // contains ip
        println!("transport: {:?}", value.transport);
    }
}

如果您的代码不感兴趣于所有头部的所有字段,这是一个更快的选择。如果您只想基于头部或其字段的子集过滤或查找数据包,这是一个不错的选择。

根据您想要切片数据包的起点,请参阅以下函数

如果您想解析截断的包(例如,ICMP 消息中返回的包),则可以使用 "lax" 解析方法

将所有头部反序列化为结构体

此选项将反序列化所有已知头部,并将它们的内容传输到头部结构体中。

match PacketHeaders::from_ethernet_slice(&packet) {
    Err(value) => println!("Err {:?}", value),
    Ok(value) => {
        println!("link: {:?}", value.link);
        println!("vlan: {:?}", value.vlan);
        println!("net: {:?}", value.net); // contains ip
        println!("transport: {:?}", value.transport);
    }
}

当只访问少量字段时,此选项比切片慢。但是,如果您对大多数字段都感兴趣,或者您想要以修改后的值重新序列化头部,它可能是更快的选择。

根据您想要向下解包的起点,查看以下函数

如果您想解析截断的包(例如,ICMP 消息中返回的包),则可以使用 "lax" 解析方法

手动切片仅一个包层

还可以只切片一个包层

结果数据类型允许访问层和负载的头部,如果层有限制负载长度的长度字段,则自动限制负载长度(例如,IPv6数据包的负载将受IPv6头部中的“负载长度”字段限制)。

手动切片和解析仅头部

还可以仅解析头部。如果您只想切片头部,请参阅以下[NAME]HeaderSlice.from_slice方法的文档:

对于反序列化到相应的头部结构,请参阅以下内容:

如何生成伪造的数据包?

数据包构建器

PacketBuilder 结构体提供了一个高级接口,可以快速创建网络数据包。PacketBuilder 将自动设置可以从数据包内容和组成推断出的字段(例如校验和、长度、以太网类型、IP协议号)。

示例

use etherparse::PacketBuilder;

let builder = PacketBuilder::
    ethernet2([1,2,3,4,5,6],     //source mac
               [7,8,9,10,11,12]) //destination mac
    .ipv4([192,168,1,1], //source ip
          [192,168,1,2], //destination ip
          20)            //time to life
    .udp(21,    //source port
         1234); //destination port

//payload of the udp packet
let payload = [1,2,3,4,5,6,7,8];

//get some memory to store the result
let mut result = Vec::<u8>::with_capacity(builder.size(payload.len()));

//serialize
//this will automatically set all length fields, checksums and identifiers (ethertype & protocol)
//before writing the packet out to "result"
builder.write(&mut result, &payload).unwrap();

还有一个TCP数据包示例可供参考。

有关更多信息,请参阅PacketBuilder 文档

手动序列化每个头部

另外,也可以手动构建一个数据包(示例)。一般来说,每个表示头部的结构体都有一个“write”方法,允许它被序列化。这些write方法有时会自动计算校验和并将它们填充进去。如果这种行为不希望发生(例如,如果你想生成一个校验和不正确的数据包),也可以调用一个“write_raw”方法,该方法将简单地序列化数据而不进行校验和计算。

阅读不同方法的文档以获取更多详细信息

参考文献

许可

根据您的选择,受Apache许可证第2.0版或MIT许可证的许可。相应的许可证文本可以在LICENSE-APACHE文件和LICENSE-MIT文件中找到。

贡献

除非您明确声明,否则您有意提交以包含在您的工作中的任何贡献均应按上述方式许可,不附加任何额外条款或条件。

依赖项