@ -123,7 +123,11 @@
# define LOG_ANY BIT_U64(58)
# define LOG_URI BIT_U64(59)
# define LOG_ALL_RRTYPES (~(uint64_t)(LOG_QUERIES|LOG_ANSWERS))
# define LOG_FORMAT_GROUPED BIT_U64(60)
# define LOG_FORMAT_DETAILED BIT_U64(61)
# define LOG_FORMAT_ALL (LOG_FORMAT_GROUPED|LOG_FORMAT_DETAILED)
# define LOG_ALL_RRTYPES (~(uint64_t)(LOG_QUERIES|LOG_ANSWERS|LOG_FORMAT_DETAILED|LOG_FORMAT_GROUPED))
typedef enum {
DNS_RRTYPE_A = 0 ,
@ -402,26 +406,13 @@ static int DNSRRTypeEnabled(uint16_t type, uint64_t flags)
# endif
# ifndef HAVE_RUST
static void LogQuery ( LogDnsLogThread * aft , json_t * js , DNSTransaction * tx ,
uint64_t tx_id , DNSQueryEntry * entry ) __attribute__ ( ( nonnull ) ) ;
static void LogQuery ( LogDnsLogThread * aft , json_t * js , DNSTransaction * tx ,
uint64_t tx_id , DNSQueryEntry * entry )
static json_t * OutputQuery ( DNSTransaction * tx , uint64_t tx_id , DNSQueryEntry * entry )
{
SCLogDebug ( " got a DNS request and now logging !! " ) ;
if ( ! DNSRRTypeEnabled ( entry - > type , aft - > dnslog_ctx - > flags ) ) {
return ;
}
json_t * djs = json_object ( ) ;
if ( djs = = NULL ) {
return ;
return NULL ;
}
/* reset */
MemBufferReset ( aft - > buffer ) ;
/* type */
json_object_set_new ( djs , " type " , json_string ( " query " ) ) ;
@ -444,6 +435,26 @@ static void LogQuery(LogDnsLogThread *aft, json_t *js, DNSTransaction *tx,
/* tx id (tx counter) */
json_object_set_new ( djs , " tx_id " , json_integer ( tx_id ) ) ;
return djs ;
}
static void LogQuery ( LogDnsLogThread * aft , json_t * js , DNSTransaction * tx ,
uint64_t tx_id , DNSQueryEntry * entry )
{
SCLogDebug ( " got a DNS request and now logging !! " ) ;
if ( ! DNSRRTypeEnabled ( entry - > type , aft - > dnslog_ctx - > flags ) ) {
return ;
}
json_t * djs = OutputQuery ( tx , tx_id , entry ) ;
if ( djs = = NULL ) {
return ;
}
/* reset */
MemBufferReset ( aft - > buffer ) ;
/* dns */
json_object_set_new ( js , " dns " , djs ) ;
OutputJSONBuffer ( js , aft - > dnslog_ctx - > file_ctx , & aft - > buffer ) ;
@ -452,10 +463,242 @@ static void LogQuery(LogDnsLogThread *aft, json_t *js, DNSTransaction *tx,
# endif
# ifndef HAVE_RUST
static void OutputAnswer ( LogDnsLogThread * aft , json_t * djs ,
DNSTransaction * tx , DNSAnswerEntry * entry ) __attribute__ ( ( nonnull ) ) ;
static void OutputAnswer ( LogDnsLogThread * aft , json_t * djs ,
static json_t * DnsParseSshFpType ( DNSAnswerEntry * entry , uint8_t * ptr )
{
/* get algo and type */
uint8_t algo = * ptr ;
uint8_t fptype = * ( ptr + 1 ) ;
/* turn fp raw buffer into a nice :-separate hex string */
uint16_t fp_len = ( entry - > data_len - 2 ) ;
uint8_t * dptr = ptr + 2 ;
/* c-string for ':' separated hex and trailing \0. */
uint32_t output_len = fp_len * 3 + 1 ;
char hexstring [ output_len ] ;
memset ( hexstring , 0x00 , output_len ) ;
uint16_t x ;
for ( x = 0 ; x < fp_len ; x + + ) {
char one [ 4 ] ;
snprintf ( one , sizeof ( one ) , x = = fp_len - 1 ? " %02x " : " %02x: " , dptr [ x ] ) ;
strlcat ( hexstring , one , output_len ) ;
}
/* wrap the whole thing in it's own structure */
json_t * hjs = json_object ( ) ;
if ( hjs = = NULL ) {
return NULL ;
}
json_object_set_new ( hjs , " fingerprint " , json_string ( hexstring ) ) ;
json_object_set_new ( hjs , " algo " , json_integer ( algo ) ) ;
json_object_set_new ( hjs , " type " , json_integer ( fptype ) ) ;
return hjs ;
}
static void OutputAnswerDetailed ( DNSAnswerEntry * entry , json_t * js )
{
do {
json_t * jdata = json_object ( ) ;
if ( jdata = = NULL ) {
return ;
}
/* query */
if ( entry - > fqdn_len > 0 ) {
char * c ;
c = BytesToString ( ( uint8_t * ) ( ( uint8_t * ) entry + sizeof ( DNSAnswerEntry ) ) ,
entry - > fqdn_len ) ;
if ( c ! = NULL ) {
json_object_set_new ( jdata , " rrname " , json_string ( c ) ) ;
SCFree ( c ) ;
}
}
/* name */
char record [ 16 ] = " " ;
DNSCreateTypeString ( entry - > type , record , sizeof ( record ) ) ;
json_object_set_new ( jdata , " rrtype " , json_string ( record ) ) ;
/* ttl */
json_object_set_new ( jdata , " ttl " , json_integer ( entry - > ttl ) ) ;
uint8_t * ptr = ( uint8_t * ) ( ( uint8_t * ) entry + sizeof ( DNSAnswerEntry ) + entry - > fqdn_len ) ;
if ( entry - > type = = DNS_RECORD_TYPE_A & & entry - > data_len = = 4 ) {
char a [ 16 ] = " " ;
PrintInet ( AF_INET , ( const void * ) ptr , a , sizeof ( a ) ) ;
json_object_set_new ( jdata , " rdata " , json_string ( a ) ) ;
} else if ( entry - > type = = DNS_RECORD_TYPE_AAAA & & entry - > data_len = = 16 ) {
char a [ 46 ] = " " ;
PrintInet ( AF_INET6 , ( const void * ) ptr , a , sizeof ( a ) ) ;
json_object_set_new ( jdata , " rdata " , json_string ( a ) ) ;
} else if ( entry - > data_len = = 0 ) {
json_object_set_new ( jdata , " rdata " , json_string ( " " ) ) ;
} else if ( entry - > type = = DNS_RECORD_TYPE_TXT | | entry - > type = = DNS_RECORD_TYPE_CNAME | |
entry - > type = = DNS_RECORD_TYPE_MX | | entry - > type = = DNS_RECORD_TYPE_PTR | |
entry - > type = = DNS_RECORD_TYPE_NS ) {
if ( entry - > data_len ! = 0 ) {
char buffer [ 256 ] = " " ;
uint16_t copy_len = entry - > data_len < ( sizeof ( buffer ) - 1 ) ?
entry - > data_len : sizeof ( buffer ) - 1 ;
memcpy ( buffer , ptr , copy_len ) ;
buffer [ copy_len ] = ' \0 ' ;
json_object_set_new ( jdata , " rdata " , json_string ( buffer ) ) ;
} else {
json_object_set_new ( jdata , " rdata " , json_string ( " " ) ) ;
}
} else if ( entry - > type = = DNS_RECORD_TYPE_SSHFP ) {
if ( entry - > data_len > 2 ) {
json_t * hjs = DnsParseSshFpType ( entry , ptr ) ;
if ( hjs ! = NULL ) {
json_object_set_new ( jdata , " sshfp " , hjs ) ;
}
}
}
json_array_append_new ( js , jdata ) ;
} while ( ( entry = TAILQ_NEXT ( entry , next ) ) ) ;
}
static void OutputAnswerGrouped ( DNSAnswerEntry * entry , json_t * js )
{
struct {
# define ENTRY_TYPE_A 0
# define ENTRY_TYPE_AAAA 1
# define ENTRY_TYPE_TXT 2
# define ENTRY_TYPE_CNAME 3
# define ENTRY_TYPE_MX 4
# define ENTRY_TYPE_PTR 5
# define ENTRY_TYPE_NS 6
# define ENTRY_TYPE_SSHFP 7
# define ENTRY_TYPE_MAX 8
const char * name ;
json_t * value ;
} dns_rtypes [ ] = {
{ " A " , NULL } ,
{ " AAAA " , NULL } ,
{ " TXT " , NULL } ,
{ " CNAME " , NULL } ,
{ " MX " , NULL } ,
{ " PTR " , NULL } ,
{ " NS " , NULL } ,
{ " SSHFP " , NULL }
} ;
int i ;
json_t * jrdata = json_object ( ) ;
if ( jrdata = = NULL ) {
return ;
}
do {
uint8_t * ptr = ( uint8_t * ) ( ( uint8_t * ) entry + sizeof ( DNSAnswerEntry ) + entry - > fqdn_len ) ;
if ( entry - > type = = DNS_RECORD_TYPE_A & & entry - > data_len = = 4 ) {
char a [ 16 ] = " " ;
if ( dns_rtypes [ ENTRY_TYPE_A ] . value = = NULL ) {
dns_rtypes [ ENTRY_TYPE_A ] . value = json_array ( ) ;
if ( dns_rtypes [ ENTRY_TYPE_A ] . value = = NULL ) {
goto out ;
}
}
PrintInet ( AF_INET , ( const void * ) ptr , a , sizeof ( a ) ) ;
json_array_append_new ( dns_rtypes [ ENTRY_TYPE_A ] . value , json_string ( a ) ) ;
} else if ( entry - > type = = DNS_RECORD_TYPE_AAAA & & entry - > data_len = = 16 ) {
char a [ 46 ] = " " ;
if ( dns_rtypes [ ENTRY_TYPE_AAAA ] . value = = NULL ) {
dns_rtypes [ ENTRY_TYPE_AAAA ] . value = json_array ( ) ;
if ( dns_rtypes [ ENTRY_TYPE_AAAA ] . value = = NULL ) {
goto out ;
}
}
PrintInet ( AF_INET6 , ( const void * ) ptr , a , sizeof ( a ) ) ;
json_array_append_new ( dns_rtypes [ ENTRY_TYPE_AAAA ] . value , json_string ( a ) ) ;
} else if ( entry - > data_len = = 0 ) {
json_object_set_new ( js , " rdata " , json_string ( " " ) ) ;
} else if ( entry - > type = = DNS_RECORD_TYPE_TXT | | entry - > type = = DNS_RECORD_TYPE_CNAME | |
entry - > type = = DNS_RECORD_TYPE_MX | | entry - > type = = DNS_RECORD_TYPE_PTR | |
entry - > type = = DNS_RECORD_TYPE_NS ) {
if ( entry - > data_len ! = 0 ) {
char buffer [ 256 ] = " " ;
uint16_t copy_len = entry - > data_len < ( sizeof ( buffer ) - 1 ) ?
entry - > data_len : sizeof ( buffer ) - 1 ;
memcpy ( buffer , ptr , copy_len ) ;
buffer [ copy_len ] = ' \0 ' ;
if ( entry - > type = = DNS_RECORD_TYPE_TXT ) {
if ( dns_rtypes [ ENTRY_TYPE_TXT ] . value = = NULL ) {
dns_rtypes [ ENTRY_TYPE_TXT ] . value = json_array ( ) ;
if ( dns_rtypes [ ENTRY_TYPE_TXT ] . value = = NULL ) {
goto out ;
}
}
json_array_append_new ( dns_rtypes [ ENTRY_TYPE_TXT ] . value , json_string ( buffer ) ) ;
} else if ( entry - > type = = DNS_RECORD_TYPE_CNAME ) {
if ( dns_rtypes [ ENTRY_TYPE_CNAME ] . value = = NULL ) {
dns_rtypes [ ENTRY_TYPE_CNAME ] . value = json_array ( ) ;
if ( dns_rtypes [ ENTRY_TYPE_CNAME ] . value = = NULL ) {
goto out ;
}
}
json_array_append_new ( dns_rtypes [ ENTRY_TYPE_CNAME ] . value , json_string ( buffer ) ) ;
} else if ( entry - > type = = DNS_RECORD_TYPE_MX ) {
if ( dns_rtypes [ ENTRY_TYPE_MX ] . value = = NULL ) {
dns_rtypes [ ENTRY_TYPE_MX ] . value = json_array ( ) ;
if ( dns_rtypes [ ENTRY_TYPE_MX ] . value = = NULL ) {
goto out ;
}
}
json_array_append_new ( dns_rtypes [ ENTRY_TYPE_MX ] . value , json_string ( buffer ) ) ;
} else if ( entry - > type = = DNS_RECORD_TYPE_PTR ) {
if ( dns_rtypes [ ENTRY_TYPE_PTR ] . value = = NULL ) {
dns_rtypes [ ENTRY_TYPE_PTR ] . value = json_array ( ) ;
if ( dns_rtypes [ ENTRY_TYPE_PTR ] . value = = NULL ) {
goto out ;
}
}
json_array_append_new ( dns_rtypes [ ENTRY_TYPE_PTR ] . value , json_string ( buffer ) ) ;
} else if ( entry - > type = = DNS_RECORD_TYPE_NS ) {
if ( dns_rtypes [ ENTRY_TYPE_NS ] . value = = NULL ) {
dns_rtypes [ ENTRY_TYPE_NS ] . value = json_array ( ) ;
if ( dns_rtypes [ ENTRY_TYPE_NS ] . value = = NULL ) {
goto out ;
}
}
json_array_append_new ( dns_rtypes [ ENTRY_TYPE_NS ] . value , json_string ( buffer ) ) ;
}
} else {
json_object_set_new ( js , " rdata " , json_string ( " " ) ) ;
}
} else if ( entry - > type = = DNS_RECORD_TYPE_SSHFP ) {
if ( entry - > data_len > 2 ) {
json_t * hjs = DnsParseSshFpType ( entry , ptr ) ;
if ( hjs ! = NULL ) {
if ( dns_rtypes [ ENTRY_TYPE_SSHFP ] . value = = NULL ) {
dns_rtypes [ ENTRY_TYPE_SSHFP ] . value = json_array ( ) ;
if ( dns_rtypes [ ENTRY_TYPE_SSHFP ] . value = = NULL ) {
goto out ;
}
}
json_array_append_new ( dns_rtypes [ ENTRY_TYPE_SSHFP ] . value , hjs ) ;
}
}
}
} while ( ( entry = TAILQ_NEXT ( entry , next ) ) ) ;
out :
for ( i = 0 ; i < ENTRY_TYPE_MAX ; i + + ) {
if ( dns_rtypes [ i ] . value ! = NULL ) {
json_object_set_new ( jrdata , dns_rtypes [ i ] . name , dns_rtypes [ i ] . value ) ;
dns_rtypes [ i ] . value = NULL ;
}
}
json_object_set_new ( js , " grouped " , jrdata ) ;
}
static void OutputAnswerV1 ( LogDnsLogThread * aft , json_t * djs ,
DNSTransaction * tx , DNSAnswerEntry * entry )
{
if ( ! DNSRRTypeEnabled ( entry - > type , aft - > dnslog_ctx - > flags ) ) {
@ -538,33 +781,8 @@ static void OutputAnswer(LogDnsLogThread *aft, json_t *djs,
}
} else if ( entry - > type = = DNS_RECORD_TYPE_SSHFP ) {
if ( entry - > data_len > 2 ) {
/* get algo and type */
uint8_t algo = * ptr ;
uint8_t fptype = * ( ptr + 1 ) ;
/* turn fp raw buffer into a nice :-separate hex string */
uint16_t fp_len = ( entry - > data_len - 2 ) ;
uint8_t * dptr = ptr + 2 ;
/* c-string for ':' separated hex and trailing \0. */
uint32_t output_len = fp_len * 3 + 1 ;
char hexstring [ output_len ] ;
memset ( hexstring , 0x00 , output_len ) ;
uint16_t x ;
for ( x = 0 ; x < fp_len ; x + + ) {
char one [ 4 ] ;
snprintf ( one , sizeof ( one ) , x = = fp_len - 1 ? " %02x " : " %02x: " , dptr [ x ] ) ;
strlcat ( hexstring , one , output_len ) ;
}
/* wrap the whole thing in it's own structure */
json_t * hjs = json_object ( ) ;
json_t * hjs = DnsParseSshFpType ( entry , ptr ) ;
if ( hjs ! = NULL ) {
json_object_set_new ( hjs , " fingerprint " , json_string ( hexstring ) ) ;
json_object_set_new ( hjs , " algo " , json_integer ( algo ) ) ;
json_object_set_new ( hjs , " type " , json_integer ( fptype ) ) ;
json_object_set_new ( js , " sshfp " , hjs ) ;
}
}
@ -578,6 +796,50 @@ static void OutputAnswer(LogDnsLogThread *aft, json_t *djs,
return ;
}
static void OutputAnswerV2 ( LogDnsLogThread * aft , json_t * djs ,
DNSTransaction * tx , DNSAnswerEntry * entry )
{
if ( ! DNSRRTypeEnabled ( entry - > type , aft - > dnslog_ctx - > flags ) ) {
return ;
}
json_t * js = json_object ( ) ;
if ( js = = NULL )
return ;
/* type */
json_object_set_new ( js , " type " , json_string ( " answer " ) ) ;
/* id */
json_object_set_new ( js , " id " , json_integer ( tx - > tx_id ) ) ;
/* rcode */
char rcode [ 16 ] = " " ;
DNSCreateRcodeString ( tx - > rcode , rcode , sizeof ( rcode ) ) ;
json_object_set_new ( js , " rcode " , json_string ( rcode ) ) ;
if ( aft - > dnslog_ctx - > flags & LOG_FORMAT_DETAILED ) {
json_t * jarray = json_array ( ) ;
if ( jarray = = NULL )
return ;
OutputAnswerDetailed ( entry , jarray ) ;
json_object_set_new ( js , " answers " , jarray ) ;
}
if ( aft - > dnslog_ctx - > flags & LOG_FORMAT_GROUPED ) {
OutputAnswerGrouped ( entry , js ) ;
}
/* reset */
MemBufferReset ( aft - > buffer ) ;
json_object_set_new ( djs , " dns " , js ) ;
OutputJSONBuffer ( djs , aft - > dnslog_ctx - > file_ctx , & aft - > buffer ) ;
json_object_del ( djs , " dns " ) ;
return ;
}
# endif
# ifndef HAVE_RUST
@ -642,13 +904,20 @@ static void LogAnswers(LogDnsLogThread *aft, json_t *js, DNSTransaction *tx, uin
}
DNSAnswerEntry * entry = NULL ;
TAILQ_FOREACH ( entry , & tx - > answer_list , next ) {
OutputAnswer ( aft , js , tx , entry ) ;
if ( aft - > dnslog_ctx - > version = = DNS_VERSION_2 ) {
entry = TAILQ_FIRST ( & tx - > answer_list ) ;
if ( entry ) {
OutputAnswerV2 ( aft , js , tx , entry ) ;
}
} else {
TAILQ_FOREACH ( entry , & tx - > answer_list , next ) {
OutputAnswerV1 ( aft , js , tx , entry ) ;
}
}
entry = NULL ;
TAILQ_FOREACH ( entry , & tx - > authority_list , next ) {
OutputAnswer ( aft , js , tx , entry ) ;
OutputAnswer V1 ( aft , js , tx , entry ) ;
}
}
@ -911,6 +1180,23 @@ static void JsonDnsLogInitFilters(LogDnsFileCtx *dnslog_ctx, ConfNode *conf)
JsonDnsLogParseConfig ( dnslog_ctx , conf , " query " , " answer " , " custom " ) ;
} else {
JsonDnsLogParseConfig ( dnslog_ctx , conf , " requests " , " responses " , " types " ) ;
if ( dnslog_ctx - > flags & LOG_ANSWERS ) {
ConfNode * format ;
if ( ( format = ConfNodeLookupChild ( conf , " formats " ) ) ! = NULL ) {
dnslog_ctx - > flags & = ~ LOG_FORMAT_ALL ;
ConfNode * field ;
TAILQ_FOREACH ( field , & format - > head , next ) {
if ( strcasecmp ( field - > val , " detailed " ) = = 0 ) {
dnslog_ctx - > flags | = LOG_FORMAT_DETAILED ;
} else if ( strcasecmp ( field - > val , " grouped " ) = = 0 ) {
dnslog_ctx - > flags | = LOG_FORMAT_GROUPED ;
}
}
} else {
dnslog_ctx - > flags | = LOG_FORMAT_ALL ;
}
}
}
}
}