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