pcapng/blocks/section_header.rs
1use nom::IResult;
2use nom::{le_u64, le_u32, le_u16};
3use block::RawBlock;
4use options::{parse_options, Options};
5
6pub const TY: u32 = 0x0A0D0D0A;
7
8// 0 1 2 3
9// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
10// +---------------------------------------------------------------+
11// 0 | Block Type = 0x0A0D0D0A |
12// +---------------------------------------------------------------+
13// 4 | Block Total Length |
14// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
15// 8 | Byte-Order Magic |
16// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17// 12 | Major Version | Minor Version |
18// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19// 16 | |
20// | Section Length |
21// | |
22// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
23// 24 / /
24// / Options (variable) /
25// / /
26// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
27// | Block Total Length |
28// +---------------------------------------------------------------+
29
30named!(section_header_body<&[u8],SectionHeader>,
31 do_parse!(
32 magic: le_u32
33 >> major_version: le_u16
34 >> minor_version: le_u16
35 >> _section_length: le_u64
36 >> options: opt!(complete!(parse_options))
37
38 // Can we get the blocks by virtue of knowing how much data we have left here?
39 >> ( {
40 let section_length = if _section_length == 0xFFFFFFFFFFFFFFFF {
41 SectionLength::Unspecified
42 } else {
43 SectionLength::Bytes(_section_length)
44 };
45
46 assert_eq!(magic, 0x1A2B3C4D);
47 SectionHeader {
48 ty: TY,
49 block_length: 0,
50 magic: magic,
51 major_version: major_version,
52 minor_version: minor_version,
53 section_length: section_length,
54 options: options,
55 check_length: 0,
56 } } )
57 )
58 );
59
60#[derive(PartialEq,Debug)]
61pub enum SectionLength {
62 Bytes(u64),
63 Unspecified,
64}
65
66#[derive(Debug)]
67pub struct SectionHeader<'a> {
68 pub ty: u32,
69 pub block_length: u32,
70 pub magic: u32,
71 pub major_version: u16,
72 pub minor_version: u16,
73 pub section_length: SectionLength,
74 pub options: Option<Options<'a>>,
75 pub check_length: u32,
76}
77
78pub fn parse(blk: RawBlock) -> IResult<&[u8], SectionHeader> {
79 // TODO(richo) Actually parse out the options afterward
80 // I think that we can do this by invoking an options parser, and using the fact that we're
81 // dealing with slices by this point to our advantage
82 match section_header_body(blk.body) {
83 // FIXME(richo) actually do something with the leftover bytes
84 IResult::Done(left, mut block) => {
85 block.block_length = blk.block_length;
86 block.check_length = blk.check_length;
87 IResult::Done(left, block)
88 }
89 IResult::Error(e) => IResult::Error(e),
90 IResult::Incomplete(e) => IResult::Incomplete(e),
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use nom::IResult;
97
98 use super::*;
99 use block::parse_block;
100 use blocks::constants::BlockType;
101
102 #[test]
103 fn test_parse_section_header() {
104 let input = b"\n\r\r\n\x1c\x00\x00\x00M<+\x1a\x01\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x1c\x00\x00\x00";
105 match parse_block(input) {
106 IResult::Done(_, block) => {
107 if let IResult::Done(left, section_header) = parse(block) {
108
109 // Ignored because we do not currently parse the whole block
110 assert_eq!(left, b"");
111 assert_eq!(section_header.ty, BlockType::SectionHeader as u32);
112 assert_eq!(section_header.block_length, 28);
113 assert_eq!(section_header.magic, 0x1A2B3C4D);
114 assert_eq!(section_header.section_length, SectionLength::Unspecified);
115 assert!(section_header.options.is_none());
116 assert_eq!(section_header.check_length, 28);
117 }
118 }
119 _ => {
120 assert!(false);
121 }
122 }
123 }
124}