Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "dns-message-parser"
version = "0.8.0"
version = "0.9.0"
authors = ["LinkTed <[email protected]>"]
edition = "2018"
readme = "README.md"
Expand Down Expand Up @@ -28,7 +28,7 @@ hex = "0.4"
thiserror = "2"

[dev-dependencies]
criterion = "0.5"
criterion = "0.6"

[[bench]]
name = "message"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ A library to encode and decode DNS packets ([RFC1035](https://tools.ietf.org/htm
Add this to your `Cargo.toml`:
```toml
[dependencies]
dns-message-parser = "0.7.0"
dns-message-parser = "0.9.0"
```

## Example
Expand Down
12 changes: 10 additions & 2 deletions src/decode/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ impl<'a, 'b: 'a> Decoder<'a, 'b> {
}
}

pub(super) fn new_main_offset(&self, offset: usize) -> Decoder<'static, 'static> {
pub(super) fn new_main_offset(&self, offset: u16) -> Decoder<'static, 'static> {
let main = self.get_main();
Decoder {
parent: None,
bytes: main.bytes.clone(),
offset,
offset: offset as usize,
}
}

Expand All @@ -57,6 +57,14 @@ impl<'a, 'b: 'a> Decoder<'a, 'b> {
}
}

pub(super) fn remaining(&self) -> DecodeResult<usize> {
let bytes_len = self.bytes.len();
match bytes_len.checked_sub(self.offset) {
Some(remaining) => Ok(remaining),
None => Err(DecodeError::NotEnoughBytes(bytes_len, self.offset)),
}
}

