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