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