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