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