net_parser_rs/layer4/
udp.rs

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, //src port, 50871
61        0x00u8, 0x50u8, //dst port, 80
62        0x00u8, 0x28u8, //length 40, less header length is payload of 32
63        0x00u8, 0x00u8, //checksum
64        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, //payload, 32 bytes
68    ];
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}