resolve/
record.rs

1//! DNS resource record types
2
3use std::mem::transmute;
4use std::net::{Ipv4Addr, Ipv6Addr};
5
6use 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        try!(data.read(&mut buf));
121        Ok(A{address: Ipv4Addr::new(buf[0], buf[1], buf[2], buf[3])})
122    }
123
124    fn encode(&self, data: &mut MsgWriter) -> Result<(), EncodeError> {
125        data.write(&self.address.octets())
126    }
127
128    fn record_type() -> RecordType { RecordType::A }
129}
130
131/// An IPv6 host address
132#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
133pub struct AAAA {
134    /// The host address
135    pub address: Ipv6Addr,
136}
137
138impl Record for AAAA {
139    fn decode(data: &mut MsgReader) -> Result<Self, DecodeError> {
140        let mut buf = [0; 16];
141        try!(data.read(&mut buf));
142        let segments: [u16; 8] = unsafe { transmute(buf) };
143        Ok(AAAA{address: Ipv6Addr::new(
144            u16::from_be(segments[0]), u16::from_be(segments[1]),
145            u16::from_be(segments[2]), u16::from_be(segments[3]),
146            u16::from_be(segments[4]), u16::from_be(segments[5]),
147            u16::from_be(segments[6]), u16::from_be(segments[7]))})
148    }
149
150    fn encode(&self, data: &mut MsgWriter) -> Result<(), EncodeError> {
151        let mut segments = self.address.segments();
152        for seg in &mut segments { *seg = seg.to_be() }
153        let buf: [u8; 16] = unsafe { transmute(segments) };
154        data.write(&buf)
155    }
156
157    fn record_type() -> RecordType { RecordType::AAAA }
158}
159
160/// Canonical name for an alias
161#[derive(Clone, Debug, PartialEq, Eq, Hash)]
162pub struct CName {
163    /// Canonical host name
164    pub name: String,
165}
166
167impl Record for CName {
168    fn decode(data: &mut MsgReader) -> Result<Self, DecodeError> {
169        Ok(CName{name: try!(data.read_name())})
170    }
171
172    fn encode(&self, data: &mut MsgWriter) -> Result<(), EncodeError> {
173        data.write_name(&self.name)
174    }
175
176    fn record_type() -> RecordType { RecordType::CName }
177}
178
179/// Mail exchange data
180#[derive(Clone, Debug, PartialEq, Eq, Hash)]
181pub struct Mx {
182    /// Represents the preference of this record among others.
183    /// Lower values are preferred.
184    pub preference: u16,
185    /// Domain name willing to act as mail exchange for the host.
186    pub exchange: String,
187}
188
189impl Record for Mx {
190    fn decode(data: &mut MsgReader) -> Result<Self, DecodeError> {
191        Ok(Mx{
192            preference: try!(data.read_u16()),
193            exchange: try!(data.read_name()),
194        })
195    }
196
197    fn encode(&self, data: &mut MsgWriter) -> Result<(), EncodeError> {
198        try!(data.write_u16(self.preference));
199        data.write_name(&self.exchange)
200    }
201
202    fn record_type() -> RecordType { RecordType::Mx }
203}
204
205/// Authoritative name server
206#[derive(Clone, Debug, PartialEq, Eq, Hash)]
207pub struct Ns {
208    /// Host which should be authoritative for the specified class and domain
209    pub name: String,
210}
211
212impl Record for Ns {
213    fn decode(data: &mut MsgReader) -> Result<Self, DecodeError> {
214        Ok(Ns{name: try!(data.read_name())})
215    }
216
217    fn encode(&self, data: &mut MsgWriter) -> Result<(), EncodeError> {
218        data.write_name(&self.name)
219    }
220
221    fn record_type() -> RecordType { RecordType::Ns }
222}
223
224/// Domain name pointer
225#[derive(Clone, Debug, PartialEq, Eq, Hash)]
226pub struct Ptr {
227    /// The name of the host
228    pub name: String,
229}
230
231impl Record for Ptr {
232    fn decode(data: &mut MsgReader) -> Result<Self, DecodeError> {
233        Ok(Ptr{name: try!(data.read_name())})
234    }
235
236    fn encode(&self, data: &mut MsgWriter) -> Result<(), EncodeError> {
237        data.write_name(&self.name)
238    }
239
240    fn record_type() -> RecordType { RecordType::Ptr }
241}
242
243/// Start of authority
244#[derive(Clone, Debug, PartialEq, Eq, Hash)]
245pub struct Soa {
246    /// Domain name of the name server that was the original or primary source
247    /// of data for this zone.
248    pub mname: String,
249    /// Domain name which specifies the mailbox of the person responsible
250    /// for this zone.
251    pub rname: String,
252    /// Version number of the original copy of the zone. This value wraps and
253    /// should be compared using sequence space arithmetic.
254    pub serial: u32,
255    /// Time interval before the zone should be refreshed.
256    pub refresh: u32,
257    /// Time interval that should elapse before a failed refresh should be retried.
258    pub retry: u32,
259    /// Time value that specifies the upper limit on the time interval that can
260    /// elapse before the zone is no longer authoritative.
261    pub expire: u32,
262    /// Minimum TTL that should be exported with any resource record from this zone.
263    pub minimum: u32,
264}
265
266impl Record for Soa {
267    fn decode(data: &mut MsgReader) -> Result<Self, DecodeError> {
268        Ok(Soa{
269            mname: try!(data.read_name()),
270            rname: try!(data.read_name()),
271            serial: try!(data.read_u32()),
272            refresh: try!(data.read_u32()),
273            retry: try!(data.read_u32()),
274            expire: try!(data.read_u32()),
275            minimum: try!(data.read_u32()),
276        })
277    }
278
279    fn encode(&self, data: &mut MsgWriter) -> Result<(), EncodeError> {
280        try!(data.write_name(&self.mname));
281        try!(data.write_name(&self.rname));
282        try!(data.write_u32(self.serial));
283        try!(data.write_u32(self.refresh));
284        try!(data.write_u32(self.retry));
285        try!(data.write_u32(self.expire));
286        try!(data.write_u32(self.minimum));
287        Ok(())
288    }
289
290    fn record_type() -> RecordType { RecordType::Soa }
291}
292
293/// Service record
294#[derive(Clone, Debug, PartialEq, Eq, Hash)]
295pub struct Srv {
296    /// Record priority
297    pub priority: u16,
298    /// Record weight
299    pub weight: u16,
300    /// Service port
301    pub port: u16,
302    /// Target host name
303    pub target: String,
304}
305
306impl Record for Srv {
307    fn decode(data: &mut MsgReader) -> Result<Self, DecodeError> {
308        Ok(Srv{
309            priority: try!(data.read_u16()),
310            weight: try!(data.read_u16()),
311            port: try!(data.read_u16()),
312            target: try!(data.read_name()),
313        })
314    }
315
316    fn encode(&self, data: &mut MsgWriter) -> Result<(), EncodeError> {
317        try!(data.write_u16(self.priority));
318        try!(data.write_u16(self.weight));
319        try!(data.write_u16(self.port));
320        try!(data.write_name(&self.target));
321        Ok(())
322    }
323
324    fn record_type() -> RecordType { RecordType::Srv }
325}
326
327/// Text record
328#[derive(Clone, Debug, PartialEq, Eq, Hash)]
329pub struct Txt {
330    /// One or more character strings
331    pub data: Vec<u8>,
332}
333
334impl Record for Txt {
335    fn decode(data: &mut MsgReader) -> Result<Self, DecodeError> {
336        Ok(Txt{data: try!(data.read_character_string())})
337    }
338
339    fn encode(&self, data: &mut MsgWriter) -> Result<(), EncodeError> {
340        data.write_character_string(&self.data)
341    }
342
343    fn record_type() -> RecordType { RecordType::Txt }
344}