dnstap_parser/
parser.rs

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