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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
//! Resource Records
//!
//! This module defines the [`Record`] type that represents DNS resource
//! records. It also provides a type alias for parsed records with generic
//! data through [`GenericRecord`].
//!
//! [`Record`]: struct.Record.html
//! [`GenericRecord`]: type.GenericRecord.html

use std::fmt;
use super::{Composer, ComposeError, ComposeResult, DName, GenericRecordData,
            ParsedDName, ParsedRecordData, Parser, ParseResult, RecordData};
use ::iana::{Class, Rtype};


//------------ Record --------------------------------------------------------

/// A DNS resource record.
///
/// All information available through the DNS is stored in resource records.
/// They have a three part key of a domain name, resource record type, and
/// class. Data is arranged in a tree which is navigated using the domain
/// name. Each node in the tree carries a label, starting with the root
/// label as the top-most node. The tree is traversed by stepping through the
/// name from right to left, finding a child node carring the label of each
/// step.
///
/// The record type describes the kind of data the record holds, such as IP
/// addresses. The class, finally, describes which sort of network the
/// information is for since DNS was originally intended to be used for
/// networks other than the Internet as well. In practice, the only relevant
/// class is IN, the Internet. Note that each class has its own tree of nodes.
///
/// The payload of a resource record is its data. Its purpose, meaning, and
/// format is determined by the record type. For each unique three-part key
/// there can be multiple resource records. All these records for the same
/// key are called *resource record sets,* most often shortened to ‘RRset.’
///
/// There is one more piece of data: the TTL or time to live. This value
/// says how long a record remains valid before it should be refreshed from
/// its original source, given in seconds. The TTL is used to add caching
/// facilities to the DNS.
///
/// Values of the `Record` type represent one single resource record. Since
/// there are currently more than eighty record types—see [`Rtype`] for a
/// complete list—, the type is generic over a trait for record data. This
/// trait holds both the record type value and the record data as they are
/// inseparably entwined.
///
/// Since records contain domain names, the `Record` type is additionally
/// generic over a domain name type. 
///
/// There is three ways to create a record value. First, you can make one
/// yourself using the [`new()`] function. In will neatly take care of all
/// the generics through type inference. Secondly, you can parse a record
/// from an existing message. [`Message`] and its friends provide a way to
/// do that; see there for all the details. Finally, you can scan a record
/// from master data (aka zonefiles). See the [`domain::master`] module for
/// that.
///
/// Records can be place into DNS messages through the value chain starting 
/// with [`MessageBuilder`]. In order to make adding records easier, `Record`
/// implements the `From` trait for two kinds of tuples: A four-tuple of
/// name, class, time-to-live value, and record data and a triple leaving
/// out the class and assuming it to `Class::In`.
///
/// [`new()´]: #method.new
/// [`Message`]: ../message/struct.Message.html
/// [`MessageBuilder`]: ../message_builder/struct.MessageBuilder.html
/// [`Rtype`]: ../../iana/enum.Rtype.html
/// [`domain::master`]: ../../master/index.html
#[derive(Clone, Debug)]
pub struct Record<N: DName, D: RecordData> {
    name: N,
    class: Class,
    ttl: u32,
    data: D
}


/// # Creation and Element Access
///
impl<N: DName, D: RecordData> Record<N, D> {
    /// Creates a new record from its parts.
    pub fn new(name: N, class: Class, ttl: u32, data: D) -> Self {
        Record{name: name, class: class, ttl: ttl, data: data}
    }

    /// Returns a reference to the domain name.
    ///
    /// The domain name, sometimes called the *owner* of the record,
    /// specifies the node in the DNS tree this record belongs to.
    pub fn name(&self) -> &N {
        &self.name
    }

    /// Returns the record type.
    pub fn rtype(&self) -> Rtype {
        self.data.rtype()
    }

    /// Returns the record class.
    pub fn class(&self) -> Class {
        self.class
    }

    /// Sets the record’s class.
    pub fn set_class(&mut self, class: Class) {
        self.class = class
    }

    /// Returns the record’s time-to-live.
    pub fn ttl(&self) -> u32 {
        self.ttl
    }

    /// Sets the record’s time-to-live.
    pub fn set_ttl(&mut self, ttl: u32) {
        self.ttl = ttl
    }

    /// Return a reference to the record data.
    pub fn data(&self) -> &D {
        &self.data
    }

    /// Returns a mutable reference to the record data.
    pub fn data_mut(&mut self) -> &mut D {
        &mut self.data
    }

