trippy_packet/
lib.rs

1//! Packet wire format parsing and building.
2//!
3//! The following packet are supported:
4//! - `ICMPv4`
5//! - `ICMPv6`
6//! - `IPv4`
7//! - `IPv6`
8//! - `UDP`
9//! - `TCP`
10//! - `ICMP` extensions
11//!
12//! # Endianness
13//!
14//! The internal representation is held in network byte order (big-endian) and
15//! all accessor methods take and return data in host byte order, converting as
16//! necessary for the given architecture.
17//!
18//! # Example
19//!
20//! The following example parses an `UDP` packet and asserts its fields:
21//!
22//! ```rust
23//! # fn main() -> anyhow::Result<()> {
24//! use trippy_packet::udp::UdpPacket;
25//!
26//! let buf = hex_literal::hex!("68 bf 81 b6 00 40 ac be");
27//! let packet = UdpPacket::new_view(&buf)?;
28//! assert_eq!(26815, packet.get_source());
29//! assert_eq!(33206, packet.get_destination());
30//! assert_eq!(64, packet.get_length());
31//! assert_eq!(44222, packet.get_checksum());
32//! assert!(packet.payload().is_empty());
33//! # Ok(())
34//! # }
35//! ```
36//!
37//! The following example builds an `ICMPv4` echo request packet:
38//!
39//! ```rust
40//! # fn main() -> anyhow::Result<()> {
41//! use trippy_packet::checksum::icmp_ipv4_checksum;
42//! use trippy_packet::icmpv4::echo_request::EchoRequestPacket;
43//! use trippy_packet::icmpv4::{IcmpCode, IcmpPacket, IcmpType};
44//!
45//! let mut buf = [0; IcmpPacket::minimum_packet_size()];
46//! let mut icmp = EchoRequestPacket::new(&mut buf)?;
47//! icmp.set_icmp_type(IcmpType::EchoRequest);
48//! icmp.set_icmp_code(IcmpCode(0));
49//! icmp.set_identifier(1234);
50//! icmp.set_sequence(10);
51//! icmp.set_checksum(icmp_ipv4_checksum(icmp.packet()));
52//! assert_eq!(icmp.packet(), &hex_literal::hex!("08 00 f3 23 04 d2 00 0a"));
53//! # Ok(())
54//! # }
55//! ```
56#![forbid(unsafe_code)]
57
58mod buffer;
59
60/// Packet errors.
61pub mod error;
62
63/// Functions for calculating network checksums.
64pub mod checksum;
65
66/// `ICMPv4` packets.
67pub mod icmpv4;
68
69/// `ICMPv6` packets.
70pub mod icmpv6;
71
72/// `ICMP` extensions.
73pub mod icmp_extension;
74
75/// `IPv4` packets.
76pub mod ipv4;
77
78/// `IPv6` packets.
79pub mod ipv6;
80
81/// `UDP` packets.
82pub mod udp;
83
84/// `TCP` packets.
85pub mod tcp;
86
87/// The IP packet next layer protocol.
88#[derive(Debug, Clone, Copy, Eq, PartialEq)]
89pub enum IpProtocol {
90    Icmp,
91    IcmpV6,
92    Udp,
93    Tcp,
94    Other(u8),
95}
96
97impl IpProtocol {
98    #[must_use]
99    pub const fn id(self) -> u8 {
100        match self {
101            Self::Icmp => 1,
102            Self::IcmpV6 => 58,
103            Self::Udp => 17,
104            Self::Tcp => 6,
105            Self::Other(id) => id,
106        }
107    }
108
109    #[must_use]
110    pub const fn new(value: u8) -> Self {
111        Self::Other(value)
112    }
113}
114
115impl From<u8> for IpProtocol {
116    fn from(id: u8) -> Self {
117        match id {
118            1 => Self::Icmp,
119            58 => Self::IcmpV6,
120            17 => Self::Udp,
121            6 => Self::Tcp,
122            p => Self::Other(p),
123        }
124    }
125}
126
127/// Format a payload as a hexadecimal string.
128#[must_use]
129pub fn fmt_payload(bytes: &[u8]) -> String {
130    use itertools::Itertools as _;
131    format!("{:02x}", bytes.iter().format(" "))
132}