dns_resolver/
metrics.rs

1use std::net::{Ipv4Addr, Ipv6Addr};
2
3use dns_types::protocol::types::*;
4use dns_types::zones::types::*;
5
6/// The A record for a blocked question
7pub const BLOCKED_A: RecordTypeWithData = RecordTypeWithData::A {
8    address: Ipv4Addr::UNSPECIFIED,
9};
10
11/// The AAAA record for a blocked question
12pub const BLOCKED_AAAA: RecordTypeWithData = RecordTypeWithData::AAAA {
13    address: Ipv6Addr::UNSPECIFIED,
14};
15
16/// Metrics from a resolution attempt.  The resolvers build this
17/// structure rather than update the Prometheus metrics directly.
18pub struct Metrics {
19    /// Hits on authoritative data: zone authoritative answers,
20    /// CNAMEs, delegations, and name errors.  Does not include
21    /// blocked domains.
22    pub authoritative_hits: u64,
23    /// Hits on non-authoritative data: zone non-authoritative answers
24    /// and CNAMEs (zone non-authoritative delegations and name errors
25    /// are ignored).  Does not include blocked domains.
26    pub override_hits: u64,
27    /// A or AAAA questions (ie, not *) where the result is from a
28    /// zone and has the unspecified IP.
29    pub blocked: u64,
30    /// Cache misses
31    pub cache_misses: u64,
32    /// Cache hits
33    pub cache_hits: u64,
34    /// Questions which are answered by some upstream nameserver.
35    pub nameserver_hits: u64,
36    /// Questions which an upstream nameserver fails to answer.
37    pub nameserver_misses: u64,
38}
39
40impl Metrics {
41    pub fn new() -> Self {
42        Metrics {
43            authoritative_hits: 0,
44            override_hits: 0,
45            blocked: 0,
46            cache_misses: 0,
47            cache_hits: 0,
48            nameserver_hits: 0,
49            nameserver_misses: 0,
50        }
51    }
52
53    pub fn zoneresult_answer(&mut self, rrs: &[ResourceRecord], zone: &Zone, question: &Question) {
54        if rrs.len() == 1 {
55            let rtype = &rrs[0].rtype_with_data;
56            if (question.qtype == QueryType::Record(RecordType::A) && rtype == &BLOCKED_A)
57                || (question.qtype == QueryType::Record(RecordType::AAAA) && rtype == &BLOCKED_AAAA)
58            {
59                self.blocked += 1;
60                return;
61            }
62        }
63
64        if zone.is_authoritative() {
65            self.authoritative_hits += 1;
66        } else {
67            self.override_hits += 1;
68        }
69    }
70
71    pub fn zoneresult_cname(&mut self, zone: &Zone) {
72        if zone.is_authoritative() {
73            self.authoritative_hits += 1;
74        } else {
75            self.override_hits += 1;
76        }
77    }
78
79    pub fn zoneresult_delegation(&mut self, zone: &Zone) {
80        if zone.is_authoritative() {
81            self.authoritative_hits += 1;
82        }
83    }
84
85    pub fn zoneresult_nameerror(&mut self, zone: &Zone) {
86        if zone.is_authoritative() {
87            self.authoritative_hits += 1;
88        }
89    }
90
91    pub fn cache_hit(&mut self) {
92        self.cache_hits += 1;
93    }
94
95    pub fn cache_miss(&mut self) {
96        self.cache_misses += 1;
97    }
98
99    pub fn nameserver_hit(&mut self) {
100        self.nameserver_hits += 1;
101    }
102
103    pub fn nameserver_miss(&mut self) {
104        self.nameserver_misses += 1;
105    }
106}
107
108impl Default for Metrics {
109    fn default() -> Self {
110        Self::new()
111    }
112}