summaryrefslogtreecommitdiffstats
path: root/rust/src/dns/log.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rust/src/dns/log.rs')
-rw-r--r--rust/src/dns/log.rs671
1 files changed, 671 insertions, 0 deletions
diff --git a/rust/src/dns/log.rs b/rust/src/dns/log.rs
new file mode 100644
index 0000000..5212b1a
--- /dev/null
+++ b/rust/src/dns/log.rs
@@ -0,0 +1,671 @@
+/* Copyright (C) 2017 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+use std;
+use std::collections::HashMap;
+use std::string::String;
+
+use crate::dns::dns::*;
+use crate::jsonbuilder::{JsonBuilder, JsonError};
+
+pub const LOG_A: u64 = BIT_U64!(2);
+pub const LOG_NS: u64 = BIT_U64!(3);
+pub const LOG_MD: u64 = BIT_U64!(4);
+pub const LOG_MF: u64 = BIT_U64!(5);
+pub const LOG_CNAME: u64 = BIT_U64!(6);
+pub const LOG_SOA: u64 = BIT_U64!(7);
+pub const LOG_MB: u64 = BIT_U64!(8);
+pub const LOG_MG: u64 = BIT_U64!(9);
+pub const LOG_MR: u64 = BIT_U64!(10);
+pub const LOG_NULL: u64 = BIT_U64!(11);
+pub const LOG_WKS: u64 = BIT_U64!(12);
+pub const LOG_PTR: u64 = BIT_U64!(13);
+pub const LOG_HINFO: u64 = BIT_U64!(14);
+pub const LOG_MINFO: u64 = BIT_U64!(15);
+pub const LOG_MX: u64 = BIT_U64!(16);
+pub const LOG_TXT: u64 = BIT_U64!(17);
+pub const LOG_RP: u64 = BIT_U64!(18);
+pub const LOG_AFSDB: u64 = BIT_U64!(19);
+pub const LOG_X25: u64 = BIT_U64!(20);
+pub const LOG_ISDN: u64 = BIT_U64!(21);
+pub const LOG_RT: u64 = BIT_U64!(22);
+pub const LOG_NSAP: u64 = BIT_U64!(23);
+pub const LOG_NSAPPTR: u64 = BIT_U64!(24);
+pub const LOG_SIG: u64 = BIT_U64!(25);
+pub const LOG_KEY: u64 = BIT_U64!(26);
+pub const LOG_PX: u64 = BIT_U64!(27);
+pub const LOG_GPOS: u64 = BIT_U64!(28);
+pub const LOG_AAAA: u64 = BIT_U64!(29);
+pub const LOG_LOC: u64 = BIT_U64!(30);
+pub const LOG_NXT: u64 = BIT_U64!(31);
+pub const LOG_SRV: u64 = BIT_U64!(32);
+pub const LOG_ATMA: u64 = BIT_U64!(33);
+pub const LOG_NAPTR: u64 = BIT_U64!(34);
+pub const LOG_KX: u64 = BIT_U64!(35);
+pub const LOG_CERT: u64 = BIT_U64!(36);
+pub const LOG_A6: u64 = BIT_U64!(37);
+pub const LOG_DNAME: u64 = BIT_U64!(38);
+pub const LOG_OPT: u64 = BIT_U64!(39);
+pub const LOG_APL: u64 = BIT_U64!(40);
+pub const LOG_DS: u64 = BIT_U64!(41);
+pub const LOG_SSHFP: u64 = BIT_U64!(42);
+pub const LOG_IPSECKEY: u64 = BIT_U64!(43);
+pub const LOG_RRSIG: u64 = BIT_U64!(44);
+pub const LOG_NSEC: u64 = BIT_U64!(45);
+pub const LOG_DNSKEY: u64 = BIT_U64!(46);
+pub const LOG_DHCID: u64 = BIT_U64!(47);
+pub const LOG_NSEC3: u64 = BIT_U64!(48);
+pub const LOG_NSEC3PARAM: u64 = BIT_U64!(49);
+pub const LOG_TLSA: u64 = BIT_U64!(50);
+pub const LOG_HIP: u64 = BIT_U64!(51);
+pub const LOG_CDS: u64 = BIT_U64!(52);
+pub const LOG_CDNSKEY: u64 = BIT_U64!(53);
+pub const LOG_SPF: u64 = BIT_U64!(54);
+pub const LOG_TKEY: u64 = BIT_U64!(55);
+pub const LOG_TSIG: u64 = BIT_U64!(56);
+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);
+pub const LOG_HTTPS: u64 = BIT_U64!(62);
+
+fn dns_log_rrtype_enabled(rtype: u16, flags: u64) -> bool {
+ if flags == !0 {
+ return true;
+ }
+
+ match rtype {
+ DNS_RECORD_TYPE_A => {
+ return flags & LOG_A != 0;
+ }
+ DNS_RECORD_TYPE_NS => {
+ return flags & LOG_NS != 0;
+ }
+ DNS_RECORD_TYPE_MD => {
+ return flags & LOG_MD != 0;
+ }
+ DNS_RECORD_TYPE_MF => {
+ return flags & LOG_MF != 0;
+ }
+ DNS_RECORD_TYPE_CNAME => {
+ return flags & LOG_CNAME != 0;
+ }
+ DNS_RECORD_TYPE_SOA => {
+ return flags & LOG_SOA != 0;
+ }
+ DNS_RECORD_TYPE_MB => {
+ return flags & LOG_MB != 0;
+ }
+ DNS_RECORD_TYPE_MG => {
+ return flags & LOG_MG != 0;
+ }
+ DNS_RECORD_TYPE_MR => {
+ return flags & LOG_MR != 0;
+ }
+ DNS_RECORD_TYPE_NULL => {
+ return flags & LOG_NULL != 0;
+ }
+ DNS_RECORD_TYPE_WKS => {
+ return flags & LOG_WKS != 0;
+ }
+ DNS_RECORD_TYPE_PTR => {
+ return flags & LOG_PTR != 0;
+ }
+ DNS_RECORD_TYPE_HINFO => {
+ return flags & LOG_HINFO != 0;
+ }
+ DNS_RECORD_TYPE_MINFO => {
+ return flags & LOG_MINFO != 0;
+ }
+ DNS_RECORD_TYPE_MX => {
+ return flags & LOG_MX != 0;
+ }
+ DNS_RECORD_TYPE_TXT => {
+ return flags & LOG_TXT != 0;
+ }
+ DNS_RECORD_TYPE_RP => {
+ return flags & LOG_RP != 0;
+ }
+ DNS_RECORD_TYPE_AFSDB => {
+ return flags & LOG_AFSDB != 0;
+ }
+ DNS_RECORD_TYPE_X25 => {
+ return flags & LOG_X25 != 0;
+ }
+ DNS_RECORD_TYPE_ISDN => {
+ return flags & LOG_ISDN != 0;
+ }
+ DNS_RECORD_TYPE_RT => {
+ return flags & LOG_RT != 0;
+ }
+ DNS_RECORD_TYPE_NSAP => {
+ return flags & LOG_NSAP != 0;
+ }
+ DNS_RECORD_TYPE_NSAPPTR => {
+ return flags & LOG_NSAPPTR != 0;
+ }
+ DNS_RECORD_TYPE_SIG => {
+ return flags & LOG_SIG != 0;
+ }
+ DNS_RECORD_TYPE_KEY => {
+ return flags & LOG_KEY != 0;
+ }
+ DNS_RECORD_TYPE_PX => {
+ return flags & LOG_PX != 0;
+ }
+ DNS_RECORD_TYPE_GPOS => {
+ return flags & LOG_GPOS != 0;
+ }
+ DNS_RECORD_TYPE_AAAA => {
+ return flags & LOG_AAAA != 0;
+ }
+ DNS_RECORD_TYPE_LOC => {
+ return flags & LOG_LOC != 0;
+ }
+ DNS_RECORD_TYPE_NXT => {
+ return flags & LOG_NXT != 0;
+ }
+ DNS_RECORD_TYPE_SRV => {
+ return flags & LOG_SRV != 0;
+ }
+ DNS_RECORD_TYPE_ATMA => {
+ return flags & LOG_ATMA != 0;
+ }
+ DNS_RECORD_TYPE_NAPTR => {
+ return flags & LOG_NAPTR != 0;
+ }
+ DNS_RECORD_TYPE_KX => {
+ return flags & LOG_KX != 0;
+ }
+ DNS_RECORD_TYPE_CERT => {
+ return flags & LOG_CERT != 0;
+ }
+ DNS_RECORD_TYPE_A6 => {
+ return flags & LOG_A6 != 0;
+ }
+ DNS_RECORD_TYPE_DNAME => {
+ return flags & LOG_DNAME != 0;
+ }
+ DNS_RECORD_TYPE_OPT => {
+ return flags & LOG_OPT != 0;
+ }
+ DNS_RECORD_TYPE_APL => {
+ return flags & LOG_APL != 0;
+ }
+ DNS_RECORD_TYPE_DS => {
+ return flags & LOG_DS != 0;
+ }
+ DNS_RECORD_TYPE_SSHFP => {
+ return flags & LOG_SSHFP != 0;
+ }
+ DNS_RECORD_TYPE_IPSECKEY => {
+ return flags & LOG_IPSECKEY != 0;
+ }
+ DNS_RECORD_TYPE_RRSIG => {
+ return flags & LOG_RRSIG != 0;
+ }
+ DNS_RECORD_TYPE_NSEC => {
+ return flags & LOG_NSEC != 0;
+ }
+ DNS_RECORD_TYPE_DNSKEY => {
+ return flags & LOG_DNSKEY != 0;
+ }
+ DNS_RECORD_TYPE_DHCID => {
+ return flags & LOG_DHCID != 0;
+ }
+ DNS_RECORD_TYPE_NSEC3 => return flags & LOG_NSEC3 != 0,
+ DNS_RECORD_TYPE_NSEC3PARAM => {
+ return flags & LOG_NSEC3PARAM != 0;
+ }
+ DNS_RECORD_TYPE_TLSA => {
+ return flags & LOG_TLSA != 0;
+ }
+ DNS_RECORD_TYPE_HIP => {
+ return flags & LOG_HIP != 0;
+ }
+ DNS_RECORD_TYPE_CDS => {
+ return flags & LOG_CDS != 0;
+ }
+ DNS_RECORD_TYPE_CDNSKEY => {
+ return flags & LOG_CDNSKEY != 0;
+ }
+ DNS_RECORD_TYPE_HTTPS => {
+ return flags & LOG_HTTPS != 0;
+ }
+ DNS_RECORD_TYPE_SPF => {
+ return flags & LOG_SPF != 0;
+ }
+ DNS_RECORD_TYPE_TKEY => {
+ return flags & LOG_TKEY != 0;
+ }
+ DNS_RECORD_TYPE_TSIG => {
+ return flags & LOG_TSIG != 0;
+ }
+ DNS_RECORD_TYPE_MAILA => {
+ return flags & LOG_MAILA != 0;
+ }
+ DNS_RECORD_TYPE_ANY => {
+ return flags & LOG_ANY != 0;
+ }
+ DNS_RECORD_TYPE_URI => {
+ return flags & LOG_URI != 0;
+ }
+ _ => {
+ return false;
+ }
+ }
+}
+
+pub fn dns_rrtype_string(rrtype: u16) -> String {
+ match rrtype {
+ DNS_RECORD_TYPE_A => "A",
+ DNS_RECORD_TYPE_NS => "NS",
+ DNS_RECORD_TYPE_AAAA => "AAAA",
+ DNS_RECORD_TYPE_CNAME => "CNAME",
+ DNS_RECORD_TYPE_TXT => "TXT",
+ DNS_RECORD_TYPE_MX => "MX",
+ DNS_RECORD_TYPE_SOA => "SOA",
+ DNS_RECORD_TYPE_PTR => "PTR",
+ DNS_RECORD_TYPE_SIG => "SIG",
+ DNS_RECORD_TYPE_KEY => "KEY",
+ DNS_RECORD_TYPE_WKS => "WKS",
+ DNS_RECORD_TYPE_TKEY => "TKEY",
+ DNS_RECORD_TYPE_TSIG => "TSIG",
+ DNS_RECORD_TYPE_ANY => "ANY",
+ DNS_RECORD_TYPE_RRSIG => "RRSIG",
+ DNS_RECORD_TYPE_NSEC => "NSEC",
+ DNS_RECORD_TYPE_DNSKEY => "DNSKEY",
+ DNS_RECORD_TYPE_HINFO => "HINFO",
+ DNS_RECORD_TYPE_MINFO => "MINFO",
+ DNS_RECORD_TYPE_RP => "RP",
+ DNS_RECORD_TYPE_AFSDB => "AFSDB",
+ DNS_RECORD_TYPE_X25 => "X25",
+ DNS_RECORD_TYPE_ISDN => "ISDN",
+ DNS_RECORD_TYPE_RT => "RT",
+ DNS_RECORD_TYPE_NSAP => "NSAP",
+ DNS_RECORD_TYPE_NSAPPTR => "NSAPPT",
+ DNS_RECORD_TYPE_PX => "PX",
+ DNS_RECORD_TYPE_GPOS => "GPOS",
+ DNS_RECORD_TYPE_LOC => "LOC",
+ DNS_RECORD_TYPE_SRV => "SRV",
+ DNS_RECORD_TYPE_ATMA => "ATMA",
+ DNS_RECORD_TYPE_NAPTR => "NAPTR",
+ DNS_RECORD_TYPE_KX => "KX",
+ DNS_RECORD_TYPE_CERT => "CERT",
+ DNS_RECORD_TYPE_A6 => "A6",
+ DNS_RECORD_TYPE_DNAME => "DNAME",
+ DNS_RECORD_TYPE_OPT => "OPT",
+ DNS_RECORD_TYPE_APL => "APL",
+ DNS_RECORD_TYPE_DS => "DS",
+ DNS_RECORD_TYPE_SSHFP => "SSHFP",
+ DNS_RECORD_TYPE_IPSECKEY => "IPSECKEY",
+ DNS_RECORD_TYPE_DHCID => "DHCID",
+ DNS_RECORD_TYPE_NSEC3 => "NSEC3",
+ DNS_RECORD_TYPE_NSEC3PARAM => "NSEC3PARAM",
+ DNS_RECORD_TYPE_TLSA => "TLSA",
+ DNS_RECORD_TYPE_HIP => "HIP",
+ DNS_RECORD_TYPE_CDS => "CDS",
+ DNS_RECORD_TYPE_CDNSKEY => "CDSNKEY",
+ DNS_RECORD_TYPE_HTTPS => "HTTPS",
+ DNS_RECORD_TYPE_MAILA => "MAILA",
+ DNS_RECORD_TYPE_URI => "URI",
+ DNS_RECORD_TYPE_MB => "MB",
+ DNS_RECORD_TYPE_MG => "MG",
+ DNS_RECORD_TYPE_MR => "MR",
+ DNS_RECORD_TYPE_NULL => "NULL",
+ DNS_RECORD_TYPE_SPF => "SPF",
+ DNS_RECORD_TYPE_NXT => "NXT",
+ DNS_RECORD_TYPE_MD => "ND",
+ DNS_RECORD_TYPE_MF => "MF",
+ _ => {
+ return rrtype.to_string();
+ }
+ }
+ .to_string()
+}
+
+pub fn dns_rcode_string(flags: u16) -> String {
+ match flags & 0x000f {
+ DNS_RCODE_NOERROR => "NOERROR",
+ DNS_RCODE_FORMERR => "FORMERR",
+ DNS_RCODE_SERVFAIL => "SERVFAIL",
+ DNS_RCODE_NXDOMAIN => "NXDOMAIN",
+ DNS_RCODE_NOTIMP => "NOTIMP",
+ DNS_RCODE_REFUSED => "REFUSED",
+ DNS_RCODE_YXDOMAIN => "YXDOMAIN",
+ DNS_RCODE_YXRRSET => "YXRRSET",
+ DNS_RCODE_NXRRSET => "NXRRSET",
+ DNS_RCODE_NOTAUTH => "NOTAUTH",
+ DNS_RCODE_NOTZONE => "NOTZONE",
+ DNS_RCODE_BADVERS => "BADVERS/BADSIG",
+ DNS_RCODE_BADKEY => "BADKEY",
+ DNS_RCODE_BADTIME => "BADTIME",
+ DNS_RCODE_BADMODE => "BADMODE",
+ DNS_RCODE_BADNAME => "BADNAME",
+ DNS_RCODE_BADALG => "BADALG",
+ DNS_RCODE_BADTRUNC => "BADTRUNC",
+ _ => {
+ return (flags & 0x000f).to_string();
+ }
+ }
+ .to_string()
+}
+
+/// Format bytes as an IP address string.
+pub fn dns_print_addr(addr: &Vec<u8>) -> std::string::String {
+ if addr.len() == 4 {
+ return format!("{}.{}.{}.{}", addr[0], addr[1], addr[2], addr[3]);
+ } else if addr.len() == 16 {
+ return format!("{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}",
+ addr[0],
+ addr[1],
+ addr[2],
+ addr[3],
+ addr[4],
+ addr[5],
+ addr[6],
+ addr[7],
+ addr[8],
+ addr[9],
+ addr[10],
+ addr[11],
+ addr[12],
+ addr[13],
+ addr[14],
+ addr[15]);
+ } else {
+ return "".to_string();
+ }
+}
+
+/// Log SOA section fields.
+fn dns_log_soa(soa: &DNSRDataSOA) -> Result<JsonBuilder, JsonError> {
+ let mut js = JsonBuilder::try_new_object()?;
+
+ js.set_string_from_bytes("mname", &soa.mname)?;
+ js.set_string_from_bytes("rname", &soa.rname)?;
+ js.set_uint("serial", soa.serial as u64)?;
+ js.set_uint("refresh", soa.refresh as u64)?;
+ js.set_uint("retry", soa.retry as u64)?;
+ js.set_uint("expire", soa.expire as u64)?;
+ js.set_uint("minimum", soa.minimum as u64)?;
+
+ js.close()?;
+ return Ok(js);
+}
+
+/// Log SSHFP section fields.
+fn dns_log_sshfp(sshfp: &DNSRDataSSHFP) -> Result<JsonBuilder, JsonError> {
+ let mut js = JsonBuilder::try_new_object()?;
+
+ let mut hex = Vec::new();
+ for byte in &sshfp.fingerprint {
+ hex.push(format!("{:02x}", byte));
+ }
+
+ js.set_string("fingerprint", &hex.join(":"))?;
+ js.set_uint("algo", sshfp.algo as u64)?;
+ js.set_uint("type", sshfp.fp_type as u64)?;
+
+ js.close()?;
+ return Ok(js);
+}
+
+/// Log SRV section fields.
+fn dns_log_srv(srv: &DNSRDataSRV) -> Result<JsonBuilder, JsonError> {
+ let mut js = JsonBuilder::try_new_object()?;
+
+ js.set_uint("priority", srv.priority as u64)?;
+ js.set_uint("weight", srv.weight as u64)?;
+ js.set_uint("port", srv.port as u64)?;
+ js.set_string_from_bytes("name", &srv.target)?;
+
+ js.close()?;
+ return Ok(js);
+}
+
+fn dns_log_json_answer_detail(answer: &DNSAnswerEntry) -> Result<JsonBuilder, JsonError> {
+ let mut jsa = JsonBuilder::try_new_object()?;
+
+ jsa.set_string_from_bytes("rrname", &answer.name)?;
+ jsa.set_string("rrtype", &dns_rrtype_string(answer.rrtype))?;
+ jsa.set_uint("ttl", answer.ttl as u64)?;
+
+ match &answer.data {
+ DNSRData::A(addr) | DNSRData::AAAA(addr) => {
+ jsa.set_string("rdata", &dns_print_addr(addr))?;
+ }
+ DNSRData::CNAME(bytes)
+ | DNSRData::MX(bytes)
+ | DNSRData::NS(bytes)
+ | DNSRData::TXT(bytes)
+ | DNSRData::NULL(bytes)
+ | DNSRData::PTR(bytes) => {
+ jsa.set_string_from_bytes("rdata", bytes)?;
+ }
+ DNSRData::SOA(soa) => {
+ jsa.set_object("soa", &dns_log_soa(soa)?)?;
+ }
+ DNSRData::SSHFP(sshfp) => {
+ jsa.set_object("sshfp", &dns_log_sshfp(sshfp)?)?;
+ }
+ DNSRData::SRV(srv) => {
+ jsa.set_object("srv", &dns_log_srv(srv)?)?;
+ }
+ _ => {}
+ }
+
+ jsa.close()?;
+ return Ok(jsa);
+}
+
+fn dns_log_json_answer(
+ js: &mut JsonBuilder, response: &DNSResponse, flags: u64,
+) -> Result<(), JsonError> {
+ let header = &response.header;
+
+ js.set_uint("version", 2)?;
+ js.set_string("type", "answer")?;
+ js.set_uint("id", header.tx_id as u64)?;
+ js.set_string("flags", format!("{:x}", header.flags).as_str())?;
+ if header.flags & 0x8000 != 0 {
+ js.set_bool("qr", true)?;
+ }
+ if header.flags & 0x0400 != 0 {
+ js.set_bool("aa", true)?;
+ }
+ if header.flags & 0x0200 != 0 {
+ js.set_bool("tc", true)?;
+ }
+ if header.flags & 0x0100 != 0 {
+ js.set_bool("rd", true)?;
+ }
+ if header.flags & 0x0080 != 0 {
+ js.set_bool("ra", true)?;
+ }
+ if header.flags & 0x0040 != 0 {
+ js.set_bool("z", true)?;
+ }
+
+ let opcode = ((header.flags >> 11) & 0xf) as u8;
+ js.set_uint("opcode", opcode as u64)?;
+
+ if let Some(query) = response.queries.first() {
+ js.set_string_from_bytes("rrname", &query.name)?;
+ js.set_string("rrtype", &dns_rrtype_string(query.rrtype))?;
+ }
+ js.set_string("rcode", &dns_rcode_string(header.flags))?;
+
+ if !response.answers.is_empty() {
+ let mut js_answers = JsonBuilder::try_new_array()?;
+
+ // For grouped answers we use a HashMap keyed by the rrtype.
+ let mut answer_types = HashMap::new();
+
+ for answer in &response.answers {
+ if flags & LOG_FORMAT_GROUPED != 0 {
+ let type_string = dns_rrtype_string(answer.rrtype);
+ match &answer.data {
+ DNSRData::A(addr) | DNSRData::AAAA(addr) => {
+ if !answer_types.contains_key(&type_string) {
+ answer_types.insert(type_string.to_string(), JsonBuilder::try_new_array()?);
+ }
+ if let Some(a) = answer_types.get_mut(&type_string) {
+ a.append_string(&dns_print_addr(addr))?;
+ }
+ }
+ DNSRData::CNAME(bytes)
+ | DNSRData::MX(bytes)
+ | DNSRData::NS(bytes)
+ | DNSRData::TXT(bytes)
+ | DNSRData::NULL(bytes)
+ | DNSRData::PTR(bytes) => {
+ if !answer_types.contains_key(&type_string) {
+ answer_types.insert(type_string.to_string(), JsonBuilder::try_new_array()?);
+ }
+ if let Some(a) = answer_types.get_mut(&type_string) {
+ a.append_string_from_bytes(bytes)?;
+ }
+ }
+ DNSRData::SOA(soa) => {
+ if !answer_types.contains_key(&type_string) {
+ answer_types.insert(type_string.to_string(), JsonBuilder::try_new_array()?);
+ }
+ if let Some(a) = answer_types.get_mut(&type_string) {
+ a.append_object(&dns_log_soa(soa)?)?;
+ }
+ }
+ DNSRData::SSHFP(sshfp) => {
+ if !answer_types.contains_key(&type_string) {
+ answer_types.insert(type_string.to_string(), JsonBuilder::try_new_array()?);
+ }
+ if let Some(a) = answer_types.get_mut(&type_string) {
+ a.append_object(&dns_log_sshfp(sshfp)?)?;
+ }
+ }
+ DNSRData::SRV(srv) => {
+ if !answer_types.contains_key(&type_string) {
+ answer_types.insert(type_string.to_string(), JsonBuilder::try_new_array()?);
+ }
+ if let Some(a) = answer_types.get_mut(&type_string) {
+ a.append_object(&dns_log_srv(srv)?)?;
+ }
+ }
+ _ => {}
+ }
+ }
+
+ if flags & LOG_FORMAT_DETAILED != 0 {
+ js_answers.append_object(&dns_log_json_answer_detail(answer)?)?;
+ }
+ }
+
+ js_answers.close()?;
+
+ if flags & LOG_FORMAT_DETAILED != 0 {
+ js.set_object("answers", &js_answers)?;
+ }
+
+ if flags & LOG_FORMAT_GROUPED != 0 {
+ js.open_object("grouped")?;
+ for (k, mut v) in answer_types.drain() {
+ v.close()?;
+ js.set_object(&k, &v)?;
+ }
+ js.close()?;
+ }
+ }
+
+ if !response.authorities.is_empty() {
+ js.open_array("authorities")?;
+ for auth in &response.authorities {
+ let auth_detail = dns_log_json_answer_detail(auth)?;
+ js.append_object(&auth_detail)?;
+ }
+ js.close()?;
+ }
+
+ Ok(())
+}
+
+fn dns_log_query(
+ tx: &mut DNSTransaction, i: u16, flags: u64, jb: &mut JsonBuilder,
+) -> Result<bool, JsonError> {
+ let index = i as usize;
+ if let Some(request) = &tx.request {
+ if index < request.queries.len() {
+ let query = &request.queries[index];
+ if dns_log_rrtype_enabled(query.rrtype, flags) {
+ jb.set_string("type", "query")?;
+ jb.set_uint("id", request.header.tx_id as u64)?;
+ jb.set_string_from_bytes("rrname", &query.name)?;
+ jb.set_string("rrtype", &dns_rrtype_string(query.rrtype))?;
+ jb.set_uint("tx_id", tx.id - 1)?;
+ if request.header.flags & 0x0040 != 0 {
+ jb.set_bool("z", true)?;
+ }
+ let opcode = ((request.header.flags >> 11) & 0xf) as u8;
+ jb.set_uint("opcode", opcode as u64)?;
+ return Ok(true);
+ }
+ }
+ }
+
+ return Ok(false);
+}
+
+#[no_mangle]
+pub extern "C" fn rs_dns_log_json_query(
+ tx: &mut DNSTransaction, i: u16, flags: u64, jb: &mut JsonBuilder,
+) -> bool {
+ match dns_log_query(tx, i, flags, jb) {
+ Ok(false) | Err(_) => {
+ return false;
+ }
+ Ok(true) => {
+ return true;
+ }
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn rs_dns_log_json_answer(
+ tx: &mut DNSTransaction, flags: u64, js: &mut JsonBuilder,
+) -> bool {
+ if let Some(response) = &tx.response {
+ for query in &response.queries {
+ if dns_log_rrtype_enabled(query.rrtype, flags) {
+ return dns_log_json_answer(js, response, flags).is_ok();
+ }
+ }
+ }
+ return false;
+}
+
+#[no_mangle]
+pub extern "C" fn rs_dns_do_log_answer(tx: &mut DNSTransaction, flags: u64) -> bool {
+ if let Some(response) = &tx.response {
+ for query in &response.queries {
+ if dns_log_rrtype_enabled(query.rrtype, flags) {
+ return true;
+ }
+ }
+ }
+ return false;
+}