dns: add pdu frame

Adds a PDU frame to the DNS parser. For UDP this is the DNS payload
portion of the DNS packet, for TCP this is the payload minus the leading
legth field.

Ticket: 4984
pull/7349/head
Jason Ish 4 years ago committed by Victor Julien
parent 8d1840f595
commit b8b6a17a5b

@ -1,4 +1,4 @@
/* Copyright (C) 2017 Open Information Security Foundation
/* Copyright (C) 2017-2022 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
@ -25,6 +25,7 @@ use std::collections::VecDeque;
use crate::applayer::*;
use crate::core::{self, *};
use crate::dns::parser;
use crate::frames::Frame;
use nom7::{Err, IResult};
use nom7::number::streaming::be_u16;
@ -115,6 +116,15 @@ pub const DNS_RCODE_BADTRUNC: u16 = 22;
static mut ALPROTO_DNS: AppProto = ALPROTO_UNKNOWN;
#[derive(AppLayerFrameType)]
pub enum DnsFrameType {
/// DNS PDU frame. For UDP DNS this is the complete UDP payload, for TCP
/// this is the DNS payload not including the leading length field allowing
/// this frame to be used for UDP and TCP DNS.
Pdu,
}
#[derive(Debug, PartialEq, AppLayerEvent)]
pub enum DNSEvent {
MalformedData,
@ -388,7 +398,7 @@ impl DNSState {
self.events += 1;
}
pub fn parse_request(&mut self, input: &[u8]) -> bool {
fn parse_request(&mut self, input: &[u8]) -> bool {
match parser::dns_parse_request(input) {
Ok((_, request)) => {
if request.header.flags & 0x8000 != 0 {
@ -425,6 +435,18 @@ impl DNSState {
}
}
fn parse_request_udp(&mut self, flow: *const core::Flow, stream_slice: StreamSlice) -> bool {
let input = stream_slice.as_slice();
let _pdu = Frame::new_ts(flow, &stream_slice, input, input.len() as i64, DnsFrameType::Pdu as u8);
self.parse_request(input)
}
fn parse_response_udp(&mut self, flow: *const core::Flow, stream_slice: StreamSlice) -> bool {
let input = stream_slice.as_slice();
let _pdu = Frame::new_tc(flow, &stream_slice, input, input.len() as i64, DnsFrameType::Pdu as u8);
self.parse_response(input)
}
pub fn parse_response(&mut self, input: &[u8]) -> bool {
match parser::dns_parse_response(input) {
Ok((_, response)) => {
@ -473,7 +495,8 @@ impl DNSState {
/// prefix.
///
/// Returns the number of messages parsed.
pub fn parse_request_tcp(&mut self, input: &[u8]) -> AppLayerResult {
pub fn parse_request_tcp(&mut self, flow: *const core::Flow, stream_slice: StreamSlice) -> AppLayerResult {
let input = stream_slice.as_slice();
if self.gap {
let (is_dns, _, is_incomplete) = probe_tcp(input);
if is_dns || is_incomplete {
@ -496,8 +519,9 @@ impl DNSState {
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..]) {
let msg = &cur_i[2..(size + 2)];
let _pdu = Frame::new_ts(flow, &stream_slice, msg, msg.len() as i64, DnsFrameType::Pdu as u8);
if self.parse_request(msg) {
cur_i = &cur_i[(size + 2)..];
consumed += size + 2;
} else {
@ -520,7 +544,8 @@ impl DNSState {
/// prefix.
///
/// Returns the number of messages parsed.
pub fn parse_response_tcp(&mut self, input: &[u8]) -> AppLayerResult {
pub fn parse_response_tcp(&mut self, flow: *const core::Flow, stream_slice: StreamSlice) -> AppLayerResult {
let input = stream_slice.as_slice();
if self.gap {
let (is_dns, _, is_incomplete) = probe_tcp(input);
if is_dns || is_incomplete {
@ -543,8 +568,9 @@ impl DNSState {
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..]) {
let msg = &cur_i[2..(size + 2)];
let _pdu = Frame::new_tc(flow, &stream_slice, msg, msg.len() as i64, DnsFrameType::Pdu as u8);
if self.parse_response(msg) {
cur_i = &cur_i[(size + 2)..];
consumed += size + 2;
} else {
@ -683,7 +709,7 @@ pub unsafe extern "C" fn rs_dns_state_tx_free(state: *mut std::os::raw::c_void,
/// C binding parse a DNS request. Returns 1 on success, -1 on failure.
#[no_mangle]
pub unsafe extern "C" fn rs_dns_parse_request(_flow: *const core::Flow,
pub unsafe extern "C" fn rs_dns_parse_request(flow: *const core::Flow,
state: *mut std::os::raw::c_void,
_pstate: *mut std::os::raw::c_void,
stream_slice: StreamSlice,
@ -691,7 +717,7 @@ pub unsafe extern "C" fn rs_dns_parse_request(_flow: *const core::Flow,
)
-> AppLayerResult {
let state = cast_pointer!(state, DNSState);
if state.parse_request(stream_slice.as_slice()) {
if state.parse_request_udp(flow, stream_slice) {
AppLayerResult::ok()
} else {
AppLayerResult::err()
@ -699,7 +725,7 @@ pub unsafe extern "C" fn rs_dns_parse_request(_flow: *const core::Flow,
}
#[no_mangle]
pub unsafe extern "C" fn rs_dns_parse_response(_flow: *const core::Flow,
pub unsafe extern "C" fn rs_dns_parse_response(flow: *const core::Flow,
state: *mut std::os::raw::c_void,
_pstate: *mut std::os::raw::c_void,
stream_slice: StreamSlice,
@ -707,7 +733,7 @@ pub unsafe extern "C" fn rs_dns_parse_response(_flow: *const core::Flow,
)
-> AppLayerResult {
let state = cast_pointer!(state, DNSState);
if state.parse_response(stream_slice.as_slice()) {
if state.parse_response_udp(flow, stream_slice) {
AppLayerResult::ok()
} else {
AppLayerResult::err()
@ -716,7 +742,7 @@ pub unsafe extern "C" fn rs_dns_parse_response(_flow: *const core::Flow,
/// C binding parse a DNS request. Returns 1 on success, -1 on failure.
#[no_mangle]
pub unsafe extern "C" fn rs_dns_parse_request_tcp(_flow: *const core::Flow,
pub unsafe extern "C" fn rs_dns_parse_request_tcp(flow: *const core::Flow,
state: *mut std::os::raw::c_void,
_pstate: *mut std::os::raw::c_void,
stream_slice: StreamSlice,
@ -727,13 +753,13 @@ pub unsafe extern "C" fn rs_dns_parse_request_tcp(_flow: *const core::Flow,
if stream_slice.is_gap() {
state.request_gap(stream_slice.gap_size());
} else if stream_slice.len() > 0 {
return state.parse_request_tcp(stream_slice.as_slice());
return state.parse_request_tcp(flow, stream_slice);
}
AppLayerResult::ok()
}
#[no_mangle]
pub unsafe extern "C" fn rs_dns_parse_response_tcp(_flow: *const core::Flow,
pub unsafe extern "C" fn rs_dns_parse_response_tcp(flow: *const core::Flow,
state: *mut std::os::raw::c_void,
_pstate: *mut std::os::raw::c_void,
stream_slice: StreamSlice,
@ -744,7 +770,7 @@ pub unsafe extern "C" fn rs_dns_parse_response_tcp(_flow: *const core::Flow,
if stream_slice.is_gap() {
state.response_gap(stream_slice.gap_size());
} else if stream_slice.len() > 0 {
return state.parse_response_tcp(stream_slice.as_slice());
return state.parse_response_tcp(flow, stream_slice);
}
AppLayerResult::ok()
}
@ -961,8 +987,8 @@ pub unsafe extern "C" fn rs_dns_udp_register_parser() {
apply_tx_config: Some(rs_dns_apply_tx_config),
flags: APP_LAYER_PARSER_OPT_UNIDIR_TXS,
truncate: None,
get_frame_id_by_name: None,
get_frame_name_by_id: None,
get_frame_id_by_name: Some(DnsFrameType::ffi_id_from_name),
get_frame_name_by_id: Some(DnsFrameType::ffi_name_from_id),
};
let ip_proto_str = CString::new("udp").unwrap();
@ -1006,8 +1032,8 @@ pub unsafe extern "C" fn rs_dns_tcp_register_parser() {
apply_tx_config: Some(rs_dns_apply_tx_config),
flags: APP_LAYER_PARSER_OPT_ACCEPT_GAPS | APP_LAYER_PARSER_OPT_UNIDIR_TXS,
truncate: None,
get_frame_id_by_name: None,
get_frame_name_by_id: None,
get_frame_id_by_name: Some(DnsFrameType::ffi_id_from_name),
get_frame_name_by_id: Some(DnsFrameType::ffi_name_from_id),
};
let ip_proto_str = CString::new("tcp").unwrap();
@ -1056,7 +1082,7 @@ mod tests {
let mut state = DNSState::new();
assert_eq!(
AppLayerResult::ok(),
state.parse_request_tcp(&request)
state.parse_request_tcp(std::ptr::null(), StreamSlice::from_slice(&request, 0, 0))
);
}
@ -1092,7 +1118,7 @@ mod tests {
let mut state = DNSState::new();
assert_eq!(
AppLayerResult::incomplete(0, 52),
state.parse_request_tcp(&request)
state.parse_request_tcp(std::ptr::null(), StreamSlice::from_slice(&request, 0, 0))
);
}
@ -1133,7 +1159,7 @@ mod tests {
let mut state = DNSState::new();
assert_eq!(
AppLayerResult::ok(),
state.parse_response_tcp(&request)
state.parse_response_tcp(std::ptr::null(), StreamSlice::from_slice(&request, 0, 0))
);
}
@ -1177,7 +1203,7 @@ mod tests {
let mut state = DNSState::new();
assert_eq!(
AppLayerResult::incomplete(0, 103),
state.parse_response_tcp(&request)
state.parse_response_tcp(std::ptr::null(), StreamSlice::from_slice(&request, 0, 0))
);
}
@ -1376,15 +1402,22 @@ mod tests {
0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01,
0x00, 0x01
];
// A NULL flow.
let flow = std::ptr::null();
let mut state = DNSState::new();
assert_eq!(
AppLayerResult::ok(),
state.parse_request_tcp(buf)
state.parse_request_tcp(flow, StreamSlice::from_slice(buf, 0, 0))
);
}
#[test]
fn test_dns_tcp_parser_split_payload() {
// A NULL flow.
let flow = std::ptr::null();
/* incomplete payload */
let buf1: &[u8] = &[
0x00, 0x1c, 0x10, 0x32, 0x01, 0x00, 0x00, 0x01,
@ -1413,15 +1446,15 @@ mod tests {
let mut state = DNSState::new();
assert_eq!(
AppLayerResult::incomplete(0, 30),
state.parse_request_tcp(buf1)
state.parse_request_tcp(flow, StreamSlice::from_slice(buf1, 0, 0))
);
assert_eq!(
AppLayerResult::incomplete(30, 30),
state.parse_request_tcp(buf2)
state.parse_request_tcp(flow, StreamSlice::from_slice(buf2, 0, 0))
);
assert_eq!(
AppLayerResult::ok(),
state.parse_request_tcp(buf3)
state.parse_request_tcp(flow, StreamSlice::from_slice(buf3, 0, 0))
);
}

Loading…
Cancel
Save