Skip to main content

iris_core/protocols/stream/dns/
transaction.rs

1//! DNS transaction components.
2
3use dns_parser::rdata::{Aaaa, RData, A};
4use dns_parser::{Packet, ResponseCode};
5
6use serde::Serialize;
7
8/// A DNS Query.
9#[derive(Clone, Debug, Serialize)]
10pub struct DnsQuery {
11    pub num_questions: u16,
12    pub recursion_desired: bool, // appears in query & answer
13    pub queries: Vec<String>,    // typically only one question per query, could have multiple
14}
15
16impl DnsQuery {
17    pub(super) fn parse_query(pkt: &Packet) -> Self {
18        let mut queries = Vec::new();
19        for q in &pkt.questions {
20            log::debug!("  query: {}/{:?}", q.qname, q.qtype);
21            queries.push(q.qname.to_string());
22        }
23        DnsQuery {
24            num_questions: pkt.header.questions,
25            recursion_desired: pkt.header.recursion_desired,
26            queries,
27        }
28    }
29}
30
31/// A DNS Response.
32#[derive(Clone, Debug, Serialize)]
33pub struct DnsResponse {
34    pub response_code: ResponseCode,
35    pub authoritative: bool, // if the DNS server is authoritative for the queried hostname, appear in answer
36    pub recursion_available: bool, // appear in answer
37    pub num_answers: u16,
38    pub num_additional: u16, // the number of  records in  Additional section in answer
39    pub num_nameservers: u16, // the number of  records in  Authority section in answer
40    pub answers: Vec<DnsRecord>,
41    pub nameservers: Vec<DnsRecord>,
42    pub additionals: Vec<DnsRecord>,
43}
44
45impl DnsResponse {
46    pub(super) fn parse_response(pkt: &Packet) -> Self {
47        let mut answers = Vec::new();
48        for answer in &pkt.answers {
49            log::debug!("  answer: {}/{:?}", answer.name, answer.data);
50            let data = Data::new(&answer.data);
51            answers.push(DnsRecord {
52                name: answer.name.to_string(),
53                data,
54                ttl: answer.ttl,
55            });
56        }
57        let mut nameservers = Vec::new();
58        for nameserver in &pkt.nameservers {
59            let data = Data::new(&nameserver.data);
60            nameservers.push(DnsRecord {
61                name: nameserver.name.to_string(),
62                data,
63                ttl: nameserver.ttl,
64            });
65        }
66        let mut additionals = Vec::new();
67        for additional in &pkt.additional {
68            let data = Data::new(&additional.data);
69            additionals.push(DnsRecord {
70                name: additional.name.to_string(),
71                data,
72                ttl: additional.ttl,
73            });
74        }
75        DnsResponse {
76            response_code: pkt.header.response_code,
77            authoritative: pkt.header.authoritative,
78            recursion_available: pkt.header.recursion_available,
79            num_answers: pkt.header.answers,
80            num_additional: pkt.header.additional,
81            num_nameservers: pkt.header.nameservers,
82            answers,
83            nameservers,
84            additionals,
85        }
86    }
87}
88
89/// A DNS Record.
90#[derive(Clone, Debug, Serialize)]
91pub struct DnsRecord {
92    pub name: String,
93    pub data: Data,
94    pub ttl: u32,
95}
96
97/// RData types.
98#[derive(Clone, Debug, Serialize)]
99pub enum Data {
100    A(A),
101    Aaaa(Aaaa),
102    Cname(String),
103    Mx(Mx),
104    Ns(String),
105    Ptr(String),
106    Soa(Soa),
107    Srv(Srv),
108    Txt(String),
109    Unknown,
110}
111
112impl Data {
113    fn new(data: &RData) -> Self {
114        match data {
115            RData::A(a) => Data::A(*a),
116            RData::AAAA(a) => Data::Aaaa(*a),
117            RData::CNAME(a) => Data::Cname(a.0.to_string()),
118            RData::MX(a) => Data::Mx(Mx {
119                preference: a.preference,
120                exchange: a.exchange.to_string(),
121            }),
122            RData::NS(a) => Data::Ns(a.0.to_string()),
123            RData::PTR(a) => Data::Ptr(a.0.to_string()),
124            RData::SOA(a) => Data::Soa(Soa {
125                primary_ns: a.primary_ns.to_string(),
126                mailbox: a.mailbox.to_string(),
127                serial: a.serial,
128                refresh: a.refresh,
129                retry: a.retry,
130                expire: a.expire,
131                minimum_ttl: a.minimum_ttl,
132            }),
133            RData::SRV(a) => Data::Srv(Srv {
134                priority: a.priority,
135                weight: a.weight,
136                port: a.port,
137                target: a.target.to_string(),
138            }),
139            RData::TXT(a) => Data::Txt(String::from_utf8_lossy(a.bytes).to_string()),
140            RData::Unknown(..) => Data::Unknown,
141        }
142    }
143}
144
145/// A DNS mail exchange (MX) record.
146#[derive(Debug, PartialEq, Eq, Clone, Serialize)]
147pub struct Mx {
148    pub preference: u16,
149    pub exchange: String,
150}
151
152/// A DNS start of authority (SOA) record.
153#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
154pub struct Soa {
155    pub primary_ns: String,
156    pub mailbox: String,
157    pub serial: u32,
158    pub refresh: u32,
159    pub retry: u32,
160    pub expire: u32,
161    pub minimum_ttl: u32,
162}
163
164/// A DNS service (SRV) record.
165#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
166pub struct Srv {
167    pub priority: u16,
168    pub weight: u16,
169    pub port: u16,
170    pub target: String,
171}