Skip to content
Closed
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
35 changes: 35 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
resolver = "2"

members = ["simple-dns", "simple-mdns"]
members = ["simple-dns", "simple-mdns", "simple-dns/fuzz"]

4 changes: 4 additions & 0 deletions simple-dns/fuzz/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
target
corpus
artifacts
coverage
21 changes: 21 additions & 0 deletions simple-dns/fuzz/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "simple-dns-fuzz"
version = "0.0.0"
publish = false
edition = "2021"

[package.metadata]
cargo-fuzz = true

[dependencies]
libfuzzer-sys = "0.4"

[dependencies.simple-dns]
path = ".."

[[bin]]
name = "packet_parse"
path = "fuzz_targets/packet_parse.rs"
test = false
doc = false
bench = false
18 changes: 18 additions & 0 deletions simple-dns/fuzz/fuzz_targets/packet_parse.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#![no_main]

use libfuzzer_sys::fuzz_target;

use simple_dns::Packet;

fuzz_target!(|data: &[u8]| {
// fuzzed code goes here
if let Ok(original) = Packet::parse(data) {
let compressed = original.build_bytes_vec_compressed().unwrap();

if let Ok(decompressed) = Packet::parse(&compressed) {
let encoded = decompressed.build_bytes_vec().unwrap();

assert_eq!(encoded, original.build_bytes_vec().unwrap());
}
}
});
10 changes: 8 additions & 2 deletions simple-dns/src/dns/character_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ impl<'a> TryFrom<CharacterString<'a>> for String {
}

impl<'a> WireFormat<'a> for CharacterString<'a> {
fn parse(data: &'a [u8], position: &mut usize) -> crate::Result<Self>
const MINIMUM_LEN: usize = 1;

fn parse_after_check(data: &'a [u8], position: &mut usize) -> crate::Result<Self>
where
Self: Sized,
{
Expand All @@ -57,6 +59,10 @@ impl<'a> WireFormat<'a> for CharacterString<'a> {
return Err(SimpleDnsError::InvalidCharacterString);
}

if *position + 1 + length > data.len() {
return Err(crate::SimpleDnsError::InsufficientData);
}

let data = &data[*position + 1..*position + 1 + length];
*position += length + 1;

Expand All @@ -72,7 +78,7 @@ impl<'a> WireFormat<'a> for CharacterString<'a> {
}

fn len(&self) -> usize {
self.data.len() + 1
self.data.len() + Self::MINIMUM_LEN
}
}

Expand Down
10 changes: 6 additions & 4 deletions simple-dns/src/dns/name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ impl<'a> Name<'a> {
}

