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