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
/*
 * Copyright (C) 2015 Benjamin Fry <benjaminfry@me.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//! Query struct for looking up resource records

use ::rr::domain::Name;
use ::rr::record_type::RecordType;
use ::rr::dns_class::DNSClass;
use ::serialize::binary::*;
use ::error::*;

/// Query struct for looking up resource records, basically a resource record without RDATA.
///
/// [RFC 1035, DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION, November 1987](https://tools.ietf.org/html/rfc1035)
///
/// ```text
/// 4.1.2. Question section format
///
/// The question section is used to carry the "question" in most queries,
/// i.e., the parameters that define what is being asked.  The section
/// contains QDCOUNT (usually 1) entries, each of the following format:
///
///                                     1  1  1  1  1  1
///       0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
///     |                                               |
///     /                     QNAME / ZNAME             /
///     /                                               /
///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
///     |                     QTYPE / ZTYPE             |
///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
///     |                     QCLASS / ZCLASS           |
///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
///
/// ```
#[derive(PartialEq, Debug)]
pub struct Query {
  name: Name, query_type: RecordType, query_class: DNSClass
}

impl Query {
  /// return a default query with an empty name and A, IN for the query_type and query_class
  pub fn new() -> Self {
    Query { name: Name::new(), query_type: RecordType::A, query_class: DNSClass::IN }
  }

  /// replaces name with the new name
  pub fn name(&mut self, name: Name) -> &mut Self { self.name = name; self }
  pub fn query_type(&mut self, query_type: RecordType) -> &mut Self { self.query_type = query_type; self }
  pub fn query_class(&mut self, query_class: DNSClass) -> &mut Self { self.query_class = query_class; self }

  /// ```text
  /// QNAME           a domain name represented as a sequence of labels, where
  ///                 each label consists of a length octet followed by that
  ///                 number of octets.  The domain name terminates with the
  ///                 zero length octet for the null label of the root.  Note
  ///                 that this field may be an odd number of octets; no
  ///                 padding is used.
  /// ```
  pub fn get_name(&self) -> &Name { &self.name }

  /// ```text
  /// QTYPE           a two octet code which specifies the type of the query.
  ///                 The values for this field include all codes valid for a
  ///                 TYPE field, together with some more general codes which
  ///                 can match more than one type of RR.
  /// ```
  pub fn get_query_type(&self) -> RecordType { self.query_type }

  /// ```text
  /// QCLASS          a two octet code that specifies the class of the query.
  ///                 For example, the QCLASS field is IN for the Internet.
  /// ```
  pub fn get_query_class(&self) -> DNSClass { self.query_class }

}

impl BinSerializable<Query> for Query {
  fn read(decoder: &mut BinDecoder) -> DecodeResult<Self> {
    let name = try!(Name::read(decoder));
    let query_type = try!(RecordType::read(decoder));
    let query_class = try!(DNSClass::read(decoder));

    Ok(Query { name: name, query_type: query_type, query_class: query_class})
  }

  fn emit(&self, encoder: &mut BinEncoder) -> EncodeResult {
    try!(self.name.emit(encoder));
    try!(self.query_type.emit(encoder));
    try!(self.query_class.emit(encoder));

    Ok(())
  }
}

#[test]
fn test_read_and_emit() {
  let expect = Query { name: Name::with_labels(vec!["www".to_string(),"example".to_string(),"com".to_string()]),
                       query_type: RecordType::AAAA, query_class: DNSClass::IN };

  let mut byte_vec: Vec<u8> = Vec::with_capacity(512);
  {
    let mut encoder = BinEncoder::new(&mut byte_vec);
    expect.emit(&mut encoder).unwrap();
  }

  let mut decoder = BinDecoder::new(&byte_vec);
  let got = Query::read(&mut decoder).unwrap();
  assert_eq!(got, expect);
}