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;
15use core::marker::PhantomData;
16
17use net_types::ip::{GenericOverIp, Ip, IpAddr, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr};
18use packet::{
19 BufferViewMut, NoOpSerializationContext, PacketBuilder, ParsablePacket, ParseMetadata,
20 PartialPacketBuilder, SerializationContext,
21};
22use zerocopy::{
23 FromBytes, Immutable, IntoBytes, KnownLayout, SplitByteSlice, SplitByteSliceMut, Unaligned,
24};
25
26use crate::error::{IpParseResult, Ipv6ParseError, ParseError};
27use crate::ethernet::EthernetIpExt;
28use crate::icmp::IcmpIpExt;
29use crate::ipv4::{IPV4_MIN_HDR_LEN, Ipv4Header, Ipv4Packet, Ipv4PacketBuilder, Ipv4PacketRaw};
30use crate::ipv6::{IPV6_FIXED_HDR_LEN, Ipv6Header, Ipv6Packet, Ipv6PacketBuilder, Ipv6PacketRaw};
31use crate::private::Sealed;
32
33pub trait IpProtoExt: Ip {
36 type Proto: IpProtocol
40 + GenericOverIp<Self, Type = Self::Proto>
41 + GenericOverIp<Ipv4, Type = Ipv4Proto>
42 + GenericOverIp<Ipv6, Type = Ipv6Proto>
43 + Copy
44 + Clone
45 + Hash
46 + Debug
47 + Display
48 + PartialEq
49 + Eq
50 + PartialOrd
51 + Ord;
52}
53
54impl IpProtoExt for Ipv4 {
55 type Proto = Ipv4Proto;
56}
57
58impl IpProtoExt for Ipv6 {
59 type Proto = Ipv6Proto;
60}
61
62pub struct IpEnvelope<I: IpExt> {
64 pub has_options: bool,
66 _marker: PhantomData<I>,
67}
68
69impl<I: IpExt> IpEnvelope<I> {
70 pub fn new(has_options: bool) -> Self {
72 Self { has_options, _marker: PhantomData }
73 }
74}
75
76pub trait IpSerializationContext<I: IpExt>: SerializationContext {
78 fn envelope_to_state(envelope: IpEnvelope<I>) -> Self::ContextState;
80}
81
82impl<I: IpExt> IpSerializationContext<I> for NoOpSerializationContext {
83 fn envelope_to_state(_envelope: IpEnvelope<I>) -> Self::ContextState {
84 ()
85 }
86}
87
88pub trait IpExt: EthernetIpExt + IcmpIpExt {
91 type PacketParseError: From<ParseError> + Debug + PartialEq + Send + Sync;
93
94 type Packet<B: SplitByteSlice>: IpPacket<B, Self>
96 + GenericOverIp<Self, Type = Self::Packet<B>>
97 + GenericOverIp<Ipv4, Type = Ipv4Packet<B>>
98 + GenericOverIp<Ipv6, Type = Ipv6Packet<B>>;
99 type PacketRaw<B: SplitByteSlice>: IpPacketRaw<B, Self>
101 + GenericOverIp<Self, Type = Self::PacketRaw<B>>
102 + GenericOverIp<Ipv4, Type = Ipv4PacketRaw<B>>
103 + GenericOverIp<Ipv6, Type = Ipv6PacketRaw<B>>;
104 type PacketBuilder<C: IpSerializationContext<Self>>: IpPacketBuilder<C, Self> + Eq;
106 const MIN_HEADER_LENGTH: usize;
108}
109
110impl IpExt for Ipv4 {
111 type PacketParseError = ParseError;
112 type Packet<B: SplitByteSlice> = Ipv4Packet<B>;
113 type PacketRaw<B: SplitByteSlice> = Ipv4PacketRaw<B>;
114 type PacketBuilder<C: IpSerializationContext<Self>> = Ipv4PacketBuilder;
115
116 const MIN_HEADER_LENGTH: usize = IPV4_MIN_HDR_LEN;
117}
118
119impl IpExt for Ipv6 {
120 type PacketParseError = Ipv6ParseError;
121 type Packet<B: SplitByteSlice> = Ipv6Packet<B>;
122 type PacketRaw<B: SplitByteSlice> = Ipv6PacketRaw<B>;
123 type PacketBuilder<C: IpSerializationContext<Self>> = Ipv6PacketBuilder;
124
125 const MIN_HEADER_LENGTH: usize = IPV6_FIXED_HDR_LEN;
126}
127
128#[derive(Debug)]
130pub enum Nat64Error {
131 NotImplemented,
133}
134
135#[derive(Debug)]
137pub enum Nat64TranslationResult<S, E> {
138 Forward(S),
140 Drop,
142 Err(E),
144}
145
146#[derive(
151 Default,
152 Debug,
153 Clone,
154 Copy,
155 PartialEq,
156 Eq,
157 KnownLayout,
158 FromBytes,
159 IntoBytes,
160 Immutable,
161 Unaligned,
162)]
163#[repr(C)]
164pub struct DscpAndEcn(u8);
165
166const DSCP_OFFSET: u8 = 2;
167const DSCP_MAX: u8 = (1 << (8 - DSCP_OFFSET)) - 1;
168const ECN_MAX: u8 = (1 << DSCP_OFFSET) - 1;
169
170impl DscpAndEcn {
171 pub const fn default() -> Self {
174 Self(0)
175 }
176
177 pub const fn new(dscp: u8, ecn: u8) -> Self {
180 debug_assert!(dscp <= DSCP_MAX);
181 debug_assert!(ecn <= ECN_MAX);
182 Self((dscp << DSCP_OFFSET) + ecn)
183 }
184
185 pub const fn new_with_raw(value: u8) -> Self {
188 Self(value)
189 }
190
191 pub fn dscp(self) -> u8 {
193 let Self(v) = self;
194 v >> 2
195 }
196
197 pub fn ecn(self) -> u8 {
199 let Self(v) = self;
200 v & 0x3
201 }
202
203 pub fn raw(self) -> u8 {
205 let Self(value) = self;
206 value
207 }
208}
209
210impl From<u8> for DscpAndEcn {
211 fn from(value: u8) -> Self {
212 Self::new_with_raw(value)
213 }
214}
215
216pub trait IpPacket<B: SplitByteSlice, I: IpExt>:
220 Sized + Debug + ParsablePacket<B, (), Error = I::PacketParseError>
221{
222 type Builder<C: IpSerializationContext<I>>: IpPacketBuilder<C, I>;
224
225 fn src_ip(&self) -> I::Addr;
227
228 fn dst_ip(&self) -> I::Addr;
230
231 fn proto(&self) -> I::Proto;
233
234 fn ttl(&self) -> u8;
236
237 fn dscp_and_ecn(&self) -> DscpAndEcn;
240
241 fn set_ttl(&mut self, ttl: u8)
245 where
246 B: SplitByteSliceMut;
247
248 fn header_len(&self) -> usize;
250
251 fn body(&self) -> &[u8];
253
254 fn into_metadata(self) -> (I::Addr, I::Addr, I::Proto, ParseMetadata) {
259 let src_ip = self.src_ip();
260 let dst_ip = self.dst_ip();
261 let proto = self.proto();
262 let meta = self.parse_metadata();
263 (src_ip, dst_ip, proto, meta)
264 }
265
266 fn as_ip_addr_ref(&self) -> IpAddr<&'_ Ipv4Packet<B>, &'_ Ipv6Packet<B>>;
268
269 fn reassemble_fragmented_packet<'a, BV: BufferViewMut<B>, IT: Iterator<Item = &'a [u8]>>(
275 buffer: BV,
276 header: &[u8],
277 body_fragments: IT,
278 ) -> IpParseResult<I, ()>
279 where
280 B: SplitByteSliceMut;
281
282 fn to_vec(&self) -> Vec<u8>;
284
285 fn builder<C: IpSerializationContext<I>>(&self) -> Self::Builder<C>;
287}
288
289impl<B: SplitByteSlice> IpPacket<B, Ipv4> for Ipv4Packet<B> {
290 type Builder<C: IpSerializationContext<Ipv4>> = Ipv4PacketBuilder;
291
292 fn src_ip(&self) -> Ipv4Addr {
293 Ipv4Header::src_ip(self)
294 }
295 fn dst_ip(&self) -> Ipv4Addr {
296 Ipv4Header::dst_ip(self)
297 }
298 fn proto(&self) -> Ipv4Proto {
299 Ipv4Header::proto(self)
300 }
301 fn dscp_and_ecn(&self) -> DscpAndEcn {
302 Ipv4Header::dscp_and_ecn(self)
303 }
304 fn ttl(&self) -> u8 {
305 Ipv4Header::ttl(self)
306 }
307 fn set_ttl(&mut self, ttl: u8)
308 where
309 B: SplitByteSliceMut,
310 {
311 Ipv4Packet::set_ttl(self, ttl)
312 }
313 fn header_len(&self) -> usize {
314 Ipv4Packet::header_len(self)
315 }
316 fn body(&self) -> &[u8] {
317 Ipv4Packet::body(self)
318 }
319
320 fn as_ip_addr_ref(&self) -> IpAddr<&'_ Self, &'_ Ipv6Packet<B>> {
321 IpAddr::V4(self)
322 }
323
324 fn reassemble_fragmented_packet<'a, BV: BufferViewMut<B>, IT: Iterator<Item = &'a [u8]>>(
325 buffer: BV,
326 header: &[u8],
327 body_fragments: IT,
328 ) -> IpParseResult<Ipv4, ()>
329 where
330 B: SplitByteSliceMut,
331 {
332 crate::ipv4::reassemble_fragmented_packet(buffer, header, body_fragments)
333 }
334
335 fn to_vec(&self) -> Vec<u8> {
336 self.to_vec()
337 }
338
339 fn builder<C: IpSerializationContext<Ipv4>>(&self) -> Self::Builder<C> {
340 Ipv4Header::builder(self)
341 }
342}
343
344impl<B: SplitByteSlice> IpPacket<B, Ipv6> for Ipv6Packet<B> {
345 type Builder<C: IpSerializationContext<Ipv6>> = Ipv6PacketBuilder;
346
347 fn src_ip(&self) -> Ipv6Addr {
348 Ipv6Header::src_ip(self)
349 }
350 fn dst_ip(&self) -> Ipv6Addr {
351 Ipv6Header::dst_ip(self)
352 }
353 fn proto(&self) -> Ipv6Proto {
354 Ipv6Packet::proto(self)
355 }
356 fn dscp_and_ecn(&self) -> DscpAndEcn {
357 Ipv6Header::dscp_and_ecn(self)
358 }
359 fn ttl(&self) -> u8 {
360 Ipv6Header::hop_limit(self)
361 }
362 fn set_ttl(&mut self, ttl: u8)
363 where
364 B: SplitByteSliceMut,
365 {
366 Ipv6Packet::set_hop_limit(self, ttl)
367 }
368 fn header_len(&self) -> usize {
369 Ipv6Packet::header_len(self)
370 }
371 fn body(&self) -> &[u8] {
372 Ipv6Packet::body(self)
373 }
374
375 fn as_ip_addr_ref(&self) -> IpAddr<&'_ Ipv4Packet<B>, &'_ Self> {
376 IpAddr::V6(self)
377 }
378 fn reassemble_fragmented_packet<'a, BV: BufferViewMut<B>, IT: Iterator<Item = &'a [u8]>>(
379 buffer: BV,
380 header: &[u8],
381 body_fragments: IT,
382 ) -> IpParseResult<Ipv6, ()>
383 where
384 B: SplitByteSliceMut,
385 {
386 crate::ipv6::reassemble_fragmented_packet(buffer, header, body_fragments)
387 }
388
389 fn to_vec(&self) -> Vec<u8> {
390 self.to_vec()
391 }
392
393 fn builder<C: IpSerializationContext<Ipv6>>(&self) -> Self::Builder<C> {
394 self.builder()
395 }
396}
397
398pub trait IpPacketRaw<B: SplitByteSlice, I: IpExt>:
402 Sized + ParsablePacket<B, (), Error = I::PacketParseError>
403{
404}
405
406impl<B: SplitByteSlice> IpPacketRaw<B, Ipv4> for Ipv4PacketRaw<B> {}
407impl<B: SplitByteSlice, I: IpExt> GenericOverIp<I> for Ipv4PacketRaw<B> {
408 type Type = <I as IpExt>::PacketRaw<B>;
409}
410
411impl<B: SplitByteSlice> IpPacketRaw<B, Ipv6> for Ipv6PacketRaw<B> {}
412impl<B: SplitByteSlice, I: IpExt> GenericOverIp<I> for Ipv6PacketRaw<B> {
413 type Type = <I as IpExt>::PacketRaw<B>;
414}
415
416pub trait IpPacketBuilder<C: SerializationContext, I: IpExt>:
418 PacketBuilder<C> + PartialPacketBuilder<C> + Clone + Debug
419{
420 fn new(src_ip: I::Addr, dst_ip: I::Addr, ttl: u8, proto: I::Proto) -> Self;
424
425 fn src_ip(&self) -> I::Addr;
427
428 fn set_src_ip(&mut self, addr: I::Addr);
430
431 fn dst_ip(&self) -> I::Addr;
433
434 fn set_dst_ip(&mut self, addr: I::Addr);
436
437 fn proto(&self) -> I::Proto;
439
440 fn set_dscp_and_ecn(&mut self, dscp_and_ecn: DscpAndEcn);
442}
443
444pub trait IpProtocol: From<IpProto> + From<u8> + Sealed + Send + Sync + 'static {}
446
447impl Sealed for Never {}
448
449create_protocol_enum!(
450 #[allow(missing_docs)]
459 #[derive(Copy, Clone, Hash, Eq, Ord, PartialEq, PartialOrd)]
460 pub enum IpProto: u8 {
461 Tcp, 6, "TCP";
462 Udp, 17, "UDP";
463 Reserved, 255, "IANA-RESERVED";
464 }
465);
466
467create_protocol_enum!(
468 #[allow(missing_docs)]
474 #[derive(Copy, Clone, Hash, Eq, Ord, PartialEq, PartialOrd)]
475 pub enum Ipv4Proto: u8 {
476 Icmp, 1, "ICMP";
477 Igmp, 2, "IGMP";
478 + Proto(IpProto);
479 _, "IPv4 protocol {}";
480 }
481);
482
483impl IpProtocol for Ipv4Proto {}
484impl<I: Ip + IpProtoExt> GenericOverIp<I> for Ipv4Proto {
485 type Type = I::Proto;
486}
487impl Sealed for Ipv4Proto {}
488
489create_protocol_enum!(
490 #[allow(missing_docs)]
496 #[derive(Copy, Clone, Hash, Eq, Ord, PartialEq, PartialOrd)]
497 pub enum Ipv6Proto: u8 {
498 Icmpv6, 58, "ICMPv6";
499 NoNextHeader, 59, "NO NEXT HEADER";
500 + Proto(IpProto);
501 _, "IPv6 protocol {}";
502 }
503);
504
505impl IpProtocol for Ipv6Proto {}
506impl<I: Ip + IpProtoExt> GenericOverIp<I> for Ipv6Proto {
507 type Type = I::Proto;
508}
509impl Sealed for Ipv6Proto {}
510
511create_protocol_enum!(
512 #[allow(missing_docs)]
518 #[derive(Copy, Clone, Hash, Eq, PartialEq)]
519 pub enum Ipv6ExtHdrType: u8 {
520 HopByHopOptions, 0, "IPv6 HOP-BY-HOP OPTIONS HEADER";
521 Routing, 43, "IPv6 ROUTING HEADER";
522 Fragment, 44, "IPv6 FRAGMENT HEADER";
523 EncapsulatingSecurityPayload, 50, "ENCAPSULATING SECURITY PAYLOAD";
524 Authentication, 51, "AUTHENTICATION HEADER";
525 DestinationOptions, 60, "IPv6 DESTINATION OPTIONS HEADER";
526 _, "IPv6 EXTENSION HEADER {}";
527 }
528);
529
530#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Copy, Clone)]
541pub struct FragmentOffset(u16);
542
543impl FragmentOffset {
544 pub const ZERO: FragmentOffset = FragmentOffset(0);
546
547 pub const fn new(offset: u16) -> Option<Self> {
551 if offset < 1 << 13 { Some(Self(offset)) } else { None }
552 }
553
554 pub(crate) fn new_with_lsb(offset: u16) -> Self {
557 Self(offset & 0x1FFF)
558 }
559
560 pub(crate) fn new_with_msb(offset: u16) -> Self {
563 Self(offset >> 3)
564 }
565
566 pub const fn new_with_bytes(offset_bytes: u16) -> Option<Self> {
570 if offset_bytes & 0x7 == 0 {
571 Some(Self(offset_bytes >> 3))
573 } else {
574 None
575 }
576 }
577
578 pub const fn into_raw(self) -> u16 {
580 self.0
581 }
582
583 pub fn into_bytes(self) -> u16 {
588 self.0 << 3
591 }
592}
593
594#[cfg(test)]
595mod tests {
596 use super::*;
597
598 #[test]
599 fn fragment_offset_raw() {
600 assert_eq!(FragmentOffset::new(1), Some(FragmentOffset(1)));
601 assert_eq!(FragmentOffset::new(1 << 13), None);
602 }
603
604 #[test]
605 fn fragment_offset_bytes() {
606 assert_eq!(FragmentOffset::new_with_bytes(0), Some(FragmentOffset(0)));
607 for i in 1..=7 {
608 assert_eq!(FragmentOffset::new_with_bytes(i), None);
609 }
610 assert_eq!(FragmentOffset::new_with_bytes(8), Some(FragmentOffset(1)));
611 assert_eq!(FragmentOffset::new_with_bytes(u16::MAX), None);
612 assert_eq!(
613 FragmentOffset::new_with_bytes(u16::MAX & !0x7),
614 Some(FragmentOffset((1 << 13) - 1)),
615 );
616 }
617}