packet_formats/
udp.rs

1// Copyright 2018 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 UDP packets.
6//!
7//! The UDP packet format is defined in [RFC 768].
8//!
9//! [RFC 768]: https://datatracker.ietf.org/doc/html/rfc768
10
11use core::fmt::Debug;
12#[cfg(test)]
13use core::fmt::{self, Formatter};
14use core::num::NonZeroU16;
15use core::ops::Range;
16
17use net_types::ip::{Ip, IpAddress, IpVersionMarker};
18use packet::{
19    BufferView, BufferViewMut, ByteSliceInnerPacketBuilder, EmptyBuf, FragmentedBytesMut, FromRaw,
20    InnerPacketBuilder, MaybeParsed, PacketBuilder, PacketConstraints, ParsablePacket,
21    ParseMetadata, SerializeTarget, Serializer,
22};
23use zerocopy::byteorder::network_endian::U16;
24use zerocopy::{
25    FromBytes, Immutable, IntoBytes, KnownLayout, Ref, SplitByteSlice, SplitByteSliceMut, Unaligned,
26};
27
28use crate::error::{ParseError, ParseResult};
29use crate::ip::IpProto;
30use crate::{compute_transport_checksum_parts, compute_transport_checksum_serialize};
31
32/// The size of a UDP header in bytes.
33pub const HEADER_BYTES: usize = 8;
34const CHECKSUM_OFFSET: usize = 6;
35const CHECKSUM_RANGE: Range<usize> = CHECKSUM_OFFSET..CHECKSUM_OFFSET + 2;
36
37#[derive(Debug, KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned)]
38#[repr(C)]
39struct Header {
40    src_port: U16,
41    dst_port: U16,
42    length: U16,
43    checksum: [u8; 2],
44}
45
46impl Header {
47    fn checksummed(&self) -> bool {
48        self.checksum != U16::ZERO
49    }
50
51    pub fn set_src_port(&mut self, new: u16) {
52        let old = self.src_port;
53        let new = U16::from(new);
54        self.src_port = new;
55        if self.checksummed() {
56            self.checksum =
57                internet_checksum::update(self.checksum, old.as_bytes(), new.as_bytes());
58        }
59    }
60
61    pub fn set_dst_port(&mut self, new: NonZeroU16) {
62        let old = self.dst_port;
63        let new = U16::from(new.get());
64        self.dst_port = new;
65        if self.checksummed() {
66            self.checksum =
67                internet_checksum::update(self.checksum, old.as_bytes(), new.as_bytes());
68        }
69    }
70
71    pub fn update_checksum_pseudo_header_address<A: IpAddress>(&mut self, old: A, new: A) {
72        if self.checksummed() {
73            self.checksum = internet_checksum::update(self.checksum, old.bytes(), new.bytes());
74        }
75    }
76}
77
78/// A UDP packet.
79///
80/// A `UdpPacket` shares its underlying memory with the byte slice it was parsed
81/// from or serialized to, meaning that no copying or extra allocation is
82/// necessary.
83///
84/// A `UdpPacket` - whether parsed using `parse` or created using `serialize` -
85/// maintains the invariant that the checksum is always valid.
86pub struct UdpPacket<B> {
87    header: Ref<B, Header>,
88    body: B,
89}
90
91/// Arguments required to parse a UDP packet.
92pub struct UdpParseArgs<A: IpAddress> {
93    src_ip: A,
94    dst_ip: A,
95}
96
97impl<A: IpAddress> UdpParseArgs<A> {
98    /// Construct a new `UdpParseArgs`.
99    pub fn new(src_ip: A, dst_ip: A) -> UdpParseArgs<A> {
100        UdpParseArgs { src_ip, dst_ip }
101    }
102}
103
104impl<B: SplitByteSlice, A: IpAddress> FromRaw<UdpPacketRaw<B>, UdpParseArgs<A>> for UdpPacket<B> {
105    type Error = ParseError;
106
107    fn try_from_raw_with(raw: UdpPacketRaw<B>, args: UdpParseArgs<A>) -> Result<Self, Self::Error> {
108        // See for details: https://en.wikipedia.org/wiki/User_Datagram_Protocol#Packet_structure
109        let header = raw
110            .header
111            .ok_or_else(|_| debug_err!(ParseError::Format, "too few bytes for header"))?;
112        let body = raw.body.ok_or_else(|_| debug_err!(ParseError::Format, "incomplete body"))?;
113
114        let checksum = header.checksum;
115        // A 0 checksum indicates that the checksum wasn't computed. In IPv4,
116        // this means that it shouldn't be validated. In IPv6, the checksum is
117        // mandatory, so this is an error.
118        if checksum != [0, 0] {
119            let parts = [Ref::bytes(&header), body.deref().as_ref()];
120            let checksum = compute_transport_checksum_parts(
121                args.src_ip,
122                args.dst_ip,
123                IpProto::Udp.into(),
124                parts.iter(),
125            )
126            .ok_or_else(debug_err_fn!(ParseError::Format, "packet too large"))?;
127
128            // Even the checksum is transmitted as 0xFFFF, the checksum of the whole
129            // UDP packet should still be 0. This is because in 1's complement, it is
130            // not possible to produce +0(0) from adding non-zero 16-bit words.
131            // Since our 0xFFFF ensures there is at least one non-zero 16-bit word,
132            // the addition can only produce -0(0xFFFF) and after negation, it is
133            // still 0. A test `test_udp_checksum_0xffff` is included to make sure
134            // this is true.
135            if checksum != [0, 0] {
136                return debug_err!(
137                    Err(ParseError::Checksum),
138                    "invalid checksum {:X?}",
139                    header.checksum,
140                );
141            }
142        } else if A::Version::VERSION.is_v6() {
143            return debug_err!(Err(ParseError::Format), "missing checksum");
144        }
145
146        if header.dst_port.get() == 0 {
147            return debug_err!(Err(ParseError::Format), "zero destination port");
148        }
149
150        Ok(UdpPacket { header, body })
151    }
152}
153
154impl<B: SplitByteSlice, A: IpAddress> ParsablePacket<B, UdpParseArgs<A>> for UdpPacket<B> {
155    type Error = ParseError;
156
157    fn parse_metadata(&self) -> ParseMetadata {
158        ParseMetadata::from_packet(Ref::bytes(&self.header).len(), self.body.len(), 0)
159    }
160
161    fn parse<BV: BufferView<B>>(buffer: BV, args: UdpParseArgs<A>) -> ParseResult<Self> {
162        UdpPacketRaw::<B>::parse(buffer, IpVersionMarker::<A::Version>::default())
163            .and_then(|u| UdpPacket::try_from_raw_with(u, args))
164    }
165}
166
167impl<B: SplitByteSlice> UdpPacket<B> {
168    /// The packet body.
169    pub fn body(&self) -> &[u8] {
170        self.body.deref()
171    }
172
173    /// Consumes this packet and returns the body.
174    ///
175    /// Note that the returned `B` has the same lifetime as the buffer from
176    /// which this packet was parsed. By contrast, the [`body`] method returns a
177    /// slice with the same lifetime as the receiver.
178    ///
179    /// [`body`]: UdpPacket::body
180    pub fn into_body(self) -> B {
181        self.body
182    }
183
184    /// The source UDP port, if any.
185    ///
186    /// The source port is optional, and may have been omitted by the sender.
187    pub fn src_port(&self) -> Option<NonZeroU16> {
188        NonZeroU16::new(self.header.src_port.get())
189    }
190
191    /// The destination UDP port.
192    pub fn dst_port(&self) -> NonZeroU16 {
193        // Infallible because it was validated in parse.
194        NonZeroU16::new(self.header.dst_port.get()).unwrap()
195    }
196
197    /// Did this packet have a checksum?
198    ///
199    /// On IPv4, the sender may optionally omit the checksum. If this function
200    /// returns false, the sender omitted the checksum, and `parse` will not
201    /// have validated it.
202    ///
203    /// On IPv6, it is guaranteed that `checksummed` will return true because
204    /// IPv6 requires a checksum, and so any UDP packet missing one will fail
205    /// validation in `parse`.
206    pub fn checksummed(&self) -> bool {
207        self.header.checksummed()
208    }
209
210    /// Constructs a builder with the same contents as this packet.
211    pub fn builder<A: IpAddress>(&self, src_ip: A, dst_ip: A) -> UdpPacketBuilder<A> {
212        UdpPacketBuilder {
213            src_ip,
214            dst_ip,
215            src_port: self.src_port(),
216            dst_port: Some(self.dst_port()),
217        }
218    }
219
220    /// Consumes this packet and constructs a [`Serializer`] with the same
221    /// contents.
222    ///
223    /// The returned `Serializer` has the [`Buffer`] type [`EmptyBuf`], which
224    /// means it is not able to reuse the buffer backing this `UdpPacket` when
225    /// serializing, and will always need to allocate a new buffer.
226    ///
227    /// By consuming `self` instead of taking it by-reference, `into_serializer`
228    /// is able to return a `Serializer` whose lifetime is restricted by the
229    /// lifetime of the buffer from which this `UdpPacket` was parsed rather
230    /// than by the lifetime on `&self`, which may be more restricted.
231    ///
232    /// [`Buffer`]: packet::Serializer::Buffer
233    pub fn into_serializer<'a, A: IpAddress>(
234        self,
235        src_ip: A,
236        dst_ip: A,
237    ) -> impl Serializer<Buffer = EmptyBuf> + Debug + 'a
238    where
239        B: 'a,
240    {
241        let builder = self.builder(src_ip, dst_ip);
242        ByteSliceInnerPacketBuilder(self.body).into_serializer().encapsulate(builder)
243    }
244}
245
246impl<B: SplitByteSliceMut> UdpPacket<B> {
247    /// Set the source port of the UDP packet.
248    pub fn set_src_port(&mut self, new: u16) {
249        self.header.set_src_port(new)
250    }
251
252    /// Set the destination port of the UDP packet.
253    pub fn set_dst_port(&mut self, new: NonZeroU16) {
254        self.header.set_dst_port(new);
255    }
256
257    /// Update the checksum to reflect an updated address in the pseudo header.
258    pub fn update_checksum_pseudo_header_address<A: IpAddress>(&mut self, old: A, new: A) {
259        self.header.update_checksum_pseudo_header_address(old, new);
260    }
261}
262
263/// The minimal information required from a UDP packet header.
264///
265/// A `UdpPacketHeader` may be the result of a partially parsed UDP packet in
266/// [`UdpPacketRaw`].
267#[derive(Debug, Default, KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned, PartialEq)]
268#[repr(C)]
269struct UdpFlowHeader {
270    src_port: U16,
271    dst_port: U16,
272}
273
274/// A partially parsed UDP packet header.
275#[derive(Debug)]
276struct PartialHeader<B: SplitByteSlice> {
277    flow: Ref<B, UdpFlowHeader>,
278    rest: B,
279}
280
281/// A partially-parsed and not yet validated UDP packet.
282///
283/// A `UdpPacketRaw` shares its underlying memory with the byte slice it was
284/// parsed from or serialized to, meaning that no copying or extra allocation is
285/// necessary.
286///
287/// Parsing a `UdpPacketRaw` from raw data will succeed as long as at least 4
288/// bytes are available, which will be extracted as a [`UdpFlowHeader`] that
289/// contains the UDP source and destination ports. A `UdpPacketRaw` is, then,
290/// guaranteed to always have at least that minimal information available.
291///
292/// [`UdpPacket`] provides a [`FromRaw`] implementation that can be used to
293/// validate a `UdpPacketRaw`.
294pub struct UdpPacketRaw<B: SplitByteSlice> {
295    header: MaybeParsed<Ref<B, Header>, PartialHeader<B>>,
296    body: MaybeParsed<B, B>,
297}
298
299impl<B, I> ParsablePacket<B, IpVersionMarker<I>> for UdpPacketRaw<B>
300where
301    B: SplitByteSlice,
302    I: Ip,
303{
304    type Error = ParseError;
305
306    fn parse_metadata(&self) -> ParseMetadata {
307        let header_len = match &self.header {
308            MaybeParsed::Complete(h) => Ref::bytes(&h).len(),
309            MaybeParsed::Incomplete(h) => Ref::bytes(&h.flow).len() + h.rest.len(),
310        };
311        ParseMetadata::from_packet(header_len, self.body.len(), 0)
312    }
313
314    fn parse<BV: BufferView<B>>(mut buffer: BV, _args: IpVersionMarker<I>) -> ParseResult<Self> {
315        // See for details: https://en.wikipedia.org/wiki/User_Datagram_Protocol#Packet_structure
316
317        let header = if let Some(header) = buffer.take_obj_front::<Header>() {
318            header
319        } else {
320            let flow = buffer
321                .take_obj_front::<UdpFlowHeader>()
322                .ok_or_else(debug_err_fn!(ParseError::Format, "too few bytes for flow header"))?;
323            // if we can't parse an entire header, just return early since
324            // there's no way to look into how many body bytes to consume:
325            return Ok(UdpPacketRaw {
326                header: MaybeParsed::Incomplete(PartialHeader {
327                    flow,
328                    rest: buffer.take_rest_front(),
329                }),
330                body: MaybeParsed::Incomplete(buffer.into_rest()),
331            });
332        };
333        let buffer_len = buffer.len();
334
335        fn get_udp_body_length<I: Ip>(header: &Header, remaining_buff_len: usize) -> Option<usize> {
336            // IPv6 supports jumbograms, so a UDP packet may be greater than
337            // 2^16 bytes in size. In this case, the size doesn't fit in the
338            // 16-bit length field in the header, and so the length field is set
339            // to zero to indicate this.
340            //
341            // Per RFC 2675 Section 4, we only do that if the UDP header plus
342            // data is actually more than 65535.
343            if I::VERSION.is_v6()
344                && header.length.get() == 0
345                && remaining_buff_len.saturating_add(HEADER_BYTES) >= (core::u16::MAX as usize)
346            {
347                return Some(remaining_buff_len);
348            }
349
350            usize::from(header.length.get()).checked_sub(HEADER_BYTES)
351        }
352
353        let body = if let Some(body_len) = get_udp_body_length::<I>(&header, buffer_len) {
354            if body_len <= buffer_len {
355                // Discard any padding left by the previous layer. The unwrap is safe
356                // and the subtraction is always valid because body_len is guaranteed
357                // to not exceed buffer.len()
358                let _: B = buffer.take_back(buffer_len - body_len).unwrap();
359                MaybeParsed::Complete(buffer.into_rest())
360            } else {
361                // buffer does not contain all the body bytes
362                MaybeParsed::Incomplete(buffer.into_rest())
363            }
364        } else {
365            // body_len can't be calculated because it's less than the header
366            // length, consider all the rest of the buffer padding and return
367            // an incomplete empty body.
368            let _: B = buffer.take_rest_back();
369            MaybeParsed::Incomplete(buffer.into_rest())
370        };
371
372        Ok(UdpPacketRaw { header: MaybeParsed::Complete(header), body })
373    }
374}
375
376impl<B: SplitByteSlice> UdpPacketRaw<B> {
377    /// The source UDP port, if any.
378    ///
379    /// The source port is optional, and may have been omitted by the sender.
380    pub fn src_port(&self) -> Option<NonZeroU16> {
381        NonZeroU16::new(
382            self.header
383                .as_ref()
384                .map(|header| header.src_port)
385                .map_incomplete(|partial_header| partial_header.flow.src_port)
386                .into_inner()
387                .get(),
388        )
389    }
390
391    /// The destination UDP port.
392    ///
393    /// UDP packets must not have a destination port of 0; thus, if this
394    /// function returns `None`, then the packet is malformed.
395    pub fn dst_port(&self) -> Option<NonZeroU16> {
396        NonZeroU16::new(
397            self.header
398                .as_ref()
399                .map(|header| header.dst_port)
400                .map_incomplete(|partial_header| partial_header.flow.dst_port)
401                .into_inner()
402                .get(),
403        )
404    }
405
406    /// Constructs a builder with the same contents as this packet.
407    ///
408    /// Note that, since `UdpPacketRaw` does not validate its header fields,
409    /// it's possible for `builder` to produce a `UdpPacketBuilder` which
410    /// describes an invalid UDP packet. In particular, it's possible that its
411    /// destination port will be zero, which is illegal.
412    pub fn builder<A: IpAddress>(&self, src_ip: A, dst_ip: A) -> UdpPacketBuilder<A> {
413        UdpPacketBuilder { src_ip, dst_ip, src_port: self.src_port(), dst_port: self.dst_port() }
414    }
415
416    /// Consumes this packet and constructs a [`Serializer`] with the same
417    /// contents.
418    ///
419    /// Returns `None` if the body was not fully parsed.
420    ///
421    /// This method has the same validity caveats as [`builder`].
422    ///
423    /// The returned `Serializer` has the [`Buffer`] type [`EmptyBuf`], which
424    /// means it is not able to reuse the buffer backing this `UdpPacket` when
425    /// serializing, and will always need to allocate a new buffer.
426    ///
427    /// By consuming `self` instead of taking it by-reference, `into_serializer`
428    /// is able to return a `Serializer` whose lifetime is restricted by the
429    /// lifetime of the buffer from which this `UdpPacket` was parsed rather
430    /// than by the lifetime on `&self`, which may be more restricted.
431    ///
432    /// [`builder`]: UdpPacketRaw::builder
433    /// [`Buffer`]: packet::Serializer::Buffer
434    pub fn into_serializer<'a, A: IpAddress>(
435        self,
436        src_ip: A,
437        dst_ip: A,
438    ) -> Option<impl Serializer<Buffer = EmptyBuf> + 'a>
439    where
440        B: 'a,
441    {
442        let builder = self.builder(src_ip, dst_ip);
443        self.body
444            .complete()
445            .ok()
446            .map(|body| ByteSliceInnerPacketBuilder(body).into_serializer().encapsulate(builder))
447    }
448}
449
450impl<B: SplitByteSliceMut> UdpPacketRaw<B> {
451    /// Set the source port of the UDP packet.
452    pub fn set_src_port(&mut self, new: u16) {
453        match &mut self.header {
454            MaybeParsed::Complete(h) => h.set_src_port(new),
455            MaybeParsed::Incomplete(h) => {
456                h.flow.src_port = U16::from(new);
457
458                // We don't have the checksum, so there's nothing to update.
459            }
460        }
461    }
462
463    /// Set the destination port of the UDP packet.
464    pub fn set_dst_port(&mut self, new: NonZeroU16) {
465        match &mut self.header {
466            MaybeParsed::Complete(h) => h.set_dst_port(new),
467            MaybeParsed::Incomplete(h) => {
468                h.flow.dst_port = U16::from(new.get());
469
470                // We don't have the checksum, so there's nothing to update.
471            }
472        }
473    }
474
475    /// Update the checksum to reflect an updated address in the pseudo header.
476    pub fn update_checksum_pseudo_header_address<A: IpAddress>(&mut self, old: A, new: A) {
477        match &mut self.header {
478            MaybeParsed::Complete(h) => h.update_checksum_pseudo_header_address(old, new),
479            MaybeParsed::Incomplete(_) => {
480                // We don't have the checksum, so there's nothing to update.
481            }
482        }
483    }
484}
485
486// NOTE(joshlf): In order to ensure that the checksum is always valid, we don't
487// expose any setters for the fields of the UDP packet; the only way to set them
488// is via UdpPacketBuilder::serialize. This, combined with checksum validation
489// performed in UdpPacket::parse, provides the invariant that a UdpPacket always
490// has a valid checksum.
491
492/// A builder for UDP packets.
493#[derive(Copy, Clone, Debug, PartialEq)]
494pub struct UdpPacketBuilder<A: IpAddress> {
495    src_ip: A,
496    dst_ip: A,
497    src_port: Option<NonZeroU16>,
498    dst_port: Option<NonZeroU16>,
499}
500
501impl<A: IpAddress> UdpPacketBuilder<A> {
502    /// Constructs a new `UdpPacketBuilder`.
503    pub fn new(
504        src_ip: A,
505        dst_ip: A,
506        src_port: Option<NonZeroU16>,
507        dst_port: NonZeroU16,
508    ) -> UdpPacketBuilder<A> {
509        UdpPacketBuilder { src_ip, dst_ip, src_port, dst_port: Some(dst_port) }
510    }
511
512    /// Returns the source port for the builder.
513    pub fn src_port(&self) -> Option<NonZeroU16> {
514        self.src_port
515    }
516
517    /// Returns the destination port for the builder.
518    pub fn dst_port(&self) -> Option<NonZeroU16> {
519        self.dst_port
520    }
521
522    /// Sets the source IP address for the builder.
523    pub fn set_src_ip(&mut self, addr: A) {
524        self.src_ip = addr;
525    }
526
527    /// Sets the destination IP address for the builder.
528    pub fn set_dst_ip(&mut self, addr: A) {
529        self.dst_ip = addr;
530    }
531
532    /// Sets the source port for the builder.
533    pub fn set_src_port(&mut self, port: u16) {
534        self.src_port = NonZeroU16::new(port);
535    }
536
537    /// Sets the destination port for the builder.
538    pub fn set_dst_port(&mut self, port: NonZeroU16) {
539        self.dst_port = Some(port);
540    }
541}
542
543impl<A: IpAddress> PacketBuilder for UdpPacketBuilder<A> {
544    fn constraints(&self) -> PacketConstraints {
545        PacketConstraints::new(
546            HEADER_BYTES,
547            0,
548            0,
549            if A::Version::VERSION.is_v4() {
550                (1 << 16) - 1
551            } else {
552                // IPv6 supports jumbograms, so a UDP packet may be greater than
553                // 2^16 bytes. In this case, the size doesn't fit in the 16-bit
554                // length field in the header, and so the length field is set to
555                // zero. That means that, from this packet's perspective,
556                // there's no effective limit on the body size.
557                core::usize::MAX
558            },
559        )
560    }
561
562    fn serialize(&self, target: &mut SerializeTarget<'_>, body: FragmentedBytesMut<'_, '_>) {
563        // See for details: https://en.wikipedia.org/wiki/User_Datagram_Protocol#Packet_structure
564
565        let total_len = target.header.len() + body.len() + target.footer.len();
566
567        // `write_obj_front` consumes the extent of the receiving slice, but
568        // that behavior is undesirable here: at the end of this method, we
569        // write the checksum back into the header. To avoid this, we re-slice
570        // header before calling `write_obj_front`; the re-slice will be
571        // consumed, but `target.header` is unaffected.
572        (&mut &mut target.header[..]).write_obj_front(&Header {
573            src_port: U16::new(self.src_port.map_or(0, NonZeroU16::get)),
574            dst_port: U16::new(self.dst_port.map_or(0, NonZeroU16::get)),
575            length: U16::new(total_len.try_into().unwrap_or_else(|_| {
576                if A::Version::VERSION.is_v6() {
577                    // See comment in max_body_len
578                    0u16
579                } else {
580                    panic!(
581                    "total UDP packet length of {} bytes overflows 16-bit length field of UDP header",
582                    total_len)
583                }
584            })),
585            // Initialize the checksum to 0 so that we will get the correct
586            // value when we compute it below.
587            checksum: [0, 0],
588        }).expect("too few bytes for UDP header");
589
590        let mut checksum = compute_transport_checksum_serialize(
591            self.src_ip,
592            self.dst_ip,
593            IpProto::Udp.into(),
594            target,
595            body,
596        )
597        .unwrap_or_else(|| {
598            panic!(
599                "total UDP packet length of {} bytes overflows length field of pseudo-header",
600                total_len
601            )
602        });
603        if checksum == [0, 0] {
604            checksum = [0xFF, 0xFF];
605        }
606        target.header[CHECKSUM_RANGE].copy_from_slice(&checksum[..]);
607    }
608}
609
610// needed by Result::unwrap_err in the tests below
611#[cfg(test)]
612impl<B> Debug for UdpPacket<B> {
613    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
614        write!(fmt, "UdpPacket")
615    }
616}
617
618#[cfg(test)]
619mod tests {
620    use byteorder::{ByteOrder, NetworkEndian};
621    use net_types::ip::{Ipv4, Ipv4Addr, Ipv6, Ipv6Addr};
622    use packet::{Buf, ParseBuffer};
623
624    use super::*;
625    use crate::ethernet::{EthernetFrame, EthernetFrameLengthCheck};
626    use crate::ipv4::{Ipv4Header, Ipv4Packet};
627    use crate::ipv6::{Ipv6Header, Ipv6Packet};
628    use crate::testutil::benchmarks::{black_box, Bencher};
629    use crate::testutil::*;
630
631    const TEST_SRC_IPV4: Ipv4Addr = Ipv4Addr::new([1, 2, 3, 4]);
632    const TEST_DST_IPV4: Ipv4Addr = Ipv4Addr::new([5, 6, 7, 8]);
633    const TEST_SRC_IPV6: Ipv6Addr =
634        Ipv6Addr::from_bytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
635    const TEST_DST_IPV6: Ipv6Addr =
636        Ipv6Addr::from_bytes([17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]);
637
638    #[test]
639    fn test_parse_serialize_full_ipv4() {
640        use crate::testdata::dns_request_v4::*;
641
642        let mut buf = ETHERNET_FRAME.bytes;
643        let frame = buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
644        verify_ethernet_frame(&frame, ETHERNET_FRAME);
645
646        let mut body = frame.body();
647        let ip_packet = body.parse::<Ipv4Packet<_>>().unwrap();
648        verify_ipv4_packet(&ip_packet, IPV4_PACKET);
649
650        let mut body = ip_packet.body();
651        let udp_packet = body
652            .parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(
653                ip_packet.src_ip(),
654                ip_packet.dst_ip(),
655            ))
656            .unwrap();
657        verify_udp_packet(&udp_packet, UDP_PACKET);
658
659        let buffer = udp_packet
660            .body()
661            .into_serializer()
662            .encapsulate(udp_packet.builder(ip_packet.src_ip(), ip_packet.dst_ip()))
663            .encapsulate(ip_packet.builder())
664            .encapsulate(frame.builder())
665            .serialize_vec_outer()
666            .unwrap();
667        assert_eq!(buffer.as_ref(), ETHERNET_FRAME.bytes);
668    }
669
670    #[test]
671    fn test_parse_serialize_full_ipv6() {
672        use crate::testdata::dns_request_v6::*;
673
674        let mut buf = ETHERNET_FRAME.bytes;
675        let frame = buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
676        verify_ethernet_frame(&frame, ETHERNET_FRAME);
677
678        let mut body = frame.body();
679        let ip_packet = body.parse::<Ipv6Packet<_>>().unwrap();
680        verify_ipv6_packet(&ip_packet, IPV6_PACKET);
681
682        let mut body = ip_packet.body();
683        let udp_packet = body
684            .parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(
685                ip_packet.src_ip(),
686                ip_packet.dst_ip(),
687            ))
688            .unwrap();
689        verify_udp_packet(&udp_packet, UDP_PACKET);
690
691        let buffer = udp_packet
692            .body()
693            .into_serializer()
694            .encapsulate(udp_packet.builder(ip_packet.src_ip(), ip_packet.dst_ip()))
695            .encapsulate(ip_packet.builder())
696            .encapsulate(frame.builder())
697            .serialize_vec_outer()
698            .unwrap();
699        assert_eq!(buffer.as_ref(), ETHERNET_FRAME.bytes);
700    }
701
702    #[test]
703    fn test_parse() {
704        // source port of 0 (meaning none) is allowed, as is a missing checksum
705        let mut buf = &[0, 0, 1, 2, 0, 8, 0, 0][..];
706        let packet = buf
707            .parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(TEST_SRC_IPV4, TEST_DST_IPV4))
708            .unwrap();
709        assert!(packet.src_port().is_none());
710        assert_eq!(packet.dst_port().get(), NetworkEndian::read_u16(&[1, 2]));
711        assert!(!packet.checksummed());
712        assert!(packet.body().is_empty());
713
714        // length of 0 is allowed in IPv6 if the body is long enough
715        let mut buf = vec![0_u8, 0, 1, 2, 0, 0, 0xBF, 0x12];
716        buf.extend((0..core::u16::MAX).into_iter().map(|p| p as u8));
717        let bv = &mut &buf[..];
718        let packet = bv
719            .parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(TEST_SRC_IPV6, TEST_DST_IPV6))
720            .unwrap();
721        assert!(packet.src_port().is_none());
722        assert_eq!(packet.dst_port().get(), NetworkEndian::read_u16(&[1, 2]));
723        assert!(packet.checksummed());
724        assert_eq!(packet.body().len(), core::u16::MAX as usize);
725    }
726
727    #[test]
728    fn test_serialize() {
729        let mut buf = (&[])
730            .into_serializer()
731            .encapsulate(UdpPacketBuilder::new(
732                TEST_SRC_IPV4,
733                TEST_DST_IPV4,
734                NonZeroU16::new(1),
735                NonZeroU16::new(2).unwrap(),
736            ))
737            .serialize_vec_outer()
738            .unwrap();
739        assert_eq!(buf.as_ref(), [0, 1, 0, 2, 0, 8, 239, 199]);
740        let packet = buf
741            .parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(TEST_SRC_IPV4, TEST_DST_IPV4))
742            .unwrap();
743        // assert that when we parse those bytes, we get the values we set in
744        // the builder
745        assert_eq!(packet.src_port().unwrap().get(), 1);
746        assert_eq!(packet.dst_port().get(), 2);
747        assert!(packet.checksummed());
748    }
749
750    #[test]
751    fn test_serialize_zeroes() {
752        // Test that UdpPacket::serialize properly zeroes memory before serializing
753        // the header.
754        let mut buf_0 = [0; HEADER_BYTES];
755        let _: Buf<&mut [u8]> = Buf::new(&mut buf_0[..], HEADER_BYTES..)
756            .encapsulate(UdpPacketBuilder::new(
757                TEST_SRC_IPV4,
758                TEST_DST_IPV4,
759                NonZeroU16::new(1),
760                NonZeroU16::new(2).unwrap(),
761            ))
762            .serialize_vec_outer()
763            .unwrap()
764            .unwrap_a();
765        let mut buf_1 = [0xFF; HEADER_BYTES];
766        let _: Buf<&mut [u8]> = Buf::new(&mut buf_1[..], HEADER_BYTES..)
767            .encapsulate(UdpPacketBuilder::new(
768                TEST_SRC_IPV4,
769                TEST_DST_IPV4,
770                NonZeroU16::new(1),
771                NonZeroU16::new(2).unwrap(),
772            ))
773            .serialize_vec_outer()
774            .unwrap()
775            .unwrap_a();
776        assert_eq!(buf_0, buf_1);
777    }
778
779    #[test]
780    fn test_parse_error() {
781        // Test that while a given byte pattern optionally succeeds, zeroing out
782        // certain bytes causes failure. `zero` is a list of byte indices to
783        // zero out that should cause failure.
784        fn test_zero<I: IpAddress>(
785            src: I,
786            dst: I,
787            succeeds: bool,
788            zero: &[usize],
789            err: ParseError,
790        ) {
791            // Set checksum to zero so that, in IPV4, it will be ignored. In
792            // IPv6, this /is/ the test.
793            let mut buf = [1, 2, 3, 4, 0, 8, 0, 0];
794            if succeeds {
795                let mut buf = &buf[..];
796                assert!(buf.parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(src, dst)).is_ok());
797            }
798            for idx in zero {
799                buf[*idx] = 0;
800            }
801            let mut buf = &buf[..];
802            assert_eq!(
803                buf.parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(src, dst)).unwrap_err(),
804                err
805            );
806        }
807
808        // destination port of 0 is disallowed
809        test_zero(TEST_SRC_IPV4, TEST_DST_IPV4, true, &[2, 3], ParseError::Format);
810        // length of 0 is disallowed in IPv4
811        test_zero(TEST_SRC_IPV4, TEST_DST_IPV4, true, &[4, 5], ParseError::Format);
812        // missing checksum is disallowed in IPv6; this won't succeed ahead of
813        // time because the checksum bytes are already zero
814        test_zero(TEST_SRC_IPV6, TEST_DST_IPV6, false, &[], ParseError::Format);
815
816        // 2^32 overflows on 32-bit platforms
817        #[cfg(target_pointer_width = "64")]
818        {
819            // total length of 2^32 or greater is disallowed in IPv6
820            let mut buf = vec![0u8; 1 << 32];
821            (&mut buf[..HEADER_BYTES]).copy_from_slice(&[0, 0, 1, 2, 0, 0, 0xFF, 0xE4]);
822            assert_eq!(
823                (&buf[..])
824                    .parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(TEST_SRC_IPV6, TEST_DST_IPV6))
825                    .unwrap_err(),
826                ParseError::Format
827            );
828        }
829    }
830
831    #[test]
832    #[should_panic(expected = "too few bytes for UDP header")]
833    fn test_serialize_fail_header_too_short() {
834        let mut buf = [0u8; 7];
835        let mut buf = [&mut buf[..]];
836        let buf = FragmentedBytesMut::new(&mut buf[..]);
837        let (header, body, footer) = buf.try_split_contiguous(..).unwrap();
838        let builder =
839            UdpPacketBuilder::new(TEST_SRC_IPV4, TEST_DST_IPV4, None, NonZeroU16::new(1).unwrap());
840        builder.serialize(&mut SerializeTarget { header, footer }, body);
841    }
842
843    #[test]
844    #[should_panic(expected = "total UDP packet length of 65536 bytes overflows 16-bit length \
845                               field of UDP header")]
846    fn test_serialize_fail_packet_too_long_ipv4() {
847        let ser = (&[0; (1 << 16) - HEADER_BYTES][..]).into_serializer().encapsulate(
848            UdpPacketBuilder::new(TEST_SRC_IPV4, TEST_DST_IPV4, None, NonZeroU16::new(1).unwrap()),
849        );
850        let _ = ser.serialize_vec_outer();
851    }
852
853    #[test]
854    fn test_partial_parse() {
855        use core::ops::Deref as _;
856
857        // Try to get something with only the flow header:
858        let buf = [0, 0, 1, 2, 10, 20];
859        let mut bv = &buf[..];
860        let packet =
861            bv.parse_with::<_, UdpPacketRaw<_>>(IpVersionMarker::<Ipv4>::default()).unwrap();
862        let UdpPacketRaw { header, body } = &packet;
863        let PartialHeader { flow, rest } = header.as_ref().incomplete().unwrap();
864        assert_eq!(
865            flow.deref(),
866            &UdpFlowHeader { src_port: U16::new(0), dst_port: U16::new(0x0102) }
867        );
868        assert_eq!(*rest, &buf[4..]);
869        assert_eq!(body.incomplete().unwrap(), []);
870        assert!(UdpPacket::try_from_raw_with(
871            packet,
872            UdpParseArgs::new(TEST_SRC_IPV4, TEST_DST_IPV4)
873        )
874        .is_err());
875
876        // check that we fail if flow header is not retrievable:
877        let mut buf = &[0, 0, 1][..];
878        assert!(buf.parse_with::<_, UdpPacketRaw<_>>(IpVersionMarker::<Ipv4>::default()).is_err());
879
880        // Get an incomplete body:
881        let buf = [0, 0, 1, 2, 0, 30, 0, 0, 10, 20];
882        let mut bv = &buf[..];
883        let packet =
884            bv.parse_with::<_, UdpPacketRaw<_>>(IpVersionMarker::<Ipv4>::default()).unwrap();
885        let UdpPacketRaw { header, body } = &packet;
886        assert_eq!(Ref::bytes(&header.as_ref().complete().unwrap()), &buf[..8]);
887        assert_eq!(body.incomplete().unwrap(), &buf[8..]);
888        assert!(UdpPacket::try_from_raw_with(
889            packet,
890            UdpParseArgs::new(TEST_SRC_IPV4, TEST_DST_IPV4)
891        )
892        .is_err());
893
894        // Incomplete empty body if total length in header is less than 8:
895        let buf = [0, 0, 1, 2, 0, 6, 0, 0, 10, 20];
896        let mut bv = &buf[..];
897        let packet =
898            bv.parse_with::<_, UdpPacketRaw<_>>(IpVersionMarker::<Ipv4>::default()).unwrap();
899        let UdpPacketRaw { header, body } = &packet;
900        assert_eq!(Ref::bytes(&header.as_ref().complete().unwrap()), &buf[..8]);
901        assert_eq!(body.incomplete().unwrap(), []);
902        assert!(UdpPacket::try_from_raw_with(
903            packet,
904            UdpParseArgs::new(TEST_SRC_IPV4, TEST_DST_IPV4)
905        )
906        .is_err());
907
908        // IPv6 allows zero-length body, which will just be the rest of the
909        // buffer, but only as long as it has more than 65535 bytes, otherwise
910        // it'll just be interpreted as an invalid length:
911        let buf = [0, 0, 1, 2, 0, 0, 0, 0, 10, 20];
912        let mut bv = &buf[..];
913        let packet =
914            bv.parse_with::<_, UdpPacketRaw<_>>(IpVersionMarker::<Ipv6>::default()).unwrap();
915        let UdpPacketRaw { header, body } = &packet;
916        assert_eq!(Ref::bytes(&header.as_ref().complete().unwrap()), &buf[..8]);
917        assert_eq!(body.incomplete().unwrap(), []);
918        // Now try same thing but with a body that's actually big enough to
919        // justify len being 0.
920        let mut buf = vec![0, 0, 1, 2, 0, 0, 0, 0, 10, 20];
921        buf.extend((0..core::u16::MAX).into_iter().map(|x| x as u8));
922        let bv = &mut &buf[..];
923        let packet =
924            bv.parse_with::<_, UdpPacketRaw<_>>(IpVersionMarker::<Ipv6>::default()).unwrap();
925        let UdpPacketRaw { header, body } = &packet;
926        assert_eq!(Ref::bytes(header.as_ref().complete().unwrap()), &buf[..8]);
927        assert_eq!(body.complete().unwrap(), &buf[8..]);
928    }
929
930    #[test]
931    fn test_udp_checksum_0xffff() {
932        // Test the behavior when a UDP packet has to
933        // flip its checksum field.
934        let builder = (&[0xff, 0xd9]).into_serializer().encapsulate(UdpPacketBuilder::new(
935            Ipv4Addr::new([0, 0, 0, 0]),
936            Ipv4Addr::new([0, 0, 0, 0]),
937            None,
938            NonZeroU16::new(1).unwrap(),
939        ));
940        let buf = builder.serialize_vec_outer().unwrap();
941        // The serializer has flipped the bits for us.
942        // Normally, 0xFFFF can't be checksum because -0
943        // can not be produced by adding non-negtive 16-bit
944        // words
945        assert_eq!(buf.as_ref()[7], 0xFF);
946        assert_eq!(buf.as_ref()[8], 0xFF);
947
948        // When validating the checksum, just add'em up.
949        let mut c = internet_checksum::Checksum::new();
950        c.add_bytes(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 10]);
951        c.add_bytes(buf.as_ref());
952        assert!(c.checksum() == [0, 0]);
953    }
954
955    //
956    // Benchmarks
957    //
958
959    fn bench_parse_inner<B: Bencher>(b: &mut B) {
960        use crate::testdata::dns_request_v4::*;
961        let bytes = parse_ip_packet_in_ethernet_frame::<Ipv4>(
962            ETHERNET_FRAME.bytes,
963            EthernetFrameLengthCheck::Check,
964        )
965        .unwrap()
966        .0;
967
968        b.iter(|| {
969            let buf = bytes;
970            let _: UdpPacket<_> = black_box(
971                black_box(buf)
972                    .parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(
973                        IPV4_PACKET.metadata.src_ip,
974                        IPV4_PACKET.metadata.dst_ip,
975                    ))
976                    .unwrap(),
977            );
978        })
979    }
980
981    bench!(bench_parse, bench_parse_inner);
982
983    fn bench_serialize_inner<B: Bencher>(b: &mut B) {
984        use crate::testdata::dns_request_v4::*;
985        let builder = UdpPacketBuilder::new(
986            IPV4_PACKET.metadata.src_ip,
987            IPV4_PACKET.metadata.dst_ip,
988            None,
989            NonZeroU16::new(UDP_PACKET.metadata.dst_port).unwrap(),
990        );
991        let header_len = builder.constraints().header_len();
992        let total_len = header_len + UDP_PACKET.bytes[UDP_PACKET.body_range].len();
993        let mut buf = vec![0; total_len];
994        buf[header_len..].copy_from_slice(&UDP_PACKET.bytes[UDP_PACKET.body_range]);
995
996        b.iter(|| {
997            let _: Buf<_> = black_box(
998                black_box(Buf::new(&mut buf[..], header_len..total_len).encapsulate(builder))
999                    .serialize_no_alloc_outer(),
1000            )
1001            .unwrap();
1002        })
1003    }
1004
1005    bench!(bench_serialize, bench_serialize_inner);
1006}