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