@ -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 ) )
) ;
}