1use 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
36pub const HEADER_BYTES: usize = 8;
38
39pub 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; }
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; }
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; }
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
100pub struct UdpPacket<B> {
109 header: Ref<B, Header>,
110 body: B,
111}
112
113pub trait UdpParseContext {
115 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
126pub 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 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 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 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 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 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 pub fn body(&self) -> &[u8] {
225 self.body.deref()
226 }
227
228 pub fn as_bytes(&self) -> [&[u8]; 2] {
230 [&Ref::bytes(&self.header), self.body.deref()]
231 }
232
233 pub fn into_body(self) -> B {
241 self.body
242 }
243
244 pub fn src_port(&self) -> Option<NonZeroU16> {
248 NonZeroU16::new(self.header.src_port.get())
249 }
250
251 pub fn dst_port(&self) -> NonZeroU16 {
253 NonZeroU16::new(self.header.dst_port.get()).unwrap()
255 }
256
257 pub fn checksummed(&self) -> bool {
267 self.header.checksummed()
268 }
269
270 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 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 pub fn set_src_port(&mut self, new: u16) {
309 self.header.set_src_port(new)
310 }
311
312 pub fn set_dst_port(&mut self, new: NonZeroU16) {
314 self.header.set_dst_port(new);
315 }
316
317 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#[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#[derive(Debug)]
342struct PartialHeader<B: SplitByteSlice> {
343 flow: Ref<B, UdpFlowHeader>,
344 rest: B,
345}
346
347pub 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 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 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 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 let _: B = buffer.take_back(buffer_len - body_len).unwrap();
425 MaybeParsed::Complete(buffer.into_rest())
426 } else {
427 MaybeParsed::Incomplete(buffer.into_rest())
429 }
430 } else {
431 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 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 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 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 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 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 }
526 }
527 }
528
529 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 }
538 }
539 }
540
541 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 }
548 }
549 }
550}
551
552pub struct UdpEnvelope;
560
561pub trait UdpSerializationContext: SerializationContext {
563 fn envelope_to_state(envelope: UdpEnvelope) -> Self::ContextState;
565
566 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#[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 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 pub fn src_port(&self) -> Option<NonZeroU16> {
602 self.src_port
603 }
604
605 pub fn dst_port(&self) -> Option<NonZeroU16> {
607 self.dst_port
608 }
609
610 pub fn set_src_ip(&mut self, addr: A) {
612 self.src_ip = addr;
613 }
614
615 pub fn set_dst_ip(&mut self, addr: A) {
617 self.dst_ip = addr;
618 }
619
620 pub fn set_src_port(&mut self, port: u16) {
622 self.src_port = NonZeroU16::new(port);
623 }
624
625 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 let total_len = buffer.len() + body_len;
634
635 (&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 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 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 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(); 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 if *checksum_bytes == [0, 0] {
736 *checksum_bytes = [0xFF, 0xFF];
737 }
738}
739
740#[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 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 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_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 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 fn test_zero<I: IpAddress>(
911 src: I,
912 dst: I,
913 succeeds: bool,
914 zero: &[usize],
915 err: ParseError,
916 ) {
917 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 test_zero(TEST_SRC_IPV4, TEST_DST_IPV4, true, &[2, 3], ParseError::Format);
936 test_zero(TEST_SRC_IPV4, TEST_DST_IPV4, true, &[4, 5], ParseError::Format);
938 test_zero(TEST_SRC_IPV6, TEST_DST_IPV6, false, &[], ParseError::Format);
941
942 #[cfg(target_pointer_width = "64")]
944 {
945 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 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 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 let mut buf = &[0, 0, 1][..];
1037 assert!(buf.parse_with::<_, UdpPacketRaw<_>>(IpVersionMarker::<Ipv4>::default()).is_err());
1038
1039 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 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 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 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 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 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 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 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 assert_eq!(&buf.as_ref()[CHECKSUM_OFFSET..CHECKSUM_OFFSET + 2], [0xFF, 0xFF]);
1135
1136 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 packet.set_src_port(0); 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); assert_eq!(packet.header.checksum, [0xFF, 0xFF]);
1162
1163 packet.set_dst_port(DST_PORT); 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); assert_eq!(packet.header.checksum, [0xFF, 0xFF]);
1170
1171 packet.update_checksum_pseudo_header_address(ADDR, ADDR); 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); assert_eq!(packet.header.checksum, [0xFF, 0xFF]);
1179 }
1180}