eve/dns/v2: support eve/dns v2 in rust

pull/3288/head
Jason Ish 7 years ago committed by Victor Julien
parent 57d9574839
commit 27fd521420

@ -19,10 +19,14 @@ extern crate libc;
use std;
use std::string::String;
use std::collections::HashMap;
use json::*;
use dns::dns::*;
pub const LOG_QUERIES : u64 = BIT_U64!(0);
pub const LOG_ANSWER : u64 = BIT_U64!(1);
pub const LOG_A : u64 = BIT_U64!(2);
pub const LOG_NS : u64 = BIT_U64!(3);
pub const LOG_MD : u64 = BIT_U64!(4);
@ -82,6 +86,9 @@ pub const LOG_MAILA : u64 = BIT_U64!(57);
pub const LOG_ANY : u64 = BIT_U64!(58);
pub const LOG_URI : u64 = BIT_U64!(59);
pub const LOG_FORMAT_GROUPED : u64 = BIT_U64!(60);
pub const LOG_FORMAT_DETAILED : u64 = BIT_U64!(61);
fn dns_log_rrtype_enabled(rtype: u16, flags: u64) -> bool
{
if flags == !0 {
@ -391,11 +398,11 @@ pub fn dns_print_addr(addr: &Vec<u8>) -> std::string::String {
}
/// Log the SSHPF in an DNSAnswerEntry.
fn dns_log_sshfp(js: &Json, answer: &DNSAnswerEntry)
fn dns_log_sshfp(answer: &DNSAnswerEntry) -> Option<Json>
{
// Need at least 3 bytes - TODO: log something if we don't?
if answer.data.len() < 3 {
return;
return None
}
let sshfp = Json::object();
@ -408,39 +415,44 @@ fn dns_log_sshfp(js: &Json, answer: &DNSAnswerEntry)
sshfp.set_integer("algo", answer.data[0] as u64);
sshfp.set_integer("type", answer.data[1] as u64);
js.set("sshfp", sshfp);
return Some(sshfp);
}
#[no_mangle]
pub extern "C" fn rs_dns_log_json_query(tx: &mut DNSTransaction,
i: libc::uint16_t,
flags: libc::uint64_t)
-> *mut JsonT
fn dns_log_json_answer_detail(answer: &DNSAnswerEntry) -> Json
{
let index = i as usize;
for request in &tx.request {
if index < request.queries.len() {
let query = &request.queries[index];
if dns_log_rrtype_enabled(query.rrtype, flags) {
let js = Json::object();
js.set_string("type", "query");
js.set_integer("id", request.header.tx_id as u64);
js.set_string_from_bytes("rrname", &query.name);
js.set_string("rrtype", &dns_rrtype_string(query.rrtype));
js.set_integer("tx_id", tx.id - 1);
return js.unwrap();
}
let jsa = Json::object();
jsa.set_string_from_bytes("rrname", &answer.name);
jsa.set_string("rrtype", &dns_rrtype_string(answer.rrtype));
jsa.set_integer("ttl", answer.ttl as u64);
match answer.rrtype {
DNS_RECORD_TYPE_A | DNS_RECORD_TYPE_AAAA => {
jsa.set_string("rdata", &dns_print_addr(&answer.data));
}
DNS_RECORD_TYPE_CNAME |
DNS_RECORD_TYPE_MX |
DNS_RECORD_TYPE_TXT |
DNS_RECORD_TYPE_PTR => {
jsa.set_string_from_bytes("rdata", &answer.data);
},
DNS_RECORD_TYPE_SSHFP => {
for sshfp in dns_log_sshfp(&answer) {
jsa.set("sshfp", sshfp);
}
},
_ => {}
}
return std::ptr::null_mut();
return jsa;
}
fn dns_log_json_answer(header: &DNSHeader, answer: &DNSAnswerEntry)
-> Json
fn dns_log_json_answer(response: &DNSResponse, flags: u64) -> Json
{
let header = &response.header;
let js = Json::object();
js.set_integer("version", 2);
js.set_string("type", "answer");
js.set_integer("id", header.tx_id as u64);
js.set_string("flags", format!("{:x}", header.flags).as_str());
@ -459,94 +471,130 @@ fn dns_log_json_answer(header: &DNSHeader, answer: &DNSAnswerEntry)
if header.flags & 0x0080 != 0 {
js.set_boolean("ra", true);
}
js.set_string("rcode", &dns_rcode_string(header.flags));
js.set_string_from_bytes("rrname", &answer.name);
js.set_string("rrtype", &dns_rrtype_string(answer.rrtype));
js.set_integer("ttl", answer.ttl as u64);
match answer.rrtype {
DNS_RECORD_TYPE_A | DNS_RECORD_TYPE_AAAA => {
js.set_string("rdata", &dns_print_addr(&answer.data));
}
DNS_RECORD_TYPE_CNAME |
DNS_RECORD_TYPE_MX |
DNS_RECORD_TYPE_TXT |
DNS_RECORD_TYPE_PTR => {
js.set_string_from_bytes("rdata", &answer.data);
},
DNS_RECORD_TYPE_SSHFP => {
dns_log_sshfp(&js, &answer);
},
_ => {}
for query in &response.queries {
js.set_string_from_bytes("rrname", &query.name);
break;
}
js.set_string("rcode", &dns_rcode_string(header.flags));
return js;
}
if response.answers.len() > 0 {
let js_answers = Json::array();
fn dns_log_json_failure(r: &DNSResponse, index: usize, flags: u64)
-> * mut JsonT {
if index >= r.queries.len() {
return std::ptr::null_mut();
}
// For grouped answers we use a HashMap keyed by the rrtype.
let mut answer_types = HashMap::new();
let ref query = r.queries[index];
for answer in &response.answers {
if !dns_log_rrtype_enabled(query.rrtype, flags) {
return std::ptr::null_mut();
}
if flags & LOG_FORMAT_GROUPED != 0 {
let type_string = dns_rrtype_string(answer.rrtype);
match answer.rrtype {
DNS_RECORD_TYPE_A | DNS_RECORD_TYPE_AAAA => {
if !answer_types.contains_key(&type_string) {
answer_types.insert(type_string.to_string(),
Json::array());
}
for a in &answer_types.get(&type_string) {
a.array_append(
Json::string(&dns_print_addr(&answer.data)));
}
}
DNS_RECORD_TYPE_CNAME |
DNS_RECORD_TYPE_MX |
DNS_RECORD_TYPE_TXT |
DNS_RECORD_TYPE_PTR => {
if !answer_types.contains_key(&type_string) {
answer_types.insert(type_string.to_string(),
Json::array());
}
for a in &answer_types.get(&type_string) {
a.array_append(
Json::string_from_bytes(&answer.data));
}
},
DNS_RECORD_TYPE_SSHFP => {
if !answer_types.contains_key(&type_string) {
answer_types.insert(type_string.to_string(),
Json::array());
}
for a in &answer_types.get(&type_string) {
for sshfp in dns_log_sshfp(&answer) {
a.array_append(sshfp);
}
}
},
_ => {}
}
}
let js = Json::object();
if flags & LOG_FORMAT_DETAILED != 0 {
js_answers.array_append(dns_log_json_answer_detail(answer));
}
}
js.set_string("type", "answer");
js.set_integer("id", r.header.tx_id as u64);
js.set_string("rcode", &dns_rcode_string(r.header.flags));
js.set_string_from_bytes("rrname", &query.name);
if flags & LOG_FORMAT_DETAILED != 0 {
js.set("answers", js_answers);
}
if flags & LOG_FORMAT_GROUPED != 0 {
let grouped = Json::object();
for (k, v) in answer_types.drain() {
grouped.set(&k, v);
}
js.set("grouped", grouped);
}
}
if response.authorities.len() > 0 {
let js_auth = Json::array();
for auth in &response.authorities {
js_auth.array_append(dns_log_json_answer_detail(auth));
}
js.set("authorities", js_auth);
}
return js.unwrap();
return js;
}
#[no_mangle]
pub extern "C" fn rs_dns_log_json_answer(tx: &mut DNSTransaction,
i: libc::uint16_t,
flags: libc::uint64_t)
-> *mut JsonT
pub extern "C" fn rs_dns_log_json_query(tx: &mut DNSTransaction,
i: libc::uint16_t,
flags: libc::uint64_t)
-> *mut JsonT
{
let index = i as usize;
for response in &tx.response {
if response.header.flags & 0x000f > 0 {
if index == 0 {
return dns_log_json_failure(response, index, flags);
for request in &tx.request {
if index < request.queries.len() {
let query = &request.queries[index];
if dns_log_rrtype_enabled(query.rrtype, flags) {
let js = Json::object();
js.set_string("type", "query");
js.set_integer("id", request.header.tx_id as u64);
js.set_string_from_bytes("rrname", &query.name);
js.set_string("rrtype", &dns_rrtype_string(query.rrtype));
js.set_integer("tx_id", tx.id - 1);
return js.unwrap();
}
break;
}
if index >= response.answers.len() {
break;
}
let answer = &response.answers[index];
if dns_log_rrtype_enabled(answer.rrtype, flags) {
let js = dns_log_json_answer(&response.header, answer);
return js.unwrap();
}
}
return std::ptr::null_mut();
}
#[no_mangle]
pub extern "C" fn rs_dns_log_json_authority(tx: &mut DNSTransaction,
i: libc::uint16_t,
flags: libc::uint64_t)
-> *mut JsonT
pub extern "C" fn rs_dns_log_json_answer(tx: &mut DNSTransaction,
flags: libc::uint64_t)
-> *mut JsonT
{
let index = i as usize;
for response in &tx.response {
if index >= response.authorities.len() {
break;
}
let answer = &response.authorities[index];
if dns_log_rrtype_enabled(answer.rrtype, flags) {
let js = dns_log_json_answer(&response.header, answer);
return js.unwrap();
for query in &response.queries {
if dns_log_rrtype_enabled(query.rrtype, flags) {
let js = dns_log_json_answer(response, flags as u64);
return js.unwrap();
}
}
}
return std::ptr::null_mut();
}

@ -1077,30 +1077,14 @@ static int JsonDnsLoggerToClient(ThreadVars *tv, void *thread_data,
}
#if HAVE_RUST
/* Log answers. */
for (uint16_t i = 0; i < 0xffff; i++) {
json_t *answer = rs_dns_log_json_answer(txptr, i,
if (td->dnslog_ctx->version == DNS_VERSION_2) {
json_t *answer = rs_dns_log_json_answer(txptr,
td->dnslog_ctx->flags);
if (answer == NULL) {
break;
if (answer != NULL) {
json_object_set_new(js, "dns", answer);
MemBufferReset(td->buffer);
OutputJSONBuffer(js, td->dnslog_ctx->file_ctx, &td->buffer);
}
json_object_set_new(js, "dns", answer);
MemBufferReset(td->buffer);
OutputJSONBuffer(js, td->dnslog_ctx->file_ctx, &td->buffer);
json_object_del(js, "dns");
}
/* Log authorities. */
for (uint16_t i = 0; i < 0xffff; i++) {
json_t *answer = rs_dns_log_json_authority(txptr, i,
td->dnslog_ctx->flags);
if (answer == NULL) {
break;
}
json_object_set_new(js, "dns", answer);
MemBufferReset(td->buffer);
OutputJSONBuffer(js, td->dnslog_ctx->file_ctx, &td->buffer);
json_object_del(js, "dns");
}
#else
DNSTransaction *tx = txptr;
@ -1229,34 +1213,43 @@ static void JsonDnsLogParseConfig(LogDnsFileCtx *dnslog_ctx, ConfNode *conf,
}
}
static DnsVersion JsonDnsParseVersion(ConfNode *conf)
{
if (conf == NULL) {
return DNS_VERSION_1;
}
DnsVersion version = DNS_VERSION_1;
intmax_t config_version;
if (ConfGetChildValueInt(conf, "version", &config_version)) {
switch(config_version) {
case 1:
version = DNS_VERSION_1;
break;
case 2:
version = DNS_VERSION_2;
break;
default:
SCLogWarning(SC_ERR_INVALID_ARGUMENT,
"Invalid version option: %ji, "
"forcing it to version 1", config_version);
version = DNS_VERSION_1;
break;
}
} else {
SCLogWarning(SC_ERR_INVALID_ARGUMENT,
"Version not found, forcing it to version 1");
version = DNS_VERSION_1;
}
return version;
}
static void JsonDnsLogInitFilters(LogDnsFileCtx *dnslog_ctx, ConfNode *conf)
{
dnslog_ctx->flags = ~0UL;
if (conf) {
intmax_t version;
int ret = ConfGetChildValueInt(conf, "version", &version);
if (ret) {
switch(version) {
case 1:
dnslog_ctx->version = DNS_VERSION_1;
break;
case 2:
dnslog_ctx->version = DNS_VERSION_2;
break;
default:
SCLogWarning(SC_ERR_INVALID_ARGUMENT,
"Invalid version option: %ji, "
"forcing it to version 1", version);
dnslog_ctx->version = DNS_VERSION_1;
break;
}
} else {
SCLogWarning(SC_ERR_INVALID_ARGUMENT,
"Version not found, forcing it to version 1");
dnslog_ctx->version = DNS_VERSION_1;
}
if (dnslog_ctx->version == DNS_VERSION_1) {
JsonDnsLogParseConfig(dnslog_ctx, conf, "query", "answer", "custom");
} else {
@ -1287,9 +1280,19 @@ static OutputInitResult JsonDnsLogInitCtxSub(ConfNode *conf, OutputCtx *parent_c
OutputInitResult result = { NULL, false };
const char *enabled = ConfNodeLookupChildValue(conf, "enabled");
if (enabled != NULL && !ConfValIsTrue(enabled)) {
result.ok = true;
return result;
}
DnsVersion version = JsonDnsParseVersion(conf);
#ifdef HAVE_RUST
if (version != 2) {
SCLogError(SC_ERR_NOT_SUPPORTED, "EVE/DNS version %d not support with "
"by Rust builds.", version);
exit(1);
}
#endif
OutputJsonCtx *ojc = parent_ctx->data;
LogDnsFileCtx *dnslog_ctx = SCMalloc(sizeof(LogDnsFileCtx));
@ -1310,6 +1313,7 @@ static OutputInitResult JsonDnsLogInitCtxSub(ConfNode *conf, OutputCtx *parent_c
output_ctx->data = dnslog_ctx;
output_ctx->DeInit = LogDnsLogDeInitCtxSub;
dnslog_ctx->version = version;
JsonDnsLogInitFilters(dnslog_ctx, conf);
SCLogDebug("DNS log sub-module initialized");
@ -1335,6 +1339,15 @@ static OutputInitResult JsonDnsLogInitCtx(ConfNode *conf)
return result;
}
DnsVersion version = JsonDnsParseVersion(conf);
#ifdef HAVE_RUST
if (version != 2) {
SCLogError(SC_ERR_NOT_SUPPORTED, "EVE/DNS version %d not support with "
"by Rust builds.", version);
exit(1);
}
#endif
LogFileCtx *file_ctx = LogFileNewCtx();
if(file_ctx == NULL) {
@ -1366,6 +1379,7 @@ static OutputInitResult JsonDnsLogInitCtx(ConfNode *conf)
output_ctx->data = dnslog_ctx;
output_ctx->DeInit = LogDnsLogDeInitCtx;
dnslog_ctx->version = version;
JsonDnsLogInitFilters(dnslog_ctx, conf);
SCLogDebug("DNS log output initialized");

Loading…
Cancel
Save