1use crate::ip::{self, IPProtocol};
4use nom::bits;
5use nom::bytes;
6use nom::error::Error;
7use nom::number;
8use nom::sequence;
9use nom::IResult;
10use std::convert::TryFrom;
11use std::net::Ipv4Addr;
12
13#[derive(Clone, Copy, Debug, PartialEq, Eq)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15pub struct IPv4Header {
16 pub version: u8,
17 pub ihl: u8,
18 pub tos: u8,
19 pub length: u16,
20 pub id: u16,
21 pub flags: u8,
22 pub fragment_offset: u16,
23 pub ttl: u8,
24 pub protocol: IPProtocol,
25 pub chksum: u16,
26 pub source_addr: Ipv4Addr,
27 pub dest_addr: Ipv4Addr,
28}
29
30fn flag_frag_offset(input: &[u8]) -> IResult<&[u8], (u8, u16)> {
31 bits::bits::<_, _, Error<_>, _, _>(sequence::pair(
32 bits::streaming::take(3u8),
33 bits::streaming::take(13u16),
34 ))(input)
35}
36
37pub(crate) fn address(input: &[u8]) -> IResult<&[u8], Ipv4Addr> {
38 let (input, ipv4) = bytes::streaming::take(4u8)(input)?;
39
40 Ok((input, Ipv4Addr::from(<[u8; 4]>::try_from(ipv4).unwrap())))
41}
42
43pub fn parse_ipv4_header(input: &[u8]) -> IResult<&[u8], IPv4Header> {
44 let (input, verihl) = ip::two_nibbles(input)?;
45 let (input, tos) = number::streaming::be_u8(input)?;
46 let (input, length) = number::streaming::be_u16(input)?;
47 let (input, id) = number::streaming::be_u16(input)?;
48 let (input, flag_frag_offset) = flag_frag_offset(input)?;
49 let (input, ttl) = number::streaming::be_u8(input)?;
50 let (input, protocol) = ip::protocol(input)?;
51 let (input, chksum) = number::streaming::be_u16(input)?;
52 let (input, source_addr) = address(input)?;
53 let (input, dest_addr) = address(input)?;
54
55 Ok((
56 input,
57 IPv4Header {
58 version: verihl.0,
59 ihl: verihl.1,
60 tos,
61 length,
62 id,
63 flags: flag_frag_offset.0,
64 fragment_offset: flag_frag_offset.1,
65 ttl,
66 protocol,
67 chksum,
68 source_addr,
69 dest_addr,
70 },
71 ))
72}
73
74#[cfg(test)]
75mod tests {
76 use super::{ip::protocol, parse_ipv4_header, IPProtocol, IPv4Header};
77 use std::net::Ipv4Addr;
78
79 const EMPTY_SLICE: &'static [u8] = &[];
80 macro_rules! mk_protocol_test {
81 ($func_name:ident, $bytes:expr, $correct_proto:expr) => {
82 #[test]
83 fn $func_name() {
84 let bytes = $bytes;
85 assert_eq!(protocol(&bytes), Ok((EMPTY_SLICE, $correct_proto)));
86 }
87 };
88 }
89
90 mk_protocol_test!(protocol_gets_icmp_correct, [1], IPProtocol::ICMP);
91 mk_protocol_test!(protocol_gets_tcp_correct, [6], IPProtocol::TCP);
92 mk_protocol_test!(protocol_gets_udp_correct, [17], IPProtocol::UDP);
93
94 #[test]
95 fn ipparse_gets_packet_correct() {
96 let bytes = [
97 0x45, 0x00, 0x05, 0xdc, 0x1a, 0xe6, 0x20, 0x00, 0x40, 0x01, 0x22, 0xed, 0x0a, 0x0a, 0x01, 0x87, 0x0a, 0x0a, 0x01, 0xb4, ];
108
109 let expectation = IPv4Header {
110 version: 4,
111 ihl: 5,
112 tos: 0,
113 length: 1500,
114 id: 0x1ae6,
115 flags: 0x01,
116 fragment_offset: 0,
117 ttl: 64,
118 protocol: IPProtocol::ICMP,
119 chksum: 0x22ed,
120 source_addr: Ipv4Addr::new(10, 10, 1, 135),
121 dest_addr: Ipv4Addr::new(10, 10, 1, 180),
122 };
123 assert_eq!(parse_ipv4_header(&bytes), Ok((EMPTY_SLICE, expectation)));
124 }
125}