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
use crate::blocks::options::Options;
use crate::blocks::Block;
use crate::constants::*;
use crate::enums::*;
use crate::writer::Encodable;
use byteorder::{ByteOrder, WriteBytesExt};
use std::io;
use std::io::Write;
#[derive(Debug)]
pub struct InterfaceDescriptionBlock<'a> {
link_type: u16,
snap_len: u32,
options: &'a Options<'a>,
}
impl<'a> InterfaceDescriptionBlock<'a> {
pub fn new(
link_type: LinkType,
snap_len: u32,
options: &'a Options,
) -> InterfaceDescriptionBlock<'a> {
InterfaceDescriptionBlock {
link_type: link_type.value(),
snap_len,
options,
}
}
}
impl Block for InterfaceDescriptionBlock<'_> {
const TYPE: BlockType = BlockType::InterfaceDescription;
fn length(&self) -> u32 {
BLOCK_COMMON_LEN + 2 + 2 + 4 + self.options.length()
}
}
impl<W: Write> Encodable<W> for InterfaceDescriptionBlock<'_> {
fn encode<B: ByteOrder>(&self, w: &mut W) -> io::Result<()> {
let total_length = self.length();
w.write_u32::<B>(Self::TYPE.value())?;
w.write_u32::<B>(total_length)?;
w.write_u16::<B>(self.link_type)?;
w.write_u16::<B>(0)?;
w.write_u32::<B>(self.snap_len)?;
self.options.encode::<B>(w)?;
w.write_u32::<B>(total_length)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use byteorder::{BigEndian, LittleEndian};
use nom::IResult;
use pcapng;
#[test]
fn new_idb() {
let opts = Options::new();
let idb = InterfaceDescriptionBlock::new(LinkType::Ethernet, 1500, &opts);
let mut buf = vec![];
idb.encode::<BigEndian>(&mut buf).unwrap();
assert_eq!(&buf[12..16], &[0, 0, 0x05, 0xdc]);
let mut buf = vec![];
idb.encode::<LittleEndian>(&mut buf).unwrap();
assert_eq!(&buf[12..16], &[0xdc, 0x05, 0, 0]);
}
#[test]
fn round_trip() {
let opts = Options::new();
let idb = InterfaceDescriptionBlock::new(LinkType::Ethernet, 1500, &opts);
let mut buf = vec![];
idb.encode::<LittleEndian>(&mut buf).unwrap();
if let IResult::Done(_, blocks) = pcapng::block::parse_blocks(&buf[..]) {
for raw in blocks {
if let IResult::Done(_, block) = raw.parse() {
if let pcapng::block::Block::InterfaceDescription(parsed_idb) = block {
assert_eq!(parsed_idb.link_type, 1);
assert_eq!(parsed_idb.snap_len, 1500);
} else {
panic!()
}
} else {
panic!();
}
}
} else {
panic!();
}
}
}