Skip to main content

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