suricata
app-layer-dns-tcp.c
Go to the documentation of this file.
1 /* Copyright (C) 2013 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 
18 /**
19  * \file
20  * \author Victor Julien <victor@inliniac.net>
21  */
22 
24 #include "suricata.h"
25 
26 #include "debug.h"
27 #include "decode.h"
28 
29 #include "flow-util.h"
30 
31 #include "threads.h"
32 
33 #include "util-print.h"
34 #include "util-pool.h"
35 #include "util-debug.h"
36 
37 #include "stream-tcp-private.h"
38 #include "stream-tcp-reassemble.h"
39 #include "stream-tcp.h"
40 #include "stream.h"
41 
42 #include "app-layer-protos.h"
43 #include "app-layer-parser.h"
44 
45 #include "util-spm.h"
46 #include "util-unittest.h"
47 
48 #include "app-layer-dns-tcp.h"
49 
50 #ifdef HAVE_RUST
51 #include "app-layer-dns-tcp-rust.h"
52 #endif
53 
54 #ifndef HAVE_RUST
55 struct DNSTcpHeader_ {
56  uint16_t len;
57  uint16_t tx_id;
58  uint16_t flags;
59  uint16_t questions;
60  uint16_t answer_rr;
61  uint16_t authority_rr;
62  uint16_t additional_rr;
63 } __attribute__((__packed__));
64 typedef struct DNSTcpHeader_ DNSTcpHeader;
65 
66 static uint16_t DNSTcpProbingParser(Flow *f, uint8_t *input, uint32_t ilen);
67 
68 /** \internal
69  * \param input_len at least enough for the DNSTcpHeader
70  */
71 static int DNSTCPRequestParseProbe(uint8_t *input, uint32_t input_len)
72 {
73 #ifdef DEBUG
74  BUG_ON(input_len < sizeof(DNSTcpHeader));
75 #endif
76  SCLogDebug("starting %u", input_len);
77 
78  DNSTcpHeader *dns_tcp_header = (DNSTcpHeader *)input;
79  if (SCNtohs(dns_tcp_header->len) < sizeof(DNSHeader)) {
80  goto bad_data;
81  }
82  if (SCNtohs(dns_tcp_header->len) >= input_len) {
83  goto insufficient_data;
84  }
85 
86  input += 2;
87  input_len -= 2;
88  DNSHeader *dns_header = (DNSHeader *)input;
89 
90  uint16_t q;
91  const uint8_t *data = input + sizeof(DNSHeader);
92 
93  for (q = 0; q < SCNtohs(dns_header->questions); q++) {
94  uint16_t fqdn_offset = 0;
95 
96  if (input + input_len < data + 1) {
97  SCLogDebug("input buffer too small for len field");
98  goto insufficient_data;
99  }
100  SCLogDebug("query length %u", *data);
101 
102  while (*data != 0) {
103  if (*data > 63) {
104  /** \todo set event?*/
105  goto bad_data;
106  }
107  uint8_t length = *data;
108 
109  data++;
110 
111  if (length > 0) {
112  if (input + input_len < data + length) {
113  SCLogDebug("input buffer too small for domain of len %u", length);
114  goto insufficient_data;
115  }
116  //PrintRawDataFp(stdout, data, qry->length);
117 
118  if ((fqdn_offset + length + 1) < DNS_MAX_SIZE) {
119  fqdn_offset += length;
120  } else {
121  /** \todo set event? */
122  goto bad_data;
123  }
124  }
125 
126  data += length;
127 
128  if (input + input_len < data + 1) {
129  SCLogDebug("input buffer too small for new len");
130  goto insufficient_data;
131  }
132 
133  SCLogDebug("qry length %u", *data);
134  }
135  if (fqdn_offset) {
136  fqdn_offset--;
137  }
138 
139  data++;
140  if (input + input_len < data + sizeof(DNSQueryTrailer)) {
141  SCLogDebug("input buffer too small for DNSQueryTrailer");
142  goto insufficient_data;
143  }
144 #ifdef DEBUG
145  DNSQueryTrailer *trailer = (DNSQueryTrailer *)data;
146  SCLogDebug("trailer type %04x class %04x", SCNtohs(trailer->type), SCNtohs(trailer->class));
147 #endif
148  data += sizeof(DNSQueryTrailer);
149  }
150 
151  SCReturnInt(1);
152 insufficient_data:
153  SCReturnInt(0);
154 bad_data:
155  SCReturnInt(-1);
156 }
157 
158 static int BufferData(DNSState *dns_state, uint8_t *data, uint16_t len)
159 {
160  if (dns_state->buffer == NULL) {
161  if (DNSCheckMemcap(0xffff, dns_state) < 0)
162  return -1;
163 
164  /** \todo be smarter about this, like use a pool or several pools for
165  * chunks of various sizes */
166  dns_state->buffer = SCMalloc(0xffff);
167  if (dns_state->buffer == NULL) {
168  return -1;
169  }
170  DNSIncrMemcap(0xffff, dns_state);
171  }
172 
173  if ((uint32_t)len + (uint32_t)dns_state->offset > (uint32_t)dns_state->record_len) {
174  SCLogDebug("oh my, we have more data than the max record size. What do we do. WHAT DO WE DOOOOO!");
175 #ifdef DEBUG
176  BUG_ON(1);
177 #endif
178  len = dns_state->record_len - dns_state->offset;
179  }
180 
181  memcpy(dns_state->buffer + dns_state->offset, data, len);
182  dns_state->offset += len;
183  return 0;
184 }
185 
186 static void BufferReset(DNSState *dns_state)
187 {
188  dns_state->record_len = 0;
189  dns_state->offset = 0;
190 }
191 
192 static int DNSRequestParseData(Flow *f, DNSState *dns_state, const uint8_t *input, const uint32_t input_len)
193 {
194  DNSHeader *dns_header = (DNSHeader *)input;
195 
196  if (DNSValidateRequestHeader(dns_state, dns_header) < 0)
197  goto bad_data;
198 
199  //SCLogInfo("ID %04x", SCNtohs(dns_header->tx_id));
200 
201  uint16_t q;
202  const uint8_t *data = input + sizeof(DNSHeader);
203 
204  //PrintRawDataFp(stdout, (uint8_t*)data, input_len - (data - input));
205 
206  if (dns_state != NULL) {
207  if (timercmp(&dns_state->last_req, &dns_state->last_resp, >=)) {
208  if (dns_state->window <= dns_state->unreplied_cnt) {
209  dns_state->window++;
210  }
211  }
212  }
213 
214  for (q = 0; q < SCNtohs(dns_header->questions); q++) {
215  uint8_t fqdn[DNS_MAX_SIZE];
216  uint16_t fqdn_offset = 0;
217 
218  if (input + input_len < data + 1) {
219  SCLogDebug("input buffer too small for DNSTcpQuery");
220  goto insufficient_data;
221  }
222  SCLogDebug("query length %u", *data);
223 
224  while (*data != 0) {
225  if (*data > 63) {
226  /** \todo set event?*/
227  goto insufficient_data;
228  }
229  uint8_t length = *data;
230 
231  data++;
232 
233  if (length > 0) {
234  if (input + input_len < data + length) {
235  SCLogDebug("input buffer too small for domain of len %u", length);
236  goto insufficient_data;
237  }
238  //PrintRawDataFp(stdout, data, qry->length);
239 
240  if ((size_t)(fqdn_offset + length + 1) < sizeof(fqdn)) {
241  memcpy(fqdn + fqdn_offset, data, length);
242  fqdn_offset += length;
243  fqdn[fqdn_offset++] = '.';
244  } else {
245  /** \todo set event? */
246  goto insufficient_data;
247  }
248  }
249 
250  data += length;
251 
252  if (input + input_len < data + 1) {
253  SCLogDebug("input buffer too small for DNSTcpQuery(2)");
254  goto insufficient_data;
255  }
256 
257  SCLogDebug("qry length %u", *data);
258  }
259  if (fqdn_offset) {
260  fqdn_offset--;
261  }
262 
263  data++;
264  if (input + input_len < data + sizeof(DNSQueryTrailer)) {
265  SCLogDebug("input buffer too small for DNSQueryTrailer");
266  goto insufficient_data;
267  }
268  DNSQueryTrailer *trailer = (DNSQueryTrailer *)data;
269  SCLogDebug("trailer type %04x class %04x", SCNtohs(trailer->type), SCNtohs(trailer->class));
270  data += sizeof(DNSQueryTrailer);
271 
272  /* store our data */
273  if (dns_state != NULL) {
274  DNSStoreQueryInState(dns_state, fqdn, fqdn_offset,
275  SCNtohs(trailer->type), SCNtohs(trailer->class),
276  SCNtohs(dns_header->tx_id));
277  }
278  }
279 
280  SCReturnInt(1);
281 bad_data:
282 insufficient_data:
283  SCReturnInt(-1);
284 
285 }
286 
287 /** \internal
288  * \brief Parse DNS request packet
289  */
290 static int DNSTCPRequestParse(Flow *f, void *dstate,
291  AppLayerParserState *pstate,
292  uint8_t *input, uint32_t input_len,
293  void *local_data, const uint8_t flags)
294 {
295  DNSState *dns_state = (DNSState *)dstate;
296  SCLogDebug("starting %u", input_len);
297 
298  if (input == NULL && input_len > 0) {
299  SCLogDebug("Input is NULL, but len is %"PRIu32": must be a gap.",
300  input_len);
301  dns_state->gap_ts = 1;
302  SCReturnInt(1);
303  }
304 
305  if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) {
306  SCReturnInt(1);
307  }
308 
309  /** \todo remove this when PP is fixed to enforce ipproto */
310  if (f != NULL && f->proto != IPPROTO_TCP)
311  SCReturnInt(-1);
312 
313  /* probably a rst/fin sending an eof */
314  if (input == NULL || input_len == 0) {
315  goto insufficient_data;
316  }
317 
318  /* Clear gap state. */
319  if (dns_state->gap_ts) {
320  if (DNSTcpProbingParser(f, input, input_len) == ALPROTO_DNS) {
321  SCLogDebug("New data probed as DNS, clearing gap state.");
322  BufferReset(dns_state);
323  dns_state->gap_ts = 0;
324  } else {
325  SCLogDebug("Unable to sync DNS parser, leaving gap state.");
326  SCReturnInt(1);
327  }
328  }
329 
330 next_record:
331  /* if this is the beginning of a record, we need at least the header */
332  if (dns_state->offset == 0 && input_len < sizeof(DNSTcpHeader)) {
333  SCLogDebug("ilen too small, hoped for at least %"PRIuMAX, (uintmax_t)sizeof(DNSTcpHeader));
334  goto insufficient_data;
335  }
336  SCLogDebug("input_len %u offset %u record %u",
337  input_len, dns_state->offset, dns_state->record_len);
338 
339  /* this is the first data of this record */
340  if (dns_state->offset == 0) {
341  DNSTcpHeader *dns_tcp_header = (DNSTcpHeader *)input;
342  SCLogDebug("DNS %p", dns_tcp_header);
343 
344  if (SCNtohs(dns_tcp_header->len) < sizeof(DNSHeader)) {
345  /* bogus len, doesn't fit even basic dns header */
346  goto bad_data;
347  } else if (SCNtohs(dns_tcp_header->len) == (input_len-2)) {
348  /* we have all data, so process w/o buffering */
349  if (DNSRequestParseData(f, dns_state, input+2, input_len-2) < 0)
350  goto bad_data;
351 
352  } else if ((input_len-2) > SCNtohs(dns_tcp_header->len)) {
353  /* we have all data, so process w/o buffering */
354  if (DNSRequestParseData(f, dns_state, input+2, SCNtohs(dns_tcp_header->len)) < 0)
355  goto bad_data;
356 
357  /* treat the rest of the data as a (potential) new record */
358  input += (2 + SCNtohs(dns_tcp_header->len));
359  input_len -= (2 + SCNtohs(dns_tcp_header->len));
360  goto next_record;
361  } else {
362  /* not enough data, store record length and buffer */
363  dns_state->record_len = SCNtohs(dns_tcp_header->len);
364  BufferData(dns_state, input+2, input_len-2);
365  }
366  } else if (input_len + dns_state->offset < dns_state->record_len) {
367  /* we don't have the full record yet, buffer */
368  BufferData(dns_state, input, input_len);
369  } else if (input_len > (uint32_t)(dns_state->record_len - dns_state->offset)) {
370  /* more data than expected, we may have another record coming up */
371  uint16_t need = (dns_state->record_len - dns_state->offset);
372  BufferData(dns_state, input, need);
373  int r = DNSRequestParseData(f, dns_state, dns_state->buffer, dns_state->record_len);
374  BufferReset(dns_state);
375  if (r < 0)
376  goto bad_data;
377 
378  /* treat the rest of the data as a (potential) new record */
379  input += need;
380  input_len -= need;
381  goto next_record;
382  } else {
383  /* implied exactly the amount of data we want
384  * add current to buffer, then inspect buffer */
385  BufferData(dns_state, input, input_len);
386  int r = DNSRequestParseData(f, dns_state, dns_state->buffer, dns_state->record_len);
387  BufferReset(dns_state);
388  if (r < 0)
389  goto bad_data;
390  }
391 
392  if (f != NULL) {
393  dns_state->last_req = f->lastts;
394  }
395 
396  SCReturnInt(1);
397 insufficient_data:
398  SCReturnInt(-1);
399 bad_data:
400  SCReturnInt(-1);
401 }
402 
403 static int DNSReponseParseData(Flow *f, DNSState *dns_state, const uint8_t *input, const uint32_t input_len)
404 {
405  DNSHeader *dns_header = (DNSHeader *)input;
406 
407  if (DNSValidateResponseHeader(dns_state, dns_header) < 0)
408  goto bad_data;
409 
410  DNSTransaction *tx = NULL;
411  int found = 0;
412  if ((tx = DNSTransactionFindByTxId(dns_state, SCNtohs(dns_header->tx_id))) != NULL)
413  found = 1;
414 
415  if (!found) {
416  SCLogDebug("DNS_DECODER_EVENT_UNSOLLICITED_RESPONSE");
418  } else if (dns_state->unreplied_cnt > 0) {
419  dns_state->unreplied_cnt--;
420  }
421 
422  uint16_t q;
423  const uint8_t *data = input + sizeof(DNSHeader);
424  for (q = 0; q < SCNtohs(dns_header->questions); q++) {
425  uint8_t fqdn[DNS_MAX_SIZE];
426  uint16_t fqdn_offset = 0;
427 
428  if (input + input_len < data + 1) {
429  SCLogDebug("input buffer too small for len field");
430  goto insufficient_data;
431  }
432  SCLogDebug("qry length %u", *data);
433 
434  while (*data != 0) {
435  uint8_t length = *data;
436  data++;
437 
438  if (length > 0) {
439  if (input + input_len < data + length) {
440  SCLogDebug("input buffer too small for domain of len %u", length);
441  goto insufficient_data;
442  }
443  //PrintRawDataFp(stdout, data, length);
444 
445  if ((size_t)(fqdn_offset + length + 1) < sizeof(fqdn)) {
446  memcpy(fqdn + fqdn_offset, data, length);
447  fqdn_offset += length;
448  fqdn[fqdn_offset++] = '.';
449  }
450  }
451 
452  data += length;
453 
454  if (input + input_len < data + 1) {
455  SCLogDebug("input buffer too small for len field");
456  goto insufficient_data;
457  }
458 
459  SCLogDebug("length %u", *data);
460  }
461  if (fqdn_offset) {
462  fqdn_offset--;
463  }
464 
465  data++;
466  if (input + input_len < data + sizeof(DNSQueryTrailer)) {
467  SCLogDebug("input buffer too small for DNSQueryTrailer");
468  goto insufficient_data;
469  }
470 #if DEBUG
471  DNSQueryTrailer *trailer = (DNSQueryTrailer *)data;
472  SCLogDebug("trailer type %04x class %04x", SCNtohs(trailer->type), SCNtohs(trailer->class));
473 #endif
474  data += sizeof(DNSQueryTrailer);
475  }
476 
477  for (q = 0; q < SCNtohs(dns_header->answer_rr); q++) {
478  data = DNSReponseParse(dns_state, dns_header, q, DNS_LIST_ANSWER,
479  input, input_len, data);
480  if (data == NULL) {
481  goto insufficient_data;
482  }
483  }
484 
485  //PrintRawDataFp(stdout, (uint8_t *)data, input_len - (data - input));
486  for (q = 0; q < SCNtohs(dns_header->authority_rr); q++) {
487  data = DNSReponseParse(dns_state, dns_header, q, DNS_LIST_AUTHORITY,
488  input, input_len, data);
489  if (data == NULL) {
490  goto insufficient_data;
491  }
492  }
493 
494  /* parse rcode, e.g. "noerror" or "nxdomain" */
495  uint8_t rcode = SCNtohs(dns_header->flags) & 0x0F;
496  if (rcode <= DNS_RCODE_NOTZONE) {
497  SCLogDebug("rcode %u", rcode);
498  if (tx != NULL)
499  tx->rcode = rcode;
500  } else {
501  /* this is not invalid, rcodes can be user defined */
502  SCLogDebug("unexpected DNS rcode %u", rcode);
503  }
504 
505  if (SCNtohs(dns_header->flags) & 0x0080) {
506  SCLogDebug("recursion desired");
507  if (tx != NULL)
508  tx->recursion_desired = 1;
509  }
510 
511  if (tx != NULL) {
512  tx->flags = ntohs(dns_header->flags);
513  tx->replied = 1;
514  }
515 
516  SCReturnInt(1);
517 bad_data:
518 insufficient_data:
519  SCReturnInt(-1);
520 }
521 
522 /** \internal
523  * \brief DNS TCP record parser, entry function
524  *
525  * Parses a DNS TCP record and fills the DNS state
526  *
527  * As TCP records can be 64k we'll have to buffer the data. Streaming parsing
528  * would have been _very_ tricky due to the way names are compressed in DNS
529  *
530  */
531 static int DNSTCPResponseParse(Flow *f, void *dstate,
532  AppLayerParserState *pstate,
533  uint8_t *input, uint32_t input_len,
534  void *local_data, const uint8_t flags)
535 {
536  DNSState *dns_state = (DNSState *)dstate;
537 
538  if (input == NULL && input_len > 0) {
539  SCLogDebug("Input is NULL, but len is %"PRIu32": must be a gap.",
540  input_len);
541  dns_state->gap_tc = 1;
542  SCReturnInt(1);
543  }
544 
545  if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) {
546  SCReturnInt(1);
547  }
548 
549  /** \todo remove this when PP is fixed to enforce ipproto */
550  if (f != NULL && f->proto != IPPROTO_TCP)
551  SCReturnInt(-1);
552 
553  /* probably a rst/fin sending an eof */
554  if (input == NULL || input_len == 0) {
555  goto insufficient_data;
556  }
557 
558  /* Clear gap state. */
559  if (dns_state->gap_tc) {
560  if (DNSTcpProbingParser(f, input, input_len) == ALPROTO_DNS) {
561  SCLogDebug("New data probed as DNS, clearing gap state.");
562  BufferReset(dns_state);
563  dns_state->gap_tc = 0;
564  } else {
565  SCLogDebug("Unable to sync DNS parser, leaving gap state.");
566  SCReturnInt(1);
567  }
568  }
569 
570 next_record:
571  /* if this is the beginning of a record, we need at least the header */
572  if (dns_state->offset == 0 && input_len < sizeof(DNSTcpHeader)) {
573  SCLogDebug("ilen too small, hoped for at least %"PRIuMAX, (uintmax_t)sizeof(DNSTcpHeader));
574  goto insufficient_data;
575  }
576  SCLogDebug("input_len %u offset %u record %u",
577  input_len, dns_state->offset, dns_state->record_len);
578 
579  /* this is the first data of this record */
580  if (dns_state->offset == 0) {
581  DNSTcpHeader *dns_tcp_header = (DNSTcpHeader *)input;
582  SCLogDebug("DNS %p", dns_tcp_header);
583 
584  if (SCNtohs(dns_tcp_header->len) == 0) {
585  goto bad_data;
586  } else if (SCNtohs(dns_tcp_header->len) == (input_len-2)) {
587  /* we have all data, so process w/o buffering */
588  if (DNSReponseParseData(f, dns_state, input+2, input_len-2) < 0)
589  goto bad_data;
590 
591  } else if ((input_len-2) > SCNtohs(dns_tcp_header->len)) {
592  /* we have all data, so process w/o buffering */
593  if (DNSReponseParseData(f, dns_state, input+2, SCNtohs(dns_tcp_header->len)) < 0)
594  goto bad_data;
595 
596  /* treat the rest of the data as a (potential) new record */
597  input += (2 + SCNtohs(dns_tcp_header->len));
598  input_len -= (2 + SCNtohs(dns_tcp_header->len));
599  goto next_record;
600  } else {
601  /* not enough data, store record length and buffer */
602  dns_state->record_len = SCNtohs(dns_tcp_header->len);
603  BufferData(dns_state, input+2, input_len-2);
604  }
605  } else if (input_len + dns_state->offset < dns_state->record_len) {
606  /* we don't have the full record yet, buffer */
607  BufferData(dns_state, input, input_len);
608  } else if (input_len > (uint32_t)(dns_state->record_len - dns_state->offset)) {
609  /* more data than expected, we may have another record coming up */
610  uint16_t need = (dns_state->record_len - dns_state->offset);
611  BufferData(dns_state, input, need);
612  int r = DNSReponseParseData(f, dns_state, dns_state->buffer, dns_state->record_len);
613  BufferReset(dns_state);
614  if (r < 0)
615  goto bad_data;
616 
617  /* treat the rest of the data as a (potential) new record */
618  input += need;
619  input_len -= need;
620  goto next_record;
621  } else {
622  /* implied exactly the amount of data we want
623  * add current to buffer, then inspect buffer */
624  BufferData(dns_state, input, input_len);
625  int r = DNSReponseParseData(f, dns_state, dns_state->buffer, dns_state->record_len);
626  BufferReset(dns_state);
627  if (r < 0)
628  goto bad_data;
629  }
630 
631  if (f != NULL) {
632  dns_state->last_resp = f->lastts;
633  }
634 
635  SCReturnInt(1);
636 insufficient_data:
637  SCReturnInt(-1);
638 bad_data:
639  SCReturnInt(-1);
640 }
641 
642 static uint16_t DNSTcpProbingParser(Flow *f, uint8_t *input, uint32_t ilen)
643 {
644  if (ilen == 0 || ilen < sizeof(DNSTcpHeader)) {
645  SCLogDebug("ilen too small, hoped for at least %"PRIuMAX, (uintmax_t)sizeof(DNSTcpHeader));
646  return ALPROTO_UNKNOWN;
647  }
648 
649  DNSTcpHeader *dns_header = (DNSTcpHeader *)input;
650  if (SCNtohs(dns_header->len) < sizeof(DNSHeader)) {
651  /* length field bogus, won't even fit a minimal DNS header. */
652  return ALPROTO_FAILED;
653  } else if (SCNtohs(dns_header->len) > ilen) {
654  int r = DNSTCPRequestParseProbe(input, ilen);
655  if (r == -1) {
656  /* probing parser told us "bad data", so it's not
657  * DNS */
658  return ALPROTO_FAILED;
659  } else if (ilen > 512) {
660  SCLogDebug("all the parser told us was not enough data, which is expected. Lets assume it's DNS");
661  return ALPROTO_DNS;
662  }
663 
664  SCLogDebug("not yet enough info %u > %u", SCNtohs(dns_header->len), ilen);
665  return ALPROTO_UNKNOWN;
666  }
667 
668  int r = DNSTCPRequestParseProbe(input, ilen);
669  if (r != 1)
670  return ALPROTO_FAILED;
671 
672  SCLogDebug("ALPROTO_DNS");
673  return ALPROTO_DNS;
674 }
675 
676 /**
677  * \brief Probing parser for TCP DNS responses.
678  *
679  * This is a minimal parser that just checks that the input contains enough
680  * data for a TCP DNS response.
681  */
682 static uint16_t DNSTcpProbeResponse(Flow *f, uint8_t *input, uint32_t len)
683 {
684  if (len == 0 || len < sizeof(DNSTcpHeader)) {
685  return ALPROTO_UNKNOWN;
686  }
687 
688  DNSTcpHeader *dns_header = (DNSTcpHeader *)input;
689 
690  if (SCNtohs(dns_header->len) < sizeof(DNSHeader)) {
691  return ALPROTO_FAILED;
692  }
693 
694  return ALPROTO_DNS;
695 }
696 #endif /* HAVE_RUST */
697 
699 {
700 #ifdef HAVE_RUST
702  return;
703 #else
704  const char *proto_name = "dns";
705  /** DNS */
706  if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
708 
709  if (RunmodeIsUnittests()) {
710  AppLayerProtoDetectPPRegister(IPPROTO_TCP,
711  "53",
712  ALPROTO_DNS,
713  0, sizeof(DNSTcpHeader),
715  DNSTcpProbingParser, NULL);
716  } else {
717  int have_cfg = AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP,
718  proto_name, ALPROTO_DNS,
719  0, sizeof(DNSTcpHeader),
720  DNSTcpProbingParser,
721  DNSTcpProbeResponse);
722  /* if we have no config, we enable the default port 53 */
723  if (!have_cfg) {
724  SCLogWarning(SC_ERR_DNS_CONFIG, "no DNS TCP config found, "
725  "enabling DNS detection on "
726  "port 53.");
727  AppLayerProtoDetectPPRegister(IPPROTO_TCP, "53",
728  ALPROTO_DNS, 0, sizeof(DNSTcpHeader),
729  STREAM_TOSERVER, DNSTcpProbingParser,
730  DNSTcpProbeResponse);
731  }
732  }
733  } else {
734  SCLogInfo("Protocol detection and parser disabled for %s protocol.",
735  proto_name);
736  return;
737  }
738 
739  if (AppLayerParserConfParserEnabled("tcp", proto_name)) {
741  DNSTCPRequestParse);
743  DNSTCPResponseParse);
745  DNSStateFree);
748 
754 
764 
765  /* This parser accepts gaps. */
768 
769  } else {
770  SCLogInfo("Parsed disabled for %s protocol. Protocol detection"
771  "still on.", proto_name);
772  }
773 #ifdef UNITTESTS
776 #endif
777  return;
778 #endif /* HAVE_RUST */
779 }
780 
781 /* UNITTESTS */
782 #ifndef HAVE_RUST
783 #ifdef UNITTESTS
784 
785 #include "util-unittest-helper.h"
786 
787 static int DNSTCPParserTestMultiRecord(void)
788 {
789  /* This is a buffer containing 20 DNS requests each prefixed by
790  * the request length for transport over TCP. It was generated with Scapy,
791  * where each request is:
792  * DNS(id=i, rd=1, qd=DNSQR(qname="%d.google.com" % i, qtype="A"))
793  * where i is 0 to 19.
794  */
795  uint8_t req[] = {
796  0x00, 0x1e, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
797  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x30,
798  0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
799  0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
800  0x00, 0x1e, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01,
801  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x31,
802  0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
803  0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
804  0x00, 0x1e, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01,
805  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x32,
806  0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
807  0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
808  0x00, 0x1e, 0x00, 0x03, 0x01, 0x00, 0x00, 0x01,
809  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x33,
810  0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
811  0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
812  0x00, 0x1e, 0x00, 0x04, 0x01, 0x00, 0x00, 0x01,
813  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x34,
814  0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
815  0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
816  0x00, 0x1e, 0x00, 0x05, 0x01, 0x00, 0x00, 0x01,
817  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x35,
818  0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
819  0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
820  0x00, 0x1e, 0x00, 0x06, 0x01, 0x00, 0x00, 0x01,
821  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x36,
822  0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
823  0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
824  0x00, 0x1e, 0x00, 0x07, 0x01, 0x00, 0x00, 0x01,
825  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x37,
826  0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
827  0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
828  0x00, 0x1e, 0x00, 0x08, 0x01, 0x00, 0x00, 0x01,
829  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x38,
830  0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
831  0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
832  0x00, 0x1e, 0x00, 0x09, 0x01, 0x00, 0x00, 0x01,
833  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x39,
834  0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
835  0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
836  0x00, 0x1f, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x01,
837  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x31,
838  0x30, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
839  0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00,
840  0x01, 0x00, 0x1f, 0x00, 0x0b, 0x01, 0x00, 0x00,
841  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
842  0x31, 0x31, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
843  0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01,
844  0x00, 0x01, 0x00, 0x1f, 0x00, 0x0c, 0x01, 0x00,
845  0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
846  0x02, 0x31, 0x32, 0x06, 0x67, 0x6f, 0x6f, 0x67,
847  0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00,
848  0x01, 0x00, 0x01, 0x00, 0x1f, 0x00, 0x0d, 0x01,
849  0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
850  0x00, 0x02, 0x31, 0x33, 0x06, 0x67, 0x6f, 0x6f,
851  0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00,
852  0x00, 0x01, 0x00, 0x01, 0x00, 0x1f, 0x00, 0x0e,
853  0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
854  0x00, 0x00, 0x02, 0x31, 0x34, 0x06, 0x67, 0x6f,
855  0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d,
856  0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x1f, 0x00,
857  0x0f, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
858  0x00, 0x00, 0x00, 0x02, 0x31, 0x35, 0x06, 0x67,
859  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f,
860  0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x1f,
861  0x00, 0x10, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
862  0x00, 0x00, 0x00, 0x00, 0x02, 0x31, 0x36, 0x06,
863  0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63,
864  0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
865  0x1f, 0x00, 0x11, 0x01, 0x00, 0x00, 0x01, 0x00,
866  0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x31, 0x37,
867  0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
868  0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
869  0x00, 0x1f, 0x00, 0x12, 0x01, 0x00, 0x00, 0x01,
870  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x31,
871  0x38, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
872  0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00,
873  0x01, 0x00, 0x1f, 0x00, 0x13, 0x01, 0x00, 0x00,
874  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
875  0x31, 0x39, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
876  0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01,
877  0x00, 0x01
878  };
879  size_t reqlen = sizeof(req);
880 
881  DNSState *state = DNSStateAlloc();
882  FAIL_IF_NULL(state);
883  Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 53);
884  FAIL_IF_NULL(f);
885  f->proto = IPPROTO_TCP;
886  f->alproto = ALPROTO_DNS;
887  f->alstate = state;
888 
889  FAIL_IF_NOT(DNSTCPRequestParse(f, f->alstate, NULL, req, reqlen, NULL, STREAM_START));
890  FAIL_IF(state->transaction_max != 20);
891 
892  UTHFreeFlow(f);
893  PASS;
894 }
895 
897 {
898  UtRegisterTest("DNSTCPParserTestMultiRecord", DNSTCPParserTestMultiRecord);
899 }
900 
901 #endif /* UNITTESTS */
902 #endif /* HAVE_RUST */
uint16_t additional_rr
void DNSIncrMemcap(uint32_t size, DNSState *state)
#define SCLogDebug(...)
Definition: util-debug.h:335
int DNSGetAlstateProgressCompletionStatus(uint8_t direction)
get value for &#39;complete&#39; status in DNS
void AppLayerParserRegisterOptionFlags(uint8_t ipproto, AppProto alproto, uint32_t flags)
AppLayerDecoderEvents * DNSGetEvents(void *state, uint64_t id)
void AppLayerProtoDetectPPRegister(uint8_t ipproto, const char *portstr, AppProto alproto, uint16_t min_depth, uint16_t max_depth, uint8_t direction, ProbingParserFPtr ProbingParser1, ProbingParserFPtr ProbingParser2)
register parser at a port
uint64_t DNSGetTxDetectFlags(void *vtx, uint8_t dir)
void AppLayerParserRegisterGetStateProgressFunc(uint8_t ipproto, AppProto alproto, int(*StateGetProgress)(void *alstate, uint8_t direction))
#define BUG_ON(x)
uint8_t proto
Definition: flow.h:346
Per flow DNS state container.
#define PASS
Pass the test.
void DNSSetTxDetectFlags(void *vtx, uint8_t dir, uint64_t detect_flags)
void * DNSStateAlloc(void)
int AppLayerProtoDetectConfProtoDetectionEnabled(const char *ipproto, const char *alproto)
Given a protocol name, checks if proto detection is enabled in the conf file.
void DNSStoreQueryInState(DNSState *dns_state, const uint8_t *fqdn, const uint16_t fqdn_len, const uint16_t type, const uint16_t class, const uint16_t tx_id)
void AppLayerParserRegisterDetectFlagsFuncs(uint8_t ipproto, AppProto alproto, uint64_t(*GetTxDetectFlags)(void *tx, uint8_t dir), void(*SetTxDetectFlags)(void *tx, uint8_t dir, uint64_t))
int AppLayerParserStateIssetFlag(AppLayerParserState *pstate, uint8_t flag)
void AppLayerParserRegisterDetectStateFuncs(uint8_t ipproto, AppProto alproto, DetectEngineState *(*GetTxDetectState)(void *tx), int(*SetTxDetectState)(void *tx, DetectEngineState *))
struct timeval last_req
LoggerId DNSGetTxLogged(void *alstate, void *tx)
DNS Transaction, request/reply with same TX id.
#define FAIL_IF(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:71
void RegisterDNSTCPParsers(void)
struct timeval last_resp
void AppLayerParserRegisterLoggerFuncs(uint8_t ipproto, AppProto alproto, LoggerId(*StateGetTxLogged)(void *, void *), void(*StateSetTxLogged)(void *, void *, LoggerId))
struct DNSTcpHeader_ __attribute__((__packed__))
DNP3 link header.
int DNSCheckMemcap(uint32_t want, DNSState *state)
DNSTransaction * DNSTransactionFindByTxId(const DNSState *dns_state, const uint16_t tx_id)
void * alstate
Definition: flow.h:436
int AppLayerParserConfParserEnabled(const char *ipproto, const char *alproto_name)
check if a parser is enabled in the config Returns enabled always if: were running unittests and when...
Flow * UTHBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp)
int AppLayerParserRegisterParser(uint8_t ipproto, AppProto alproto, uint8_t direction, AppLayerParserFPtr Parser)
Register app layer parser for the protocol.
void AppLayerParserRegisterGetTx(uint8_t ipproto, AppProto alproto, void *(StateGetTx)(void *alstate, uint64_t tx_id))
#define DNS_MAX_SIZE
int AppLayerProtoDetectPPParseConfPorts(const char *ipproto_name, uint8_t ipproto, const char *alproto_name, AppProto alproto, uint16_t min_depth, uint16_t max_depth, ProbingParserFPtr ProbingParserTs, ProbingParserFPtr ProbingParserTc)
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
DetectEngineState * DNSGetTxDetectState(void *vtx)
uint32_t unreplied_cnt
#define STREAM_TOCLIENT
Definition: stream.h:32
void DNSSetEvent(DNSState *s, uint8_t e)
void AppLayerParserRegisterGetStateProgressCompletionStatus(AppProto alproto, int(*StateGetProgressCompletionStatus)(uint8_t direction))
uint64_t DNSGetTxCnt(void *alstate)
int RunmodeIsUnittests(void)
Definition: suricata.c:261
int DNSValidateRequestHeader(DNSState *dns_state, const DNSHeader *dns_header)
Validation checks for DNS request header.
#define SCReturnInt(x)
Definition: util-debug.h:341
struct timeval lastts
Definition: flow.h:356
#define SCLogWarning(err_code,...)
Macro used to log WARNING messages.
Definition: util-debug.h:281
void * DNSGetTx(void *alstate, uint64_t tx_id)
void DNSStateFree(void *s)
uint16_t authority_rr
#define SCMalloc(a)
Definition: util-mem.h:174
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:254
void AppLayerProtoDetectRegisterProtocol(AppProto alproto, const char *alproto_name)
Registers a protocol for protocol detection phase.
#define SCNtohs(x)
int DNSValidateResponseHeader(DNSState *dns_state, const DNSHeader *dns_header)
Validation checks for DNS response header.
void AppLayerParserRegisterGetEventsFunc(uint8_t ipproto, AppProto alproto, AppLayerDecoderEvents *(*StateGetEvents)(void *, uint64_t))
void AppLayerParserRegisterProtocolUnittests(uint8_t ipproto, AppProto alproto, void(*RegisterUnittests)(void))
#define STREAM_START
Definition: stream.h:29
#define STREAM_TOSERVER
Definition: stream.h:31
#define APP_LAYER_PARSER_OPT_ACCEPT_GAPS
#define APP_LAYER_PARSER_EOF
void RegisterRustDNSTCPParsers(void)
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
uint16_t length
int DNSGetAlstateProgress(void *tx, uint8_t direction)
void AppLayerParserRegisterGetTxCnt(uint8_t ipproto, AppProto alproto, uint64_t(*StateGetTxCnt)(void *alstate))
void AppLayerParserRegisterStateFuncs(uint8_t ipproto, AppProto alproto, void *(*StateAlloc)(void), void(*StateFree)(void *))
void DNSStateTransactionFree(void *state, uint64_t tx_id)
dns transaction cleanup callback
AppProto alproto
application level protocol
Definition: flow.h:407
const uint8_t * DNSReponseParse(DNSState *dns_state, const DNSHeader *const dns_header, const uint16_t num, const DnsListEnum list, const uint8_t *const input, const uint32_t input_len, const uint8_t *data)
void DNSSetTxLogged(void *alstate, void *tx, LoggerId logged)
uint64_t transaction_max
int DNSSetTxDetectState(void *vtx, DetectEngineState *s)
Flow data structure.
Definition: flow.h:327
void DNSTCPParserRegisterTests(void)
#define FAIL_IF_NOT(expr)
Fail a test if expression to true.
Definition: util-unittest.h:82
#define DNS_RCODE_NOTZONE
void UTHFreeFlow(Flow *flow)
void DNSAppLayerRegisterGetEventInfo(uint8_t ipproto, AppProto alproto)
void AppLayerParserRegisterTxFreeFunc(uint8_t ipproto, AppProto alproto, void(*StateTransactionFree)(void *, uint64_t))