sync_resolve/
record.rs

1//! DNS resource record types
2
3use std::mem::transmute;
4use std::net::{Ipv4Addr, Ipv6Addr};
5
6use crate::message::{DecodeError, EncodeError, MsgReader, MsgWriter};
7
8/// Represents the class of data in a message.
9#[derive(Copy, Clone, Debug, Eq, PartialEq)]
10pub enum Class {
11    /// Internet (`IN`)
12    Internet,
13    /// Any (`*`)
14    Any,
15    /// An unrecognized class
16    Other(u16),
17}
18
19impl Class {
20    /// Converts a `u16` to a `Class`.
21    pub fn from_u16(u: u16) -> Class {
22        match u {
23            1 => Class::Internet,
24            255 => Class::Any,
25            n => Class::Other(n),
26        }
27    }
28
29    /// Converts a `Class` to a `u16`.
30    pub fn to_u16(&self) -> u16 {
31        match *self {
32            Class::Internet => 1,
33            Class::Any => 255,
34            Class::Other(n) => n,
35        }
36    }
37}
38
39/// Represents the type of data in a message.
40#[derive(Copy, Clone, Debug, Eq, PartialEq)]
41pub enum RecordType {
42    /// An IPv4 host address
43    A,
44    /// An IPv6 host address
45    AAAA,
46    /// Canonical name for an alias
47    CName,
48    /// Mail exchange
49    Mx,
50    /// Authoritative name server
51    Ns,
52    /// Domain name pointer
53    Ptr,
54    /// Start of authority
55    Soa,
56    /// Service record
57    Srv,
58    /// Text string
59    Txt,
60    /// Unrecognized record type
61    Other(u16),
62}
63
64macro_rules! record_types {
65    ( $( $name:ident => $code:expr , )+ ) => {
66        impl RecordType {
67            /// Converts a `u16` to a `RecordType`.
68            pub fn from_u16(u: u16) -> RecordType {
69                match u {
70                    $( $code => RecordType::$name , )+
71                    n => RecordType::Other(n),
72                }
73            }
74
75            /// Converts a `RecordType` to a `u16`.
76            pub fn to_u16(&self) -> u16 {
77                match *self {
78                    $( RecordType::$name => $code , )+
79                    RecordType::Other(n) => n,
80                }
81            }
82        }
83    }
84}
85
86record_types! {
87    A => 1,
88    AAAA => 28,
89    CName => 5,
90    Mx => 15,
91    Ns => 2,
92    Ptr => 12,
93    Soa => 6,
94    Srv => 33,
95    Txt => 16,
96}
97
98/// Represents resource record data.
99pub trait Record: Sized {
100    /// Decodes the `Record` from resource rdata.
101    fn decode(data: &mut MsgReader) -> Result<Self, DecodeError>;
102
103    /// Encodes the `Record` to resource rdata.
104    fn encode(&self, data: &mut MsgWriter) -> Result<(), EncodeError>;
105
106    /// Returns the `RecordType` of queries for this record.
107    fn record_type() -> RecordType;
108}
109
110/// An IPv4 host address
111#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
112pub struct A {
113    /// The host address
114    pub address: Ipv4Addr,
115}
116
117impl Record for A {
118    fn decode(data: &mut MsgReader) -> Result<Self, DecodeError> {
119        let mut buf = [0; 4];
120        data.read(&mut buf)?;
121        Ok(A {
122            address: Ipv4Addr::new(buf[0], buf[1], buf[2], buf[3]),
123        })
124    }
125
126    fn encode(&self, data: &mut MsgWriter) -> Result<(), EncodeError> {
127        data.write(&self.address.octets())
128    }
129
130    fn record_type() -> RecordType {
131        RecordType::A
132    }
133}
134
135/// An IPv6 host address
136#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
137pub struct AAAA {
138    /// The host address
139    pub address: Ipv6Addr,
140}
141
142impl Record for AAAA {
143    fn decode(data: &mut MsgReader) -> Result<Self, DecodeError> {
144        let mut buf = [0; 16];
145        data.read(&mut buf)?;
146        let segments: [u16; 8] = unsafe { transmute(buf) };
147        Ok(AAAA {
148            address: Ipv6Addr::new(
149                u16::from_be(segments[0]),
150                u16::from_be(segments[1]),
151                u16::from_be(segments[2]),
152                u16::from_be(segments[3]),
153                u16::from_be(segments[4]),
154                u16::from_be(segments[5]),
155                u16::from_be(segments[6]),
156                u16::from_be(segments[7]),
157            ),
158        })
159    }
160
161    fn encode(&self, data: &mut MsgWriter) -> Result<(), EncodeError> {
162        let mut segments = self.address.segments();
163        for seg in &mut segments {
164            *seg = seg.to_be()
165        }
166        let buf: [u8; 16] = unsafe { transmute(segments) };
167        data.write(&buf)
168    }
169
170    fn record_type() -> RecordType {
171        RecordType::AAAA
172    }
173}
174
175/// Canonical name for an alias
176#[derive(Clone, Debug, PartialEq, Eq, Hash)]
177pub struct CName {
178    /// Canonical host name
179    pub name: String,
180}
181
182impl Record for CName {
183    fn decode(data: &mut MsgReader) -> Result<Self, DecodeError> {
184        Ok(CName {
185            name: data.read_name()?,
186        })
187    }
188
189    fn encode(&self, data: &mut MsgWriter) -> Result<(), EncodeError> {
190        data.write_name(&self.name)
191    }
192
193    fn record_type() -> RecordType {
194        RecordType::CName
195    }
196}
197
198/// Mail exchange data
199#[derive(Clone, Debug, PartialEq, Eq, Hash)]
200pub struct Mx {
201    /// Represents the preference of this record among others.
202    /// Lower values are preferred.
203    pub preference: u16,
204    /// Domain name willing to act as mail exchange for the host.
205    pub exchange: String,
206}
207
208impl Record for Mx {
209    fn decode(data: &mut MsgReader) -> Result<Self, DecodeError> {
210        Ok(Mx {
211            preference: data.read_u16()?,
212            exchange: data.read_name()?,
213        })
214    }
215
216    fn encode(&self, data: &mut MsgWriter) -> Result<(), EncodeError> {
217        data.write_u16(self.preference)?;
218        data.write_name(&self.exchange)
219    }
220
221    fn record_type() -> RecordType {
222        RecordType::Mx
223    }
224}
225
226/// Authoritative name server
227#[derive(Clone, Debug, PartialEq, Eq, Hash)]
228pub struct Ns {
229    /// Host which should be authoritative for the specified class and domain
230    pub name: String,
231}
232
233impl Record for Ns {
234    fn decode(data: &mut MsgReader) -> Result<Self, DecodeError> {
235        Ok(Ns {
236            name: data.read_name()?,
237        })
238    }
239
240    fn encode(&self, data: &mut MsgWriter) -> Result<(), EncodeError> {
241        data.write_name(&self.name)
242    }
243
244    fn record_type() -> RecordType {
245        RecordType::Ns
246    }
247}
248
249/// Domain name pointer
250#[derive(Clone, Debug, PartialEq, Eq, Hash)]
251pub struct Ptr {
252    /// The name of the host
253    pub name: String,
254}
255
256impl Record for Ptr {
257    fn decode(data: &mut MsgReader) -> Result<Self, DecodeError> {
258        Ok(Ptr {
259            name: data.read_name()?,
260        })
261    }
262
263    fn encode(&self, data: &mut MsgWriter) -> Result<(), EncodeError> {
264        data.write_name(&self.name)
265    }
266
267    fn record_type() -> RecordType {
268        RecordType::Ptr
269    }
270}
271
272/// Start of authority
273#[derive(Clone, Debug, PartialEq, Eq, Hash)]
274pub struct Soa {
275    /// Domain name of the name server that was the original or primary source
276    /// of data for this zone.
277    pub mname: String,
278    /// Domain name which specifies the mailbox of the person responsible
279    /// for this zone.
280    pub rname: String,
281    /// Version number of the original copy of the zone. This value wraps and
282    /// should be compared using sequence space arithmetic.
283    pub serial: u32,
284    /// Time interval before the zone should be refreshed.
285    pub refresh: u32,
286    /// Time interval that should elapse before a failed refresh should be
287    /// retried.
288    pub retry: u32,
289    /// Time value that specifies the upper limit on the time interval that can
290    /// elapse before the zone is no longer authoritative.
291    pub expire: u32,
292    /// Minimum TTL that should be exported with any resource record from this
293    /// zone.
294    pub minimum: u32,
295}
296
297impl Record for Soa {
298    fn decode(data: &mut MsgReader) -> Result<Self, DecodeError> {
299        Ok(Soa {
300            mname: data.read_name()?,
301            rname: data.read_name()?,
302            serial: data.read_u32()?,
303            refresh: data.read_u32()?,
304            retry: data.read_u32()?,
305            expire: data.read_u32()?,
306            minimum: data.read_u32()?,
307        })
308    }
309
310    fn encode(&self, data: &mut MsgWriter) -> Result<(), EncodeError> {
311        data.write_name(&self.mname)?;
312        data.write_name(&self.rname)?;
313        data.write_u32(self.serial)?;
314        data.write_u32(self.refresh)?;
315        data.write_u32(self.retry)?;
316        data.write_u32(self.expire)?;
317        data.write_u32(self.minimum)?;
318        Ok(())
319    }
320
321    fn record_type() -> RecordType {
322        RecordType::Soa
323    }
324}
325
326/// Service record
327#[derive(Clone, Debug, PartialEq, Eq, Hash)]
328pub struct Srv {
329    /// Record priority
330    pub priority: u16,
331    /// Record weight
332    pub weight: u16,
333    /// Service port
334    pub port: u16,
335    /// Target host name
336    pub target: String,
337}
338
339impl Record for Srv {
340    fn decode(data: &mut MsgReader) -> Result<Self, DecodeError> {
341        Ok(Srv {
342            priority: data.read_u16()?,
343            weight: data.read_u16()?,
344            port: data.read_u16()?,
345            target: data.read_name()?,
346        })
347    }
348
349    fn encode(&self, data: &mut MsgWriter) -> Result<(), EncodeError> {
350        data.write_u16(self.priority)?;
351        data.write_u16(self.weight)?;
352        data.write_u16(self.port)?;
353        data.write_name(&self.target)?;
354        Ok(())
355    }
356
357    fn record_type() -> RecordType {
358        RecordType::Srv
359    }
360}
361
362/// Text record
363#[derive(Clone, Debug, PartialEq, Eq, Hash)]
364pub struct Txt {
365    /// One or more character strings
366    pub data: Vec<u8>,
367}
368
369impl Record for Txt {
370    fn decode(data: &mut MsgReader) -> Result<Self, DecodeError> {
371        Ok(Txt {
372            data: data.read_character_string()?,
373        })
374    }
375
376    fn encode(&self, data: &mut MsgWriter) -> Result<(), EncodeError> {
377        data.write_character_string(&self.data)
378    }
379
380    fn record_type() -> RecordType {
381        RecordType::Txt
382    }
383}