rust-dnsbox/lib/dnsbox-base/src/common_types/name/name_packet_parser.rs

113 lines
3.2 KiB
Rust
Raw Normal View History

2017-12-16 20:58:18 +00:00
use super::*;
2020-03-07 15:57:47 +00:00
use bytes::Buf;
2017-12-16 20:58:18 +00:00
2018-02-10 10:32:25 +00:00
/// `data`: bytes of packet from beginning until at least the end of the name
/// `start_pos`: position of first byte of the name
/// `uncmpr_offsets`: offsets of uncompressed labels so far
/// `label_len`: first compressed label length (`0xc0 | offset-high, offset-low`)
/// `total_len`: length of (uncompressed) label encoding so far
2020-03-07 15:57:47 +00:00
fn deserialize_name_compressed_cont(
data: Bytes,
start_pos: usize,
uncmpr_offsets: SmallVec<[u8; 16]>,
mut total_len: usize,
mut label_len: u8,
) -> Result<DnsName> {
let mut label_offsets = uncmpr_offsets
.into_iter()
.map(LabelOffset::LabelStart)
.collect::<SmallVec<_>>();
2017-12-16 20:58:18 +00:00
2018-02-10 10:32:25 +00:00
let mut pos = start_pos + total_len;
'next_compressed: loop {
{
2019-07-01 15:43:34 +00:00
failure::ensure!(pos + 1 < data.len(), "not enough data for compressed label");
2018-02-10 10:32:25 +00:00
let new_pos = ((label_len as usize & 0x3f) << 8) | (data[pos + 1] as usize);
2020-03-07 15:57:47 +00:00
failure::ensure!(
new_pos < pos,
"Compressed label offset too big: {} >= {}",
new_pos,
pos
);
2018-02-10 10:32:25 +00:00
pos = new_pos;
2017-12-16 20:58:18 +00:00
}
loop {
2019-07-01 15:43:34 +00:00
failure::ensure!(pos < data.len(), "not enough data for label");
2018-02-10 10:32:25 +00:00
label_len = data[pos];
2017-12-16 20:58:18 +00:00
if 0 == label_len {
2020-03-07 15:57:47 +00:00
return Ok(DnsName {
2018-02-10 10:32:25 +00:00
data: data,
label_offsets: LabelOffsets::Compressed(start_pos, label_offsets),
2017-12-16 20:58:18 +00:00
total_len: total_len as u8 + 1,
2020-03-07 15:57:47 +00:00
});
2017-12-16 20:58:18 +00:00
}
2020-03-07 15:57:47 +00:00
if label_len & 0xc0 == 0xc0 {
continue 'next_compressed;
}
2019-07-01 15:43:34 +00:00
failure::ensure!(label_len < 64, "Invalid label length {}", label_len);
2017-12-16 20:58:18 +00:00
2018-02-10 10:32:25 +00:00
total_len += 1 + label_len as usize;
2017-12-16 20:58:18 +00:00
// max len 255, but there also needs to be an empty label at the end
2020-03-07 15:57:47 +00:00
if total_len > 254 {
failure::bail!("DNS name too long")
}
2018-02-10 10:32:25 +00:00
label_offsets.push(LabelOffset::PacketStart(pos as u16));
pos += 1 + label_len as usize;
}
}
}
pub fn deserialize_name(data: &mut Cursor<Bytes>, accept_compressed: bool) -> Result<DnsName> {
check_enough_data!(data, 1, "DnsName");
let start_pos = data.position() as usize;
2020-03-07 15:57:47 +00:00
let mut total_len: usize = 0;
2018-02-10 10:32:25 +00:00
let mut label_offsets = SmallVec::new();
loop {
check_enough_data!(data, 1, "DnsName label len");
let label_len = data.get_u8() as usize;
if 0 == label_len {
let end_pos = data.position() as usize;
2020-03-07 15:57:47 +00:00
return Ok(DnsName {
2018-02-10 10:32:25 +00:00
data: data.get_ref().slice(start_pos, end_pos),
label_offsets: LabelOffsets::Uncompressed(label_offsets),
total_len: total_len as u8 + 1,
2020-03-07 15:57:47 +00:00
});
2018-02-10 10:32:25 +00:00
}
if label_len & 0xc0 == 0xc0 {
// compressed label
2020-03-07 15:57:47 +00:00
if !accept_compressed {
failure::bail!("Invalid label compression {}", label_len)
}
2018-02-10 10:32:25 +00:00
check_enough_data!(data, 1, "DnsName compressed label target");
// eat second part of compressed label
data.get_u8();
let end_pos = data.position() as usize;
let data = data.get_ref().slice(0, end_pos);
2020-03-07 15:57:47 +00:00
return deserialize_name_compressed_cont(
data,
start_pos,
label_offsets,
total_len,
label_len as u8,
);
2017-12-16 20:58:18 +00:00
}
2018-02-10 10:32:25 +00:00
label_offsets.push(total_len as u8);
2020-03-07 15:57:47 +00:00
if label_len > 63 {
failure::bail!("Invalid label length {}", label_len)
}
2018-02-10 10:32:25 +00:00
total_len += 1 + label_len;
// max len 255, but there also needs to be an empty label at the end
2020-03-07 15:57:47 +00:00
if total_len > 254 {
failure::bail! {"DNS name too long"}
}
2018-02-11 10:13:04 +00:00
check_enough_data!(data, label_len, "DnsName label");
2018-02-10 10:32:25 +00:00
data.advance(label_len);
2017-12-16 20:58:18 +00:00
}
}