1#[allow(unused_imports)]
10use alloc::vec::Vec;
11use core::cmp::PartialEq;
12use core::convert::Infallible as Never;
13use core::fmt::{Debug, Display};
14use core::hash::Hash;
15
16use net_types::ip::{GenericOverIp, Ip, IpAddr, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr};
17use packet::{BufferViewMut, PacketBuilder, ParsablePacket, ParseMetadata};
18use zerocopy::{
19 FromBytes, Immutable, IntoBytes, KnownLayout, SplitByteSlice, SplitByteSliceMut, Unaligned,
20};
21
22use crate::error::{IpParseError, IpParseResult};
23use crate::ethernet::EthernetIpExt;
24use crate::icmp::IcmpIpExt;
25use crate::ipv4::{Ipv4Header, Ipv4OnlyMeta, Ipv4Packet, Ipv4PacketBuilder};
26use crate::ipv6::{Ipv6Header, Ipv6Packet, Ipv6PacketBuilder};
27use crate::private::Sealed;
28
29pub trait IpProtoExt: Ip {
32 type Proto: IpProtocol
36 + GenericOverIp<Self, Type = Self::Proto>
37 + GenericOverIp<Ipv4, Type = Ipv4Proto>
38 + GenericOverIp<Ipv6, Type = Ipv6Proto>
39 + Copy
40 + Clone
41 + Hash
42 + Debug
43 + Display
44 + PartialEq
45 + Eq
46 + PartialOrd
47 + Ord;
48}
49
50impl IpProtoExt for Ipv4 {
51 type Proto = Ipv4Proto;
52}
53
54impl IpProtoExt for Ipv6 {
55 type Proto = Ipv6Proto;
56}
57
58pub trait IpExt: EthernetIpExt + IcmpIpExt {
61 type Packet<B: SplitByteSlice>: IpPacket<B, Self, Builder = Self::PacketBuilder>
63 + GenericOverIp<Self, Type = Self::Packet<B>>
64 + GenericOverIp<Ipv4, Type = Ipv4Packet<B>>
65 + GenericOverIp<Ipv6, Type = Ipv6Packet<B>>;
66 type PacketBuilder: IpPacketBuilder<Self> + Eq;
68}
69
70impl IpExt for Ipv4 {
71 type Packet<B: SplitByteSlice> = Ipv4Packet<B>;
72 type PacketBuilder = Ipv4PacketBuilder;
73}
74
75impl IpExt for Ipv6 {
76 type Packet<B: SplitByteSlice> = Ipv6Packet<B>;
77 type PacketBuilder = Ipv6PacketBuilder;
78}
79
80#[derive(Debug)]
82pub enum Nat64Error {
83 NotImplemented,
85}
86
87#[derive(Debug)]
89pub enum Nat64TranslationResult<S, E> {
90 Forward(S),
92 Drop,
94 Err(E),
96}
97
98#[derive(
103 Default,
104 Debug,
105 Clone,
106 Copy,
107 PartialEq,
108 Eq,
109 KnownLayout,
110 FromBytes,
111 IntoBytes,
112 Immutable,
113 Unaligned,
114)]
115#[repr(C)]
116pub struct DscpAndEcn(u8);
117
118const DSCP_OFFSET: u8 = 2;
119const DSCP_MAX: u8 = (1 << (8 - DSCP_OFFSET)) - 1;
120const ECN_MAX: u8 = (1 << DSCP_OFFSET) - 1;
121
122impl DscpAndEcn {
123 pub const fn default() -> Self {
126 Self(0)
127 }
128
129 pub const fn new(dscp: u8, ecn: u8) -> Self {
132 debug_assert!(dscp <= DSCP_MAX);
133 debug_assert!(ecn <= ECN_MAX);
134 Self((dscp << DSCP_OFFSET) + ecn)
135 }
136
137 pub const fn new_with_raw(value: u8) -> Self {
140 Self(value)
141 }
142
143 pub fn dscp(self) -> u8 {
145 let Self(v) = self;
146 v >> 2
147 }
148
149 pub fn ecn(self) -> u8 {
151 let Self(v) = self;
152 v & 0x3
153 }
154
155 pub fn raw(self) -> u8 {
157 let Self(value) = self;
158 value
159 }
160}
161
162impl From<u8> for DscpAndEcn {
163 fn from(value: u8) -> Self {
164 Self::new_with_raw(value)
165 }
166}
167
168pub trait IpPacket<B: SplitByteSlice, I: IpExt>:
172 Sized + Debug + ParsablePacket<B, (), Error = IpParseError<I>>
173{
174 type Builder: IpPacketBuilder<I>;
176
177 type VersionSpecificMeta;
180
181 fn src_ip(&self) -> I::Addr;
183
184 fn dst_ip(&self) -> I::Addr;
186
187 fn proto(&self) -> I::Proto;
189
190 fn ttl(&self) -> u8;
192
193 fn dscp_and_ecn(&self) -> DscpAndEcn;
196
197 fn set_ttl(&mut self, ttl: u8)
201 where
202 B: SplitByteSliceMut;
203
204 fn body(&self) -> &[u8];
206
207 fn version_specific_meta(&self) -> Self::VersionSpecificMeta;
209
210 fn into_metadata(self) -> (I::Addr, I::Addr, I::Proto, ParseMetadata) {
215 let src_ip = self.src_ip();
216 let dst_ip = self.dst_ip();
217 let proto = self.proto();
218 let meta = self.parse_metadata();
219 (src_ip, dst_ip, proto, meta)
220 }
221
222 fn as_ip_addr_ref(&self) -> IpAddr<&'_ Ipv4Packet<B>, &'_ Ipv6Packet<B>>;
224
225 fn reassemble_fragmented_packet<BV: BufferViewMut<B>, IT: Iterator<Item = Vec<u8>>>(
227 buffer: BV,
228 header: Vec<u8>,
229 body_fragments: IT,
230 ) -> IpParseResult<I, ()>
231 where
232 B: SplitByteSliceMut;
233
234 fn to_vec(&self) -> Vec<u8>;
236
237 fn builder(&self) -> Self::Builder;
239}
240
241impl<B: SplitByteSlice> IpPacket<B, Ipv4> for Ipv4Packet<B> {
242 type Builder = Ipv4PacketBuilder;
243 type VersionSpecificMeta = Ipv4OnlyMeta;
244
245 fn src_ip(&self) -> Ipv4Addr {
246 Ipv4Header::src_ip(self)
247 }
248 fn dst_ip(&self) -> Ipv4Addr {
249 Ipv4Header::dst_ip(self)
250 }
251 fn proto(&self) -> Ipv4Proto {
252 Ipv4Header::proto(self)
253 }
254 fn dscp_and_ecn(&self) -> DscpAndEcn {
255 Ipv4Header::dscp_and_ecn(self)
256 }
257 fn ttl(&self) -> u8 {
258 Ipv4Header::ttl(self)
259 }
260 fn set_ttl(&mut self, ttl: u8)
261 where
262 B: SplitByteSliceMut,
263 {
264 Ipv4Packet::set_ttl(self, ttl)
265 }
266 fn body(&self) -> &[u8] {
267 Ipv4Packet::body(self)
268 }
269
270 fn version_specific_meta(&self) -> Ipv4OnlyMeta {
271 Ipv4OnlyMeta { id: Ipv4Header::id(self), fragment_type: Ipv4Header::fragment_type(self) }
272 }
273
274 fn as_ip_addr_ref(&self) -> IpAddr<&'_ Self, &'_ Ipv6Packet<B>> {
275 IpAddr::V4(self)
276 }
277
278 fn reassemble_fragmented_packet<BV: BufferViewMut<B>, IT: Iterator<Item = Vec<u8>>>(
279 buffer: BV,
280 header: Vec<u8>,
281 body_fragments: IT,
282 ) -> IpParseResult<Ipv4, ()>
283 where
284 B: SplitByteSliceMut,
285 {
286 crate::ipv4::reassemble_fragmented_packet(buffer, header, body_fragments)
287 }
288
289 fn to_vec(&self) -> Vec<u8> {
290 self.to_vec()
291 }
292
293 fn builder(&self) -> Self::Builder {
294 Ipv4Header::builder(self)
295 }
296}
297
298impl<B: SplitByteSlice> IpPacket<B, Ipv6> for Ipv6Packet<B> {
299 type Builder = Ipv6PacketBuilder;
300 type VersionSpecificMeta = ();
301
302 fn src_ip(&self) -> Ipv6Addr {
303 Ipv6Header::src_ip(self)
304 }
305 fn dst_ip(&self) -> Ipv6Addr {
306 Ipv6Header::dst_ip(self)
307 }
308 fn proto(&self) -> Ipv6Proto {
309 Ipv6Packet::proto(self)
310 }
311 fn dscp_and_ecn(&self) -> DscpAndEcn {
312 Ipv6Header::dscp_and_ecn(self)
313 }
314 fn ttl(&self) -> u8 {
315 Ipv6Header::hop_limit(self)
316 }
317 fn set_ttl(&mut self, ttl: u8)
318 where
319 B: SplitByteSliceMut,
320 {
321 Ipv6Packet::set_hop_limit(self, ttl)
322 }
323 fn body(&self) -> &[u8] {
324 Ipv6Packet::body(self)
325 }
326
327 fn version_specific_meta(&self) -> () {
328 ()
329 }
330 fn as_ip_addr_ref(&self) -> IpAddr<&'_ Ipv4Packet<B>, &'_ Self> {
331 IpAddr::V6(self)
332 }
333 fn reassemble_fragmented_packet<BV: BufferViewMut<B>, IT: Iterator<Item = Vec<u8>>>(
334 buffer: BV,
335 header: Vec<u8>,
336 body_fragments: IT,
337 ) -> IpParseResult<Ipv6, ()>
338 where
339 B: SplitByteSliceMut,
340 {
341 crate::ipv6::reassemble_fragmented_packet(buffer, header, body_fragments)
342 }
343
344 fn to_vec(&self) -> Vec<u8> {
345 self.to_vec()
346 }
347
348 fn builder(&self) -> Self::Builder {
349 self.builder()
350 }
351}
352
353pub trait IpPacketBuilder<I: IpExt>: PacketBuilder + Clone + Debug {
355 fn new(src_ip: I::Addr, dst_ip: I::Addr, ttl: u8, proto: I::Proto) -> Self;
359
360 fn src_ip(&self) -> I::Addr;
362
363 fn set_src_ip(&mut self, addr: I::Addr);
365
366 fn dst_ip(&self) -> I::Addr;
368
369 fn set_dst_ip(&mut self, addr: I::Addr);
371
372 fn proto(&self) -> I::Proto;
374
375 fn set_dscp_and_ecn(&mut self, dscp_and_ecn: DscpAndEcn);
377}
378
379pub trait IpProtocol: From<IpProto> + From<u8> + Sealed + Send + Sync + 'static {}
381
382impl Sealed for Never {}
383
384create_protocol_enum!(
385 #[allow(missing_docs)]
394 #[derive(Copy, Clone, Hash, Eq, Ord, PartialEq, PartialOrd)]
395 pub enum IpProto: u8 {
396 Tcp, 6, "TCP";
397 Udp, 17, "UDP";
398 Reserved, 255, "IANA-RESERVED";
399 }
400);
401
402create_protocol_enum!(
403 #[allow(missing_docs)]
409 #[derive(Copy, Clone, Hash, Eq, Ord, PartialEq, PartialOrd)]
410 pub enum Ipv4Proto: u8 {
411 Icmp, 1, "ICMP";
412 Igmp, 2, "IGMP";
413 + Proto(IpProto);
414 _, "IPv4 protocol {}";
415 }
416);
417
418impl IpProtocol for Ipv4Proto {}
419impl<I: Ip + IpProtoExt> GenericOverIp<I> for Ipv4Proto {
420 type Type = I::Proto;
421}
422impl Sealed for Ipv4Proto {}
423
424create_protocol_enum!(
425 #[allow(missing_docs)]
431 #[derive(Copy, Clone, Hash, Eq, Ord, PartialEq, PartialOrd)]
432 pub enum Ipv6Proto: u8 {
433 Icmpv6, 58, "ICMPv6";
434 NoNextHeader, 59, "NO NEXT HEADER";
435 + Proto(IpProto);
436 _, "IPv6 protocol {}";
437 }
438);
439
440impl IpProtocol for Ipv6Proto {}
441impl<I: Ip + IpProtoExt> GenericOverIp<I> for Ipv6Proto {
442 type Type = I::Proto;
443}
444impl Sealed for Ipv6Proto {}
445
446create_protocol_enum!(
447 #[allow(missing_docs)]
453 #[derive(Copy, Clone, Hash, Eq, PartialEq)]
454 pub enum Ipv6ExtHdrType: u8 {
455 HopByHopOptions, 0, "IPv6 HOP-BY-HOP OPTIONS HEADER";
456 Routing, 43, "IPv6 ROUTING HEADER";
457 Fragment, 44, "IPv6 FRAGMENT HEADER";
458 EncapsulatingSecurityPayload, 50, "ENCAPSULATING SECURITY PAYLOAD";
459 Authentication, 51, "AUTHENTICATION HEADER";
460 DestinationOptions, 60, "IPv6 DESTINATION OPTIONS HEADER";
461 _, "IPv6 EXTENSION HEADER {}";
462 }
463);
464
465#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Copy, Clone)]
476pub struct FragmentOffset(u16);
477
478impl FragmentOffset {
479 pub const ZERO: FragmentOffset = FragmentOffset(0);
481
482 pub const fn new(offset: u16) -> Option<Self> {
486 if offset < 1 << 13 {
487 Some(Self(offset))
488 } else {
489 None
490 }
491 }
492
493 pub(crate) fn new_with_lsb(offset: u16) -> Self {
496 Self(offset & 0x1FFF)
497 }
498
499 pub(crate) fn new_with_msb(offset: u16) -> Self {
502 Self(offset >> 3)
503 }
504
505 pub const fn new_with_bytes(offset_bytes: u16) -> Option<Self> {
509 if offset_bytes & 0x7 == 0 {
510 Some(Self(offset_bytes >> 3))
512 } else {
513 None
514 }
515 }
516
517 pub const fn into_raw(self) -> u16 {
519 self.0
520 }
521
522 pub fn into_bytes(self) -> u16 {
527 self.0 << 3
530 }
531}
532
533#[cfg(test)]
534mod tests {
535 use super::*;
536
537 #[test]
538 fn fragment_offset_raw() {
539 assert_eq!(FragmentOffset::new(1), Some(FragmentOffset(1)));
540 assert_eq!(FragmentOffset::new(1 << 13), None);
541 }
542
543 #[test]
544 fn fragment_offset_bytes() {
545 assert_eq!(FragmentOffset::new_with_bytes(0), Some(FragmentOffset(0)));
546 for i in 1..=7 {
547 assert_eq!(FragmentOffset::new_with_bytes(i), None);
548 }
549 assert_eq!(FragmentOffset::new_with_bytes(8), Some(FragmentOffset(1)));
550 assert_eq!(FragmentOffset::new_with_bytes(core::u16::MAX), None);
551 assert_eq!(
552 FragmentOffset::new_with_bytes(core::u16::MAX & !0x7),
553 Some(FragmentOffset((1 << 13) - 1)),
554 );
555 }
556}