zero_packet/
misc.rs

1use crate::network::{ipv4::IPv4Reader, ipv6::IPv6Reader};
2use core::fmt::{self};
3
4/// Represents an encapsulated IP-in-IP protocol.
5#[derive(Debug)]
6pub enum IpInIp<'a> {
7    Ipv4(IPv4Reader<'a>),
8    Ipv6(IPv6Reader<'a>),
9}
10
11/// Common EtherTypes.
12///
13/// See: <https://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml.>.
14#[repr(u16)]
15#[derive(Debug, PartialEq)]
16pub enum EtherType {
17    Arp = 0x0806,
18    Ipv4 = 0x0800,
19    Ipv6 = 0x86dd,
20    Unknown(u16),
21}
22
23impl From<u16> for EtherType {
24    fn from(value: u16) -> Self {
25        match value {
26            0x0800 => EtherType::Ipv4,
27            0x0806 => EtherType::Arp,
28            0x86DD => EtherType::Ipv6,
29            other => EtherType::Unknown(other),
30        }
31    }
32}
33
34/// Common IP protocols.
35///
36/// Shares the same values as Next Header in IPv6.
37#[repr(u8)]
38#[derive(Debug, PartialEq)]
39pub enum IpProtocol {
40    Icmpv4 = 1,
41    Ipv4 = 4,
42    Tcp = 6,
43    Udp = 17,
44    Ipv6 = 41,
45    Icmpv6 = 58,
46    NoNextHeader = 59,
47    Unknown(u8),
48}
49
50impl From<u8> for IpProtocol {
51    fn from(value: u8) -> Self {
52        match value {
53            1 => IpProtocol::Icmpv4,
54            4 => IpProtocol::Ipv4,
55            6 => IpProtocol::Tcp,
56            17 => IpProtocol::Udp,
57            41 => IpProtocol::Ipv6,
58            58 => IpProtocol::Icmpv6,
59            59 => IpProtocol::NoNextHeader,
60            other => IpProtocol::Unknown(other),
61        }
62    }
63}
64
65/// Common ICMPv4 types.
66#[repr(u8)]
67#[derive(Debug, PartialEq)]
68pub enum Icmpv4Type {
69    EchoReply = 0,
70    DestUnreachable = 3,
71    SourceQuench = 4,
72    Redirect = 5,
73    EchoRequest = 8,
74    RouterAdvertisement = 9,
75    RouterSelection = 10,
76    TimeExceeded = 11,
77    ParameterProblem = 12,
78    Timestamp = 13,
79    TimestampReply = 14,
80    InformationRequest = 15,
81    InformationReply = 16,
82    AddressMaskRequest = 17,
83    AddressMaskReply = 18,
84    Traceroute = 30,
85    Photuris = 40,
86    ExtendedEchoRequest = 42,
87    ExtendedEchoReply = 43,
88    Experimental1 = 253,
89    Experimental2 = 254,
90    Unknown,
91}
92
93impl From<u8> for Icmpv4Type {
94    fn from(value: u8) -> Self {
95        match value {
96            0 => Icmpv4Type::EchoReply,
97            3 => Icmpv4Type::DestUnreachable,
98            4 => Icmpv4Type::SourceQuench,
99            5 => Icmpv4Type::Redirect,
100            8 => Icmpv4Type::EchoRequest,
101            9 => Icmpv4Type::RouterAdvertisement,
102            10 => Icmpv4Type::RouterSelection,
103            11 => Icmpv4Type::TimeExceeded,
104            12 => Icmpv4Type::ParameterProblem,
105            13 => Icmpv4Type::Timestamp,
106            14 => Icmpv4Type::TimestampReply,
107            15 => Icmpv4Type::InformationRequest,
108            16 => Icmpv4Type::InformationReply,
109            17 => Icmpv4Type::AddressMaskRequest,
110            18 => Icmpv4Type::AddressMaskReply,
111            30 => Icmpv4Type::Traceroute,
112            40 => Icmpv4Type::Photuris,
113            42 => Icmpv4Type::ExtendedEchoRequest,
114            43 => Icmpv4Type::ExtendedEchoReply,
115            253 => Icmpv4Type::Experimental1,
116            254 => Icmpv4Type::Experimental2,
117            _ => Icmpv4Type::Unknown,
118        }
119    }
120}
121
122/// Common ICMPv6 types.
123#[repr(u8)]
124#[derive(Debug, PartialEq)]
125pub enum Icmpv6Type {
126    DestUnreachable = 1,
127    PacketTooBig = 2,
128    TimeExceeded = 3,
129    ParameterProblem = 4,
130    Experimental1 = 100,
131    Experimental2 = 101,
132    EchoRequest = 128,
133    EchoReply = 129,
134    MldQuery = 130,
135    MldReport = 131,
136    MldDone = 132,
137    RouterSolicitation = 133,
138    RouterAdvertisement = 134,
139    NeighborSolicitation = 135,
140    NeighborAdvertisement = 136,
141    Redirect = 137,
142    RouterRenumbering = 138,
143    IcmpNodeInformationQuery = 139,
144    IcmpNodeInformationResponse = 140,
145    InverseNeighborDiscoverySolicitation = 141,
146    InverseNeighborDiscoveryAdvertisement = 142,
147    Mld2Report = 143,
148    HomeAgentAddressDiscoveryRequest = 144,
149    HomeAgentAddressDiscoveryReply = 145,
150    MobilePrefixSolicitation = 146,
151    MobilePrefixAdvertisement = 147,
152    CertificationPathSolicitation = 148,
153    CertificationPathAdvertisement = 149,
154    ExperimentalMobilityProtocols = 150,
155    MulticastRouterAdvertisement = 151,
156    MulticastRouterSolicitation = 152,
157    MulticastRouterTermination = 153,
158    RplControlMessage = 155,
159    Experimental3 = 200,
160    Experimental4 = 201,
161    Unknown,
162}
163
164impl From<u8> for Icmpv6Type {
165    fn from(value: u8) -> Self {
166        match value {
167            1 => Icmpv6Type::DestUnreachable,
168            2 => Icmpv6Type::PacketTooBig,
169            3 => Icmpv6Type::TimeExceeded,
170            4 => Icmpv6Type::ParameterProblem,
171            100 => Icmpv6Type::Experimental1,
172            101 => Icmpv6Type::Experimental2,
173            128 => Icmpv6Type::EchoRequest,
174            129 => Icmpv6Type::EchoReply,
175            130 => Icmpv6Type::MldQuery,
176            131 => Icmpv6Type::MldReport,
177            132 => Icmpv6Type::MldDone,
178            133 => Icmpv6Type::RouterSolicitation,
179            134 => Icmpv6Type::RouterAdvertisement,
180            135 => Icmpv6Type::NeighborSolicitation,
181            136 => Icmpv6Type::NeighborAdvertisement,
182            137 => Icmpv6Type::Redirect,
183            138 => Icmpv6Type::RouterRenumbering,
184            139 => Icmpv6Type::IcmpNodeInformationQuery,
185            140 => Icmpv6Type::IcmpNodeInformationResponse,
186            141 => Icmpv6Type::InverseNeighborDiscoverySolicitation,
187            142 => Icmpv6Type::InverseNeighborDiscoveryAdvertisement,
188            143 => Icmpv6Type::Mld2Report,
189            144 => Icmpv6Type::HomeAgentAddressDiscoveryRequest,
190            145 => Icmpv6Type::HomeAgentAddressDiscoveryReply,
191            146 => Icmpv6Type::MobilePrefixSolicitation,
192            147 => Icmpv6Type::MobilePrefixAdvertisement,
193            148 => Icmpv6Type::CertificationPathSolicitation,
194            149 => Icmpv6Type::CertificationPathAdvertisement,
195            150 => Icmpv6Type::ExperimentalMobilityProtocols,
196            151 => Icmpv6Type::MulticastRouterAdvertisement,
197            152 => Icmpv6Type::MulticastRouterSolicitation,
198            153 => Icmpv6Type::MulticastRouterTermination,
199            155 => Icmpv6Type::RplControlMessage,
200            200 => Icmpv6Type::Experimental3,
201            201 => Icmpv6Type::Experimental4,
202            _ => Icmpv6Type::Unknown,
203        }
204    }
205}
206
207/// Common Extension Header types for IPv6.
208///
209/// Shares the same values as Protocol in IPv4.
210#[repr(u8)]
211pub enum NextHeader {
212    HopByHop = 0,
213    Icmp = 1,
214    Tcp = 6,
215    Udp = 17,
216    Routing = 43,
217    Fragment = 44,
218    Esp = 50,
219    AuthHeader = 51,
220    NoNextHeader = 59,
221    Destination = 60,
222    Mobility = 135,
223    Unknown,
224}
225
226impl From<u8> for NextHeader {
227    fn from(value: u8) -> Self {
228        match value {
229            0 => NextHeader::HopByHop,
230            43 => NextHeader::Routing,
231            44 => NextHeader::Fragment,
232            50 => NextHeader::Esp,
233            51 => NextHeader::AuthHeader,
234            59 => NextHeader::NoNextHeader,
235            60 => NextHeader::Destination,
236            135 => NextHeader::Mobility,
237            _ => NextHeader::Unknown,
238        }
239    }
240}
241
242/// Workaround for the lack of heap support.
243#[inline]
244pub fn bytes_to_mac(bytes: &[u8], buffer: &mut [u8]) -> usize {
245    const HEX_CHARS: &[u8; 16] = b"0123456789abcdef";
246
247    let mut buffer_index = 0;
248    for (i, &byte) in bytes.iter().enumerate() {
249        if i != 0 {
250            buffer[buffer_index] = b':';
251            buffer_index += 1;
252        }
253
254        buffer[buffer_index] = HEX_CHARS[(byte >> 4) as usize];
255        buffer[buffer_index + 1] = HEX_CHARS[(byte & 0xf) as usize];
256        buffer_index += 2;
257    }
258
259    buffer_index
260}
261
262/// Workaround for the lack of heap support.
263#[inline]
264pub fn bytes_to_ipv6(bytes: &[u8], buffer: &mut [u8]) -> usize {
265    const HEX_CHARS: &[u8; 16] = b"0123456789abcdef";
266
267    let mut buffer_index = 0;
268    for (i, &byte) in bytes.iter().enumerate() {
269        if i % 2 == 0 && i != 0 {
270            buffer[buffer_index] = b':';
271            buffer_index += 1;
272        }
273
274        buffer[buffer_index] = HEX_CHARS[(byte >> 4) as usize];
275        buffer[buffer_index + 1] = HEX_CHARS[(byte & 0xf) as usize];
276        buffer_index += 2;
277    }
278
279    buffer_index
280}
281
282/// Wrapper to format an IP address.
283pub struct IpFormatter<'a>(pub &'a [u8]);
284
285impl fmt::Debug for IpFormatter<'_> {
286    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
287        let ip = self.0;
288        write!(f, "{}.{}.{}.{}", ip[0], ip[1], ip[2], ip[3])
289    }
290}