2017-12-16 20:58:18 +00:00
|
|
|
use bytes::Buf;
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
impl DnsName {
|
|
|
|
/// `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
|
2017-12-21 12:32:14 +00:00
|
|
|
/// `label_len`: first compressed label length (`0xc0 | offset-high, offset-low`)
|
2017-12-16 20:58:18 +00:00
|
|
|
/// `total_len`: length of (uncompressed) label encoding so far
|
|
|
|
fn parse_name_compressed_cont(data: Bytes, start_pos: usize, uncmpr_offsets: SmallVec<[u8;16]>, mut total_len: usize, mut label_len: u8) -> Result<Self> {
|
|
|
|
let mut label_offsets = uncmpr_offsets.into_iter()
|
|
|
|
.map(LabelOffset::LabelStart)
|
|
|
|
.collect::<SmallVec<_>>();
|
|
|
|
|
|
|
|
let mut pos = start_pos + total_len;
|
|
|
|
'next_compressed: loop {
|
|
|
|
{
|
2017-12-21 12:32:14 +00:00
|
|
|
ensure!(pos + 1 < data.len(), "not enough data for compressed label");
|
|
|
|
let new_pos = ((label_len as usize & 0x3f) << 8) | (data[pos + 1] as usize);
|
|
|
|
ensure!(new_pos < pos, "Compressed label offset to big");
|
2017-12-16 20:58:18 +00:00
|
|
|
pos = new_pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
loop {
|
2017-12-21 12:32:14 +00:00
|
|
|
ensure!(pos < data.len(), "not enough data for label");
|
2017-12-16 20:58:18 +00:00
|
|
|
label_len = data[pos];
|
|
|
|
|
|
|
|
if 0 == label_len {
|
|
|
|
return Ok(DnsName{
|
|
|
|
data: data,
|
|
|
|
label_offsets: LabelOffsets::Compressed(start_pos, label_offsets),
|
|
|
|
total_len: total_len as u8 + 1,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2017-12-21 12:32:14 +00:00
|
|
|
if label_len & 0xc0 == 0xc0 { continue 'next_compressed; }
|
|
|
|
ensure!(label_len < 64, "Invalid label length {}", label_len);
|
2017-12-16 20:58:18 +00:00
|
|
|
|
|
|
|
total_len += 1 + label_len as usize;
|
|
|
|
// max len 255, but there also needs to be an empty label at the end
|
|
|
|
if total_len > 254 { bail!("DNS name too long") }
|
|
|
|
|
2017-12-21 12:32:14 +00:00
|
|
|
label_offsets.push(LabelOffset::PacketStart(pos as u16));
|
2017-12-16 20:58:18 +00:00
|
|
|
pos += 1 + label_len as usize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(super) fn parse_name(data: &mut Cursor<Bytes>, accept_compressed: bool) -> Result<Self> {
|
|
|
|
check_enough_data!(data, 1, "DnsName");
|
|
|
|
let start_pos = data.position() as usize;
|
|
|
|
let mut total_len : usize = 0;
|
|
|
|
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;
|
|
|
|
return Ok(DnsName{
|
|
|
|
data: data.get_ref().slice(start_pos, end_pos),
|
|
|
|
label_offsets: LabelOffsets::Uncompressed(label_offsets),
|
|
|
|
total_len: total_len as u8 + 1,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
if label_len & 0xc0 == 0xc0 {
|
|
|
|
// compressed label
|
|
|
|
if !accept_compressed { bail!("Invalid label compression {}", label_len) }
|
2017-12-21 12:32:14 +00:00
|
|
|
check_enough_data!(data, 1, "DnsName compressed label target");
|
|
|
|
// eat second part of compressed label
|
|
|
|
data.get_u8();
|
2017-12-16 20:58:18 +00:00
|
|
|
|
|
|
|
let end_pos = data.position() as usize;
|
|
|
|
let data = data.get_ref().slice(0, end_pos);
|
|
|
|
|
|
|
|
return Self::parse_name_compressed_cont(data, start_pos, label_offsets, total_len, label_len as u8);
|
|
|
|
}
|
|
|
|
label_offsets.push(total_len as u8);
|
|
|
|
if label_len > 63 { bail!("Invalid label length {}", label_len) }
|
|
|
|
total_len += 1 + label_len;
|
|
|
|
// max len 255, but there also needs to be an empty label at the end
|
|
|
|
if total_len > 254 { bail!{"DNS name too long"} }
|
|
|
|
check_enough_data!(data, (label_len), "DnsName label");
|
|
|
|
data.advance(label_len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|