udp.rs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. use byteorder::{ByteOrder, NetworkEndian};
  2. use core::fmt;
  3. use super::{Error, Result};
  4. use crate::phy::ChecksumCapabilities;
  5. use crate::wire::ip::checksum;
  6. use crate::wire::{IpAddress, IpProtocol};
  7. /// A read/write wrapper around an User Datagram Protocol packet buffer.
  8. #[derive(Debug, PartialEq, Eq, Clone)]
  9. pub struct Packet<T: AsRef<[u8]>> {
  10. buffer: T,
  11. }
  12. mod field {
  13. #![allow(non_snake_case)]
  14. use crate::wire::field::*;
  15. pub const SRC_PORT: Field = 0..2;
  16. pub const DST_PORT: Field = 2..4;
  17. pub const LENGTH: Field = 4..6;
  18. pub const CHECKSUM: Field = 6..8;
  19. pub const fn PAYLOAD(length: u16) -> Field {
  20. CHECKSUM.end..(length as usize)
  21. }
  22. }
  23. pub const HEADER_LEN: usize = field::CHECKSUM.end;
  24. #[allow(clippy::len_without_is_empty)]
  25. impl<T: AsRef<[u8]>> Packet<T> {
  26. /// Imbue a raw octet buffer with UDP packet structure.
  27. pub const fn new_unchecked(buffer: T) -> Packet<T> {
  28. Packet { buffer }
  29. }
  30. /// Shorthand for a combination of [new_unchecked] and [check_len].
  31. ///
  32. /// [new_unchecked]: #method.new_unchecked
  33. /// [check_len]: #method.check_len
  34. pub fn new_checked(buffer: T) -> Result<Packet<T>> {
  35. let packet = Self::new_unchecked(buffer);
  36. packet.check_len()?;
  37. Ok(packet)
  38. }
  39. /// Ensure that no accessor method will panic if called.
  40. /// Returns `Err(Error)` if the buffer is too short.
  41. /// Returns `Err(Error)` if the length field has a value smaller
  42. /// than the header length.
  43. ///
  44. /// The result of this check is invalidated by calling [set_len].
  45. ///
  46. /// [set_len]: #method.set_len
  47. pub fn check_len(&self) -> Result<()> {
  48. let buffer_len = self.buffer.as_ref().len();
  49. if buffer_len < HEADER_LEN {
  50. Err(Error)
  51. } else {
  52. let field_len = self.len() as usize;
  53. if buffer_len < field_len || field_len < HEADER_LEN {
  54. Err(Error)
  55. } else {
  56. Ok(())
  57. }
  58. }
  59. }
  60. /// Consume the packet, returning the underlying buffer.
  61. pub fn into_inner(self) -> T {
  62. self.buffer
  63. }
  64. /// Return the source port field.
  65. #[inline]
  66. pub fn src_port(&self) -> u16 {
  67. let data = self.buffer.as_ref();
  68. NetworkEndian::read_u16(&data[field::SRC_PORT])
  69. }
  70. /// Return the destination port field.
  71. #[inline]
  72. pub fn dst_port(&self) -> u16 {
  73. let data = self.buffer.as_ref();
  74. NetworkEndian::read_u16(&data[field::DST_PORT])
  75. }
  76. /// Return the length field.
  77. #[inline]
  78. pub fn len(&self) -> u16 {
  79. let data = self.buffer.as_ref();
  80. NetworkEndian::read_u16(&data[field::LENGTH])
  81. }
  82. /// Return the checksum field.
  83. #[inline]
  84. pub fn checksum(&self) -> u16 {
  85. let data = self.buffer.as_ref();
  86. NetworkEndian::read_u16(&data[field::CHECKSUM])
  87. }
  88. /// Validate the partial packet checksum.
  89. ///
  90. /// # Panics
  91. /// This function panics unless `src_addr` and `dst_addr` belong to the same family,
  92. /// and that family is IPv4 or IPv6.
  93. ///
  94. /// # Fuzzing
  95. /// This function always returns `true` when fuzzing.
  96. pub fn verify_partial_checksum(&self, src_addr: &IpAddress, dst_addr: &IpAddress) -> bool {
  97. if cfg!(fuzzing) {
  98. return true;
  99. }
  100. checksum::pseudo_header(src_addr, dst_addr, IpProtocol::Udp, self.len() as u32)
  101. == self.checksum()
  102. }
  103. /// Validate the packet checksum.
  104. ///
  105. /// # Panics
  106. /// This function panics unless `src_addr` and `dst_addr` belong to the same family,
  107. /// and that family is IPv4 or IPv6.
  108. ///
  109. /// # Fuzzing
  110. /// This function always returns `true` when fuzzing.
  111. pub fn verify_checksum(&self, src_addr: &IpAddress, dst_addr: &IpAddress) -> bool {
  112. if cfg!(fuzzing) {
  113. return true;
  114. }
  115. // From the RFC:
  116. // > An all zero transmitted checksum value means that the transmitter
  117. // > generated no checksum (for debugging or for higher level protocols
  118. // > that don't care).
  119. if self.checksum() == 0 {
  120. return true;
  121. }
  122. let data = self.buffer.as_ref();
  123. checksum::combine(&[
  124. checksum::pseudo_header(src_addr, dst_addr, IpProtocol::Udp, self.len() as u32),
  125. checksum::data(&data[..self.len() as usize]),
  126. ]) == !0
  127. }
  128. }
  129. impl<'a, T: AsRef<[u8]> + ?Sized> Packet<&'a T> {
  130. /// Return a pointer to the payload.
  131. #[inline]
  132. pub fn payload(&self) -> &'a [u8] {
  133. let length = self.len();
  134. let data = self.buffer.as_ref();
  135. &data[field::PAYLOAD(length)]
  136. }
  137. }
  138. impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
  139. /// Set the source port field.
  140. #[inline]
  141. pub fn set_src_port(&mut self, value: u16) {
  142. let data = self.buffer.as_mut();
  143. NetworkEndian::write_u16(&mut data[field::SRC_PORT], value)
  144. }
  145. /// Set the destination port field.
  146. #[inline]
  147. pub fn set_dst_port(&mut self, value: u16) {
  148. let data = self.buffer.as_mut();
  149. NetworkEndian::write_u16(&mut data[field::DST_PORT], value)
  150. }
  151. /// Set the length field.
  152. #[inline]
  153. pub fn set_len(&mut self, value: u16) {
  154. let data = self.buffer.as_mut();
  155. NetworkEndian::write_u16(&mut data[field::LENGTH], value)
  156. }
  157. /// Set the checksum field.
  158. #[inline]
  159. pub fn set_checksum(&mut self, value: u16) {
  160. let data = self.buffer.as_mut();
  161. NetworkEndian::write_u16(&mut data[field::CHECKSUM], value)
  162. }
  163. /// Compute and fill in the header checksum.
  164. ///
  165. /// # Panics
  166. /// This function panics unless `src_addr` and `dst_addr` belong to the same family,
  167. /// and that family is IPv4 or IPv6.
  168. pub fn fill_checksum(&mut self, src_addr: &IpAddress, dst_addr: &IpAddress) {
  169. self.set_checksum(0);
  170. let checksum = {
  171. let data = self.buffer.as_ref();
  172. !checksum::combine(&[
  173. checksum::pseudo_header(src_addr, dst_addr, IpProtocol::Udp, self.len() as u32),
  174. checksum::data(&data[..self.len() as usize]),
  175. ])
  176. };
  177. // UDP checksum value of 0 means no checksum; if the checksum really is zero,
  178. // use all-ones, which indicates that the remote end must verify the checksum.
  179. // Arithmetically, RFC 1071 checksums of all-zeroes and all-ones behave identically,
  180. // so no action is necessary on the remote end.
  181. self.set_checksum(if checksum == 0 { 0xffff } else { checksum })
  182. }
  183. /// Return a mutable pointer to the payload.
  184. #[inline]
  185. pub fn payload_mut(&mut self) -> &mut [u8] {
  186. let length = self.len();
  187. let data = self.buffer.as_mut();
  188. &mut data[field::PAYLOAD(length)]
  189. }
  190. }
  191. impl<T: AsRef<[u8]>> AsRef<[u8]> for Packet<T> {
  192. fn as_ref(&self) -> &[u8] {
  193. self.buffer.as_ref()
  194. }
  195. }
  196. /// A high-level representation of an User Datagram Protocol packet.
  197. #[derive(Debug, PartialEq, Eq, Clone, Copy)]
  198. pub struct Repr {
  199. pub src_port: u16,
  200. pub dst_port: u16,
  201. }
  202. impl Repr {
  203. /// Parse an User Datagram Protocol packet and return a high-level representation.
  204. pub fn parse<T>(
  205. packet: &Packet<&T>,
  206. src_addr: &IpAddress,
  207. dst_addr: &IpAddress,
  208. checksum_caps: &ChecksumCapabilities,
  209. ) -> Result<Repr>
  210. where
  211. T: AsRef<[u8]> + ?Sized,
  212. {
  213. packet.check_len()?;
  214. // Destination port cannot be omitted (but source port can be).
  215. if packet.dst_port() == 0 {
  216. return Err(Error);
  217. }
  218. // Valid checksum is expected...
  219. if checksum_caps.udp.rx() && !packet.verify_checksum(src_addr, dst_addr) {
  220. match (src_addr, dst_addr) {
  221. // ... except on UDP-over-IPv4, where it can be omitted.
  222. #[cfg(feature = "proto-ipv4")]
  223. (&IpAddress::Ipv4(_), &IpAddress::Ipv4(_)) if packet.checksum() == 0 => (),
  224. _ => return Err(Error),
  225. }
  226. }
  227. Ok(Repr {
  228. src_port: packet.src_port(),
  229. dst_port: packet.dst_port(),
  230. })
  231. }
  232. /// Return the length of the packet header that will be emitted from this high-level representation.
  233. pub const fn header_len(&self) -> usize {
  234. HEADER_LEN
  235. }
  236. /// Emit a high-level representation into an User Datagram Protocol packet.
  237. ///
  238. /// This never calculates the checksum, and is intended for internal-use only,
  239. /// not for packets that are going to be actually sent over the network. For
  240. /// example, when decompressing 6lowpan.
  241. pub(crate) fn emit_header<T>(&self, packet: &mut Packet<&mut T>, payload_len: usize)
  242. where
  243. T: AsRef<[u8]> + AsMut<[u8]> + ?Sized,
  244. {
  245. packet.set_src_port(self.src_port);
  246. packet.set_dst_port(self.dst_port);
  247. packet.set_len((HEADER_LEN + payload_len) as u16);
  248. packet.set_checksum(0);
  249. }
  250. /// Emit a high-level representation into an User Datagram Protocol packet.
  251. pub fn emit<T>(
  252. &self,
  253. packet: &mut Packet<&mut T>,
  254. src_addr: &IpAddress,
  255. dst_addr: &IpAddress,
  256. payload_len: usize,
  257. emit_payload: impl FnOnce(&mut [u8]),
  258. checksum_caps: &ChecksumCapabilities,
  259. ) where
  260. T: AsRef<[u8]> + AsMut<[u8]> + ?Sized,
  261. {
  262. packet.set_src_port(self.src_port);
  263. packet.set_dst_port(self.dst_port);
  264. packet.set_len((HEADER_LEN + payload_len) as u16);
  265. emit_payload(packet.payload_mut());
  266. if checksum_caps.udp.tx() {
  267. packet.fill_checksum(src_addr, dst_addr)
  268. } else {
  269. // make sure we get a consistently zeroed checksum,
  270. // since implementations might rely on it
  271. packet.set_checksum(0);
  272. }
  273. }
  274. }
  275. impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Packet<&'a T> {
  276. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  277. // Cannot use Repr::parse because we don't have the IP addresses.
  278. write!(
  279. f,
  280. "UDP src={} dst={} len={}",
  281. self.src_port(),
  282. self.dst_port(),
  283. self.payload().len()
  284. )
  285. }
  286. }
  287. #[cfg(feature = "defmt")]
  288. impl<'a, T: AsRef<[u8]> + ?Sized> defmt::Format for Packet<&'a T> {
  289. fn format(&self, fmt: defmt::Formatter) {
  290. // Cannot use Repr::parse because we don't have the IP addresses.
  291. defmt::write!(
  292. fmt,
  293. "UDP src={} dst={} len={}",
  294. self.src_port(),
  295. self.dst_port(),
  296. self.payload().len()
  297. );
  298. }
  299. }
  300. impl fmt::Display for Repr {
  301. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  302. write!(f, "UDP src={} dst={}", self.src_port, self.dst_port)
  303. }
  304. }
  305. #[cfg(feature = "defmt")]
  306. impl defmt::Format for Repr {
  307. fn format(&self, fmt: defmt::Formatter) {
  308. defmt::write!(fmt, "UDP src={} dst={}", self.src_port, self.dst_port);
  309. }
  310. }
  311. use crate::wire::pretty_print::{PrettyIndent, PrettyPrint};
  312. impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
  313. fn pretty_print(
  314. buffer: &dyn AsRef<[u8]>,
  315. f: &mut fmt::Formatter,
  316. indent: &mut PrettyIndent,
  317. ) -> fmt::Result {
  318. match Packet::new_checked(buffer) {
  319. Err(err) => write!(f, "{indent}({err})"),
  320. Ok(packet) => write!(f, "{indent}{packet}"),
  321. }
  322. }
  323. }
  324. #[cfg(test)]
  325. mod test {
  326. use super::*;
  327. #[cfg(feature = "proto-ipv4")]
  328. use crate::wire::Ipv4Address;
  329. #[cfg(feature = "proto-ipv4")]
  330. const SRC_ADDR: Ipv4Address = Ipv4Address::new(192, 168, 1, 1);
  331. #[cfg(feature = "proto-ipv4")]
  332. const DST_ADDR: Ipv4Address = Ipv4Address::new(192, 168, 1, 2);
  333. #[cfg(feature = "proto-ipv4")]
  334. static PACKET_BYTES: [u8; 12] = [
  335. 0xbf, 0x00, 0x00, 0x35, 0x00, 0x0c, 0x12, 0x4d, 0xaa, 0x00, 0x00, 0xff,
  336. ];
  337. #[cfg(feature = "proto-ipv4")]
  338. static NO_CHECKSUM_PACKET: [u8; 12] = [
  339. 0xbf, 0x00, 0x00, 0x35, 0x00, 0x0c, 0x00, 0x00, 0xaa, 0x00, 0x00, 0xff,
  340. ];
  341. #[cfg(feature = "proto-ipv4")]
  342. static PAYLOAD_BYTES: [u8; 4] = [0xaa, 0x00, 0x00, 0xff];
  343. #[test]
  344. #[cfg(feature = "proto-ipv4")]
  345. fn test_deconstruct() {
  346. let packet = Packet::new_unchecked(&PACKET_BYTES[..]);
  347. assert_eq!(packet.src_port(), 48896);
  348. assert_eq!(packet.dst_port(), 53);
  349. assert_eq!(packet.len(), 12);
  350. assert_eq!(packet.checksum(), 0x124d);
  351. assert_eq!(packet.payload(), &PAYLOAD_BYTES[..]);
  352. assert!(packet.verify_checksum(&SRC_ADDR.into(), &DST_ADDR.into()));
  353. }
  354. #[test]
  355. #[cfg(feature = "proto-ipv4")]
  356. fn test_construct() {
  357. let mut bytes = vec![0xa5; 12];
  358. let mut packet = Packet::new_unchecked(&mut bytes);
  359. packet.set_src_port(48896);
  360. packet.set_dst_port(53);
  361. packet.set_len(12);
  362. packet.set_checksum(0xffff);
  363. packet.payload_mut().copy_from_slice(&PAYLOAD_BYTES[..]);
  364. packet.fill_checksum(&SRC_ADDR.into(), &DST_ADDR.into());
  365. assert_eq!(&*packet.into_inner(), &PACKET_BYTES[..]);
  366. }
  367. #[test]
  368. fn test_impossible_len() {
  369. let mut bytes = vec![0; 12];
  370. let mut packet = Packet::new_unchecked(&mut bytes);
  371. packet.set_len(4);
  372. assert_eq!(packet.check_len(), Err(Error));
  373. }
  374. #[test]
  375. #[cfg(feature = "proto-ipv4")]
  376. fn test_zero_checksum() {
  377. let mut bytes = vec![0; 8];
  378. let mut packet = Packet::new_unchecked(&mut bytes);
  379. packet.set_src_port(1);
  380. packet.set_dst_port(31881);
  381. packet.set_len(8);
  382. packet.fill_checksum(&SRC_ADDR.into(), &DST_ADDR.into());
  383. assert_eq!(packet.checksum(), 0xffff);
  384. }
  385. #[test]
  386. #[cfg(feature = "proto-ipv4")]
  387. fn test_no_checksum() {
  388. let mut bytes = vec![0; 8];
  389. let mut packet = Packet::new_unchecked(&mut bytes);
  390. packet.set_src_port(1);
  391. packet.set_dst_port(31881);
  392. packet.set_len(8);
  393. packet.set_checksum(0);
  394. assert!(packet.verify_checksum(&SRC_ADDR.into(), &DST_ADDR.into()));
  395. }
  396. #[cfg(feature = "proto-ipv4")]
  397. fn packet_repr() -> Repr {
  398. Repr {
  399. src_port: 48896,
  400. dst_port: 53,
  401. }
  402. }
  403. #[test]
  404. #[cfg(feature = "proto-ipv4")]
  405. fn test_parse() {
  406. let packet = Packet::new_unchecked(&PACKET_BYTES[..]);
  407. let repr = Repr::parse(
  408. &packet,
  409. &SRC_ADDR.into(),
  410. &DST_ADDR.into(),
  411. &ChecksumCapabilities::default(),
  412. )
  413. .unwrap();
  414. assert_eq!(repr, packet_repr());
  415. }
  416. #[test]
  417. #[cfg(feature = "proto-ipv4")]
  418. fn test_emit() {
  419. let repr = packet_repr();
  420. let mut bytes = vec![0xa5; repr.header_len() + PAYLOAD_BYTES.len()];
  421. let mut packet = Packet::new_unchecked(&mut bytes);
  422. repr.emit(
  423. &mut packet,
  424. &SRC_ADDR.into(),
  425. &DST_ADDR.into(),
  426. PAYLOAD_BYTES.len(),
  427. |payload| payload.copy_from_slice(&PAYLOAD_BYTES),
  428. &ChecksumCapabilities::default(),
  429. );
  430. assert_eq!(&*packet.into_inner(), &PACKET_BYTES[..]);
  431. }
  432. #[test]
  433. #[cfg(feature = "proto-ipv4")]
  434. fn test_checksum_omitted() {
  435. let packet = Packet::new_unchecked(&NO_CHECKSUM_PACKET[..]);
  436. let repr = Repr::parse(
  437. &packet,
  438. &SRC_ADDR.into(),
  439. &DST_ADDR.into(),
  440. &ChecksumCapabilities::default(),
  441. )
  442. .unwrap();
  443. assert_eq!(repr, packet_repr());
  444. }
  445. }