suricata
output-json-dns.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-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  *
21  * \author Tom DeCanio <td@npulsetech.com>
22  *
23  * Implements JSON DNS logging portion of the engine.
24  */
25 
26 #include "suricata-common.h"
27 #include "debug.h"
28 #include "detect.h"
29 #include "pkt-var.h"
30 #include "conf.h"
31 
32 #include "threads.h"
33 #include "threadvars.h"
34 #include "tm-threads.h"
35 
36 #include "util-print.h"
37 #include "util-unittest.h"
38 
39 #include "util-debug.h"
40 #include "util-mem.h"
41 #include "app-layer-parser.h"
42 #include "output.h"
43 #include "app-layer-dns-udp.h"
44 #include "app-layer.h"
45 #include "util-privs.h"
46 #include "util-buffer.h"
47 #include "util-proto-name.h"
48 #include "util-logopenfile.h"
49 #include "util-time.h"
50 
51 #include "output-json.h"
52 #include "output-json-dns.h"
53 
54 #ifdef HAVE_LIBJANSSON
55 
56 #ifdef HAVE_RUST
57 #include "rust-dns-log-gen.h"
58 #endif
59 
60 /* we can do query logging as well, but it's disabled for now as the
61  * TX id handling doesn't expect it */
62 #define QUERY 0
63 
64 #define LOG_QUERIES BIT_U64(0)
65 #define LOG_ANSWERS BIT_U64(1)
66 
67 #define LOG_A BIT_U64(2)
68 #define LOG_NS BIT_U64(3)
69 #define LOG_MD BIT_U64(4)
70 #define LOG_MF BIT_U64(5)
71 #define LOG_CNAME BIT_U64(6)
72 #define LOG_SOA BIT_U64(7)
73 #define LOG_MB BIT_U64(8)
74 #define LOG_MG BIT_U64(9)
75 #define LOG_MR BIT_U64(10)
76 #define LOG_NULL BIT_U64(11)
77 #define LOG_WKS BIT_U64(12)
78 #define LOG_PTR BIT_U64(13)
79 #define LOG_HINFO BIT_U64(14)
80 #define LOG_MINFO BIT_U64(15)
81 #define LOG_MX BIT_U64(16)
82 #define LOG_TXT BIT_U64(17)
83 #define LOG_RP BIT_U64(18)
84 #define LOG_AFSDB BIT_U64(19)
85 #define LOG_X25 BIT_U64(20)
86 #define LOG_ISDN BIT_U64(21)
87 #define LOG_RT BIT_U64(22)
88 #define LOG_NSAP BIT_U64(23)
89 #define LOG_NSAPPTR BIT_U64(24)
90 #define LOG_SIG BIT_U64(25)
91 #define LOG_KEY BIT_U64(26)
92 #define LOG_PX BIT_U64(27)
93 #define LOG_GPOS BIT_U64(28)
94 #define LOG_AAAA BIT_U64(29)
95 #define LOG_LOC BIT_U64(30)
96 #define LOG_NXT BIT_U64(31)
97 #define LOG_SRV BIT_U64(32)
98 #define LOG_ATMA BIT_U64(33)
99 #define LOG_NAPTR BIT_U64(34)
100 #define LOG_KX BIT_U64(35)
101 #define LOG_CERT BIT_U64(36)
102 #define LOG_A6 BIT_U64(37)
103 #define LOG_DNAME BIT_U64(38)
104 #define LOG_OPT BIT_U64(39)
105 #define LOG_APL BIT_U64(40)
106 #define LOG_DS BIT_U64(41)
107 #define LOG_SSHFP BIT_U64(42)
108 #define LOG_IPSECKEY BIT_U64(43)
109 #define LOG_RRSIG BIT_U64(44)
110 #define LOG_NSEC BIT_U64(45)
111 #define LOG_DNSKEY BIT_U64(46)
112 #define LOG_DHCID BIT_U64(47)
113 #define LOG_NSEC3 BIT_U64(48)
114 #define LOG_NSEC3PARAM BIT_U64(49)
115 #define LOG_TLSA BIT_U64(50)
116 #define LOG_HIP BIT_U64(51)
117 #define LOG_CDS BIT_U64(52)
118 #define LOG_CDNSKEY BIT_U64(53)
119 #define LOG_SPF BIT_U64(54)
120 #define LOG_TKEY BIT_U64(55)
121 #define LOG_TSIG BIT_U64(56)
122 #define LOG_MAILA BIT_U64(57)
123 #define LOG_ANY BIT_U64(58)
124 #define LOG_URI BIT_U64(59)
125 
126 #define LOG_FORMAT_GROUPED BIT_U64(60)
127 #define LOG_FORMAT_DETAILED BIT_U64(61)
128 
129 #define LOG_FORMAT_ALL (LOG_FORMAT_GROUPED|LOG_FORMAT_DETAILED)
130 #define LOG_ALL_RRTYPES (~(uint64_t)(LOG_QUERIES|LOG_ANSWERS|LOG_FORMAT_DETAILED|LOG_FORMAT_GROUPED))
131 
132 typedef enum {
133  DNS_RRTYPE_A = 0,
134  DNS_RRTYPE_NS,
135  DNS_RRTYPE_MD,
136  DNS_RRTYPE_MF,
137  DNS_RRTYPE_CNAME,
138  DNS_RRTYPE_SOA,
139  DNS_RRTYPE_MB,
140  DNS_RRTYPE_MG,
141  DNS_RRTYPE_MR,
142  DNS_RRTYPE_NULL,
143  DNS_RRTYPE_WKS,
144  DNS_RRTYPE_PTR,
145  DNS_RRTYPE_HINFO,
146  DNS_RRTYPE_MINFO,
147  DNS_RRTYPE_MX,
148  DNS_RRTYPE_TXT,
149  DNS_RRTYPE_RP,
150  DNS_RRTYPE_AFSDB,
151  DNS_RRTYPE_X25,
152  DNS_RRTYPE_ISDN,
153  DNS_RRTYPE_RT,
154  DNS_RRTYPE_NSAP,
155  DNS_RRTYPE_NSAPPTR,
156  DNS_RRTYPE_SIG,
157  DNS_RRTYPE_KEY,
158  DNS_RRTYPE_PX,
159  DNS_RRTYPE_GPOS,
160  DNS_RRTYPE_AAAA,
161  DNS_RRTYPE_LOC,
162  DNS_RRTYPE_NXT,
163  DNS_RRTYPE_SRV,
164  DNS_RRTYPE_ATMA,
165  DNS_RRTYPE_NAPTR,
166  DNS_RRTYPE_KX,
167  DNS_RRTYPE_CERT,
168  DNS_RRTYPE_A6,
169  DNS_RRTYPE_DNAME,
170  DNS_RRTYPE_OPT,
171  DNS_RRTYPE_APL,
172  DNS_RRTYPE_DS,
173  DNS_RRTYPE_SSHFP,
174  DNS_RRTYPE_IPSECKEY,
175  DNS_RRTYPE_RRSIG,
176  DNS_RRTYPE_NSEC,
177  DNS_RRTYPE_DNSKEY,
178  DNS_RRTYPE_DHCID,
179  DNS_RRTYPE_NSEC3,
180  DNS_RRTYPE_NSEC3PARAM,
181  DNS_RRTYPE_TLSA,
182  DNS_RRTYPE_HIP,
183  DNS_RRTYPE_CDS,
184  DNS_RRTYPE_CDNSKEY,
185  DNS_RRTYPE_SPF,
186  DNS_RRTYPE_TKEY,
187  DNS_RRTYPE_TSIG,
188  DNS_RRTYPE_MAILA,
189  DNS_RRTYPE_ANY,
190  DNS_RRTYPE_URI,
191  DNS_RRTYPE_MAX,
192 } DnsRRTypes;
193 
194 typedef enum {
195  DNS_VERSION_1 = 1,
196  DNS_VERSION_2
197 } DnsVersion;
198 
199 #ifdef HAVE_RUST
200 #define DNS_VERSION_DEFAULT DNS_VERSION_2
201 #else
202 #define DNS_VERSION_DEFAULT DNS_VERSION_1
203 #endif
204 
205 static struct {
206  const char *config_rrtype;
207  uint64_t flags;
208 } dns_rrtype_fields[] = {
209  { "a", LOG_A },
210  { "ns", LOG_NS },
211  { "md", LOG_MD },
212  { "mf", LOG_MF },
213  { "cname", LOG_CNAME },
214  { "soa", LOG_SOA },
215  { "mb", LOG_MB },
216  { "mg", LOG_MG },
217  { "mr", LOG_MR },
218  { "null", LOG_NULL },
219  { "wks", LOG_WKS },
220  { "ptr", LOG_PTR },
221  { "hinfo", LOG_HINFO },
222  { "minfo", LOG_MINFO },
223  { "mx", LOG_MX },
224  { "txt", LOG_TXT },
225  { "rp", LOG_RP },
226  { "afsdb", LOG_AFSDB },
227  { "x25", LOG_X25 },
228  { "isdn", LOG_ISDN },
229  { "rt", LOG_RT },
230  { "nsap", LOG_NSAP },
231  { "nsapptr", LOG_NSAPPTR },
232  { "sig", LOG_SIG },
233  { "key", LOG_KEY },
234  { "px", LOG_PX },
235  { "gpos", LOG_GPOS },
236  { "aaaa", LOG_AAAA },
237  { "loc", LOG_LOC },
238  { "nxt", LOG_NXT },
239  { "srv", LOG_SRV },
240  { "atma", LOG_ATMA },
241  { "naptr", LOG_NAPTR },
242  { "kx", LOG_KX },
243  { "cert", LOG_CERT },
244  { "a6", LOG_A6 },
245  { "dname", LOG_DNAME },
246  { "opt", LOG_OPT },
247  { "apl", LOG_APL },
248  { "ds", LOG_DS },
249  { "sshfp", LOG_SSHFP },
250  { "ipseckey", LOG_IPSECKEY },
251  { "rrsig", LOG_RRSIG },
252  { "nsec", LOG_NSEC },
253  { "dnskey", LOG_DNSKEY },
254  { "dhcid", LOG_DHCID },
255  { "nsec3", LOG_NSEC3 },
256  { "nsec3param", LOG_NSEC3PARAM },
257  { "tlsa", LOG_TLSA },
258  { "hip", LOG_HIP },
259  { "cds", LOG_CDS },
260  { "cdnskey", LOG_CDNSKEY },
261  { "spf", LOG_SPF },
262  { "tkey", LOG_TKEY },
263  { "tsig", LOG_TSIG },
264  { "maila", LOG_MAILA },
265  { "any", LOG_ANY },
266  { "uri", LOG_URI }
267 };
268 
269 typedef struct LogDnsFileCtx_ {
271  uint64_t flags; /** Store mode */
272  DnsVersion version;
273  OutputJsonCommonSettings cfg;
274 } LogDnsFileCtx;
275 
276 typedef struct LogDnsLogThread_ {
277  LogDnsFileCtx *dnslog_ctx;
278  /** LogFileCtx has the pointer to the file and a mutex to allow multithreading */
279  uint32_t dns_cnt;
280 
281  MemBuffer *buffer;
283 
284 #ifndef HAVE_RUST
285 static int DNSRRTypeEnabled(uint16_t type, uint64_t flags)
286 {
287  if (likely(flags == ~0UL)) {
288  return 1;
289  }
290 
291  switch (type) {
292  case DNS_RECORD_TYPE_A:
293  return ((flags & LOG_A) != 0) ? 1 : 0;
294  case DNS_RECORD_TYPE_NS:
295  return ((flags & LOG_NS) != 0) ? 1 : 0;
296  case DNS_RECORD_TYPE_MD:
297  return ((flags & LOG_MD) != 0) ? 1 : 0;
298  case DNS_RECORD_TYPE_MF:
299  return ((flags & LOG_MF) != 0) ? 1 : 0;
301  return ((flags & LOG_CNAME) != 0) ? 1 : 0;
302  case DNS_RECORD_TYPE_SOA:
303  return ((flags & LOG_SOA) != 0) ? 1 : 0;
304  case DNS_RECORD_TYPE_MB:
305  return ((flags & LOG_MB) != 0) ? 1 : 0;
306  case DNS_RECORD_TYPE_MG:
307  return ((flags & LOG_MG) != 0) ? 1 : 0;
308  case DNS_RECORD_TYPE_MR:
309  return ((flags & LOG_MR) != 0) ? 1 : 0;
311  return ((flags & LOG_NULL) != 0) ? 1 : 0;
312  case DNS_RECORD_TYPE_WKS:
313  return ((flags & LOG_WKS) != 0) ? 1 : 0;
314  case DNS_RECORD_TYPE_PTR:
315  return ((flags & LOG_PTR) != 0) ? 1 : 0;
317  return ((flags & LOG_HINFO) != 0) ? 1 : 0;
319  return ((flags & LOG_MINFO) != 0) ? 1 : 0;
320  case DNS_RECORD_TYPE_MX:
321  return ((flags & LOG_MX) != 0) ? 1 : 0;
322  case DNS_RECORD_TYPE_TXT:
323  return ((flags & LOG_TXT) != 0) ? 1 : 0;
324  case DNS_RECORD_TYPE_RP:
325  return ((flags & LOG_RP) != 0) ? 1 : 0;
327  return ((flags & LOG_AFSDB) != 0) ? 1 : 0;
328  case DNS_RECORD_TYPE_X25:
329  return ((flags & LOG_X25) != 0) ? 1 : 0;
331  return ((flags & LOG_ISDN) != 0) ? 1 : 0;
332  case DNS_RECORD_TYPE_RT:
333  return ((flags & LOG_RT) != 0) ? 1 : 0;
335  return ((flags & LOG_NSAP) != 0) ? 1 : 0;
337  return ((flags & LOG_NSAPPTR) != 0) ? 1 : 0;
338  case DNS_RECORD_TYPE_SIG:
339  return ((flags & LOG_SIG) != 0) ? 1 : 0;
340  case DNS_RECORD_TYPE_KEY:
341  return ((flags & LOG_KEY) != 0) ? 1 : 0;
342  case DNS_RECORD_TYPE_PX:
343  return ((flags & LOG_PX) != 0) ? 1 : 0;
345  return ((flags & LOG_GPOS) != 0) ? 1 : 0;
347  return ((flags & LOG_AAAA) != 0) ? 1 : 0;
348  case DNS_RECORD_TYPE_LOC:
349  return ((flags & LOG_LOC) != 0) ? 1 : 0;
350  case DNS_RECORD_TYPE_NXT:
351  return ((flags & LOG_NXT) != 0) ? 1 : 0;
352  case DNS_RECORD_TYPE_SRV:
353  return ((flags & LOG_SRV) != 0) ? 1 : 0;
355  return ((flags & LOG_ATMA) != 0) ? 1 : 0;
357  return ((flags & LOG_NAPTR) != 0) ? 1 : 0;
358  case DNS_RECORD_TYPE_KX:
359  return ((flags & LOG_KX) != 0) ? 1 : 0;
361  return ((flags & LOG_CERT) != 0) ? 1 : 0;
362  case DNS_RECORD_TYPE_A6:
363  return ((flags & LOG_A6) != 0) ? 1 : 0;
365  return ((flags & LOG_DNAME) != 0) ? 1 : 0;
366  case DNS_RECORD_TYPE_OPT:
367  return ((flags & LOG_OPT) != 0) ? 1 : 0;
368  case DNS_RECORD_TYPE_APL:
369  return ((flags & LOG_APL) != 0) ? 1 : 0;
370  case DNS_RECORD_TYPE_DS:
371  return ((flags & LOG_DS) != 0) ? 1 : 0;
373  return ((flags & LOG_SSHFP) != 0) ? 1 : 0;
375  return ((flags & LOG_IPSECKEY) != 0) ? 1 : 0;
377  return ((flags & LOG_RRSIG) != 0) ? 1 : 0;
379  return ((flags & LOG_NSEC) != 0) ? 1 : 0;
381  return ((flags & LOG_DNSKEY) != 0) ? 1 : 0;
383  return ((flags & LOG_DHCID) != 0) ? 1 : 0;
385  return ((flags & LOG_NSEC3) != 0) ? 1 : 0;
387  return ((flags & LOG_NSEC3PARAM) != 0) ? 1 : 0;
389  return ((flags & LOG_TLSA) != 0) ? 1 : 0;
390  case DNS_RECORD_TYPE_HIP:
391  return ((flags & LOG_HIP) != 0) ? 1 : 0;
392  case DNS_RECORD_TYPE_CDS:
393  return ((flags & LOG_CDS) != 0) ? 1 : 0;
395  return ((flags & LOG_CDNSKEY) != 0) ? 1 : 0;
396  case DNS_RECORD_TYPE_SPF:
397  return ((flags & LOG_SPF) != 0) ? 1 : 0;
399  return ((flags & LOG_TKEY) != 0) ? 1 : 0;
401  return ((flags & LOG_TSIG) != 0) ? 1 : 0;
403  return ((flags & LOG_MAILA) != 0) ? 1 : 0;
404  case DNS_RECORD_TYPE_ANY:
405  return ((flags & LOG_ANY) != 0) ? 1 : 0;
406  case DNS_RECORD_TYPE_URI:
407  return ((flags & LOG_URI) != 0) ? 1 : 0;
408  default:
409  return 0;
410  }
411 }
412 #endif
413 
414 #ifndef HAVE_RUST
415 static json_t *OutputQuery(DNSTransaction *tx, uint64_t tx_id, DNSQueryEntry *entry)
416 {
417  json_t *djs = json_object();
418  if (djs == NULL) {
419  return NULL;
420  }
421 
422  /* type */
423  json_object_set_new(djs, "type", json_string("query"));
424 
425  /* id */
426  json_object_set_new(djs, "id", json_integer(tx->tx_id));
427 
428  /* query */
429  char *c;
430  c = BytesToString((uint8_t *)((uint8_t *)entry + sizeof(DNSQueryEntry)), entry->len);
431  if (c != NULL) {
432  json_object_set_new(djs, "rrname", SCJsonString(c));
433  SCFree(c);
434  }
435 
436  /* name */
437  char record[16] = "";
438  DNSCreateTypeString(entry->type, record, sizeof(record));
439  json_object_set_new(djs, "rrtype", json_string(record));
440 
441  /* tx id (tx counter) */
442  json_object_set_new(djs, "tx_id", json_integer(tx_id));
443 
444  return djs;
445 }
446 
447 static void LogQuery(LogDnsLogThread *aft, json_t *js, DNSTransaction *tx,
448  uint64_t tx_id, DNSQueryEntry *entry)
449 {
450  SCLogDebug("got a DNS request and now logging !!");
451 
452  if (!DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags)) {
453  return;
454  }
455 
456  json_t *djs = OutputQuery(tx, tx_id, entry);
457  if (djs == NULL) {
458  return;
459  }
460 
461  /* reset */
462  MemBufferReset(aft->buffer);
463 
464  /* dns */
465  json_object_set_new(js, "dns", djs);
466  OutputJSONBuffer(js, aft->dnslog_ctx->file_ctx, &aft->buffer);
467  json_object_del(js, "dns");
468 }
469 #endif
470 
471 json_t *JsonDNSLogQuery(void *txptr, uint64_t tx_id)
472 {
473  json_t *queryjs = json_array();
474  if (queryjs == NULL)
475  return NULL;
476 
477 #ifdef HAVE_RUST
478  for (uint16_t i = 0; i < UINT16_MAX; i++) {
479  json_t *dns = rs_dns_log_json_query((void *)txptr, i, LOG_ALL_RRTYPES);
480  if (unlikely(dns == NULL)) {
481  break;
482  }
483  json_array_append_new(queryjs, dns);
484  }
485 #else
486  DNSTransaction *tx = txptr;
487  DNSQueryEntry *entry = NULL;
488  TAILQ_FOREACH(entry, &tx->query_list, next) {
489  json_t *qjs = OutputQuery(tx, tx_id, entry);
490  if (qjs != NULL) {
491  json_array_append_new(queryjs, qjs);
492  }
493  }
494 #endif
495 
496  return queryjs;
497 }
498 
499 #ifndef HAVE_RUST
500 
501 static json_t *DnsParseSshFpType(DNSAnswerEntry *entry, uint8_t *ptr)
502 {
503  /* get algo and type */
504  uint8_t algo = *ptr;
505  uint8_t fptype = *(ptr+1);
506 
507  /* turn fp raw buffer into a nice :-separate hex string */
508  uint16_t fp_len = (entry->data_len - 2);
509  uint8_t *dptr = ptr+2;
510 
511  /* c-string for ':' separated hex and trailing \0. */
512  uint32_t output_len = fp_len * 3 + 1;
513  char hexstring[output_len];
514  memset(hexstring, 0x00, output_len);
515 
516  uint16_t x;
517  for (x = 0; x < fp_len; x++) {
518  char one[4];
519  snprintf(one, sizeof(one), x == fp_len - 1 ? "%02x" : "%02x:", dptr[x]);
520  strlcat(hexstring, one, output_len);
521  }
522 
523  /* wrap the whole thing in it's own structure */
524  json_t *hjs = json_object();
525  if (hjs == NULL) {
526  return NULL;
527  }
528 
529  json_object_set_new(hjs, "fingerprint", json_string(hexstring));
530  json_object_set_new(hjs, "algo", json_integer(algo));
531  json_object_set_new(hjs, "type", json_integer(fptype));
532 
533  return hjs;
534 }
535 
536 static void OutputAnswerDetailed(DNSAnswerEntry *entry, json_t *js,
537  uint64_t flags)
538 {
539  do {
540  json_t *jdata = json_object();
541  if (jdata == NULL) {
542  return;
543  }
544 
545  /* query */
546  if (entry->fqdn_len > 0) {
547  char *c;
548  c = BytesToString((uint8_t *)((uint8_t *)entry + sizeof(DNSAnswerEntry)),
549  entry->fqdn_len);
550  if (c != NULL) {
551  json_object_set_new(jdata, "rrname", json_string(c));
552  SCFree(c);
553  }
554  }
555 
556  /* name */
557  char record[16] = "";
558  DNSCreateTypeString(entry->type, record, sizeof(record));
559  json_object_set_new(jdata, "rrtype", json_string(record));
560 
561  /* ttl */
562  json_object_set_new(jdata, "ttl", json_integer(entry->ttl));
563 
564  uint8_t *ptr = (uint8_t *)((uint8_t *)entry + sizeof(DNSAnswerEntry)+ entry->fqdn_len);
565  if (entry->type == DNS_RECORD_TYPE_A && entry->data_len == 4) {
566  char a[16] = "";
567  PrintInet(AF_INET, (const void *)ptr, a, sizeof(a));
568  json_object_set_new(jdata, "rdata", json_string(a));
569  } else if (entry->type == DNS_RECORD_TYPE_AAAA && entry->data_len == 16) {
570  char a[46] = "";
571  PrintInet(AF_INET6, (const void *)ptr, a, sizeof(a));
572  json_object_set_new(jdata, "rdata", json_string(a));
573  } else if (entry->data_len == 0) {
574  json_object_set_new(jdata, "rdata", json_string(""));
575  } else if (entry->type == DNS_RECORD_TYPE_TXT || entry->type == DNS_RECORD_TYPE_CNAME ||
576  entry->type == DNS_RECORD_TYPE_MX || entry->type == DNS_RECORD_TYPE_PTR ||
577  entry->type == DNS_RECORD_TYPE_NS) {
578  if (entry->data_len != 0) {
579  char buffer[256] = "";
580  uint16_t copy_len = entry->data_len < (sizeof(buffer) - 1) ?
581  entry->data_len : sizeof(buffer) - 1;
582  memcpy(buffer, ptr, copy_len);
583  buffer[copy_len] = '\0';
584  json_object_set_new(jdata, "rdata", json_string(buffer));
585  } else {
586  json_object_set_new(jdata, "rdata", json_string(""));
587  }
588  } else if (entry->type == DNS_RECORD_TYPE_SSHFP) {
589  if (entry->data_len > 2) {
590  json_t *hjs = DnsParseSshFpType(entry, ptr);
591  if (hjs != NULL) {
592  json_object_set_new(jdata, "sshfp", hjs);
593  }
594  }
595  }
596  json_array_append_new(js, jdata);
597  } while ((entry = TAILQ_NEXT(entry, next)));
598 }
599 
600 static void OutputAnswerGrouped(DNSAnswerEntry *entry, json_t *js)
601 {
602  struct {
603  #define ENTRY_TYPE_A 0
604  #define ENTRY_TYPE_AAAA 1
605  #define ENTRY_TYPE_TXT 2
606  #define ENTRY_TYPE_CNAME 3
607  #define ENTRY_TYPE_MX 4
608  #define ENTRY_TYPE_PTR 5
609  #define ENTRY_TYPE_NS 6
610  #define ENTRY_TYPE_SSHFP 7
611  #define ENTRY_TYPE_MAX 8
612  const char *name;
613  json_t *value;
614  } dns_rtypes[] = {
615  { "A", NULL },
616  { "AAAA", NULL },
617  { "TXT", NULL },
618  { "CNAME", NULL },
619  { "MX", NULL },
620  { "PTR", NULL },
621  { "NS", NULL },
622  { "SSHFP", NULL }
623  };
624 
625  int i;
626  json_t *jrdata = json_object();
627  if (jrdata == NULL) {
628  return;
629  }
630 
631  do {
632  uint8_t *ptr = (uint8_t *)((uint8_t *)entry + sizeof(DNSAnswerEntry)+ entry->fqdn_len);
633  if (entry->type == DNS_RECORD_TYPE_A && entry->data_len == 4) {
634  char a[16] = "";
635  if (dns_rtypes[ENTRY_TYPE_A].value == NULL) {
636  dns_rtypes[ENTRY_TYPE_A].value = json_array();
637  if (dns_rtypes[ENTRY_TYPE_A].value == NULL) {
638  goto out;
639  }
640  }
641  PrintInet(AF_INET, (const void *)ptr, a, sizeof(a));
642  json_array_append_new(dns_rtypes[ENTRY_TYPE_A].value, json_string(a));
643  } else if (entry->type == DNS_RECORD_TYPE_AAAA && entry->data_len == 16) {
644  char a[46] = "";
645  if (dns_rtypes[ENTRY_TYPE_AAAA].value == NULL) {
646  dns_rtypes[ENTRY_TYPE_AAAA].value = json_array();
647  if (dns_rtypes[ENTRY_TYPE_AAAA].value == NULL) {
648  goto out;
649  }
650  }
651  PrintInet(AF_INET6, (const void *)ptr, a, sizeof(a));
652  json_array_append_new(dns_rtypes[ENTRY_TYPE_AAAA].value, json_string(a));
653  } else if (entry->data_len == 0) {
654  json_object_set_new(js, "rdata", json_string(""));
655  } else if (entry->type == DNS_RECORD_TYPE_TXT || entry->type == DNS_RECORD_TYPE_CNAME ||
656  entry->type == DNS_RECORD_TYPE_MX || entry->type == DNS_RECORD_TYPE_PTR ||
657  entry->type == DNS_RECORD_TYPE_NS) {
658  if (entry->data_len != 0) {
659  char buffer[256] = "";
660  uint16_t copy_len = entry->data_len < (sizeof(buffer) - 1) ?
661  entry->data_len : sizeof(buffer) - 1;
662  memcpy(buffer, ptr, copy_len);
663  buffer[copy_len] = '\0';
664 
665  if (entry->type == DNS_RECORD_TYPE_TXT) {
666  if (dns_rtypes[ENTRY_TYPE_TXT].value == NULL) {
667  dns_rtypes[ENTRY_TYPE_TXT].value = json_array();
668  if (dns_rtypes[ENTRY_TYPE_TXT].value == NULL) {
669  goto out;
670  }
671  }
672  json_array_append_new(dns_rtypes[ENTRY_TYPE_TXT].value, json_string(buffer));
673  } else if (entry->type == DNS_RECORD_TYPE_CNAME) {
674  if (dns_rtypes[ENTRY_TYPE_CNAME].value == NULL) {
675  dns_rtypes[ENTRY_TYPE_CNAME].value = json_array();
676  if (dns_rtypes[ENTRY_TYPE_CNAME].value == NULL) {
677  goto out;
678  }
679  }
680  json_array_append_new(dns_rtypes[ENTRY_TYPE_CNAME].value, json_string(buffer));
681  } else if (entry->type == DNS_RECORD_TYPE_MX) {
682  if (dns_rtypes[ENTRY_TYPE_MX].value == NULL) {
683  dns_rtypes[ENTRY_TYPE_MX].value = json_array();
684  if (dns_rtypes[ENTRY_TYPE_MX].value == NULL) {
685  goto out;
686  }
687  }
688  json_array_append_new(dns_rtypes[ENTRY_TYPE_MX].value, json_string(buffer));
689  } else if (entry->type == DNS_RECORD_TYPE_PTR) {
690  if (dns_rtypes[ENTRY_TYPE_PTR].value == NULL) {
691  dns_rtypes[ENTRY_TYPE_PTR].value = json_array();
692  if (dns_rtypes[ENTRY_TYPE_PTR].value == NULL) {
693  goto out;
694  }
695  }
696  json_array_append_new(dns_rtypes[ENTRY_TYPE_PTR].value, json_string(buffer));
697  } else if (entry->type == DNS_RECORD_TYPE_NS) {
698  if (dns_rtypes[ENTRY_TYPE_NS].value == NULL) {
699  dns_rtypes[ENTRY_TYPE_NS].value = json_array();
700  if (dns_rtypes[ENTRY_TYPE_NS].value == NULL) {
701  goto out;
702  }
703  }
704  json_array_append_new(dns_rtypes[ENTRY_TYPE_NS].value, json_string(buffer));
705  }
706  } else {
707  json_object_set_new(js, "rdata", json_string(""));
708  }
709  } else if (entry->type == DNS_RECORD_TYPE_SSHFP) {
710  if (entry->data_len > 2) {
711  json_t *hjs = DnsParseSshFpType(entry, ptr);
712  if (hjs != NULL) {
713  if (dns_rtypes[ENTRY_TYPE_SSHFP].value == NULL) {
714  dns_rtypes[ENTRY_TYPE_SSHFP].value = json_array();
715  if (dns_rtypes[ENTRY_TYPE_SSHFP].value == NULL) {
716  goto out;
717  }
718  }
719  json_array_append_new(dns_rtypes[ENTRY_TYPE_SSHFP].value, hjs);
720  }
721  }
722  }
723  } while ((entry = TAILQ_NEXT(entry, next)));
724 
725 out:
726  for (i = 0; i < ENTRY_TYPE_MAX; i++) {
727  if (dns_rtypes[i].value != NULL) {
728  json_object_set_new(jrdata, dns_rtypes[i].name, dns_rtypes[i].value);
729  dns_rtypes[i].value = NULL;
730  }
731  }
732 
733  json_object_set_new(js, "grouped", jrdata);
734 }
735 
736 static void OutputAnswerV1(LogDnsLogThread *aft, json_t *djs,
737  DNSTransaction *tx, DNSAnswerEntry *entry)
738 {
739  if (!DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags)) {
740  return;
741  }
742 
743  json_t *js = json_object();
744  if (js == NULL)
745  return;
746 
747  /* type */
748  json_object_set_new(js, "type", json_string("answer"));
749 
750  /* id */
751  json_object_set_new(js, "id", json_integer(tx->tx_id));
752 
753  /* dns */
754  char flags[7] = "";
755  snprintf(flags, sizeof(flags), "%4x", tx->flags);
756  json_object_set_new(js, "flags", json_string(flags));
757  if (tx->flags & 0x8000)
758  json_object_set_new(js, "qr", json_true());
759  if (tx->flags & 0x0400)
760  json_object_set_new(js, "aa", json_true());
761  if (tx->flags & 0x0200)
762  json_object_set_new(js, "tc", json_true());
763  if (tx->flags & 0x0100)
764  json_object_set_new(js, "rd", json_true());
765  if (tx->flags & 0x0080)
766  json_object_set_new(js, "ra", json_true());
767 
768 
769  /* rcode */
770  char rcode[16] = "";
771  DNSCreateRcodeString(tx->rcode, rcode, sizeof(rcode));
772  json_object_set_new(js, "rcode", json_string(rcode));
773 
774  /* query */
775  if (entry->fqdn_len > 0) {
776  char *c;
777  c = BytesToString((uint8_t *)((uint8_t *)entry + sizeof(DNSAnswerEntry)),
778  entry->fqdn_len);
779  if (c != NULL) {
780  json_object_set_new(js, "rrname", SCJsonString(c));
781  SCFree(c);
782  }
783  }
784 
785  /* name */
786  char record[16] = "";
787  DNSCreateTypeString(entry->type, record, sizeof(record));
788  json_object_set_new(js, "rrtype", json_string(record));
789 
790  /* ttl */
791  json_object_set_new(js, "ttl", json_integer(entry->ttl));
792 
793  uint8_t *ptr = (uint8_t *)((uint8_t *)entry + sizeof(DNSAnswerEntry)+ entry->fqdn_len);
794  if (entry->type == DNS_RECORD_TYPE_A && entry->data_len == 4) {
795  char a[16] = "";
796  PrintInet(AF_INET, (const void *)ptr, a, sizeof(a));
797  json_object_set_new(js, "rdata", json_string(a));
798  } else if (entry->type == DNS_RECORD_TYPE_AAAA && entry->data_len == 16) {
799  char a[46] = "";
800  PrintInet(AF_INET6, (const void *)ptr, a, sizeof(a));
801  json_object_set_new(js, "rdata", json_string(a));
802  } else if (entry->data_len == 0) {
803  json_object_set_new(js, "rdata", json_string(""));
804  } else if (entry->type == DNS_RECORD_TYPE_TXT || entry->type == DNS_RECORD_TYPE_CNAME ||
805  entry->type == DNS_RECORD_TYPE_MX || entry->type == DNS_RECORD_TYPE_PTR ||
806  entry->type == DNS_RECORD_TYPE_NS) {
807  if (entry->data_len != 0) {
808  char buffer[256] = "";
809  uint16_t copy_len = entry->data_len < (sizeof(buffer) - 1) ?
810  entry->data_len : sizeof(buffer) - 1;
811  memcpy(buffer, ptr, copy_len);
812  buffer[copy_len] = '\0';
813  json_object_set_new(js, "rdata", SCJsonString(buffer));
814  } else {
815  json_object_set_new(js, "rdata", json_string(""));
816  }
817  } else if (entry->type == DNS_RECORD_TYPE_SSHFP) {
818  if (entry->data_len > 2) {
819  json_t *hjs = DnsParseSshFpType(entry, ptr);
820  if (hjs != NULL) {
821  json_object_set_new(js, "sshfp", hjs);
822  }
823  }
824  }
825 
826  /* reset */
827  MemBufferReset(aft->buffer);
828  json_object_set_new(djs, "dns", js);
829  OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, &aft->buffer);
830  json_object_del(djs, "dns");
831 
832  return;
833 }
834 
835 static json_t *BuildAnswer(DNSTransaction *tx, uint64_t tx_id, uint64_t flags,
836  DnsVersion version)
837 {
838  json_t *js = json_object();
839  if (js == NULL)
840  return NULL;
841 
842  /* version */
843  if (version == DNS_VERSION_2) {
844  json_object_set_new(js, "version", json_integer(DNS_VERSION_2));
845  } else {
846  json_object_set_new(js, "version", json_integer(DNS_VERSION_1));
847  }
848 
849  /* type */
850  json_object_set_new(js, "type", json_string("answer"));
851 
852  /* id */
853  json_object_set_new(js, "id", json_integer(tx->tx_id));
854 
855  /* flags */
856  char dns_flags[7] = "";
857  snprintf(dns_flags, sizeof(dns_flags), "%4x", tx->flags);
858  json_object_set_new(js, "flags", json_string(dns_flags));
859  if (tx->flags & 0x8000)
860  json_object_set_new(js, "qr", json_true());
861  if (tx->flags & 0x0400)
862  json_object_set_new(js, "aa", json_true());
863  if (tx->flags & 0x0200)
864  json_object_set_new(js, "tc", json_true());
865  if (tx->flags & 0x0100)
866  json_object_set_new(js, "rd", json_true());
867  if (tx->flags & 0x0080)
868  json_object_set_new(js, "ra", json_true());
869 
870  /* rcode */
871  char rcode[16] = "";
872  DNSCreateRcodeString(tx->rcode, rcode, sizeof(rcode));
873  json_object_set_new(js, "rcode", json_string(rcode));
874 
875  /* Log the query rrname and rrtype. Mostly useful on error, but
876  * still useful. */
877  DNSQueryEntry *query = TAILQ_FIRST(&tx->query_list);
878  if (query != NULL) {
879  char *c;
880  c = BytesToString((uint8_t *)((uint8_t *)query + sizeof(DNSQueryEntry)),
881  query->len);
882  if (c != NULL) {
883  json_object_set_new(js, "rrname", json_string(c));
884  SCFree(c);
885  }
886  char rrtype[16] = "";
887  DNSCreateTypeString(query->type, rrtype, sizeof(rrtype));
888  json_object_set_new(js, "rrtype", json_string(rrtype));
889  }
890 
891  if (flags & LOG_FORMAT_DETAILED) {
892  if (!TAILQ_EMPTY(&tx->answer_list)) {
893  json_t *jarray = json_array();
894  if (jarray == NULL) {
895  json_decref(js);
896  return NULL;
897  }
898  OutputAnswerDetailed(TAILQ_FIRST(&tx->answer_list), jarray, flags);
899  json_object_set_new(js, "answers", jarray);
900  }
901 
902  if (!TAILQ_EMPTY(&tx->authority_list)) {
903  json_t *js_authorities = json_array();
904  if (likely(js_authorities != NULL)) {
905  OutputAnswerDetailed(TAILQ_FIRST(&tx->authority_list),
906  js_authorities, flags);
907  json_object_set_new(js, "authorities", js_authorities);
908  }
909  }
910  }
911 
912  if (!TAILQ_EMPTY(&tx->answer_list) && (flags & LOG_FORMAT_GROUPED)) {
913  OutputAnswerGrouped(TAILQ_FIRST(&tx->answer_list), js);
914  }
915 
916  return js;
917 }
918 
919 static void OutputAnswerV2(LogDnsLogThread *aft, json_t *djs,
920  DNSTransaction *tx)
921 {
922  json_t *dnsjs = BuildAnswer(tx, tx->tx_id, aft->dnslog_ctx->flags,
923  aft->dnslog_ctx->version);
924  if (dnsjs != NULL) {
925  /* reset */
926  MemBufferReset(aft->buffer);
927  json_object_set_new(djs, "dns", dnsjs);
928  OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, &aft->buffer);
929  }
930 }
931 #endif
932 
933 json_t *JsonDNSLogAnswer(void *txptr, uint64_t tx_id)
934 {
935 #ifdef HAVE_RUST
936  return rs_dns_log_json_answer(txptr, LOG_ALL_RRTYPES);
937 #else
938  DNSTransaction *tx = txptr;
939  DNSAnswerEntry *entry = TAILQ_FIRST(&tx->answer_list);
940  if (entry) {
941  return BuildAnswer(tx, tx_id, LOG_FORMAT_DETAILED, DNS_VERSION_2);
942  }
943  return NULL;
944 #endif
945 }
946 
947 #ifndef HAVE_RUST
948 static void OutputFailure(LogDnsLogThread *aft, json_t *djs,
949  DNSTransaction *tx, DNSQueryEntry *entry) __attribute__((nonnull));
950 
951 static void OutputFailure(LogDnsLogThread *aft, json_t *djs,
952  DNSTransaction *tx, DNSQueryEntry *entry)
953 {
954  if (!DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags)) {
955  return;
956  }
957 
958  json_t *js = json_object();
959  if (js == NULL)
960  return;
961 
962  /* type */
963  json_object_set_new(js, "type", json_string("answer"));
964 
965  /* id */
966  json_object_set_new(js, "id", json_integer(tx->tx_id));
967 
968  /* rcode */
969  char rcode[16] = "";
970  DNSCreateRcodeString(tx->rcode, rcode, sizeof(rcode));
971  json_object_set_new(js, "rcode", json_string(rcode));
972 
973  /* no answer RRs, use query for rname */
974  char *c;
975  c = BytesToString((uint8_t *)((uint8_t *)entry + sizeof(DNSQueryEntry)), entry->len);
976  if (c != NULL) {
977  json_object_set_new(js, "rrname", SCJsonString(c));
978  SCFree(c);
979  }
980 
981  /* reset */
982  MemBufferReset(aft->buffer);
983  json_object_set_new(djs, "dns", js);
984  OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, &aft->buffer);
985  json_object_del(djs, "dns");
986 
987  return;
988 }
989 #endif
990 
991 #ifndef HAVE_RUST
992 static void LogAnswers(LogDnsLogThread *aft, json_t *js, DNSTransaction *tx, uint64_t tx_id)
993 {
994 
995  SCLogDebug("got a DNS response and now logging !!");
996 
997  if (aft->dnslog_ctx->version == DNS_VERSION_2) {
998  DNSQueryEntry *query = TAILQ_FIRST(&tx->query_list);
999  if (query && !DNSRRTypeEnabled(query->type, aft->dnslog_ctx->flags)) {
1000  return;
1001  }
1002  OutputAnswerV2(aft, js, tx);
1003  } else {
1004  DNSAnswerEntry *entry = NULL;
1005 
1006  /* rcode != noerror */
1007  if (tx->rcode) {
1008  /* Most DNS servers do not support multiple queries because
1009  * the rcode in response is not per-query. Multiple queries
1010  * are likely to lead to FORMERR, so log this. */
1011  DNSQueryEntry *query = NULL;
1012  TAILQ_FOREACH(query, &tx->query_list, next) {
1013  OutputFailure(aft, js, tx, query);
1014  }
1015  }
1016 
1017  TAILQ_FOREACH(entry, &tx->answer_list, next) {
1018  OutputAnswerV1(aft, js, tx, entry);
1019  }
1020  TAILQ_FOREACH(entry, &tx->authority_list, next) {
1021  OutputAnswerV1(aft, js, tx, entry);
1022  }
1023  }
1024 
1025 }
1026 #endif
1027 
1028 static int JsonDnsLoggerToServer(ThreadVars *tv, void *thread_data,
1029  const Packet *p, Flow *f, void *alstate, void *txptr, uint64_t tx_id)
1030 {
1031  SCEnter();
1032 
1033  LogDnsLogThread *td = (LogDnsLogThread *)thread_data;
1034  LogDnsFileCtx *dnslog_ctx = td->dnslog_ctx;
1035  json_t *js;
1036 
1037  if (unlikely(dnslog_ctx->flags & LOG_QUERIES) == 0) {
1038  return TM_ECODE_OK;
1039  }
1040 
1041 #ifdef HAVE_RUST
1042  for (uint16_t i = 0; i < 0xffff; i++) {
1043  js = CreateJSONHeader(p, LOG_DIR_PACKET, "dns");
1044  if (unlikely(js == NULL)) {
1045  return TM_ECODE_OK;
1046  }
1047  JsonAddCommonOptions(&dnslog_ctx->cfg, p, f, js);
1048 
1049  json_t *dns = rs_dns_log_json_query(txptr, i, td->dnslog_ctx->flags);
1050  if (unlikely(dns == NULL)) {
1051  json_decref(js);
1052  break;
1053  }
1054  json_object_set_new(js, "dns", dns);
1055  MemBufferReset(td->buffer);
1056  OutputJSONBuffer(js, td->dnslog_ctx->file_ctx, &td->buffer);
1057  json_decref(js);
1058  }
1059 #else
1060  DNSTransaction *tx = txptr;
1061  DNSQueryEntry *query = NULL;
1062  TAILQ_FOREACH(query, &tx->query_list, next) {
1063  js = CreateJSONHeader(p, LOG_DIR_PACKET, "dns");
1064  if (unlikely(js == NULL))
1065  return TM_ECODE_OK;
1066 
1067  JsonAddCommonOptions(&dnslog_ctx->cfg, p, f, js);
1068 
1069  LogQuery(td, js, tx, tx_id, query);
1070 
1071  json_decref(js);
1072  }
1073 #endif
1074 
1076 }
1077 
1078 static int JsonDnsLoggerToClient(ThreadVars *tv, void *thread_data,
1079  const Packet *p, Flow *f, void *alstate, void *txptr, uint64_t tx_id)
1080 {
1081  SCEnter();
1082 
1083  LogDnsLogThread *td = (LogDnsLogThread *)thread_data;
1084  LogDnsFileCtx *dnslog_ctx = td->dnslog_ctx;
1085 
1086  if (unlikely(dnslog_ctx->flags & LOG_ANSWERS) == 0) {
1087  return TM_ECODE_OK;
1088  }
1089 
1090  json_t *js = CreateJSONHeader(p, LOG_DIR_PACKET, "dns");
1091  if (unlikely(js == NULL))
1092  return TM_ECODE_OK;
1093 
1094  JsonAddCommonOptions(&dnslog_ctx->cfg, p, f, js);
1095 
1096 #if HAVE_RUST
1097  if (td->dnslog_ctx->version == DNS_VERSION_2) {
1098  json_t *answer = rs_dns_log_json_answer(txptr,
1099  td->dnslog_ctx->flags);
1100  if (answer != NULL) {
1101  json_object_set_new(js, "dns", answer);
1102  MemBufferReset(td->buffer);
1103  OutputJSONBuffer(js, td->dnslog_ctx->file_ctx, &td->buffer);
1104  }
1105  } else {
1106  /* Log answers. */
1107  for (uint16_t i = 0; i < UINT16_MAX; i++) {
1108  json_t *answer = rs_dns_log_json_answer_v1(txptr, i,
1109  td->dnslog_ctx->flags);
1110  if (answer == NULL) {
1111  break;
1112  }
1113  json_object_set_new(js, "dns", answer);
1114  MemBufferReset(td->buffer);
1115  OutputJSONBuffer(js, td->dnslog_ctx->file_ctx, &td->buffer);
1116  json_object_del(js, "dns");
1117  }
1118  /* Log authorities. */
1119  for (uint16_t i = 0; i < UINT16_MAX; i++) {
1120  json_t *answer = rs_dns_log_json_authority_v1(txptr, i,
1121  td->dnslog_ctx->flags);
1122  if (answer == NULL) {
1123  break;
1124  }
1125  json_object_set_new(js, "dns", answer);
1126  MemBufferReset(td->buffer);
1127  OutputJSONBuffer(js, td->dnslog_ctx->file_ctx, &td->buffer);
1128  json_object_del(js, "dns");
1129  }
1130  }
1131 #else
1132  DNSTransaction *tx = txptr;
1133 
1134  LogAnswers(td, js, tx, tx_id);
1135 #endif
1136 
1137  json_decref(js);
1138 
1140 }
1141 
1142 #define OUTPUT_BUFFER_SIZE 65536
1143 static TmEcode LogDnsLogThreadInit(ThreadVars *t, const void *initdata, void **data)
1144 {
1145  LogDnsLogThread *aft = SCMalloc(sizeof(LogDnsLogThread));
1146  if (unlikely(aft == NULL))
1147  return TM_ECODE_FAILED;
1148  memset(aft, 0, sizeof(LogDnsLogThread));
1149 
1150  if(initdata == NULL)
1151  {
1152  SCLogDebug("Error getting context for EveLogDNS. \"initdata\" argument NULL");
1153  SCFree(aft);
1154  return TM_ECODE_FAILED;
1155  }
1156 
1158  if (aft->buffer == NULL) {
1159  SCFree(aft);
1160  return TM_ECODE_FAILED;
1161  }
1162 
1163  /* Use the Ouptut Context (file pointer and mutex) */
1164  aft->dnslog_ctx= ((OutputCtx *)initdata)->data;
1165 
1166  *data = (void *)aft;
1167  return TM_ECODE_OK;
1168 }
1169 
1170 static TmEcode LogDnsLogThreadDeinit(ThreadVars *t, void *data)
1171 {
1172  LogDnsLogThread *aft = (LogDnsLogThread *)data;
1173  if (aft == NULL) {
1174  return TM_ECODE_OK;
1175  }
1176 
1177  MemBufferFree(aft->buffer);
1178  /* clear memory */
1179  memset(aft, 0, sizeof(LogDnsLogThread));
1180 
1181  SCFree(aft);
1182  return TM_ECODE_OK;
1183 }
1184 
1185 static void LogDnsLogDeInitCtx(OutputCtx *output_ctx)
1186 {
1187  LogDnsFileCtx *dnslog_ctx = (LogDnsFileCtx *)output_ctx->data;
1188  LogFileFreeCtx(dnslog_ctx->file_ctx);
1189  SCFree(dnslog_ctx);
1190  SCFree(output_ctx);
1191 }
1192 
1193 static void LogDnsLogDeInitCtxSub(OutputCtx *output_ctx)
1194 {
1195  SCLogDebug("cleaning up sub output_ctx %p", output_ctx);
1196  LogDnsFileCtx *dnslog_ctx = (LogDnsFileCtx *)output_ctx->data;
1197  SCFree(dnslog_ctx);
1198  SCFree(output_ctx);
1199 }
1200 
1201 static void JsonDnsLogParseConfig(LogDnsFileCtx *dnslog_ctx, ConfNode *conf,
1202  const char *query_key, const char *answer_key,
1203  const char *answer_types_key)
1204 {
1205  const char *query = ConfNodeLookupChildValue(conf, query_key);
1206  if (query != NULL) {
1207  if (ConfValIsTrue(query)) {
1208  dnslog_ctx->flags |= LOG_QUERIES;
1209  } else {
1210  dnslog_ctx->flags &= ~LOG_QUERIES;
1211  }
1212  } else {
1213  if (dnslog_ctx->version == DNS_VERSION_2) {
1214  dnslog_ctx->flags |= LOG_QUERIES;
1215  }
1216  }
1217 
1218  const char *response = ConfNodeLookupChildValue(conf, answer_key);
1219  if (response != NULL) {
1220  if (ConfValIsTrue(response)) {
1221  dnslog_ctx->flags |= LOG_ANSWERS;
1222  } else {
1223  dnslog_ctx->flags &= ~LOG_ANSWERS;
1224  }
1225  } else {
1226  if (dnslog_ctx->version == DNS_VERSION_2) {
1227  dnslog_ctx->flags |= LOG_ANSWERS;
1228  }
1229  }
1230 
1231  ConfNode *custom;
1232  if ((custom = ConfNodeLookupChild(conf, answer_types_key)) != NULL) {
1233  dnslog_ctx->flags &= ~LOG_ALL_RRTYPES;
1234  ConfNode *field;
1235  TAILQ_FOREACH(field, &custom->head, next)
1236  {
1237  if (field != NULL)
1238  {
1239  DnsRRTypes f;
1240  for (f = DNS_RRTYPE_A; f < DNS_RRTYPE_MAX; f++)
1241  {
1242  if (strcasecmp(dns_rrtype_fields[f].config_rrtype,
1243  field->val) == 0)
1244  {
1245  dnslog_ctx->flags |= dns_rrtype_fields[f].flags;
1246  break;
1247  }
1248  }
1249  }
1250  }
1251  } else {
1252  if (dnslog_ctx->version == DNS_VERSION_2) {
1253  dnslog_ctx->flags |= LOG_ALL_RRTYPES;
1254  }
1255  }
1256 }
1257 
1258 static DnsVersion JsonDnsParseVersion(ConfNode *conf)
1259 {
1260  if (conf == NULL) {
1261  return DNS_VERSION_DEFAULT;
1262  }
1263 
1264  DnsVersion version = DNS_VERSION_DEFAULT;
1265  intmax_t config_version;
1266  if (ConfGetChildValueInt(conf, "version", &config_version)) {
1267  switch(config_version) {
1268  case 1:
1269  version = DNS_VERSION_1;
1270  break;
1271  case 2:
1272  version = DNS_VERSION_2;
1273  break;
1274  default:
1276  "invalid eve-log dns version option: %"PRIuMAX", "
1277  "forcing it to version %u",
1278  config_version, DNS_VERSION_DEFAULT);
1279  version = DNS_VERSION_DEFAULT;
1280  break;
1281  }
1282  } else {
1284  "eve-log dns version not found, forcing it to version %u",
1285  DNS_VERSION_DEFAULT);
1286  version = DNS_VERSION_DEFAULT;
1287  }
1288  return version;
1289 }
1290 
1291 static void JsonDnsLogInitFilters(LogDnsFileCtx *dnslog_ctx, ConfNode *conf)
1292 {
1293  dnslog_ctx->flags = ~0UL;
1294 
1295  if (conf) {
1296  if (dnslog_ctx->version == DNS_VERSION_1) {
1297  JsonDnsLogParseConfig(dnslog_ctx, conf, "query", "answer", "custom");
1298  } else {
1299  JsonDnsLogParseConfig(dnslog_ctx, conf, "requests", "responses", "types");
1300 
1301  if (dnslog_ctx->flags & LOG_ANSWERS) {
1302  ConfNode *format;
1303  if ((format = ConfNodeLookupChild(conf, "formats")) != NULL) {
1304  dnslog_ctx->flags &= ~LOG_FORMAT_ALL;
1305  ConfNode *field;
1306  TAILQ_FOREACH(field, &format->head, next) {
1307  if (strcasecmp(field->val, "detailed") == 0) {
1308  dnslog_ctx->flags |= LOG_FORMAT_DETAILED;
1309  } else if (strcasecmp(field->val, "grouped") == 0) {
1310  dnslog_ctx->flags |= LOG_FORMAT_GROUPED;
1311  }
1312  }
1313  } else {
1314  dnslog_ctx->flags |= LOG_FORMAT_ALL;
1315  }
1316  }
1317  }
1318  }
1319 }
1320 
1321 static OutputInitResult JsonDnsLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx)
1322 {
1323  OutputInitResult result = { NULL, false };
1324  const char *enabled = ConfNodeLookupChildValue(conf, "enabled");
1325  if (enabled != NULL && !ConfValIsTrue(enabled)) {
1326  result.ok = true;
1327  return result;
1328  }
1329 
1330  DnsVersion version = JsonDnsParseVersion(conf);
1331 
1332  OutputJsonCtx *ojc = parent_ctx->data;
1333 
1334  LogDnsFileCtx *dnslog_ctx = SCMalloc(sizeof(LogDnsFileCtx));
1335  if (unlikely(dnslog_ctx == NULL)) {
1336  return result;
1337  }
1338  memset(dnslog_ctx, 0x00, sizeof(LogDnsFileCtx));
1339 
1340  dnslog_ctx->file_ctx = ojc->file_ctx;
1341  dnslog_ctx->cfg = ojc->cfg;
1342 
1343  OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));
1344  if (unlikely(output_ctx == NULL)) {
1345  SCFree(dnslog_ctx);
1346  return result;
1347  }
1348 
1349  output_ctx->data = dnslog_ctx;
1350  output_ctx->DeInit = LogDnsLogDeInitCtxSub;
1351 
1352  dnslog_ctx->version = version;
1353  JsonDnsLogInitFilters(dnslog_ctx, conf);
1354 
1355  SCLogDebug("DNS log sub-module initialized");
1356 
1359 
1360  result.ctx = output_ctx;
1361  result.ok = true;
1362  return result;
1363 }
1364 
1365 #define DEFAULT_LOG_FILENAME "dns.json"
1366 /** \brief Create a new dns log LogFileCtx.
1367  * \param conf Pointer to ConfNode containing this loggers configuration.
1368  * \return NULL if failure, LogFileCtx* to the file_ctx if succesful
1369  * */
1370 static OutputInitResult JsonDnsLogInitCtx(ConfNode *conf)
1371 {
1372  OutputInitResult result = { NULL, false };
1373  const char *enabled = ConfNodeLookupChildValue(conf, "enabled");
1374  if (enabled != NULL && !ConfValIsTrue(enabled)) {
1375  return result;
1376  }
1377 
1378  DnsVersion version = JsonDnsParseVersion(conf);
1379 
1381 
1382  if(file_ctx == NULL) {
1383  SCLogError(SC_ERR_DNS_LOG_GENERIC, "couldn't create new file_ctx");
1384  return result;
1385  }
1386 
1387  if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) {
1388  LogFileFreeCtx(file_ctx);
1389  return result;
1390  }
1391 
1392  LogDnsFileCtx *dnslog_ctx = SCMalloc(sizeof(LogDnsFileCtx));
1393  if (unlikely(dnslog_ctx == NULL)) {
1394  LogFileFreeCtx(file_ctx);
1395  return result;
1396  }
1397  memset(dnslog_ctx, 0x00, sizeof(LogDnsFileCtx));
1398 
1399  dnslog_ctx->file_ctx = file_ctx;
1400 
1401  OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));
1402  if (unlikely(output_ctx == NULL)) {
1403  LogFileFreeCtx(file_ctx);
1404  SCFree(dnslog_ctx);
1405  return result;
1406  }
1407 
1408  output_ctx->data = dnslog_ctx;
1409  output_ctx->DeInit = LogDnsLogDeInitCtx;
1410 
1411  dnslog_ctx->version = version;
1412  JsonDnsLogInitFilters(dnslog_ctx, conf);
1413 
1414  SCLogDebug("DNS log output initialized");
1415 
1418 
1419  result.ctx = output_ctx;
1420  result.ok = true;
1421  return result;
1422 }
1423 
1424 
1425 #define MODULE_NAME "JsonDnsLog"
1426 void JsonDnsLogRegister (void)
1427 {
1428  /* Logger for requests. */
1430  "dns-json-log", JsonDnsLogInitCtx, ALPROTO_DNS, JsonDnsLoggerToServer,
1431  0, 1, LogDnsLogThreadInit, LogDnsLogThreadDeinit, NULL);
1432 
1433  /* Logger for replies. */
1435  "dns-json-log", JsonDnsLogInitCtx, ALPROTO_DNS, JsonDnsLoggerToClient,
1436  1, 1, LogDnsLogThreadInit, LogDnsLogThreadDeinit, NULL);
1437 
1438  /* Sub-logger for requests. */
1440  MODULE_NAME, "eve-log.dns", JsonDnsLogInitCtxSub, ALPROTO_DNS,
1441  JsonDnsLoggerToServer, 0, 1, LogDnsLogThreadInit,
1442  LogDnsLogThreadDeinit, NULL);
1443 
1444  /* Sub-logger for replies. */
1446  MODULE_NAME, "eve-log.dns", JsonDnsLogInitCtxSub, ALPROTO_DNS,
1447  JsonDnsLoggerToClient, 1, 1, LogDnsLogThreadInit, LogDnsLogThreadDeinit,
1448  NULL);
1449 }
1450 
1451 #else
1452 
1454 {
1455 }
1456 
1457 #endif
#define DNS_RECORD_TYPE_NSEC
struct DNSAnswerEntry_ DNSAnswerEntry
DNS Answer storage. Stored in TX list.
MemBuffer * MemBufferCreateNew(uint32_t size)
Definition: util-buffer.c:32
uint16_t flags
#define DNS_RECORD_TYPE_ATMA
#define DNS_RECORD_TYPE_AFSDB
#define SCLogDebug(...)
Definition: util-debug.h:335
#define TAILQ_FIRST(head)
Definition: queue.h:339
#define DNS_RECORD_TYPE_MF
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:350
struct HtpBodyChunk_ * next
#define DNS_RECORD_TYPE_NSEC3
#define DNS_RECORD_TYPE_LOC
#define unlikely(expr)
Definition: util-optimize.h:35
#define DNS_RECORD_TYPE_KEY
#define MemBufferReset(mem_buffer)
Reset the mem buffer.
Definition: util-buffer.h:42
#define DNS_RECORD_TYPE_SPF
size_t strlcat(char *, const char *src, size_t siz)
Definition: util-strlcatu.c:45
#define DNS_RECORD_TYPE_DS
DNS Transaction, request/reply with same TX id.
void(* DeInit)(struct OutputCtx_ *)
Definition: tm-modules.h:84
void DNSCreateRcodeString(uint8_t rcode, char *str, size_t str_size)
#define DNS_RECORD_TYPE_RT
char * val
Definition: conf.h:34
#define DNS_RECORD_TYPE_TLSA
ConfNode * ConfNodeLookupChild(const ConfNode *node, const char *name)
Lookup a child configuration node by name.
Definition: conf.c:815
#define DNS_RECORD_TYPE_NSEC3PARAM
DNS Answer storage. Stored in TX list.
typedef __attribute__
DNP3 application header.
#define DNS_RECORD_TYPE_NXT
void JsonDnsLogRegister(void)
#define DNS_RECORD_TYPE_APL
DNS Query storage. Stored in TX list.
#define DNS_RECORD_TYPE_ISDN
#define SCCalloc(nm, a)
Definition: util-mem.h:205
const char * ConfNodeLookupChildValue(const ConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
Definition: conf.c:843
uint16_t type
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
#define DNS_RECORD_TYPE_A
#define DNS_RECORD_TYPE_TSIG
void AppLayerParserRegisterLogger(uint8_t ipproto, AppProto alproto)
void OutputRegisterTxModuleWithProgress(LoggerId id, const char *name, const char *conf_name, OutputInitFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats)
Register a tx output module with progress.
Definition: output.c:357
#define SCEnter(...)
Definition: util-debug.h:337
#define MODULE_NAME
#define DNS_RECORD_TYPE_MG
LogFileCtx * LogFileNewCtx(void)
LogFileNewCtx() Get a new LogFileCtx.
#define DNS_RECORD_TYPE_DNAME
#define DNS_RECORD_TYPE_CDNSKEY
#define DNS_RECORD_TYPE_NSAP
LogFileCtx * file_ctx
Definition: log-dnslog.c:65
#define DNS_RECORD_TYPE_SRV
int SCConfLogOpenGeneric(ConfNode *conf, LogFileCtx *log_ctx, const char *default_filename, int rotate)
open a generic output "log file", which may be a regular file or a socket
void OutputRegisterTxSubModuleWithProgress(LoggerId id, const char *parent_name, const char *name, const char *conf_name, OutputInitSubFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats)
Definition: output.c:368
const char * PrintInet(int af, const void *src, char *dst, socklen_t size)
Definition: util-print.c:267
#define DNS_RECORD_TYPE_MB
#define DNS_RECORD_TYPE_KX
#define DNS_RECORD_TYPE_X25
char * BytesToString(const uint8_t *bytes, size_t nbytes)
Turn byte array into string.
Definition: util-byte.c:40
#define SCReturnInt(x)
Definition: util-debug.h:341
#define DNS_RECORD_TYPE_PTR
#define DNS_RECORD_TYPE_AAAA
#define DNS_RECORD_TYPE_CNAME
#define SCLogWarning(err_code,...)
Macro used to log WARNING messages.
Definition: util-debug.h:281
struct LogDnsFileCtx_ LogDnsFileCtx
int ConfValIsTrue(const char *val)
Check if a value is true.
Definition: conf.c:566
#define DNS_RECORD_TYPE_RP
#define DNS_RECORD_TYPE_WKS
#define DNS_RECORD_TYPE_NSAPPTR
MemBuffer * buffer
Definition: log-dnslog.c:74
Definition: conf.h:32
OutputCtx * ctx
Definition: output.h:42
#define DEFAULT_LOG_FILENAME
#define DNS_RECORD_TYPE_CERT
#define SCMalloc(a)
Definition: util-mem.h:174
#define DNS_RECORD_TYPE_OPT
#define DNS_RECORD_TYPE_RRSIG
#define DNS_RECORD_TYPE_SIG
int LogFileFreeCtx(LogFileCtx *lf_ctx)
LogFileFreeCtx() Destroy a LogFileCtx (Close the file and free memory)
#define DNS_RECORD_TYPE_IPSECKEY
#define DNS_RECORD_TYPE_NULL
#define DNS_RECORD_TYPE_MX
uint8_t version
Definition: decode-gre.h:405
#define SCFree(a)
Definition: util-mem.h:236
#define DNS_RECORD_TYPE_A6
#define DNS_RECORD_TYPE_CDS
#define OUTPUT_BUFFER_SIZE
Definition: log-dnslog.c:58
uint16_t tx_id
#define DNS_RECORD_TYPE_ANY
#define DNS_RECORD_TYPE_GPOS
#define DNS_RECORD_TYPE_MR
void * data
Definition: tm-modules.h:81
#define DNS_RECORD_TYPE_HINFO
#define DNS_RECORD_TYPE_MD
#define DNS_RECORD_TYPE_NAPTR
#define DNS_RECORD_TYPE_TXT
#define DNS_RECORD_TYPE_MAILA
#define DNS_RECORD_TYPE_DHCID
#define DNS_RECORD_TYPE_NS
int ConfGetChildValueInt(const ConfNode *base, const char *name, intmax_t *val)
Definition: conf.c:469
#define DNS_RECORD_TYPE_TKEY
#define DNS_RECORD_TYPE_HIP
#define DNS_RECORD_TYPE_SOA
#define TAILQ_NEXT(elm, field)
Definition: queue.h:341
uint32_t flags
Definition: log-dnslog.c:66
#define TAILQ_EMPTY(head)
Definition: queue.h:347
Per thread variable structure.
Definition: threadvars.h:57
#define DNS_RECORD_TYPE_DNSKEY
#define likely(expr)
Definition: util-optimize.h:32
#define DNS_RECORD_TYPE_URI
#define DNS_RECORD_TYPE_PX
Flow data structure.
Definition: flow.h:327
#define DNS_RECORD_TYPE_MINFO
void MemBufferFree(MemBuffer *buffer)
Definition: util-buffer.c:82
void DNSCreateTypeString(uint16_t type, char *str, size_t str_size)
LogDnsFileCtx * dnslog_ctx
Definition: log-dnslog.c:70
struct LogDnsLogThread_ LogDnsLogThread
#define DNS_RECORD_TYPE_SSHFP