diff --git a/src/output-json-dns.c b/src/output-json-dns.c index 5462b752dc..ea218aac9b 100644 --- a/src/output-json-dns.c +++ b/src/output-json-dns.c @@ -56,9 +56,198 @@ * TX id handling doesn't expect it */ #define QUERY 0 +#define LOG_QUERIES (1L<<0) +#define LOG_ANSWERS (1L<<1) + +#define LOG_A (1L<<2) +#define LOG_NS (1L<<3) +#define LOG_MD (1L<<4) +#define LOG_MF (1L<<5) +#define LOG_CNAME (1L<<6) +#define LOG_SOA (1L<<7) +#define LOG_MB (1L<<8) +#define LOG_MG (1L<<9) +#define LOG_MR (1L<<10) +#define LOG_NULL (1L<<11) +#define LOG_WKS (1L<<12) +#define LOG_PTR (1L<<13) +#define LOG_HINFO (1L<<14) +#define LOG_MINFO (1L<<15) +#define LOG_MX (1L<<16) +#define LOG_TXT (1L<<17) +#define LOG_RP (1L<<18) +#define LOG_AFSDB (1L<<19) +#define LOG_X25 (1L<<20) +#define LOG_ISDN (1L<<21) +#define LOG_RT (1L<<22) +#define LOG_NSAP (1L<<23) +#define LOG_NSAPPTR (1L<<24) +#define LOG_SIG (1L<<25) +#define LOG_KEY (1L<<26) +#define LOG_PX (1L<<27) +#define LOG_GPOS (1L<<28) +#define LOG_AAAA (1L<<29) +#define LOG_LOC (1L<<30) +#define LOG_NXT (1L<<31) +#define LOG_SRV (1L<<32) +#define LOG_ATMA (1L<<33) +#define LOG_NAPTR (1L<<34) +#define LOG_KX (1L<<35) +#define LOG_CERT (1L<<36) +#define LOG_A6 (1L<<37) +#define LOG_DNAME (1L<<38) +#define LOG_OPT (1L<<39) +#define LOG_APL (1L<<40) +#define LOG_DS (1L<<41) +#define LOG_SSHFP (1L<<42) +#define LOG_IPSECKEY (1L<<43) +#define LOG_RRSIG (1L<<44) +#define LOG_NSEC (1L<<45) +#define LOG_DNSKEY (1L<<46) +#define LOG_DHCID (1L<<47) +#define LOG_NSEC3 (1L<<48) +#define LOG_NSEC3PARAM (1L<<49) +#define LOG_TLSA (1L<<50) +#define LOG_HIP (1L<<51) +#define LOG_CDS (1L<<52) +#define LOG_CDNSKEY (1L<<53) +#define LOG_SPF (1L<<54) +#define LOG_TKEY (1L<<55) +#define LOG_TSIG (1L<<56) +#define LOG_MAILA (1L<<57) +#define LOG_ANY (1L<<58) +#define LOG_URI (1L<<59) + +#define LOG_ALL_RRTYPES (~(uint64_t)(LOG_QUERIES|LOG_ANSWERS)) + +typedef enum { + DNS_RRTYPE_A = 0, + DNS_RRTYPE_NS, + DNS_RRTYPE_MD, + DNS_RRTYPE_MF, + DNS_RRTYPE_CNAME, + DNS_RRTYPE_SOA, + DNS_RRTYPE_MB, + DNS_RRTYPE_MG, + DNS_RRTYPE_MR, + DNS_RRTYPE_NULL, + DNS_RRTYPE_WKS, + DNS_RRTYPE_PTR, + DNS_RRTYPE_HINFO, + DNS_RRTYPE_MINFO, + DNS_RRTYPE_MX, + DNS_RRTYPE_TXT, + DNS_RRTYPE_RP, + DNS_RRTYPE_AFSDB, + DNS_RRTYPE_X25, + DNS_RRTYPE_ISDN, + DNS_RRTYPE_RT, + DNS_RRTYPE_NSAP, + DNS_RRTYPE_NSAPPTR, + DNS_RRTYPE_SIG, + DNS_RRTYPE_KEY, + DNS_RRTYPE_PX, + DNS_RRTYPE_GPOS, + DNS_RRTYPE_AAAA, + DNS_RRTYPE_LOC, + DNS_RRTYPE_NXT, + DNS_RRTYPE_SRV, + DNS_RRTYPE_ATMA, + DNS_RRTYPE_NAPTR, + DNS_RRTYPE_KX, + DNS_RRTYPE_CERT, + DNS_RRTYPE_A6, + DNS_RRTYPE_DNAME, + DNS_RRTYPE_OPT, + DNS_RRTYPE_APL, + DNS_RRTYPE_DS, + DNS_RRTYPE_SSHFP, + DNS_RRTYPE_IPSECKEY, + DNS_RRTYPE_RRSIG, + DNS_RRTYPE_NSEC, + DNS_RRTYPE_DNSKEY, + DNS_RRTYPE_DHCID, + DNS_RRTYPE_NSEC3, + DNS_RRTYPE_NSEC3PARAM, + DNS_RRTYPE_TLSA, + DNS_RRTYPE_HIP, + DNS_RRTYPE_CDS, + DNS_RRTYPE_CDNSKEY, + DNS_RRTYPE_SPF, + DNS_RRTYPE_TKEY, + DNS_RRTYPE_TSIG, + DNS_RRTYPE_MAILA, + DNS_RRTYPE_ANY, + DNS_RRTYPE_URI +} DnsRRTypes; + +static struct { + char *config_rrtype; + uint64_t flags; +} dns_rrtype_fields[] = { + { "a", LOG_A }, + { "ns", LOG_NS }, + { "md", LOG_MD }, + { "mf", LOG_MF }, + { "cname", LOG_CNAME }, + { "soa", LOG_SOA }, + { "mb", LOG_MB }, + { "mg", LOG_MG }, + { "mr", LOG_MR }, + { "null", LOG_NULL }, + { "wks", LOG_WKS }, + { "ptr", LOG_PTR }, + { "hinfo", LOG_HINFO }, + { "minfo", LOG_MINFO }, + { "mx", LOG_MX }, + { "txt", LOG_TXT }, + { "rp", LOG_RP }, + { "afsdb", LOG_AFSDB }, + { "x25", LOG_X25 }, + { "isdn", LOG_ISDN }, + { "rt", LOG_RT }, + { "nsap", LOG_NSAP }, + { "nsapptr", LOG_NSAPPTR }, + { "sig", LOG_SIG }, + { "key", LOG_KEY }, + { "px", LOG_PX }, + { "gpos", LOG_GPOS }, + { "aaaa", LOG_AAAA }, + { "loc", LOG_LOC }, + { "nxt", LOG_NXT }, + { "srv", LOG_SRV }, + { "atma", LOG_ATMA }, + { "naptr", LOG_NAPTR }, + { "kx", LOG_KX }, + { "cert", LOG_CERT }, + { "a6", LOG_A6 }, + { "dname", LOG_DNAME }, + { "opt", LOG_OPT }, + { "apl", LOG_APL }, + { "ds", LOG_DS }, + { "sshfp", LOG_SSHFP }, + { "ipseckey", LOG_IPSECKEY }, + { "rrsig", LOG_RRSIG }, + { "nsec", LOG_NSEC }, + { "dnskey", LOG_DNSKEY }, + { "dhcid", LOG_DHCID }, + { "nsec3", LOG_NSEC3 }, + { "nsec3param", LOG_NSEC3PARAM }, + { "tlsa", LOG_TLSA }, + { "hip", LOG_HIP }, + { "cds", LOG_CDS }, + { "cdnskey", LOG_CDNSKEY }, + { "spf", LOG_SPF }, + { "tkey", LOG_TKEY }, + { "tsig", LOG_TSIG }, + { "maila", LOG_MAILA }, + { "any", LOG_ANY }, + { "uri", LOG_URI } +}; + typedef struct LogDnsFileCtx_ { LogFileCtx *file_ctx; - uint32_t flags; /** Store mode */ + uint64_t flags; /** Store mode */ } LogDnsFileCtx; typedef struct LogDnsLogThread_ { @@ -69,6 +258,134 @@ typedef struct LogDnsLogThread_ { MemBuffer *buffer; } LogDnsLogThread; +static int DNSRRTypeEnabled(uint16_t type, uint64_t flags) +{ + if (likely(flags == ~0UL)) { + return 1; + } + + switch (type) { + case DNS_RECORD_TYPE_A: + return ((flags & LOG_A) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NS: + return ((flags & LOG_NS) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_MD: + return ((flags & LOG_MD) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_MF: + return ((flags & LOG_MF) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_CNAME: + return ((flags & LOG_CNAME) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_SOA: + return ((flags & LOG_SOA) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_MB: + return ((flags & LOG_MB) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_MG: + return ((flags & LOG_MG) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_MR: + return ((flags & LOG_MR) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NULL: + return ((flags & LOG_NULL) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_WKS: + return ((flags & LOG_WKS) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_PTR: + return ((flags & LOG_PTR) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_HINFO: + return ((flags & LOG_HINFO) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_MINFO: + return ((flags & LOG_MINFO) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_MX: + return ((flags & LOG_MX) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_TXT: + return ((flags & LOG_TXT) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_RP: + return ((flags & LOG_RP) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_AFSDB: + return ((flags & LOG_AFSDB) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_X25: + return ((flags & LOG_X25) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_ISDN: + return ((flags & LOG_ISDN) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_RT: + return ((flags & LOG_RT) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NSAP: + return ((flags & LOG_NSAP) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NSAPPTR: + return ((flags & LOG_NSAPPTR) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_SIG: + return ((flags & LOG_SIG) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_KEY: + return ((flags & LOG_KEY) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_PX: + return ((flags & LOG_PX) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_GPOS: + return ((flags & LOG_GPOS) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_AAAA: + return ((flags & LOG_AAAA) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_LOC: + return ((flags & LOG_LOC) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NXT: + return ((flags & LOG_NXT) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_SRV: + return ((flags & LOG_SRV) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_ATMA: + return ((flags & LOG_ATMA) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NAPTR: + return ((flags & LOG_NAPTR) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_KX: + return ((flags & LOG_KX) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_CERT: + return ((flags & LOG_CERT) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_A6: + return ((flags & LOG_A6) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_DNAME: + return ((flags & LOG_DNAME) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_OPT: + return ((flags & LOG_OPT) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_APL: + return ((flags & LOG_APL) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_DS: + return ((flags & LOG_DS) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_SSHFP: + return ((flags & LOG_SSHFP) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_IPSECKEY: + return ((flags & LOG_IPSECKEY) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_RRSIG: + return ((flags & LOG_RRSIG) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NSEC: + return ((flags & LOG_NSEC) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_DNSKEY: + return ((flags & LOG_DNSKEY) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_DHCID: + return ((flags & LOG_DHCID) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NSEC3: + return ((flags & LOG_NSEC3) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NSEC3PARAM: + return ((flags & LOG_NSEC3PARAM) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_TLSA: + return ((flags & LOG_TLSA) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_HIP: + return ((flags & LOG_HIP) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_CDS: + return ((flags & LOG_CDS) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_CDNSKEY: + return ((flags & LOG_CDNSKEY) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_SPF: + return ((flags & LOG_SPF) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_TKEY: + return ((flags & LOG_TKEY) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_TSIG: + return ((flags & LOG_TSIG) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_MAILA: + return ((flags & LOG_MAILA) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_ANY: + return ((flags & LOG_ANY) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_URI: + return ((flags & LOG_URI) != 0) ? 1 : 0; + default: + return 0; + } +} + static void LogQuery(LogDnsLogThread *aft, json_t *js, DNSTransaction *tx, uint64_t tx_id, DNSQueryEntry *entry) { @@ -106,7 +423,9 @@ static void LogQuery(LogDnsLogThread *aft, json_t *js, DNSTransaction *tx, /* dns */ json_object_set_new(js, "dns", djs); - OutputJSONBuffer(js, aft->dnslog_ctx->file_ctx, &aft->buffer); + if (likely(DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags))) { + OutputJSONBuffer(js, aft->dnslog_ctx->file_ctx, &aft->buffer); + } json_object_del(js, "dns"); } @@ -210,7 +529,9 @@ static void OutputAnswer(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, /* reset */ MemBufferReset(aft->buffer); json_object_set_new(djs, "dns", js); - OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, &aft->buffer); + if (likely(DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags))) { + OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, &aft->buffer); + } json_object_del(djs, "dns"); return; @@ -244,7 +565,9 @@ static void OutputFailure(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, /* reset */ MemBufferReset(aft->buffer); json_object_set_new(djs, "dns", js); - OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, &aft->buffer); + if (likely(DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags))) { + OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, &aft->buffer); + } json_object_del(djs, "dns"); return; @@ -284,18 +607,21 @@ static int JsonDnsLoggerToServer(ThreadVars *tv, void *thread_data, SCEnter(); LogDnsLogThread *td = (LogDnsLogThread *)thread_data; + LogDnsFileCtx *dnslog_ctx = td->dnslog_ctx; DNSTransaction *tx = txptr; json_t *js; - DNSQueryEntry *query = NULL; - TAILQ_FOREACH(query, &tx->query_list, next) { - js = CreateJSONHeader((Packet *)p, 1, "dns"); - if (unlikely(js == NULL)) - return TM_ECODE_OK; + if (likely(dnslog_ctx->flags & LOG_QUERIES) != 0) { + DNSQueryEntry *query = NULL; + TAILQ_FOREACH(query, &tx->query_list, next) { + js = CreateJSONHeader((Packet *)p, 1, "dns"); + if (unlikely(js == NULL)) + return TM_ECODE_OK; - LogQuery(td, js, tx, tx_id, query); + LogQuery(td, js, tx, tx_id, query); - json_decref(js); + json_decref(js); + } } SCReturnInt(TM_ECODE_OK); @@ -307,16 +633,19 @@ static int JsonDnsLoggerToClient(ThreadVars *tv, void *thread_data, SCEnter(); LogDnsLogThread *td = (LogDnsLogThread *)thread_data; + LogDnsFileCtx *dnslog_ctx = td->dnslog_ctx; DNSTransaction *tx = txptr; json_t *js; - js = CreateJSONHeader((Packet *)p, 0, "dns"); - if (unlikely(js == NULL)) - return TM_ECODE_OK; + if (likely(dnslog_ctx->flags & LOG_ANSWERS) != 0) { + js = CreateJSONHeader((Packet *)p, 0, "dns"); + if (unlikely(js == NULL)) + return TM_ECODE_OK; - LogAnswers(td, js, tx, tx_id); + LogAnswers(td, js, tx, tx_id); - json_decref(js); + json_decref(js); + } SCReturnInt(TM_ECODE_OK); } @@ -380,9 +709,54 @@ static void LogDnsLogDeInitCtxSub(OutputCtx *output_ctx) SCFree(output_ctx); } +static void JsonDnsLogInitFilters(LogDnsFileCtx *dnslog_ctx, ConfNode *conf) +{ + dnslog_ctx->flags = ~0UL; + + if (conf) { + const char *query = ConfNodeLookupChildValue(conf, "query"); + if (query != NULL) { + if (ConfValIsTrue(query)) { + dnslog_ctx->flags |= LOG_QUERIES; + } else { + dnslog_ctx->flags &= ~LOG_QUERIES; + } + } + const char *response = ConfNodeLookupChildValue(conf, "answer"); + if (response != NULL) { + if (ConfValIsTrue(response)) { + dnslog_ctx->flags |= LOG_ANSWERS; + } else { + dnslog_ctx->flags &= ~LOG_ANSWERS; + } + } + ConfNode *custom; + if ((custom = ConfNodeLookupChild(conf, "custom")) != NULL) { + dnslog_ctx->flags &= ~LOG_ALL_RRTYPES; + ConfNode *field; + TAILQ_FOREACH(field, &custom->head, next) + { + if (field != NULL) + { + DnsRRTypes f; + for (f = DNS_RRTYPE_A; f < DNS_RRTYPE_TXT; f++) + { + if (strcasecmp(dns_rrtype_fields[f].config_rrtype, + field->val) == 0) + { + dnslog_ctx->flags |= dns_rrtype_fields[f].flags; + break; + } + } + } + } + } + } +} + static OutputCtx *JsonDnsLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) { - AlertJsonThread *ajt = parent_ctx->data; + OutputJsonCtx *ojc = parent_ctx->data; LogDnsFileCtx *dnslog_ctx = SCMalloc(sizeof(LogDnsFileCtx)); if (unlikely(dnslog_ctx == NULL)) { @@ -390,7 +764,7 @@ static OutputCtx *JsonDnsLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) } memset(dnslog_ctx, 0x00, sizeof(LogDnsFileCtx)); - dnslog_ctx->file_ctx = ajt->file_ctx; + dnslog_ctx->file_ctx = ojc->file_ctx; OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) { @@ -401,6 +775,8 @@ static OutputCtx *JsonDnsLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) output_ctx->data = dnslog_ctx; output_ctx->DeInit = LogDnsLogDeInitCtxSub; + JsonDnsLogInitFilters(dnslog_ctx, conf); + SCLogDebug("DNS log sub-module initialized"); AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_DNS); @@ -447,6 +823,8 @@ static OutputCtx *JsonDnsLogInitCtx(ConfNode *conf) output_ctx->data = dnslog_ctx; output_ctx->DeInit = LogDnsLogDeInitCtx; + JsonDnsLogInitFilters(dnslog_ctx, conf); + SCLogDebug("DNS log output initialized"); AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_DNS); diff --git a/suricata.yaml.in b/suricata.yaml.in index 18217d8320..d2fb45f758 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -190,7 +190,14 @@ outputs: # custom allows additional http fields to be included in eve-log # the example below adds three additional fields when uncommented #custom: [Accept-Encoding, Accept-Language, Authorization] - - dns + - dns: + # control logging of queries and answers + # default yes, no to disable + query: yes # enable logging of DNS queries + answer: yes # enable logging of DNS answers + # control which RR types are logged + # all enabled if custom not specified + #custom: [a, aaaa, cname, mx, ns, ptr, txt] - tls: extended: yes # enable this for extended logging information - files: