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}