1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
//! mutnet is an unsafe-free and allocation-free, zero-dependency, no-std network protocol parsing and in-place manipulation library.
//!
//! # Table of contents
//! - [Usage](#usage)
//!     - [Headroom](#headroom)
//!     - [Parsing](#parsing)
//!     - [Manipulation](#manipulation)
//! - [Feature flags](#feature-flags)
//!
//! # Usage
//! Network data is wrapped in a [`DataBuffer`](data_buffer::DataBuffer) and combined with a
//! stack of protocol metadata to keep track of individual protocol header's start and length.
//!
//! ## Headroom
//! Headroom is "empty" space at the start of the wrapped network data buffer used to accommodate
//! length changes of the parsed protocol headers.
//! Using headroom for length changes allows only copying header data which, in general, is less work
//! than copying the payload.
//! For example if an IPv4 header's length should be increased for additional options, all header
//! information before the options is moved by the required amount into the headroom leaving space
//! for more options.
//!
//! ```text
//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//! |  Headroom   |     Header Data       |         Payload         |
//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//!
//! -> some method manipulates the headers in a way that requires more space ->
//! Headroom shrinks -> header data is partially copied -> new data is inserted ->
//!
//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//! |Headroom|   Header   | *** |  Data   |         Payload         |
//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//! *** = Data inserted into the headers.
//!
//! ```
//! The headroom has to be already present in the network data buffer to be wrapped by [`DataBuffer`](data_buffer::DataBuffer).
//! If no header mutation is required, the headroom can be ignored.
//!
//! ## Parsing
//!
//! After parsing data by creating the appropriate [`DataBuffer`](data_buffer::DataBuffer) with
//! metadata stack, the `ProtocolMethods` traits (e.g. [`TcpMethods`](tcp::TcpMethods)) are used to access the header data.
//!
//! #### Avoid copying data
//! If the network data buffer implements [`Copy`], the [`DataBuffer`](data_buffer::DataBuffer)
//! will take a copy of it and will copy the buffer at every parsing step (e.g. Ethernet -> Ipv4).
//! For this reason, it is advised to use references or non-[`Copy`] containers ([`Vec`], etc).
//!
//! ### Example
//! ```rust
//! use mutnet::data_buffer::DataBuffer;
//! use mutnet::ethernet::Eth;
//! use mutnet::ipv4::Ipv4;
//! use mutnet::tcp::{Tcp, TcpMethods};
//! # #[rustfmt::skip]
//! #  const ETH_IPV4_TCP: [u8; 64] = [
//! #     // Dst
//! #     0x00, 0x80, 0x41, 0xAE, 0xFD, 0x7E,
//! #     // Src
//! #     0x7E, 0xFD, 0xAE, 0x41, 0x80, 0x00,
//! #     // Ether type (IPv4)
//! #     0x08, 0x00,
//! #     // Payload
//! #     // IPv4
//! #     // Version & IHL
//! #     0x46,
//! #     // DSCP & ECN
//! #     0b0010_1000,
//! #     // Total length
//! #     0x00, 0x32,
//! #     // Identification
//! #     0x12, 0x34,
//! #     // Flags & Fragment offset
//! #     0b101_00000, 0x03,
//! #     // TTL
//! #     0x01,
//! #     // Protocol (TCP)
//! #     0x06,
//! #     // Header Checksum
//! #     0x06, 0x61,
//! #     // Source
//! #     0x7f, 0x00, 0x00, 0x1,
//! #     // Destination
//! #     0x7f, 0x00, 0x00, 0x1,
//! #     // Options
//! #     0x02, 0x04, 0xFF, 0xFF,
//! #     // Payload
//! #     // TCP
//! #     // Source port
//! #     0x12, 0x34,
//! #     // Destination port
//! #     0x45, 0x67,
//! #     // Sequence number
//! #     0x12, 0x34, 0x56, 0x78,
//! #     // Acknowledgment number
//! #     0x09, 0x87, 0x65, 0x43,
//! #     // Data offset, reserved bits, flags
//! #     0x50, 0b0101_0101,
//! #     // Window
//! #     0x12, 0x45,
//! #     // Checksum
//! #     0x19, 0xB8,
//! #     // Urgent pointer
//! #     0x56, 0x78,
//! #     // payload
//! #     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
//! # ];
//!
//! let network_data_ref = &ETH_IPV4_TCP;
//! let headroom = 0;
//!
//! // Parse network data without headroom.
//! let ethernet = DataBuffer::<&[u8;64], Eth>::parse_ethernet_layer(network_data_ref, headroom).unwrap();
//! // The network data buffer type can usually be elided.
//! let check_ipv4_checksum = true;
//! let ipv4 = DataBuffer::<_, Ipv4<Eth>>::parse_ipv4_layer(ethernet, check_ipv4_checksum).unwrap();
//! let check_tcp_checksum = true;
//! let tcp = DataBuffer::<_, Tcp<Ipv4<Eth>>>::parse_tcp_layer(ipv4, check_tcp_checksum).unwrap();
//!
//! // The mutnet::tcp::TcpMethods trait needs to be in scope to access non-mutable TCP methods.
//! assert_eq!(tcp.tcp_source_port(), 0x1234);
//! ```
//!
//! ## Manipulation
//!
//! For header manipulation, the [`DataBuffer`](data_buffer::DataBuffer) needs to be created
//! with a mutable network data buffer.
//! If this is the case the `ProtocolMethodsMut` traits (e.g. [`TcpMethodsMut`](tcp::TcpMethodsMut)) allow mutating the data
//! ```rust
//! use mutnet::data_buffer::DataBuffer;
//! use mutnet::ethernet::Eth;
//! use mutnet::ipv4::Ipv4;
//! use mutnet::tcp::{Tcp, TcpMethods, TcpMethodsMut};
//! # #[rustfmt::skip]
//! #  const ETH_IPV4_TCP: [u8; 64] = [
//! #     // Dst
//! #     0x00, 0x80, 0x41, 0xAE, 0xFD, 0x7E,
//! #     // Src
//! #     0x7E, 0xFD, 0xAE, 0x41, 0x80, 0x00,
//! #     // Ether type (IPv4)
//! #     0x08, 0x00,
//! #     // Payload
//! #     // IPv4
//! #     // Version & IHL
//! #     0x46,
//! #     // DSCP & ECN
//! #     0b0010_1000,
//! #     // Total length
//! #     0x00, 0x32,
//! #     // Identification
//! #     0x12, 0x34,
//! #     // Flags & Fragment offset
//! #     0b101_00000, 0x03,
//! #     // TTL
//! #     0x01,
//! #     // Protocol (TCP)
//! #     0x06,
//! #     // Header Checksum
//! #     0x06, 0x61,
//! #     // Source
//! #     0x7f, 0x00, 0x00, 0x1,
//! #     // Destination
//! #     0x7f, 0x00, 0x00, 0x1,
//! #     // Options
//! #     0x02, 0x04, 0xFF, 0xFF,
//! #     // Payload
//! #     // TCP
//! #     // Source port
//! #     0x12, 0x34,
//! #     // Destination port
//! #     0x45, 0x67,
//! #     // Sequence number
//! #     0x12, 0x34, 0x56, 0x78,
//! #     // Acknowledgment number
//! #     0x09, 0x87, 0x65, 0x43,
//! #     // Data offset, reserved bits, flags
//! #     0x50, 0b0101_0101,
//! #     // Window
//! #     0x12, 0x45,
//! #     // Checksum
//! #     0x19, 0xB8,
//! #     // Urgent pointer
//! #     0x56, 0x78,
//! #     // payload
//! #     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
//! # ];
//!
//! // For demonstration purposes, the data is copied into an array.
//! let mut network_data = [0;100];
//! network_data[36..].copy_from_slice(&ETH_IPV4_TCP);
//! let network_data_ref_mut = &mut network_data;
//! // Set the headroom accordingly.
//! let headroom = 36;
//!
//! // Parse network data without headroom.
//! let ethernet = DataBuffer::<&mut [u8;100], Eth>::parse_ethernet_layer(network_data_ref_mut, headroom).unwrap();
//! // The network data buffer type can usually be elided.
//! let check_ipv4_checksum = true;
//! let ipv4 = DataBuffer::<_, Ipv4<Eth>>::parse_ipv4_layer(ethernet, check_ipv4_checksum).unwrap();
//! let check_tcp_checksum = true;
//! let mut tcp = DataBuffer::<_, Tcp<Ipv4<Eth>>>::parse_tcp_layer(ipv4, check_tcp_checksum).unwrap();
//!
//! // The mutnet::tcp::TcpMethods trait needs to be in scope to access non-mutating TCP methods.
//! assert_eq!(tcp.tcp_source_port(), 0x1234);
//!
//! // The mutnet::tcp::TcpMethodsMut trait needs to be in scope to access mutating TCP methods.
//! tcp.set_tcp_source_port(0xAAAA);
//! assert_eq!(tcp.tcp_source_port(), 0xAAAA);
//! ```
//!
//!
//! # Feature flags
//!
//! Name | Description | Default?
//! ---|---|---
//! `error_trait` | use unstable `core::error:Error`, only available in nightly | No
//! `std` | use `std` | Yes
//!  ... | All other features are for development usage only | No
//!
#![cfg_attr(
    all(feature = "error_trait", not(feature = "std")),
    feature(error_in_core)
)]
#![cfg_attr(not(feature = "std"), no_std)]
#![forbid(unsafe_code)]
#![forbid(unreachable_pub)]
#![warn(missing_docs)]
#![warn(clippy::missing_errors_doc)]

mod internal_utils;
mod test_utils;
mod utility_traits;

pub mod addresses;
pub mod arp;
pub mod checksum;
pub mod data_buffer;
pub mod error;
pub mod ethernet;
pub mod ieee802_1q_vlan;
pub mod ipv4;
pub mod ipv6;
pub mod ipv6_extensions;
pub mod multi_step_parser;
pub mod no_previous_header;
pub mod tcp;
pub mod typed_protocol_headers;
pub mod udp;