dnstap_parser/
parser.rs

1use std::{
2    collections::HashSet,
3    convert::TryInto,
4    fmt::Debug,
5    net::{IpAddr, Ipv4Addr, Ipv6Addr},
6    sync::LazyLock,
7};
8
9use base64::prelude::{BASE64_STANDARD, Engine as _};
10use bytes::Bytes;
11use chrono::{TimeZone, Utc};
12use dnsmsg_parser::{dns_message_parser::DnsParserOptions, ede::EDE};
13use hickory_proto::{
14    rr::domain::Name,
15    serialize::binary::{BinDecodable, BinDecoder},
16};
17use prost::Message;
18use snafu::Snafu;
19use vector_lib::{
20    Error, Result, emit,
21    event::{LogEvent, Value},
22};
23use vrl::{owned_value_path, path};
24
25#[allow(warnings, clippy::all, clippy::pedantic, clippy::nursery)]
26mod dnstap_proto {
27    include!(concat!(env!("OUT_DIR"), "/dnstap.rs"));
28}
29
30use dnsmsg_parser::{
31    dns_message::{
32        DnsRecord, EdnsOptionEntry, OptPseudoSection, QueryHeader, QueryQuestion, UpdateHeader,
33        ZoneInfo,
34    },
35    dns_message_parser::DnsMessageParser,
36};
37use dnstap_proto::{
38    Dnstap, Message as DnstapMessage, SocketFamily, SocketProtocol,
39    message::Type as DnstapMessageType,
40};
41use vector_lib::{
42    config::log_schema,
43    lookup::{PathPrefix, lookup_v2::ValuePath},
44};
45
46use crate::{internal_events::DnstapParseWarning, schema::DNSTAP_VALUE_PATHS};
47
48#[derive(Debug, Snafu)]
49enum DnstapParserError {
50    #[snafu(display("Unsupported DNSTap message type: {}", "dnstap_message_type_id"))]
51    UnsupportedDnstapMessageTypeError { dnstap_message_type_id: i32 },
52}
53
54static DNSTAP_MESSAGE_REQUEST_TYPE_IDS: LazyLock<HashSet<i32>> = LazyLock::new(|| {
55    vec![
56        DnstapMessageType::AuthQuery as i32,
57        DnstapMessageType::ResolverQuery as i32,
58        DnstapMessageType::ClientQuery as i32,
59        DnstapMessageType::ForwarderQuery as i32,
60        DnstapMessageType::StubQuery as i32,
61        DnstapMessageType::ToolQuery as i32,
62        DnstapMessageType::UpdateQuery as i32,
63    ]
64    .into_iter()
65    .collect()
66});
67static DNSTAP_MESSAGE_RESPONSE_TYPE_IDS: LazyLock<HashSet<i32>> = LazyLock::new(|| {
68    vec![
69        DnstapMessageType::AuthResponse as i32,
70        DnstapMessageType::ResolverResponse as i32,
71        DnstapMessageType::ClientResponse as i32,
72        DnstapMessageType::ForwarderResponse as i32,
73        DnstapMessageType::StubResponse as i32,
74        DnstapMessageType::ToolResponse as i32,
75        DnstapMessageType::UpdateResponse as i32,
76    ]
77    .into_iter()
78    .collect()
79});
80
81#[derive(Default)]
82pub struct DnstapParser;
83
84impl DnstapParser {
85    fn insert<'a, V>(
86        event: &mut LogEvent,
87        prefix: impl ValuePath<'a>,
88        path: impl ValuePath<'a>,
89        value: V,
90    ) -> Option<Value>
91    where
92        V: Into<Value> + Debug,
93    {
94        event.insert((PathPrefix::Event, prefix.concat(path)), value)
95    }
96
97    pub fn parse(
98        event: &mut LogEvent,
99        frame: Bytes,
100        parsing_options: DnsParserOptions,
101    ) -> Result<()> {
102        //parse frame with dnstap protobuf
103        let proto_msg = Dnstap::decode(frame.clone())?;
104        let root = owned_value_path!();
105        if let Some(server_id) = proto_msg.identity {
106            DnstapParser::insert(
107                event,
108                &root,
109                &DNSTAP_VALUE_PATHS.server_identity,
110                String::from_utf8(server_id.clone()).unwrap_or_default(),
111            );
112        }
113
114        if let Some(version) = proto_msg.version {
115            DnstapParser::insert(
116                event,
117                &root,
118                &DNSTAP_VALUE_PATHS.server_version,
119                String::from_utf8(version).unwrap_or_default(),
120            );
121        }
122
123        if let Some(extra) = proto_msg.extra {
124            DnstapParser::insert(
125                event,
126                &root,
127                &DNSTAP_VALUE_PATHS.extra,
128                String::from_utf8(extra).unwrap_or_default(),
129            );
130        }
131
132        let dnstap_data_type_id: i32 = proto_msg.r#type;
133        let mut need_raw_data = false;
134        DnstapParser::insert(
135            event,
136            &root,
137            &DNSTAP_VALUE_PATHS.data_type_id,
138            dnstap_data_type_id,
139        );
140
141        if let Some(dnstap_data_type) = to_dnstap_data_type(dnstap_data_type_id) {
142            DnstapParser::insert(
143                event,
144                &root,
145                &DNSTAP_VALUE_PATHS.data_type,
146                dnstap_data_type.clone(),
147            );
148
149            if dnstap_data_type == "Message"
150                && let Some(message) = proto_msg.message
151                && let Err(err) =
152                    DnstapParser::parse_dnstap_message(event, &root, message, parsing_options)
153            {
154                emit!(DnstapParseWarning { error: &err });
155                need_raw_data = true;
156                DnstapParser::insert(event, &root, &DNSTAP_VALUE_PATHS.error, err.to_string());
157            }
158        } else {
159            emit!(DnstapParseWarning {
160                error: format!("Unknown dnstap data type: {dnstap_data_type_id}")
161            });
162            need_raw_data = true;
163        }
164
165        if need_raw_data {
166            DnstapParser::insert(
167                event,
168                &root,
169                &DNSTAP_VALUE_PATHS.raw_data,
170                BASE64_STANDARD.encode(&frame),
171            );
172        }
173
174        Ok(())
175    }
176
177    fn parse_dnstap_message<'a>(
178        event: &mut LogEvent,
179        prefix: impl ValuePath<'a>,
180        dnstap_message: DnstapMessage,
181        parsing_options: DnsParserOptions,
182    ) -> Result<()> {
183        if let Some(socket_family) = dnstap_message.socket_family {
184            DnstapParser::parse_dnstap_message_socket_family(
185                event,
186                prefix.clone(),
187                socket_family,
188                &dnstap_message,
189            )?;
190        }
191
192        if let Some(query_zone) = dnstap_message.query_zone.as_ref() {
193            let mut decoder: BinDecoder = BinDecoder::new(query_zone);
194            match Name::read(&mut decoder) {
195                Ok(raw_data) => {
196                    DnstapParser::insert(
197                        event,
198                        prefix.clone(),
199                        &DNSTAP_VALUE_PATHS.query_zone,
200                        raw_data.to_utf8(),
201                    );
202                }
203                Err(error) => return Err(Error::from(error.to_string())),
204            }
205        }
206
207        let dnstap_message_type_id = dnstap_message.r#type;
208        DnstapParser::insert(
209            event,
210            prefix.clone(),
211            &DNSTAP_VALUE_PATHS.message_type_id,
212            dnstap_message_type_id,
213        );
214
215        DnstapParser::insert(
216            event,
217            prefix.clone(),
218            &DNSTAP_VALUE_PATHS.message_type,
219            to_dnstap_message_type(dnstap_message_type_id),
220        );
221
222        if let Some(query_time_sec) = dnstap_message.query_time_sec {
223            DnstapParser::parse_dnstap_message_time(
224                event,
225                prefix.clone(),
226                query_time_sec,
227                dnstap_message.query_time_nsec,
228                dnstap_message_type_id,
229                dnstap_message.query_message.as_ref(),
230                &DNSTAP_MESSAGE_REQUEST_TYPE_IDS,
231            )?;
232        }
233
234        if let Some(response_time_sec) = dnstap_message.response_time_sec {
235            DnstapParser::parse_dnstap_message_time(
236                event,
237                prefix.clone(),
238                response_time_sec,
239                dnstap_message.response_time_nsec,
240                dnstap_message_type_id,
241                dnstap_message.response_message.as_ref(),
242                &DNSTAP_MESSAGE_RESPONSE_TYPE_IDS,
243            )?;
244        }
245
246        DnstapParser::parse_dnstap_message_type(
247            event,
248            prefix.clone(),
249            dnstap_message_type_id,
250            dnstap_message,
251            parsing_options,
252        )?;
253
254        Ok(())
255    }
256
257    fn parse_dnstap_message_type<'a>(
258        event: &mut LogEvent,
259        prefix: impl ValuePath<'a>,
260        dnstap_message_type_id: i32,
261        dnstap_message: DnstapMessage,
262        parsing_options: DnsParserOptions,
263    ) -> Result<()> {
264        match dnstap_message_type_id {
265            1..=12 => {
266                if let Some(query_message) = dnstap_message.query_message {
267                    let mut query_message_parser =
268                        DnsMessageParser::with_options(query_message, parsing_options.clone());
269                    if let Err(error) = DnstapParser::parse_dns_query_message(
270                        event,
271                        prefix.concat(&DNSTAP_VALUE_PATHS.request_message),
272                        &mut query_message_parser,
273                    ) {
274                        DnstapParser::log_raw_dns_message(
275                            event,
276                            prefix.concat(&DNSTAP_VALUE_PATHS.request_message),
277                            query_message_parser.raw_message(),
278                        );
279
280                        return Err(error);
281                    };
282                }
283
284                if let Some(response_message) = dnstap_message.response_message {
285                    let mut response_message_parser =
286                        DnsMessageParser::with_options(response_message, parsing_options);
287                    if let Err(error) = DnstapParser::parse_dns_query_message(
288                        event,
289                        prefix.concat(&DNSTAP_VALUE_PATHS.response_message),
290                        &mut response_message_parser,
291                    ) {
292                        DnstapParser::log_raw_dns_message(
293                            event,
294                            prefix.concat(&DNSTAP_VALUE_PATHS.response_message),
295                            response_message_parser.raw_message(),
296                        );
297
298                        return Err(error);
299                    };
300                }
301            }
302            13 | 14 => {
303                if let Some(update_request_message) = dnstap_message.query_message {
304                    let mut update_request_message_parser = DnsMessageParser::with_options(
305                        update_request_message,
306                        parsing_options.clone(),
307                    );
308                    if let Err(error) = DnstapParser::parse_dns_update_message(
309                        event,
310                        &DNSTAP_VALUE_PATHS.request_message,
311                        &mut update_request_message_parser,
312                    ) {
313                        DnstapParser::log_raw_dns_message(
314                            event,
315                            &DNSTAP_VALUE_PATHS.request_message,
316                            update_request_message_parser.raw_message(),
317                        );
318
319                        return Err(error);
320                    };
321                }
322
323                if let Some(update_response_message) = dnstap_message.response_message {
324                    let mut update_response_message_parser =
325                        DnsMessageParser::with_options(update_response_message, parsing_options);
326                    if let Err(error) = DnstapParser::parse_dns_update_message(
327                        event,
328                        &DNSTAP_VALUE_PATHS.response_message,
329                        &mut update_response_message_parser,
330                    ) {
331                        DnstapParser::log_raw_dns_message(
332                            event,
333                            &DNSTAP_VALUE_PATHS.response_message,
334                            update_response_message_parser.raw_message(),
335                        );
336
337                        return Err(error);
338                    };
339                }
340            }
341            _ => {
342                return Err(Box::new(
343                    DnstapParserError::UnsupportedDnstapMessageTypeError {
344                        dnstap_message_type_id,
345                    },
346                ));
347            }
348        }
349
350        Ok(())
351    }
352
353    fn parse_dnstap_message_time<'a>(
354        event: &mut LogEvent,
355        prefix: impl ValuePath<'a>,
356        time_sec: u64,
357        time_nsec: Option<u32>,
358        dnstap_message_type_id: i32,
359        message: Option<&Vec<u8>>,
360        type_ids: &HashSet<i32>,
361    ) -> Result<()> {
362        if time_sec > i64::MAX as u64 {
363            return Err(Error::from("Cannot parse timestamp"));
364        }
365
366        let (time_in_nanosec, query_time_nsec) = match time_nsec {
367            Some(nsec) => {
368                if let Some(time_in_ns) = (time_sec as i64)
369                    .checked_mul(1_000_000_000)
370                    .and_then(|v| v.checked_add(nsec as i64))
371                {
372                    (time_in_ns, nsec)
373                } else {
374                    return Err(Error::from("Cannot parse timestamp"));
375                }
376            }
377            None => {
378                if let Some(time_in_ns) = (time_sec as i64).checked_mul(1_000_000_000) {
379                    (time_in_ns, 0)
380                } else {
381                    return Err(Error::from("Cannot parse timestamp"));
382                }
383            }
384        };
385
386        if type_ids.contains(&dnstap_message_type_id) {
387            DnstapParser::log_time(event, prefix.clone(), time_in_nanosec, "ns");
388            let timestamp = Utc
389                .timestamp_opt(time_sec.try_into().unwrap(), query_time_nsec)
390                .single()
391                .ok_or("Invalid timestamp")?;
392            if let Some(timestamp_key) = log_schema().timestamp_key() {
393                DnstapParser::insert(event, prefix.clone(), timestamp_key, timestamp);
394            }
395        }
396
397        if message.is_none() {
398            DnstapParser::log_time(
399                event,
400                prefix.concat(&DNSTAP_VALUE_PATHS.request_message),
401                time_in_nanosec,
402                "ns",
403            );
404        }
405        Ok(())
406    }
407
408    fn parse_dnstap_message_socket_family<'a>(
409        event: &mut LogEvent,
410        prefix: impl ValuePath<'a>,
411        socket_family: i32,
412        dnstap_message: &DnstapMessage,
413    ) -> Result<()> {
414        DnstapParser::insert(
415            event,
416            prefix.clone(),
417            &DNSTAP_VALUE_PATHS.socket_family,
418            to_socket_family_name(socket_family)?.to_string(),
419        );
420
421        if let Some(socket_protocol) = dnstap_message.socket_protocol {
422            DnstapParser::insert(
423                event,
424                prefix.clone(),
425                &DNSTAP_VALUE_PATHS.socket_protocol,
426                to_socket_protocol_name(socket_protocol)?.to_string(),
427            );
428        }
429
430        if let Some(query_address) = dnstap_message.query_address.as_ref() {
431            let source_address = if socket_family == 1 {
432                if query_address.len() < 4 {
433                    return Err(Error::from("Cannot parse query_address"));
434                }
435                let address_buffer: [u8; 4] = query_address[0..4].try_into()?;
436                IpAddr::V4(Ipv4Addr::from(address_buffer))
437            } else {
438                if query_address.len() < 16 {
439                    return Err(Error::from("Cannot parse query_address"));
440                }
441                let address_buffer: [u8; 16] = query_address[0..16].try_into()?;
442                IpAddr::V6(Ipv6Addr::from(address_buffer))
443            };
444
445            DnstapParser::insert(
446                event,
447                prefix.clone(),
448                &DNSTAP_VALUE_PATHS.query_address,
449                source_address.to_string(),
450            );
451        }
452
453        if let Some(query_port) = dnstap_message.query_port {
454            DnstapParser::insert(
455                event,
456                prefix.clone(),
457                &DNSTAP_VALUE_PATHS.query_port,
458                query_port,
459            );
460        }
461
462        if let Some(response_address) = dnstap_message.response_address.as_ref() {
463            let response_addr = if socket_family == 1 {
464                if response_address.len() < 4 {
465                    return Err(Error::from("Cannot parse response_address"));
466                }
467                let address_buffer: [u8; 4] = response_address[0..4].try_into()?;
468                IpAddr::V4(Ipv4Addr::from(address_buffer))
469            } else {
470                if response_address.len() < 16 {
471                    return Err(Error::from("Cannot parse response_address"));
472                }
473                let address_buffer: [u8; 16] = response_address[0..16].try_into()?;
474                IpAddr::V6(Ipv6Addr::from(address_buffer))
475            };
476
477            DnstapParser::insert(
478                event,
479                prefix.clone(),
480                &DNSTAP_VALUE_PATHS.response_address,
481                response_addr.to_string(),
482            );
483        }
484
485        if let Some(response_port) = dnstap_message.response_port {
486            DnstapParser::insert(
487                event,
488                prefix.clone(),
489                &DNSTAP_VALUE_PATHS.response_port,
490                response_port,
491            );
492        };
493        Ok(())
494    }
495
496    fn log_time<'a>(
497        event: &mut LogEvent,
498        prefix: impl ValuePath<'a>,
499        time: i64,
500        time_precision: &str,
501    ) {
502        DnstapParser::insert(event, prefix.clone(), &DNSTAP_VALUE_PATHS.time, time);
503        DnstapParser::insert(
504            event,
505            prefix.clone(),
506            &DNSTAP_VALUE_PATHS.time_precision,
507            time_precision.to_string(),
508        );
509    }
510
511    fn log_raw_dns_message<'a>(
512        event: &mut LogEvent,
513        prefix: impl ValuePath<'a>,
514        raw_dns_message: &[u8],
515    ) {
516        DnstapParser::insert(
517            event,
518            prefix.clone(),
519            &DNSTAP_VALUE_PATHS.raw_data,
520            BASE64_STANDARD.encode(raw_dns_message),
521        );
522    }
523
524    fn parse_dns_query_message<'a>(
525        event: &mut LogEvent,
526        prefix: impl ValuePath<'a>,
527        dns_message_parser: &mut DnsMessageParser,
528    ) -> Result<()> {
529        let msg = dns_message_parser.parse_as_query_message()?;
530
531        DnstapParser::insert(
532            event,
533            prefix.clone(),
534            &DNSTAP_VALUE_PATHS.response_code,
535            msg.response_code,
536        );
537
538        if let Some(response) = msg.response {
539            DnstapParser::insert(
540                event,
541                prefix.clone(),
542                &DNSTAP_VALUE_PATHS.response,
543                response.to_string(),
544            );
545        }
546
547        DnstapParser::log_dns_query_message_header(
548            event,
549            prefix.concat(&DNSTAP_VALUE_PATHS.header),
550            &msg.header,
551        );
552
553        DnstapParser::log_dns_query_message_query_section(
554            event,
555            prefix.concat(&DNSTAP_VALUE_PATHS.question_section),
556            &msg.question_section,
557        );
558
559        DnstapParser::log_dns_message_record_section(
560            event,
561            prefix.concat(&DNSTAP_VALUE_PATHS.answer_section),
562            &msg.answer_section,
563        );
564
565        DnstapParser::log_dns_message_record_section(
566            event,
567            prefix.concat(&DNSTAP_VALUE_PATHS.authority_section),
568            &msg.authority_section,
569        );
570
571        DnstapParser::log_dns_message_record_section(
572            event,
573            prefix.concat(&DNSTAP_VALUE_PATHS.additional_section),
574            &msg.additional_section,
575        );
576
577        DnstapParser::log_edns(
578            event,
579            prefix.concat(&DNSTAP_VALUE_PATHS.opt_pseudo_section),
580            &msg.opt_pseudo_section,
581        );
582
583        Ok(())
584    }
585
586    fn log_dns_query_message_header<'a>(
587        event: &mut LogEvent,
588        prefix: impl ValuePath<'a>,
589        header: &QueryHeader,
590    ) {
591        DnstapParser::insert(event, prefix.clone(), &DNSTAP_VALUE_PATHS.id, header.id);
592        DnstapParser::insert(
593            event,
594            prefix.clone(),
595            &DNSTAP_VALUE_PATHS.opcode,
596            header.opcode,
597        );
598        DnstapParser::insert(
599            event,
600            prefix.clone(),
601            &DNSTAP_VALUE_PATHS.rcode,
602            u16::from(header.rcode),
603        );
604        DnstapParser::insert(event, prefix.clone(), &DNSTAP_VALUE_PATHS.qr, header.qr);
605        DnstapParser::insert(event, prefix.clone(), &DNSTAP_VALUE_PATHS.aa, header.aa);
606        DnstapParser::insert(event, prefix.clone(), &DNSTAP_VALUE_PATHS.tc, header.tc);
607        DnstapParser::insert(event, prefix.clone(), &DNSTAP_VALUE_PATHS.rd, header.rd);
608        DnstapParser::insert(event, prefix.clone(), &DNSTAP_VALUE_PATHS.ra, header.ra);
609        DnstapParser::insert(event, prefix.clone(), &DNSTAP_VALUE_PATHS.ad, header.ad);
610        DnstapParser::insert(event, prefix.clone(), &DNSTAP_VALUE_PATHS.cd, header.cd);
611        DnstapParser::insert(
612            event,
613            prefix.clone(),
614            &DNSTAP_VALUE_PATHS.question_count,
615            header.question_count,
616        );
617        DnstapParser::insert(
618            event,
619            prefix.clone(),
620            &DNSTAP_VALUE_PATHS.answer_count,
621            header.answer_count,
622        );
623        DnstapParser::insert(
624            event,
625            prefix.clone(),
626            &DNSTAP_VALUE_PATHS.authority_count,
627            header.authority_count,
628        );
629        DnstapParser::insert(
630            event,
631            prefix.clone(),
632            &DNSTAP_VALUE_PATHS.ar_count,
633            header.additional_count,
634        );
635    }
636
637    fn log_dns_query_message_query_section<'a>(
638        event: &mut LogEvent,
639        prefix: impl ValuePath<'a>,
640        questions: &[QueryQuestion],
641    ) {
642        for (i, query) in questions.iter().enumerate() {
643            let index_segment = path!(i as isize);
644            DnstapParser::log_dns_query_question(event, prefix.concat(index_segment), query);
645        }
646    }
647
648    fn log_dns_query_question<'a>(
649        event: &mut LogEvent,
650        prefix: impl ValuePath<'a>,
651        question: &QueryQuestion,
652    ) {
653        DnstapParser::insert(
654            event,
655            prefix.clone(),
656            &DNSTAP_VALUE_PATHS.domain_name,
657            question.name.clone(),
658        );
659        if let Some(record_type) = question.record_type.clone() {
660            DnstapParser::insert(
661                event,
662                prefix.clone(),
663                &DNSTAP_VALUE_PATHS.question_type,
664                record_type,
665            );
666        }
667        DnstapParser::insert(
668            event,
669            prefix.clone(),
670            &DNSTAP_VALUE_PATHS.question_type_id,
671            question.record_type_id,
672        );
673        DnstapParser::insert(
674            event,
675            prefix.clone(),
676            &DNSTAP_VALUE_PATHS.class,
677            question.class.clone(),
678        );
679    }
680
681    fn parse_dns_update_message<'a>(
682        event: &mut LogEvent,
683        prefix: impl ValuePath<'a>,
684        dns_message_parser: &mut DnsMessageParser,
685    ) -> Result<()> {
686        let msg = dns_message_parser.parse_as_update_message()?;
687
688        DnstapParser::insert(
689            event,
690            prefix.clone(),
691            &DNSTAP_VALUE_PATHS.response_code,
692            msg.response_code,
693        );
694
695        if let Some(response) = msg.response {
696            DnstapParser::insert(
697                event,
698                prefix.clone(),
699                &DNSTAP_VALUE_PATHS.response,
700                response.to_string(),
701            );
702        }
703
704        DnstapParser::log_dns_update_message_header(
705            event,
706            prefix.concat(&DNSTAP_VALUE_PATHS.header),
707            &msg.header,
708        );
709
710        DnstapParser::log_dns_update_message_zone_section(
711            event,
712            prefix.concat(&DNSTAP_VALUE_PATHS.zone_section),
713            &msg.zone_to_update,
714        );
715
716        DnstapParser::log_dns_message_record_section(
717            event,
718            prefix.concat(&DNSTAP_VALUE_PATHS.prerequisite_section),
719            &msg.prerequisite_section,
720        );
721
722        DnstapParser::log_dns_message_record_section(
723            event,
724            prefix.concat(&DNSTAP_VALUE_PATHS.update_section),
725            &msg.update_section,
726        );
727
728        DnstapParser::log_dns_message_record_section(
729            event,
730            prefix.concat(&DNSTAP_VALUE_PATHS.additional_section),
731            &msg.additional_section,
732        );
733
734        Ok(())
735    }
736
737    fn log_dns_update_message_header<'a>(
738        event: &mut LogEvent,
739        prefix: impl ValuePath<'a>,
740        header: &UpdateHeader,
741    ) {
742        DnstapParser::insert(event, prefix.clone(), &DNSTAP_VALUE_PATHS.id, header.id);
743
744        DnstapParser::insert(
745            event,
746            prefix.clone(),
747            &DNSTAP_VALUE_PATHS.opcode,
748            header.opcode,
749        );
750
751        DnstapParser::insert(
752            event,
753            prefix.clone(),
754            &DNSTAP_VALUE_PATHS.rcode,
755            u16::from(header.rcode),
756        );
757
758        DnstapParser::insert(event, prefix.clone(), &DNSTAP_VALUE_PATHS.qr, header.qr);
759
760        DnstapParser::insert(
761            event,
762            prefix.clone(),
763            &DNSTAP_VALUE_PATHS.zone_count,
764            header.zone_count,
765        );
766
767        DnstapParser::insert(
768            event,
769            prefix.clone(),
770            &DNSTAP_VALUE_PATHS.prerequisite_count,
771            header.prerequisite_count,
772        );
773
774        DnstapParser::insert(
775            event,
776            prefix.clone(),
777            &DNSTAP_VALUE_PATHS.update_count,
778            header.update_count,
779        );
780
781        DnstapParser::insert(
782            event,
783            prefix.clone(),
784            &DNSTAP_VALUE_PATHS.ad_count,
785            header.additional_count,
786        );
787    }
788
789    fn log_dns_update_message_zone_section<'a>(
790        event: &mut LogEvent,
791        prefix: impl ValuePath<'a>,
792        zone: &ZoneInfo,
793    ) {
794        DnstapParser::insert(
795            event,
796            prefix.clone(),
797            &DNSTAP_VALUE_PATHS.zone_name,
798            zone.name.clone(),
799        );
800        if let Some(zone_type) = zone.zone_type.clone() {
801            DnstapParser::insert(
802                event,
803                prefix.clone(),
804                &DNSTAP_VALUE_PATHS.zone_type,
805                zone_type,
806            );
807        }
808        DnstapParser::insert(
809            event,
810            prefix.clone(),
811            &DNSTAP_VALUE_PATHS.zone_type_id,
812            zone.zone_type_id,
813        );
814        DnstapParser::insert(
815            event,
816            prefix.clone(),
817            &DNSTAP_VALUE_PATHS.zone_class,
818            zone.class.clone(),
819        );
820    }
821
822    fn log_edns<'a>(
823        event: &mut LogEvent,
824        prefix: impl ValuePath<'a>,
825        opt_section: &Option<OptPseudoSection>,
826    ) {
827        if let Some(edns) = opt_section {
828            DnstapParser::insert(
829                event,
830                prefix.clone(),
831                &DNSTAP_VALUE_PATHS.extended_rcode,
832                edns.extended_rcode,
833            );
834            DnstapParser::insert(
835                event,
836                prefix.clone(),
837                &DNSTAP_VALUE_PATHS.version,
838                edns.version,
839            );
840            DnstapParser::insert(
841                event,
842                prefix.clone(),
843                &DNSTAP_VALUE_PATHS.do_flag,
844                edns.dnssec_ok,
845            );
846            DnstapParser::insert(
847                event,
848                prefix.clone(),
849                &DNSTAP_VALUE_PATHS.udp_max_payload_size,
850                edns.udp_max_payload_size,
851            );
852            DnstapParser::log_edns_ede(event, prefix.concat(&DNSTAP_VALUE_PATHS.ede), &edns.ede);
853            DnstapParser::log_edns_options(
854                event,
855                prefix.concat(&DNSTAP_VALUE_PATHS.options),
856                &edns.options,
857            );
858        }
859    }
860
861    fn log_edns_ede<'a>(event: &mut LogEvent, prefix: impl ValuePath<'a>, options: &[EDE]) {
862        options.iter().enumerate().for_each(|(i, entry)| {
863            let index_segment = path!(i as isize);
864            DnstapParser::log_edns_ede_entry(event, prefix.concat(index_segment), entry);
865        });
866    }
867
868    fn log_edns_ede_entry<'a>(event: &mut LogEvent, prefix: impl ValuePath<'a>, entry: &EDE) {
869        DnstapParser::insert(
870            event,
871            prefix.clone(),
872            &DNSTAP_VALUE_PATHS.info_code,
873            entry.info_code(),
874        );
875        if let Some(purpose) = entry.purpose() {
876            DnstapParser::insert(event, prefix.clone(), &DNSTAP_VALUE_PATHS.purpose, purpose);
877        }
878        if let Some(extra_text) = entry.extra_text() {
879            DnstapParser::insert(
880                event,
881                prefix.clone(),
882                &DNSTAP_VALUE_PATHS.extra_text,
883                extra_text,
884            );
885        }
886    }
887
888    fn log_edns_options<'a>(
889        event: &mut LogEvent,
890        prefix: impl ValuePath<'a>,
891        options: &[EdnsOptionEntry],
892    ) {
893        options.iter().enumerate().for_each(|(i, opt)| {
894            let index_segment = path!(i as isize);
895            DnstapParser::log_edns_opt(event, prefix.concat(index_segment), opt);
896        });
897    }
898
899    fn log_edns_opt<'a>(event: &mut LogEvent, prefix: impl ValuePath<'a>, opt: &EdnsOptionEntry) {
900        DnstapParser::insert(
901            event,
902            prefix.clone(),
903            &DNSTAP_VALUE_PATHS.opt_code,
904            opt.opt_code,
905        );
906        DnstapParser::insert(
907            event,
908            prefix.clone(),
909            &DNSTAP_VALUE_PATHS.opt_name,
910            opt.opt_name.clone(),
911        );
912        DnstapParser::insert(
913            event,
914            prefix.clone(),
915            &DNSTAP_VALUE_PATHS.opt_data,
916            opt.opt_data.clone(),
917        );
918    }
919
920    fn log_dns_message_record_section<'a>(
921        event: &mut LogEvent,
922        prefix: impl ValuePath<'a>,
923        records: &[DnsRecord],
924    ) {
925        for (i, record) in records.iter().enumerate() {
926            let index_segment = path!(i as isize);
927            DnstapParser::log_dns_record(event, prefix.concat(index_segment), record);
928        }
929    }
930
931    fn log_dns_record<'a>(event: &mut LogEvent, prefix: impl ValuePath<'a>, record: &DnsRecord) {
932        DnstapParser::insert(
933            event,
934            prefix.clone(),
935            &DNSTAP_VALUE_PATHS.domain_name,
936            record.name.clone(),
937        );
938        if let Some(record_type) = record.record_type.clone() {
939            DnstapParser::insert(
940                event,
941                prefix.clone(),
942                &DNSTAP_VALUE_PATHS.record_type,
943                record_type,
944            );
945        }
946        DnstapParser::insert(
947            event,
948            prefix.clone(),
949            &DNSTAP_VALUE_PATHS.record_type_id,
950            record.record_type_id,
951        );
952        DnstapParser::insert(event, prefix.clone(), &DNSTAP_VALUE_PATHS.ttl, record.ttl);
953        DnstapParser::insert(
954            event,
955            prefix.clone(),
956            &DNSTAP_VALUE_PATHS.class,
957            record.class.clone(),
958        );
959        if let Some(rdata) = &record.rdata {
960            DnstapParser::insert(
961                event,
962                prefix.clone(),
963                &DNSTAP_VALUE_PATHS.rdata,
964                rdata.to_string(),
965            );
966        };
967        if let Some(rdata_bytes) = &record.rdata_bytes {
968            DnstapParser::insert(
969                event,
970                prefix.clone(),
971                &DNSTAP_VALUE_PATHS.rdata_bytes,
972                BASE64_STANDARD.encode(rdata_bytes),
973            );
974        };
975    }
976}
977
978fn to_socket_family_name(socket_family: i32) -> Result<&'static str> {
979    if socket_family == SocketFamily::Inet as i32 {
980        Ok("INET")
981    } else if socket_family == SocketFamily::Inet6 as i32 {
982        Ok("INET6")
983    } else {
984        Err(Error::from(format!(
985            "Unknown socket family: {socket_family}"
986        )))
987    }
988}
989
990fn to_socket_protocol_name(socket_protocol: i32) -> Result<&'static str> {
991    if socket_protocol == SocketProtocol::Udp as i32 {
992        Ok("UDP")
993    } else if socket_protocol == SocketProtocol::Tcp as i32 {
994        Ok("TCP")
995    } else if socket_protocol == SocketProtocol::Dot as i32 {
996        Ok("DOT")
997    } else if socket_protocol == SocketProtocol::Doh as i32 {
998        Ok("DOH")
999    } else if socket_protocol == SocketProtocol::DnsCryptUdp as i32 {
1000        Ok("DNSCryptUDP")
1001    } else if socket_protocol == SocketProtocol::DnsCryptTcp as i32 {
1002        Ok("DNSCryptTCP")
1003    } else {
1004        Err(Error::from(format!(
1005            "Unknown socket protocol: {socket_protocol}"
1006        )))
1007    }
1008}
1009
1010fn to_dnstap_data_type(data_type_id: i32) -> Option<String> {
1011    match data_type_id {
1012        1 => Some(String::from("Message")),
1013        _ => None,
1014    }
1015}
1016
1017fn to_dnstap_message_type(type_id: i32) -> String {
1018    match type_id {
1019        1 => String::from("AuthQuery"),
1020        2 => String::from("AuthResponse"),
1021        3 => String::from("ResolverQuery"),
1022        4 => String::from("ResolverResponse"),
1023        5 => String::from("ClientQuery"),
1024        6 => String::from("ClientResponse"),
1025        7 => String::from("ForwarderQuery"),
1026        8 => String::from("ForwarderResponse"),
1027        9 => String::from("StubQuery"),
1028        10 => String::from("StubResponse"),
1029        11 => String::from("ToolQuery"),
1030        12 => String::from("ToolResponse"),
1031        13 => String::from("UpdateQuery"),
1032        14 => String::from("UpdateResponse"),
1033        _ => format!("Unknown dnstap message type: {type_id}"),
1034    }
1035}
1036
1037#[cfg(test)]
1038mod tests {
1039    use std::{collections::BTreeMap, vec};
1040
1041    use chrono::DateTime;
1042    use dnsmsg_parser::dns_message_parser::DnsParserOptions;
1043
1044    use super::*;
1045
1046    #[test]
1047    fn test_parse_dnstap_data_with_query_message() {
1048        let mut log_event = LogEvent::default();
1049        let raw_dnstap_data = "ChVqYW1lcy1WaXJ0dWFsLU1hY2hpbmUSC0JJTkQgOS4xNi4zcnoIAxACGAEiEAAAAAAAAA\
1050        AAAAAAAAAAAAAqECABBQJwlAAAAAAAAAAAADAw8+0CODVA7+zq9wVNMU3WNlI2kwIAAAABAAAAAAABCWZhY2Vib29rMQNjb\
1051        20AAAEAAQAAKQIAAACAAAAMAAoACOxjCAG9zVgzWgUDY29tAHgB";
1052        let dnstap_data = BASE64_STANDARD
1053            .decode(raw_dnstap_data)
1054            .expect("Invalid base64 encoded data.");
1055        let parse_result = DnstapParser::parse(
1056            &mut log_event,
1057            Bytes::from(dnstap_data),
1058            DnsParserOptions::default(),
1059        );
1060        assert!(parse_result.is_ok());
1061
1062        let expected_map: BTreeMap<&str, Value> = BTreeMap::from([
1063            ("dataType", Value::Bytes(Bytes::from("Message"))),
1064            ("dataTypeId", Value::Integer(1)),
1065            ("messageType", Value::Bytes(Bytes::from("ResolverQuery"))),
1066            ("messageTypeId", Value::Integer(3)),
1067            ("queryZone", Value::Bytes(Bytes::from("com."))),
1068            ("requestData.fullRcode", Value::Integer(0)),
1069            ("requestData.header.aa", Value::Boolean(false)),
1070            ("requestData.header.ad", Value::Boolean(false)),
1071            ("requestData.header.anCount", Value::Integer(0)),
1072            ("requestData.header.arCount", Value::Integer(1)),
1073            ("requestData.header.cd", Value::Boolean(false)),
1074            ("requestData.header.id", Value::Integer(37634)),
1075            ("requestData.header.nsCount", Value::Integer(0)),
1076            ("requestData.header.opcode", Value::Integer(0)),
1077            ("requestData.header.qdCount", Value::Integer(1)),
1078            ("requestData.header.qr", Value::Integer(0)),
1079            ("requestData.header.ra", Value::Boolean(false)),
1080            ("requestData.header.rcode", Value::Integer(0)),
1081            ("requestData.header.rd", Value::Boolean(false)),
1082            ("requestData.header.tc", Value::Boolean(false)),
1083            ("requestData.opt.do", Value::Boolean(true)),
1084            ("requestData.opt.ednsVersion", Value::Integer(0)),
1085            ("requestData.opt.extendedRcode", Value::Integer(0)),
1086            ("requestData.opt.options[0].optCode", Value::Integer(10)),
1087            (
1088                "requestData.opt.options[0].optName",
1089                Value::Bytes(Bytes::from("Cookie")),
1090            ),
1091            (
1092                "requestData.opt.options[0].optValue",
1093                Value::Bytes(Bytes::from("7GMIAb3NWDM=")),
1094            ),
1095            ("requestData.opt.udpPayloadSize", Value::Integer(512)),
1096            (
1097                "requestData.question[0].class",
1098                Value::Bytes(Bytes::from("IN")),
1099            ),
1100            (
1101                "requestData.question[0].domainName",
1102                Value::Bytes(Bytes::from("facebook1.com.")),
1103            ),
1104            (
1105                "requestData.question[0].questionType",
1106                Value::Bytes(Bytes::from("A")),
1107            ),
1108            ("requestData.question[0].questionTypeId", Value::Integer(1)),
1109            (
1110                "requestData.rcodeName",
1111                Value::Bytes(Bytes::from("NoError")),
1112            ),
1113            (
1114                "responseAddress",
1115                Value::Bytes(Bytes::from("2001:502:7094::30")),
1116            ),
1117            ("responsePort", Value::Integer(53)),
1118            (
1119                "serverId",
1120                Value::Bytes(Bytes::from("james-Virtual-Machine")),
1121            ),
1122            ("serverVersion", Value::Bytes(Bytes::from("BIND 9.16.3"))),
1123            ("socketFamily", Value::Bytes(Bytes::from("INET6"))),
1124            ("socketProtocol", Value::Bytes(Bytes::from("UDP"))),
1125            ("sourceAddress", Value::Bytes(Bytes::from("::"))),
1126            ("sourcePort", Value::Integer(46835)),
1127            ("time", Value::Integer(1_593_489_007_920_014_129)),
1128            ("timePrecision", Value::Bytes(Bytes::from("ns"))),
1129            (
1130                "timestamp",
1131                Value::Timestamp(
1132                    Utc.from_utc_datetime(
1133                        &DateTime::parse_from_rfc3339("2020-06-30T03:50:07.920014129Z")
1134                            .unwrap()
1135                            .naive_utc(),
1136                    ),
1137                ),
1138            ),
1139        ]);
1140
1141        // The maps need to contain identical keys and values.
1142        for (exp_key, exp_value) in expected_map {
1143            let value = log_event.get(exp_key).unwrap();
1144            assert_eq!(*value, exp_value);
1145        }
1146    }
1147
1148    #[test]
1149    fn test_parse_dnstap_data_lowercase_hostnames() {
1150        let mut log_event = LogEvent::default();
1151        let mut lowercase_log_event = LogEvent::default();
1152        let raw_dnstap_data = "Cgw2NzNiNWZiZWI5MmESMkJJTkQgOS4xOC4yMS0xK3VidW50dTIyLjA0LjErZGViLnN1cnkub3JnKzEtVWJ1bnR1cqkBCAYQARgBIgQKWQUeKgQKWQUqMMitAjg1YLXQp68GbZ9tBw9ygwGInoGAAAEABAAAAAEGVmVjdG9yA0RldgAAAQABwAwAAQABAAAAPAAEEvVWOMAMAAEAAQAAADwABBL1VnnADAABAAEAAAA8AAQS9VYSwAwAAQABAAAAPAAEEvVWWQAAKQTQAAAAAAAcAAoAGERDbSN8uKngAQAAAGXp6DXs0fbpv0n9F3gB";
1153        let dnstap_data = BASE64_STANDARD
1154            .decode(raw_dnstap_data)
1155            .expect("Invalid base64 encoded data.");
1156        let parse_result = DnstapParser::parse(
1157            &mut lowercase_log_event,
1158            Bytes::from(dnstap_data.clone()),
1159            DnsParserOptions {
1160                lowercase_hostnames: true,
1161            },
1162        );
1163        let no_lowercase_result = DnstapParser::parse(
1164            &mut log_event,
1165            Bytes::from(dnstap_data),
1166            DnsParserOptions::default(),
1167        );
1168        assert!(parse_result.is_ok());
1169        assert!(no_lowercase_result.is_ok());
1170
1171        let no_lowercase_expected: BTreeMap<&str, Value> = BTreeMap::from([
1172            ("dataType", Value::Bytes(Bytes::from("Message"))),
1173            ("dataTypeId", Value::Integer(1)),
1174            (
1175                "responseData.answers[0].domainName",
1176                Value::Bytes(Bytes::from("Vector.Dev.")),
1177            ),
1178            (
1179                "responseData.question[0].domainName",
1180                Value::Bytes(Bytes::from("Vector.Dev.")),
1181            ),
1182        ]);
1183        let expected_map: BTreeMap<&str, Value> = BTreeMap::from([
1184            ("dataType", Value::Bytes(Bytes::from("Message"))),
1185            ("dataTypeId", Value::Integer(1)),
1186            (
1187                "responseData.answers[0].domainName",
1188                Value::Bytes(Bytes::from("vector.dev.")),
1189            ),
1190            (
1191                "responseData.question[0].domainName",
1192                Value::Bytes(Bytes::from("vector.dev.")),
1193            ),
1194        ]);
1195
1196        // The maps need to contain identical keys and values.
1197        for (exp_key, exp_value) in no_lowercase_expected {
1198            let value = log_event.get(exp_key).unwrap();
1199            assert_eq!(*value, exp_value);
1200        }
1201        for (exp_key, exp_value) in expected_map {
1202            let value = lowercase_log_event.get(exp_key).unwrap();
1203            assert_eq!(*value, exp_value);
1204        }
1205    }
1206
1207    #[test]
1208    fn test_parse_dnstap_data_with_ede_options() {
1209        let mut log_event = LogEvent::default();
1210        let raw_dnstap_data = "ChVqYW1lcy1WaXJ0dWFsLU1hY2hpbmUSC0JJTkQgOS4xNi4zGgBy5wEIAxACGAEiEAAAAAAAAAAAAAAAAAAAAAAqECABBQJwlAAAAAAAAAAAADAw8+0CODVA7+zq9wVNMU3WNlI2kwIAAAABAAAAAAABCWZhY2Vib29rMQNjb20AAAEAAQAAKQIAAACAAAAMAAoACOxjCAG9zVgzWgUDY29tAGAAbQAAAAByZLM4AAAAAQAAAAAAAQJoNQdleGFtcGxlA2NvbQAABgABAAApBNABAUAAADkADwA1AAlubyBTRVAgbWF0Y2hpbmcgdGhlIERTIGZvdW5kIGZvciBkbnNzZWMtZmFpbGVkLm9yZy54AQ==";
1211        let dnstap_data = BASE64_STANDARD
1212            .decode(raw_dnstap_data)
1213            .expect("Invalid base64 encoded data.");
1214        let parse_result = DnstapParser::parse(
1215            &mut log_event,
1216            Bytes::from(dnstap_data),
1217            DnsParserOptions::default(),
1218        );
1219        assert!(parse_result.is_ok());
1220
1221        let expected_map: BTreeMap<&str, Value> = BTreeMap::from([
1222            ("responseData.opt.ede[0].infoCode", Value::Integer(9)),
1223            (
1224                "responseData.opt.ede[0].purpose",
1225                Value::Bytes(Bytes::from("DNSKEY Missing")),
1226            ),
1227            (
1228                "responseData.opt.ede[0].extraText",
1229                Value::Bytes(Bytes::from(
1230                    "no SEP matching the DS found for dnssec-failed.org.",
1231                )),
1232            ),
1233        ]);
1234
1235        // The maps need to contain identical keys and values.
1236        for (exp_key, exp_value) in expected_map {
1237            let value = log_event.get(exp_key).unwrap();
1238            assert_eq!(*value, exp_value);
1239        }
1240    }
1241
1242    #[test]
1243    fn test_parse_dnstap_data_with_update_message() {
1244        let mut log_event = LogEvent::default();
1245        let raw_dnstap_data = "ChVqYW1lcy1WaXJ0dWFsLU1hY2hpbmUSC0JJTkQgOS4xNi4zcmsIDhABGAEiBH8AAA\
1246        EqBH8AAAEwrG44AEC+iu73BU14gfofUh1wi6gAAAEAAAAAAAAHZXhhbXBsZQNjb20AAAYAAWC+iu73BW0agDwvch1wi6gAA\
1247        AEAAAAAAAAHZXhhbXBsZQNjb20AAAYAAXgB";
1248        let dnstap_data = BASE64_STANDARD
1249            .decode(raw_dnstap_data)
1250            .expect("Invalid base64 encoded data.");
1251        let parse_result = DnstapParser::parse(
1252            &mut log_event,
1253            Bytes::from(dnstap_data),
1254            DnsParserOptions::default(),
1255        );
1256        assert!(parse_result.is_ok());
1257
1258        let expected_map: BTreeMap<&str, Value> = BTreeMap::from([
1259            ("dataType", Value::Bytes(Bytes::from("Message"))),
1260            ("dataTypeId", Value::Integer(1)),
1261            ("messageType", Value::Bytes(Bytes::from("UpdateResponse"))),
1262            ("messageTypeId", Value::Integer(14)),
1263            ("requestData.fullRcode", Value::Integer(0)),
1264            ("requestData.header.adCount", Value::Integer(0)),
1265            ("requestData.header.id", Value::Integer(28811)),
1266            ("requestData.header.opcode", Value::Integer(5)),
1267            ("requestData.header.prCount", Value::Integer(0)),
1268            ("requestData.header.qr", Value::Integer(1)),
1269            ("requestData.header.rcode", Value::Integer(0)),
1270            ("requestData.header.upCount", Value::Integer(0)),
1271            ("requestData.header.zoCount", Value::Integer(1)),
1272            (
1273                "requestData.rcodeName",
1274                Value::Bytes(Bytes::from("NoError")),
1275            ),
1276            ("requestData.zone.zClass", Value::Bytes(Bytes::from("IN"))),
1277            (
1278                "requestData.zone.zName",
1279                Value::Bytes(Bytes::from("example.com.")),
1280            ),
1281            ("requestData.zone.zType", Value::Bytes(Bytes::from("SOA"))),
1282            ("requestData.zone.zTypeId", Value::Integer(6)),
1283            ("responseAddress", Value::Bytes(Bytes::from("127.0.0.1"))),
1284            ("responseData.fullRcode", Value::Integer(0)),
1285            ("responseData.header.adCount", Value::Integer(0)),
1286            ("responseData.header.id", Value::Integer(28811)),
1287            ("responseData.header.opcode", Value::Integer(5)),
1288            ("responseData.header.prCount", Value::Integer(0)),
1289            ("responseData.header.qr", Value::Integer(1)),
1290            ("responseData.header.rcode", Value::Integer(0)),
1291            ("responseData.header.upCount", Value::Integer(0)),
1292            ("responseData.header.zoCount", Value::Integer(1)),
1293            (
1294                "responseData.rcodeName",
1295                Value::Bytes(Bytes::from("NoError")),
1296            ),
1297            ("responseData.zone.zClass", Value::Bytes(Bytes::from("IN"))),
1298            (
1299                "responseData.zone.zName",
1300                Value::Bytes(Bytes::from("example.com.")),
1301            ),
1302            ("responseData.zone.zType", Value::Bytes(Bytes::from("SOA"))),
1303            ("responseData.zone.zTypeId", Value::Integer(6)),
1304            ("responsePort", Value::Integer(0)),
1305            (
1306                "serverId",
1307                Value::Bytes(Bytes::from("james-Virtual-Machine")),
1308            ),
1309            ("serverVersion", Value::Bytes(Bytes::from("BIND 9.16.3"))),
1310            ("socketFamily", Value::Bytes(Bytes::from("INET"))),
1311            ("socketProtocol", Value::Bytes(Bytes::from("UDP"))),
1312            ("sourceAddress", Value::Bytes(Bytes::from("127.0.0.1"))),
1313            ("sourcePort", Value::Integer(14124)),
1314            ("time", Value::Integer(1_593_541_950_792_494_106)),
1315            ("timePrecision", Value::Bytes(Bytes::from("ns"))),
1316            (
1317                "timestamp",
1318                Value::Timestamp(
1319                    Utc.from_utc_datetime(
1320                        &DateTime::parse_from_rfc3339("2020-06-30T18:32:30.792494106Z")
1321                            .unwrap()
1322                            .naive_utc(),
1323                    ),
1324                ),
1325            ),
1326        ]);
1327
1328        // The maps need to contain identical keys and values.
1329        for (exp_key, exp_value) in expected_map {
1330            let value = log_event.get(exp_key).unwrap();
1331            assert_eq!(*value, exp_value);
1332        }
1333    }
1334
1335    #[test]
1336    fn test_parse_dnstap_data_with_invalid_data() {
1337        let mut log_event = LogEvent::default();
1338        let e = DnstapParser::parse(
1339            &mut log_event,
1340            Bytes::from(vec![1, 2, 3]),
1341            DnsParserOptions::default(),
1342        )
1343        .expect_err("Expected TrustDnsError.");
1344        assert!(e.to_string().contains("Protobuf message"));
1345    }
1346
1347    #[test]
1348    fn test_parse_dnstap_data_with_invalid_timestamp() {
1349        fn test_one_timestamp_parse(time_sec: u64, time_nsec: Option<u32>) -> Result<()> {
1350            let mut event = LogEvent::default();
1351            let root = owned_value_path!();
1352            let type_ids = HashSet::from([1]);
1353            DnstapParser::parse_dnstap_message_time(
1354                &mut event, &root, time_sec, time_nsec, 1, None, &type_ids,
1355            )
1356        }
1357        // okay case
1358        assert!(test_one_timestamp_parse(1337, Some(42)).is_ok());
1359        // overflow in cast (u64 -> i64)
1360        assert!(test_one_timestamp_parse(u64::MAX, Some(42)).is_err());
1361        assert!(test_one_timestamp_parse(u64::MAX, None).is_err());
1362        // overflow in multiplication
1363        assert!(test_one_timestamp_parse(i64::MAX as u64, Some(42)).is_err());
1364        assert!(test_one_timestamp_parse(i64::MAX as u64, None).is_err());
1365        // overflow in add
1366        assert!(
1367            test_one_timestamp_parse((i64::MAX / 1_000_000_000) as u64, Some(u32::MAX)).is_err()
1368        );
1369        // cannot be parsed by timestamp_opt
1370        assert!(test_one_timestamp_parse(96, Some(1616928816)).is_err());
1371    }
1372
1373    #[test]
1374    fn test_parse_dnstap_message_socket_family_bad_addr() {
1375        // while parsing address is optional, but in this function assume otherwise
1376        fn test_one_input(socket_family: i32, msg: DnstapMessage) -> Result<()> {
1377            let mut event = LogEvent::default();
1378            let root = owned_value_path!();
1379            DnstapParser::parse_dnstap_message_socket_family(&mut event, &root, socket_family, &msg)
1380        }
1381        // all bad cases which can panic
1382        {
1383            let message = DnstapMessage {
1384                query_address: Some(vec![]),
1385                ..Default::default()
1386            };
1387            assert!(test_one_input(1, message).is_err());
1388        }
1389        {
1390            let message = DnstapMessage {
1391                query_address: Some(vec![]),
1392                ..Default::default()
1393            };
1394            assert!(test_one_input(2, message).is_err());
1395        }
1396
1397        {
1398            let message = DnstapMessage {
1399                response_address: Some(vec![]),
1400                ..Default::default()
1401            };
1402            assert!(test_one_input(1, message).is_err());
1403        }
1404        {
1405            let message = DnstapMessage {
1406                response_address: Some(vec![]),
1407                ..Default::default()
1408            };
1409            assert!(test_one_input(2, message).is_err());
1410        }
1411    }
1412
1413    #[test]
1414    fn test_get_socket_family_name() {
1415        assert_eq!("INET", to_socket_family_name(1).unwrap());
1416        assert_eq!("INET6", to_socket_family_name(2).unwrap());
1417        assert!(to_socket_family_name(3).is_err());
1418    }
1419
1420    #[test]
1421    fn test_get_socket_protocol_name() {
1422        assert_eq!("UDP", to_socket_protocol_name(1).unwrap());
1423        assert_eq!("TCP", to_socket_protocol_name(2).unwrap());
1424        assert_eq!("DOT", to_socket_protocol_name(3).unwrap());
1425        assert_eq!("DOH", to_socket_protocol_name(4).unwrap());
1426        assert_eq!("DNSCryptUDP", to_socket_protocol_name(5).unwrap());
1427        assert_eq!("DNSCryptTCP", to_socket_protocol_name(6).unwrap());
1428        assert!(to_socket_protocol_name(7).is_err());
1429    }
1430}