|
|
|
|
@ -359,9 +359,6 @@ pub struct DNSState {
|
|
|
|
|
|
|
|
|
|
pub events: u16,
|
|
|
|
|
|
|
|
|
|
pub request_buffer: Vec<u8>,
|
|
|
|
|
pub response_buffer: Vec<u8>,
|
|
|
|
|
|
|
|
|
|
config: Option<ConfigTracker>,
|
|
|
|
|
|
|
|
|
|
gap: bool,
|
|
|
|
|
@ -374,22 +371,16 @@ impl DNSState {
|
|
|
|
|
tx_id: 0,
|
|
|
|
|
transactions: Vec::new(),
|
|
|
|
|
events: 0,
|
|
|
|
|
request_buffer: Vec::new(),
|
|
|
|
|
response_buffer: Vec::new(),
|
|
|
|
|
config: None,
|
|
|
|
|
gap: false,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Allocate a new state with capacites in the buffers for
|
|
|
|
|
/// potentially buffering as might be needed in TCP.
|
|
|
|
|
pub fn new_tcp() -> DNSState {
|
|
|
|
|
return DNSState{
|
|
|
|
|
tx_id: 0,
|
|
|
|
|
transactions: Vec::new(),
|
|
|
|
|
events: 0,
|
|
|
|
|
request_buffer: Vec::with_capacity(0xffff),
|
|
|
|
|
response_buffer: Vec::with_capacity(0xffff),
|
|
|
|
|
config: None,
|
|
|
|
|
gap: false,
|
|
|
|
|
};
|
|
|
|
|
@ -540,98 +531,98 @@ impl DNSState {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// TCP variation of response request parser to handle the length
|
|
|
|
|
/// prefix as well as buffering.
|
|
|
|
|
///
|
|
|
|
|
/// Always buffer and read from the buffer. Should optimize to skip
|
|
|
|
|
/// the buffer if not needed.
|
|
|
|
|
/// prefix.
|
|
|
|
|
///
|
|
|
|
|
/// Returns the number of messages parsed.
|
|
|
|
|
pub fn parse_request_tcp(&mut self, input: &[u8]) -> i8 {
|
|
|
|
|
pub fn parse_request_tcp(&mut self, input: &[u8]) -> AppLayerResult {
|
|
|
|
|
if self.gap {
|
|
|
|
|
let (is_dns, _, is_incomplete) = probe_tcp(input);
|
|
|
|
|
if is_dns || is_incomplete{
|
|
|
|
|
if is_dns || is_incomplete {
|
|
|
|
|
self.gap = false;
|
|
|
|
|
} else {
|
|
|
|
|
return 0
|
|
|
|
|
AppLayerResult::ok();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.request_buffer.extend_from_slice(input);
|
|
|
|
|
|
|
|
|
|
let mut count = 0;
|
|
|
|
|
while self.request_buffer.len() > 0 {
|
|
|
|
|
let size = match be_u16(&self.request_buffer) as IResult<&[u8],_> {
|
|
|
|
|
let mut cur_i = input;
|
|
|
|
|
let mut consumed = 0;
|
|
|
|
|
while cur_i.len() > 0 {
|
|
|
|
|
let size = match be_u16(&cur_i) as IResult<&[u8],_> {
|
|
|
|
|
Ok((_, len)) => i32::from(len),
|
|
|
|
|
_ => 0
|
|
|
|
|
} as usize;
|
|
|
|
|
SCLogDebug!("Have {} bytes, need {} to parse",
|
|
|
|
|
self.request_buffer.len(), size);
|
|
|
|
|
if size > 0 && self.request_buffer.len() >= size + 2 {
|
|
|
|
|
let msg: Vec<u8> = self.request_buffer.drain(0..(size + 2))
|
|
|
|
|
.collect();
|
|
|
|
|
SCLogDebug!("[request] Have {} bytes, need {} to parse",
|
|
|
|
|
cur_i.len(), size + 2);
|
|
|
|
|
if size > 0 && cur_i.len() >= size + 2 {
|
|
|
|
|
let msg = &cur_i[0..(size + 2)];
|
|
|
|
|
if self.parse_request(&msg[2..]) {
|
|
|
|
|
count += 1
|
|
|
|
|
cur_i = &cur_i[(size + 2)..];
|
|
|
|
|
consumed += size + 2;
|
|
|
|
|
} else {
|
|
|
|
|
return AppLayerResult::err();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
SCLogDebug!("Not enough DNS traffic to parse.");
|
|
|
|
|
break;
|
|
|
|
|
SCLogDebug!("[request]Not enough DNS traffic to parse. Returning {}/{}",
|
|
|
|
|
consumed as u32, (cur_i.len() - consumed) as u32);
|
|
|
|
|
return AppLayerResult::incomplete(consumed as u32,
|
|
|
|
|
(cur_i.len() - consumed) as u32);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return count;
|
|
|
|
|
AppLayerResult::ok()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// TCP variation of the response parser to handle the length
|
|
|
|
|
/// prefix as well as buffering.
|
|
|
|
|
///
|
|
|
|
|
/// Always buffer and read from the buffer. Should optimize to skip
|
|
|
|
|
/// the buffer if not needed.
|
|
|
|
|
/// prefix.
|
|
|
|
|
///
|
|
|
|
|
/// Returns the number of messages parsed.
|
|
|
|
|
pub fn parse_response_tcp(&mut self, input: &[u8]) -> i8 {
|
|
|
|
|
pub fn parse_response_tcp(&mut self, input: &[u8]) -> AppLayerResult {
|
|
|
|
|
if self.gap {
|
|
|
|
|
let (is_dns, _, is_incomplete) = probe_tcp(input);
|
|
|
|
|
if is_dns || is_incomplete{
|
|
|
|
|
if is_dns || is_incomplete {
|
|
|
|
|
self.gap = false;
|
|
|
|
|
} else {
|
|
|
|
|
return 0
|
|
|
|
|
return AppLayerResult::ok();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.response_buffer.extend_from_slice(input);
|
|
|
|
|
|
|
|
|
|
let mut count = 0;
|
|
|
|
|
while self.response_buffer.len() > 0 {
|
|
|
|
|
let size = match be_u16(&self.response_buffer) as IResult<&[u8],_> {
|
|
|
|
|
let mut cur_i = input;
|
|
|
|
|
let mut consumed = 0;
|
|
|
|
|
while cur_i.len() > 0 {
|
|
|
|
|
let size = match be_u16(&cur_i) as IResult<&[u8],_> {
|
|
|
|
|
Ok((_, len)) => i32::from(len),
|
|
|
|
|
_ => 0
|
|
|
|
|
} as usize;
|
|
|
|
|
if size > 0 && self.response_buffer.len() >= size + 2 {
|
|
|
|
|
let msg: Vec<u8> = self.response_buffer.drain(0..(size + 2))
|
|
|
|
|
.collect();
|
|
|
|
|
SCLogDebug!("[response] Have {} bytes, need {} to parse",
|
|
|
|
|
cur_i.len(), size + 2);
|
|
|
|
|
if size > 0 && cur_i.len() >= size + 2 {
|
|
|
|
|
let msg = &cur_i[0..(size + 2)];
|
|
|
|
|
if self.parse_response(&msg[2..]) {
|
|
|
|
|
count += 1;
|
|
|
|
|
cur_i = &cur_i[(size + 2)..];
|
|
|
|
|
consumed += size + 2;
|
|
|
|
|
} else {
|
|
|
|
|
return AppLayerResult::err();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
SCLogDebug!("[response]Not enough DNS traffic to parse. Returning {}/{}",
|
|
|
|
|
consumed as u32, (cur_i.len() - consumed) as u32);
|
|
|
|
|
return AppLayerResult::incomplete(consumed as u32,
|
|
|
|
|
(cur_i.len() - consumed) as u32);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return count;
|
|
|
|
|
AppLayerResult::ok()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// A gap has been seen in the request direction. Set the gap flag
|
|
|
|
|
/// to clear any buffered data.
|
|
|
|
|
/// A gap has been seen in the request direction. Set the gap flag.
|
|
|
|
|
pub fn request_gap(&mut self, gap: u32) {
|
|
|
|
|
if gap > 0 {
|
|
|
|
|
self.request_buffer.clear();
|
|
|
|
|
self.gap = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// A gap has been seen in the response direction. Set the gap
|
|
|
|
|
/// flag to clear any buffered data.
|
|
|
|
|
/// flag.
|
|
|
|
|
pub fn response_gap(&mut self, gap: u32) {
|
|
|
|
|
if gap > 0 {
|
|
|
|
|
self.response_buffer.clear();
|
|
|
|
|
self.gap = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -747,8 +738,7 @@ pub extern "C" fn rs_dns_parse_request_tcp(_flow: *const core::Flow,
|
|
|
|
|
if input != std::ptr::null_mut() {
|
|
|
|
|
let buf = unsafe{
|
|
|
|
|
std::slice::from_raw_parts(input, input_len as usize)};
|
|
|
|
|
let _ = state.parse_request_tcp(buf);
|
|
|
|
|
return AppLayerResult::ok();
|
|
|
|
|
state.parse_request_tcp(buf);
|
|
|
|
|
}
|
|
|
|
|
state.request_gap(input_len);
|
|
|
|
|
}
|
|
|
|
|
@ -769,8 +759,7 @@ pub extern "C" fn rs_dns_parse_response_tcp(_flow: *const core::Flow,
|
|
|
|
|
if input != std::ptr::null_mut() {
|
|
|
|
|
let buf = unsafe{
|
|
|
|
|
std::slice::from_raw_parts(input, input_len as usize)};
|
|
|
|
|
let _ = state.parse_response_tcp(buf);
|
|
|
|
|
return AppLayerResult::ok();
|
|
|
|
|
return state.parse_response_tcp(buf);
|
|
|
|
|
}
|
|
|
|
|
state.response_gap(input_len);
|
|
|
|
|
}
|
|
|
|
|
@ -1129,7 +1118,10 @@ mod tests {
|
|
|
|
|
request.extend(dns_payload);
|
|
|
|
|
|
|
|
|
|
let mut state = DNSState::new();
|
|
|
|
|
assert_eq!(1, state.parse_request_tcp(&request));
|
|
|
|
|
assert_eq!(
|
|
|
|
|
AppLayerResult::ok(),
|
|
|
|
|
state.parse_request_tcp(&request)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
@ -1162,7 +1154,10 @@ mod tests {
|
|
|
|
|
request.extend(dns_payload);
|
|
|
|
|
|
|
|
|
|
let mut state = DNSState::new();
|
|
|
|
|
assert_eq!(0, state.parse_request_tcp(&request));
|
|
|
|
|
assert_eq!(
|
|
|
|
|
AppLayerResult::incomplete(0, 51),
|
|
|
|
|
state.parse_request_tcp(&request)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
@ -1200,7 +1195,10 @@ mod tests {
|
|
|
|
|
request.extend(dns_payload);
|
|
|
|
|
|
|
|
|
|
let mut state = DNSState::new();
|
|
|
|
|
assert_eq!(1, state.parse_response_tcp(&request));
|
|
|
|
|
assert_eq!(
|
|
|
|
|
AppLayerResult::ok(),
|
|
|
|
|
state.parse_response_tcp(&request)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Test that a TCP DNS payload won't be parsed if there is not
|
|
|
|
|
@ -1241,7 +1239,10 @@ mod tests {
|
|
|
|
|
request.extend(dns_payload);
|
|
|
|
|
|
|
|
|
|
let mut state = DNSState::new();
|
|
|
|
|
assert_eq!(0, state.parse_response_tcp(&request));
|
|
|
|
|
assert_eq!(
|
|
|
|
|
AppLayerResult::incomplete(0, 102),
|
|
|
|
|
state.parse_response_tcp(&request)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Port of the C RustDNSUDPParserTest02 unit test.
|
|
|
|
|
@ -1440,6 +1441,34 @@ mod tests {
|
|
|
|
|
0x00, 0x01
|
|
|
|
|
];
|
|
|
|
|
let mut state = DNSState::new();
|
|
|
|
|
assert_eq!(state.parse_request_tcp(buf), 20);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
AppLayerResult::ok(),
|
|
|
|
|
state.parse_request_tcp(buf)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_dns_tcp_parser_split_payload() {
|
|
|
|
|
/* incomplete payload */
|
|
|
|
|
let buf1: &[u8] = &[
|
|
|
|
|
0x00, 0x1c, 0x10, 0x32, 0x01, 0x00, 0x00, 0x01,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
|
|
|
|
];
|
|
|
|
|
/* complete payload */
|
|
|
|
|
let buf2: &[u8] = &[
|
|
|
|
|
0x00, 0x1c, 0x10, 0x32, 0x01, 0x00, 0x00, 0x01,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, 0x65, 0x03,
|
|
|
|
|
0x63, 0x6F, 0x6D, 0x00, 0x00, 0x10, 0x00, 0x01
|
|
|
|
|
];
|
|
|
|
|
let mut state = DNSState::new();
|
|
|
|
|
assert_eq!(
|
|
|
|
|
AppLayerResult::incomplete(0, 14),
|
|
|
|
|
state.parse_request_tcp(buf1)
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
AppLayerResult::ok(),
|
|
|
|
|
state.parse_request_tcp(buf2)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|