/// Returns an Iter of this Name Labels
pub fn iter(&'a self) -> std::slice::Iter<Label<'a>> {
pub fn iter(&'a self) -> std::slice::Iter<'a, Label<'a>> {
self.labels.iter()
}

Expand Down Expand Up @@ -160,7 +160,9 @@ impl<'a> Name<'a> {
}

impl<'a> WireFormat<'a> for Name<'a> {
fn parse(data: &'a [u8], position: &mut usize) -> crate::Result<Self>
const MINIMUM_LEN: usize = 1;

fn parse_after_check(data: &'a [u8], position: &mut usize) -> crate::Result<Self>
where
Self: Sized,
{
Expand All @@ -173,7 +175,7 @@ impl<'a> WireFormat<'a> for Name<'a> {
let mut name_size = 0usize;

loop {
if *position >= data.len() {
if pointer_position >= data.len() {
return Err(crate::SimpleDnsError::InsufficientData);
}

Expand Down Expand Up @@ -250,7 +252,7 @@ impl<'a> WireFormat<'a> for Name<'a> {
.iter()
.map(|label| label.len() + 1)
.sum::<usize>()
+ 1
+ Self::MINIMUM_LEN
}
}

Expand Down
14 changes: 10 additions & 4 deletions simple-dns/src/dns/question.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,17 @@ impl<'a> Question<'a> {
}

impl<'a> WireFormat<'a> for Question<'a> {
const MINIMUM_LEN: usize = 4;

// Disable redundant length check.
fn parse(data: &'a [u8], position: &mut usize) -> crate::Result<Self> {
Self::parse_after_check(data, position)
}

fn parse_after_check(data: &'a [u8], position: &mut usize) -> crate::Result<Self> {
let qname = Name::parse(data, position)?;
if *position + 4 > data.len() {
return Err(crate::SimpleDnsError::InsufficientData);
}

Self::check_len(data, position)?;

let qtype = u16::from_be_bytes(data[*position..*position + 2].try_into()?);
let qclass = u16::from_be_bytes(data[*position + 2..*position + 4].try_into()?);
Expand All @@ -73,7 +79,7 @@ impl<'a> WireFormat<'a> for Question<'a> {
}

fn len(&self) -> usize {
self.qname.len() + 4
self.qname.len() + Self::MINIMUM_LEN
}

fn write_to<T: std::io::Write>(&self, out: &mut T) -> crate::Result<()> {
Expand Down
8 changes: 3 additions & 5 deletions simple-dns/src/dns/rdata/a.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ impl RR for A {
}

impl<'a> WireFormat<'a> for A {
fn parse(data: &'a [u8], position: &mut usize) -> crate::Result<Self>
const MINIMUM_LEN: usize = 4;

fn parse_after_check(data: &'a [u8], position: &mut usize) -> crate::Result<Self>
where
Self: Sized,
{
Expand All @@ -28,10 +30,6 @@ impl<'a> WireFormat<'a> for A {
out.write_all(&self.address.to_be_bytes())
.map_err(crate::SimpleDnsError::from)
}

fn len(&self) -> usize {
4
}
}

impl A {
Expand Down
8 changes: 3 additions & 5 deletions simple-dns/src/dns/rdata/aaaa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ impl RR for AAAA {
}

impl<'a> WireFormat<'a> for AAAA {
fn parse(data: &'a [u8], position: &mut usize) -> crate::Result<Self>
const MINIMUM_LEN: usize = 16;

fn parse_after_check(data: &'a [u8], position: &mut usize) -> crate::Result<Self>
where
Self: Sized,
{
Expand All @@ -24,10 +26,6 @@ impl<'a> WireFormat<'a> for AAAA {
Ok(Self { address })
}

fn len(&self) -> usize {
16
}

fn write_to<T: std::io::Write>(&self, out: &mut T) -> crate::Result<()> {
out.write_all(&self.address.to_be_bytes())
.map_err(crate::SimpleDnsError::from)
Expand Down
6 changes: 4 additions & 2 deletions simple-dns/src/dns/rdata/afsdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ impl<'a> AFSDB<'a> {
}

impl<'a> WireFormat<'a> for AFSDB<'a> {
fn parse(data: &'a [u8], position: &mut usize) -> crate::Result<Self>
const MINIMUM_LEN: usize = 2;

fn parse_after_check(data: &'a [u8], position: &mut usize) -> crate::Result<Self>
where
Self: Sized,
{
Expand All @@ -54,7 +56,7 @@ impl<'a> WireFormat<'a> for AFSDB<'a> {
}

fn len(&self) -> usize {
self.hostname.len() + 2
self.hostname.len() + Self::MINIMUM_LEN
}
}

Expand Down
6 changes: 4 additions & 2 deletions simple-dns/src/dns/rdata/caa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ impl<'a> CAA<'a> {
}

impl<'a> WireFormat<'a> for CAA<'a> {
fn parse(data: &'a [u8], position: &mut usize) -> crate::Result<Self>
const MINIMUM_LEN: usize = 1;

fn parse_after_check(data: &'a [u8], position: &mut usize) -> crate::Result<Self>
where
Self: Sized,
{
Expand All @@ -54,7 +56,7 @@ impl<'a> WireFormat<'a> for CAA<'a> {
}

fn len(&self) -> usize {
self.tag.len() + self.value.len() + 1
self.tag.len() + self.value.len() + Self::MINIMUM_LEN
}
}

Expand Down
15 changes: 6 additions & 9 deletions simple-dns/src/dns/rdata/cert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ pub struct CERT<'a> {
pub certificate: Cow<'a, [u8]>,
}


impl<'a> RR for CERT<'a> {
const TYPE_CODE: u16 = 37;
}

impl<'a> WireFormat<'a> for CERT<'a> {
fn parse(data: &'a [u8], position: &mut usize) -> crate::Result<Self>
const MINIMUM_LEN: usize = 5;

fn parse_after_check(data: &'a [u8], position: &mut usize) -> crate::Result<Self>
where
Self: Sized,
{
Expand Down Expand Up @@ -53,7 +54,7 @@ impl<'a> WireFormat<'a> for CERT<'a> {
}

fn len(&self) -> usize {
5 + self.certificate.len()
self.certificate.len() + Self::MINIMUM_LEN
}
}

Expand Down Expand Up @@ -108,12 +109,8 @@ mod tests {
assert_eq!(sample_rdata.type_code, 3);
assert_eq!(sample_rdata.key_tag, 0);
assert_eq!(sample_rdata.algorithm, 0);
assert_eq!(
*sample_rdata.certificate,
*b"\x00\x00\x00\x00\x00"
);

assert_eq!(*sample_rdata.certificate, *b"\x00\x00\x00\x00\x00");

Ok(())
}

}
9 changes: 5 additions & 4 deletions simple-dns/src/dns/rdata/dhcid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,17 @@ pub struct DHCID<'a> {
/// Digest type code
pub digest_type: u8,
/// Digest (length depends on digest type)
pub digest: Cow<'a, [u8]>
pub digest: Cow<'a, [u8]>,
}

impl<'a> RR for DHCID<'a> {
const TYPE_CODE: u16 = 49;
}

impl<'a> WireFormat<'a> for DHCID<'a> {
fn parse(data: &'a [u8], position: &mut usize) -> crate::Result<Self>
const MINIMUM_LEN: usize = 3;

fn parse_after_check(data: &'a [u8], position: &mut usize) -> crate::Result<Self>
where
Self: Sized,
{
Expand Down Expand Up @@ -48,7 +50,7 @@ impl<'a> WireFormat<'a> for DHCID<'a> {
}

fn len(&self) -> usize {
2 + 1 + self.digest.len()
self.digest.len() + Self::MINIMUM_LEN
}
}

Expand Down Expand Up @@ -101,5 +103,4 @@ mod tests {

Ok(())
}

}
Loading