dns: split header and body parsing

As part of extra header validation, split out DNS body parsing to
avoid the overhead of parsing the header twice.
pull/8430/head
Jason Ish 4 years ago committed by Victor Julien
parent 595700ab7e
commit d720ead470

@ -383,18 +383,23 @@ impl DNSState {
tx.tx_data.set_event(event as u8); tx.tx_data.set_event(event as u8);
} }
fn validate_header(&self, input: &[u8]) -> bool { fn validate_header<'a>(&self, input: &'a [u8]) -> Option<(&'a [u8], DNSHeader)> {
parser::dns_parse_header(input) if let Ok((body, header)) = parser::dns_parse_header(input) {
.map(|(_, header)| probe_header_validity(header, input.len()).0) if probe_header_validity(&header, input.len()).0 {
.unwrap_or(false) return Some((body, header));
}
}
None
} }
fn parse_request(&mut self, input: &[u8], is_tcp: bool) -> bool { fn parse_request(&mut self, input: &[u8], is_tcp: bool) -> bool {
if !self.validate_header(input) { let (body, header) = if let Some((body, header)) = self.validate_header(input) {
(body, header)
} else {
return !is_tcp; return !is_tcp;
} };
match parser::dns_parse_request(input) { match parser::dns_parse_request_body(body, input, header) {
Ok((_, request)) => { Ok((_, request)) => {
if request.header.flags & 0x8000 != 0 { if request.header.flags & 0x8000 != 0 {
SCLogDebug!("DNS message is not a request"); SCLogDebug!("DNS message is not a request");
@ -460,11 +465,13 @@ impl DNSState {
} }
pub fn parse_response(&mut self, input: &[u8], is_tcp: bool) -> bool { pub fn parse_response(&mut self, input: &[u8], is_tcp: bool) -> bool {
if !self.validate_header(input) { let (body, header) = if let Some((body, header)) = self.validate_header(input) {
(body, header)
} else {
return !is_tcp; return !is_tcp;
} };
match parser::dns_parse_response(input) { match parser::dns_parse_response_body(body, input, header) {
Ok((_, response)) => { Ok((_, response)) => {
SCLogDebug!("Response header flags: {}", response.header.flags); SCLogDebug!("Response header flags: {}", response.header.flags);
@ -653,7 +660,7 @@ impl DNSState {
const DNS_HEADER_SIZE: usize = 12; const DNS_HEADER_SIZE: usize = 12;
fn probe_header_validity(header: DNSHeader, rlen: usize) -> (bool, bool, bool) { fn probe_header_validity(header: &DNSHeader, rlen: usize) -> (bool, bool, bool) {
let min_msg_size = 2 let min_msg_size = 2
* (header.additional_rr as usize * (header.additional_rr as usize
+ header.answer_rr as usize + header.answer_rr as usize
@ -686,7 +693,7 @@ fn probe(input: &[u8], dlen: usize) -> (bool, bool, bool) {
// parse a complete message, so perform header validation only. // parse a complete message, so perform header validation only.
if input.len() < dlen { if input.len() < dlen {
if let Ok((_, header)) = parser::dns_parse_header(input) { if let Ok((_, header)) = parser::dns_parse_header(input) {
return probe_header_validity(header, dlen); return probe_header_validity(&header, dlen);
} else { } else {
return (false, false, false); return (false, false, false);
} }
@ -694,11 +701,11 @@ fn probe(input: &[u8], dlen: usize) -> (bool, bool, bool) {
match parser::dns_parse_request(input) { match parser::dns_parse_request(input) {
Ok((_, request)) => { Ok((_, request)) => {
return probe_header_validity(request.header, dlen); return probe_header_validity(&request.header, dlen);
} }
Err(Err::Incomplete(_)) => match parser::dns_parse_header(input) { Err(Err::Incomplete(_)) => match parser::dns_parse_header(input) {
Ok((_, header)) => { Ok((_, header)) => {
return probe_header_validity(header, dlen); return probe_header_validity(&header, dlen);
} }
Err(Err::Incomplete(_)) => (false, false, true), Err(Err::Incomplete(_)) => (false, false, true),
Err(_) => (false, false, false), Err(_) => (false, false, false),

@ -49,7 +49,7 @@ pub fn dns_parse_header(i: &[u8]) -> IResult<&[u8], DNSHeader> {
/// ///
/// Parameters: /// Parameters:
/// start: the start of the name /// start: the start of the name
/// message: the complete message that start is a part of /// message: the complete message that start is a part of with the DNS header
pub fn dns_parse_name<'b>(start: &'b [u8], message: &'b [u8]) -> IResult<&'b [u8], Vec<u8>> { pub fn dns_parse_name<'b>(start: &'b [u8], message: &'b [u8]) -> IResult<&'b [u8], Vec<u8>> {
let mut pos = start; let mut pos = start;
let mut pivot = start; let mut pivot = start;
@ -192,12 +192,18 @@ fn dns_parse_answer<'a>(
} }
/// Parse a DNS response. /// Parse a DNS response.
pub fn dns_parse_response(slice: &[u8]) -> IResult<&[u8], DNSResponse> { pub fn dns_parse_response(message: &[u8]) -> IResult<&[u8], DNSResponse> {
let i = slice; let i = message;
let (i, header) = dns_parse_header(i)?; let (i, header) = dns_parse_header(i)?;
let (i, queries) = count(|b| dns_parse_query(b, slice), header.questions as usize)(i)?; dns_parse_response_body(i, message, header)
let (i, answers) = dns_parse_answer(i, slice, header.answer_rr as usize)?; }
let (i, authorities) = dns_parse_answer(i, slice, header.authority_rr as usize)?;
pub fn dns_parse_response_body<'a>(
i: &'a [u8], message: &'a [u8], header: DNSHeader,
) -> IResult<&'a [u8], DNSResponse> {
let (i, queries) = count(|b| dns_parse_query(b, message), header.questions as usize)(i)?;
let (i, answers) = dns_parse_answer(i, message, header.answer_rr as usize)?;
let (i, authorities) = dns_parse_answer(i, message, header.authority_rr as usize)?;
Ok(( Ok((
i, i,
DNSResponse { DNSResponse {
@ -348,7 +354,14 @@ pub fn dns_parse_rdata<'a>(
pub fn dns_parse_request(input: &[u8]) -> IResult<&[u8], DNSRequest> { pub fn dns_parse_request(input: &[u8]) -> IResult<&[u8], DNSRequest> {
let i = input; let i = input;
let (i, header) = dns_parse_header(i)?; let (i, header) = dns_parse_header(i)?;
let (i, queries) = count(|b| dns_parse_query(b, input), header.questions as usize)(i)?; dns_parse_request_body(i, input, header)
}
pub fn dns_parse_request_body<'a>(
input: &'a [u8], message: &'a [u8], header: DNSHeader,
) -> IResult<&'a [u8], DNSRequest> {
let i = input;
let (i, queries) = count(|b| dns_parse_query(b, message), header.questions as usize)(i)?;
Ok((i, DNSRequest { header, queries })) Ok((i, DNSRequest { header, queries }))
} }

Loading…
Cancel
Save