]> git.ipfire.org Git - people/ms/suricata.git/blame - rust/src/dns/dns.rs
dns/rust - if let Some over options instead of loop.
[people/ms/suricata.git] / rust / src / dns / dns.rs
CommitLineData
9449739d
JI
1/* Copyright (C) 2017 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
73388042
JI
18extern crate libc;
19extern crate nom;
20
21use std;
22use std::mem::transmute;
23
24use log::*;
c54fc7f9 25use applayer::LoggerFlags;
73388042
JI
26use core;
27use dns::parser;
28
ba1a67e2
JI
29/// DNS record types.
30pub const DNS_RECORD_TYPE_A : u16 = 1;
31pub const DNS_RECORD_TYPE_NS : u16 = 2;
32pub const DNS_RECORD_TYPE_MD : u16 = 3; // Obsolete
33pub const DNS_RECORD_TYPE_MF : u16 = 4; // Obsolete
34pub const DNS_RECORD_TYPE_CNAME : u16 = 5;
35pub const DNS_RECORD_TYPE_SOA : u16 = 6;
36pub const DNS_RECORD_TYPE_MB : u16 = 7; // Experimental
37pub const DNS_RECORD_TYPE_MG : u16 = 8; // Experimental
38pub const DNS_RECORD_TYPE_MR : u16 = 9; // Experimental
39pub const DNS_RECORD_TYPE_NULL : u16 = 10; // Experimental
40pub const DNS_RECORD_TYPE_WKS : u16 = 11;
41pub const DNS_RECORD_TYPE_PTR : u16 = 12;
42pub const DNS_RECORD_TYPE_HINFO : u16 = 13;
43pub const DNS_RECORD_TYPE_MINFO : u16 = 14;
44pub const DNS_RECORD_TYPE_MX : u16 = 15;
45pub const DNS_RECORD_TYPE_TXT : u16 = 16;
46pub const DNS_RECORD_TYPE_RP : u16 = 17;
47pub const DNS_RECORD_TYPE_AFSDB : u16 = 18;
48pub const DNS_RECORD_TYPE_X25 : u16 = 19;
49pub const DNS_RECORD_TYPE_ISDN : u16 = 20;
50pub const DNS_RECORD_TYPE_RT : u16 = 21;
51pub const DNS_RECORD_TYPE_NSAP : u16 = 22;
52pub const DNS_RECORD_TYPE_NSAPPTR : u16 = 23;
53pub const DNS_RECORD_TYPE_SIG : u16 = 24;
54pub const DNS_RECORD_TYPE_KEY : u16 = 25;
55pub const DNS_RECORD_TYPE_PX : u16 = 26;
56pub const DNS_RECORD_TYPE_GPOS : u16 = 27;
57pub const DNS_RECORD_TYPE_AAAA : u16 = 28;
58pub const DNS_RECORD_TYPE_LOC : u16 = 29;
5a8537fe 59pub const DNS_RECORD_TYPE_NXT : u16 = 30; // Obsolete
ba1a67e2
JI
60pub const DNS_RECORD_TYPE_SRV : u16 = 33;
61pub const DNS_RECORD_TYPE_ATMA : u16 = 34;
62pub const DNS_RECORD_TYPE_NAPTR : u16 = 35;
63pub const DNS_RECORD_TYPE_KX : u16 = 36;
64pub const DNS_RECORD_TYPE_CERT : u16 = 37;
65pub const DNS_RECORD_TYPE_A6 : u16 = 38; // Obsolete
66pub const DNS_RECORD_TYPE_DNAME : u16 = 39;
67pub const DNS_RECORD_TYPE_OPT : u16 = 41;
68pub const DNS_RECORD_TYPE_APL : u16 = 42;
69pub const DNS_RECORD_TYPE_DS : u16 = 43;
70pub const DNS_RECORD_TYPE_SSHFP : u16 = 44;
71pub const DNS_RECORD_TYPE_IPSECKEY : u16 = 45;
72pub const DNS_RECORD_TYPE_RRSIG : u16 = 46;
73pub const DNS_RECORD_TYPE_NSEC : u16 = 47;
74pub const DNS_RECORD_TYPE_DNSKEY : u16 = 48;
75pub const DNS_RECORD_TYPE_DHCID : u16 = 49;
76pub const DNS_RECORD_TYPE_NSEC3 : u16 = 50;
77pub const DNS_RECORD_TYPE_NSEC3PARAM : u16 = 51;
78pub const DNS_RECORD_TYPE_TLSA : u16 = 52;
79pub const DNS_RECORD_TYPE_HIP : u16 = 55;
80pub const DNS_RECORD_TYPE_CDS : u16 = 59;
81pub const DNS_RECORD_TYPE_CDNSKEY : u16 = 60;
82pub const DNS_RECORD_TYPE_SPF : u16 = 99; // Obsolete
83pub const DNS_RECORD_TYPE_TKEY : u16 = 249;
84pub const DNS_RECORD_TYPE_TSIG : u16 = 250;
85pub const DNS_RECORD_TYPE_MAILA : u16 = 254; // Obsolete
86pub const DNS_RECORD_TYPE_ANY : u16 = 255;
87pub const DNS_RECORD_TYPE_URI : u16 = 256;
88
73388042
JI
89/// DNS error codes.
90pub const DNS_RCODE_NOERROR: u16 = 0;
91pub const DNS_RCODE_FORMERR: u16 = 1;
5a8537fe 92pub const DNS_RCODE_SERVFAIL: u16 = 2;
73388042 93pub const DNS_RCODE_NXDOMAIN: u16 = 3;
5a8537fe
JI
94pub const DNS_RCODE_NOTIMP: u16 = 4;
95pub const DNS_RCODE_REFUSED: u16 = 5;
96pub const DNS_RCODE_YXDOMAIN: u16 = 6;
97pub const DNS_RCODE_YXRRSET: u16 = 7;
98pub const DNS_RCODE_NXRRSET: u16 = 8;
99pub const DNS_RCODE_NOTAUTH: u16 = 9;
100pub const DNS_RCODE_NOTZONE: u16 = 10;
101// Support for OPT RR from RFC6891 will be needed to
102// parse RCODE values over 15
103pub const DNS_RCODE_BADVERS: u16 = 16;
104pub const DNS_RCODE_BADSIG: u16 = 16;
105pub const DNS_RCODE_BADKEY: u16 = 17;
106pub const DNS_RCODE_BADTIME: u16 = 18;
107pub const DNS_RCODE_BADMODE: u16 = 19;
108pub const DNS_RCODE_BADNAME: u16 = 20;
109pub const DNS_RCODE_BADALG: u16 = 21;
110pub const DNS_RCODE_BADTRUNC: u16 = 22;
111
73388042
JI
112
113/// The maximum number of transactions to keep in the queue pending
114/// processing before they are aggressively purged. Due to the
115/// stateless nature of this parser this is rarely needed, especially
116/// when one call to parse a request parses and a single request, and
117/// likewise for responses.
118///
119/// Where this matters is when one TCP buffer contains multiple
120/// requests are responses and one call into the parser creates
121/// multiple transactions. In this case we have to hold onto
122/// transactions longer than until handling the next transaction so it
123/// gets logged.
124const MAX_TRANSACTIONS: usize = 32;
125
126#[repr(u32)]
127pub enum DNSEvent {
128 UnsolicitedResponse = 0,
129 MalformedData,
130 NotRequest,
131 NotResponse,
132 ZFlagSet,
133 Flooded,
134 StateMemCapReached,
135}
136
9449739d
JI
137#[derive(Debug,PartialEq)]
138pub struct DNSHeader {
139 pub tx_id: u16,
140 pub flags: u16,
141 pub questions: u16,
142 pub answer_rr: u16,
143 pub authority_rr: u16,
144 pub additional_rr: u16,
145}
146
147#[derive(Debug)]
148pub struct DNSQueryEntry {
149 pub name: Vec<u8>,
150 pub rrtype: u16,
151 pub rrclass: u16,
152}
153
154#[derive(Debug,PartialEq)]
155pub struct DNSAnswerEntry {
156 pub name: Vec<u8>,
157 pub rrtype: u16,
158 pub rrclass: u16,
159 pub ttl: u32,
9449739d
JI
160 pub data: Vec<u8>,
161}
162
163#[derive(Debug)]
164pub struct DNSRequest {
165 pub header: DNSHeader,
166 pub queries: Vec<DNSQueryEntry>,
167}
168
169#[derive(Debug)]
170pub struct DNSResponse {
171 pub header: DNSHeader,
172 pub queries: Vec<DNSQueryEntry>,
173 pub answers: Vec<DNSAnswerEntry>,
174 pub authorities: Vec<DNSAnswerEntry>,
175}
73388042
JI
176
177#[derive(Debug)]
178pub struct DNSTransaction {
179 pub id: u64,
180 pub request: Option<DNSRequest>,
181 pub response: Option<DNSResponse>,
98eca552
VJ
182 detect_flags_ts: u64,
183 detect_flags_tc: u64,
c54fc7f9 184 pub logged: LoggerFlags,
73388042
JI
185 pub de_state: Option<*mut core::DetectEngineState>,
186 pub events: *mut core::AppLayerDecoderEvents,
187}
188
189impl DNSTransaction {
190
191 pub fn new() -> DNSTransaction {
192 return DNSTransaction{
193 id: 0,
194 request: None,
195 response: None,
98eca552
VJ
196 detect_flags_ts: 0,
197 detect_flags_tc: 0,
c54fc7f9 198 logged: LoggerFlags::new(),
73388042
JI
199 de_state: None,
200 events: std::ptr::null_mut(),
201 }
202 }
203
204 pub fn free(&mut self) {
205 if self.events != std::ptr::null_mut() {
206 core::sc_app_layer_decoder_events_free_events(&mut self.events);
207 }
f815027c
VJ
208 match self.de_state {
209 Some(state) => {
210 core::sc_detect_engine_state_free(state);
211 }
212 None => { },
213 }
73388042
JI
214 }
215
216 /// Get the DNS transactions ID (not the internal tracking ID).
217 pub fn tx_id(&self) -> u16 {
b7a58680 218 if let &Some(ref request) = &self.request {
73388042
JI
219 return request.header.tx_id;
220 }
b7a58680 221 if let &Some(ref response) = &self.response {
73388042
JI
222 return response.header.tx_id;
223 }
224
225 // Shouldn't happen.
226 return 0;
227 }
228
229 /// Get the reply code of the transaction. Note that this will
230 /// also return 0 if there is no reply.
231 pub fn rcode(&self) -> u16 {
b7a58680 232 if let &Some(ref response) = &self.response {
73388042
JI
233 return response.header.flags & 0x000f;
234 }
235 return 0;
236 }
237
238}
239
240impl Drop for DNSTransaction {
241 fn drop(&mut self) {
242 self.free();
243 }
244}
245
246pub struct DNSState {
247 // Internal transaction ID.
248 pub tx_id: u64,
249
250 // Transactions.
251 pub transactions: Vec<DNSTransaction>,
252
73388042
JI
253 pub events: u16,
254
255 pub request_buffer: Vec<u8>,
256 pub response_buffer: Vec<u8>,
70808a4f
JI
257
258 gap: bool,
73388042
JI
259}
260
261impl DNSState {
262
263 pub fn new() -> DNSState {
264 return DNSState{
265 tx_id: 0,
266 transactions: Vec::new(),
73388042
JI
267 events: 0,
268 request_buffer: Vec::new(),
269 response_buffer: Vec::new(),
70808a4f 270 gap: false,
73388042
JI
271 };
272 }
273
274 /// Allocate a new state with capacites in the buffers for
275 /// potentially buffering as might be needed in TCP.
276 pub fn new_tcp() -> DNSState {
277 return DNSState{
278 tx_id: 0,
279 transactions: Vec::new(),
73388042
JI
280 events: 0,
281 request_buffer: Vec::with_capacity(0xffff),
282 response_buffer: Vec::with_capacity(0xffff),
70808a4f 283 gap: false,
73388042
JI
284 };
285 }
286
73388042
JI
287 pub fn new_tx(&mut self) -> DNSTransaction {
288 let mut tx = DNSTransaction::new();
289 self.tx_id += 1;
290 tx.id = self.tx_id;
291 return tx;
292 }
293
294 pub fn free_tx(&mut self, tx_id: u64) {
73388042
JI
295 let len = self.transactions.len();
296 let mut found = false;
297 let mut index = 0;
298 for i in 0..len {
299 let tx = &self.transactions[i];
300 if tx.id == tx_id + 1 {
301 found = true;
302 index = i;
303 break;
304 }
305 }
306 if found {
f815027c 307 self.transactions.remove(index);
73388042
JI
308 }
309 }
310
311 // Purges all transactions except one. This is a stateless parser
312 // so we don't need to hang onto old transactions.
313 //
314 // This is to actually handle an edge case where a DNS flood
315 // occurs in a single direction with no response packets. In such
316 // a case the functions to free a transaction are never called by
317 // the app-layer as they require bidirectional traffic.
318 pub fn purge(&mut self, tx_id: u64) {
319 while self.transactions.len() > MAX_TRANSACTIONS {
320 if self.transactions[0].id == tx_id + 1 {
321 return;
322 }
323 SCLogDebug!("Purging DNS TX with ID {}", self.transactions[0].id);
f815027c 324 self.transactions.remove(0);
73388042
JI
325 }
326 }
327
328 pub fn get_tx(&mut self, tx_id: u64) -> Option<&DNSTransaction> {
329 SCLogDebug!("get_tx: tx_id={}", tx_id);
330 self.purge(tx_id);
331 for tx in &mut self.transactions {
332 if tx.id == tx_id + 1 {
333 SCLogDebug!("Found DNS TX with ID {}", tx_id);
334 return Some(tx);
335 }
336 }
337 SCLogDebug!("Failed to find DNS TX with ID {}", tx_id);
338 return None;
339 }
340
341 /// Set an event. The event is set on the most recent transaction.
342 pub fn set_event(&mut self, event: DNSEvent) {
343 let len = self.transactions.len();
344 if len == 0 {
345 return;
346 }
347
e023ce9a 348 let tx = &mut self.transactions[len - 1];
73388042
JI
349 core::sc_app_layer_decoder_events_set_event_raw(&mut tx.events,
350 event as u8);
351 self.events += 1;
352 }
353
354 pub fn parse_request(&mut self, input: &[u8]) -> bool {
355 match parser::dns_parse_request(input) {
356 nom::IResult::Done(_, request) => {
357 if request.header.flags & 0x8000 != 0 {
358 SCLogDebug!("DNS message is not a request");
359 self.set_event(DNSEvent::NotRequest);
360 return false;
361 }
362
363 if request.header.flags & 0x0040 != 0 {
364 SCLogDebug!("Z-flag set on DNS response");
365 self.set_event(DNSEvent::ZFlagSet);
366 return false;
367 }
368
369 let mut tx = self.new_tx();
370 tx.request = Some(request);
371 self.transactions.push(tx);
372 return true;
373 }
374 nom::IResult::Incomplete(_) => {
375 // Insufficient data.
376 SCLogDebug!("Insufficient data while parsing DNS request");
377 self.set_event(DNSEvent::MalformedData);
378 return false;
379 }
380 nom::IResult::Error(_) => {
381 // Error, probably malformed data.
382 SCLogDebug!("An error occurred while parsing DNS request");
383 self.set_event(DNSEvent::MalformedData);
384 return false;
385 }
386 }
387 }
388
389 pub fn parse_response(&mut self, input: &[u8]) -> bool {
390 match parser::dns_parse_response(input) {
391 nom::IResult::Done(_, response) => {
392
393 SCLogDebug!("Response header flags: {}", response.header.flags);
394
395 if response.header.flags & 0x8000 == 0 {
396 SCLogDebug!("DNS message is not a response");
397 self.set_event(DNSEvent::NotResponse);
398 }
399
400 if response.header.flags & 0x0040 != 0 {
401 SCLogDebug!("Z-flag set on DNS response");
402 self.set_event(DNSEvent::ZFlagSet);
403 return false;
404 }
405
406 let mut tx = self.new_tx();
407 tx.response = Some(response);
408 self.transactions.push(tx);
409 return true;
410 }
411 nom::IResult::Incomplete(_) => {
412 // Insufficient data.
413 SCLogDebug!("Insufficient data while parsing DNS response");
414 self.set_event(DNSEvent::MalformedData);
415 return false;
416 }
417 nom::IResult::Error(_) => {
418 // Error, probably malformed data.
419 SCLogDebug!("An error occurred while parsing DNS response");
420 self.set_event(DNSEvent::MalformedData);
421 return false;
422 }
423 }
424 }
425
426 /// TCP variation of response request parser to handle the length
427 /// prefix as well as buffering.
428 ///
429 /// Always buffer and read from the buffer. Should optimize to skip
430 /// the buffer if not needed.
ecc63481
JI
431 ///
432 /// Returns the number of messages parsed.
73388042 433 pub fn parse_request_tcp(&mut self, input: &[u8]) -> i8 {
70808a4f
JI
434 if self.gap {
435 if probe_tcp(input) {
436 self.gap = false;
437 } else {
438 return 0
439 }
440 }
441
73388042
JI
442 self.request_buffer.extend_from_slice(input);
443
ecc63481 444 let mut count = 0;
73388042
JI
445 while self.request_buffer.len() > 0 {
446 let size = match nom::be_u16(&self.request_buffer) {
ecc63481
JI
447 nom::IResult::Done(_, len) => len,
448 _ => 0
449 } as usize;
73388042
JI
450 SCLogDebug!("Have {} bytes, need {} to parse",
451 self.request_buffer.len(), size);
ecc63481 452 if size > 0 && self.request_buffer.len() >= size + 2 {
73388042
JI
453 let msg: Vec<u8> = self.request_buffer.drain(0..(size + 2))
454 .collect();
455 if self.parse_request(&msg[2..]) {
ecc63481 456 count += 1
73388042 457 }
ecc63481
JI
458 } else {
459 SCLogDebug!("Not enough DNS traffic to parse.");
460 break;
73388042 461 }
73388042 462 }
ecc63481 463 return count;
73388042
JI
464 }
465
466 /// TCP variation of the response parser to handle the length
467 /// prefix as well as buffering.
468 ///
469 /// Always buffer and read from the buffer. Should optimize to skip
470 /// the buffer if not needed.
ecc63481
JI
471 ///
472 /// Returns the number of messages parsed.
73388042 473 pub fn parse_response_tcp(&mut self, input: &[u8]) -> i8 {
70808a4f
JI
474 if self.gap {
475 if probe_tcp(input) {
476 self.gap = false;
477 } else {
478 return 0
479 }
480 }
481
73388042 482 self.response_buffer.extend_from_slice(input);
ecc63481
JI
483
484 let mut count = 0;
485 while self.response_buffer.len() > 0 {
486 let size = match nom::be_u16(&self.response_buffer) {
487 nom::IResult::Done(_, len) => len,
488 _ => 0
489 } as usize;
490 if size > 0 && self.response_buffer.len() >= size + 2 {
491 let msg: Vec<u8> = self.response_buffer.drain(0..(size + 2))
492 .collect();
493 if self.parse_response(&msg[2..]) {
494 count += 1;
495 }
496 } else {
497 break;
73388042 498 }
73388042 499 }
ecc63481 500 return count;
70808a4f
JI
501 }
502
503 /// A gap has been seen in the request direction. Set the gap flag
504 /// to clear any buffered data.
505 pub fn request_gap(&mut self, gap: u32) {
506 if gap > 0 {
507 self.request_buffer.clear();
508 self.gap = true;
509 }
510 }
511
512 /// A gap has been seen in the response direction. Set the gap
513 /// flag to clear any buffered data.
514 pub fn response_gap(&mut self, gap: u32) {
515 if gap > 0 {
516 self.response_buffer.clear();
517 self.gap = true;
518 }
73388042
JI
519 }
520}
521
70808a4f
JI
522/// Probe input to see if it looks like DNS.
523fn probe(input: &[u8]) -> bool {
524 match parser::dns_parse_request(input) {
525 nom::IResult::Done(_, _) => true,
526 _ => false
527 }
528}
529
530/// Probe TCP input to see if it looks like DNS.
531pub fn probe_tcp(input: &[u8]) -> bool {
532 match nom::be_u16(input) {
3063851d
JI
533 nom::IResult::Done(rem, _) => {
534 return probe(rem);
70808a4f
JI
535 },
536 _ => {}
537 }
538 return false;
539}
540
73388042
JI
541/// Returns *mut DNSState
542#[no_mangle]
543pub extern "C" fn rs_dns_state_new() -> *mut libc::c_void {
544 let state = DNSState::new();
545 let boxed = Box::new(state);
546 return unsafe{transmute(boxed)};
547}
548
549/// Returns *mut DNSState
550#[no_mangle]
551pub extern "C" fn rs_dns_state_tcp_new() -> *mut libc::c_void {
552 let state = DNSState::new_tcp();
553 let boxed = Box::new(state);
554 return unsafe{transmute(boxed)};
555}
556
557/// Params:
558/// - state: *mut DNSState as void pointer
559#[no_mangle]
560pub extern "C" fn rs_dns_state_free(state: *mut libc::c_void) {
561 // Just unbox...
562 let _drop: Box<DNSState> = unsafe{transmute(state)};
563}
564
565#[no_mangle]
566pub extern "C" fn rs_dns_state_tx_free(state: &mut DNSState,
567 tx_id: libc::uint64_t)
568{
569 state.free_tx(tx_id);
570}
571
572/// C binding parse a DNS request. Returns 1 on success, -1 on failure.
573#[no_mangle]
574pub extern "C" fn rs_dns_parse_request(_flow: *mut core::Flow,
575 state: &mut DNSState,
576 _pstate: *mut libc::c_void,
577 input: *mut libc::uint8_t,
578 input_len: libc::uint32_t,
579 _data: *mut libc::c_void)
580 -> libc::int8_t {
581 let buf = unsafe{std::slice::from_raw_parts(input, input_len as usize)};
582 if state.parse_request(buf) {
583 1
584 } else {
585 -1
586 }
587}
588
589#[no_mangle]
590pub extern "C" fn rs_dns_parse_response(_flow: *mut core::Flow,
591 state: &mut DNSState,
592 _pstate: *mut libc::c_void,
593 input: *mut libc::uint8_t,
594 input_len: libc::uint32_t,
595 _data: *mut libc::c_void)
596 -> libc::int8_t {
597 let buf = unsafe{std::slice::from_raw_parts(input, input_len as usize)};
598 if state.parse_response(buf) {
599 1
600 } else {
601 -1
602 }
603}
604
605/// C binding parse a DNS request. Returns 1 on success, -1 on failure.
606#[no_mangle]
607pub extern "C" fn rs_dns_parse_request_tcp(_flow: *mut core::Flow,
608 state: &mut DNSState,
609 _pstate: *mut libc::c_void,
610 input: *mut libc::uint8_t,
611 input_len: libc::uint32_t,
612 _data: *mut libc::c_void)
613 -> libc::int8_t {
70808a4f
JI
614 if input_len > 0 {
615 if input != std::ptr::null_mut() {
616 let buf = unsafe{
617 std::slice::from_raw_parts(input, input_len as usize)};
618 return state.parse_request_tcp(buf);
619 }
620 state.request_gap(input_len);
621 }
622 return 0;
73388042
JI
623}
624
625#[no_mangle]
626pub extern "C" fn rs_dns_parse_response_tcp(_flow: *mut core::Flow,
627 state: &mut DNSState,
628 _pstate: *mut libc::c_void,
629 input: *mut libc::uint8_t,
630 input_len: libc::uint32_t,
631 _data: *mut libc::c_void)
632 -> libc::int8_t {
70808a4f
JI
633 if input_len > 0 {
634 if input != std::ptr::null_mut() {
635 let buf = unsafe{
636 std::slice::from_raw_parts(input, input_len as usize)};
637 return state.parse_response_tcp(buf);
638 }
639 state.response_gap(input_len);
640 }
641 return 0;
73388042
JI
642}
643
644#[no_mangle]
645pub extern "C" fn rs_dns_state_progress_completion_status(
646 _direction: libc::uint8_t)
647 -> libc::c_int
648{
649 SCLogDebug!("rs_dns_state_progress_completion_status");
650 return 1;
651}
652
653#[no_mangle]
654pub extern "C" fn rs_dns_tx_get_alstate_progress(_tx: &mut DNSTransaction,
655 _direction: libc::uint8_t)
656 -> libc::uint8_t
657{
658 // This is a stateless parser, just the existence of a transaction
659 // means its complete.
660 SCLogDebug!("rs_dns_tx_get_alstate_progress");
661 return 1;
662}
663
98eca552
VJ
664#[no_mangle]
665pub extern "C" fn rs_dns_tx_set_detect_flags(tx: &mut DNSTransaction,
666 dir: libc::uint8_t,
667 flags: libc::uint64_t)
668{
669 if dir & core::STREAM_TOSERVER != 0 {
670 tx.detect_flags_ts = flags as u64;
671 } else {
672 tx.detect_flags_tc = flags as u64;
673 }
674}
675
676#[no_mangle]
677pub extern "C" fn rs_dns_tx_get_detect_flags(tx: &mut DNSTransaction,
678 dir: libc::uint8_t)
679 -> libc::uint64_t
680{
681 if dir & core::STREAM_TOSERVER != 0 {
682 return tx.detect_flags_ts as libc::uint64_t;
683 } else {
684 return tx.detect_flags_tc as libc::uint64_t;
685 }
686}
687
73388042
JI
688#[no_mangle]
689pub extern "C" fn rs_dns_tx_set_logged(_state: &mut DNSState,
690 tx: &mut DNSTransaction,
bca0cd71 691 logged: libc::uint32_t)
73388042 692{
bca0cd71 693 tx.logged.set(logged);
73388042
JI
694}
695
696#[no_mangle]
697pub extern "C" fn rs_dns_tx_get_logged(_state: &mut DNSState,
bca0cd71
VJ
698 tx: &mut DNSTransaction)
699 -> u32
73388042 700{
bca0cd71 701 return tx.logged.get();
73388042
JI
702}
703
704#[no_mangle]
705pub extern "C" fn rs_dns_state_get_tx_count(state: &mut DNSState)
706 -> libc::uint64_t
707{
708 SCLogDebug!("rs_dns_state_get_tx_count: returning {}", state.tx_id);
709 return state.tx_id;
710}
711
712#[no_mangle]
713pub extern "C" fn rs_dns_state_get_tx(state: &mut DNSState,
714 tx_id: libc::uint64_t)
715 -> *mut DNSTransaction
716{
717 match state.get_tx(tx_id) {
718 Some(tx) => {
719 return unsafe{transmute(tx)};
720 }
721 None => {
722 return std::ptr::null_mut();
723 }
724 }
725}
726
73388042
JI
727#[no_mangle]
728pub extern "C" fn rs_dns_state_set_tx_detect_state(
73388042
JI
729 tx: &mut DNSTransaction,
730 de_state: &mut core::DetectEngineState)
731{
73388042
JI
732 tx.de_state = Some(de_state);
733}
734
735#[no_mangle]
736pub extern "C" fn rs_dns_state_get_tx_detect_state(
737 tx: &mut DNSTransaction)
738 -> *mut core::DetectEngineState
739{
740 match tx.de_state {
741 Some(ds) => {
742 return ds;
743 },
744 None => {
745 return std::ptr::null_mut();
746 }
747 }
748}
749
73388042
JI
750#[no_mangle]
751pub extern "C" fn rs_dns_state_get_events(state: &mut DNSState,
752 tx_id: libc::uint64_t)
753 -> *mut core::AppLayerDecoderEvents
754{
755 match state.get_tx(tx_id) {
756 Some(tx) => {
757 return tx.events;
758 }
759 _ => {
760 return std::ptr::null_mut();
761 }
762 }
763}
764
765#[no_mangle]
766pub extern "C" fn rs_dns_tx_get_query_name(tx: &mut DNSTransaction,
767 i: libc::uint16_t,
768 buf: *mut *const libc::uint8_t,
769 len: *mut libc::uint32_t)
770 -> libc::uint8_t
771{
b7a58680 772 if let &Some(ref request) = &tx.request {
73388042
JI
773 if (i as usize) < request.queries.len() {
774 let query = &request.queries[i as usize];
775 if query.name.len() > 0 {
776 unsafe {
777 *len = query.name.len() as libc::uint32_t;
778 *buf = query.name.as_ptr();
779 }
780 return 1;
781 }
782 }
783 }
784 return 0;
785}
786
787/// Get the DNS transaction ID of a transaction.
788//
789/// extern uint16_t rs_dns_tx_get_tx_id(RSDNSTransaction *);
790#[no_mangle]
791pub extern "C" fn rs_dns_tx_get_tx_id(tx: &mut DNSTransaction) -> libc::uint16_t
792{
793 return tx.tx_id()
794}
795
796/// Get the DNS response flags for a transaction.
797///
798/// extern uint16_t rs_dns_tx_get_response_flags(RSDNSTransaction *);
799#[no_mangle]
800pub extern "C" fn rs_dns_tx_get_response_flags(tx: &mut DNSTransaction)
801 -> libc::uint16_t
802{
803 return tx.rcode();
804}
805
806#[no_mangle]
807pub extern "C" fn rs_dns_tx_get_query_rrtype(tx: &mut DNSTransaction,
808 i: libc::uint16_t,
809 rrtype: *mut libc::uint16_t)
810 -> libc::uint8_t
811{
b7a58680 812 if let &Some(ref request) = &tx.request {
73388042
JI
813 if (i as usize) < request.queries.len() {
814 let query = &request.queries[i as usize];
815 if query.name.len() > 0 {
816 unsafe {
817 *rrtype = query.rrtype;
818 }
819 return 1;
820 }
821 }
822 }
823 return 0;
824}
825
826#[no_mangle]
827pub extern "C" fn rs_dns_probe(input: *const libc::uint8_t, len: libc::uint32_t)
828 -> libc::uint8_t
829{
830 let slice: &[u8] = unsafe {
831 std::slice::from_raw_parts(input as *mut u8, len as usize)
832 };
70808a4f
JI
833 if probe(slice) {
834 return 1;
73388042 835 }
70808a4f 836 return 0;
73388042
JI
837}
838
839#[no_mangle]
840pub extern "C" fn rs_dns_probe_tcp(input: *const libc::uint8_t,
841 len: libc::uint32_t)
842 -> libc::uint8_t
843{
844 let slice: &[u8] = unsafe {
845 std::slice::from_raw_parts(input as *mut u8, len as usize)
846 };
70808a4f
JI
847 if probe_tcp(slice) {
848 return 1;
73388042
JI
849 }
850 return 0;
851}
852
853#[cfg(test)]
854mod tests {
855
ecc63481
JI
856 use dns::dns::DNSState;
857
858 #[test]
859 fn test_dns_parse_request_tcp_valid() {
860 // A UDP DNS request with the DNS payload starting at byte 42.
861 // From pcap: https://github.com/jasonish/suricata-verify/blob/7cc0e1bd0a5249b52e6e87d82d57c0b6aaf75fce/dns-udp-dig-a-www-suricata-ids-org/dig-a-www.suricata-ids.org.pcap
862 let buf: &[u8] = &[
863 0x00, 0x15, 0x17, 0x0d, 0x06, 0xf7, 0xd8, 0xcb, /* ........ */
864 0x8a, 0xed, 0xa1, 0x46, 0x08, 0x00, 0x45, 0x00, /* ...F..E. */
865 0x00, 0x4d, 0x23, 0x11, 0x00, 0x00, 0x40, 0x11, /* .M#...@. */
866 0x41, 0x64, 0x0a, 0x10, 0x01, 0x0b, 0x0a, 0x10, /* Ad...... */
867 0x01, 0x01, 0xa3, 0x4d, 0x00, 0x35, 0x00, 0x39, /* ...M.5.9 */
868 0xb2, 0xb3, 0x8d, 0x32, 0x01, 0x20, 0x00, 0x01, /* ...2. .. */
869 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x77, /* .......w */
870 0x77, 0x77, 0x0c, 0x73, 0x75, 0x72, 0x69, 0x63, /* ww.suric */
871 0x61, 0x74, 0x61, 0x2d, 0x69, 0x64, 0x73, 0x03, /* ata-ids. */
872 0x6f, 0x72, 0x67, 0x00, 0x00, 0x01, 0x00, 0x01, /* org..... */
873 0x00, 0x00, 0x29, 0x10, 0x00, 0x00, 0x00, 0x00, /* ..)..... */
874 0x00, 0x00, 0x00 /* ... */
875 ];
876
877 // The DNS payload starts at offset 42.
878 let dns_payload = &buf[42..];
879
880 // Make a TCP DNS request payload.
881 let mut request = Vec::new();
882 request.push(((dns_payload.len() as u16) >> 8) as u8);
883 request.push(((dns_payload.len() as u16) & 0xff) as u8);
884 request.extend(dns_payload);
885
886 let mut state = DNSState::new();
887 assert_eq!(1, state.parse_request_tcp(&request));
888 }
889
73388042 890 #[test]
ecc63481
JI
891 fn test_dns_parse_request_tcp_short_payload() {
892 // A UDP DNS request with the DNS payload starting at byte 42.
893 // From pcap: https://github.com/jasonish/suricata-verify/blob/7cc0e1bd0a5249b52e6e87d82d57c0b6aaf75fce/dns-udp-dig-a-www-suricata-ids-org/dig-a-www.suricata-ids.org.pcap
73388042 894 let buf: &[u8] = &[
ecc63481
JI
895 0x00, 0x15, 0x17, 0x0d, 0x06, 0xf7, 0xd8, 0xcb, /* ........ */
896 0x8a, 0xed, 0xa1, 0x46, 0x08, 0x00, 0x45, 0x00, /* ...F..E. */
897 0x00, 0x4d, 0x23, 0x11, 0x00, 0x00, 0x40, 0x11, /* .M#...@. */
898 0x41, 0x64, 0x0a, 0x10, 0x01, 0x0b, 0x0a, 0x10, /* Ad...... */
899 0x01, 0x01, 0xa3, 0x4d, 0x00, 0x35, 0x00, 0x39, /* ...M.5.9 */
900 0xb2, 0xb3, 0x8d, 0x32, 0x01, 0x20, 0x00, 0x01, /* ...2. .. */
901 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x77, /* .......w */
902 0x77, 0x77, 0x0c, 0x73, 0x75, 0x72, 0x69, 0x63, /* ww.suric */
903 0x61, 0x74, 0x61, 0x2d, 0x69, 0x64, 0x73, 0x03, /* ata-ids. */
904 0x6f, 0x72, 0x67, 0x00, 0x00, 0x01, 0x00, 0x01, /* org..... */
905 0x00, 0x00, 0x29, 0x10, 0x00, 0x00, 0x00, 0x00, /* ..)..... */
906 0x00, 0x00, 0x00 /* ... */
73388042 907 ];
ecc63481
JI
908
909 // The DNS payload starts at offset 42.
910 let dns_payload = &buf[42..];
911
912 // Make a TCP DNS request payload but with the length 1 larger
913 // than the available data.
914 let mut request = Vec::new();
915 request.push(((dns_payload.len() as u16) >> 8) as u8);
d83707be 916 request.push(((dns_payload.len() as u16) & 0xff) as u8 + 1);
ecc63481
JI
917 request.extend(dns_payload);
918
919 let mut state = DNSState::new();
920 assert_eq!(0, state.parse_request_tcp(&request));
921 }
922
923 #[test]
924 fn test_dns_parse_response_tcp_valid() {
925 // A UDP DNS response with the DNS payload starting at byte 42.
926 // From pcap: https://github.com/jasonish/suricata-verify/blob/7cc0e1bd0a5249b52e6e87d82d57c0b6aaf75fce/dns-udp-dig-a-www-suricata-ids-org/dig-a-www.suricata-ids.org.pcap
927 let buf: &[u8] = &[
928 0xd8, 0xcb, 0x8a, 0xed, 0xa1, 0x46, 0x00, 0x15, /* .....F.. */
929 0x17, 0x0d, 0x06, 0xf7, 0x08, 0x00, 0x45, 0x00, /* ......E. */
930 0x00, 0x80, 0x65, 0x4e, 0x40, 0x00, 0x40, 0x11, /* ..eN@.@. */
931 0xbe, 0xf3, 0x0a, 0x10, 0x01, 0x01, 0x0a, 0x10, /* ........ */
932 0x01, 0x0b, 0x00, 0x35, 0xa3, 0x4d, 0x00, 0x6c, /* ...5.M.l */
933 0x8d, 0x8c, 0x8d, 0x32, 0x81, 0xa0, 0x00, 0x01, /* ...2.... */
934 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, /* .......w */
935 0x77, 0x77, 0x0c, 0x73, 0x75, 0x72, 0x69, 0x63, /* ww.suric */
936 0x61, 0x74, 0x61, 0x2d, 0x69, 0x64, 0x73, 0x03, /* ata-ids. */
937 0x6f, 0x72, 0x67, 0x00, 0x00, 0x01, 0x00, 0x01, /* org..... */
938 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, /* ........ */
939 0x0d, 0xd8, 0x00, 0x12, 0x0c, 0x73, 0x75, 0x72, /* .....sur */
940 0x69, 0x63, 0x61, 0x74, 0x61, 0x2d, 0x69, 0x64, /* icata-id */
941 0x73, 0x03, 0x6f, 0x72, 0x67, 0x00, 0xc0, 0x32, /* s.org..2 */
942 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xf4, /* ........ */
943 0x00, 0x04, 0xc0, 0x00, 0x4e, 0x18, 0xc0, 0x32, /* ....N..2 */
944 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xf4, /* ........ */
945 0x00, 0x04, 0xc0, 0x00, 0x4e, 0x19 /* ....N. */
946 ];
947
948 // The DNS payload starts at offset 42.
949 let dns_payload = &buf[42..];
950
951 // Make a TCP DNS response payload.
952 let mut request = Vec::new();
953 request.push(((dns_payload.len() as u16) >> 8) as u8);
954 request.push(((dns_payload.len() as u16) & 0xff) as u8);
955 request.extend(dns_payload);
956
957 let mut state = DNSState::new();
958 assert_eq!(1, state.parse_response_tcp(&request));
959 }
960
961 // Test that a TCP DNS payload won't be parsed if there is not
962 // enough data.
963 #[test]
964 fn test_dns_parse_response_tcp_short_payload() {
965 // A UDP DNS response with the DNS payload starting at byte 42.
966 // From pcap: https://github.com/jasonish/suricata-verify/blob/7cc0e1bd0a5249b52e6e87d82d57c0b6aaf75fce/dns-udp-dig-a-www-suricata-ids-org/dig-a-www.suricata-ids.org.pcap
967 let buf: &[u8] = &[
968 0xd8, 0xcb, 0x8a, 0xed, 0xa1, 0x46, 0x00, 0x15, /* .....F.. */
969 0x17, 0x0d, 0x06, 0xf7, 0x08, 0x00, 0x45, 0x00, /* ......E. */
970 0x00, 0x80, 0x65, 0x4e, 0x40, 0x00, 0x40, 0x11, /* ..eN@.@. */
971 0xbe, 0xf3, 0x0a, 0x10, 0x01, 0x01, 0x0a, 0x10, /* ........ */
972 0x01, 0x0b, 0x00, 0x35, 0xa3, 0x4d, 0x00, 0x6c, /* ...5.M.l */
973 0x8d, 0x8c, 0x8d, 0x32, 0x81, 0xa0, 0x00, 0x01, /* ...2.... */
974 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, /* .......w */
975 0x77, 0x77, 0x0c, 0x73, 0x75, 0x72, 0x69, 0x63, /* ww.suric */
976 0x61, 0x74, 0x61, 0x2d, 0x69, 0x64, 0x73, 0x03, /* ata-ids. */
977 0x6f, 0x72, 0x67, 0x00, 0x00, 0x01, 0x00, 0x01, /* org..... */
978 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, /* ........ */
979 0x0d, 0xd8, 0x00, 0x12, 0x0c, 0x73, 0x75, 0x72, /* .....sur */
980 0x69, 0x63, 0x61, 0x74, 0x61, 0x2d, 0x69, 0x64, /* icata-id */
981 0x73, 0x03, 0x6f, 0x72, 0x67, 0x00, 0xc0, 0x32, /* s.org..2 */
982 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xf4, /* ........ */
983 0x00, 0x04, 0xc0, 0x00, 0x4e, 0x18, 0xc0, 0x32, /* ....N..2 */
984 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xf4, /* ........ */
985 0x00, 0x04, 0xc0, 0x00, 0x4e, 0x19 /* ....N. */
986 ];
987
988 // The DNS payload starts at offset 42.
989 let dns_payload = &buf[42..];
990
991 // Make a TCP DNS response payload, but make the length 1 byte
992 // larger than the actual size.
993 let mut request = Vec::new();
994 request.push(((dns_payload.len() as u16) >> 8) as u8);
995 request.push((((dns_payload.len() as u16) & 0xff) + 1) as u8);
996 request.extend(dns_payload);
997
998 let mut state = DNSState::new();
999 assert_eq!(0, state.parse_response_tcp(&request));
73388042
JI
1000 }
1001}