use crate::detect::EnumString;
use crate::dns::dns::*;
use nom7::combinator::rest;
use nom7::error::ErrorKind;
use nom7::multi::{count, length_data};
use nom7::number::streaming::{be_u16, be_u32, be_u8};
use nom7::{error_position, Err, IResult};
static MAX_NAME_LEN: usize = 1025;
fn dns_parse_name<'b>(
start: &'b [u8], message: &'b [u8], parse_flags: &mut DNSNameFlags,
) -> IResult<&'b [u8], DNSName> {
let mut pos = start;
let mut pivot = start;
let mut name: Vec<u8> = Vec::with_capacity(32);
let mut count = 0;
let mut flags = DNSNameFlags::default();
loop {
if pos.is_empty() {
break;
}
let len = pos[0];
if len == 0x00 {
pos = &pos[1..];
break;
} else if len & 0b1100_0000 == 0 {
let (rem, label) = length_data(be_u8)(pos)?;
if !flags.contains(DNSNameFlags::TRUNCATED) {
if !name.is_empty() {
name.push(b'.');
}
name.extend(label);
}
pos = rem;
} else if len & 0b1100_0000 == 0b1100_0000 {
let (rem, leader) = be_u16(pos)?;
let offset = usize::from(leader) & 0x3fff;
if offset > message.len() {
return Err(Err::Error(error_position!(pos, ErrorKind::OctDigit)));
}
if &message[offset..] == pos {
flags.insert(DNSNameFlags::INFINITE_LOOP);
if pivot != start {
break;
}
return Err(Err::Error(error_position!(pos, ErrorKind::OctDigit)));
}
pos = &message[offset..];
if pivot == start {
pivot = rem;
}
} else {
return Err(Err::Error(error_position!(pos, ErrorKind::OctDigit)));
}
count += 1;
if count > 255 {
flags.insert(DNSNameFlags::LABEL_LIMIT);
if pivot != start {
flags.insert(DNSNameFlags::TRUNCATED);
break;
}
return Err(Err::Error(error_position!(pos, ErrorKind::OctDigit)));
}
if name.len() > MAX_NAME_LEN {
name.truncate(MAX_NAME_LEN);
flags.insert(DNSNameFlags::TRUNCATED);
if pivot != start {
break;
}
}
}
parse_flags.insert(flags);
if pivot != start {
Ok((pivot, DNSName { value: name, flags }))
} else {
Ok((pos, DNSName { value: name, flags }))
}
}
fn dns_parse_answer<'a>(
slice: &'a [u8], message: &'a [u8], count: usize, flags: &mut DNSNameFlags,
) -> IResult<&'a [u8], Vec<DNSAnswerEntry>> {
let mut answers = Vec::new();
let mut input = slice;
struct Answer<'a> {
name: DNSName,
rrtype: u16,
rrclass: u16,
ttl: u32,
data: &'a [u8],
}
fn subparser<'a>(
i: &'a [u8], message: &'a [u8], flags: &mut DNSNameFlags,
) -> IResult<&'a [u8], Answer<'a>> {
let (i, name) = dns_parse_name(i, message, flags)?;
let (i, rrtype) = be_u16(i)?;
let (i, rrclass) = be_u16(i)?;
let (i, ttl) = be_u32(i)?;
let (i, data) = length_data(be_u16)(i)?;
let answer = Answer {
name,
rrtype,
rrclass,
ttl,
data,
};
Ok((i, answer))
}
for _ in 0..count {
match subparser(input, message, flags) {
Ok((rem, val)) => {
if val.data.is_empty() && val.rrtype == DNSRecordType::OPT as u16 {
answers.push(DNSAnswerEntry {
name: val.name.clone(),
rrtype: val.rrtype,
rrclass: val.rrclass,
ttl: val.ttl,
data: DNSRData::OPT(Vec::new()),
});
input = rem;
continue;
}
let (_, rdata) = dns_parse_rdata(val.data, message, val.rrtype, flags)?;
answers.push(DNSAnswerEntry {
name: val.name.clone(),
rrtype: val.rrtype,
rrclass: val.rrclass,
ttl: val.ttl,
data: rdata,
});
input = rem;
}
Err(e) => {
return Err(e);
}
}
}
return Ok((input, answers));
}
fn dns_parse_query<'a>(
input: &'a [u8], message: &'a [u8], flags: &mut DNSNameFlags,
) -> IResult<&'a [u8], DNSQueryEntry> {
let i = input;
let (i, name) = dns_parse_name(i, message, flags)?;
let (i, rrtype) = be_u16(i)?;
let (i, rrclass) = be_u16(i)?;
Ok((
i,
DNSQueryEntry {
name,
rrtype,
rrclass,
},
))
}
fn dns_parse_rdata_a(input: &[u8]) -> IResult<&[u8], DNSRData> {
rest(input).map(|(input, data)| (input, DNSRData::A(data.to_vec())))
}
fn dns_parse_rdata_aaaa(input: &[u8]) -> IResult<&[u8], DNSRData> {
rest(input).map(|(input, data)| (input, DNSRData::AAAA(data.to_vec())))
}
fn dns_parse_rdata_cname<'a>(
input: &'a [u8], message: &'a [u8], flags: &mut DNSNameFlags,
) -> IResult<&'a [u8], DNSRData> {
dns_parse_name(input, message, flags).map(|(input, name)| (input, DNSRData::CNAME(name)))
}
fn dns_parse_rdata_ns<'a>(
input: &'a [u8], message: &'a [u8], flags: &mut DNSNameFlags,
) -> IResult<&'a [u8], DNSRData> {
dns_parse_name(input, message, flags).map(|(input, name)| (input, DNSRData::NS(name)))
}
fn dns_parse_rdata_ptr<'a>(
input: &'a [u8], message: &'a [u8], flags: &mut DNSNameFlags,
) -> IResult<&'a [u8], DNSRData> {
dns_parse_name(input, message, flags).map(|(input, name)| (input, DNSRData::PTR(name)))
}
fn dns_parse_rdata_soa<'a>(
input: &'a [u8], message: &'a [u8], flags: &mut DNSNameFlags,
) -> IResult<&'a [u8], DNSRData> {
let i = input;
let (i, mname) = dns_parse_name(i, message, flags)?;
let (i, rname) = dns_parse_name(i, message, flags)?;
let (i, serial) = be_u32(i)?;
let (i, refresh) = be_u32(i)?;
let (i, retry) = be_u32(i)?;
let (i, expire) = be_u32(i)?;
let (i, minimum) = be_u32(i)?;
Ok((
i,
DNSRData::SOA(DNSRDataSOA {
mname,
rname,
serial,
refresh,
retry,
expire,
minimum,
}),
))
}
fn dns_parse_rdata_mx<'a>(
input: &'a [u8], message: &'a [u8], flags: &mut DNSNameFlags,
) -> IResult<&'a [u8], DNSRData> {
let (i, _) = be_u16(input)?;
let (i, name) = dns_parse_name(i, message, flags)?;
Ok((i, DNSRData::MX(name)))
}
fn dns_parse_rdata_srv<'a>(
input: &'a [u8], message: &'a [u8], flags: &mut DNSNameFlags,
) -> IResult<&'a [u8], DNSRData> {
let i = input;
let (i, priority) = be_u16(i)?;
let (i, weight) = be_u16(i)?;
let (i, port) = be_u16(i)?;
let (i, target) = dns_parse_name(i, message, flags)?;
Ok((
i,
DNSRData::SRV(DNSRDataSRV {
priority,
weight,
port,
target,
}),
))
}
fn dns_parse_rdata_txt(input: &[u8]) -> IResult<&[u8], DNSRData> {
let mut txt_strings = Vec::new();
let mut i = input;
while !i.is_empty() {
let (j, txt) = length_data(be_u8)(i)?;
txt_strings.push(txt.to_vec());
i = j;
}
Ok((i, DNSRData::TXT(txt_strings)))
}
fn dns_parse_rdata_null(input: &[u8]) -> IResult<&[u8], DNSRData> {
rest(input).map(|(input, data)| (input, DNSRData::NULL(data.to_vec())))
}
fn dns_parse_rdata_sshfp(input: &[u8]) -> IResult<&[u8], DNSRData> {
let i = input;
let (i, algo) = be_u8(i)?;
let (i, fp_type) = be_u8(i)?;
let fingerprint = i;
Ok((
&[],
DNSRData::SSHFP(DNSRDataSSHFP {
algo,
fp_type,
fingerprint: fingerprint.to_vec(),
}),
))
}
fn dns_parse_rdata_opt(input: &[u8]) -> IResult<&[u8], DNSRData> {
let mut dns_rdata_opt_vec = Vec::new();
let mut i = input;
while !i.is_empty() {
let (j, code) = be_u16(i)?;
let (j, data) = length_data(be_u16)(j)?;
i = j;
dns_rdata_opt_vec.push(DNSRDataOPT {
code,
data: data.to_vec(),
});
}
Ok((i, DNSRData::OPT(dns_rdata_opt_vec)))
}
fn dns_parse_rdata_unknown(input: &[u8]) -> IResult<&[u8], DNSRData> {
rest(input).map(|(input, data)| (input, DNSRData::Unknown(data.to_vec())))
}
fn dns_parse_rdata<'a>(
input: &'a [u8], message: &'a [u8], rrtype: u16, flags: &mut DNSNameFlags,
) -> IResult<&'a [u8], DNSRData> {
match DNSRecordType::from_u(rrtype) {
Some(DNSRecordType::A) => dns_parse_rdata_a(input),
Some(DNSRecordType::AAAA) => dns_parse_rdata_aaaa(input),
Some(DNSRecordType::CNAME) => dns_parse_rdata_cname(input, message, flags),
Some(DNSRecordType::PTR) => dns_parse_rdata_ptr(input, message, flags),
Some(DNSRecordType::SOA) => dns_parse_rdata_soa(input, message, flags),
Some(DNSRecordType::MX) => dns_parse_rdata_mx(input, message, flags),
Some(DNSRecordType::NS) => dns_parse_rdata_ns(input, message, flags),
Some(DNSRecordType::TXT) => dns_parse_rdata_txt(input),
Some(DNSRecordType::NULL) => dns_parse_rdata_null(input),
Some(DNSRecordType::SSHFP) => dns_parse_rdata_sshfp(input),
Some(DNSRecordType::SRV) => dns_parse_rdata_srv(input, message, flags),
Some(DNSRecordType::OPT) => dns_parse_rdata_opt(input),
_ => dns_parse_rdata_unknown(input),
}
}
pub fn dns_parse_header(i: &[u8]) -> IResult<&[u8], DNSHeader> {
let (i, tx_id) = be_u16(i)?;
let (i, flags) = be_u16(i)?;
let (i, questions) = be_u16(i)?;
let (i, answer_rr) = be_u16(i)?;
let (i, authority_rr) = be_u16(i)?;
let (i, additional_rr) = be_u16(i)?;
Ok((
i,
DNSHeader {
tx_id,
flags,
questions,
answer_rr,
authority_rr,
additional_rr,
},
))
}
pub fn dns_parse_body<'a>(
i: &'a [u8], message: &'a [u8], header: DNSHeader,
) -> IResult<&'a [u8], (DNSMessage, DNSNameFlags)> {
let mut flags = DNSNameFlags::default();
let (i, queries) = count(
|b| dns_parse_query(b, message, &mut flags),
header.questions as usize,
)(i)?;
let (i, answers) = dns_parse_answer(i, message, header.answer_rr as usize, &mut flags)?;
let mut invalid_authorities = false;
let mut authorities = Vec::new();
let mut i_next = i;
let authorities_parsed = dns_parse_answer(i, message, header.authority_rr as usize, &mut flags);
if let Ok((i, authorities_ok)) = authorities_parsed {
authorities = authorities_ok;
i_next = i;
} else {
invalid_authorities = true;
}
let mut invalid_additionals = false;
let mut additionals = Vec::new();
if !invalid_authorities {
let additionals_parsed =
dns_parse_answer(i_next, message, header.additional_rr as usize, &mut flags);
if let Ok((i, additionals_ok)) = additionals_parsed {
additionals = additionals_ok;
i_next = i;
} else {
invalid_additionals = true;
}
}
Ok((
i_next,
(
DNSMessage {
header,
queries,
answers,
authorities,
invalid_authorities,
additionals,
invalid_additionals,
},
flags,
),
))
}
#[cfg(test)]
mod tests {
use crate::dns::dns::{DNSAnswerEntry, DNSHeader};
use crate::dns::parser::*;
#[test]
fn test_dns_parse_name() {
let buf: &[u8] = &[
0x09, 0x63,
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2d, 0x63, 0x66,
0x07, 0x64, 0x72, 0x6f, 0x70, 0x62, 0x6f, 0x78,
0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00,
];
let expected_remainder: &[u8] = &[0x00, 0x01, 0x00];
let mut flags = DNSNameFlags::default();
let (remainder, name) = dns_parse_name(buf, buf, &mut flags).unwrap();
assert_eq!("client-cf.dropbox.com".as_bytes(), &name.value[..]);
assert_eq!(remainder, expected_remainder);
}
#[test]
fn test_dns_parse_name_with_pointer() {
let buf: &[u8] = &[
0xd8, 0xcb, 0x8a, 0xed, 0xa1, 0x46, 0x00, 0x15,
0x17, 0x0d, 0x06, 0xf7, 0x08, 0x00, 0x45, 0x00,
0x00, 0x7b, 0x71, 0x6e, 0x00, 0x00, 0x39, 0x11,
0xf4, 0xd9, 0x08, 0x08, 0x08, 0x08, 0x0a, 0x10,
0x01, 0x0b, 0x00, 0x35, 0xe1, 0x8e, 0x00, 0x67,
0x60, 0x00, 0xef, 0x08, 0x81, 0x80, 0x00, 0x01,
0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x03, 0x77,
0x77, 0x77, 0x0c, 0x73, 0x75, 0x72, 0x69, 0x63,
0x61, 0x74, 0x61, 0x2d, 0x69, 0x64, 0x73, 0x03,
0x6f, 0x72, 0x67, 0x00, 0x00, 0x01, 0x00, 0x01,
0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00,
0x0e, 0x0f, 0x00, 0x02, 0xc0, 0x10, 0xc0, 0x10,
0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x2b,
0x00, 0x04, 0xc0, 0x00, 0x4e, 0x19, 0xc0, 0x10,
0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x2b,
0x00, 0x04, 0xc0, 0x00, 0x4e, 0x18, 0x00, 0x00,
0x29, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
];
let message = &buf[42..];
let start1 = &buf[54..];
let mut flags = DNSNameFlags::default();
let res1 = dns_parse_name(start1, message, &mut flags);
assert_eq!(
res1,
Ok((
&start1[22..],
DNSName {
value: "www.suricata-ids.org".as_bytes().to_vec(),
flags: DNSNameFlags::default(),
}
))
);
let start2 = &buf[80..];
let mut flags = DNSNameFlags::default();
let res2 = dns_parse_name(start2, message, &mut flags);
assert_eq!(
res2,
Ok((
&start2[2..],
DNSName {
value: "www.suricata-ids.org".as_bytes().to_vec(),
flags: DNSNameFlags::default()
}
))
);
let start3 = &buf[94..];
let mut flags = DNSNameFlags::default();
let res3 = dns_parse_name(start3, message, &mut flags);
assert_eq!(
res3,
Ok((
&start3[2..],
DNSName {
value: "suricata-ids.org".as_bytes().to_vec(),
flags: DNSNameFlags::default()
}
))
);
let start4 = &buf[110..];
let mut flags = DNSNameFlags::default();
let res4 = dns_parse_name(start4, message, &mut flags);
assert_eq!(
res4,
Ok((
&start4[2..],
DNSName {
value: "suricata-ids.org".as_bytes().to_vec(),
flags: DNSNameFlags::default()
}
))
);
}
#[test]
fn test_dns_parse_name_double_pointer() {
let buf: &[u8] = &[
0xd8, 0xcb, 0x8a, 0xed, 0xa1, 0x46, 0x00, 0x15,
0x17, 0x0d, 0x06, 0xf7, 0x08, 0x00, 0x45, 0x00,
0x00, 0x66, 0x5e, 0x20, 0x40, 0x00, 0x40, 0x11,
0xc6, 0x3b, 0x0a, 0x10, 0x01, 0x01, 0x0a, 0x10,
0x01, 0x0b, 0x00, 0x35, 0xc2, 0x21, 0x00, 0x52,
0x35, 0xc5, 0x0d, 0x4f, 0x81, 0x80, 0x00, 0x01,
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x05, 0x62,
0x6c, 0x6f, 0x63, 0x6b, 0x07, 0x64, 0x72, 0x6f,
0x70, 0x62, 0x6f, 0x78, 0x03, 0x63, 0x6f, 0x6d,
0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00,
0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00,
0x0b, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x02,
0x67, 0x31, 0xc0, 0x12, 0xc0, 0x2f, 0x00, 0x01,
0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04,
0x2d, 0x3a, 0x46, 0x21,
];
let message: &[u8] = &buf[42..];
let start: &[u8] = &buf[100..];
let mut flags = DNSNameFlags::default();
let res = dns_parse_name(start, message, &mut flags);
assert_eq!(
res,
Ok((
&start[2..],
DNSName {
value: "block.g1.dropbox.com".as_bytes().to_vec(),
flags: DNSNameFlags::default()
}
))
);
}
#[test]
fn test_dns_parse_request() {
let pkt: &[u8] = &[
0x8d, 0x32, 0x01, 0x20, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x77,
0x77, 0x77, 0x0c, 0x73, 0x75, 0x72, 0x69, 0x63,
0x61, 0x74, 0x61, 0x2d, 0x69, 0x64, 0x73, 0x03,
0x6f, 0x72, 0x67, 0x00, 0x00, 0x01, 0x00, 0x01,
0x00, 0x00, 0x29, 0x10, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00,
];
let (body, header) = dns_parse_header(pkt).unwrap();
let res = dns_parse_body(body, pkt, header);
let (rem, (request, _flags)) = res.unwrap();
assert!(rem.is_empty());
assert_eq!(
request.header,
DNSHeader {
tx_id: 0x8d32,
flags: 0x0120,
questions: 1,
answer_rr: 0,
authority_rr: 0,
additional_rr: 1,
}
);
assert_eq!(request.queries.len(), 1);
let query = &request.queries[0];
assert_eq!(query.name.value, "www.suricata-ids.org".as_bytes().to_vec());
assert_eq!(query.rrtype, 1);
assert_eq!(query.rrclass, 1);
assert_eq!(request.additionals.len(), 1);
let additional = &request.additionals[0];
assert_eq!(
additional,
&DNSAnswerEntry {
name: DNSName {
value: vec![],
flags: DNSNameFlags::default()
},
rrtype: DNSRecordType::OPT as u16,
rrclass: 0x1000, ttl: 0, data: DNSRData::OPT(vec![]), }
);
}
#[test]
fn test_dns_parse_request_multi_opt() {
let pkt: &[u8] = &[
0x8d, 0x32, 0x01, 0x20, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x77,
0x77, 0x77, 0x0c, 0x73, 0x75, 0x72, 0x69, 0x63,
0x61, 0x74, 0x61, 0x2d, 0x69, 0x64, 0x73, 0x03,
0x6f, 0x72, 0x67, 0x00, 0x00, 0x01, 0x00, 0x01,
0x00, 0x00, 0x29, 0x10, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x10,
0x00, 0x0a,
0x00, 0x08,
0x7f, 0x86, 0xcf, 0x8b, 0x81, 0xf6, 0xf9, 0x55,
0x00, 0x03,
0x00, 0x00,
];
let (body, header) = dns_parse_header(pkt).unwrap();
let res = dns_parse_body(body, pkt, header);
let (rem, (request, _flags)) = res.unwrap();
assert!(rem.is_empty());
assert_eq!(
request.header,
DNSHeader {
tx_id: 0x8d32,
flags: 0x0120,
questions: 1,
answer_rr: 0,
authority_rr: 0,
additional_rr: 1,
}
);
assert_eq!(request.queries.len(), 1);
let query = &request.queries[0];
assert_eq!(query.name.value, "www.suricata-ids.org".as_bytes().to_vec());
assert_eq!(query.rrtype, 1);
assert_eq!(query.rrclass, 1);
assert_eq!(request.additionals.len(), 1);
let additional = &request.additionals[0];
assert_eq!(
additional,
&DNSAnswerEntry {
name: DNSName {
value: vec![],
flags: DNSNameFlags::default()
},
rrtype: DNSRecordType::OPT as u16,
rrclass: 0x1000, ttl: 0, data: DNSRData::OPT(vec![
DNSRDataOPT {
code: 0x000a,
data: vec![0x7f, 0x86, 0xcf, 0x8b, 0x81, 0xf6, 0xf9, 0x55]
},
DNSRDataOPT {
code: 0x0003,
data: vec![]
},
])
}
);
}
fn dns_parse_response(message: &[u8]) -> IResult<&[u8], (DNSMessage, DNSNameFlags)> {
let i = message;
let (i, header) = dns_parse_header(i)?;
dns_parse_body(i, message, header)
}
#[test]
fn test_dns_parse_response() {
let pkt: &[u8] = &[
0x8d, 0x32, 0x81, 0xa0, 0x00, 0x01,
0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x77,
0x77, 0x77, 0x0c, 0x73, 0x75, 0x72, 0x69, 0x63,
0x61, 0x74, 0x61, 0x2d, 0x69, 0x64, 0x73, 0x03,
0x6f, 0x72, 0x67, 0x00, 0x00, 0x01, 0x00, 0x01,
0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00,
0x0d, 0xd8, 0x00, 0x12, 0x0c, 0x73, 0x75, 0x72,
0x69, 0x63, 0x61, 0x74, 0x61, 0x2d, 0x69, 0x64,
0x73, 0x03, 0x6f, 0x72, 0x67, 0x00, 0xc0, 0x32,
0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xf4,
0x00, 0x04, 0xc0, 0x00, 0x4e, 0x18, 0xc0, 0x32,
0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xf4,
0x00, 0x04, 0xc0, 0x00, 0x4e, 0x19,
];
let (rem, (response, _flags)) = dns_parse_response(pkt).unwrap();
assert_eq!(rem.len(), 0);
assert_eq!(
response.header,
DNSHeader {
tx_id: 0x8d32,
flags: 0x81a0,
questions: 1,
answer_rr: 3,
authority_rr: 0,
additional_rr: 0,
}
);
assert_eq!(response.answers.len(), 3);
let answer1 = &response.answers[0];
assert_eq!(
answer1.name.value,
"www.suricata-ids.org".as_bytes().to_vec()
);
assert_eq!(answer1.rrtype, 5);
assert_eq!(answer1.rrclass, 1);
assert_eq!(answer1.ttl, 3544);
assert_eq!(
answer1.data,
DNSRData::CNAME(DNSName {
value: "suricata-ids.org".as_bytes().to_vec(),
flags: DNSNameFlags::default()
})
);
let answer2 = &response.answers[1];
assert_eq!(
answer2,
&DNSAnswerEntry {
name: DNSName {
value: "suricata-ids.org".as_bytes().to_vec(),
flags: DNSNameFlags::default()
},
rrtype: 1,
rrclass: 1,
ttl: 244,
data: DNSRData::A([192, 0, 78, 24].to_vec()),
}
);
let answer3 = &response.answers[2];
assert_eq!(
answer3,
&DNSAnswerEntry {
name: DNSName {
value: "suricata-ids.org".as_bytes().to_vec(),
flags: DNSNameFlags::default()
},
rrtype: 1,
rrclass: 1,
ttl: 244,
data: DNSRData::A([192, 0, 78, 25].to_vec()),
}
)
}
#[test]
fn test_dns_parse_response_nxdomain_soa() {
let pkt: &[u8] = &[
0x82, 0x95, 0x81, 0x83, 0x00, 0x01,
0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x03, 0x64,
0x6e, 0x65, 0x04, 0x6f, 0x69, 0x73, 0x66, 0x03,
0x6e, 0x65, 0x74, 0x00, 0x00, 0x01, 0x00, 0x01,
0xc0, 0x10, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00,
0x03, 0x83, 0x00, 0x45, 0x06, 0x6e, 0x73, 0x2d,
0x31, 0x31, 0x30, 0x09, 0x61, 0x77, 0x73, 0x64,
0x6e, 0x73, 0x2d, 0x31, 0x33, 0x03, 0x63, 0x6f,
0x6d, 0x00, 0x11, 0x61, 0x77, 0x73, 0x64, 0x6e,
0x73, 0x2d, 0x68, 0x6f, 0x73, 0x74, 0x6d, 0x61,
0x73, 0x74, 0x65, 0x72, 0x06, 0x61, 0x6d, 0x61,
0x7a, 0x6f, 0x6e, 0xc0, 0x3b, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x1c, 0x20, 0x00, 0x00, 0x03,
0x84, 0x00, 0x12, 0x75, 0x00, 0x00, 0x01, 0x51,
0x80, 0x00, 0x00, 0x29, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
];
let (rem, (response, _flags)) = dns_parse_response(pkt).unwrap();
assert!(rem.is_empty());
assert_eq!(
response.header,
DNSHeader {
tx_id: 0x8295,
flags: 0x8183,
questions: 1,
answer_rr: 0,
authority_rr: 1,
additional_rr: 1,
}
);
assert_eq!(response.authorities.len(), 1);
let authority = &response.authorities[0];
assert_eq!(authority.name.value, "oisf.net".as_bytes().to_vec());
assert_eq!(authority.rrtype, 6);
assert_eq!(authority.rrclass, 1);
assert_eq!(authority.ttl, 899);
assert_eq!(
authority.data,
DNSRData::SOA(DNSRDataSOA {
mname: DNSName {
value: "ns-110.awsdns-13.com".as_bytes().to_vec(),
flags: DNSNameFlags::default()
},
rname: DNSName {
value: "awsdns-hostmaster.amazon.com".as_bytes().to_vec(),
flags: DNSNameFlags::default()
},
serial: 1,
refresh: 7200,
retry: 900,
expire: 1209600,
minimum: 86400,
})
);
assert_eq!(response.additionals.len(), 1);
let additional = &response.additionals[0];
assert_eq!(
additional,
&DNSAnswerEntry {
name: DNSName {
value: vec![],
flags: DNSNameFlags::default()
},
rrtype: DNSRecordType::OPT as u16,
rrclass: 0x0200, ttl: 0, data: DNSRData::OPT(vec![]), }
);
}
#[test]
fn test_dns_parse_response_null() {
let pkt: &[u8] = &[
0x12, 0xb0, 0x84, 0x00, 0x00, 0x01, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x0b, 0x76, 0x61, 0x61,
0x61, 0x61, 0x6b, 0x61, 0x72, 0x64, 0x6c, 0x69,
0x06, 0x70, 0x69, 0x72, 0x61, 0x74, 0x65, 0x03,
0x73, 0x65, 0x61, 0x00, 0x00, 0x0a, 0x00, 0x01,
0xc0, 0x0c, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x09, 0x56, 0x41, 0x43, 0x4b,
0x44, 0x03, 0xc5, 0xe9, 0x01,
];
let (rem, (response, _flags)) = dns_parse_response(pkt).unwrap();
assert_eq!(rem.len(), 0);
assert_eq!(
response.header,
DNSHeader {
tx_id: 0x12b0,
flags: 0x8400,
questions: 1,
answer_rr: 1,
authority_rr: 0,
additional_rr: 0,
}
);
assert_eq!(response.queries.len(), 1);
let query = &response.queries[0];
assert_eq!(
query.name.value,
"vaaaakardli.pirate.sea".as_bytes().to_vec()
);
assert_eq!(query.rrtype, DNSRecordType::NULL as u16);
assert_eq!(query.rrclass, 1);
assert_eq!(response.answers.len(), 1);
let answer = &response.answers[0];
assert_eq!(
answer.name.value,
"vaaaakardli.pirate.sea".as_bytes().to_vec()
);
assert_eq!(answer.rrtype, DNSRecordType::NULL as u16);
assert_eq!(answer.rrclass, 1);
assert_eq!(answer.ttl, 0);
assert_eq!(
answer.data,
DNSRData::NULL(vec![
0x56, 0x41, 0x43, 0x4b,
0x44, 0x03, 0xc5, 0xe9, 0x01,
])
);
}
#[test]
fn test_dns_parse_rdata_sshfp() {
let data: &[u8] = &[
0x02, 0x01, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf6, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78,
0x9a, 0xbc, 0xde, 0xf6, 0x78, 0x90,
];
let (rem, rdata) = dns_parse_rdata_sshfp(data).unwrap();
assert_eq!(rem.len(), 0);
if let DNSRData::SSHFP(sshfp) = rdata {
assert_eq!(sshfp.algo, 2);
assert_eq!(sshfp.fp_type, 1);
assert_eq!(sshfp.fingerprint, &data[2..]);
} else {
panic!("Expected DNSRData::SSHFP");
}
}
#[test]
fn test_dns_parse_rdata_srv() {
let pkt: &[u8] = &[
0xeb, 0x56, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5f,
0x73, 0x69, 0x70, 0x04, 0x5f, 0x75, 0x64, 0x70, 0x03, 0x73, 0x69, 0x70, 0x05, 0x76,
0x6f, 0x69, 0x63, 0x65, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f,
0x6d, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00,
0x01, 0x13, 0x00, 0x26, 0x00, 0x14, 0x00, 0x01, 0x13, 0xc4, 0x0d, 0x73, 0x69, 0x70,
0x2d, 0x61, 0x6e, 0x79, 0x63, 0x61, 0x73, 0x74, 0x2d, 0x32, 0x05, 0x76, 0x6f, 0x69,
0x63, 0x65, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00,
0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x01, 0x13, 0x00, 0x26, 0x00, 0x0a,
0x00, 0x01, 0x13, 0xc4, 0x0d, 0x73, 0x69, 0x70, 0x2d, 0x61, 0x6e, 0x79, 0x63, 0x61,
0x73, 0x74, 0x2d, 0x31, 0x05, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x06, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00,
];
let (rem, (response, _flags)) = dns_parse_response(pkt).unwrap();
assert_eq!(rem.len(), 0);
assert_eq!(response.answers.len(), 2);
let answer1 = &response.answers[0];
if let DNSRData::SRV(srv) = &answer1.data {
assert_eq!(srv.priority, 20);
assert_eq!(srv.weight, 1);
assert_eq!(srv.port, 5060);
assert_eq!(
srv.target.value,
"sip-anycast-2.voice.google.com".as_bytes().to_vec()
);
} else {
panic!("Expected DNSRData::SRV");
}
let answer2 = &response.answers[1];
if let DNSRData::SRV(srv) = &answer2.data {
assert_eq!(srv.priority, 10);
assert_eq!(srv.weight, 1);
assert_eq!(srv.port, 5060);
assert_eq!(
srv.target.value,
"sip-anycast-1.voice.google.com".as_bytes().to_vec()
);
} else {
panic!("Expected DNSRData::SRV");
}
}
#[test]
fn test_dns_parse_name_truncated() {
let mut buf: Vec<u8> = vec![];
for i in 1..18 {
buf.push(0b0011_1111);
buf.resize(i * 64, b'a');
}
let mut flags = DNSNameFlags::default();
let (rem, name) = dns_parse_name(&buf, &buf, &mut flags).unwrap();
assert_eq!(name.value.len(), MAX_NAME_LEN);
assert!(name.flags.contains(DNSNameFlags::TRUNCATED));
assert!(rem.is_empty());
}
#[test]
fn test_dns_parse_name_truncated_max_segments_no_pointer() {
let mut buf: Vec<u8> = vec![];
for _ in 0..256 {
buf.push(0b0000_0001);
buf.push(b'a');
}
let mut flags = DNSNameFlags::default();
assert!(dns_parse_name(&buf, &buf, &mut flags).is_err());
}
#[test]
fn test_dns_parse_name_truncated_max_segments_with_pointer() {
#[rustfmt::skip]
let buf: Vec<u8> = vec![
0b0000_0001,
b'a',
0b1100_0000,
0b0000_0000,
0b1100_0000,
0b000_0000
];
let mut flags = DNSNameFlags::default();
let (_rem, name) = dns_parse_name(&buf[4..], &buf, &mut flags).unwrap();
assert_eq!(name.value.len(), 255);
assert!(name.flags.contains(DNSNameFlags::TRUNCATED));
}
#[test]
fn test_dns_parse_name_self_reference() {
let buf = vec![0b1100_0000, 0b0000_0000];
let mut flags = DNSNameFlags::default();
assert!(dns_parse_name(&buf, &buf, &mut flags).is_err());
}
}