    /// Trades the record for its record data.
    pub fn into_data(self) -> D {
        self.data
    }
}


/// # Parsing
///
impl<'a, D: ParsedRecordData<'a>> Record<ParsedDName<'a>, D> {
    /// Parses a record from a parser.
    ///
    /// This function is only available for records that use a parsed domain
    /// name and a record data type that, too, can be parsed.
    pub fn parse(parser: &mut Parser<'a>) -> ParseResult<Option<Self>> {
        let name = try!(ParsedDName::parse(parser));
        let rtype = try!(Rtype::parse(parser));
        let class = try!(Class::parse(parser));
        let ttl = try!(parser.parse_u32());
        let rdlen = try!(parser.parse_u16()) as usize;
        try!(parser.set_limit(rdlen));
        let data = try!(D::parse(rtype, parser));
        if data.is_none() {
            try!(parser.skip(rdlen));
        }
        parser.remove_limit();
        Ok(data.map(|data| Record::new(name, class, ttl, data)))
    }
}

impl<'a> Record<ParsedDName<'a>, GenericRecordData<'a>> {
    /// Parses a record with generic data from a parser.
    pub fn parse_generic(parser: &mut Parser<'a>) -> ParseResult<Self> {
        Self::parse(parser).map(Option::unwrap)
    }
}
    

/// # Composing
///
impl<N: DName, D: RecordData> Record<N, D> {
    /// Appends the record’s wire-format representation to a composer.
    pub fn compose<C: AsMut<Composer>>(&self, composer: C)
                                       -> ComposeResult<()> {
        let mut builder = RecordBuilder::new(composer, &self.name, self.class,
                                             self.rtype(), self.ttl)?;
        self.data.compose(&mut builder)?;
        builder.finish().map(|_| ())
    }
}


//--- From

impl<N: DName, D: RecordData> From<(N, Class, u32, D)> for Record<N, D> {
    fn from(x: (N, Class, u32, D)) -> Self {
        Record::new(x.0, x.1, x.2, x.3)
    }
}

impl<N: DName, D: RecordData> From<(N, u32, D)> for Record<N, D> {
    fn from(x: (N, u32, D)) -> Self {
        Record::new(x.0, Class::In, x.1, x.2)
    }
}


//--- Display

impl<N, D> fmt::Display for Record<N, D>
     where N: DName + fmt::Display,
           D: RecordData + fmt::Display {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}\t{}\t{}\t{}\t{}",
               self.name, self.ttl, self.class, self.data.rtype(),
               self.data)
    }
}


//------------ GenericRecord -------------------------------------------------

/// A record with generic record data.
pub type GenericRecord<'a> = Record<ParsedDName<'a>, GenericRecordData<'a>>;


//------------ RecordBuilder -------------------------------------------------

/// A type for building records in place.
///
/// This type can be used to build complex record types without first
/// assembling the record data first, saving one copy.
///
/// A value of this type is created via `new()` which is given the target to
/// build into and the name, class, type, and ttl of the record. The returned
/// value is a composer and the record data can be written into it. Once all
/// writing is done, the original target can be retrieved via the `finish()`
/// method.
#[derive(Clone, Debug)]
pub struct RecordBuilder<C: AsMut<Composer>> {
    composer: C,
    len_pos: usize
}

impl<C: AsMut<Composer>> RecordBuilder<C> {
    pub fn new<N: DName>(mut composer: C, name: &N, class: Class,
                         rtype: Rtype, ttl: u32) -> ComposeResult<Self> {
        name.compose(composer.as_mut())?;
        rtype.compose(composer.as_mut())?;
        class.compose(composer.as_mut())?;
        composer.as_mut().compose_u32(ttl)?;
        let len_pos = composer.as_mut().pos();
        composer.as_mut().compose_u16(0)?;
        Ok(RecordBuilder { composer, len_pos })
    }

    pub fn finish(mut self) -> ComposeResult<C> {
        let delta = self.composer.as_mut().delta(self.len_pos) - 2;
        if delta > (::std::u16::MAX as usize) {
            return Err(ComposeError::Overflow)
        }
        self.composer.as_mut().update_u16(self.len_pos, delta as u16);
        Ok(self.composer)
    }
}

impl<C: AsMut<Composer>> AsMut<Composer> for RecordBuilder<C> {
    fn as_mut(&mut self) -> &mut Composer {
        self.composer.as_mut()
    }
}