2 个版本

0.1.1 2021 年 5 月 20 日
0.1.0 2021 年 5 月 18 日

#89#位域

Download history 85/week @ 2024-04-01 17/week @ 2024-04-08 18/week @ 2024-04-15 23/week @ 2024-04-22 18/week @ 2024-04-29 30/week @ 2024-05-06 24/week @ 2024-05-13 24/week @ 2024-05-20 29/week @ 2024-05-27 22/week @ 2024-06-03 23/week @ 2024-06-10 28/week @ 2024-06-17 24/week @ 2024-06-24 9/week @ 2024-07-08 43/week @ 2024-07-15

每月下载量 78 次
7 个 crate 中使用(通过 libpacket

MIT/Apache 许可证

87KB
2K SLoC

libpacket

用于各种协议的包解析器。

从未维护的 libpnet 中提取。


lib.rs:

The pnet_macros crate provides the #[packet] macro and compiler plugin, which is used to specify the format of on-the-wire packets, and automatically generate zero-copy accessors and mutators for the fields. It is used as follows

/// Import the `Packet` custom derive attribute
use libpacket_derive::Packet;
/// This module contains a list of type aliases which may be used
use libpacket_core::types::{u4, u12be};

/// Packets are specified in the same way as normal Rust structs, but with a `#[packet]`
/// attribute.
#[derive(Packet)]
pub struct Example {
    // This is a simple field which contains a 4-bit, unsigned integer.
    // Note that `u4` is simply an alias for `u8` - the name is a hint
    // to the compiler plugin, it is NOT a usable 4 bit type!
    simple_field1: u4,

    // This specifies that `simple_field2` should be a 12-bit field,
    // with bits stored in big endian
    simple_field2: u12be,

    // All packets must specify a `#[payload]`, which should be a
    // `Vec<u8>`. This represents the packet's payload, for example in
    // an IPv4 packet, the payload could be a UDP packet, or in a UDP
    // packet the payload could be the application data. All the
    // remaining space in the packet is considered to be the payload
    // (this doesn't have to be the case, see the documentation for
    // `#[payload]` below.
    #[payload]
    payload: Vec<u8>
}

A number of things will then be generated. You can see this in action in the documentation and source of each of the packet types in the pnet::packet module. Things generated include (assuming the Example struct from above)

  • An ExamplePacket<'p> structure, which is used for receiving packets on the network. This structure contains
    • A method, pub fn new<'p>(packet: &'p [u8]) -> ExamplePacket<'p>, used for the construction of an ExamplePacket, given a buffer to store it. The buffer should be long enough to contain all the fields in the packet.
    • 一种方法,pub fn to_immutable<'p>(&'p self) -> ExamplePacket<'p>,它只是一个恒等函数。它的存在是为了与MutableExamplePacket保持一致。
    • 一些访问器方法,形式为pub get_{field_name}(&self) -> {field_type},用于检索在线值的宿主表示。
  • 一个MutableExamplePacket<'p>结构体,在网络发送数据包时使用。该结构体包含
    • 一种方法,pub fn new<'p>(packet: &'p mut [u8]) -> MutableExamplePacket<'p>,用于根据存储它的缓冲区构建一个MutableExamplePacket。该缓冲区应足够长,可以包含数据包中的所有字段。
    • 一种方法,pub fn to_immutable<'p>(&'p self) -> ExamplePacket<'p>,它将MutableExamplePacket转换为ExamplePacket
    • 一种方法,pub fn populate(&mut self, packet: Example),给定一个Example结构体,将使用Example结构体中的值填充MutableExamplePacket
    • 一些访问器方法,形式为pub get_{field_name}(&self) -> {field_type},用于检索在线值的宿主表示。
    • 存在多种修改器方法,其形式为 pub set_{字段名}(&mut self, val: {字段类型}),该方法将接受一个主机值,将其转换为所需的在线格式,并将其存储在支持 MutableExamplePacket 的缓冲区中。
  • 为每个 MutableExamplePacketExamplePacket 结构实现了一系列特性和方法。这些包括
    • pnet::packet::PacketExamplePacketMutableExamplePacket
    • pnet::packet::MutablePacket (仅 MutableExamplePacket
    • std::fmt::DebugExamplePacketMutableExamplePacket
    • pnet::packet::FromPacketExamplePacketMutableExamplePacket
    • pnet::packet::PacketSizeExamplePacketMutableExamplePacket
  • 一个 ExampleIterator 结构,它实现了 std::iter::Iterator,允许遍历另一个数据包中包含的 ExamplePacket 向量。内部使用。

属性

字段可能具有一些属性,这些包括

  • #[length_fn = "function_name"]

    此属性用于启用可变长度字段。要指定可变长度字段,它应该具有类型 Vec<T>。它必须具有 #[length_fn](或 #[length])属性,该属性指定用于计算字段长度的函数名称。长度函数的签名应为 fn {function_name}<'a>(example_packet: &ExamplePacket<'a>) -> usize,用您结构中适当命名的数据包类型替换 &ExamplePacket<'a>。您可以访问计算字段长度所需的任何字段。返回值应该是字段使用的字节数。

    向量中包含的类型可以是 pnet_macros::types 中指定的基本类型之一,或者是一个标记了 #[derive(Packet)] 的结构,例如 Vec<Example>

  • #[length = "算术表达式"]

    此属性用于启用可变长度字段。要指定可变长度字段,它应该具有 Vec<T> 类型。它必须具有 #[length](或 #[length_fn])属性,该属性指定一个算术表达式来计算字段的长度。表达式中只包含字段名、常量、整数、基本算术表达式(+ - * / %)和括号。例如:#[length = "field_name + CONSTANT - 4]

    向量中包含的类型可以是 pnet_macros::types 中指定的基本类型之一,或者是一个标记了 #[derive(Packet)] 的结构,例如 Vec<Example>

  • #[payload]

    此属性指定与数据包关联的有效负载。这应指定与数据包关联的数据。它可以在两个地方使用

    • 数据包中的最后一个字段,在这种情况下,它假定使用包含数据包的缓冲区的剩余长度
    • 数据包中的另一个位置,在这种情况下,必须还指定 #[length_fn] 属性以给出有效负载的长度。如果数据包没有有效负载,则必须仍然指定此属性,但可以提供一个返回零的 #[length_fn] 属性。
  • #[construct_with(, ...)]

    不幸的是,编译器插件当前在装饰阶段(生成所有上述内容的阶段)无法访问类型信息,因此需要此属性。对于所有既不是原始类型也不是原始类型向量的字段,必须使用此属性。

    • 字段类型必须有一个 new 方法,该方法接受一个或多个原始类型的参数。
    • 字段必须带有 #[construct_with(...)] 属性,指定与 new 方法相同的类型列表。
    • 必须为字段类型实现 pnet::packet::ToPrimitiveValues 特性,该特性必须返回一个元组,包含在 #[construct_with(...)] 属性和 new 方法中指定的参数所指定的原始类型。

依赖项

~3–4.5MB
~88K SLoC