1use crate::Error;
2use byteorder::{BigEndian as BE, WriteBytesExt};
3use log::*;
4use nom::*;
5use std::mem::size_of;
6use std::io::{Cursor, Write};
7
8const HEADER_LENGTH: usize = 4 * std::mem::size_of::<u16>();
9
10#[derive(Clone, Copy, Debug)]
11pub struct Udp<'a> {
12 pub src_port: u16,
13 pub dst_port: u16,
14 pub checksum: u16,
15 pub payload: &'a [u8],
16}
17
18impl<'a> Udp<'a> {
19 pub fn as_bytes(&self) -> Vec<u8> {
20 let inner = Vec::with_capacity(
21 size_of::<u16>() * 3
22 + self.payload.len()
23 );
24 let mut writer = Cursor::new(inner);
25 writer.write_u16::<BE>(self.src_port).unwrap();
26 writer.write_u16::<BE>(self.dst_port).unwrap();
27 writer.write_u16::<BE>((self.payload.len() + HEADER_LENGTH) as _).unwrap();
28 writer.write_u16::<BE>(self.checksum).unwrap();
29 writer.write(self.payload).unwrap();
30 writer.into_inner()
31 }
32
33 pub fn parse<'b>(input: &'b [u8]) -> Result<(&'b [u8], Udp<'b>), Error> {
34 trace!("Available={}", input.len());
35
36 do_parse!(
37 input,
38 src_port: be_u16
39 >> dst_port: be_u16
40 >> length: map!(be_u16, |s| (s as usize) - HEADER_LENGTH)
41 >> checksum: be_u16
42 >> payload: take!(length)
43 >> (Udp {
44 src_port,
45 dst_port,
46 checksum,
47 payload
48 })
49 ).map_err(Error::from)
50 }
51}
52
53#[cfg(test)]
54pub mod tests {
55 use hex_slice::AsHex;
56
57 use super::*;
58
59 pub const RAW_DATA: &'static [u8] = &[
60 0xC6u8, 0xB7u8, 0x00u8, 0x50u8, 0x00u8, 0x28u8, 0x00u8, 0x00u8, 0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8,
65 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8,
66 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0xfcu8, 0xfdu8, 0xfeu8,
67 0xffu8, ];
69
70 #[test]
71 fn parse_udp() {
72 let _ = env_logger::try_init();
73
74 let (rem, l4) = Udp::parse(RAW_DATA).expect("Unable to parse");
75
76 assert!(rem.is_empty());
77
78 assert_eq!(l4.src_port, 50871);
79 assert_eq!(l4.dst_port, 80);
80 assert_eq!(
81 l4.payload,
82 [
83 0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8,
84 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8,
85 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0xfcu8, 0xfdu8,
86 0xfeu8, 0xffu8
87 ],
88 "Payload Mismatch: {:x}",
89 l4.payload.as_hex()
90 );
91
92 assert_eq!(l4.as_bytes().as_slice(), RAW_DATA);
93 }
94}