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