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.
1521///
1522/// # Panics
1523///
1524/// Panics if the provided header is too small to hold a valid header.
1525pub(crate) fn reassemble_fragmented_packet<
1526    B: SplitByteSliceMut,
1527    BV: BufferViewMut<B>,
1528    I: Iterator<Item = Vec<u8>>,
1529>(
1530    mut buffer: BV,
1531    header: Vec<u8>,
1532    body_fragments: I,
1533) -> IpParseResult<Ipv6, ()> {
1534    assert!(header.len() >= IPV6_FIXED_HDR_LEN);
1535
1536    let bytes = buffer.as_mut();
1537
1538    // First, copy over the header data.
1539    bytes[0..header.len()].copy_from_slice(&header[..]);
1540    let mut byte_count = header.len();
1541
1542    // Next, copy over the body fragments.
1543    for p in body_fragments {
1544        bytes[byte_count..byte_count + p.len()].copy_from_slice(&p[..]);
1545        byte_count += p.len();
1546    }
1547
1548    //
1549    // Fix up the IPv6 header
1550    //
1551
1552    // For IPv6, the payload length is the sum of the length of the
1553    // extension headers and the packet body. The header as it is stored
1554    // includes the IPv6 fixed header and all extension headers, so
1555    // `bytes_count` is the sum of the size of the fixed header,
1556    // extension headers and packet body. To calculate the payload
1557    // length we subtract the size of the fixed header from the total
1558    // byte count of a reassembled packet.
1559    let payload_length = byte_count - IPV6_FIXED_HDR_LEN;
1560
1561    // Make sure that the payload length is not more than the maximum
1562    // possible IPv6 packet length.
1563    if payload_length > usize::from(core::u16::MAX) {
1564        return debug_err!(
1565            Err(ParseError::Format.into()),
1566            "fragmented packet payload length of {} bytes is too large",
1567            payload_length
1568        );
1569    }
1570
1571    // We know the call to `unwrap` will not fail because we verified the length
1572    // of `header` and copied it's bytes into `bytes`.
1573    let mut header = Ref::<_, FixedHeader>::from_prefix(bytes).unwrap().0;
1574
1575    // Update the payload length field.
1576    header.payload_len.set(u16::try_from(payload_length).unwrap());
1577
1578    Ok(())
1579}
1580
1581#[cfg(test)]
1582mod tests {
1583    use assert_matches::assert_matches;
1584    use packet::{Buf, FragmentedBuffer, ParseBuffer};
1585    use test_case::test_case;
1586
1587    use crate::ethernet::{EthernetFrame, EthernetFrameLengthCheck};
1588    use crate::testutil::*;
1589
1590    use super::ext_hdrs::*;
1591    use super::*;
1592
1593    const DEFAULT_SRC_IP: Ipv6Addr =
1594        Ipv6Addr::from_bytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
1595    const DEFAULT_DST_IP: Ipv6Addr =
1596        Ipv6Addr::from_bytes([17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]);
1597
1598    const DEFAULT_V4_SRC_IP: Ipv4Addr = Ipv4Addr::new([1, 2, 3, 4]);
1599    const DEFAULT_V4_DST_IP: Ipv4Addr = Ipv4Addr::new([5, 6, 7, 8]);
1600
1601    #[test]
1602    fn test_parse_serialize_full_tcp() {
1603        use crate::testdata::syn_v6::*;
1604
1605        let mut buf = ETHERNET_FRAME.bytes;
1606        let frame = buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
1607        verify_ethernet_frame(&frame, ETHERNET_FRAME);
1608
1609        let mut body = frame.body();
1610        let packet = body.parse::<Ipv6Packet<_>>().unwrap();
1611        verify_ipv6_packet(&packet, IPV6_PACKET);
1612
1613        // Verify serialization via builders.
1614        let buffer = packet
1615            .body()
1616            .into_serializer()
1617            .wrap_in(packet.builder())
1618            .wrap_in(frame.builder())
1619            .serialize_vec_outer()
1620            .unwrap();
1621        assert_eq!(buffer.as_ref(), ETHERNET_FRAME.bytes);
1622
1623        // Verify serialization via `to_vec`.
1624        assert_eq!(&packet.to_vec()[..], IPV6_PACKET.bytes);
1625    }
1626
1627    #[test]
1628    fn test_parse_serialize_full_udp() {
1629        use crate::testdata::dns_request_v6::*;
1630
1631        let mut buf = ETHERNET_FRAME.bytes;
1632        let frame = buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
1633        verify_ethernet_frame(&frame, ETHERNET_FRAME);
1634
1635        let mut body = frame.body();
1636        let packet = body.parse::<Ipv6Packet<_>>().unwrap();
1637        verify_ipv6_packet(&packet, IPV6_PACKET);
1638
1639        // Verify serialization via builders.
1640        let buffer = packet
1641            .body()
1642            .into_serializer()
1643            .wrap_in(packet.builder())
1644            .wrap_in(frame.builder())
1645            .serialize_vec_outer()
1646            .unwrap();
1647        assert_eq!(buffer.as_ref(), ETHERNET_FRAME.bytes);
1648
1649        // Verify serialization via `to_vec`.
1650        assert_eq!(&packet.to_vec()[..], IPV6_PACKET.bytes);
1651    }
1652
1653    #[test]
1654    fn test_parse_serialize_with_extension_headers() {
1655        // NB; Use MLD as test data arbitrarily, because it includes IPv6
1656        // extension headers.
1657        use crate::testdata::mld_router_report::*;
1658
1659        let mut buf = REPORT;
1660        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
1661        assert_eq!(packet.iter_extension_hdrs().count(), 1);
1662
1663        // NB: Don't verify serialization via builders, as they omit IPv6
1664        // extension headers.
1665
1666        // Verify serialization via `to_vec`.
1667        assert_eq!(&packet.to_vec()[..], REPORT);
1668    }
1669
1670    fn fixed_hdr_to_bytes(fixed_hdr: FixedHeader) -> [u8; IPV6_FIXED_HDR_LEN] {
1671        zerocopy::transmute!(fixed_hdr)
1672    }
1673
1674    // Return a new FixedHeader with reasonable defaults.
1675    fn new_fixed_hdr() -> FixedHeader {
1676        FixedHeader::new(
1677            DscpAndEcn::new(0, 2),
1678            0x77,
1679            0,
1680            IpProto::Tcp.into(),
1681            64,
1682            DEFAULT_SRC_IP,
1683            DEFAULT_DST_IP,
1684        )
1685    }
1686
1687    #[test]
1688    fn test_parse() {
1689        let mut buf = &fixed_hdr_to_bytes(new_fixed_hdr())[..];
1690        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
1691        assert_eq!(packet.dscp_and_ecn().dscp(), 0);
1692        assert_eq!(packet.dscp_and_ecn().ecn(), 2);
1693        assert_eq!(packet.flowlabel(), 0x77);
1694        assert_eq!(packet.hop_limit(), 64);
1695        assert_eq!(packet.fixed_hdr.next_hdr, IpProto::Tcp.into());
1696        assert_eq!(packet.proto(), IpProto::Tcp.into());
1697        assert_eq!(packet.src_ip(), DEFAULT_SRC_IP);
1698        assert_eq!(packet.dst_ip(), DEFAULT_DST_IP);
1699        assert_eq!(packet.body(), []);
1700    }
1701
1702    #[test]
1703    fn test_parse_with_ext_hdrs() {
1704        #[rustfmt::skip]
1705        let mut buf = [
1706            // FixedHeader (will be replaced later)
1707            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1708            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1709
1710            // HopByHop Options Extension Header
1711            Ipv6ExtHdrType::Routing.into(), // Next Header
1712            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1713            0,                       // Pad1
1714            1, 0,                    // Pad2
1715            1, 1, 0,                 // Pad3
1716
1717            // Routing Extension Header
1718            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
1719            4,                                  // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1720            0,                                  // Routing Type (Deprecated as per RFC 5095)
1721            0,                                  // Segments Left
1722            0, 0, 0, 0,                         // Reserved
1723            // Addresses for Routing Header w/ Type 0
1724            0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
1725            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1726
1727            // Destination Options Extension Header
1728            IpProto::Tcp.into(),    // Next Header
1729            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1730            0,                      // Pad1
1731            1, 0,                   // Pad2
1732            1, 1, 0,                // Pad3
1733            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
1734
1735            // Body
1736            1, 2, 3, 4, 5,
1737        ];
1738        let mut fixed_hdr = new_fixed_hdr();
1739        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
1740        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
1741        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
1742        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
1743        let mut buf = &buf[..];
1744        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
1745        assert_eq!(packet.dscp_and_ecn().dscp(), 0);
1746        assert_eq!(packet.dscp_and_ecn().ecn(), 2);
1747        assert_eq!(packet.flowlabel(), 0x77);
1748        assert_eq!(packet.hop_limit(), 64);
1749        assert_eq!(packet.fixed_hdr.next_hdr, Ipv6ExtHdrType::HopByHopOptions.into());
1750        assert_eq!(packet.proto(), IpProto::Tcp.into());
1751        assert_eq!(packet.src_ip(), DEFAULT_SRC_IP);
1752        assert_eq!(packet.dst_ip(), DEFAULT_DST_IP);
1753        assert_eq!(packet.body(), [1, 2, 3, 4, 5]);
1754        let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = packet.iter_extension_hdrs().collect();
1755        assert_eq!(ext_hdrs.len(), 2);
1756        // Check first extension header (hop-by-hop options)
1757        assert_eq!(ext_hdrs[0].next_header, Ipv6ExtHdrType::Routing.into());
1758        if let Ipv6ExtensionHeaderData::HopByHopOptions { options } = ext_hdrs[0].data() {
1759            // Everything should have been a NOP/ignore
1760            assert_eq!(options.iter().count(), 0);
1761        } else {
1762            panic!("Should have matched HopByHopOptions!");
1763        }
1764
1765        // Note the second extension header (routing) should have been skipped because
1766        // it's routing type is unrecognized, but segments left is 0.
1767
1768        // Check the third extension header (destination options)
1769        assert_eq!(ext_hdrs[1].next_header, IpProto::Tcp.into());
1770        if let Ipv6ExtensionHeaderData::DestinationOptions { options } = ext_hdrs[1].data() {
1771            // Everything should have been a NOP/ignore
1772            assert_eq!(options.iter().count(), 0);
1773        } else {
1774            panic!("Should have matched DestinationOptions!");
1775        }
1776
1777        // Test with a NoNextHeader as the final Next Header
1778        #[rustfmt::skip]
1779        let mut buf = [
1780            // FixedHeader (will be replaced later)
1781            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1782            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1783
1784            // HopByHop Options Extension Header w/ NoNextHeader as the next header
1785            Ipv6Proto::NoNextHeader.into(), // Next Header
1786            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1787            0,                       // Pad1
1788            1, 0,                    // Pad2
1789            1, 1, 0,                 // Pad3
1790
1791            // Body
1792            1, 2, 3, 4, 5,
1793        ];
1794        let mut fixed_hdr = new_fixed_hdr();
1795        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
1796        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
1797        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
1798        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
1799        let mut buf = &buf[..];
1800        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
1801        assert_eq!(packet.dscp_and_ecn().dscp(), 0);
1802        assert_eq!(packet.dscp_and_ecn().ecn(), 2);
1803        assert_eq!(packet.flowlabel(), 0x77);
1804        assert_eq!(packet.hop_limit(), 64);
1805        assert_eq!(packet.fixed_hdr.next_hdr, Ipv6ExtHdrType::HopByHopOptions.into());
1806        assert_eq!(packet.proto(), Ipv6Proto::NoNextHeader);
1807        assert_eq!(packet.src_ip(), DEFAULT_SRC_IP);
1808        assert_eq!(packet.dst_ip(), DEFAULT_DST_IP);
1809        assert_eq!(packet.body(), [1, 2, 3, 4, 5]);
1810        let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = packet.iter_extension_hdrs().collect();
1811        assert_eq!(ext_hdrs.len(), 1);
1812        // Check first extension header (hop-by-hop options)
1813        assert_eq!(ext_hdrs[0].next_header, Ipv6Proto::NoNextHeader.into());
1814        if let Ipv6ExtensionHeaderData::HopByHopOptions { options } = ext_hdrs[0].data() {
1815            // Everything should have been a NOP/ignore
1816            assert_eq!(options.iter().count(), 0);
1817        } else {
1818            panic!("Should have matched HopByHopOptions!");
1819        }
1820    }
1821
1822    #[test]
1823    fn test_parse_error() {
1824        // Set the version to 5. The version must be 6.
1825        let mut fixed_hdr = new_fixed_hdr();
1826        fixed_hdr.version_tc_flowlabel[0] = 0x50;
1827        assert_eq!(
1828            (&fixed_hdr_to_bytes(fixed_hdr)[..]).parse::<Ipv6Packet<_>>().unwrap_err(),
1829            ParseError::Format.into()
1830        );
1831
1832        // Set the payload len to 2, even though there's no payload.
1833        let mut fixed_hdr = new_fixed_hdr();
1834        fixed_hdr.payload_len = U16::new(2);
1835        assert_eq!(
1836            (&fixed_hdr_to_bytes(fixed_hdr)[..]).parse::<Ipv6Packet<_>>().unwrap_err(),
1837            ParseError::Format.into()
1838        );
1839
1840        // Use invalid next header.
1841        let mut fixed_hdr = new_fixed_hdr();
1842        fixed_hdr.next_hdr = 255;
1843        assert_eq!(
1844            (&fixed_hdr_to_bytes(fixed_hdr)[..]).parse::<Ipv6Packet<_>>().unwrap_err(),
1845            Ipv6ParseError::ParameterProblem {
1846                src_ip: DEFAULT_SRC_IP,
1847                dst_ip: DEFAULT_DST_IP,
1848                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
1849                pointer: u32::from(NEXT_HEADER_OFFSET),
1850                must_send_icmp: false,
1851                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
1852            }
1853        );
1854
1855        // Use ICMP(v4) as next header.
1856        let mut fixed_hdr = new_fixed_hdr();
1857        fixed_hdr.next_hdr = Ipv4Proto::Icmp.into();
1858        assert_eq!(
1859            (&fixed_hdr_to_bytes(fixed_hdr)[..]).parse::<Ipv6Packet<_>>().unwrap_err(),
1860            Ipv6ParseError::ParameterProblem {
1861                src_ip: DEFAULT_SRC_IP,
1862                dst_ip: DEFAULT_DST_IP,
1863                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
1864                pointer: u32::from(NEXT_HEADER_OFFSET),
1865                must_send_icmp: false,
1866                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
1867            }
1868        );
1869
1870        // Test HopByHop extension header not being the very first extension header
1871        #[rustfmt::skip]
1872        let mut buf = [
1873            // FixedHeader (will be replaced later)
1874            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1875            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1876
1877            // Routing Extension Header
1878            Ipv6ExtHdrType::HopByHopOptions.into(),    // Next Header (Valid but HopByHop restricted to first extension header)
1879            4,                                  // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1880            0,                                  // Routing Type
1881            0,                                  // Segments Left
1882            0, 0, 0, 0,                         // Reserved
1883            // Addresses for Routing Header w/ Type 0
1884            0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
1885            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1886
1887            // HopByHop Options Extension Header
1888            IpProto::Tcp.into(),             // Next Header
1889            0,                                  // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1890            0,                                  // Pad1
1891            1, 0,                               // Pad2
1892            1, 1, 0,                            // Pad3
1893
1894            // Body
1895            1, 2, 3, 4, 5,
1896        ];
1897        let mut fixed_hdr = new_fixed_hdr();
1898        fixed_hdr.next_hdr = Ipv6ExtHdrType::Routing.into();
1899        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
1900        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
1901        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
1902        let mut buf = &buf[..];
1903        assert_eq!(
1904            buf.parse::<Ipv6Packet<_>>().unwrap_err(),
1905            Ipv6ParseError::ParameterProblem {
1906                src_ip: DEFAULT_SRC_IP,
1907                dst_ip: DEFAULT_DST_IP,
1908                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
1909                pointer: IPV6_FIXED_HDR_LEN as u32,
1910                must_send_icmp: false,
1911                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
1912            }
1913        );
1914
1915        // Test Unrecognized Routing Type
1916        #[rustfmt::skip]
1917        let mut buf = [
1918            // FixedHeader (will be replaced later)
1919            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1920            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1921
1922            // Routing Extension Header
1923            IpProto::Tcp.into(),                // Next Header
1924            4,                                  // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1925            255,                                // Routing Type (Invalid)
1926            1,                                  // Segments Left
1927            0, 0, 0, 0,                         // Reserved
1928            // Addresses for Routing Header w/ Type 0
1929            0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
1930            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1931
1932            // Body
1933            1, 2, 3, 4, 5,
1934        ];
1935        let mut fixed_hdr = new_fixed_hdr();
1936        fixed_hdr.next_hdr = Ipv6ExtHdrType::Routing.into();
1937        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
1938        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
1939        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
1940        let mut buf = &buf[..];
1941        assert_eq!(
1942            buf.parse::<Ipv6Packet<_>>().unwrap_err(),
1943            Ipv6ParseError::ParameterProblem {
1944                src_ip: DEFAULT_SRC_IP,
1945                dst_ip: DEFAULT_DST_IP,
1946                code: Icmpv6ParameterProblemCode::ErroneousHeaderField,
1947                pointer: (IPV6_FIXED_HDR_LEN as u32) + 2,
1948                must_send_icmp: true,
1949                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
1950            }
1951        );
1952    }
1953
1954    #[test]
1955    fn test_parse_all_next_header_values() {
1956        // Test that, when parsing a packet with the fixed header's Next Header
1957        // field set to any value, parsing does not panic. A previous version
1958        // of this code would panic on some Next Header values.
1959
1960        // This packet was found via fuzzing to trigger a panic.
1961        let mut buf = [
1962            0x81, 0x13, 0x27, 0xeb, 0x75, 0x92, 0x33, 0x89, 0x01, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
1963            0x03, 0x70, 0x00, 0x22, 0xf7, 0x30, 0x2c, 0x06, 0xfe, 0xc9, 0x00, 0x2d, 0x3b, 0xeb,
1964            0xad, 0x3e, 0x5c, 0x41, 0xc8, 0x70, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf6, 0x11, 0x00,
1965            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x4f, 0x4f, 0x6f, 0x4f, 0x4f, 0x4f, 0x4f,
1966            0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x19, 0x19,
1967            0x19, 0x19, 0x19, 0x4f, 0x4f, 0x4f, 0x4f, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1968            0x00, 0x4f, 0x4f, 0x5a, 0x5a, 0x5a, 0xc9, 0x5a, 0x46, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
1969            0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0xe4, 0x5a, 0x5a, 0x5a, 0x5a,
1970        ];
1971
1972        // First, assert that the Next Header value found by the fuzzer (51)
1973        // produces the error we expect.
1974        assert_matches!(
1975            (&buf[..]).parse::<Ipv6Packet<_>>(),
1976            Err(Ipv6ParseError::ParameterProblem {
1977                src_ip: _,
1978                dst_ip: _,
1979                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
1980                pointer: 0,
1981                must_send_icmp: false,
1982                action: IpParseErrorAction::DiscardPacket,
1983            })
1984        );
1985
1986        // Second, ensure that, regardless of the exact result produced, no Next
1987        // Header value causes parsing to panic.
1988        for b in 0u8..=255 {
1989            // Overwrite the Next Header field.
1990            buf[6] = b;
1991            let _: Result<_, _> = (&buf[..]).parse::<Ipv6Packet<_>>();
1992        }
1993    }
1994
1995    #[test]
1996    fn test_partial_parse() {
1997        use core::convert::TryInto as _;
1998        use core::ops::Deref as _;
1999
2000        // Can't partial parse extension headers:
2001        #[rustfmt::skip]
2002        let mut buf = [
2003            // FixedHeader (will be replaced later)
2004            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2005            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2006
2007            // HopByHop Options Extension Header
2008            IpProto::Tcp.into(), // Next Header
2009            0,                   // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2010            0,                   // Pad1
2011            1, 0,                // Pad2
2012            1, 1, 0,             // Pad3
2013
2014            // Body
2015            1, 2, 3, 4, 5,
2016        ];
2017        let len = buf.len() - IPV6_FIXED_HDR_LEN;
2018        let len = len.try_into().unwrap();
2019        let make_fixed_hdr = || {
2020            let mut fixed_hdr = new_fixed_hdr();
2021            fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2022            fixed_hdr.payload_len = U16::new(len);
2023            fixed_hdr
2024        };
2025        // make HopByHop malformed:
2026        const MALFORMED_BYTE: u8 = 10;
2027        buf[IPV6_FIXED_HDR_LEN + 1] = MALFORMED_BYTE;
2028        let fixed_hdr = fixed_hdr_to_bytes(make_fixed_hdr());
2029        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr);
2030        let mut buf = &buf[..];
2031        let partial = buf.parse::<Ipv6PacketRaw<_>>().unwrap();
2032        let Ipv6PacketRaw { fixed_hdr, extension_hdrs, body_proto } = &partial;
2033        assert_eq!(fixed_hdr.deref(), &make_fixed_hdr());
2034        assert_eq!(
2035            *extension_hdrs.as_ref().incomplete().unwrap(),
2036            [IpProto::Tcp.into(), MALFORMED_BYTE]
2037        );
2038        assert_eq!(body_proto, &Err(ExtHdrParseError));
2039        assert!(Ipv6Packet::try_from_raw(partial).is_err());
2040
2041        // Incomplete body:
2042        let mut buf = [
2043            // FixedHeader (will be replaced later)
2044            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,
2045            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Body
2046            1, 2, 3, 4, 5,
2047        ];
2048        let make_fixed_hdr = || {
2049            let mut fixed_hdr = new_fixed_hdr();
2050            fixed_hdr.next_hdr = IpProto::Tcp.into();
2051            fixed_hdr.payload_len = U16::new(10);
2052            fixed_hdr
2053        };
2054        let fixed_hdr = fixed_hdr_to_bytes(make_fixed_hdr());
2055        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr);
2056        let mut parsebuff = &buf[..];
2057        let partial = parsebuff.parse::<Ipv6PacketRaw<_>>().unwrap();
2058        let Ipv6PacketRaw { fixed_hdr, extension_hdrs, body_proto } = &partial;
2059        assert_eq!(fixed_hdr.deref(), &make_fixed_hdr());
2060        assert_eq!(extension_hdrs.as_ref().complete().unwrap().deref(), []);
2061        let (body, proto) = body_proto.unwrap();
2062        assert_eq!(body.incomplete().unwrap(), &buf[IPV6_FIXED_HDR_LEN..]);
2063        assert_eq!(proto, IpProto::Tcp.into());
2064        assert!(Ipv6Packet::try_from_raw(partial).is_err());
2065    }
2066
2067    // Return a stock Ipv6PacketBuilder with reasonable default values.
2068    fn new_builder() -> Ipv6PacketBuilder {
2069        Ipv6PacketBuilder::new(DEFAULT_SRC_IP, DEFAULT_DST_IP, 64, IpProto::Tcp.into())
2070    }
2071
2072    #[test]
2073    fn test_serialize() {
2074        let mut builder = new_builder();
2075        builder.dscp_and_ecn(DscpAndEcn::new(0x12, 3));
2076        builder.flowlabel(0x10405);
2077        let mut buf = (&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
2078            .into_serializer()
2079            .wrap_in(builder)
2080            .serialize_vec_outer()
2081            .unwrap();
2082        // assert that we get the literal bytes we expected
2083        assert_eq!(
2084            buf.as_ref(),
2085            &[
2086                100, 177, 4, 5, 0, 10, 6, 64, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
2087                16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 0, 1, 2, 3, 4,
2088                5, 6, 7, 8, 9
2089            ][..],
2090        );
2091
2092        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2093        // assert that when we parse those bytes, we get the values we set in
2094        // the builder
2095        assert_eq!(packet.dscp_and_ecn().dscp(), 0x12);
2096        assert_eq!(packet.dscp_and_ecn().ecn(), 3);
2097        assert_eq!(packet.flowlabel(), 0x10405);
2098    }
2099
2100    #[test]
2101    fn test_partial_serialize() {
2102        let mut builder = new_builder();
2103        builder.dscp_and_ecn(DscpAndEcn::new(0x12, 3));
2104        builder.flowlabel(0x10405);
2105        let body = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
2106        let packet = (&body).into_serializer().wrap_in(builder);
2107
2108        // Note that this header is different from the one in test_serialize
2109        // because the checksum is not calculated.
2110        const HEADER_LEN: usize = 40;
2111        const HEADER: [u8; HEADER_LEN] = [
2112            100, 177, 4, 5, 0, 10, 6, 64, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
2113            17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
2114        ];
2115        let mut expected_partial = HEADER.to_vec();
2116        expected_partial.resize(expected_partial.len() + body.len(), 0);
2117
2118        for i in 1..expected_partial.len() {
2119            let mut buf = vec![0u8; i];
2120            let result =
2121                packet.partial_serialize(PacketConstraints::UNCONSTRAINED, buf.as_mut_slice());
2122
2123            // PartialSerializer serializes the header only if the buffer is
2124            // large enough to fit the whole header.
2125            let bytes_written = if i >= HEADER_LEN { HEADER_LEN } else { 0 };
2126            assert_eq!(
2127                result,
2128                Ok(PartialSerializeResult { bytes_written, total_size: body.len() + HEADER_LEN })
2129            );
2130            if bytes_written > 0 {
2131                assert_eq!(buf, expected_partial[..i]);
2132            }
2133        }
2134    }
2135
2136    #[test]
2137    fn test_serialize_zeroes() {
2138        // Test that Ipv6PacketBuilder::serialize properly zeroes memory before
2139        // serializing the header.
2140        let mut buf_0 = [0; IPV6_FIXED_HDR_LEN];
2141        let _: Buf<&mut [u8]> = Buf::new(&mut buf_0[..], IPV6_FIXED_HDR_LEN..)
2142            .wrap_in(new_builder())
2143            .serialize_vec_outer()
2144            .unwrap()
2145            .unwrap_a();
2146        let mut buf_1 = [0xFF; IPV6_FIXED_HDR_LEN];
2147        let _: Buf<&mut [u8]> = Buf::new(&mut buf_1[..], IPV6_FIXED_HDR_LEN..)
2148            .wrap_in(new_builder())
2149            .serialize_vec_outer()
2150            .unwrap()
2151            .unwrap_a();
2152        assert_eq!(&buf_0[..], &buf_1[..]);
2153    }
2154
2155    #[test]
2156    fn test_packet_builder_proto_not_next_header() {
2157        // Test that Ipv6PacketBuilder's `proto` field is used as the Protocol
2158        // Number for the upper layer payload, not the Next Header value for the
2159        // extension header.
2160        let mut buf = (&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
2161            .into_serializer()
2162            .wrap_in(
2163                Ipv6PacketBuilderWithHbhOptions::new(
2164                    new_builder(),
2165                    &[HopByHopOption {
2166                        action: ExtensionHeaderOptionAction::SkipAndContinue,
2167                        mutable: false,
2168                        data: HopByHopOptionData::RouterAlert { data: 0 },
2169                    }],
2170                )
2171                .unwrap(),
2172            )
2173            .serialize_vec_outer()
2174            .unwrap();
2175        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2176        assert_eq!(packet.proto(), IpProto::Tcp.into());
2177        assert_eq!(packet.next_header(), Ipv6ExtHdrType::HopByHopOptions.into());
2178    }
2179
2180    #[test]
2181    #[should_panic(expected = "SizeLimitExceeded, Nested { inner: Buf { buf:")]
2182    fn test_serialize_panic_packet_length() {
2183        // Test that a packet whose payload is longer than 2^16 - 1 bytes is
2184        // rejected.
2185        let _: Buf<&mut [u8]> = Buf::new(&mut [0; 1 << 16][..], ..)
2186            .wrap_in(new_builder())
2187            .serialize_vec_outer()
2188            .unwrap()
2189            .unwrap_a();
2190    }
2191
2192    #[test]
2193    #[should_panic(expected = "packet must have at least one extension header")]
2194    fn test_copy_header_bytes_for_fragment_without_ext_hdrs() {
2195        let mut buf = &fixed_hdr_to_bytes(new_fixed_hdr())[..];
2196        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2197        let _: Vec<_> = packet.copy_header_bytes_for_fragment();
2198    }
2199
2200    #[test]
2201    #[should_panic(expected = "exhausted all extension headers without finding fragment header")]
2202    fn test_copy_header_bytes_for_fragment_with_1_ext_hdr_no_fragment() {
2203        #[rustfmt::skip]
2204        let mut buf = [
2205            // FixedHeader (will be replaced later)
2206            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2207            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2208
2209            // HopByHop Options Extension Header
2210            IpProto::Tcp.into(),     // Next Header
2211            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2212            0,                       // Pad1
2213            1, 0,                    // Pad2
2214            1, 1, 0,                 // Pad3
2215
2216            // Body
2217            1, 2, 3, 4, 5,
2218        ];
2219        let mut fixed_hdr = new_fixed_hdr();
2220        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2221        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
2222        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2223        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2224        let mut buf = &buf[..];
2225        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2226        let _: Vec<_> = packet.copy_header_bytes_for_fragment();
2227    }
2228
2229    #[test]
2230    #[should_panic(expected = "exhausted all extension headers without finding fragment header")]
2231    fn test_copy_header_bytes_for_fragment_with_2_ext_hdr_no_fragment() {
2232        #[rustfmt::skip]
2233        let mut buf = [
2234            // FixedHeader (will be replaced later)
2235            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2236            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2237
2238            // HopByHop Options Extension Header
2239            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
2240            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2241            0,                       // Pad1
2242            1, 0,                    // Pad2
2243            1, 1, 0,                 // Pad3
2244
2245            // Destination Options Extension Header
2246            IpProto::Tcp.into(),    // Next Header
2247            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2248            0,                      // Pad1
2249            1, 0,                   // Pad2
2250            1, 1, 0,                // Pad3
2251            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
2252
2253            // Body
2254            1, 2, 3, 4, 5,
2255        ];
2256        let mut fixed_hdr = new_fixed_hdr();
2257        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2258        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
2259        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2260        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2261        let mut buf = &buf[..];
2262        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2263        let _: Vec<_> = packet.copy_header_bytes_for_fragment();
2264    }
2265
2266    #[test]
2267    fn test_copy_header_bytes_for_fragment() {
2268        //
2269        // Only a fragment extension header
2270        //
2271
2272        #[rustfmt::skip]
2273        let mut bytes = [
2274            // FixedHeader (will be replaced later)
2275            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2276            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2277
2278            // Fragment Extension Header
2279            IpProto::Tcp.into(),     // Next Header
2280            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2281            0, 0,                    // Fragment Offset, Res, M (M_flag)
2282            1, 1, 1, 1,              // Identification
2283
2284            // Body
2285            1, 2, 3, 4, 5,
2286        ];
2287        let mut fixed_hdr = new_fixed_hdr();
2288        fixed_hdr.next_hdr = Ipv6ExtHdrType::Fragment.into();
2289        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2290        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2291        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2292        let mut buf = &bytes[..];
2293        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2294        let copied_bytes = packet.copy_header_bytes_for_fragment();
2295        bytes[6] = IpProto::Tcp.into();
2296        assert_eq!(&copied_bytes[..], &bytes[..IPV6_FIXED_HDR_LEN]);
2297
2298        //
2299        // Fragment header after a single extension header
2300        //
2301
2302        #[rustfmt::skip]
2303        let mut bytes = [
2304            // FixedHeader (will be replaced later)
2305            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2306            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2307
2308            // HopByHop Options Extension Header
2309            Ipv6ExtHdrType::Fragment.into(),    // Next Header
2310            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2311            0,                       // Pad1
2312            1, 0,                    // Pad2
2313            1, 1, 0,                 // Pad3
2314
2315            // Fragment Extension Header
2316            IpProto::Tcp.into(),     // Next Header
2317            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2318            0, 0,                    // Fragment Offset, Res, M (M_flag)
2319            1, 1, 1, 1,              // Identification
2320
2321            // Body
2322            1, 2, 3, 4, 5,
2323        ];
2324        let mut fixed_hdr = new_fixed_hdr();
2325        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2326        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2327        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2328        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2329        let mut buf = &bytes[..];
2330        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2331        let copied_bytes = packet.copy_header_bytes_for_fragment();
2332        bytes[IPV6_FIXED_HDR_LEN] = IpProto::Tcp.into();
2333        assert_eq!(&copied_bytes[..], &bytes[..IPV6_FIXED_HDR_LEN + 8]);
2334
2335        //
2336        // Fragment header after many extension headers (many = 2)
2337        //
2338
2339        #[rustfmt::skip]
2340        let mut bytes = [
2341            // FixedHeader (will be replaced later)
2342            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2343            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2344
2345            // HopByHop Options Extension Header
2346            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
2347            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2348            0,                       // Pad1
2349            1, 0,                    // Pad2
2350            1, 1, 0,                 // Pad3
2351
2352            // Destination Options Extension Header
2353            Ipv6ExtHdrType::Fragment.into(),    // Next Header
2354            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2355            0,                      // Pad1
2356            1, 0,                   // Pad2
2357            1, 1, 0,                // Pad3
2358            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
2359
2360            // Fragment Extension Header
2361            IpProto::Tcp.into(),     // Next Header
2362            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2363            0, 0,                    // Fragment Offset, Res, M (M_flag)
2364            1, 1, 1, 1,              // Identification
2365
2366            // Body
2367            1, 2, 3, 4, 5,
2368        ];
2369        let mut fixed_hdr = new_fixed_hdr();
2370        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2371        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2372        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2373        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2374        let mut buf = &bytes[..];
2375        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2376        let copied_bytes = packet.copy_header_bytes_for_fragment();
2377        bytes[IPV6_FIXED_HDR_LEN + 8] = IpProto::Tcp.into();
2378        assert_eq!(&copied_bytes[..], &bytes[..IPV6_FIXED_HDR_LEN + 24]);
2379
2380        //
2381        // Fragment header before an extension header
2382        //
2383
2384        #[rustfmt::skip]
2385        let mut bytes = [
2386            // FixedHeader (will be replaced later)
2387            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2388            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2389
2390            // Fragment Extension Header
2391            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
2392            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2393            0, 0,                    // Fragment Offset, Res, M (M_flag)
2394            1, 1, 1, 1,              // Identification
2395
2396            // Destination Options Extension Header
2397            IpProto::Tcp.into(),    // Next Header
2398            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2399            0,                      // Pad1
2400            1, 0,                   // Pad2
2401            1, 1, 0,                // Pad3
2402            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
2403
2404            // Body
2405            1, 2, 3, 4, 5,
2406        ];
2407        let mut fixed_hdr = new_fixed_hdr();
2408        fixed_hdr.next_hdr = Ipv6ExtHdrType::Fragment.into();
2409        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2410        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2411        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2412        let mut buf = &bytes[..];
2413        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2414        let copied_bytes = packet.copy_header_bytes_for_fragment();
2415        let mut expected_bytes = Vec::new();
2416        expected_bytes.extend_from_slice(&bytes[..IPV6_FIXED_HDR_LEN]);
2417        expected_bytes.extend_from_slice(&bytes[IPV6_FIXED_HDR_LEN + 8..bytes.len() - 5]);
2418        expected_bytes[6] = Ipv6ExtHdrType::DestinationOptions.into();
2419        assert_eq!(&copied_bytes[..], &expected_bytes[..]);
2420
2421        //
2422        // Fragment header before many extension headers (many = 2)
2423        //
2424
2425        #[rustfmt::skip]
2426        let mut bytes = [
2427            // FixedHeader (will be replaced later)
2428            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2429            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2430
2431            // Fragment Extension Header
2432            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
2433            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2434            0, 0,                    // Fragment Offset, Res, M (M_flag)
2435            1, 1, 1, 1,              // Identification
2436
2437            // Destination Options Extension Header
2438            Ipv6ExtHdrType::Routing.into(),    // Next Header
2439            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2440            0,                      // Pad1
2441            1, 0,                   // Pad2
2442            1, 1, 0,                // Pad3
2443            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
2444
2445            // Routing extension header
2446            IpProto::Tcp.into(),                // Next Header
2447            4,                                  // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2448            0,                                  // Routing Type (Deprecated as per RFC 5095)
2449            0,                                  // Segments Left
2450            0, 0, 0, 0,                         // Reserved
2451            // Addresses for Routing Header w/ Type 0
2452            0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
2453            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
2454
2455            // Body
2456            1, 2, 3, 4, 5,
2457        ];
2458        let mut fixed_hdr = new_fixed_hdr();
2459        fixed_hdr.next_hdr = Ipv6ExtHdrType::Fragment.into();
2460        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2461        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2462        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2463        let mut buf = &bytes[..];
2464        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2465        let copied_bytes = packet.copy_header_bytes_for_fragment();
2466        let mut expected_bytes = Vec::new();
2467        expected_bytes.extend_from_slice(&bytes[..IPV6_FIXED_HDR_LEN]);
2468        expected_bytes.extend_from_slice(&bytes[IPV6_FIXED_HDR_LEN + 8..bytes.len() - 5]);
2469        expected_bytes[6] = Ipv6ExtHdrType::DestinationOptions.into();
2470        assert_eq!(&copied_bytes[..], &expected_bytes[..]);
2471
2472        //
2473        // Fragment header between extension headers
2474        //
2475
2476        #[rustfmt::skip]
2477        let mut bytes = [
2478            // FixedHeader (will be replaced later)
2479            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2480            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2481
2482            // HopByHop Options Extension Header
2483            Ipv6ExtHdrType::Fragment.into(),    // Next Header
2484            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2485            0,                       // Pad1
2486            1, 0,                    // Pad2
2487            1, 1, 0,                 // Pad3
2488
2489            // Fragment Extension Header
2490            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
2491            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2492            0, 0,                    // Fragment Offset, Res, M (M_flag)
2493            1, 1, 1, 1,              // Identification
2494
2495            // Destination Options Extension Header
2496            IpProto::Tcp.into(),    // Next Header
2497            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2498            0,                      // Pad1
2499            1, 0,                   // Pad2
2500            1, 1, 0,                // Pad3
2501            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
2502
2503            // Body
2504            1, 2, 3, 4, 5,
2505        ];
2506        let mut fixed_hdr = new_fixed_hdr();
2507        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2508        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2509        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2510        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2511        let mut buf = &bytes[..];
2512        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2513        let copied_bytes = packet.copy_header_bytes_for_fragment();
2514        let mut expected_bytes = Vec::new();
2515        expected_bytes.extend_from_slice(&bytes[..IPV6_FIXED_HDR_LEN + 8]);
2516        expected_bytes.extend_from_slice(&bytes[IPV6_FIXED_HDR_LEN + 16..bytes.len() - 5]);
2517        expected_bytes[IPV6_FIXED_HDR_LEN] = Ipv6ExtHdrType::DestinationOptions.into();
2518        assert_eq!(&copied_bytes[..], &expected_bytes[..]);
2519
2520        //
2521        // Multiple fragment extension headers
2522        //
2523
2524        #[rustfmt::skip]
2525        let mut bytes = [
2526            // FixedHeader (will be replaced later)
2527            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2528            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2529
2530            // Fragment Extension Header
2531            Ipv6ExtHdrType::Fragment.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            1, 1, 1, 1,              // Identification
2535
2536            // Fragment Extension Header
2537            IpProto::Tcp.into(),     // Next Header
2538            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2539            0, 0,                    // Fragment Offset, Res, M (M_flag)
2540            2, 2, 2, 2,              // Identification
2541
2542            // Body
2543            1, 2, 3, 4, 5,
2544        ];
2545        let mut fixed_hdr = new_fixed_hdr();
2546        fixed_hdr.next_hdr = Ipv6ExtHdrType::Fragment.into();
2547        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2548        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2549        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2550        let mut buf = &bytes[..];
2551        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2552        let copied_bytes = packet.copy_header_bytes_for_fragment();
2553        let mut expected_bytes = Vec::new();
2554        expected_bytes.extend_from_slice(&bytes[..IPV6_FIXED_HDR_LEN]);
2555        expected_bytes.extend_from_slice(&bytes[IPV6_FIXED_HDR_LEN + 8..bytes.len() - 5]);
2556        assert_eq!(&copied_bytes[..], &expected_bytes[..]);
2557    }
2558
2559    #[test]
2560    fn test_next_multiple_of_eight() {
2561        for x in 0usize..=IPV6_HBH_OPTIONS_MAX_LEN {
2562            let y = next_multiple_of_eight(x);
2563            assert_eq!(y % 8, 0);
2564            assert!(y >= x);
2565            if x % 8 == 0 {
2566                assert_eq!(x, y);
2567            } else {
2568                assert_eq!(x + (8 - x % 8), y);
2569            }
2570        }
2571    }
2572
2573    fn create_ipv4_and_ipv6_builders(
2574        proto_v4: Ipv4Proto,
2575        proto_v6: Ipv6Proto,
2576    ) -> (Ipv4PacketBuilder, Ipv6PacketBuilder) {
2577        const IP_DSCP_AND_ECN: DscpAndEcn = DscpAndEcn::new(0x12, 3);
2578        const IP_TTL: u8 = 64;
2579
2580        let mut ipv4_builder =
2581            Ipv4PacketBuilder::new(DEFAULT_V4_SRC_IP, DEFAULT_V4_DST_IP, IP_TTL, proto_v4);
2582        ipv4_builder.dscp_and_ecn(IP_DSCP_AND_ECN);
2583        ipv4_builder.df_flag(false);
2584        ipv4_builder.mf_flag(false);
2585        ipv4_builder.fragment_offset(FragmentOffset::ZERO);
2586
2587        let mut ipv6_builder =
2588            Ipv6PacketBuilder::new(DEFAULT_SRC_IP, DEFAULT_DST_IP, IP_TTL, proto_v6);
2589        ipv6_builder.dscp_and_ecn(IP_DSCP_AND_ECN);
2590        ipv6_builder.flowlabel(0x456);
2591
2592        (ipv4_builder, ipv6_builder)
2593    }
2594
2595    fn create_tcp_ipv4_and_ipv6_pkt()
2596    -> (packet::Either<EmptyBuf, Buf<Vec<u8>>>, packet::Either<EmptyBuf, Buf<Vec<u8>>>) {
2597        use crate::tcp::TcpSegmentBuilder;
2598        use core::num::NonZeroU16;
2599
2600        let tcp_src_port: NonZeroU16 = NonZeroU16::new(20).unwrap();
2601        let tcp_dst_port: NonZeroU16 = NonZeroU16::new(30).unwrap();
2602        const TCP_SEQ_NUM: u32 = 4321;
2603        const TCP_ACK_NUM: Option<u32> = Some(1234);
2604        const TCP_WINDOW_SIZE: u16 = 12345;
2605        const PAYLOAD: [u8; 10] = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
2606
2607        let (ipv4_builder, ipv6_builder) =
2608            create_ipv4_and_ipv6_builders(IpProto::Tcp.into(), IpProto::Tcp.into());
2609
2610        let tcp_builder = TcpSegmentBuilder::new(
2611            DEFAULT_V4_SRC_IP,
2612            DEFAULT_V4_DST_IP,
2613            tcp_src_port,
2614            tcp_dst_port,
2615            TCP_SEQ_NUM,
2616            TCP_ACK_NUM,
2617            TCP_WINDOW_SIZE,
2618        );
2619
2620        let v4_pkt_buf = (&PAYLOAD)
2621            .into_serializer()
2622            .wrap_in(tcp_builder)
2623            .wrap_in(ipv4_builder)
2624            .serialize_vec_outer()
2625            .expect("Failed to serialize to v4_pkt_buf");
2626
2627        let v6_tcp_builder = TcpSegmentBuilder::new(
2628            DEFAULT_SRC_IP,
2629            DEFAULT_DST_IP,
2630            tcp_src_port,
2631            tcp_dst_port,
2632            TCP_SEQ_NUM,
2633            TCP_ACK_NUM,
2634            TCP_WINDOW_SIZE,
2635        );
2636
2637        let v6_pkt_buf = (&PAYLOAD)
2638            .into_serializer()
2639            .wrap_in(v6_tcp_builder)
2640            .wrap_in(ipv6_builder)
2641            .serialize_vec_outer()
2642            .expect("Failed to serialize to v4_pkt_buf");
2643
2644        (v4_pkt_buf, v6_pkt_buf)
2645    }
2646
2647    #[test]
2648    fn test_nat64_translate_tcp() {
2649        let (expected_v4_pkt_buf, mut v6_pkt_buf) = create_tcp_ipv4_and_ipv6_pkt();
2650
2651        let parsed_v6_packet =
2652            v6_pkt_buf.parse::<Ipv6Packet<_>>().expect("Failed to parse v6_pkt_buf");
2653        let nat64_translation_result =
2654            parsed_v6_packet.nat64_translate(DEFAULT_V4_SRC_IP, DEFAULT_V4_DST_IP);
2655
2656        let serializable_pkt =
2657            assert_matches!(nat64_translation_result, Nat64TranslationResult::Forward(s) => s);
2658
2659        let translated_v4_pkt_buf = serializable_pkt
2660            .serialize_vec_outer()
2661            .expect("Failed to serialize to translated_v4_pkt_buf");
2662
2663        assert_eq!(
2664            expected_v4_pkt_buf.to_flattened_vec(),
2665            translated_v4_pkt_buf.to_flattened_vec()
2666        );
2667    }
2668
2669    fn create_udp_ipv4_and_ipv6_pkt()
2670    -> (packet::Either<EmptyBuf, Buf<Vec<u8>>>, packet::Either<EmptyBuf, Buf<Vec<u8>>>) {
2671        use crate::udp::UdpPacketBuilder;
2672        use core::num::NonZeroU16;
2673
2674        let udp_src_port: NonZeroU16 = NonZeroU16::new(35000).unwrap();
2675        let udp_dst_port: NonZeroU16 = NonZeroU16::new(53).unwrap();
2676        const PAYLOAD: [u8; 10] = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
2677
2678        let (ipv4_builder, ipv6_builder) =
2679            create_ipv4_and_ipv6_builders(IpProto::Udp.into(), IpProto::Udp.into());
2680
2681        let v4_udp_builder = UdpPacketBuilder::new(
2682            DEFAULT_V4_SRC_IP,
2683            DEFAULT_V4_DST_IP,
2684            Some(udp_src_port),
2685            udp_dst_port,
2686        );
2687
2688        let v4_pkt_buf = (&PAYLOAD)
2689            .into_serializer()
2690            .wrap_in(v4_udp_builder)
2691            .wrap_in(ipv4_builder)
2692            .serialize_vec_outer()
2693            .expect("Unable to serialize to v4_pkt_buf");
2694
2695        let v6_udp_builder =
2696            UdpPacketBuilder::new(DEFAULT_SRC_IP, DEFAULT_DST_IP, Some(udp_src_port), udp_dst_port);
2697
2698        let v6_pkt_buf = (&PAYLOAD)
2699            .into_serializer()
2700            .wrap_in(v6_udp_builder)
2701            .wrap_in(ipv6_builder)
2702            .serialize_vec_outer()
2703            .expect("Unable to serialize to v6_pkt_buf");
2704
2705        (v4_pkt_buf, v6_pkt_buf)
2706    }
2707
2708    #[test]
2709    fn test_nat64_translate_udp() {
2710        let (expected_v4_pkt_buf, mut v6_pkt_buf) = create_udp_ipv4_and_ipv6_pkt();
2711
2712        let parsed_v6_packet =
2713            v6_pkt_buf.parse::<Ipv6Packet<_>>().expect("Unable to parse Ipv6Packet");
2714        let nat64_translation_result =
2715            parsed_v6_packet.nat64_translate(DEFAULT_V4_SRC_IP, DEFAULT_V4_DST_IP);
2716
2717        let serializable_pkt = assert_matches!(nat64_translation_result,
2718                                               Nat64TranslationResult::Forward(s) => s);
2719
2720        let translated_v4_pkt_buf = serializable_pkt
2721            .serialize_vec_outer()
2722            .expect("Unable to serialize to translated_v4_pkt_buf");
2723
2724        assert_eq!(
2725            expected_v4_pkt_buf.to_flattened_vec(),
2726            translated_v4_pkt_buf.to_flattened_vec()
2727        );
2728    }
2729
2730    #[test]
2731    fn test_nat64_translate_non_tcp_udp_icmp() {
2732        const PAYLOAD: [u8; 10] = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
2733
2734        let (ipv4_builder, ipv6_builder) =
2735            create_ipv4_and_ipv6_builders(Ipv4Proto::Other(59), Ipv6Proto::Other(59));
2736
2737        let expected_v4_pkt_buf = (&PAYLOAD)
2738            .into_serializer()
2739            .wrap_in(ipv4_builder)
2740            .serialize_vec_outer()
2741            .expect("Unable to serialize to expected_v4_pkt_buf");
2742
2743        let mut v6_pkt_buf = (&PAYLOAD)
2744            .into_serializer()
2745            .wrap_in(ipv6_builder)
2746            .serialize_vec_outer()
2747            .expect("Unable to serialize to v6_pkt_buf");
2748
2749        let translated_v4_pkt_buf = {
2750            let parsed_v6_packet = v6_pkt_buf
2751                .parse::<Ipv6Packet<_>>()
2752                .expect("Unable to serialize to translated_v4_pkt_buf");
2753
2754            let nat64_translation_result =
2755                parsed_v6_packet.nat64_translate(DEFAULT_V4_SRC_IP, DEFAULT_V4_DST_IP);
2756
2757            let serializable_pkt = assert_matches!(nat64_translation_result,
2758                                                   Nat64TranslationResult::Forward(s) => s);
2759
2760            let translated_buf = serializable_pkt
2761                .serialize_vec_outer()
2762                .expect("Unable to serialize to translated_buf");
2763
2764            translated_buf
2765        };
2766
2767        assert_eq!(
2768            expected_v4_pkt_buf.to_flattened_vec(),
2769            translated_v4_pkt_buf.to_flattened_vec()
2770        );
2771    }
2772
2773    #[test_case(new_builder(), true; "fixed header more frags")]
2774    #[test_case(Ipv6PacketBuilderWithHbhOptions::new(
2775        new_builder(),
2776        &[HopByHopOption {
2777            action: ExtensionHeaderOptionAction::SkipAndContinue,
2778            mutable: false,
2779            data: HopByHopOptionData::RouterAlert { data: 0 },
2780        }]).unwrap(), false; "hbh last frag")]
2781    fn ipv6_packet_builder_with_fragment_header<
2782        B: Ipv6HeaderBuilder + Ipv6HeaderBefore<Ipv6PacketBuilderWithFragmentHeader<B>> + Debug,
2783    >(
2784        inner: B,
2785        more_fragments: bool,
2786    ) {
2787        const PAYLOAD: [u8; 10] = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
2788        let fragment_offset = FragmentOffset::new(13).unwrap();
2789        let identification = 0xABCDABCD;
2790        let builder = Ipv6PacketBuilderWithFragmentHeader::new(
2791            inner,
2792            fragment_offset,
2793            more_fragments,
2794            identification,
2795        );
2796        let mut serialized =
2797            builder.wrap_body(PAYLOAD.into_serializer()).serialize_vec_outer().unwrap().unwrap_b();
2798        let packet = serialized.parse::<Ipv6Packet<_>>().unwrap();
2799        assert!(packet.fragment_header_present());
2800        assert_eq!(packet.proto(), Ipv6Proto::Proto(IpProto::Tcp));
2801        let fragment_data = packet
2802            .extension_hdrs
2803            .into_iter()
2804            .find_map(|ext_hdr| match ext_hdr.into_data() {
2805                Ipv6ExtensionHeaderData::Fragment { fragment_data } => Some(fragment_data),
2806                _ => None,
2807            })
2808            .unwrap();
2809        assert_eq!(fragment_data.fragment_offset(), fragment_offset);
2810        assert_eq!(fragment_data.identification(), identification);
2811        assert_eq!(fragment_data.m_flag(), more_fragments);
2812    }
2813
2814    // Tests that the PacketBuilder implementations correct the maximum body
2815    // length in PacketConstraints to remove any extension header bytes used.
2816    #[test]
2817    fn extension_headers_take_from_max_body_size() {
2818        let builder = new_builder();
2819        assert_eq!(builder.constraints().max_body_len(), IPV6_MAX_PAYLOAD_LENGTH);
2820        let builder =
2821            Ipv6PacketBuilderWithFragmentHeader::new(builder, FragmentOffset::ZERO, false, 1234);
2822        assert_eq!(
2823            builder.constraints().max_body_len(),
2824            IPV6_MAX_PAYLOAD_LENGTH - IPV6_FRAGMENT_EXT_HDR_LEN
2825        );
2826    }
2827
2828    #[test]
2829    fn test_partial_serialize_parsed() {
2830        let packet_bytes = [
2831            100, 177, 4, 5, 0, 10, 6, 64, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
2832            17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 0, 1, 2, 3, 4, 5, 6, 7,
2833            8, 9,
2834        ];
2835        let packet_len = packet_bytes.len();
2836        let mut packet_bytes_copy = packet_bytes;
2837        let mut packet_bytes_ref: &mut [u8] = &mut packet_bytes_copy[..];
2838        let packet = packet_bytes_ref.parse::<Ipv6Packet<_>>().unwrap();
2839
2840        for i in 1..(packet_len + 1) {
2841            let mut buf = vec![0u8; i];
2842            let result =
2843                packet.partial_serialize(PacketConstraints::UNCONSTRAINED, buf.as_mut_slice());
2844
2845            let bytes_written = if i >= packet_len { packet_len } else { i };
2846            assert_eq!(
2847                result,
2848                Ok(PartialSerializeResult { bytes_written, total_size: packet_len })
2849            );
2850            assert_eq!(buf[..bytes_written], packet_bytes[..bytes_written]);
2851        }
2852    }
2853}