1use std::borrow::Cow;
4use std::io::{Result as IoResult, Write};
5
6use byteorder_slice::byteorder::WriteBytesExt;
7use byteorder_slice::result::ReadSlice;
8use byteorder_slice::ByteOrder;
9use derive_into_owned::IntoOwned;
10
11use super::block_common::{Block, PcapNgBlock};
12use super::opt_common::{CustomBinaryOption, CustomUtf8Option, PcapNgOption, UnknownOption, WriteOptTo};
13use crate::errors::PcapError;
14
15
16#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
19pub struct NameResolutionBlock<'a> {
20 pub records: Vec<Record<'a>>,
22 pub options: Vec<NameResolutionOption<'a>>,
24}
25
26impl<'a> PcapNgBlock<'a> for NameResolutionBlock<'a> {
27 fn from_slice<B: ByteOrder>(mut slice: &'a [u8]) -> Result<(&'a [u8], Self), PcapError> {
28 let mut records = Vec::new();
29
30 loop {
31 let (slice_tmp, record) = Record::from_slice::<B>(slice)?;
32 slice = slice_tmp;
33
34 match record {
35 Record::End => break,
36 _ => records.push(record),
37 }
38 }
39
40 let (rem, options) = NameResolutionOption::opts_from_slice::<B>(slice)?;
41
42 let block = NameResolutionBlock { records, options };
43
44 Ok((rem, block))
45 }
46
47 fn write_to<B: ByteOrder, W: Write>(&self, writer: &mut W) -> IoResult<usize> {
48 let mut len = 0;
49
50 for record in &self.records {
51 len += record.write_to::<B, _>(writer)?;
52 }
53 len += Record::End.write_to::<B, _>(writer)?;
54
55 len += NameResolutionOption::write_opts_to::<B, _>(&self.options, writer)?;
56
57 Ok(len)
58 }
59
60 fn into_block(self) -> Block<'a> {
61 Block::NameResolution(self)
62 }
63}
64
65#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
67pub enum Record<'a> {
68 End,
70 Ipv4(Ipv4Record<'a>),
72 Ipv6(Ipv6Record<'a>),
74 Unknown(UnknownRecord<'a>),
76}
77
78impl<'a> Record<'a> {
79 pub fn from_slice<B: ByteOrder>(mut slice: &'a [u8]) -> Result<(&'a [u8], Self), PcapError> {
81 let type_ = slice.read_u16::<B>().map_err(|_| PcapError::IncompleteBuffer)?;
82 let length = slice.read_u16::<B>().map_err(|_| PcapError::IncompleteBuffer)?;
83 let pad_len = (4 - length % 4) % 4;
84
85 if slice.len() < length as usize {
86 return Err(PcapError::InvalidField("NameResolutionBlock: Record length > slice.len()"));
87 }
88 let value = &slice[..length as usize];
89
90 let record = match type_ {
91 0 => {
92 if length != 0 {
93 return Err(PcapError::InvalidField("NameResolutionBlock: nrb_record_end length != 0"));
94 }
95 Record::End
96 },
97
98 1 => {
99 let record = Ipv4Record::from_slice(value)?;
100 Record::Ipv4(record)
101 },
102
103 2 => {
104 let record = Ipv6Record::from_slice(value)?;
105 Record::Ipv6(record)
106 },
107
108 _ => {
109 let record = UnknownRecord::new(type_, length, value);
110 Record::Unknown(record)
111 },
112 };
113
114 let len = length as usize + pad_len as usize;
115
116 Ok((&slice[len..], record))
117 }
118
119 pub fn write_to<B: ByteOrder, W: Write>(&self, writer: &mut W) -> IoResult<usize> {
121 match self {
122 Record::End => {
123 writer.write_u16::<B>(0)?;
124 writer.write_u16::<B>(0)?;
125
126 Ok(4)
127 },
128
129 Record::Ipv4(a) => {
130 let len = a.write_to::<B, _>(&mut std::io::sink()).unwrap();
131 let pad_len = (4 - len % 4) % 4;
132
133 writer.write_u16::<B>(1)?;
134 writer.write_u16::<B>(len as u16)?;
135 a.write_to::<B, _>(writer)?;
136 writer.write_all(&[0_u8; 3][..pad_len])?;
137
138 Ok(4 + len + pad_len)
139 },
140
141 Record::Ipv6(a) => {
142 let len = a.write_to::<B, _>(&mut std::io::sink()).unwrap();
143 let pad_len = (4 - len % 4) % 4;
144
145 writer.write_u16::<B>(2)?;
146 writer.write_u16::<B>(len as u16)?;
147 a.write_to::<B, _>(writer)?;
148 writer.write_all(&[0_u8; 3][..pad_len])?;
149
150 Ok(4 + len + pad_len)
151 },
152
153 Record::Unknown(a) => {
154 let len = a.value.len();
155 let pad_len = (4 - len % 4) % 4;
156
157 writer.write_u16::<B>(a.type_)?;
158 writer.write_u16::<B>(a.length)?;
159 writer.write_all(&a.value)?;
160 writer.write_all(&[0_u8; 3][..pad_len])?;
161
162 Ok(4 + len + pad_len)
163 },
164 }
165 }
166}
167
168#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
170pub struct Ipv4Record<'a> {
171 pub ip_addr: Cow<'a, [u8]>,
173 pub names: Vec<Cow<'a, str>>,
175}
176
177impl<'a> Ipv4Record<'a> {
178 pub fn from_slice(mut slice: &'a [u8]) -> Result<Self, PcapError> {
180 if slice.len() < 6 {
181 return Err(PcapError::InvalidField("NameResolutionBlock: Ipv4Record len < 6"));
182 }
183
184 let ip_addr = &slice[..4];
185 slice = &slice[4..];
186
187 let mut names = vec![];
188 for name in slice.split(|&b| b == 0) {
189 if name.is_empty() {
190 break;
191 }
192 names.push(Cow::Borrowed(std::str::from_utf8(name)?));
193 }
194
195 if names.is_empty() {
196 return Err(PcapError::InvalidField("NameResolutionBlock: Ipv4Record without any name"));
197 }
198
199 let record = Ipv4Record { ip_addr: Cow::Borrowed(ip_addr), names };
200
201 Ok(record)
202 }
203
204 pub fn write_to<B: ByteOrder, W: Write>(&self, writer: &mut W) -> IoResult<usize> {
206 let mut len = 4;
207
208 writer.write_all(&self.ip_addr)?;
209 for name in &self.names {
210 writer.write_all(name.as_bytes())?;
211 writer.write_u8(0)?;
212
213 len += name.as_bytes().len();
214 len += 1;
215 }
216
217 Ok(len)
218 }
219}
220
221
222#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
224pub struct Ipv6Record<'a> {
225 pub ip_addr: Cow<'a, [u8]>,
227 pub names: Vec<Cow<'a, str>>,
229}
230
231impl<'a> Ipv6Record<'a> {
232 pub fn from_slice(mut slice: &'a [u8]) -> Result<Self, PcapError> {
234 if slice.len() < 18 {
235 return Err(PcapError::InvalidField("NameResolutionBlock: Ipv6Record len < 18"));
236 }
237
238 let ip_addr = &slice[..16];
239 slice = &slice[16..];
240
241 let mut names = vec![];
242 for name in slice.split(|&b| b == 0) {
243 if name.is_empty() {
244 break;
245 }
246
247 names.push(Cow::Borrowed(std::str::from_utf8(name)?));
248 }
249
250 if names.is_empty() {
251 return Err(PcapError::InvalidField("NameResolutionBlock: Ipv6Record without any name"));
252 }
253
254 let record = Ipv6Record { ip_addr: Cow::Borrowed(ip_addr), names };
255
256 Ok(record)
257 }
258
259 pub fn write_to<B: ByteOrder, W: Write>(&self, writer: &mut W) -> IoResult<usize> {
261 let mut len = 16;
262
263 writer.write_all(&self.ip_addr)?;
264 for name in &self.names {
265 writer.write_all(name.as_bytes())?;
266 writer.write_u8(0)?;
267
268 len += name.as_bytes().len();
269 len += 1;
270 }
271
272 Ok(len)
273 }
274}
275
276#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
278pub struct UnknownRecord<'a> {
279 pub type_: u16,
281 pub length: u16,
283 pub value: Cow<'a, [u8]>,
285}
286
287impl<'a> UnknownRecord<'a> {
288 fn new(type_: u16, length: u16, value: &'a [u8]) -> Self {
290 UnknownRecord { type_, length, value: Cow::Borrowed(value) }
291 }
292}
293
294
295#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
297pub enum NameResolutionOption<'a> {
298 Comment(Cow<'a, str>),
301
302 NsDnsName(Cow<'a, str>),
304
305 NsDnsIpv4Addr(Cow<'a, [u8]>),
307
308 NsDnsIpv6Addr(Cow<'a, [u8]>),
310
311 CustomBinary(CustomBinaryOption<'a>),
313
314 CustomUtf8(CustomUtf8Option<'a>),
316
317 Unknown(UnknownOption<'a>),
319}
320
321impl<'a> PcapNgOption<'a> for NameResolutionOption<'a> {
322 fn from_slice<B: ByteOrder>(code: u16, length: u16, slice: &'a [u8]) -> Result<Self, PcapError> {
323 let opt = match code {
324 1 => NameResolutionOption::Comment(Cow::Borrowed(std::str::from_utf8(slice)?)),
325 2 => NameResolutionOption::NsDnsName(Cow::Borrowed(std::str::from_utf8(slice)?)),
326 3 => {
327 if slice.len() != 4 {
328 return Err(PcapError::InvalidField("NameResolutionOption: NsDnsIpv4Addr length != 4"));
329 }
330 NameResolutionOption::NsDnsIpv4Addr(Cow::Borrowed(slice))
331 },
332 4 => {
333 if slice.len() != 16 {
334 return Err(PcapError::InvalidField("NameResolutionOption: NsDnsIpv6Addr length != 16"));
335 }
336 NameResolutionOption::NsDnsIpv6Addr(Cow::Borrowed(slice))
337 },
338
339 2988 | 19372 => NameResolutionOption::CustomUtf8(CustomUtf8Option::from_slice::<B>(code, slice)?),
340 2989 | 19373 => NameResolutionOption::CustomBinary(CustomBinaryOption::from_slice::<B>(code, slice)?),
341
342 _ => NameResolutionOption::Unknown(UnknownOption::new(code, length, slice)),
343 };
344
345 Ok(opt)
346 }
347
348 fn write_to<B: ByteOrder, W: Write>(&self, writer: &mut W) -> IoResult<usize> {
349 match self {
350 NameResolutionOption::Comment(a) => a.write_opt_to::<B, W>(1, writer),
351 NameResolutionOption::NsDnsName(a) => a.write_opt_to::<B, W>(2, writer),
352 NameResolutionOption::NsDnsIpv4Addr(a) => a.write_opt_to::<B, W>(3, writer),
353 NameResolutionOption::NsDnsIpv6Addr(a) => a.write_opt_to::<B, W>(4, writer),
354 NameResolutionOption::CustomBinary(a) => a.write_opt_to::<B, W>(a.code, writer),
355 NameResolutionOption::CustomUtf8(a) => a.write_opt_to::<B, W>(a.code, writer),
356 NameResolutionOption::Unknown(a) => a.write_opt_to::<B, W>(a.code, writer),
357 }
358 }
359}