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    /// 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        self.builder(src_ip, dst_ip)
242            .wrap_body(ByteSliceInnerPacketBuilder(self.body).into_serializer())
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| builder.wrap_body(ByteSliceInnerPacketBuilder(body).into_serializer()))
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    fn serialize_header(&self, body_len: usize, mut buffer: &mut [u8]) {
543        // See for details: https://en.wikipedia.org/wiki/User_Datagram_Protocol#Packet_structure
544
545        let total_len = buffer.len() + body_len;
546
547        // `write_obj_front` consumes the extent of the receiving slice, but
548        // that behavior is undesirable here: at the end of this method, we
549        // write the checksum back into the header. To avoid this, we re-slice
550        // header before calling `write_obj_front`; the re-slice will be
551        // consumed, but `target.header` is unaffected.
552        (&mut buffer)
553            .write_obj_front(&Header {
554                src_port: U16::new(self.src_port.map_or(0, NonZeroU16::get)),
555                dst_port: U16::new(self.dst_port.map_or(0, NonZeroU16::get)),
556                length: U16::new(total_len.try_into().unwrap_or_else(|_| {
557                    if A::Version::VERSION.is_v6() {
558                        // See comment in `constraints()`.
559                        0u16
560                    } else {
561                        panic!(
562                            "total UDP packet length of {total_len} bytes \
563                            overflows 16-bit length field of UDP header"
564                        )
565                    }
566                })),
567                // Initialize the checksum to 0 so that we will get the correct
568                // value when we compute it below.
569                checksum: [0, 0],
570            })
571            .expect("too few bytes for UDP header");
572    }
573}
574
575impl<A: IpAddress> PacketBuilder for UdpPacketBuilder<A> {
576    fn constraints(&self) -> PacketConstraints {
577        PacketConstraints::new(
578            HEADER_BYTES,
579            0,
580            0,
581            if A::Version::VERSION.is_v4() {
582                (1 << 16) - 1
583            } else {
584                // IPv6 supports jumbograms, so a UDP packet may be greater than
585                // 2^16 bytes. In this case, the size doesn't fit in the 16-bit
586                // length field in the header, and so the length field is set to
587                // zero. That means that, from this packet's perspective,
588                // there's no effective limit on the body size.
589                core::usize::MAX
590            },
591        )
592    }
593
594    fn serialize(&self, target: &mut SerializeTarget<'_>, body: FragmentedBytesMut<'_, '_>) {
595        self.serialize_header(body.len(), target.header);
596
597        let mut checksum = compute_transport_checksum_serialize(
598            self.src_ip,
599            self.dst_ip,
600            IpProto::Udp.into(),
601            target,
602            body,
603        )
604        .unwrap(); // Not expected to fail since we were able to serialize the packet.
605
606        if checksum == [0, 0] {
607            checksum = [0xFF, 0xFF];
608        }
609        target.header[CHECKSUM_RANGE].copy_from_slice(&checksum[..]);
610    }
611}
612
613impl<A: IpAddress> PartialPacketBuilder for UdpPacketBuilder<A> {
614    fn partial_serialize(&self, body_len: usize, buffer: &mut [u8]) {
615        self.serialize_header(body_len, buffer);
616    }
617}
618
619// needed by Result::unwrap_err in the tests below
620#[cfg(test)]
621impl<B> Debug for UdpPacket<B> {
622    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
623        write!(fmt, "UdpPacket")
624    }
625}
626
627#[cfg(test)]
628mod tests {
629    use byteorder::{ByteOrder, NetworkEndian};
630    use net_types::ip::{Ipv4, Ipv4Addr, Ipv6, Ipv6Addr};
631    use packet::{Buf, ParseBuffer};
632
633    use super::*;
634    use crate::ethernet::{EthernetFrame, EthernetFrameLengthCheck};
635    use crate::ipv4::{Ipv4Header, Ipv4Packet};
636    use crate::ipv6::{Ipv6Header, Ipv6Packet};
637    use crate::testutil::benchmarks::{black_box, Bencher};
638    use crate::testutil::*;
639
640    const TEST_SRC_IPV4: Ipv4Addr = Ipv4Addr::new([1, 2, 3, 4]);
641    const TEST_DST_IPV4: Ipv4Addr = Ipv4Addr::new([5, 6, 7, 8]);
642    const TEST_SRC_IPV6: Ipv6Addr =
643        Ipv6Addr::from_bytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
644    const TEST_DST_IPV6: Ipv6Addr =
645        Ipv6Addr::from_bytes([17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]);
646
647    #[test]
648    fn test_parse_serialize_full_ipv4() {
649        use crate::testdata::dns_request_v4::*;
650
651        let mut buf = ETHERNET_FRAME.bytes;
652        let frame = buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
653        verify_ethernet_frame(&frame, ETHERNET_FRAME);
654
655        let mut body = frame.body();
656        let ip_packet = body.parse::<Ipv4Packet<_>>().unwrap();
657        verify_ipv4_packet(&ip_packet, IPV4_PACKET);
658
659        let mut body = ip_packet.body();
660        let udp_packet = body
661            .parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(
662                ip_packet.src_ip(),
663                ip_packet.dst_ip(),
664            ))
665            .unwrap();
666        verify_udp_packet(&udp_packet, UDP_PACKET);
667
668        let buffer = udp_packet
669            .body()
670            .into_serializer()
671            .wrap_in(udp_packet.builder(ip_packet.src_ip(), ip_packet.dst_ip()))
672            .wrap_in(ip_packet.builder())
673            .wrap_in(frame.builder())
674            .serialize_vec_outer()
675            .unwrap();
676        assert_eq!(buffer.as_ref(), ETHERNET_FRAME.bytes);
677    }
678
679    #[test]
680    fn test_parse_serialize_full_ipv6() {
681        use crate::testdata::dns_request_v6::*;
682
683        let mut buf = ETHERNET_FRAME.bytes;
684        let frame = buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
685        verify_ethernet_frame(&frame, ETHERNET_FRAME);
686
687        let mut body = frame.body();
688        let ip_packet = body.parse::<Ipv6Packet<_>>().unwrap();
689        verify_ipv6_packet(&ip_packet, IPV6_PACKET);
690
691        let mut body = ip_packet.body();
692        let udp_packet = body
693            .parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(
694                ip_packet.src_ip(),
695                ip_packet.dst_ip(),
696            ))
697            .unwrap();
698        verify_udp_packet(&udp_packet, UDP_PACKET);
699
700        let buffer = udp_packet
701            .body()
702            .into_serializer()
703            .wrap_in(udp_packet.builder(ip_packet.src_ip(), ip_packet.dst_ip()))
704            .wrap_in(ip_packet.builder())
705            .wrap_in(frame.builder())
706            .serialize_vec_outer()
707            .unwrap();
708        assert_eq!(buffer.as_ref(), ETHERNET_FRAME.bytes);
709    }
710
711    #[test]
712    fn test_parse() {
713        // source port of 0 (meaning none) is allowed, as is a missing checksum
714        let mut buf = &[0, 0, 1, 2, 0, 8, 0, 0][..];
715        let packet = buf
716            .parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(TEST_SRC_IPV4, TEST_DST_IPV4))
717            .unwrap();
718        assert!(packet.src_port().is_none());
719        assert_eq!(packet.dst_port().get(), NetworkEndian::read_u16(&[1, 2]));
720        assert!(!packet.checksummed());
721        assert!(packet.body().is_empty());
722
723        // length of 0 is allowed in IPv6 if the body is long enough
724        let mut buf = vec![0_u8, 0, 1, 2, 0, 0, 0xBF, 0x12];
725        buf.extend((0..core::u16::MAX).into_iter().map(|p| p as u8));
726        let bv = &mut &buf[..];
727        let packet = bv
728            .parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(TEST_SRC_IPV6, TEST_DST_IPV6))
729            .unwrap();
730        assert!(packet.src_port().is_none());
731        assert_eq!(packet.dst_port().get(), NetworkEndian::read_u16(&[1, 2]));
732        assert!(packet.checksummed());
733        assert_eq!(packet.body().len(), core::u16::MAX as usize);
734    }
735
736    fn new_test_udp_builder() -> UdpPacketBuilder<Ipv4Addr> {
737        UdpPacketBuilder::new(
738            TEST_SRC_IPV4,
739            TEST_DST_IPV4,
740            NonZeroU16::new(1),
741            NonZeroU16::new(2).unwrap(),
742        )
743    }
744
745    #[test]
746    fn test_serialize() {
747        let mut buf = new_test_udp_builder().wrap_body(EmptyBuf).serialize_vec_outer().unwrap();
748        assert_eq!(buf.as_ref(), [0, 1, 0, 2, 0, 8, 239, 199]);
749        let packet = buf
750            .parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(TEST_SRC_IPV4, TEST_DST_IPV4))
751            .unwrap();
752        // assert that when we parse those bytes, we get the values we set in
753        // the builder
754        assert_eq!(packet.src_port().unwrap().get(), 1);
755        assert_eq!(packet.dst_port().get(), 2);
756        assert!(packet.checksummed());
757    }
758
759    #[test]
760    fn test_serialize_zeroes() {
761        // Test that UdpPacket::serialize properly zeroes memory before serializing
762        // the header.
763        let mut buf_0 = [0; HEADER_BYTES];
764        let _: Buf<&mut [u8]> = new_test_udp_builder()
765            .wrap_body(Buf::new(&mut buf_0[..], HEADER_BYTES..))
766            .serialize_vec_outer()
767            .unwrap()
768            .unwrap_a();
769        let mut buf_1 = [0xFF; HEADER_BYTES];
770        let _: Buf<&mut [u8]> = new_test_udp_builder()
771            .wrap_body(Buf::new(&mut buf_1[..], HEADER_BYTES..))
772            .serialize_vec_outer()
773            .unwrap()
774            .unwrap_a();
775        assert_eq!(buf_0, buf_1);
776    }
777
778    #[test]
779    fn test_parse_error() {
780        // Test that while a given byte pattern optionally succeeds, zeroing out
781        // certain bytes causes failure. `zero` is a list of byte indices to
782        // zero out that should cause failure.
783        fn test_zero<I: IpAddress>(
784            src: I,
785            dst: I,
786            succeeds: bool,
787            zero: &[usize],
788            err: ParseError,
789        ) {
790            // Set checksum to zero so that, in IPV4, it will be ignored. In
791            // IPv6, this /is/ the test.
792            let mut buf = [1, 2, 3, 4, 0, 8, 0, 0];
793            if succeeds {
794                let mut buf = &buf[..];
795                assert!(buf.parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(src, dst)).is_ok());
796            }
797            for idx in zero {
798                buf[*idx] = 0;
799            }
800            let mut buf = &buf[..];
801            assert_eq!(
802                buf.parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(src, dst)).unwrap_err(),
803                err
804            );
805        }
806
807        // destination port of 0 is disallowed
808        test_zero(TEST_SRC_IPV4, TEST_DST_IPV4, true, &[2, 3], ParseError::Format);
809        // length of 0 is disallowed in IPv4
810        test_zero(TEST_SRC_IPV4, TEST_DST_IPV4, true, &[4, 5], ParseError::Format);
811        // missing checksum is disallowed in IPv6; this won't succeed ahead of
812        // time because the checksum bytes are already zero
813        test_zero(TEST_SRC_IPV6, TEST_DST_IPV6, false, &[], ParseError::Format);
814
815        // 2^32 overflows on 32-bit platforms
816        #[cfg(target_pointer_width = "64")]
817        {
818            // total length of 2^32 or greater is disallowed in IPv6
819            let mut buf = vec![0u8; 1 << 32];
820            (&mut buf[..HEADER_BYTES]).copy_from_slice(&[0, 0, 1, 2, 0, 0, 0xFF, 0xE4]);
821            assert_eq!(
822                (&buf[..])
823                    .parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(TEST_SRC_IPV6, TEST_DST_IPV6))
824                    .unwrap_err(),
825                ParseError::Format
826            );
827        }
828    }
829
830    #[test]
831    #[should_panic(expected = "too few bytes for UDP header")]
832    fn test_serialize_fail_header_too_short() {
833        let mut buf = [0u8; 7];
834        let mut buf = [&mut buf[..]];
835        let buf = FragmentedBytesMut::new(&mut buf[..]);
836        let (header, body, footer) = buf.try_split_contiguous(..).unwrap();
837        let builder =
838            UdpPacketBuilder::new(TEST_SRC_IPV4, TEST_DST_IPV4, None, NonZeroU16::new(1).unwrap());
839        builder.serialize(&mut SerializeTarget { header, footer }, body);
840    }
841
842    #[test]
843    #[should_panic(expected = "total UDP packet length of 65536 bytes overflows 16-bit length \
844                               field of UDP header")]
845    fn test_serialize_fail_packet_too_long_ipv4() {
846        let ser =
847            UdpPacketBuilder::new(TEST_SRC_IPV4, TEST_DST_IPV4, None, NonZeroU16::new(1).unwrap())
848                .wrap_body((&[0; (1 << 16) - HEADER_BYTES][..]).into_serializer());
849        let _ = ser.serialize_vec_outer();
850    }
851
852    #[test]
853    fn test_partial_parse() {
854        use core::ops::Deref as _;
855
856        // Try to get something with only the flow header:
857        let buf = [0, 0, 1, 2, 10, 20];
858        let mut bv = &buf[..];
859        let packet =
860            bv.parse_with::<_, UdpPacketRaw<_>>(IpVersionMarker::<Ipv4>::default()).unwrap();
861        let UdpPacketRaw { header, body } = &packet;
862        let PartialHeader { flow, rest } = header.as_ref().incomplete().unwrap();
863        assert_eq!(
864            flow.deref(),
865            &UdpFlowHeader { src_port: U16::new(0), dst_port: U16::new(0x0102) }
866        );
867        assert_eq!(*rest, &buf[4..]);
868        assert_eq!(body.incomplete().unwrap(), []);
869        assert!(UdpPacket::try_from_raw_with(
870            packet,
871            UdpParseArgs::new(TEST_SRC_IPV4, TEST_DST_IPV4)
872        )
873        .is_err());
874
875        // check that we fail if flow header is not retrievable:
876        let mut buf = &[0, 0, 1][..];
877        assert!(buf.parse_with::<_, UdpPacketRaw<_>>(IpVersionMarker::<Ipv4>::default()).is_err());
878
879        // Get an incomplete body:
880        let buf = [0, 0, 1, 2, 0, 30, 0, 0, 10, 20];
881        let mut bv = &buf[..];
882        let packet =
883            bv.parse_with::<_, UdpPacketRaw<_>>(IpVersionMarker::<Ipv4>::default()).unwrap();
884        let UdpPacketRaw { header, body } = &packet;
885        assert_eq!(Ref::bytes(&header.as_ref().complete().unwrap()), &buf[..8]);
886        assert_eq!(body.incomplete().unwrap(), &buf[8..]);
887        assert!(UdpPacket::try_from_raw_with(
888            packet,
889            UdpParseArgs::new(TEST_SRC_IPV4, TEST_DST_IPV4)
890        )
891        .is_err());
892
893        // Incomplete empty body if total length in header is less than 8:
894        let buf = [0, 0, 1, 2, 0, 6, 0, 0, 10, 20];
895        let mut bv = &buf[..];
896        let packet =
897            bv.parse_with::<_, UdpPacketRaw<_>>(IpVersionMarker::<Ipv4>::default()).unwrap();
898        let UdpPacketRaw { header, body } = &packet;
899        assert_eq!(Ref::bytes(&header.as_ref().complete().unwrap()), &buf[..8]);
900        assert_eq!(body.incomplete().unwrap(), []);
901        assert!(UdpPacket::try_from_raw_with(
902            packet,
903            UdpParseArgs::new(TEST_SRC_IPV4, TEST_DST_IPV4)
904        )
905        .is_err());
906
907        // IPv6 allows zero-length body, which will just be the rest of the
908        // buffer, but only as long as it has more than 65535 bytes, otherwise
909        // it'll just be interpreted as an invalid length:
910        let buf = [0, 0, 1, 2, 0, 0, 0, 0, 10, 20];
911        let mut bv = &buf[..];
912        let packet =
913            bv.parse_with::<_, UdpPacketRaw<_>>(IpVersionMarker::<Ipv6>::default()).unwrap();
914        let UdpPacketRaw { header, body } = &packet;
915        assert_eq!(Ref::bytes(&header.as_ref().complete().unwrap()), &buf[..8]);
916        assert_eq!(body.incomplete().unwrap(), []);
917        // Now try same thing but with a body that's actually big enough to
918        // justify len being 0.
919        let mut buf = vec![0, 0, 1, 2, 0, 0, 0, 0, 10, 20];
920        buf.extend((0..core::u16::MAX).into_iter().map(|x| x as u8));
921        let bv = &mut &buf[..];
922        let packet =
923            bv.parse_with::<_, UdpPacketRaw<_>>(IpVersionMarker::<Ipv6>::default()).unwrap();
924        let UdpPacketRaw { header, body } = &packet;
925        assert_eq!(Ref::bytes(header.as_ref().complete().unwrap()), &buf[..8]);
926        assert_eq!(body.complete().unwrap(), &buf[8..]);
927    }
928
929    #[test]
930    fn test_udp_checksum_0xffff() {
931        // Test the behavior when a UDP packet has to  flip its checksum field.
932        let serializer = UdpPacketBuilder::new(
933            Ipv4Addr::new([0, 0, 0, 0]),
934            Ipv4Addr::new([0, 0, 0, 0]),
935            None,
936            NonZeroU16::new(1).unwrap(),
937        )
938        .wrap_body((&[0xff, 0xd9]).into_serializer());
939        let buf = serializer.serialize_vec_outer().unwrap();
940        // The serializer has flipped the bits for us.
941        // Normally, 0xFFFF can't be checksum because -0
942        // can not be produced by adding non-negtive 16-bit
943        // words
944        assert_eq!(buf.as_ref()[7], 0xFF);
945        assert_eq!(buf.as_ref()[8], 0xFF);
946
947        // When validating the checksum, just add'em up.
948        let mut c = internet_checksum::Checksum::new();
949        c.add_bytes(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 10]);
950        c.add_bytes(buf.as_ref());
951        assert!(c.checksum() == [0, 0]);
952    }
953
954    //
955    // Benchmarks
956    //
957
958    fn bench_parse_inner<B: Bencher>(b: &mut B) {
959        use crate::testdata::dns_request_v4::*;
960        let bytes = parse_ip_packet_in_ethernet_frame::<Ipv4>(
961            ETHERNET_FRAME.bytes,
962            EthernetFrameLengthCheck::Check,
963        )
964        .unwrap()
965        .0;
966
967        b.iter(|| {
968            let buf = bytes;
969            let _: UdpPacket<_> = black_box(
970                black_box(buf)
971                    .parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(
972                        IPV4_PACKET.metadata.src_ip,
973                        IPV4_PACKET.metadata.dst_ip,
974                    ))
975                    .unwrap(),
976            );
977        })
978    }
979
980    bench!(bench_parse, bench_parse_inner);
981
982    fn bench_serialize_inner<B: Bencher>(b: &mut B) {
983        use crate::testdata::dns_request_v4::*;
984        let builder = UdpPacketBuilder::new(
985            IPV4_PACKET.metadata.src_ip,
986            IPV4_PACKET.metadata.dst_ip,
987            None,
988            NonZeroU16::new(UDP_PACKET.metadata.dst_port).unwrap(),
989        );
990        let header_len = builder.constraints().header_len();
991        let total_len = header_len + UDP_PACKET.bytes[UDP_PACKET.body_range].len();
992        let mut buf = vec![0; total_len];
993        buf[header_len..].copy_from_slice(&UDP_PACKET.bytes[UDP_PACKET.body_range]);
994
995        b.iter(|| {
996            let _: Buf<_> = black_box(
997                black_box(builder.wrap_body(Buf::new(&mut buf[..], header_len..total_len)))
998                    .serialize_no_alloc_outer(),
999            )
1000            .unwrap();
1001        })
1002    }
1003
1004    bench!(bench_serialize, bench_serialize_inner);
1005}