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}