dnstap_parser/
schema.rs

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