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