pub(super) fn finished(self) -> DecodeResult<()> {
match self.is_finished()? {
true => Ok(()),
Expand Down
88 changes: 48 additions & 40 deletions src/decode/domain_name.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
decode::Decoder, domain_name::DOMAIN_NAME_MAX_RECURSION, DecodeError, DecodeResult, DomainName,
};
use std::{collections::HashSet, str::from_utf8, usize};
use std::{collections::HashSet, str::from_utf8};

const COMPRESSION_BITS: u8 = 0b1100_0000;
const COMPRESSION_BITS_REV: u8 = 0b0011_1111;
Expand All @@ -12,67 +12,75 @@ const fn is_compressed(length: u8) -> bool {
}

#[inline]
const fn get_offset(length_1: u8, length_2: u8) -> usize {
(((length_1 & COMPRESSION_BITS_REV) as usize) << 8) | length_2 as usize
const fn get_offset(length_1: u8, length_2: u8) -> u16 {
(((length_1 & COMPRESSION_BITS_REV) as u16) << 8) | length_2 as u16
}

enum DomainNameLength {
Compressed(u16),
Label(u8),
}

impl<'a, 'b: 'a> Decoder<'a, 'b> {
fn domain_name_length(&mut self) -> DecodeResult<DomainNameLength> {
let length = self.u8()?;
if is_compressed(length) {
let offset = self.u8()?;
Ok(DomainNameLength::Compressed(get_offset(length, offset)))
} else {
Ok(DomainNameLength::Label(length))
}
}

pub(super) fn domain_name(&mut self) -> DecodeResult<DomainName> {
let mut domain_name = DomainName::default();

let mut length = self.u8()?;
while length != 0 {
if is_compressed(length) {
let mut recursions = HashSet::new();
self.domain_name_recursion(&mut domain_name, &mut recursions, length)?;
return Ok(domain_name);
} else {
length = self.domain_name_label(&mut domain_name, length)?;
loop {
match self.domain_name_length()? {
DomainNameLength::Compressed(offset) => {
self.domain_name_recursion(&mut domain_name, offset)?;
return Ok(domain_name);
}
DomainNameLength::Label(0) => return Ok(domain_name),
DomainNameLength::Label(length) => {
self.domain_name_label(&mut domain_name, length)?
}
}
}
Ok(domain_name)
}

fn domain_name_label(&mut self, domain_name: &mut DomainName, length: u8) -> DecodeResult<u8> {
fn domain_name_label(&mut self, domain_name: &mut DomainName, length: u8) -> DecodeResult<()> {
let buffer = self.read(length as usize)?;
let label = from_utf8(buffer.as_ref())?;
let label = label.parse()?;
domain_name.append_label(label)?;
self.u8()
Ok(())
}

fn domain_name_recursion(
&mut self,
domain_name: &mut DomainName,
recursions: &mut HashSet<usize>,
mut length: u8,
) -> DecodeResult<()> {
let mut buffer = self.u8()?;
let mut offset = get_offset(length, buffer);
fn domain_name_recursion(&self, domain_name: &mut DomainName, offset: u16) -> DecodeResult<()> {
let mut decoder = self.new_main_offset(offset);
let mut recursions = HashSet::new();

length = decoder.u8()?;

while length != 0 {
if is_compressed(length) {
buffer = decoder.u8()?;
offset = get_offset(length, buffer);
if recursions.insert(offset) {
let recursions_len = recursions.len();
if recursions_len > DOMAIN_NAME_MAX_RECURSION {
return Err(DecodeError::MaxRecursion(recursions_len));
loop {
match decoder.domain_name_length()? {
DomainNameLength::Compressed(offset) => {
if recursions.insert(offset) {
let recursions_len = recursions.len();
if recursions_len > DOMAIN_NAME_MAX_RECURSION {
return Err(DecodeError::MaxRecursion(recursions_len));
}
} else {
return Err(DecodeError::EndlessRecursion(offset));
}
} else {
return Err(DecodeError::EndlessRecursion(offset));

decoder.offset = offset as usize;
}
DomainNameLength::Label(0) => return Ok(()),
DomainNameLength::Label(length) => {
decoder.domain_name_label(domain_name, length)?;
}
decoder.offset = offset as usize;
length = decoder.u8()?;
} else {
length = decoder.domain_name_label(domain_name, length)?;
}
}

Ok(())
}
}

Expand Down
8 changes: 6 additions & 2 deletions src/decode/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::rr::edns::CookieError;
use crate::rr::edns::{CookieError, ExtendedDNSErrorExtraTextError};
use crate::rr::{AddressError, Class, ISDNError, PSDNAddressError, TagError, Type};
use crate::{Dns, DomainName, DomainNameError, LabelError};
use hex::FromHexError;
Expand Down Expand Up @@ -69,6 +69,10 @@ pub enum DecodeError {
CookieError(#[from] CookieError),
#[error("Could not decode AddressNumber: {0}")]
EcsAddressNumber(u16),
#[error("Could not decode EcsAddressNumber: {0}")]
ExtendedDNSErrorCodes(u16),
#[error("Could not decode ExtendedDNSErrorExtraText: {0}")]
ExtendedDNSErrorExtraTextError(#[from] ExtendedDNSErrorExtraTextError),
#[error("The IPv4 Address is too big: {0}")]
EcsTooBigIpv4Address(usize),
#[error("The IPv6 Address is too big: {0}")]
Expand All @@ -90,7 +94,7 @@ pub enum DecodeError {
#[error("Could not decode the domain name, the because maximum recursion is reached: {0}")]
MaxRecursion(usize),
#[error("Could not decode the domain name, because an endless recursion was detected: {0}")]
EndlessRecursion(usize),
EndlessRecursion(u16),
#[error("The are remaining bytes, which was not parsed")]
RemainingBytes(usize, Dns),
#[error("Padding is not zero: {0}")]
Expand Down
6 changes: 5 additions & 1 deletion src/decode/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,12 @@ impl<'a, 'b: 'a> Decoder<'a, 'b> {
Ok(buffer.get_u64())
}

pub(super) fn string(&mut self) -> DecodeResult<String> {
pub(super) fn string_with_len(&mut self) -> DecodeResult<String> {
let length = self.u8()? as usize;
self.string(length)
}

pub(super) fn string(&mut self, length: usize) -> DecodeResult<String> {
let buffer = self.read(length)?;
let string = from_utf8(buffer.as_ref())?;
Ok(String::from(string))
Expand Down
5 changes: 2 additions & 3 deletions src/decode/rr/draft_ietf_dnsop_svcb_https.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,7 @@ impl<'a, 'b: 'a> Decoder<'a, 'b> {
/// Decode a single service parameter
///
/// Parameters:
/// - `service_parameter_key` - the IANA-controlled numeric identifier as defined in section
/// 14.3 of the RFC
/// - `service_parameter_key` - the IANA-controlled numeric identifier as defined in section 14.3 of the RFC
///
/// Returns:
/// - `Ok(ServiceParameter)` - if there were no issues decoding the value
Expand All @@ -72,7 +71,7 @@ impl<'a, 'b: 'a> Decoder<'a, 'b> {
1 => {
let mut alpn_ids = vec![];
while !self.is_finished()? {
alpn_ids.push(self.string()?);
alpn_ids.push(self.string_with_len()?);
}
ServiceParameter::ALPN { alpn_ids }
}
Expand Down
1 change: 1 addition & 0 deletions src/decode/rr/edns/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ mod rfc_6891;
mod rfc_7830;
mod rfc_7871;
mod rfc_7873;
mod rfc_8914;
13 changes: 8 additions & 5 deletions src/decode/rr/edns/rfc_6891.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,16 @@ impl<'a, 'b: 'a> Decoder<'b, 'b> {
fn rr_edns_option(&'a mut self) -> DecodeResult<EDNSOption> {
let edns_option_code = self.rr_edns_option_code()?;
let edns_option_length = self.u16()?;
let mut ends_option_data = self.sub(edns_option_length)?;
let mut edns_option_data = self.sub(edns_option_length)?;
let edns_option = match edns_option_code {
EDNSOptionCode::ECS => EDNSOption::ECS(ends_option_data.rr_edns_ecs()?),
EDNSOptionCode::Cookie => EDNSOption::Cookie(ends_option_data.rr_edns_cookie()?),
EDNSOptionCode::Padding => EDNSOption::Padding(ends_option_data.rr_edns_padding()?),
EDNSOptionCode::ECS => EDNSOption::ECS(edns_option_data.rr_edns_ecs()?),
EDNSOptionCode::Cookie => EDNSOption::Cookie(edns_option_data.rr_edns_cookie()?),
EDNSOptionCode::Padding => EDNSOption::Padding(edns_option_data.rr_edns_padding()?),
EDNSOptionCode::ExtendedDnsError => {
EDNSOption::ExtendedDNSErrors(edns_option_data.rr_edns_extended_dns_errors()?)
}
};
ends_option_data.finished()?;
edns_option_data.finished()?;
Ok(edns_option)
}

Expand Down
34 changes: 34 additions & 0 deletions src/decode/rr/edns/rfc_8914.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use crate::decode::Decoder;
use crate::rr::edns::{ExtendedDNSErrorCodes, ExtendedDNSErrorExtraText, ExtendedDNSErrors};
use crate::{DecodeError, DecodeResult};
use std::convert::TryFrom;

impl<'a, 'b: 'a> Decoder<'a, 'b> {
fn rr_edns_extended_dns_error_codes(&mut self) -> DecodeResult<ExtendedDNSErrorCodes> {
let buffer = self.u16()?;
match ExtendedDNSErrorCodes::try_from(buffer) {
Ok(edns_extended_dns_errors_codes) => Ok(edns_extended_dns_errors_codes),
Err(buffer) => Err(DecodeError::ExtendedDNSErrorCodes(buffer)),
}
}

fn rr_edns_extended_dns_errors_extra_text(
&mut self,
) -> DecodeResult<ExtendedDNSErrorExtraText> {
let extended_dns_errors_extra_text =
ExtendedDNSErrorExtraText::try_from(self.string(self.remaining()?)?)?;
Ok(extended_dns_errors_extra_text)
}

pub(super) fn rr_edns_extended_dns_errors(&mut self) -> DecodeResult<ExtendedDNSErrors> {
println!("AA");
let info_code = self.rr_edns_extended_dns_error_codes()?;
println!("AA");
let extra_text = self.rr_edns_extended_dns_errors_extra_text()?;
println!("AA {0}", extra_text.as_ref().is_empty());
Ok(ExtendedDNSErrors {
info_code,
extra_text,
})
}
}
6 changes: 3 additions & 3 deletions src/decode/rr/rfc_1035.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ impl<'a, 'b: 'a> Decoder<'a, 'b> {

pub(super) fn rr_hinfo(&mut self, header: Header) -> DecodeResult<HINFO> {
let class = header.get_class()?;
let cpu = self.string()?;
let os = self.string()?;
let cpu = self.string_with_len()?;
let os = self.string_with_len()?;
let hinfo = HINFO {
domain_name: header.domain_name,
ttl: header.ttl,
Expand All @@ -105,7 +105,7 @@ impl<'a, 'b: 'a> Decoder<'a, 'b> {
let class = header.get_class()?;
let mut strings = Vec::new();
while !self.is_finished()? {
strings.push(self.string()?);
strings.push(self.string_with_len()?);
}
let strings = strings.try_into().map_err(|_| DecodeError::TXTEmpty)?;
let txt = TXT {
Expand Down
6 changes: 3 additions & 3 deletions src/decode/rr/rfc_1183.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl<'a, 'b: 'a> Decoder<'a, 'b> {

pub(super) fn rr_x25(&mut self, header: Header) -> DecodeResult<X25> {
let class = header.get_class()?;
let psdn_address = self.string()?;
let psdn_address = self.string_with_len()?;
let psdn_address = PSDNAddress::try_from(psdn_address)?;

let x25 = X25 {
Expand All @@ -45,13 +45,13 @@ impl<'a, 'b: 'a> Decoder<'a, 'b> {

pub(super) fn rr_isdn(&mut self, header: Header) -> DecodeResult<ISDN> {
let class = header.get_class()?;
let isdn_address = self.string()?;
let isdn_address = self.string_with_len()?;
let isdn_address = ISDNAddress::try_from(isdn_address)?;

let sa = if self.is_finished()? {
None
} else {
let sa = self.string()?;
let sa = self.string_with_len()?;
let sa = SA::try_from(sa)?;
Some(sa)
};
Expand Down
6 changes: 3 additions & 3 deletions src/decode/rr/rfc_1712.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ impl<'a, 'b: 'a> Decoder<'a, 'b> {
let class = header.get_class()?;

// TODO String value check
let longitude = self.string()?;
let longitude = self.string_with_len()?;
let longitude_len = longitude.len();
if !(1..=256).contains(&longitude_len) {
return Err(DecodeError::GPOS);
}

let latitude = self.string()?;
let latitude = self.string_with_len()?;
let latitude_len = latitude.len();
if !(1..=256).contains(&latitude_len) {
return Err(DecodeError::GPOS);
}

let altitude = self.string()?;
let altitude = self.string_with_len()?;
let altitude_len = altitude.len();
if !(1..=256).contains(&altitude_len) {
return Err(DecodeError::GPOS);
Expand Down
2 changes: 1 addition & 1 deletion src/decode/rr/rfc_8659.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::convert::TryFrom;

impl<'a, 'b: 'a> Decoder<'a, 'b> {
fn rr_caa_tag(&mut self) -> DecodeResult<Tag> {
let tag = self.string()?;
let tag = self.string_with_len()?;
let tag = Tag::try_from(tag)?;
Ok(tag)
}
Expand Down
Loading
Loading