1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
//! DNS transaction components.

use dns_parser::rdata::{Aaaa, RData, A};
use dns_parser::{Packet, ResponseCode};

use serde::Serialize;

/// A DNS Query.
#[derive(Clone, Debug, Serialize)]
pub struct DnsQuery {
    pub num_questions: u16,
    pub recursion_desired: bool, // appears in query & answer
    pub queries: Vec<String>,    // typically only one question per query, could have multiple
}

impl DnsQuery {
    pub(super) fn parse_query(pkt: &Packet) -> Self {
        let mut queries = Vec::new();
        for q in &pkt.questions {
            log::debug!("  query: {}/{:?}", q.qname, q.qtype);
            queries.push(q.qname.to_string());
        }
        DnsQuery {
            num_questions: pkt.header.questions,
            recursion_desired: pkt.header.recursion_desired,
            queries,
        }
    }
}

/// A DNS Response.
#[derive(Clone, Debug, Serialize)]
pub struct DnsResponse {
    pub response_code: ResponseCode,
    pub authoritative: bool, // if the DNS server is authoritative for the queried hostname, appear in answer
    pub recursion_available: bool, // appear in answer
    pub num_answers: u16,
    pub num_additional: u16, // the number of  records in  Additional section in answer
    pub num_nameservers: u16, // the number of  records in  Authority section in answer
    pub answers: Vec<DnsRecord>,
    pub nameservers: Vec<DnsRecord>,
    pub additionals: Vec<DnsRecord>,
}

impl DnsResponse {
    pub(super) fn parse_response(pkt: &Packet) -> Self {
        let mut answers = Vec::new();
        for answer in &pkt.answers {
            log::debug!("  answer: {}/{:?}", answer.name, answer.data);
            let data = Data::new(&answer.data);
            answers.push(DnsRecord {
                name: answer.name.to_string(),
                data,
                ttl: answer.ttl,
            });
        }
        let mut nameservers = Vec::new();
        for nameserver in &pkt.nameservers {
            let data = Data::new(&nameserver.data);
            nameservers.push(DnsRecord {
                name: nameserver.name.to_string(),
                data,
                ttl: nameserver.ttl,
            });
        }
        let mut additionals = Vec::new();
        for additional in &pkt.additional {
            let data = Data::new(&additional.data);
            additionals.push(DnsRecord {
                name: additional.name.to_string(),
                data,
                ttl: additional.ttl,
            });
        }
        DnsResponse {
            response_code: pkt.header.response_code,
            authoritative: pkt.header.authoritative,
            recursion_available: pkt.header.recursion_available,
            num_answers: pkt.header.answers,
            num_additional: pkt.header.additional,
            num_nameservers: pkt.header.nameservers,
            answers,
            nameservers,
            additionals,
        }
    }
}

/// A DNS Record.
#[derive(Clone, Debug, Serialize)]
pub struct DnsRecord {
    pub name: String,
    pub data: Data,
    pub ttl: u32,
}

/// RData types.
#[derive(Clone, Debug, Serialize)]
pub enum Data {
    A(A),
    Aaaa(Aaaa),
    Cname(String),
    Mx(Mx),
    Ns(String),
    Ptr(String),
    Soa(Soa),
    Srv(Srv),
    Txt(String),
    Unknown,
}

impl Data {
    fn new(data: &RData) -> Self {
        match data {
            RData::A(a) => Data::A(*a),
            RData::AAAA(a) => Data::Aaaa(*a),
            RData::CNAME(a) => Data::Cname(a.0.to_string()),
            RData::MX(a) => Data::Mx(Mx {
                preference: a.preference,
                exchange: a.exchange.to_string(),
            }),
            RData::NS(a) => Data::Ns(a.0.to_string()),
            RData::PTR(a) => Data::Ptr(a.0.to_string()),
            RData::SOA(a) => Data::Soa(Soa {
                primary_ns: a.primary_ns.to_string(),
                mailbox: a.mailbox.to_string(),
                serial: a.serial,
                refresh: a.refresh,
                retry: a.retry,
                expire: a.expire,
                minimum_ttl: a.minimum_ttl,
            }),
            RData::SRV(a) => Data::Srv(Srv {
                priority: a.priority,
                weight: a.weight,
                port: a.port,
                target: a.target.to_string(),
            }),
            RData::TXT(a) => Data::Txt(String::from_utf8_lossy(a.bytes).to_string()),
            RData::Unknown(..) => Data::Unknown,
        }
    }
}

/// A DNS mail exchange (MX) record.
#[derive(Debug, PartialEq, Eq, Clone, Serialize)]
pub struct Mx {
    pub preference: u16,
    pub exchange: String,
}

/// A DNS start of authority (SOA) record.
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
pub struct Soa {
    pub primary_ns: String,
    pub mailbox: String,
    pub serial: u32,
    pub refresh: u32,
    pub retry: u32,
    pub expire: u32,
    pub minimum_ttl: u32,
}

/// A DNS service (SRV) record.
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
pub struct Srv {
    pub priority: u16,
    pub weight: u16,
    pub port: u16,
    pub target: String,
}