-/* 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
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;
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,
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 {
}
}
+ 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)) => {
/// 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 {
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 {
/// 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 {
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 {
/// 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,
)
-> 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()
}
#[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,
)
-> 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()
/// 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,
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,
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()
}
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();
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();
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))
);
}
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))
);
}
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))
);
}
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))
);
}
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,
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))
);
}