Skip to main content

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