net_parse/l3/
mod.rs

1use nom::{be_u8,be_u16,be_u32,rest};
2
3use {ParseOps,ConvError};
4use packet_writer::{PacketWriter,WriteFields};
5
6named!(bytes_to_ip<&[u8], IPv4Hdr>, do_parse!(
7    version_and_length: be_u8 >>
8    qos: be_u8 >>
9    pk_length: be_u16 >>
10    ident: be_u16 >>
11    flags_and_offset: be_u16 >>
12    ttl: be_u8 >>
13    proto: be_u8 >>
14    checksum: be_u16 >>
15    source_ip: be_u32 >>
16    dest_ip: be_u32 >>
17    options: take!((version_and_length & 0x0f) * 4 - 20) >>
18    (IPv4Hdr { version: (version_and_length & 0xf0) >> 4, hdr_length: (version_and_length & 0x0f),
19               dscp: (qos >> 2) & 0x3f, ecn: qos & 0x03,
20               pk_length, ident, do_not_fragment: (1 << 14) & flags_and_offset == (1 << 14),
21               more_packets: (1 << 13) & flags_and_offset == (1 << 13),
22               packet_offset: flags_and_offset & 0x1fff, ttl, proto, checksum, source_ip,
23               dest_ip, options: options.to_vec() })
24));
25named!(strip_ip<&[u8]>, do_parse!(
26    version_and_length: be_u8 >>
27    take!(((version_and_length & 0x0f) * 4) - 1) >>
28    inner_bytes: rest >>
29    (inner_bytes)
30));
31
32#[derive(Debug,PartialEq)]
33struct IPv4Hdr {
34    version: u8,
35    hdr_length: u8,
36    dscp: u8,
37    ecn: u8,
38    pk_length: u16,
39    ident: u16,
40    do_not_fragment: bool,
41    more_packets: bool,
42    packet_offset: u16,
43    ttl: u8,
44    proto: u8,
45    checksum: u16,
46    source_ip: u32,
47    dest_ip: u32,
48    options: Vec<u8>,
49}
50
51impl<'a> ParseOps<'a> for IPv4Hdr {
52    fn to_bytes(self) -> Result<Vec<u8>, ConvError> {
53        let mut pw = PacketWriter::new();
54        pw.write_u8(((self.version & 0x0f) << 4) | (self.hdr_length & 0x0f))?;
55        pw.write_u8(((self.dscp & 0x3f) << 2) | (self.ecn & 0x03))?;
56        pw.write_u16(self.pk_length)?;
57        pw.write_u16(self.ident)?;
58        let do_not_fragment_bin = if self.do_not_fragment { 1 } else { 0 };
59        let more_packets_bin = if self.more_packets { 1 } else { 0 };
60        pw.write_u16(((0x0001 & do_not_fragment_bin) << 14) | ((0x0001 & more_packets_bin) << 13)
61                     | (0x1fff & self.packet_offset))?;
62        pw.write_u8(self.ttl)?;
63        pw.write_u8(self.proto)?;
64        pw.write_u16(self.checksum)?;
65        pw.write_u32(self.source_ip)?;
66        pw.write_u32(self.dest_ip)?;
67        pw.write_bytes(self.options.as_slice())?;
68        Ok(pw.get_result())
69    }
70
71    fn from_bytes(buf: &[u8]) -> Result<Self, ConvError> {
72        match bytes_to_ip(buf) {
73            Ok((_, ip)) => Ok(ip),
74            Err(e) => {
75                Err(ConvError(
76                    format!("Failed to parse - here is the remaining output: {:?}", e)
77                ))
78            },
79        }
80    }
81
82    fn strip_header(buf: &[u8]) -> Result<&[u8], ConvError> {
83        match strip_ip(buf) {
84            Ok((_, stripped)) => Ok(stripped),
85            Err(e) => {
86                Err(ConvError(
87                    format!("Failed to parse - here is the remaining output: {:?}", e)
88                ))
89            },
90        }
91    }
92}
93
94#[cfg(test)]
95mod test {
96    use super::*;
97
98    #[test]
99    fn test_write_header() {
100        assert_eq!(IPv4Hdr { version: 4, hdr_length: 5, dscp: 0, ecn: 0, pk_length: 0,
101                             ident: 1, do_not_fragment: false, more_packets: true,
102                             packet_offset: 2, ttl: 30, proto: 1, checksum: 0xabcd,
103                             source_ip: 0xdeadbeef, dest_ip: 0xbeefdead, options: Vec::new(),
104        }.to_bytes().unwrap(), &[69, 0, 0, 0, 0, 1, 32, 2, 30, 1, 0xab, 0xcd, 0xde, 0xad,
105                                 0xbe, 0xef, 0xbe, 0xef, 0xde, 0xad])
106    }
107
108    #[test]
109    fn test_parse_header() {
110        let s = &[70, 0, 0, 0, 0, 1, 32, 2, 30, 1, 0xab, 0xcd, 0xde, 0xad,
111                  0xbe, 0xef, 0xbe, 0xef, 0xde, 0xad, 0, 0, 0, 0];
112        assert_eq!(IPv4Hdr::from_bytes(s).unwrap(),
113                   IPv4Hdr { version: 4, hdr_length: 6, dscp: 0, ecn: 0, pk_length: 0,
114                             ident: 1, do_not_fragment: false, more_packets: true,
115                             packet_offset: 2, ttl: 30, proto: 1, checksum: 0xabcd,
116                             source_ip: 0xdeadbeef, dest_ip: 0xbeefdead, options: vec![0, 0, 0, 0] });
117    }
118
119    #[test]
120    fn test_strip_header() {
121        let s = &[70, 0, 0, 0, 0, 1, 32, 2, 30, 1, 0xab, 0xcd, 0xde, 0xad,
122                  0xbe, 0xef, 0xbe, 0xef, 0xde, 0xad, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8];
123        assert_eq!(IPv4Hdr::strip_header(s).unwrap(), &[1, 2, 3, 4, 5, 6, 7, 8]);
124    }
125}