packet_formats/ipv6/
mod.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Parsing and serialization of IPv6 packets.
6//!
7//! The IPv6 packet format is defined in [RFC 8200] Sections 3 and 4.
8//!
9//! [RFC 8200]: https://datatracker.ietf.org/doc/html/rfc8200
10
11pub mod ext_hdrs;
12
13use alloc::vec::Vec;
14use core::borrow::Borrow;
15use core::fmt::{self, Debug, Formatter};
16use core::ops::Range;
17
18use log::debug;
19use net_types::ip::{GenericOverIp, Ipv4Addr, Ipv6, Ipv6Addr, Ipv6SourceAddr};
20use packet::records::{AlignedRecordSequenceBuilder, Records, RecordsRaw};
21use packet::{
22    BufferAlloc, BufferProvider, BufferView, BufferViewMut, EmptyBuf, FragmentedBytesMut, FromRaw,
23    GrowBufferMut, InnerPacketBuilder, MaybeParsed, PacketBuilder, PacketConstraints,
24    ParsablePacket, ParseMetadata, ReusableBuffer, SerializeError, SerializeTarget, Serializer,
25};
26use zerocopy::byteorder::network_endian::{U16, U32};
27use zerocopy::{
28    FromBytes, Immutable, IntoBytes, KnownLayout, Ref, SplitByteSlice, SplitByteSliceMut, Unaligned,
29};
30
31use crate::error::{IpParseError, IpParseErrorAction, IpParseResult, ParseError};
32use crate::icmp::Icmpv6ParameterProblemCode;
33use crate::ip::{
34    DscpAndEcn, FragmentOffset, IpExt, IpPacketBuilder, IpProto, Ipv4Proto, Ipv6ExtHdrType,
35    Ipv6Proto, Nat64Error, Nat64TranslationResult,
36};
37use crate::ipv4::{Ipv4PacketBuilder, HDR_PREFIX_LEN};
38use crate::tcp::{TcpParseArgs, TcpSegment};
39use crate::udp::{UdpPacket, UdpParseArgs};
40
41use ext_hdrs::{
42    is_valid_next_header, is_valid_next_header_upper_layer, ExtensionHeaderOptionAction,
43    HopByHopOption, HopByHopOptionData, Ipv6ExtensionHeader, Ipv6ExtensionHeaderData,
44    Ipv6ExtensionHeaderImpl, Ipv6ExtensionHeaderParsingContext, Ipv6ExtensionHeaderParsingError,
45    IPV6_FRAGMENT_EXT_HDR_LEN,
46};
47
48/// Length of the IPv6 fixed header.
49pub const IPV6_FIXED_HDR_LEN: usize = 40;
50
51/// The range of bytes within an IPv6 header buffer that the
52/// payload length field uses.
53pub const IPV6_PAYLOAD_LEN_BYTE_RANGE: Range<usize> = 4..6;
54
55// Offset to the Next Header field within the fixed IPv6 header
56const NEXT_HEADER_OFFSET: u8 = 6;
57
58// The maximum length for Hop-by-Hop Options. The stored byte's maximum
59// representable value is `core::u8::MAX` and it means the header has
60// that many 8-octets, not including the first 8 octets.
61const IPV6_HBH_OPTIONS_MAX_LEN: usize = (core::u8::MAX as usize) * 8 + 8;
62
63/// The maximum payload length after an IPv6 header.
64///
65/// The maximum IPv6 payload is the total number of bytes after the fixed header
66/// and must fit in a u16 as defined in [RFC 8200 Section 3].
67///
68/// [RFC 8200 Section 3]: https://datatracker.ietf.org/doc/html/rfc8200#section-3.
69const IPV6_MAX_PAYLOAD_LENGTH: usize = core::u16::MAX as usize;
70
71/// Convert an extension header parsing error to an IP packet
72/// parsing error.
73fn ext_hdr_err_fn(hdr: &FixedHeader, err: Ipv6ExtensionHeaderParsingError) -> IpParseError<Ipv6> {
74    // Below, we set parameter problem data's `pointer` to `IPV6_FIXED_HDR_LEN` + `pointer`
75    // since the the `pointer` we get from an `Ipv6ExtensionHeaderParsingError` is calculated
76    // from the start of the extension headers. Within an IPv6 packet, extension headers
77    // start right after the fixed header with a length of `IPV6_FIXED_HDR_LEN` so we add `pointer`
78    // to `IPV6_FIXED_HDR_LEN` to get the pointer to the field with the parameter problem error
79    // from the start of the IPv6 packet. For a non-jumbogram packet, we know that
80    // `IPV6_FIXED_HDR_LEN` + `pointer` will not overflow because the maximum size of an
81    // IPv6 packet is 65575 bytes (fixed header + extension headers + body) and 65575 definitely
82    // fits within an `u32`. This may no longer hold true if/when jumbogram packets are supported.
83    // For the jumbogram case when the size of extension headers could be >= (4 GB - 41 bytes) (which
84    // we almost certainly will never encounter), the pointer calculation may overflow. To account for
85    // this scenario, we check for overflows when adding `IPV6_FIXED_HDR_LEN` to `pointer`. If
86    // we do end up overflowing, we will discard the packet (even if we were normally required to
87    // send back an ICMP error message) because we will be unable to construct a correct ICMP error
88    // message (the pointer field of the ICMP message will not be able to hold a value > (4^32 - 1)
89    // which is what we would have if the pointer calculation overflows). But again, we should almost
90    // never encounter this scenario so we don't care if we have incorrect behaviour.
91
92    match err {
93        Ipv6ExtensionHeaderParsingError::ErroneousHeaderField {
94            pointer,
95            must_send_icmp,
96            header_len: _,
97        } => {
98            let (pointer, action) = match pointer.checked_add(IPV6_FIXED_HDR_LEN as u32) {
99                // Pointer calculation overflowed so set action to discard the packet and
100                // 0 for the pointer (which won't be used anyways since the packet will be
101                // discarded without sending an ICMP response).
102                None => (0, IpParseErrorAction::DiscardPacket),
103                // Pointer calculation didn't overflow so set action to send an ICMP
104                // message to the source of the original packet and the pointer value
105                // to what we calculated.
106                Some(p) => (p, IpParseErrorAction::DiscardPacketSendIcmpNoMulticast),
107            };
108
109            IpParseError::ParameterProblem {
110                src_ip: hdr.src_ip,
111                dst_ip: hdr.dst_ip,
112                code: Icmpv6ParameterProblemCode::ErroneousHeaderField,
113                pointer,
114                must_send_icmp,
115                header_len: (),
116                action,
117            }
118        }
119        Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader {
120            pointer,
121            must_send_icmp,
122            header_len: _,
123        } => {
124            let (pointer, action) = match pointer.checked_add(IPV6_FIXED_HDR_LEN as u32) {
125                None => (0, IpParseErrorAction::DiscardPacket),
126                Some(p) => (p, IpParseErrorAction::DiscardPacketSendIcmpNoMulticast),
127            };
128
129            IpParseError::ParameterProblem {
130                src_ip: hdr.src_ip,
131                dst_ip: hdr.dst_ip,
132                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
133                pointer,
134                must_send_icmp,
135                header_len: (),
136                action,
137            }
138        }
139        Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
140            pointer,
141            must_send_icmp,
142            header_len: _,
143            action,
144        } => {
145            let (pointer, action) = match pointer.checked_add(IPV6_FIXED_HDR_LEN as u32) {
146                None => (0, IpParseErrorAction::DiscardPacket),
147                Some(p) => {
148                    let action = match action {
149                        ExtensionHeaderOptionAction::SkipAndContinue => unreachable!(
150                            "Should never end up here because this action should never result in an error"
151                        ),
152                        ExtensionHeaderOptionAction::DiscardPacket => IpParseErrorAction::DiscardPacket,
153                        ExtensionHeaderOptionAction::DiscardPacketSendIcmp => {
154                            IpParseErrorAction::DiscardPacketSendIcmp
155                        }
156                        ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast => {
157                            IpParseErrorAction::DiscardPacketSendIcmpNoMulticast
158                        }
159                    };
160
161                    (p, action)
162                }
163            };
164
165            IpParseError::ParameterProblem {
166                src_ip: hdr.src_ip,
167                dst_ip: hdr.dst_ip,
168                code: Icmpv6ParameterProblemCode::UnrecognizedIpv6Option,
169                pointer,
170                must_send_icmp,
171                header_len: (),
172                action,
173            }
174        }
175        Ipv6ExtensionHeaderParsingError::BufferExhausted
176        | Ipv6ExtensionHeaderParsingError::MalformedData => {
177            // Unexpectedly running out of a buffer or encountering malformed
178            // data when parsing is a formatting error.
179            IpParseError::Parse { error: ParseError::Format }
180        }
181    }
182}
183
184/// The IPv6 fixed header which precedes any extension headers and the body.
185#[derive(Debug, Default, KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned, PartialEq)]
186#[repr(C)]
187pub struct FixedHeader {
188    version_tc_flowlabel: [u8; 4],
189    payload_len: U16,
190    next_hdr: u8,
191    hop_limit: u8,
192    src_ip: Ipv6Addr,
193    dst_ip: Ipv6Addr,
194}
195
196const IP_VERSION: u8 = 6;
197const VERSION_OFFSET: u8 = 4;
198const FLOW_LABEL_MAX: u32 = (1 << 20) - 1;
199
200impl FixedHeader {
201    #[allow(clippy::too_many_arguments)]
202    fn new(
203        dscp_and_ecn: DscpAndEcn,
204        flow_label: u32,
205        payload_len: u16,
206        next_hdr: u8,
207        hop_limit: u8,
208        src_ip: Ipv6Addr,
209        dst_ip: Ipv6Addr,
210    ) -> FixedHeader {
211        debug_assert!(flow_label <= FLOW_LABEL_MAX);
212
213        let traffic_class = dscp_and_ecn.raw();
214        FixedHeader {
215            version_tc_flowlabel: [
216                IP_VERSION << VERSION_OFFSET | traffic_class >> 4,
217                (traffic_class << 4) | ((flow_label >> 16) as u8),
218                (flow_label >> 8) as u8,
219                flow_label as u8,
220            ],
221            payload_len: U16::new(payload_len),
222            next_hdr,
223            hop_limit,
224            src_ip,
225            dst_ip,
226        }
227    }
228
229    fn version(&self) -> u8 {
230        self.version_tc_flowlabel[0] >> 4
231    }
232
233    fn dscp_and_ecn(&self) -> DscpAndEcn {
234        ((self.version_tc_flowlabel[0] & 0xF) << 4 | self.version_tc_flowlabel[1] >> 4).into()
235    }
236
237    fn flowlabel(&self) -> u32 {
238        (u32::from(self.version_tc_flowlabel[1]) & 0xF) << 16
239            | u32::from(self.version_tc_flowlabel[2]) << 8
240            | u32::from(self.version_tc_flowlabel[3])
241    }
242}
243
244/// Provides common access to IPv6 header fields.
245///
246/// `Ipv6Header` provides access to IPv6 header fields as a common
247/// implementation for both [`Ipv6Packet`] and [`Ipv6PacketRaw`].
248pub trait Ipv6Header {
249    /// Gets a reference to the IPv6 [`FixedHeader`].
250    fn get_fixed_header(&self) -> &FixedHeader;
251
252    /// The Hop Limit.
253    fn hop_limit(&self) -> u8 {
254        self.get_fixed_header().hop_limit
255    }
256
257    /// The Next Header.
258    fn next_header(&self) -> u8 {
259        self.get_fixed_header().next_hdr
260    }
261
262    /// The source IP address.
263    fn src_ip(&self) -> Ipv6Addr {
264        self.get_fixed_header().src_ip
265    }
266
267    /// The destination IP address.
268    fn dst_ip(&self) -> Ipv6Addr {
269        self.get_fixed_header().dst_ip
270    }
271
272    /// The Differentiated Services Code Point (DSCP) and the Explicit
273    /// Congestion Notification (ECN).
274    fn dscp_and_ecn(&self) -> DscpAndEcn {
275        self.get_fixed_header().dscp_and_ecn()
276    }
277}
278
279impl Ipv6Header for FixedHeader {
280    fn get_fixed_header(&self) -> &FixedHeader {
281        self
282    }
283}
284
285/// An IPv6 packet.
286///
287/// An `Ipv6Packet` shares its underlying memory with the byte slice it was
288/// parsed from or serialized to, meaning that no copying or extra allocation is
289/// necessary.
290pub struct Ipv6Packet<B> {
291    fixed_hdr: Ref<B, FixedHeader>,
292    extension_hdrs: Records<B, Ipv6ExtensionHeaderImpl>,
293    body: B,
294    proto: Ipv6Proto,
295}
296
297impl<B: SplitByteSlice, I: IpExt> GenericOverIp<I> for Ipv6Packet<B> {
298    type Type = <I as IpExt>::Packet<B>;
299}
300
301impl<B: SplitByteSlice> Ipv6Header for Ipv6Packet<B> {
302    fn get_fixed_header(&self) -> &FixedHeader {
303        &self.fixed_hdr
304    }
305}
306
307impl<B: SplitByteSlice> ParsablePacket<B, ()> for Ipv6Packet<B> {
308    type Error = IpParseError<Ipv6>;
309
310    fn parse_metadata(&self) -> ParseMetadata {
311        let header_len = Ref::bytes(&self.fixed_hdr).len() + self.extension_hdrs.bytes().len();
312        ParseMetadata::from_packet(header_len, self.body.len(), 0)
313    }
314
315    fn parse<BV: BufferView<B>>(buffer: BV, _args: ()) -> IpParseResult<Ipv6, Self> {
316        Ipv6PacketRaw::parse(buffer, ()).and_then(Ipv6Packet::try_from_raw)
317    }
318}
319
320impl<B: SplitByteSlice> FromRaw<Ipv6PacketRaw<B>, ()> for Ipv6Packet<B> {
321    type Error = IpParseError<Ipv6>;
322
323    fn try_from_raw_with(raw: Ipv6PacketRaw<B>, _args: ()) -> Result<Self, Self::Error> {
324        let fixed_hdr = raw.fixed_hdr;
325
326        // Make sure that the fixed header has a valid next header before
327        // validating extension headers.
328        if !is_valid_next_header(fixed_hdr.next_hdr, true) {
329            return debug_err!(
330                Err(IpParseError::ParameterProblem {
331                    src_ip: fixed_hdr.src_ip,
332                    dst_ip: fixed_hdr.dst_ip,
333                    code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
334                    pointer: u32::from(NEXT_HEADER_OFFSET),
335                    must_send_icmp: false,
336                    header_len: (),
337                    action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
338                }),
339                "Unrecognized next header value"
340            );
341        }
342
343        let extension_hdrs = match raw.extension_hdrs {
344            MaybeParsed::Complete(v) => {
345                Records::try_from_raw(v).map_err(|e| ext_hdr_err_fn(&fixed_hdr, e))?
346            }
347            MaybeParsed::Incomplete(_) => {
348                return debug_err!(
349                    Err(ParseError::Format.into()),
350                    "Incomplete IPv6 extension headers"
351                );
352            }
353        };
354
355        // If extension headers parse successfully, then proto and a
356        // `MaybeParsed` body MUST be available, and the proto must be a valid
357        // next header for upper layers.
358        let (body, proto) =
359            raw.body_proto.expect("Unable to retrieve Ipv6Proto or MaybeParsed body from raw");
360        debug_assert!(is_valid_next_header_upper_layer(proto.into()));
361
362        let body = match body {
363            MaybeParsed::Complete(b) => b,
364            MaybeParsed::Incomplete(_b) => {
365                return debug_err!(Err(ParseError::Format.into()), "IPv6 body unretrievable.");
366            }
367        };
368
369        // check that the lengths match:
370        //
371        // As per Section 3 of RFC 8200, payload length includes the length of
372        // the extension headers as well.
373        if extension_hdrs.bytes().len() + body.len() != usize::from(fixed_hdr.payload_len.get()) {
374            return debug_err!(
375                Err(ParseError::Format.into()),
376                "Payload len does not match body and extension headers"
377            );
378        }
379
380        // validate IP version in header
381        if fixed_hdr.version() != 6 {
382            return debug_err!(
383                Err(ParseError::Format.into()),
384                "unexpected IP version: {}",
385                fixed_hdr.version()
386            );
387        }
388
389        Ok(Ipv6Packet { fixed_hdr, extension_hdrs, body, proto })
390    }
391}
392
393impl<B: SplitByteSlice> Ipv6Packet<B> {
394    /// Returns an iterator over the extension headers.
395    pub fn iter_extension_hdrs(&self) -> impl Iterator<Item = Ipv6ExtensionHeader<'_>> {
396        self.extension_hdrs.iter()
397    }
398
399    /// The packet body.
400    pub fn body(&self) -> &[u8] {
401        &self.body
402    }
403
404    /// The Differentiated Services Code Point (DSCP) and the Explicit
405    /// Congestion Notification (ECN).
406    pub fn dscp_and_ecn(&self) -> DscpAndEcn {
407        self.fixed_hdr.dscp_and_ecn()
408    }
409
410    /// The flow label.
411    pub fn flowlabel(&self) -> u32 {
412        self.fixed_hdr.flowlabel()
413    }
414
415    /// The Upper layer protocol for this packet.
416    ///
417    /// This is found in the fixed header's Next Header if there are no extension
418    /// headers, or the Next Header value in the last extension header if there are.
419    /// This also  uses the same codes, encoded by the Rust type `Ipv6Proto`.
420    pub fn proto(&self) -> Ipv6Proto {
421        self.proto
422    }
423
424    /// The source IP address represented as an [`Ipv6SourceAddr`].
425    ///
426    /// Unlike [`IpHeader::src_ip`], `src_ipv6` returns an `Ipv6SourceAddr`,
427    /// which represents the valid values that a source address can take
428    /// (namely, a unicast or unspecified address) or `None` if the address is
429    /// invalid (namely, a multicast address or an ipv4-mapped-ipv6 address).
430    pub fn src_ipv6(&self) -> Option<Ipv6SourceAddr> {
431        Ipv6SourceAddr::new(self.fixed_hdr.src_ip)
432    }
433
434    /// Return a buffer that is a copy of the header bytes in this
435    /// packet, including the fixed and extension headers, but without
436    /// the first fragment extension header.
437    ///
438    /// Note, if there are multiple fragment extension headers, only
439    /// the first fragment extension header will be removed.
440    ///
441    /// # Panics
442    ///
443    /// Panics if there is no fragment extension header in this packet.
444    pub fn copy_header_bytes_for_fragment(&self) -> Vec<u8> {
445        // Since the final header will not include a fragment header, we don't
446        // need to allocate bytes for it (`IPV6_FRAGMENT_EXT_HDR_LEN` bytes).
447        let expected_bytes_len = self.header_len() - IPV6_FRAGMENT_EXT_HDR_LEN;
448        let mut bytes = Vec::with_capacity(expected_bytes_len);
449
450        bytes.extend_from_slice(Ref::bytes(&self.fixed_hdr));
451
452        // We cannot simply copy over the extension headers because we want
453        // discard the first fragment header, so we iterate over our
454        // extension headers and find out where our fragment header starts at.
455        let mut iter = self.extension_hdrs.iter();
456
457        // This should never panic because we must only call this function
458        // when the packet is fragmented so it must have at least one extension
459        // header (the fragment extension header).
460        let ext_hdr = iter.next().expect("packet must have at least one extension header");
461
462        if self.fixed_hdr.next_hdr == Ipv6ExtHdrType::Fragment.into() {
463            // The fragment header is the first extension header so
464            // we need to patch the fixed header.
465
466            // Update the next header value in the fixed header within the buffer
467            // to the next header value from the fragment header.
468            bytes[6] = ext_hdr.next_header;
469
470            // Copy extension headers that appear after the fragment header
471            bytes.extend_from_slice(&self.extension_hdrs.bytes()[IPV6_FRAGMENT_EXT_HDR_LEN..]);
472        } else {
473            let mut ext_hdr = ext_hdr;
474            let mut ext_hdr_start = 0;
475            let mut ext_hdr_end = iter.context().bytes_parsed;
476
477            // Here we keep looping until `next_ext_hdr` points to the fragment header.
478            // Once we find the fragment header, we update the next header value within
479            // the extension header preceeding the fragment header, `ext_hdr`. Note,
480            // we keep track of where in the extension header buffer the current `ext_hdr`
481            // starts and ends so we can patch its next header value.
482            loop {
483                // This should never panic because if we panic, it means that we got a
484                // `None` value from `iter.next()` which would mean we exhausted all the
485                // extension headers while looking for the fragment header, meaning there
486                // is no fragment header. This function should never be called if there
487                // is no fragment extension header in the packet.
488                let next_ext_hdr = iter
489                    .next()
490                    .expect("exhausted all extension headers without finding fragment header");
491
492                if let Ipv6ExtensionHeaderData::Fragment { .. } = next_ext_hdr.data() {
493                    // The next extension header is the fragment header
494                    // so we copy the buffer before and after the extension header
495                    // into `bytes` and patch the next header value within the
496                    // current extension header in `bytes`.
497
498                    // Size of the fragment header should be exactly `IPV6_FRAGMENT_EXT_HDR_LEN`.
499                    let fragment_hdr_end = ext_hdr_end + IPV6_FRAGMENT_EXT_HDR_LEN;
500                    assert_eq!(fragment_hdr_end, iter.context().bytes_parsed);
501
502                    let extension_hdr_bytes = self.extension_hdrs.bytes();
503
504                    // Copy extension headers that appear before the fragment header
505                    bytes.extend_from_slice(&extension_hdr_bytes[..ext_hdr_end]);
506
507                    // Copy extension headers that appear after the fragment header
508                    bytes.extend_from_slice(&extension_hdr_bytes[fragment_hdr_end..]);
509
510                    // Update the current `ext_hdr`'s next header value to the next
511                    // header value within the fragment extension header.
512                    match ext_hdr.data() {
513                        // The next header value is located in the first byte of the
514                        // extension header.
515                        Ipv6ExtensionHeaderData::HopByHopOptions { .. }
516                        | Ipv6ExtensionHeaderData::DestinationOptions { .. } => {
517                            bytes[IPV6_FIXED_HDR_LEN+ext_hdr_start] = next_ext_hdr.next_header;
518                        }
519                        Ipv6ExtensionHeaderData::Fragment { .. } => unreachable!("If we had a fragment header before `ext_hdr`, we should have used that instead"),
520                    }
521
522                    break;
523                }
524
525                ext_hdr = next_ext_hdr;
526                ext_hdr_start = ext_hdr_end;
527                ext_hdr_end = iter.context().bytes_parsed;
528            }
529        }
530
531        // `bytes`'s length should be exactly `expected_bytes_len`.
532        assert_eq!(bytes.len(), expected_bytes_len);
533        bytes
534    }
535
536    fn header_len(&self) -> usize {
537        Ref::bytes(&self.fixed_hdr).len() + self.extension_hdrs.bytes().len()
538    }
539
540    fn fragment_header_present(&self) -> bool {
541        for ext_hdr in self.extension_hdrs.iter() {
542            if matches!(ext_hdr.data(), Ipv6ExtensionHeaderData::Fragment { .. }) {
543                return true;
544            }
545        }
546        false
547    }
548
549    /// Construct a builder with the same contents as this packet.
550    pub fn builder(&self) -> Ipv6PacketBuilder {
551        Ipv6PacketBuilder {
552            dscp_and_ecn: self.dscp_and_ecn(),
553            flowlabel: self.flowlabel(),
554            hop_limit: self.hop_limit(),
555            proto: self.proto(),
556            src_ip: self.src_ip(),
557            dst_ip: self.dst_ip(),
558        }
559    }
560
561    /// Performs the header translation part of NAT64 as described in [RFC
562    /// 7915].
563    ///
564    /// `nat64_translate` follows the rules described in RFC 7915 to construct
565    /// the IPv4 equivalent of this IPv6 packet. If the payload is a TCP segment
566    /// or a UDP packet, its checksum will be updated. If the payload is an
567    /// ICMPv6 packet, it will be converted to the equivalent ICMPv4 packet. For
568    /// all other payloads, the payload will be unchanged, and the IP header will
569    /// be translated. On success, a [`Serializer`] is returned which describes
570    /// the new packet to be sent.
571    ///
572    /// Note that the IPv4 TTL/IPv6 Hop Limit field is not modified. It is the
573    /// caller's responsibility to decrement and process this field per RFC
574    /// 7915.
575    ///
576    /// In some cases, the packet has no IPv4 equivalent, in which case the
577    /// value [`Nat64TranslationResult::Drop`] will be returned, instructing the
578    /// caller to silently drop the packet.
579    ///
580    /// # Errors
581    ///
582    /// `nat64_translate` will return an error if support has not yet been
583    /// implemented for translating a particular IP protocol.
584    ///
585    /// [RFC 7915]: https://datatracker.ietf.org/doc/html/rfc7915
586    pub fn nat64_translate(
587        &self,
588        v4_src_addr: Ipv4Addr,
589        v4_dst_addr: Ipv4Addr,
590    ) -> Nat64TranslationResult<impl Serializer<Buffer = EmptyBuf> + Debug + '_, Nat64Error> {
591        // A single `Serializer` type so that all possible return values from
592        // this function have the same type.
593        #[derive(Debug)]
594        enum Nat64Serializer<T, U, O> {
595            Tcp(T),
596            Udp(U),
597            Other(O),
598        }
599
600        impl<T, U, O> Serializer for Nat64Serializer<T, U, O>
601        where
602            T: Serializer<Buffer = EmptyBuf>,
603            U: Serializer<Buffer = EmptyBuf>,
604            O: Serializer<Buffer = EmptyBuf>,
605        {
606            type Buffer = EmptyBuf;
607            fn serialize<B, P>(
608                self,
609                outer: PacketConstraints,
610                provider: P,
611            ) -> Result<B, (SerializeError<P::Error>, Self)>
612            where
613                B: GrowBufferMut,
614                P: BufferProvider<Self::Buffer, B>,
615            {
616                match self {
617                    Nat64Serializer::Tcp(serializer) => serializer
618                        .serialize(outer, provider)
619                        .map_err(|(err, ser)| (err, Nat64Serializer::Tcp(ser))),
620                    Nat64Serializer::Udp(serializer) => serializer
621                        .serialize(outer, provider)
622                        .map_err(|(err, ser)| (err, Nat64Serializer::Udp(ser))),
623                    Nat64Serializer::Other(serializer) => serializer
624                        .serialize(outer, provider)
625                        .map_err(|(err, ser)| (err, Nat64Serializer::Other(ser))),
626                }
627            }
628
629            fn serialize_new_buf<B: ReusableBuffer, A: BufferAlloc<B>>(
630                &self,
631                outer: PacketConstraints,
632                alloc: A,
633            ) -> Result<B, SerializeError<A::Error>> {
634                match self {
635                    Nat64Serializer::Tcp(serializer) => serializer.serialize_new_buf(outer, alloc),
636                    Nat64Serializer::Udp(serializer) => serializer.serialize_new_buf(outer, alloc),
637                    Nat64Serializer::Other(serializer) => {
638                        serializer.serialize_new_buf(outer, alloc)
639                    }
640                }
641            }
642        }
643
644        // TODO(https://fxbug.dev/42174049): Add support for fragmented packets
645        // forwarding.
646        if self.fragment_header_present() {
647            return Nat64TranslationResult::Err(Nat64Error::NotImplemented);
648        }
649
650        let v4_builder = |v4_proto| {
651            let mut builder =
652                Ipv4PacketBuilder::new(v4_src_addr, v4_dst_addr, self.hop_limit(), v4_proto);
653            builder.dscp_and_ecn(self.dscp_and_ecn());
654
655            // The IPv4 header length is 20 bytes (so IHL field value is 5), as
656            // no header options are present in translated IPv4 packet.
657            // As per RFC 7915 Section 5.1:
658            //  "Internet Header Length:  5 (no IPv4 options)"
659            const IPV4_HEADER_LEN_BYTES: usize = HDR_PREFIX_LEN;
660
661            // As per RFC 7915 Section 5.1,
662            //    "Flags:  The More Fragments flag is set to zero.  The Don't Fragment
663            //        (DF) flag is set as follows: If the size of the translated IPv4
664            //        packet is less than or equal to 1260 bytes, it is set to zero;
665            //        otherwise, it is set to one."
666            builder.df_flag(self.body().len() + IPV4_HEADER_LEN_BYTES > 1260);
667
668            // TODO(https://fxbug.dev/42174049): This needs an update once
669            // we don't return early for fragment_header_present case.
670            builder.fragment_offset(FragmentOffset::ZERO);
671            builder.mf_flag(false);
672
673            builder
674        };
675
676        match self.proto() {
677            Ipv6Proto::Proto(IpProto::Tcp) => {
678                let v4_pkt_builder = v4_builder(Ipv4Proto::Proto(IpProto::Tcp));
679                let args = TcpParseArgs::new(self.src_ip(), self.dst_ip());
680                // TODO(https://fxbug.dev/42174405): We're doing roughly similar work
681                // in valid/invalid parsing case. Remove match statement and
682                // update the checksum in place without needing to parse the TCP
683                // segment once we have ability to update the checksum.
684                match TcpSegment::parse(&mut self.body.as_bytes(), args) {
685                    Ok(tcp) => {
686                        // Creating a new tcp_serializer for IPv6 packet from
687                        // the existing one ensures that checksum is
688                        // updated due to changed IP addresses.
689                        let tcp_serializer =
690                            Nat64Serializer::Tcp(tcp.into_serializer(v4_src_addr, v4_dst_addr));
691                        Nat64TranslationResult::Forward(tcp_serializer.encapsulate(v4_pkt_builder))
692                    }
693                    Err(msg) => {
694                        debug!("Parsing of TCP segment failed: {:?}", msg);
695
696                        // This means we can't create a TCP segment builder with
697                        // updated checksum. Parsing may fail due to a variety of
698                        // reasons, including incorrect checksum in incoming packet.
699                        // We should still return a packet with IP payload copied
700                        // as is from IPv6 to IPv4. This handling is similar to
701                        // the handling of the case with unsupported protocol type
702                        // as done in `Ipv6Proto::Other(val)` case below. The similar
703                        // reasoning from RFC appiles here as well.
704                        let common_serializer =
705                            Nat64Serializer::Other(self.body().into_serializer());
706                        Nat64TranslationResult::Forward(
707                            common_serializer.encapsulate(v4_pkt_builder),
708                        )
709                    }
710                }
711            }
712
713            // TODO(https://fxbug.dev/42174405): We're doing roughly similar work
714            // in valid/invalid parsing case. Remove match statement and
715            // update the checksum in place without needing to parse the UDP segment
716            // once we have ability to update checksum.
717            Ipv6Proto::Proto(IpProto::Udp) => {
718                let v4_pkt_builder = v4_builder(Ipv4Proto::Proto(IpProto::Udp));
719                let args = UdpParseArgs::new(self.src_ip(), self.dst_ip());
720                match UdpPacket::parse(&mut self.body.as_bytes(), args) {
721                    Ok(udp) => {
722                        // Creating a new udp_serializer for IPv6 packet from
723                        // the existing one ensures that checksum is
724                        // updated due to changed IP addresses.
725                        let udp_serializer =
726                            Nat64Serializer::Udp(udp.into_serializer(v4_src_addr, v4_dst_addr));
727                        Nat64TranslationResult::Forward(udp_serializer.encapsulate(v4_pkt_builder))
728                    }
729                    Err(msg) => {
730                        debug!("Parsing of UDP packet failed: {:?}", msg);
731
732                        // This means we can't create a UDP packet builder with
733                        // updated checksum. Parsing may fail due to a variety of
734                        // reasons, including incorrect checksum in incoming packet.
735                        // We should still return a packet with IP payload copied
736                        // as is from IPv6 to IPv4. This handling is similar to
737                        // the handling of the case with unsupported protocol type
738                        // as done in `Ipv6Proto::Other(val)` case below. The similar
739                        // reasoning from RFC appiles here as well.
740
741                        let common_serializer =
742                            Nat64Serializer::Other(self.body().into_serializer());
743                        Nat64TranslationResult::Forward(
744                            common_serializer.encapsulate(v4_pkt_builder),
745                        )
746                    }
747                }
748            }
749
750            // TODO(https://fxbug.dev/42174051): Implement ICMP packet translation
751            // support here.
752            Ipv6Proto::Icmpv6 => Nat64TranslationResult::Err(Nat64Error::NotImplemented),
753
754            // For all other protocols, an IPv4 packet must be forwarded even if
755            // the transport layer checksum update is not implemented.
756            // As per RFC 7915 Section 5.1,
757            //     "Protocol:
758            //       ...
759            //
760            //       For the first 'next header' that does not match one of the cases
761            //       above, its Next Header value (which contains the transport
762            //       protocol number) is copied to the protocol field in the IPv4
763            //       header.  This means that all transport protocols are translated.
764            //
765            //       Note:  Some translated protocols will fail at the receiver for
766            //          various reasons: some are known to fail when translated (e.g.,
767            //          IPsec Authentication Header (51)), and others will fail
768            //          checksum validation if the address translation is not checksum
769            //          neutral [RFC6052] and the translator does not update the
770            //          transport protocol's checksum (because the translator doesn't
771            //          support recalculating the checksum for that transport protocol;
772            //          see Section 5.5)."
773            Ipv6Proto::Other(val) => {
774                let v4_pkt_builder = v4_builder(Ipv4Proto::Other(val));
775                let common_serializer = Nat64Serializer::Other(self.body().into_serializer());
776                Nat64TranslationResult::Forward(common_serializer.encapsulate(v4_pkt_builder))
777            }
778
779            Ipv6Proto::NoNextHeader => {
780                let v4_pkt_builder = v4_builder(Ipv4Proto::Other(Ipv6Proto::NoNextHeader.into()));
781                let common_serializer = Nat64Serializer::Other(self.body().into_serializer());
782                Nat64TranslationResult::Forward(common_serializer.encapsulate(v4_pkt_builder))
783            }
784
785            // Don't forward packets that use IANA's reserved protocol; they're
786            // invalid.
787            Ipv6Proto::Proto(IpProto::Reserved) => Nat64TranslationResult::Drop,
788        }
789    }
790
791    /// Copies the packet (Header + Extensions + Body) into a `Vec`.
792    pub fn to_vec(&self) -> Vec<u8> {
793        let Ipv6Packet { fixed_hdr, extension_hdrs, body, proto: _ } = self;
794        let mut buf = Vec::with_capacity(
795            Ref::bytes(&fixed_hdr).len() + extension_hdrs.bytes().len() + body.as_bytes().len(),
796        );
797        buf.extend(Ref::bytes(&fixed_hdr));
798        buf.extend(extension_hdrs.bytes());
799        buf.extend(body.as_bytes());
800        buf
801    }
802}
803
804impl<B: SplitByteSliceMut> Ipv6Packet<B> {
805    /// Set the source IP address.
806    pub fn set_src_ip(&mut self, addr: Ipv6Addr) {
807        self.fixed_hdr.src_ip = addr;
808    }
809
810    /// Set the destination IP address.
811    pub fn set_dst_ip(&mut self, addr: Ipv6Addr) {
812        self.fixed_hdr.dst_ip = addr;
813    }
814
815    /// Set the hop limit.
816    pub fn set_hop_limit(&mut self, hlim: u8) {
817        self.fixed_hdr.hop_limit = hlim;
818    }
819
820    /// The packet body.
821    pub fn body_mut(&mut self) -> &mut [u8] {
822        &mut self.body
823    }
824
825    /// Provides simultaneous access to header, extension headers, and mutable
826    /// body.
827    pub fn parts_with_body_mut(&mut self) -> (&FixedHeader, ExtensionHeaders<'_>, &mut [u8]) {
828        (&self.fixed_hdr, ExtensionHeaders(self.extension_hdrs.as_ref()), &mut self.body)
829    }
830}
831
832impl<B: SplitByteSlice> Debug for Ipv6Packet<B> {
833    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
834        f.debug_struct("Ipv6Packet")
835            .field("src_ip", &self.src_ip())
836            .field("dst_ip", &self.dst_ip())
837            .field("hop_limit", &self.hop_limit())
838            .field("proto", &self.proto())
839            .field("dscp", &self.dscp_and_ecn().dscp())
840            .field("ecn", &self.dscp_and_ecn().ecn())
841            .field("flowlabel", &self.flowlabel())
842            .field("extension headers", &"TODO")
843            .field("body", &alloc::format!("<{} bytes>", self.body.len()))
844            .finish()
845    }
846}
847
848/// The extension headers in an [`Ipv6Packet`].
849pub struct ExtensionHeaders<'a>(Records<&'a [u8], Ipv6ExtensionHeaderImpl>);
850
851impl<'a> ExtensionHeaders<'a> {
852    /// Returns an iterator over the extension headers.
853    pub fn iter(&self) -> impl Iterator<Item = Ipv6ExtensionHeader<'_>> {
854        self.0.iter()
855    }
856}
857
858/// We were unable to parse the extension headers.
859///
860/// As a result, we were unable to determine the upper-layer Protocol Number
861/// (which is stored in the last extension header's Next Header field) and were
862/// unable figure out where the body begins.
863#[derive(Copy, Clone, Debug, Eq, PartialEq)]
864pub struct ExtHdrParseError;
865
866/// A partially parsed and not yet validated IPv6 packet.
867///
868/// `Ipv6PacketRaw` provides minimal parsing of an IPv6 packet, namely
869/// it only requires that the fixed header part ([`HeaderPrefix`]) be retrieved,
870/// all the other parts of the packet may be missing when attempting to create
871/// it.
872///
873/// [`Ipv6Packet`] provides a [`FromRaw`] implementation that can be used to
874/// validate an `Ipv6PacketRaw`.
875pub struct Ipv6PacketRaw<B> {
876    /// A raw packet always contains at least a fully parsed `FixedHeader`.
877    fixed_hdr: Ref<B, FixedHeader>,
878    /// When `extension_hdrs` is [`MaybeParsed::Complete`], it contains the
879    /// `RecordsRaw` that can be validated for full extension headers parsing.
880    /// Otherwise, it just contains the extension header bytes that were
881    /// successfully consumed before reaching an error (typically "buffer
882    /// exhausted").
883    extension_hdrs: MaybeParsed<RecordsRaw<B, Ipv6ExtensionHeaderImpl>, B>,
884    /// The body and upper-layer Protocol Number.
885    ///
886    /// If extension headers failed to parse, this will be
887    /// `Err(ExtHdrParseError)`. Extension headers must be parsed in order to
888    /// find the bounds of the upper-layer payload and to find that last
889    /// extension header's Next Header field, which is the Protocol Number of
890    /// the upper-layer payload.
891    ///
892    /// The body will be [`MaybeParsed::Complete`] if all the body bytes were
893    /// consumed (as stated by the header's payload length value) or
894    /// [`MaybeParsed::Incomplete`] containing the bytes that were present
895    /// otherwise.
896    body_proto: Result<(MaybeParsed<B, B>, Ipv6Proto), ExtHdrParseError>,
897}
898
899impl<B> Ipv6PacketRaw<B> {
900    /// Returns a mutable reference to the body bytes of this [`Ipv6PacketRaw`].
901    ///
902    /// Might not be complete if a full packet was not received.
903    pub fn body_mut(&mut self) -> Option<&mut B> {
904        match self.body_proto {
905            Ok(ref mut b) => match b {
906                (MaybeParsed::Complete(ref mut b), _) => Some(b),
907                (MaybeParsed::Incomplete(ref mut b), _) => Some(b),
908            },
909            Err(_) => None,
910        }
911    }
912}
913
914impl<B: SplitByteSlice> Ipv6Header for Ipv6PacketRaw<B> {
915    fn get_fixed_header(&self) -> &FixedHeader {
916        &self.fixed_hdr
917    }
918}
919
920impl<B: SplitByteSlice> ParsablePacket<B, ()> for Ipv6PacketRaw<B> {
921    type Error = IpParseError<Ipv6>;
922
923    fn parse<BV: BufferView<B>>(mut buffer: BV, _args: ()) -> Result<Self, Self::Error> {
924        let fixed_hdr = buffer
925            .take_obj_front::<FixedHeader>()
926            .ok_or_else(debug_err_fn!(ParseError::Format, "too few bytes for header"))?;
927        let payload_len = fixed_hdr.payload_len.get().into();
928        // Trim the buffer if it exceeds the length specified in the header.
929        let _: Option<B> = buffer.len().checked_sub(payload_len).map(|padding| {
930            buffer.take_back(padding).unwrap_or_else(|| {
931                panic!("buffer.len()={} padding={}", buffer.len(), padding);
932            })
933        });
934
935        let mut extension_hdr_context = Ipv6ExtensionHeaderParsingContext::new(fixed_hdr.next_hdr);
936
937        let extension_hdrs =
938            RecordsRaw::parse_raw_with_mut_context(&mut buffer, &mut extension_hdr_context)
939                .map_incomplete(|(b, _)| b);
940
941        let body_proto = match &extension_hdrs {
942            MaybeParsed::Complete(r) => {
943                let _: &RecordsRaw<B, _> = r;
944                // If we have extension headers our context's
945                // (`extension_hdr_context`) `next_header` would be updated with
946                // the last extension header's Next Header value. This will also
947                // work if we don't have any extension headers. Let's consider
948                // that scenario: When we have no extension headers, the Next
949                // Header value in the fixed header will be a valid upper layer
950                // protocol value.  `parse_bv_with_mut_context` will return
951                // almost immediately without doing any actual work when it
952                // checks the context's (`extension_hdr_context`) `next_header`
953                // value and ends parsing since, according to our context, its
954                // data is for an upper layer protocol. Now, since nothing was
955                // parsed, our context was never modified, so the next header
956                // value it was initialized with when calling
957                // `Ipv6ExtensionHeaderParsingContext::new`, will not have
958                // changed. We simply use that value and assign it to proto
959                // below.
960
961                // Extension header raw parsing only finishes when we have a
962                // valid next header that is meant for the upper layer. The
963                // assertion below enforces that contract.
964                assert!(is_valid_next_header_upper_layer(extension_hdr_context.next_header));
965                let proto = Ipv6Proto::from(extension_hdr_context.next_header);
966                let body = MaybeParsed::new_with_min_len(
967                    buffer.into_rest(),
968                    payload_len.saturating_sub(extension_hdrs.len()),
969                );
970                Ok((body, proto))
971            }
972            MaybeParsed::Incomplete(b) => {
973                let _: &B = b;
974                Err(ExtHdrParseError)
975            }
976        };
977
978        Ok(Ipv6PacketRaw { fixed_hdr, extension_hdrs, body_proto })
979    }
980
981    fn parse_metadata(&self) -> ParseMetadata {
982        let header_len = Ref::bytes(&self.fixed_hdr).len() + self.extension_hdrs.len();
983        let body_len = self.body_proto.as_ref().map(|(b, _p)| b.len()).unwrap_or(0);
984        ParseMetadata::from_packet(header_len, body_len, 0)
985    }
986}
987
988impl<B: SplitByteSlice> Ipv6PacketRaw<B> {
989    /// Returns the body and upper-layer Protocol Number.
990    ///
991    /// If extension headers failed to parse, `body_proto` returns
992    /// `Err(ExtHdrParseError)`. Extension headers must be parsed in order to
993    /// find the bounds of the upper-layer payload and to find that last
994    /// extension header's Next Header field, which is the Protocol Number of
995    /// the upper-layer payload.
996    ///
997    /// The returned body will be [`MaybeParsed::Complete`] if all the body
998    /// bytes were consumed (as stated by the header's payload length value) or
999    /// [`MaybeParsed::Incomplete`] containing the bytes that were present
1000    /// otherwise.
1001    pub fn body_proto(&self) -> Result<(MaybeParsed<&[u8], &[u8]>, Ipv6Proto), ExtHdrParseError> {
1002        self.body_proto
1003            .as_ref()
1004            .map(|(mp, proto)| {
1005                (mp.as_ref().map(|b| b.deref()).map_incomplete(|b| b.deref()), *proto)
1006            })
1007            .map_err(|e| *e)
1008    }
1009
1010    /// Returns the body.
1011    ///
1012    /// If extension headers failed to parse, `body` returns
1013    /// `Err(ExtHdrParseError)`. Extension headers must be parsed in order to
1014    /// find the bounds of the upper-layer payload.
1015    ///
1016    /// The returned body will be [`MaybeParsed::Complete`] if all the body
1017    /// bytes were consumed (as stated by the header's payload length value) or
1018    /// [`MaybeParsed::Incomplete`] containing the bytes that were present
1019    /// otherwise.
1020    pub fn body(&self) -> Result<MaybeParsed<&[u8], &[u8]>, ExtHdrParseError> {
1021        self.body_proto().map(|(body, _proto)| body)
1022    }
1023
1024    /// Returns the upper-layer Protocol Number.
1025    ///
1026    /// If extension headers failed to parse, `body_proto` returns
1027    /// `Err(ExtHdrParseError)`. Extension headers must be parsed in order to
1028    /// find the last extension header's Next Header field, which is the
1029    /// Protocol Number of the upper-layer payload.
1030    pub fn proto(&self) -> Result<Ipv6Proto, ExtHdrParseError> {
1031        self.body_proto().map(|(_body, proto)| proto)
1032    }
1033}
1034
1035impl<B: SplitByteSliceMut> Ipv6PacketRaw<B> {
1036    /// Set the source IP address.
1037    pub fn set_src_ip(&mut self, addr: Ipv6Addr) {
1038        self.fixed_hdr.src_ip = addr;
1039    }
1040
1041    /// Set the destination IP address.
1042    pub fn set_dst_ip(&mut self, addr: Ipv6Addr) {
1043        self.fixed_hdr.dst_ip = addr;
1044    }
1045}
1046
1047/// A next header that may be either a next layer header or an IPv6 extension
1048/// header.
1049pub enum NextHeader {
1050    /// A next layer header follows.
1051    NextLayer(Ipv6Proto),
1052    /// An extension header follows.
1053    Extension(Ipv6ExtHdrType),
1054}
1055
1056impl From<NextHeader> for u8 {
1057    fn from(next_hdr: NextHeader) -> Self {
1058        match next_hdr {
1059            NextHeader::NextLayer(n) => n.into(),
1060            NextHeader::Extension(e) => e.into(),
1061        }
1062    }
1063}
1064
1065mod sealed {
1066    use super::*;
1067    /// A marker trait for IPv6 headers that can be serialized before header
1068    /// `T`.
1069    ///
1070    /// This trait is used to enforce IPv6 extension header ordering according
1071    /// to [RFC 8200 Section 4.1].
1072    ///
1073    /// [RFC 8200 Section 4.1]: https://datatracker.ietf.org/doc/html/rfc8200#section-4.1
1074    pub trait Ipv6HeaderBefore<T> {}
1075
1076    impl<'a, O, T> Ipv6HeaderBefore<T> for &'a O where O: Ipv6HeaderBefore<T> {}
1077
1078    /// A trait abstracting all types of IPv6 header builders.
1079    pub trait Ipv6HeaderBuilder {
1080        /// Returns an immutable reference to the fixed header builder.
1081        fn fixed_header(&self) -> &Ipv6PacketBuilder;
1082
1083        /// Returns the total header length of the extension headers, including
1084        /// previous extension headers, but excluding the fixed header size.
1085        fn extension_headers_len(&self) -> usize;
1086
1087        /// Serializes the header into `buffer`.
1088        ///
1089        /// `next_header` is the header immediately after the current one.
1090        /// `payload_len` is the total size of the frame after this header.
1091        fn serialize_header<B: SplitByteSliceMut, BV: BufferViewMut<B>>(
1092            &self,
1093            buffer: &mut BV,
1094            next_header: NextHeader,
1095            payload_len: usize,
1096        );
1097    }
1098}
1099use sealed::{Ipv6HeaderBefore, Ipv6HeaderBuilder};
1100
1101impl<'a, O> Ipv6HeaderBuilder for &'a O
1102where
1103    O: Ipv6HeaderBuilder,
1104{
1105    fn fixed_header(&self) -> &Ipv6PacketBuilder {
1106        O::fixed_header(self)
1107    }
1108
1109    fn extension_headers_len(&self) -> usize {
1110        O::extension_headers_len(self)
1111    }
1112
1113    fn serialize_header<B: SplitByteSliceMut, BV: BufferViewMut<B>>(
1114        &self,
1115        buffer: &mut BV,
1116        next_header: NextHeader,
1117        payload_len: usize,
1118    ) {
1119        O::serialize_header(self, buffer, next_header, payload_len)
1120    }
1121}
1122
1123/// A helper macro to implement `PacketBuilder` methods for implementers of
1124/// `Ipv6HeaderBuilder`.
1125///
1126/// This can't be a blanket impl because `PacketBuilder` is a foreign trait.
1127macro_rules! impl_packet_builder {
1128    {} => {
1129        fn constraints(&self) -> PacketConstraints {
1130            let ext_headers = self.extension_headers_len();
1131            let header_len = IPV6_FIXED_HDR_LEN + ext_headers;
1132            let footer_len = 0;
1133            let min_body_len = 0;
1134            // Extension headers take from the IPv6 available payload size.
1135            // See RFC 8200 Section 3 for details.
1136            let max_body_len = IPV6_MAX_PAYLOAD_LENGTH - ext_headers;
1137            PacketConstraints::new(header_len, footer_len, min_body_len, max_body_len)
1138        }
1139
1140        fn serialize(&self, target: &mut SerializeTarget<'_>, body: FragmentedBytesMut<'_, '_>) {
1141            let mut bv = &mut target.header;
1142            self.serialize_header(
1143                &mut bv,
1144                NextHeader::NextLayer(self.fixed_header().proto()),
1145                body.len(),
1146            );
1147        }
1148    }
1149}
1150
1151/// A builder for IPv6 packets.
1152#[derive(Debug, Clone, Eq, PartialEq)]
1153pub struct Ipv6PacketBuilder {
1154    dscp_and_ecn: DscpAndEcn,
1155    flowlabel: u32,
1156    hop_limit: u8,
1157    // The protocol number of the upper layer protocol, not the Next Header
1158    // value of the first extension header (if one exists).
1159    proto: Ipv6Proto,
1160    src_ip: Ipv6Addr,
1161    dst_ip: Ipv6Addr,
1162}
1163
1164impl Ipv6PacketBuilder {
1165    /// Constructs a new `Ipv6PacketBuilder`.
1166    ///
1167    /// The `proto` field encodes the protocol number identifying the upper
1168    /// layer payload, not the Next Header value of the first extension header
1169    /// (if one exists).
1170    pub fn new<S: Into<Ipv6Addr>, D: Into<Ipv6Addr>>(
1171        src_ip: S,
1172        dst_ip: D,
1173        hop_limit: u8,
1174        proto: Ipv6Proto,
1175    ) -> Ipv6PacketBuilder {
1176        Ipv6PacketBuilder {
1177            dscp_and_ecn: DscpAndEcn::default(),
1178            flowlabel: 0,
1179            hop_limit,
1180            proto,
1181            src_ip: src_ip.into(),
1182            dst_ip: dst_ip.into(),
1183        }
1184    }
1185
1186    /// Set the Differentiated Services Code Point (DSCP) and the Explicit
1187    /// Congestion Notification (ECN).
1188    pub fn dscp_and_ecn(&mut self, dscp_and_ecn: DscpAndEcn) {
1189        self.dscp_and_ecn = dscp_and_ecn;
1190    }
1191
1192    /// Set the flowlabel.
1193    ///
1194    /// # Panics
1195    ///
1196    /// `flowlabel` panics if `flowlabel` is greater than 2^20 - 1.
1197    pub fn flowlabel(&mut self, flowlabel: u32) {
1198        assert!(flowlabel <= 1 << 20, "invalid flowlabel: {:x}", flowlabel);
1199        self.flowlabel = flowlabel;
1200    }
1201}
1202
1203impl Ipv6HeaderBuilder for Ipv6PacketBuilder {
1204    fn fixed_header(&self) -> &Ipv6PacketBuilder {
1205        self
1206    }
1207
1208    fn extension_headers_len(&self) -> usize {
1209        0
1210    }
1211
1212    fn serialize_header<B: SplitByteSliceMut, BV: BufferViewMut<B>>(
1213        &self,
1214        buffer: &mut BV,
1215        next_header: NextHeader,
1216        payload_len: usize,
1217    ) {
1218        buffer
1219            .write_obj_front(&FixedHeader::new(
1220                self.dscp_and_ecn,
1221                self.flowlabel,
1222                {
1223                    // The caller promises to supply a body whose length
1224                    // does not exceed max_body_len. Doing this as a
1225                    // debug_assert (rather than an assert) is fine because,
1226                    // with debug assertions disabled, we'll just write an
1227                    // incorrect header value, which is acceptable if the
1228                    // caller has violated their contract.
1229                    debug_assert!(payload_len <= core::u16::MAX as usize);
1230                    payload_len as u16
1231                },
1232                next_header.into(),
1233                self.hop_limit,
1234                self.src_ip,
1235                self.dst_ip,
1236            ))
1237            .expect("not enough bytes for IPv6 fixed header");
1238    }
1239}
1240
1241impl PacketBuilder for Ipv6PacketBuilder {
1242    impl_packet_builder! {}
1243}
1244
1245/// A builder for Ipv6 packets with HBH Options.
1246#[derive(Debug, Clone)]
1247pub struct Ipv6PacketBuilderWithHbhOptions<'a, I> {
1248    prefix_builder: Ipv6PacketBuilder,
1249    hbh_options: AlignedRecordSequenceBuilder<HopByHopOption<'a>, I>,
1250}
1251
1252impl<'a, I> Ipv6PacketBuilderWithHbhOptions<'a, I>
1253where
1254    I: Iterator + Clone,
1255    I::Item: Borrow<HopByHopOption<'a>>,
1256{
1257    /// Creates a IPv6 packet builder with a Hop By Hop Options extension header.
1258    pub fn new<T: IntoIterator<Item = I::Item, IntoIter = I>>(
1259        prefix_builder: Ipv6PacketBuilder,
1260        options: T,
1261    ) -> Option<Ipv6PacketBuilderWithHbhOptions<'a, I>> {
1262        let iter = options.into_iter();
1263        // https://tools.ietf.org/html/rfc2711#section-2.1 specifies that
1264        // an RouterAlert option can only appear once.
1265        if iter
1266            .clone()
1267            .filter(|r| matches!(r.borrow().data, HopByHopOptionData::RouterAlert { .. }))
1268            .count()
1269            > 1
1270        {
1271            return None;
1272        }
1273        let hbh_options = AlignedRecordSequenceBuilder::new(2, iter);
1274        // And we don't want our options to become too long.
1275        if next_multiple_of_eight(2 + hbh_options.serialized_len()) > IPV6_HBH_OPTIONS_MAX_LEN {
1276            return None;
1277        }
1278        Some(Ipv6PacketBuilderWithHbhOptions { prefix_builder, hbh_options })
1279    }
1280
1281    fn aligned_hbh_len(&self) -> usize {
1282        let opt_len = self.hbh_options.serialized_len();
1283        let hbh_len = opt_len + 2;
1284        next_multiple_of_eight(hbh_len)
1285    }
1286}
1287
1288fn next_multiple_of_eight(x: usize) -> usize {
1289    (x + 7) & (!7)
1290}
1291
1292impl IpPacketBuilder<Ipv6> for Ipv6PacketBuilder {
1293    fn new(src_ip: Ipv6Addr, dst_ip: Ipv6Addr, ttl: u8, proto: Ipv6Proto) -> Self {
1294        Ipv6PacketBuilder::new(src_ip, dst_ip, ttl, proto)
1295    }
1296
1297    fn src_ip(&self) -> Ipv6Addr {
1298        self.src_ip
1299    }
1300
1301    fn set_src_ip(&mut self, addr: Ipv6Addr) {
1302        self.src_ip = addr;
1303    }
1304
1305    fn dst_ip(&self) -> Ipv6Addr {
1306        self.dst_ip
1307    }
1308
1309    fn set_dst_ip(&mut self, addr: Ipv6Addr) {
1310        self.dst_ip = addr;
1311    }
1312
1313    fn proto(&self) -> Ipv6Proto {
1314        self.proto
1315    }
1316
1317    fn set_dscp_and_ecn(&mut self, dscp_and_ecn: DscpAndEcn) {
1318        self.dscp_and_ecn = dscp_and_ecn;
1319    }
1320}
1321
1322impl<'a, I> Ipv6HeaderBuilder for Ipv6PacketBuilderWithHbhOptions<'a, I>
1323where
1324    I: Iterator + Clone,
1325    I::Item: Borrow<HopByHopOption<'a>>,
1326{
1327    fn fixed_header(&self) -> &Ipv6PacketBuilder {
1328        &self.prefix_builder
1329    }
1330
1331    fn extension_headers_len(&self) -> usize {
1332        self.prefix_builder.extension_headers_len() + self.aligned_hbh_len()
1333    }
1334
1335    fn serialize_header<B: SplitByteSliceMut, BV: BufferViewMut<B>>(
1336        &self,
1337        buffer: &mut BV,
1338        next_header: NextHeader,
1339        payload_len: usize,
1340    ) {
1341        let aligned_hbh_len = self.aligned_hbh_len();
1342        // The next header in the fixed header now should be 0 (Hop-by-Hop Extension Header)
1343        self.prefix_builder.serialize_header(
1344            buffer,
1345            NextHeader::Extension(Ipv6ExtHdrType::HopByHopOptions),
1346            payload_len + aligned_hbh_len,
1347        );
1348        // take the first two bytes to write in proto and length information.
1349        let mut hbh_header = buffer.take_front(aligned_hbh_len).unwrap();
1350        let hbh_header = hbh_header.as_mut();
1351        hbh_header[0] = next_header.into();
1352        hbh_header[1] = u8::try_from((aligned_hbh_len - 8) / 8).expect("extension header too big");
1353        self.hbh_options.serialize_into(&mut hbh_header[2..]);
1354    }
1355}
1356
1357impl<'a, I> PacketBuilder for Ipv6PacketBuilderWithHbhOptions<'a, I>
1358where
1359    I: Iterator + Clone,
1360    I::Item: Borrow<HopByHopOption<'a>>,
1361{
1362    impl_packet_builder! {}
1363}
1364
1365impl<'a, I> IpPacketBuilder<Ipv6> for Ipv6PacketBuilderWithHbhOptions<'a, I>
1366where
1367    I: Iterator<Item: Borrow<HopByHopOption<'a>>> + Debug + Default + Clone,
1368{
1369    fn new(src_ip: Ipv6Addr, dst_ip: Ipv6Addr, ttl: u8, proto: Ipv6Proto) -> Self {
1370        Ipv6PacketBuilderWithHbhOptions::new(
1371            Ipv6PacketBuilder::new(src_ip, dst_ip, ttl, proto),
1372            I::default(),
1373        )
1374        .expect("packet builder with no options should be valid")
1375    }
1376
1377    fn src_ip(&self) -> Ipv6Addr {
1378        self.prefix_builder.src_ip
1379    }
1380
1381    fn set_src_ip(&mut self, addr: Ipv6Addr) {
1382        self.prefix_builder.src_ip = addr;
1383    }
1384
1385    fn dst_ip(&self) -> Ipv6Addr {
1386        self.prefix_builder.dst_ip
1387    }
1388
1389    fn set_dst_ip(&mut self, addr: Ipv6Addr) {
1390        self.prefix_builder.dst_ip = addr;
1391    }
1392
1393    fn proto(&self) -> Ipv6Proto {
1394        self.prefix_builder.proto
1395    }
1396
1397    fn set_dscp_and_ecn(&mut self, dscp_and_ecn: DscpAndEcn) {
1398        self.prefix_builder.set_dscp_and_ecn(dscp_and_ecn)
1399    }
1400}
1401
1402/// An IPv6 packet builder that includes the fragmentation header.
1403///
1404/// `Ipv6PacketBuilderWithFragmentHeader` wraps another compatible packet
1405/// builder to attach the fragment header on it.
1406///
1407/// See [RFC 8200 Section 2.5] for the fragment header format.
1408///
1409/// [RFC 8200 Section 2.5]: https://datatracker.ietf.org/doc/html/rfc8200#section-4.5
1410#[derive(Debug, Eq, PartialEq)]
1411pub struct Ipv6PacketBuilderWithFragmentHeader<B> {
1412    header_builder: B,
1413    fragment_offset: FragmentOffset,
1414    more_fragments: bool,
1415    identification: u32,
1416}
1417
1418impl<B: Ipv6HeaderBefore<Self>> Ipv6PacketBuilderWithFragmentHeader<B> {
1419    /// Creates a new `Ipv6PacketBuilderWithFragmentHeader`.
1420    pub fn new(
1421        header_builder: B,
1422        fragment_offset: FragmentOffset,
1423        more_fragments: bool,
1424        identification: u32,
1425    ) -> Self {
1426        Self { header_builder, fragment_offset, more_fragments, identification }
1427    }
1428}
1429
1430impl<B> Ipv6HeaderBefore<Ipv6PacketBuilderWithFragmentHeader<B>> for Ipv6PacketBuilder {}
1431impl<B, I> Ipv6HeaderBefore<Ipv6PacketBuilderWithFragmentHeader<B>>
1432    for Ipv6PacketBuilderWithHbhOptions<'_, I>
1433{
1434}
1435
1436/// A marker trait for all header builder types that can be used to construct
1437/// and serialize IPv6 headers using [`Ipv6PacketBuilderWithFragmentHeader`].
1438pub trait Ipv6PacketBuilderBeforeFragment:
1439    Ipv6HeaderBefore<Ipv6PacketBuilderWithFragmentHeader<Self>> + Ipv6HeaderBuilder + Sized
1440{
1441}
1442impl<B> Ipv6PacketBuilderBeforeFragment for B where
1443    B: Ipv6HeaderBefore<Ipv6PacketBuilderWithFragmentHeader<Self>> + Ipv6HeaderBuilder + Sized
1444{
1445}
1446
1447impl<B: Ipv6HeaderBuilder> Ipv6HeaderBuilder for Ipv6PacketBuilderWithFragmentHeader<B> {
1448    fn fixed_header(&self) -> &Ipv6PacketBuilder {
1449        self.header_builder.fixed_header()
1450    }
1451
1452    fn extension_headers_len(&self) -> usize {
1453        self.header_builder.extension_headers_len() + IPV6_FRAGMENT_EXT_HDR_LEN
1454    }
1455
1456    fn serialize_header<BB: SplitByteSliceMut, BV: BufferViewMut<BB>>(
1457        &self,
1458        buffer: &mut BV,
1459        next_header: NextHeader,
1460        payload_len: usize,
1461    ) {
1462        let Self { header_builder, fragment_offset, more_fragments, identification } = self;
1463        let payload_len = payload_len + IPV6_FRAGMENT_EXT_HDR_LEN;
1464        header_builder.serialize_header(
1465            buffer,
1466            NextHeader::Extension(Ipv6ExtHdrType::Fragment),
1467            payload_len,
1468        );
1469        buffer.write_obj_front(&u8::from(next_header)).unwrap();
1470        // Reserved.
1471        let _: BB = buffer.take_front_zero(1).unwrap();
1472        let more_fragments = u16::from(*more_fragments);
1473        buffer
1474            .write_obj_front(&U16::new(fragment_offset.into_raw() << 3 | more_fragments))
1475            .unwrap();
1476        buffer.write_obj_front(&U32::new(*identification)).unwrap();
1477    }
1478}
1479
1480impl<B: Ipv6HeaderBuilder> PacketBuilder for Ipv6PacketBuilderWithFragmentHeader<B> {
1481    impl_packet_builder! {}
1482}
1483
1484/// Reassembles a fragmented packet into a parsed IP packet.
1485pub(crate) fn reassemble_fragmented_packet<
1486    B: SplitByteSliceMut,
1487    BV: BufferViewMut<B>,
1488    I: Iterator<Item = Vec<u8>>,
1489>(
1490    mut buffer: BV,
1491    header: Vec<u8>,
1492    body_fragments: I,
1493) -> IpParseResult<Ipv6, ()> {
1494    let bytes = buffer.as_mut();
1495
1496    // First, copy over the header data.
1497    bytes[0..header.len()].copy_from_slice(&header[..]);
1498    let mut byte_count = header.len();
1499
1500    // Next, copy over the body fragments.
1501    for p in body_fragments {
1502        bytes[byte_count..byte_count + p.len()].copy_from_slice(&p[..]);
1503        byte_count += p.len();
1504    }
1505
1506    //
1507    // Fix up the IPv6 header
1508    //
1509
1510    // For IPv6, the payload length is the sum of the length of the
1511    // extension headers and the packet body. The header as it is stored
1512    // includes the IPv6 fixed header and all extension headers, so
1513    // `bytes_count` is the sum of the size of the fixed header,
1514    // extension headers and packet body. To calculate the payload
1515    // length we subtract the size of the fixed header from the total
1516    // byte count of a reassembled packet.
1517    let payload_length = byte_count - IPV6_FIXED_HDR_LEN;
1518
1519    // Make sure that the payload length is not more than the maximum
1520    // possible IPv4 packet length.
1521    if payload_length > usize::from(core::u16::MAX) {
1522        return debug_err!(
1523            Err(ParseError::Format.into()),
1524            "fragmented packet payload length of {} bytes is too large",
1525            payload_length
1526        );
1527    }
1528
1529    // We know the call to `unwrap` will not fail because we just copied the header
1530    // bytes into `bytes`.
1531    let mut header = Ref::<_, FixedHeader>::from_prefix(bytes).unwrap().0;
1532
1533    // Update the payload length field.
1534    header.payload_len.set(u16::try_from(payload_length).unwrap());
1535
1536    Ok(())
1537}
1538
1539#[cfg(test)]
1540mod tests {
1541    use assert_matches::assert_matches;
1542    use packet::{Buf, FragmentedBuffer, ParseBuffer};
1543    use test_case::test_case;
1544
1545    use crate::ethernet::{EthernetFrame, EthernetFrameLengthCheck};
1546    use crate::testutil::*;
1547
1548    use super::ext_hdrs::*;
1549    use super::*;
1550
1551    const DEFAULT_SRC_IP: Ipv6Addr =
1552        Ipv6Addr::from_bytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
1553    const DEFAULT_DST_IP: Ipv6Addr =
1554        Ipv6Addr::from_bytes([17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]);
1555
1556    const DEFAULT_V4_SRC_IP: Ipv4Addr = Ipv4Addr::new([1, 2, 3, 4]);
1557    const DEFAULT_V4_DST_IP: Ipv4Addr = Ipv4Addr::new([5, 6, 7, 8]);
1558
1559    #[test]
1560    fn test_parse_serialize_full_tcp() {
1561        use crate::testdata::syn_v6::*;
1562
1563        let mut buf = ETHERNET_FRAME.bytes;
1564        let frame = buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
1565        verify_ethernet_frame(&frame, ETHERNET_FRAME);
1566
1567        let mut body = frame.body();
1568        let packet = body.parse::<Ipv6Packet<_>>().unwrap();
1569        verify_ipv6_packet(&packet, IPV6_PACKET);
1570
1571        // Verify serialization via builders.
1572        let buffer = packet
1573            .body()
1574            .into_serializer()
1575            .encapsulate(packet.builder())
1576            .encapsulate(frame.builder())
1577            .serialize_vec_outer()
1578            .unwrap();
1579        assert_eq!(buffer.as_ref(), ETHERNET_FRAME.bytes);
1580
1581        // Verify serialization via `to_vec`.
1582        assert_eq!(&packet.to_vec()[..], IPV6_PACKET.bytes);
1583    }
1584
1585    #[test]
1586    fn test_parse_serialize_full_udp() {
1587        use crate::testdata::dns_request_v6::*;
1588
1589        let mut buf = ETHERNET_FRAME.bytes;
1590        let frame = buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
1591        verify_ethernet_frame(&frame, ETHERNET_FRAME);
1592
1593        let mut body = frame.body();
1594        let packet = body.parse::<Ipv6Packet<_>>().unwrap();
1595        verify_ipv6_packet(&packet, IPV6_PACKET);
1596
1597        // Verify serialization via builders.
1598        let buffer = packet
1599            .body()
1600            .into_serializer()
1601            .encapsulate(packet.builder())
1602            .encapsulate(frame.builder())
1603            .serialize_vec_outer()
1604            .unwrap();
1605        assert_eq!(buffer.as_ref(), ETHERNET_FRAME.bytes);
1606
1607        // Verify serialization via `to_vec`.
1608        assert_eq!(&packet.to_vec()[..], IPV6_PACKET.bytes);
1609    }
1610
1611    #[test]
1612    fn test_parse_serialize_with_extension_headers() {
1613        // NB; Use MLD as test data arbitrarily, because it includes IPv6
1614        // extension headers.
1615        use crate::testdata::mld_router_report::*;
1616
1617        let mut buf = REPORT;
1618        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
1619        assert_eq!(packet.iter_extension_hdrs().count(), 1);
1620
1621        // NB: Don't verify serialization via builders, as they omit IPv6
1622        // extension headers.
1623
1624        // Verify serialization via `to_vec`.
1625        assert_eq!(&packet.to_vec()[..], REPORT);
1626    }
1627
1628    fn fixed_hdr_to_bytes(fixed_hdr: FixedHeader) -> [u8; IPV6_FIXED_HDR_LEN] {
1629        zerocopy::transmute!(fixed_hdr)
1630    }
1631
1632    // Return a new FixedHeader with reasonable defaults.
1633    fn new_fixed_hdr() -> FixedHeader {
1634        FixedHeader::new(
1635            DscpAndEcn::new(0, 2),
1636            0x77,
1637            0,
1638            IpProto::Tcp.into(),
1639            64,
1640            DEFAULT_SRC_IP,
1641            DEFAULT_DST_IP,
1642        )
1643    }
1644
1645    #[test]
1646    fn test_parse() {
1647        let mut buf = &fixed_hdr_to_bytes(new_fixed_hdr())[..];
1648        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
1649        assert_eq!(packet.dscp_and_ecn().dscp(), 0);
1650        assert_eq!(packet.dscp_and_ecn().ecn(), 2);
1651        assert_eq!(packet.flowlabel(), 0x77);
1652        assert_eq!(packet.hop_limit(), 64);
1653        assert_eq!(packet.fixed_hdr.next_hdr, IpProto::Tcp.into());
1654        assert_eq!(packet.proto(), IpProto::Tcp.into());
1655        assert_eq!(packet.src_ip(), DEFAULT_SRC_IP);
1656        assert_eq!(packet.dst_ip(), DEFAULT_DST_IP);
1657        assert_eq!(packet.body(), []);
1658    }
1659
1660    #[test]
1661    fn test_parse_with_ext_hdrs() {
1662        #[rustfmt::skip]
1663        let mut buf = [
1664            // FixedHeader (will be replaced later)
1665            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1666            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1667
1668            // HopByHop Options Extension Header
1669            Ipv6ExtHdrType::Routing.into(), // Next Header
1670            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1671            0,                       // Pad1
1672            1, 0,                    // Pad2
1673            1, 1, 0,                 // Pad3
1674
1675            // Routing Extension Header
1676            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
1677            4,                                  // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1678            0,                                  // Routing Type (Deprecated as per RFC 5095)
1679            0,                                  // Segments Left
1680            0, 0, 0, 0,                         // Reserved
1681            // Addresses for Routing Header w/ Type 0
1682            0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
1683            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1684
1685            // Destination Options Extension Header
1686            IpProto::Tcp.into(),    // Next Header
1687            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1688            0,                      // Pad1
1689            1, 0,                   // Pad2
1690            1, 1, 0,                // Pad3
1691            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
1692
1693            // Body
1694            1, 2, 3, 4, 5,
1695        ];
1696        let mut fixed_hdr = new_fixed_hdr();
1697        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
1698        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
1699        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
1700        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
1701        let mut buf = &buf[..];
1702        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
1703        assert_eq!(packet.dscp_and_ecn().dscp(), 0);
1704        assert_eq!(packet.dscp_and_ecn().ecn(), 2);
1705        assert_eq!(packet.flowlabel(), 0x77);
1706        assert_eq!(packet.hop_limit(), 64);
1707        assert_eq!(packet.fixed_hdr.next_hdr, Ipv6ExtHdrType::HopByHopOptions.into());
1708        assert_eq!(packet.proto(), IpProto::Tcp.into());
1709        assert_eq!(packet.src_ip(), DEFAULT_SRC_IP);
1710        assert_eq!(packet.dst_ip(), DEFAULT_DST_IP);
1711        assert_eq!(packet.body(), [1, 2, 3, 4, 5]);
1712        let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = packet.iter_extension_hdrs().collect();
1713        assert_eq!(ext_hdrs.len(), 2);
1714        // Check first extension header (hop-by-hop options)
1715        assert_eq!(ext_hdrs[0].next_header, Ipv6ExtHdrType::Routing.into());
1716        if let Ipv6ExtensionHeaderData::HopByHopOptions { options } = ext_hdrs[0].data() {
1717            // Everything should have been a NOP/ignore
1718            assert_eq!(options.iter().count(), 0);
1719        } else {
1720            panic!("Should have matched HopByHopOptions!");
1721        }
1722
1723        // Note the second extension header (routing) should have been skipped because
1724        // it's routing type is unrecognized, but segments left is 0.
1725
1726        // Check the third extension header (destination options)
1727        assert_eq!(ext_hdrs[1].next_header, IpProto::Tcp.into());
1728        if let Ipv6ExtensionHeaderData::DestinationOptions { options } = ext_hdrs[1].data() {
1729            // Everything should have been a NOP/ignore
1730            assert_eq!(options.iter().count(), 0);
1731        } else {
1732            panic!("Should have matched DestinationOptions!");
1733        }
1734
1735        // Test with a NoNextHeader as the final Next Header
1736        #[rustfmt::skip]
1737        let mut buf = [
1738            // FixedHeader (will be replaced later)
1739            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1740            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1741
1742            // HopByHop Options Extension Header w/ NoNextHeader as the next header
1743            Ipv6Proto::NoNextHeader.into(), // Next Header
1744            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1745            0,                       // Pad1
1746            1, 0,                    // Pad2
1747            1, 1, 0,                 // Pad3
1748
1749            // Body
1750            1, 2, 3, 4, 5,
1751        ];
1752        let mut fixed_hdr = new_fixed_hdr();
1753        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
1754        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
1755        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
1756        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
1757        let mut buf = &buf[..];
1758        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
1759        assert_eq!(packet.dscp_and_ecn().dscp(), 0);
1760        assert_eq!(packet.dscp_and_ecn().ecn(), 2);
1761        assert_eq!(packet.flowlabel(), 0x77);
1762        assert_eq!(packet.hop_limit(), 64);
1763        assert_eq!(packet.fixed_hdr.next_hdr, Ipv6ExtHdrType::HopByHopOptions.into());
1764        assert_eq!(packet.proto(), Ipv6Proto::NoNextHeader);
1765        assert_eq!(packet.src_ip(), DEFAULT_SRC_IP);
1766        assert_eq!(packet.dst_ip(), DEFAULT_DST_IP);
1767        assert_eq!(packet.body(), [1, 2, 3, 4, 5]);
1768        let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = packet.iter_extension_hdrs().collect();
1769        assert_eq!(ext_hdrs.len(), 1);
1770        // Check first extension header (hop-by-hop options)
1771        assert_eq!(ext_hdrs[0].next_header, Ipv6Proto::NoNextHeader.into());
1772        if let Ipv6ExtensionHeaderData::HopByHopOptions { options } = ext_hdrs[0].data() {
1773            // Everything should have been a NOP/ignore
1774            assert_eq!(options.iter().count(), 0);
1775        } else {
1776            panic!("Should have matched HopByHopOptions!");
1777        }
1778    }
1779
1780    #[test]
1781    fn test_parse_error() {
1782        // Set the version to 5. The version must be 6.
1783        let mut fixed_hdr = new_fixed_hdr();
1784        fixed_hdr.version_tc_flowlabel[0] = 0x50;
1785        assert_eq!(
1786            (&fixed_hdr_to_bytes(fixed_hdr)[..]).parse::<Ipv6Packet<_>>().unwrap_err(),
1787            ParseError::Format.into()
1788        );
1789
1790        // Set the payload len to 2, even though there's no payload.
1791        let mut fixed_hdr = new_fixed_hdr();
1792        fixed_hdr.payload_len = U16::new(2);
1793        assert_eq!(
1794            (&fixed_hdr_to_bytes(fixed_hdr)[..]).parse::<Ipv6Packet<_>>().unwrap_err(),
1795            ParseError::Format.into()
1796        );
1797
1798        // Use invalid next header.
1799        let mut fixed_hdr = new_fixed_hdr();
1800        fixed_hdr.next_hdr = 255;
1801        assert_eq!(
1802            (&fixed_hdr_to_bytes(fixed_hdr)[..]).parse::<Ipv6Packet<_>>().unwrap_err(),
1803            IpParseError::ParameterProblem {
1804                src_ip: DEFAULT_SRC_IP,
1805                dst_ip: DEFAULT_DST_IP,
1806                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
1807                pointer: u32::from(NEXT_HEADER_OFFSET),
1808                must_send_icmp: false,
1809                header_len: (),
1810                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
1811            }
1812        );
1813
1814        // Use ICMP(v4) as next header.
1815        let mut fixed_hdr = new_fixed_hdr();
1816        fixed_hdr.next_hdr = Ipv4Proto::Icmp.into();
1817        assert_eq!(
1818            (&fixed_hdr_to_bytes(fixed_hdr)[..]).parse::<Ipv6Packet<_>>().unwrap_err(),
1819            IpParseError::ParameterProblem {
1820                src_ip: DEFAULT_SRC_IP,
1821                dst_ip: DEFAULT_DST_IP,
1822                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
1823                pointer: u32::from(NEXT_HEADER_OFFSET),
1824                must_send_icmp: false,
1825                header_len: (),
1826                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
1827            }
1828        );
1829
1830        // Test HopByHop extension header not being the very first extension header
1831        #[rustfmt::skip]
1832        let mut buf = [
1833            // FixedHeader (will be replaced later)
1834            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1835            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1836
1837            // Routing Extension Header
1838            Ipv6ExtHdrType::HopByHopOptions.into(),    // Next Header (Valid but HopByHop restricted to first extension header)
1839            4,                                  // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1840            0,                                  // Routing Type
1841            0,                                  // Segments Left
1842            0, 0, 0, 0,                         // Reserved
1843            // Addresses for Routing Header w/ Type 0
1844            0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
1845            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1846
1847            // HopByHop Options Extension Header
1848            IpProto::Tcp.into(),             // Next Header
1849            0,                                  // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1850            0,                                  // Pad1
1851            1, 0,                               // Pad2
1852            1, 1, 0,                            // Pad3
1853
1854            // Body
1855            1, 2, 3, 4, 5,
1856        ];
1857        let mut fixed_hdr = new_fixed_hdr();
1858        fixed_hdr.next_hdr = Ipv6ExtHdrType::Routing.into();
1859        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
1860        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
1861        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
1862        let mut buf = &buf[..];
1863        assert_eq!(
1864            buf.parse::<Ipv6Packet<_>>().unwrap_err(),
1865            IpParseError::ParameterProblem {
1866                src_ip: DEFAULT_SRC_IP,
1867                dst_ip: DEFAULT_DST_IP,
1868                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
1869                pointer: IPV6_FIXED_HDR_LEN as u32,
1870                must_send_icmp: false,
1871                header_len: (),
1872                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
1873            }
1874        );
1875
1876        // Test Unrecognized Routing Type
1877        #[rustfmt::skip]
1878        let mut buf = [
1879            // FixedHeader (will be replaced later)
1880            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1881            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1882
1883            // Routing Extension Header
1884            IpProto::Tcp.into(),                // Next Header
1885            4,                                  // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1886            255,                                // Routing Type (Invalid)
1887            1,                                  // Segments Left
1888            0, 0, 0, 0,                         // Reserved
1889            // Addresses for Routing Header w/ Type 0
1890            0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
1891            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1892
1893            // Body
1894            1, 2, 3, 4, 5,
1895        ];
1896        let mut fixed_hdr = new_fixed_hdr();
1897        fixed_hdr.next_hdr = Ipv6ExtHdrType::Routing.into();
1898        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
1899        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
1900        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
1901        let mut buf = &buf[..];
1902        assert_eq!(
1903            buf.parse::<Ipv6Packet<_>>().unwrap_err(),
1904            IpParseError::ParameterProblem {
1905                src_ip: DEFAULT_SRC_IP,
1906                dst_ip: DEFAULT_DST_IP,
1907                code: Icmpv6ParameterProblemCode::ErroneousHeaderField,
1908                pointer: (IPV6_FIXED_HDR_LEN as u32) + 2,
1909                must_send_icmp: true,
1910                header_len: (),
1911                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
1912            }
1913        );
1914    }
1915
1916    #[test]
1917    fn test_parse_all_next_header_values() {
1918        // Test that, when parsing a packet with the fixed header's Next Header
1919        // field set to any value, parsing does not panic. A previous version
1920        // of this code would panic on some Next Header values.
1921
1922        // This packet was found via fuzzing to trigger a panic.
1923        let mut buf = [
1924            0x81, 0x13, 0x27, 0xeb, 0x75, 0x92, 0x33, 0x89, 0x01, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
1925            0x03, 0x70, 0x00, 0x22, 0xf7, 0x30, 0x2c, 0x06, 0xfe, 0xc9, 0x00, 0x2d, 0x3b, 0xeb,
1926            0xad, 0x3e, 0x5c, 0x41, 0xc8, 0x70, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf6, 0x11, 0x00,
1927            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x4f, 0x4f, 0x6f, 0x4f, 0x4f, 0x4f, 0x4f,
1928            0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x19, 0x19,
1929            0x19, 0x19, 0x19, 0x4f, 0x4f, 0x4f, 0x4f, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1930            0x00, 0x4f, 0x4f, 0x5a, 0x5a, 0x5a, 0xc9, 0x5a, 0x46, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
1931            0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0xe4, 0x5a, 0x5a, 0x5a, 0x5a,
1932        ];
1933
1934        // First, assert that the Next Header value found by the fuzzer (51)
1935        // produces the error we expect.
1936        assert_matches!(
1937            (&buf[..]).parse::<Ipv6Packet<_>>(),
1938            Err(IpParseError::ParameterProblem {
1939                src_ip: _,
1940                dst_ip: _,
1941                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
1942                pointer: 0,
1943                must_send_icmp: false,
1944                header_len: (),
1945                action: IpParseErrorAction::DiscardPacket,
1946            })
1947        );
1948
1949        // Second, ensure that, regardless of the exact result produced, no Next
1950        // Header value causes parsing to panic.
1951        for b in 0u8..=255 {
1952            // Overwrite the Next Header field.
1953            buf[6] = b;
1954            let _: Result<_, _> = (&buf[..]).parse::<Ipv6Packet<_>>();
1955        }
1956    }
1957
1958    #[test]
1959    fn test_partial_parse() {
1960        use core::convert::TryInto as _;
1961        use core::ops::Deref as _;
1962
1963        // Can't partial parse extension headers:
1964        #[rustfmt::skip]
1965        let mut buf = [
1966            // FixedHeader (will be replaced later)
1967            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1968            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1969
1970            // HopByHop Options Extension Header
1971            IpProto::Tcp.into(), // Next Header
1972            0,                   // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1973            0,                   // Pad1
1974            1, 0,                // Pad2
1975            1, 1, 0,             // Pad3
1976
1977            // Body
1978            1, 2, 3, 4, 5,
1979        ];
1980        let len = buf.len() - IPV6_FIXED_HDR_LEN;
1981        let len = len.try_into().unwrap();
1982        let make_fixed_hdr = || {
1983            let mut fixed_hdr = new_fixed_hdr();
1984            fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
1985            fixed_hdr.payload_len = U16::new(len);
1986            fixed_hdr
1987        };
1988        // make HopByHop malformed:
1989        const MALFORMED_BYTE: u8 = 10;
1990        buf[IPV6_FIXED_HDR_LEN + 1] = MALFORMED_BYTE;
1991        let fixed_hdr = fixed_hdr_to_bytes(make_fixed_hdr());
1992        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr);
1993        let mut buf = &buf[..];
1994        let partial = buf.parse::<Ipv6PacketRaw<_>>().unwrap();
1995        let Ipv6PacketRaw { fixed_hdr, extension_hdrs, body_proto } = &partial;
1996        assert_eq!(fixed_hdr.deref(), &make_fixed_hdr());
1997        assert_eq!(
1998            *extension_hdrs.as_ref().incomplete().unwrap(),
1999            [IpProto::Tcp.into(), MALFORMED_BYTE]
2000        );
2001        assert_eq!(body_proto, &Err(ExtHdrParseError));
2002        assert!(Ipv6Packet::try_from_raw(partial).is_err());
2003
2004        // Incomplete body:
2005        let mut buf = [
2006            // FixedHeader (will be replaced later)
2007            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2008            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Body
2009            1, 2, 3, 4, 5,
2010        ];
2011        let make_fixed_hdr = || {
2012            let mut fixed_hdr = new_fixed_hdr();
2013            fixed_hdr.next_hdr = IpProto::Tcp.into();
2014            fixed_hdr.payload_len = U16::new(10);
2015            fixed_hdr
2016        };
2017        let fixed_hdr = fixed_hdr_to_bytes(make_fixed_hdr());
2018        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr);
2019        let mut parsebuff = &buf[..];
2020        let partial = parsebuff.parse::<Ipv6PacketRaw<_>>().unwrap();
2021        let Ipv6PacketRaw { fixed_hdr, extension_hdrs, body_proto } = &partial;
2022        assert_eq!(fixed_hdr.deref(), &make_fixed_hdr());
2023        assert_eq!(extension_hdrs.as_ref().complete().unwrap().deref(), []);
2024        let (body, proto) = body_proto.unwrap();
2025        assert_eq!(body.incomplete().unwrap(), &buf[IPV6_FIXED_HDR_LEN..]);
2026        assert_eq!(proto, IpProto::Tcp.into());
2027        assert!(Ipv6Packet::try_from_raw(partial).is_err());
2028    }
2029
2030    // Return a stock Ipv6PacketBuilder with reasonable default values.
2031    fn new_builder() -> Ipv6PacketBuilder {
2032        Ipv6PacketBuilder::new(DEFAULT_SRC_IP, DEFAULT_DST_IP, 64, IpProto::Tcp.into())
2033    }
2034
2035    #[test]
2036    fn test_serialize() {
2037        let mut builder = new_builder();
2038        builder.dscp_and_ecn(DscpAndEcn::new(0x12, 3));
2039        builder.flowlabel(0x10405);
2040        let mut buf = (&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
2041            .into_serializer()
2042            .encapsulate(builder)
2043            .serialize_vec_outer()
2044            .unwrap();
2045        // assert that we get the literal bytes we expected
2046        assert_eq!(
2047            buf.as_ref(),
2048            &[
2049                100, 177, 4, 5, 0, 10, 6, 64, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
2050                16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 0, 1, 2, 3, 4,
2051                5, 6, 7, 8, 9
2052            ][..],
2053        );
2054
2055        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2056        // assert that when we parse those bytes, we get the values we set in
2057        // the builder
2058        assert_eq!(packet.dscp_and_ecn().dscp(), 0x12);
2059        assert_eq!(packet.dscp_and_ecn().ecn(), 3);
2060        assert_eq!(packet.flowlabel(), 0x10405);
2061    }
2062
2063    #[test]
2064    fn test_serialize_zeroes() {
2065        // Test that Ipv6PacketBuilder::serialize properly zeroes memory before
2066        // serializing the header.
2067        let mut buf_0 = [0; IPV6_FIXED_HDR_LEN];
2068        let _: Buf<&mut [u8]> = Buf::new(&mut buf_0[..], IPV6_FIXED_HDR_LEN..)
2069            .encapsulate(new_builder())
2070            .serialize_vec_outer()
2071            .unwrap()
2072            .unwrap_a();
2073        let mut buf_1 = [0xFF; IPV6_FIXED_HDR_LEN];
2074        let _: Buf<&mut [u8]> = Buf::new(&mut buf_1[..], IPV6_FIXED_HDR_LEN..)
2075            .encapsulate(new_builder())
2076            .serialize_vec_outer()
2077            .unwrap()
2078            .unwrap_a();
2079        assert_eq!(&buf_0[..], &buf_1[..]);
2080    }
2081
2082    #[test]
2083    fn test_packet_builder_proto_not_next_header() {
2084        // Test that Ipv6PacketBuilder's `proto` field is used as the Protocol
2085        // Number for the upper layer payload, not the Next Header value for the
2086        // extension header.
2087        let mut buf = (&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
2088            .into_serializer()
2089            .encapsulate(
2090                Ipv6PacketBuilderWithHbhOptions::new(
2091                    new_builder(),
2092                    &[HopByHopOption {
2093                        action: ExtensionHeaderOptionAction::SkipAndContinue,
2094                        mutable: false,
2095                        data: HopByHopOptionData::RouterAlert { data: 0 },
2096                    }],
2097                )
2098                .unwrap(),
2099            )
2100            .serialize_vec_outer()
2101            .unwrap();
2102        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2103        assert_eq!(packet.proto(), IpProto::Tcp.into());
2104        assert_eq!(packet.next_header(), Ipv6ExtHdrType::HopByHopOptions.into());
2105    }
2106
2107    #[test]
2108    #[should_panic(expected = "SizeLimitExceeded, Nested { inner: Buf { buf:")]
2109    fn test_serialize_panic_packet_length() {
2110        // Test that a packet whose payload is longer than 2^16 - 1 bytes is
2111        // rejected.
2112        let _: Buf<&mut [u8]> = Buf::new(&mut [0; 1 << 16][..], ..)
2113            .encapsulate(new_builder())
2114            .serialize_vec_outer()
2115            .unwrap()
2116            .unwrap_a();
2117    }
2118
2119    #[test]
2120    #[should_panic(expected = "packet must have at least one extension header")]
2121    fn test_copy_header_bytes_for_fragment_without_ext_hdrs() {
2122        let mut buf = &fixed_hdr_to_bytes(new_fixed_hdr())[..];
2123        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2124        let _: Vec<_> = packet.copy_header_bytes_for_fragment();
2125    }
2126
2127    #[test]
2128    #[should_panic(expected = "exhausted all extension headers without finding fragment header")]
2129    fn test_copy_header_bytes_for_fragment_with_1_ext_hdr_no_fragment() {
2130        #[rustfmt::skip]
2131        let mut buf = [
2132            // FixedHeader (will be replaced later)
2133            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2134            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2135
2136            // HopByHop Options Extension Header
2137            IpProto::Tcp.into(),     // Next Header
2138            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2139            0,                       // Pad1
2140            1, 0,                    // Pad2
2141            1, 1, 0,                 // Pad3
2142
2143            // Body
2144            1, 2, 3, 4, 5,
2145        ];
2146        let mut fixed_hdr = new_fixed_hdr();
2147        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2148        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
2149        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2150        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2151        let mut buf = &buf[..];
2152        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2153        let _: Vec<_> = packet.copy_header_bytes_for_fragment();
2154    }
2155
2156    #[test]
2157    #[should_panic(expected = "exhausted all extension headers without finding fragment header")]
2158    fn test_copy_header_bytes_for_fragment_with_2_ext_hdr_no_fragment() {
2159        #[rustfmt::skip]
2160        let mut buf = [
2161            // FixedHeader (will be replaced later)
2162            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2163            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2164
2165            // HopByHop Options Extension Header
2166            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
2167            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2168            0,                       // Pad1
2169            1, 0,                    // Pad2
2170            1, 1, 0,                 // Pad3
2171
2172            // Destination Options Extension Header
2173            IpProto::Tcp.into(),    // Next Header
2174            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2175            0,                      // Pad1
2176            1, 0,                   // Pad2
2177            1, 1, 0,                // Pad3
2178            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
2179
2180            // Body
2181            1, 2, 3, 4, 5,
2182        ];
2183        let mut fixed_hdr = new_fixed_hdr();
2184        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2185        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
2186        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2187        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2188        let mut buf = &buf[..];
2189        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2190        let _: Vec<_> = packet.copy_header_bytes_for_fragment();
2191    }
2192
2193    #[test]
2194    fn test_copy_header_bytes_for_fragment() {
2195        //
2196        // Only a fragment extension header
2197        //
2198
2199        #[rustfmt::skip]
2200        let mut bytes = [
2201            // FixedHeader (will be replaced later)
2202            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2203            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2204
2205            // Fragment Extension Header
2206            IpProto::Tcp.into(),     // Next Header
2207            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2208            0, 0,                    // Fragment Offset, Res, M (M_flag)
2209            1, 1, 1, 1,              // Identification
2210
2211            // Body
2212            1, 2, 3, 4, 5,
2213        ];
2214        let mut fixed_hdr = new_fixed_hdr();
2215        fixed_hdr.next_hdr = Ipv6ExtHdrType::Fragment.into();
2216        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2217        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2218        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2219        let mut buf = &bytes[..];
2220        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2221        let copied_bytes = packet.copy_header_bytes_for_fragment();
2222        bytes[6] = IpProto::Tcp.into();
2223        assert_eq!(&copied_bytes[..], &bytes[..IPV6_FIXED_HDR_LEN]);
2224
2225        //
2226        // Fragment header after a single extension header
2227        //
2228
2229        #[rustfmt::skip]
2230        let mut bytes = [
2231            // FixedHeader (will be replaced later)
2232            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2233            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2234
2235            // HopByHop Options Extension Header
2236            Ipv6ExtHdrType::Fragment.into(),    // Next Header
2237            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2238            0,                       // Pad1
2239            1, 0,                    // Pad2
2240            1, 1, 0,                 // Pad3
2241
2242            // Fragment Extension Header
2243            IpProto::Tcp.into(),     // Next Header
2244            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2245            0, 0,                    // Fragment Offset, Res, M (M_flag)
2246            1, 1, 1, 1,              // Identification
2247
2248            // Body
2249            1, 2, 3, 4, 5,
2250        ];
2251        let mut fixed_hdr = new_fixed_hdr();
2252        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2253        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2254        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2255        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2256        let mut buf = &bytes[..];
2257        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2258        let copied_bytes = packet.copy_header_bytes_for_fragment();
2259        bytes[IPV6_FIXED_HDR_LEN] = IpProto::Tcp.into();
2260        assert_eq!(&copied_bytes[..], &bytes[..IPV6_FIXED_HDR_LEN + 8]);
2261
2262        //
2263        // Fragment header after many extension headers (many = 2)
2264        //
2265
2266        #[rustfmt::skip]
2267        let mut bytes = [
2268            // FixedHeader (will be replaced later)
2269            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2270            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2271
2272            // HopByHop Options Extension Header
2273            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
2274            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2275            0,                       // Pad1
2276            1, 0,                    // Pad2
2277            1, 1, 0,                 // Pad3
2278
2279            // Destination Options Extension Header
2280            Ipv6ExtHdrType::Fragment.into(),    // Next Header
2281            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2282            0,                      // Pad1
2283            1, 0,                   // Pad2
2284            1, 1, 0,                // Pad3
2285            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
2286
2287            // Fragment Extension Header
2288            IpProto::Tcp.into(),     // Next Header
2289            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2290            0, 0,                    // Fragment Offset, Res, M (M_flag)
2291            1, 1, 1, 1,              // Identification
2292
2293            // Body
2294            1, 2, 3, 4, 5,
2295        ];
2296        let mut fixed_hdr = new_fixed_hdr();
2297        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2298        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2299        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2300        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2301        let mut buf = &bytes[..];
2302        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2303        let copied_bytes = packet.copy_header_bytes_for_fragment();
2304        bytes[IPV6_FIXED_HDR_LEN + 8] = IpProto::Tcp.into();
2305        assert_eq!(&copied_bytes[..], &bytes[..IPV6_FIXED_HDR_LEN + 24]);
2306
2307        //
2308        // Fragment header before an extension header
2309        //
2310
2311        #[rustfmt::skip]
2312        let mut bytes = [
2313            // FixedHeader (will be replaced later)
2314            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2315            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2316
2317            // Fragment Extension Header
2318            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
2319            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2320            0, 0,                    // Fragment Offset, Res, M (M_flag)
2321            1, 1, 1, 1,              // Identification
2322
2323            // Destination Options Extension Header
2324            IpProto::Tcp.into(),    // Next Header
2325            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2326            0,                      // Pad1
2327            1, 0,                   // Pad2
2328            1, 1, 0,                // Pad3
2329            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
2330
2331            // Body
2332            1, 2, 3, 4, 5,
2333        ];
2334        let mut fixed_hdr = new_fixed_hdr();
2335        fixed_hdr.next_hdr = Ipv6ExtHdrType::Fragment.into();
2336        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2337        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2338        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2339        let mut buf = &bytes[..];
2340        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2341        let copied_bytes = packet.copy_header_bytes_for_fragment();
2342        let mut expected_bytes = Vec::new();
2343        expected_bytes.extend_from_slice(&bytes[..IPV6_FIXED_HDR_LEN]);
2344        expected_bytes.extend_from_slice(&bytes[IPV6_FIXED_HDR_LEN + 8..bytes.len() - 5]);
2345        expected_bytes[6] = Ipv6ExtHdrType::DestinationOptions.into();
2346        assert_eq!(&copied_bytes[..], &expected_bytes[..]);
2347
2348        //
2349        // Fragment header before many extension headers (many = 2)
2350        //
2351
2352        #[rustfmt::skip]
2353        let mut bytes = [
2354            // FixedHeader (will be replaced later)
2355            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2356            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2357
2358            // Fragment Extension Header
2359            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
2360            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2361            0, 0,                    // Fragment Offset, Res, M (M_flag)
2362            1, 1, 1, 1,              // Identification
2363
2364            // Destination Options Extension Header
2365            Ipv6ExtHdrType::Routing.into(),    // Next Header
2366            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2367            0,                      // Pad1
2368            1, 0,                   // Pad2
2369            1, 1, 0,                // Pad3
2370            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
2371
2372            // Routing extension header
2373            IpProto::Tcp.into(),                // Next Header
2374            4,                                  // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2375            0,                                  // Routing Type (Deprecated as per RFC 5095)
2376            0,                                  // Segments Left
2377            0, 0, 0, 0,                         // Reserved
2378            // Addresses for Routing Header w/ Type 0
2379            0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
2380            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
2381
2382            // Body
2383            1, 2, 3, 4, 5,
2384        ];
2385        let mut fixed_hdr = new_fixed_hdr();
2386        fixed_hdr.next_hdr = Ipv6ExtHdrType::Fragment.into();
2387        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2388        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2389        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2390        let mut buf = &bytes[..];
2391        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2392        let copied_bytes = packet.copy_header_bytes_for_fragment();
2393        let mut expected_bytes = Vec::new();
2394        expected_bytes.extend_from_slice(&bytes[..IPV6_FIXED_HDR_LEN]);
2395        expected_bytes.extend_from_slice(&bytes[IPV6_FIXED_HDR_LEN + 8..bytes.len() - 5]);
2396        expected_bytes[6] = Ipv6ExtHdrType::DestinationOptions.into();
2397        assert_eq!(&copied_bytes[..], &expected_bytes[..]);
2398
2399        //
2400        // Fragment header between extension headers
2401        //
2402
2403        #[rustfmt::skip]
2404        let mut bytes = [
2405            // FixedHeader (will be replaced later)
2406            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2407            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2408
2409            // HopByHop Options Extension Header
2410            Ipv6ExtHdrType::Fragment.into(),    // Next Header
2411            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2412            0,                       // Pad1
2413            1, 0,                    // Pad2
2414            1, 1, 0,                 // Pad3
2415
2416            // Fragment Extension Header
2417            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
2418            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2419            0, 0,                    // Fragment Offset, Res, M (M_flag)
2420            1, 1, 1, 1,              // Identification
2421
2422            // Destination Options Extension Header
2423            IpProto::Tcp.into(),    // Next Header
2424            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2425            0,                      // Pad1
2426            1, 0,                   // Pad2
2427            1, 1, 0,                // Pad3
2428            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
2429
2430            // Body
2431            1, 2, 3, 4, 5,
2432        ];
2433        let mut fixed_hdr = new_fixed_hdr();
2434        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2435        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2436        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2437        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2438        let mut buf = &bytes[..];
2439        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2440        let copied_bytes = packet.copy_header_bytes_for_fragment();
2441        let mut expected_bytes = Vec::new();
2442        expected_bytes.extend_from_slice(&bytes[..IPV6_FIXED_HDR_LEN + 8]);
2443        expected_bytes.extend_from_slice(&bytes[IPV6_FIXED_HDR_LEN + 16..bytes.len() - 5]);
2444        expected_bytes[IPV6_FIXED_HDR_LEN] = Ipv6ExtHdrType::DestinationOptions.into();
2445        assert_eq!(&copied_bytes[..], &expected_bytes[..]);
2446
2447        //
2448        // Multiple fragment extension headers
2449        //
2450
2451        #[rustfmt::skip]
2452        let mut bytes = [
2453            // FixedHeader (will be replaced later)
2454            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2455            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2456
2457            // Fragment Extension Header
2458            Ipv6ExtHdrType::Fragment.into(),     // Next Header
2459            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2460            0, 0,                    // Fragment Offset, Res, M (M_flag)
2461            1, 1, 1, 1,              // Identification
2462
2463            // Fragment Extension Header
2464            IpProto::Tcp.into(),     // Next Header
2465            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2466            0, 0,                    // Fragment Offset, Res, M (M_flag)
2467            2, 2, 2, 2,              // Identification
2468
2469            // Body
2470            1, 2, 3, 4, 5,
2471        ];
2472        let mut fixed_hdr = new_fixed_hdr();
2473        fixed_hdr.next_hdr = Ipv6ExtHdrType::Fragment.into();
2474        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2475        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2476        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2477        let mut buf = &bytes[..];
2478        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2479        let copied_bytes = packet.copy_header_bytes_for_fragment();
2480        let mut expected_bytes = Vec::new();
2481        expected_bytes.extend_from_slice(&bytes[..IPV6_FIXED_HDR_LEN]);
2482        expected_bytes.extend_from_slice(&bytes[IPV6_FIXED_HDR_LEN + 8..bytes.len() - 5]);
2483        assert_eq!(&copied_bytes[..], &expected_bytes[..]);
2484    }
2485
2486    #[test]
2487    fn test_next_multiple_of_eight() {
2488        for x in 0usize..=IPV6_HBH_OPTIONS_MAX_LEN {
2489            let y = next_multiple_of_eight(x);
2490            assert_eq!(y % 8, 0);
2491            assert!(y >= x);
2492            if x % 8 == 0 {
2493                assert_eq!(x, y);
2494            } else {
2495                assert_eq!(x + (8 - x % 8), y);
2496            }
2497        }
2498    }
2499
2500    fn create_ipv4_and_ipv6_builders(
2501        proto_v4: Ipv4Proto,
2502        proto_v6: Ipv6Proto,
2503    ) -> (Ipv4PacketBuilder, Ipv6PacketBuilder) {
2504        const IP_DSCP_AND_ECN: DscpAndEcn = DscpAndEcn::new(0x12, 3);
2505        const IP_TTL: u8 = 64;
2506
2507        let mut ipv4_builder =
2508            Ipv4PacketBuilder::new(DEFAULT_V4_SRC_IP, DEFAULT_V4_DST_IP, IP_TTL, proto_v4);
2509        ipv4_builder.dscp_and_ecn(IP_DSCP_AND_ECN);
2510        ipv4_builder.df_flag(false);
2511        ipv4_builder.mf_flag(false);
2512        ipv4_builder.fragment_offset(FragmentOffset::ZERO);
2513
2514        let mut ipv6_builder =
2515            Ipv6PacketBuilder::new(DEFAULT_SRC_IP, DEFAULT_DST_IP, IP_TTL, proto_v6);
2516        ipv6_builder.dscp_and_ecn(IP_DSCP_AND_ECN);
2517        ipv6_builder.flowlabel(0x456);
2518
2519        (ipv4_builder, ipv6_builder)
2520    }
2521
2522    fn create_tcp_ipv4_and_ipv6_pkt(
2523    ) -> (packet::Either<EmptyBuf, Buf<Vec<u8>>>, packet::Either<EmptyBuf, Buf<Vec<u8>>>) {
2524        use crate::tcp::TcpSegmentBuilder;
2525        use core::num::NonZeroU16;
2526
2527        let tcp_src_port: NonZeroU16 = NonZeroU16::new(20).unwrap();
2528        let tcp_dst_port: NonZeroU16 = NonZeroU16::new(30).unwrap();
2529        const TCP_SEQ_NUM: u32 = 4321;
2530        const TCP_ACK_NUM: Option<u32> = Some(1234);
2531        const TCP_WINDOW_SIZE: u16 = 12345;
2532        const PAYLOAD: [u8; 10] = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
2533
2534        let (ipv4_builder, ipv6_builder) =
2535            create_ipv4_and_ipv6_builders(IpProto::Tcp.into(), IpProto::Tcp.into());
2536
2537        let tcp_builder = TcpSegmentBuilder::new(
2538            DEFAULT_V4_SRC_IP,
2539            DEFAULT_V4_DST_IP,
2540            tcp_src_port,
2541            tcp_dst_port,
2542            TCP_SEQ_NUM,
2543            TCP_ACK_NUM,
2544            TCP_WINDOW_SIZE,
2545        );
2546
2547        let v4_pkt_buf = (&PAYLOAD)
2548            .into_serializer()
2549            .encapsulate(tcp_builder)
2550            .encapsulate(ipv4_builder)
2551            .serialize_vec_outer()
2552            .expect("Failed to serialize to v4_pkt_buf");
2553
2554        let v6_tcp_builder = TcpSegmentBuilder::new(
2555            DEFAULT_SRC_IP,
2556            DEFAULT_DST_IP,
2557            tcp_src_port,
2558            tcp_dst_port,
2559            TCP_SEQ_NUM,
2560            TCP_ACK_NUM,
2561            TCP_WINDOW_SIZE,
2562        );
2563
2564        let v6_pkt_buf = (&PAYLOAD)
2565            .into_serializer()
2566            .encapsulate(v6_tcp_builder)
2567            .encapsulate(ipv6_builder)
2568            .serialize_vec_outer()
2569            .expect("Failed to serialize to v4_pkt_buf");
2570
2571        (v4_pkt_buf, v6_pkt_buf)
2572    }
2573
2574    #[test]
2575    fn test_nat64_translate_tcp() {
2576        let (expected_v4_pkt_buf, mut v6_pkt_buf) = create_tcp_ipv4_and_ipv6_pkt();
2577
2578        let parsed_v6_packet =
2579            v6_pkt_buf.parse::<Ipv6Packet<_>>().expect("Failed to parse v6_pkt_buf");
2580        let nat64_translation_result =
2581            parsed_v6_packet.nat64_translate(DEFAULT_V4_SRC_IP, DEFAULT_V4_DST_IP);
2582
2583        let serializable_pkt =
2584            assert_matches!(nat64_translation_result, Nat64TranslationResult::Forward(s) => s);
2585
2586        let translated_v4_pkt_buf = serializable_pkt
2587            .serialize_vec_outer()
2588            .expect("Failed to serialize to translated_v4_pkt_buf");
2589
2590        assert_eq!(
2591            expected_v4_pkt_buf.to_flattened_vec(),
2592            translated_v4_pkt_buf.to_flattened_vec()
2593        );
2594    }
2595
2596    fn create_udp_ipv4_and_ipv6_pkt(
2597    ) -> (packet::Either<EmptyBuf, Buf<Vec<u8>>>, packet::Either<EmptyBuf, Buf<Vec<u8>>>) {
2598        use crate::udp::UdpPacketBuilder;
2599        use core::num::NonZeroU16;
2600
2601        let udp_src_port: NonZeroU16 = NonZeroU16::new(35000).unwrap();
2602        let udp_dst_port: NonZeroU16 = NonZeroU16::new(53).unwrap();
2603        const PAYLOAD: [u8; 10] = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
2604
2605        let (ipv4_builder, ipv6_builder) =
2606            create_ipv4_and_ipv6_builders(IpProto::Udp.into(), IpProto::Udp.into());
2607
2608        let v4_udp_builder = UdpPacketBuilder::new(
2609            DEFAULT_V4_SRC_IP,
2610            DEFAULT_V4_DST_IP,
2611            Some(udp_src_port),
2612            udp_dst_port,
2613        );
2614
2615        let v4_pkt_buf = (&PAYLOAD)
2616            .into_serializer()
2617            .encapsulate(v4_udp_builder)
2618            .encapsulate(ipv4_builder)
2619            .serialize_vec_outer()
2620            .expect("Unable to serialize to v4_pkt_buf");
2621
2622        let v6_udp_builder =
2623            UdpPacketBuilder::new(DEFAULT_SRC_IP, DEFAULT_DST_IP, Some(udp_src_port), udp_dst_port);
2624
2625        let v6_pkt_buf = (&PAYLOAD)
2626            .into_serializer()
2627            .encapsulate(v6_udp_builder)
2628            .encapsulate(ipv6_builder)
2629            .serialize_vec_outer()
2630            .expect("Unable to serialize to v6_pkt_buf");
2631
2632        (v4_pkt_buf, v6_pkt_buf)
2633    }
2634
2635    #[test]
2636    fn test_nat64_translate_udp() {
2637        let (expected_v4_pkt_buf, mut v6_pkt_buf) = create_udp_ipv4_and_ipv6_pkt();
2638
2639        let parsed_v6_packet =
2640            v6_pkt_buf.parse::<Ipv6Packet<_>>().expect("Unable to parse Ipv6Packet");
2641        let nat64_translation_result =
2642            parsed_v6_packet.nat64_translate(DEFAULT_V4_SRC_IP, DEFAULT_V4_DST_IP);
2643
2644        let serializable_pkt = assert_matches!(nat64_translation_result,
2645                                               Nat64TranslationResult::Forward(s) => s);
2646
2647        let translated_v4_pkt_buf = serializable_pkt
2648            .serialize_vec_outer()
2649            .expect("Unable to serialize to translated_v4_pkt_buf");
2650
2651        assert_eq!(
2652            expected_v4_pkt_buf.to_flattened_vec(),
2653            translated_v4_pkt_buf.to_flattened_vec()
2654        );
2655    }
2656
2657    #[test]
2658    fn test_nat64_translate_non_tcp_udp_icmp() {
2659        const PAYLOAD: [u8; 10] = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
2660
2661        let (ipv4_builder, ipv6_builder) =
2662            create_ipv4_and_ipv6_builders(Ipv4Proto::Other(59), Ipv6Proto::Other(59));
2663
2664        let expected_v4_pkt_buf = (&PAYLOAD)
2665            .into_serializer()
2666            .encapsulate(ipv4_builder)
2667            .serialize_vec_outer()
2668            .expect("Unable to serialize to expected_v4_pkt_buf");
2669
2670        let mut v6_pkt_buf = (&PAYLOAD)
2671            .into_serializer()
2672            .encapsulate(ipv6_builder)
2673            .serialize_vec_outer()
2674            .expect("Unable to serialize to v6_pkt_buf");
2675
2676        let translated_v4_pkt_buf = {
2677            let parsed_v6_packet = v6_pkt_buf
2678                .parse::<Ipv6Packet<_>>()
2679                .expect("Unable to serialize to translated_v4_pkt_buf");
2680
2681            let nat64_translation_result =
2682                parsed_v6_packet.nat64_translate(DEFAULT_V4_SRC_IP, DEFAULT_V4_DST_IP);
2683
2684            let serializable_pkt = assert_matches!(nat64_translation_result,
2685                                                   Nat64TranslationResult::Forward(s) => s);
2686
2687            let translated_buf = serializable_pkt
2688                .serialize_vec_outer()
2689                .expect("Unable to serialize to translated_buf");
2690
2691            translated_buf
2692        };
2693
2694        assert_eq!(
2695            expected_v4_pkt_buf.to_flattened_vec(),
2696            translated_v4_pkt_buf.to_flattened_vec()
2697        );
2698    }
2699
2700    #[test_case(new_builder(), true; "fixed header more frags")]
2701    #[test_case(Ipv6PacketBuilderWithHbhOptions::new(
2702        new_builder(),
2703        &[HopByHopOption {
2704            action: ExtensionHeaderOptionAction::SkipAndContinue,
2705            mutable: false,
2706            data: HopByHopOptionData::RouterAlert { data: 0 },
2707        }]).unwrap(), false; "hbh last frag")]
2708    fn ipv6_packet_builder_with_fragment_header<
2709        B: Ipv6HeaderBuilder + Ipv6HeaderBefore<Ipv6PacketBuilderWithFragmentHeader<B>> + Debug,
2710    >(
2711        inner: B,
2712        more_fragments: bool,
2713    ) {
2714        const PAYLOAD: [u8; 10] = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
2715        let fragment_offset = FragmentOffset::new(13).unwrap();
2716        let identification = 0xABCDABCD;
2717        let builder = Ipv6PacketBuilderWithFragmentHeader::new(
2718            inner,
2719            fragment_offset,
2720            more_fragments,
2721            identification,
2722        );
2723        let mut serialized = PAYLOAD
2724            .into_serializer()
2725            .encapsulate(builder)
2726            .serialize_vec_outer()
2727            .unwrap()
2728            .unwrap_b();
2729        let packet = serialized.parse::<Ipv6Packet<_>>().unwrap();
2730        assert!(packet.fragment_header_present());
2731        assert_eq!(packet.proto(), Ipv6Proto::Proto(IpProto::Tcp));
2732        let fragment_data = packet
2733            .extension_hdrs
2734            .into_iter()
2735            .find_map(|ext_hdr| match ext_hdr.into_data() {
2736                Ipv6ExtensionHeaderData::Fragment { fragment_data } => Some(fragment_data),
2737                _ => None,
2738            })
2739            .unwrap();
2740        assert_eq!(fragment_data.fragment_offset(), fragment_offset);
2741        assert_eq!(fragment_data.identification(), identification);
2742        assert_eq!(fragment_data.m_flag(), more_fragments);
2743    }
2744
2745    // Tests that the PacketBuilder implementations correct the maximum body
2746    // length in PacketConstraints to remove any extension header bytes used.
2747    #[test]
2748    fn extension_headers_take_from_max_body_size() {
2749        let builder = new_builder();
2750        assert_eq!(builder.constraints().max_body_len(), IPV6_MAX_PAYLOAD_LENGTH);
2751        let builder =
2752            Ipv6PacketBuilderWithFragmentHeader::new(builder, FragmentOffset::ZERO, false, 1234);
2753        assert_eq!(
2754            builder.constraints().max_body_len(),
2755            IPV6_MAX_PAYLOAD_LENGTH - IPV6_FRAGMENT_EXT_HDR_LEN
2756        );
2757    }
2758}