dnstap_parser/
schema.rs

1use std::{collections::BTreeMap, sync::LazyLock};
2
3use vector_lib::lookup::{OwnedValuePath, owned_value_path};
4use vrl::{
5    btreemap,
6    value::{
7        Kind,
8        kind::{Collection, Field},
9    },
10};
11
12#[derive(Debug, Default, Clone)]
13pub struct DnstapEventSchema;
14
15impl DnstapEventSchema {
16    /// The message schema for the request and response message fields
17    pub(crate) fn request_message_schema_definition(&self) -> Collection<Field> {
18        let mut result: BTreeMap<Field, Kind> = BTreeMap::new();
19        result.insert(
20            DNSTAP_VALUE_PATHS.time.to_string().into(),
21            Kind::integer().or_undefined(),
22        );
23
24        result.insert(
25            DNSTAP_VALUE_PATHS.time.to_string().into(),
26            Kind::integer().or_undefined(),
27        );
28        result.insert(
29            DNSTAP_VALUE_PATHS.time_precision.to_string().into(),
30            Kind::bytes().or_undefined(),
31        );
32        result.insert(
33            DNSTAP_VALUE_PATHS.time_precision.to_string().into(),
34            Kind::bytes().or_undefined(),
35        );
36        result.insert(
37            DNSTAP_VALUE_PATHS.response_code.to_string().into(),
38            Kind::integer().or_undefined(),
39        );
40        result.insert(
41            DNSTAP_VALUE_PATHS.response_code.to_string().into(),
42            Kind::integer().or_undefined(),
43        );
44        result.insert(
45            DNSTAP_VALUE_PATHS.response.to_string().into(),
46            Kind::bytes().or_undefined(),
47        );
48        result.insert(
49            DNSTAP_VALUE_PATHS.response.to_string().into(),
50            Kind::bytes().or_undefined(),
51        );
52
53        let mut schema = DnsQueryHeaderSchema::schema_definition();
54        schema.merge(DnsUpdateHeaderSchema::schema_definition(), true);
55
56        result.insert(
57            DNSTAP_VALUE_PATHS.header.to_string().into(),
58            Kind::object(schema).or_undefined(),
59        );
60
61        result.insert(
62            DNSTAP_VALUE_PATHS.zone_section.to_string().into(),
63            Kind::object(DnsUpdateZoneInfoSchema::schema_definition()).or_undefined(),
64        );
65
66        result.insert(
67            DNSTAP_VALUE_PATHS.question_section.to_string().into(),
68            Kind::array(Collection::from_unknown(Kind::object(
69                DnsQueryQuestionSchema::schema_definition(),
70            )))
71            .or_undefined(),
72        );
73
74        result.insert(
75            DNSTAP_VALUE_PATHS.answer_section.to_string().into(),
76            Kind::array(Collection::from_unknown(Kind::object(
77                DnsRecordSchema::schema_definition(),
78            )))
79            .or_undefined(),
80        );
81
82        result.insert(
83            DNSTAP_VALUE_PATHS.authority_section.to_string().into(),
84            Kind::array(Collection::from_unknown(Kind::object(
85                DnsRecordSchema::schema_definition(),
86            )))
87            .or_undefined(),
88        );
89
90        result.insert(
91            DNSTAP_VALUE_PATHS.additional_section.to_string().into(),
92            Kind::array(Collection::from_unknown(Kind::object(
93                DnsRecordSchema::schema_definition(),
94            )))
95            .or_undefined(),
96        );
97
98        result.insert(
99            DNSTAP_VALUE_PATHS.opt_pseudo_section.to_string().into(),
100            Kind::object(DnsMessageOptPseudoSectionSchema::schema_definition()).or_undefined(),
101        );
102
103        result.insert(
104            DNSTAP_VALUE_PATHS.raw_data.to_string().into(),
105            Kind::bytes().or_undefined(),
106        );
107
108        result.insert(
109            DNSTAP_VALUE_PATHS.prerequisite_section.to_string().into(),
110            Kind::array(Collection::from_unknown(Kind::object(
111                DnsRecordSchema::schema_definition(),
112            )))
113            .or_undefined(),
114        );
115
116        result.insert(
117            DNSTAP_VALUE_PATHS.update_section.to_string().into(),
118            Kind::array(Collection::from_unknown(Kind::object(
119                DnsRecordSchema::schema_definition(),
120            )))
121            .or_undefined(),
122        );
123
124        result.insert(
125            DNSTAP_VALUE_PATHS.additional_section.to_string().into(),
126            Kind::array(Collection::from_unknown(Kind::object(
127                DnsRecordSchema::schema_definition(),
128            )))
129            .or_undefined(),
130        );
131
132        result.into()
133    }
134
135    /// Schema definition for fields stored in the root.
136    fn root_schema_definition(
137        &self,
138        schema: vector_lib::schema::Definition,
139    ) -> vector_lib::schema::Definition {
140        schema
141            .optional_field(&DNSTAP_VALUE_PATHS.server_identity, Kind::bytes(), None)
142            .optional_field(&DNSTAP_VALUE_PATHS.server_version, Kind::bytes(), None)
143            .optional_field(&DNSTAP_VALUE_PATHS.extra, Kind::bytes(), None)
144            .with_event_field(&DNSTAP_VALUE_PATHS.data_type_id, Kind::integer(), None)
145            .optional_field(&DNSTAP_VALUE_PATHS.data_type, Kind::bytes(), None)
146            .optional_field(&DNSTAP_VALUE_PATHS.error, Kind::bytes(), None)
147            .optional_field(&DNSTAP_VALUE_PATHS.raw_data, Kind::bytes(), None)
148            .optional_field(&DNSTAP_VALUE_PATHS.time, Kind::integer(), None)
149            .optional_field(&DNSTAP_VALUE_PATHS.time_precision, Kind::bytes(), None)
150    }
151
152    /// Schema definition from the message.
153    pub fn message_schema_definition(
154        &self,
155        schema: vector_lib::schema::Definition,
156    ) -> vector_lib::schema::Definition {
157        schema
158            .optional_field(&DNSTAP_VALUE_PATHS.socket_family, Kind::bytes(), None)
159            .optional_field(&DNSTAP_VALUE_PATHS.socket_protocol, Kind::bytes(), None)
160            .optional_field(&DNSTAP_VALUE_PATHS.query_address, Kind::bytes(), None)
161            .optional_field(&DNSTAP_VALUE_PATHS.query_port, Kind::integer(), None)
162            .optional_field(&DNSTAP_VALUE_PATHS.response_address, Kind::bytes(), None)
163            .optional_field(&DNSTAP_VALUE_PATHS.response_port, Kind::integer(), None)
164            .optional_field(&DNSTAP_VALUE_PATHS.query_zone, Kind::bytes(), None)
165            .with_event_field(&DNSTAP_VALUE_PATHS.message_type_id, Kind::integer(), None)
166            .optional_field(&DNSTAP_VALUE_PATHS.message_type, Kind::bytes(), None)
167            .optional_field(
168                &DNSTAP_VALUE_PATHS.request_message,
169                Kind::object(self.request_message_schema_definition()),
170                None,
171            )
172            .optional_field(
173                &DNSTAP_VALUE_PATHS.response_message,
174                Kind::object(self.request_message_schema_definition()),
175                None,
176            )
177    }
178
179    /// The schema definition for a dns tap message.
180    pub fn schema_definition(
181        &self,
182        schema: vector_lib::schema::Definition,
183    ) -> vector_lib::schema::Definition {
184        self.root_schema_definition(self.message_schema_definition(schema))
185    }
186}
187
188/// Collection of owned value paths.
189#[derive(Debug, Clone)]
190pub struct DnstapPaths {
191    // DnstapRootDataSchema
192    pub server_identity: OwnedValuePath,
193    pub server_version: OwnedValuePath,
194    pub extra: OwnedValuePath,
195    pub data_type: OwnedValuePath,
196    pub data_type_id: OwnedValuePath,
197    pub time: OwnedValuePath,
198    pub time_precision: OwnedValuePath,
199    pub error: OwnedValuePath,
200    pub raw_data: OwnedValuePath,
201
202    // DnstapMessageSchema
203    pub socket_family: OwnedValuePath,
204    pub socket_protocol: OwnedValuePath,
205    pub query_address: OwnedValuePath,
206    pub query_port: OwnedValuePath,
207    pub response_address: OwnedValuePath,
208    pub response_port: OwnedValuePath,
209    pub query_zone: OwnedValuePath,
210    pub message_type: OwnedValuePath,
211    pub message_type_id: OwnedValuePath,
212    pub request_message: OwnedValuePath,
213    pub response_message: OwnedValuePath,
214
215    // DnsQueryMessageSchema
216    pub response_code: OwnedValuePath,
217    pub response: OwnedValuePath,
218    pub header: OwnedValuePath,
219    pub question_section: OwnedValuePath,
220    pub answer_section: OwnedValuePath,
221    pub authority_section: OwnedValuePath,
222    pub additional_section: OwnedValuePath,
223    pub opt_pseudo_section: OwnedValuePath,
224
225    // DnsUpdateMessageSchema
226    pub zone_section: OwnedValuePath,
227    pub prerequisite_section: OwnedValuePath,
228    pub update_section: OwnedValuePath,
229
230    // DnsMessageHeaderCommonSchema
231    pub id: OwnedValuePath,
232    pub opcode: OwnedValuePath,
233    pub rcode: OwnedValuePath,
234    pub qr: OwnedValuePath,
235
236    // DnsQueryHeaderSchema
237    pub aa: OwnedValuePath,
238    pub tc: OwnedValuePath,
239    pub rd: OwnedValuePath,
240    pub ra: OwnedValuePath,
241    pub ad: OwnedValuePath,
242    pub cd: OwnedValuePath,
243    pub question_count: OwnedValuePath,
244    pub answer_count: OwnedValuePath,
245    pub authority_count: OwnedValuePath,
246    pub ar_count: OwnedValuePath,
247
248    // DnsUpdateHeaderSchema
249    pub zone_count: OwnedValuePath,
250    pub prerequisite_count: OwnedValuePath,
251    pub update_count: OwnedValuePath,
252    pub ad_count: OwnedValuePath,
253
254    // DnsMessageOptPseudoSectionSchema
255    pub extended_rcode: OwnedValuePath,
256    pub version: OwnedValuePath,
257    pub do_flag: OwnedValuePath,
258    pub udp_max_payload_size: OwnedValuePath,
259    pub ede: OwnedValuePath,
260    pub options: OwnedValuePath,
261
262    // DnsMessageEdeOptionSchema
263    pub info_code: OwnedValuePath,
264    pub purpose: OwnedValuePath,
265    pub extra_text: OwnedValuePath,
266
267    // DnsMessageOptionSchema
268    pub opt_code: OwnedValuePath,
269    pub opt_name: OwnedValuePath,
270    pub opt_data: OwnedValuePath,
271
272    // DnsRecordSchema
273    pub domain_name: OwnedValuePath,
274    pub record_type: OwnedValuePath,
275    pub record_type_id: OwnedValuePath,
276    pub ttl: OwnedValuePath,
277    pub class: OwnedValuePath,
278    pub rdata: OwnedValuePath,
279    pub rdata_bytes: OwnedValuePath,
280
281    // DnsQueryQuestionSchema
282    pub question_type: OwnedValuePath,
283    pub question_type_id: OwnedValuePath,
284
285    // DnsUpdateZoneInfoSchema
286    pub zone_name: OwnedValuePath,
287    pub zone_class: OwnedValuePath,
288    pub zone_type: OwnedValuePath,
289    pub zone_type_id: OwnedValuePath,
290}
291
292/// Lazily initialized singleton.
293pub static DNSTAP_VALUE_PATHS: LazyLock<DnstapPaths> = LazyLock::new(|| DnstapPaths {
294    server_identity: owned_value_path!("serverId"),
295    server_version: owned_value_path!("serverVersion"),
296    extra: owned_value_path!("extraInfo"),
297    data_type: owned_value_path!("dataType"),
298    data_type_id: owned_value_path!("dataTypeId"),
299    time: owned_value_path!("time"),
300    time_precision: owned_value_path!("timePrecision"),
301    error: owned_value_path!("error"),
302    raw_data: owned_value_path!("rawData"),
303    socket_family: owned_value_path!("socketFamily"),
304    socket_protocol: owned_value_path!("socketProtocol"),
305    query_address: owned_value_path!("sourceAddress"),
306    query_port: owned_value_path!("sourcePort"),
307    response_address: owned_value_path!("responseAddress"),
308    response_port: owned_value_path!("responsePort"),
309    query_zone: owned_value_path!("queryZone"),
310    message_type: owned_value_path!("messageType"),
311    message_type_id: owned_value_path!("messageTypeId"),
312    request_message: owned_value_path!("requestData"),
313    response_message: owned_value_path!("responseData"),
314    response_code: owned_value_path!("fullRcode"),
315    response: owned_value_path!("rcodeName"),
316    header: owned_value_path!("header"),
317    question_section: owned_value_path!("question"),
318    answer_section: owned_value_path!("answers"),
319    authority_section: owned_value_path!("authority"),
320    additional_section: owned_value_path!("additional"),
321    opt_pseudo_section: owned_value_path!("opt"),
322    zone_section: owned_value_path!("zone"),
323    prerequisite_section: owned_value_path!("prerequisite"),
324    update_section: owned_value_path!("update"),
325    id: owned_value_path!("id"),
326    opcode: owned_value_path!("opcode"),
327    rcode: owned_value_path!("rcode"),
328    qr: owned_value_path!("qr"),
329    aa: owned_value_path!("aa"),
330    tc: owned_value_path!("tc"),
331    rd: owned_value_path!("rd"),
332    ra: owned_value_path!("ra"),
333    ad: owned_value_path!("ad"),
334    cd: owned_value_path!("cd"),
335    question_count: owned_value_path!("qdCount"),
336    answer_count: owned_value_path!("anCount"),
337    authority_count: owned_value_path!("nsCount"),
338    ar_count: owned_value_path!("arCount"),
339    zone_count: owned_value_path!("zoCount"),
340    prerequisite_count: owned_value_path!("prCount"),
341    update_count: owned_value_path!("upCount"),
342    ad_count: owned_value_path!("adCount"),
343    extended_rcode: owned_value_path!("extendedRcode"),
344    version: owned_value_path!("ednsVersion"),
345    do_flag: owned_value_path!("do"),
346    udp_max_payload_size: owned_value_path!("udpPayloadSize"),
347    ede: owned_value_path!("ede"),
348    options: owned_value_path!("options"),
349    info_code: owned_value_path!("infoCode"),
350    purpose: owned_value_path!("purpose"),
351    extra_text: owned_value_path!("extraText"),
352    opt_code: owned_value_path!("optCode"),
353    opt_name: owned_value_path!("optName"),
354    opt_data: owned_value_path!("optValue"),
355    record_type: owned_value_path!("recordType"),
356    record_type_id: owned_value_path!("recordTypeId"),
357    ttl: owned_value_path!("ttl"),
358    class: owned_value_path!("class"),
359    rdata: owned_value_path!("rData"),
360    rdata_bytes: owned_value_path!("rDataBytes"),
361    domain_name: owned_value_path!("domainName"),
362    question_type: owned_value_path!("questionType"),
363    question_type_id: owned_value_path!("questionTypeId"),
364    zone_name: owned_value_path!("zName"),
365    zone_class: owned_value_path!("zClass"),
366    zone_type: owned_value_path!("zType"),
367    zone_type_id: owned_value_path!("zTypeId"),
368});
369
370#[derive(Debug, Default, Clone)]
371pub struct DnsQueryHeaderSchema;
372
373impl DnsQueryHeaderSchema {
374    pub fn schema_definition() -> Collection<Field> {
375        btreemap! {
376            DNSTAP_VALUE_PATHS.id.to_string() => Kind::integer(),
377            DNSTAP_VALUE_PATHS.opcode.to_string() => Kind::integer(),
378            DNSTAP_VALUE_PATHS.rcode.to_string() => Kind::integer(),
379            DNSTAP_VALUE_PATHS.qr.to_string() => Kind::integer(),
380            DNSTAP_VALUE_PATHS.aa.to_string() => Kind::boolean(),
381            DNSTAP_VALUE_PATHS.tc.to_string() => Kind::boolean(),
382            DNSTAP_VALUE_PATHS.rd.to_string() => Kind::boolean(),
383            DNSTAP_VALUE_PATHS.ra.to_string() => Kind::boolean(),
384            DNSTAP_VALUE_PATHS.ad.to_string() => Kind::boolean(),
385            DNSTAP_VALUE_PATHS.cd.to_string() => Kind::boolean(),
386            DNSTAP_VALUE_PATHS.ar_count.to_string() => Kind::integer().or_undefined(),
387            DNSTAP_VALUE_PATHS.question_count.to_string() => Kind::integer().or_undefined(),
388            DNSTAP_VALUE_PATHS.answer_count.to_string() => Kind::integer().or_undefined(),
389            DNSTAP_VALUE_PATHS.authority_count.to_string() => Kind::integer().or_undefined(),
390        }
391        .into()
392    }
393}
394
395#[derive(Debug, Default, Clone)]
396pub struct DnsUpdateHeaderSchema;
397
398impl DnsUpdateHeaderSchema {
399    pub fn schema_definition() -> Collection<Field> {
400        btreemap! {
401            DNSTAP_VALUE_PATHS.id.to_string() => Kind::integer(),
402            DNSTAP_VALUE_PATHS.opcode.to_string() => Kind::integer(),
403            DNSTAP_VALUE_PATHS.rcode.to_string() => Kind::integer(),
404            DNSTAP_VALUE_PATHS.qr.to_string() => Kind::integer(),
405            DNSTAP_VALUE_PATHS.zone_count.to_string() => Kind::integer().or_undefined(),
406            DNSTAP_VALUE_PATHS.prerequisite_count.to_string() => Kind::integer().or_undefined(),
407            DNSTAP_VALUE_PATHS.update_count.to_string() => Kind::integer().or_undefined(),
408            DNSTAP_VALUE_PATHS.ad_count.to_string() => Kind::integer().or_undefined(),
409        }
410        .into()
411    }
412}
413
414#[derive(Debug, Default, Clone)]
415pub struct DnsMessageOptPseudoSectionSchema;
416
417impl DnsMessageOptPseudoSectionSchema {
418    pub fn schema_definition() -> Collection<Field> {
419        btreemap! {
420            DNSTAP_VALUE_PATHS.extended_rcode.to_string() => Kind::integer(),
421            DNSTAP_VALUE_PATHS.version.to_string() => Kind::integer(),
422            DNSTAP_VALUE_PATHS.do_flag.to_string() => Kind::boolean(),
423            DNSTAP_VALUE_PATHS.udp_max_payload_size.to_string() => Kind::integer(),
424            DNSTAP_VALUE_PATHS.options.to_string() => Kind::array(
425                Collection::from_unknown(Kind::object(DnsMessageOptionSchema::schema_definition()))
426            ).or_undefined(),
427        }
428        .into()
429    }
430}
431
432#[derive(Debug, Default, Clone)]
433pub struct DnsMessageEdeOptionSchema;
434
435impl DnsMessageEdeOptionSchema {
436    pub fn schema_definition() -> Collection<Field> {
437        btreemap! {
438            DNSTAP_VALUE_PATHS.info_code.to_string() => Kind::integer(),
439            DNSTAP_VALUE_PATHS.purpose.to_string() => Kind::bytes(),
440            DNSTAP_VALUE_PATHS.extra_text.to_string() => Kind::bytes(),
441        }
442        .into()
443    }
444}
445
446#[derive(Debug, Default, Clone)]
447pub struct DnsMessageOptionSchema;
448
449impl DnsMessageOptionSchema {
450    pub fn schema_definition() -> Collection<Field> {
451        btreemap! {
452            DNSTAP_VALUE_PATHS.opt_code.to_string() => Kind::integer(),
453            DNSTAP_VALUE_PATHS.opt_name.to_string() => Kind::bytes(),
454            DNSTAP_VALUE_PATHS.opt_data.to_string() => Kind::bytes(),
455        }
456        .into()
457    }
458}
459
460#[derive(Debug, Default, Clone)]
461pub struct DnsRecordSchema;
462
463impl DnsRecordSchema {
464    pub fn schema_definition() -> Collection<Field> {
465        btreemap! {
466            DNSTAP_VALUE_PATHS.domain_name.to_string() => Kind::bytes(),
467            DNSTAP_VALUE_PATHS.record_type.to_string() => Kind::bytes().or_undefined(),
468            DNSTAP_VALUE_PATHS.record_type_id.to_string() => Kind::integer(),
469            DNSTAP_VALUE_PATHS.ttl.to_string() => Kind::integer(),
470            DNSTAP_VALUE_PATHS.class.to_string() => Kind::bytes(),
471            DNSTAP_VALUE_PATHS.rdata.to_string() => Kind::bytes(),
472            DNSTAP_VALUE_PATHS.rdata_bytes.to_string() => Kind::bytes().or_undefined(),
473        }
474        .into()
475    }
476}
477
478#[derive(Debug, Default, Clone)]
479pub struct DnsQueryQuestionSchema;
480
481impl DnsQueryQuestionSchema {
482    pub fn schema_definition() -> Collection<Field> {
483        btreemap! {
484            DNSTAP_VALUE_PATHS.class.to_string() => Kind::bytes(),
485            DNSTAP_VALUE_PATHS.domain_name.to_string() => Kind::bytes(),
486            DNSTAP_VALUE_PATHS.question_type.to_string() => Kind::bytes(),
487            DNSTAP_VALUE_PATHS.question_type_id.to_string() => Kind::integer(),
488        }
489        .into()
490    }
491}
492
493#[derive(Debug, Default, Clone)]
494pub struct DnsUpdateZoneInfoSchema;
495
496impl DnsUpdateZoneInfoSchema {
497    pub fn schema_definition() -> Collection<Field> {
498        btreemap! {
499            DNSTAP_VALUE_PATHS.zone_name.to_string() => Kind::bytes(),
500            DNSTAP_VALUE_PATHS.zone_type.to_string() => Kind::bytes().or_undefined(),
501            DNSTAP_VALUE_PATHS.zone_type_id.to_string() => Kind::integer(),
502            DNSTAP_VALUE_PATHS.zone_class.to_string() => Kind::bytes(),
503        }
504        .into()
505    }
506}