Tests for the message Header

This commit is contained in:
Benjamin Fry 2015-08-14 16:28:01 -07:00
parent 7dc08e7664
commit 2d2822edc6
6 changed files with 256 additions and 188 deletions

View File

@ -199,4 +199,3 @@
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.

View File

@ -1,2 +1,36 @@
# trust-dns
A Rust based DNS server
A Rust based DNS server
# Goals
- Build a safe and secure DNS server and client with modern features.
- Use Threads to allow all code to panic! and fail fast, without taking down
the server.
- Protect against DDOS attacks (to a degree)
- Support options for Global Load Balancer functions
- Build in a nice REST interface for managing server?
# Status:
Under active development! Do not attempt to use in any production systems.
# In progress:
- Support original (minus unused) RFC 1035 specification.
All parsers complete.
Todo: Serializers.
Todo: Operations.
- Support DNS Update RFC 2136.
- DNSSEC Resource Records RFC 4034
- DNSSec protocol RFC 4035
- Dynamic DNS Update Leases https://tools.ietf.org/html/draft-sekar-dns-ul-01
- DNS Long-Lived Queries http://tools.ietf.org/html/draft-sekar-dns-llq-01
# FAQ
- Why are you building another DNS server?
Because I've gotten tired of seeing the security advisories out there for BIND.
Using Rust semantics it should be possible to develop a high performance and
safe DNS Server that is more resilient to attacks.

View File

@ -2,83 +2,86 @@ use super::op_code::OpCode;
use super::response_code::ResponseCode;
use super::super::rr::util;
/// RFC 1035 Domain Implementation and Specification November 1987
///
/// 4.1.1. Header section format
///
/// The header contains the following fields:
///
/// 1 1 1 1 1 1
/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
/// | ID |
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
/// |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
/// | QDCOUNT |
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
/// | ANCOUNT |
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
/// | NSCOUNT |
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
/// | ARCOUNT |
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
///
/// where:
///
/// ID A 16 bit identifier assigned by the program that
/// generates any kind of query. This identifier is copied
/// the corresponding reply and can be used by the requester
/// to match up replies to outstanding queries.
///
/// QR A one bit field that specifies whether this message is a
/// query (0), or a response (1).
///
/// OPCODE A four bit field that specifies kind of query in this
/// message. This value is set by the originator of a query
/// and copied into the response. The values are: <see super::op_code>
///
/// AA Authoritative Answer - this bit is valid in responses,
/// and specifies that the responding name server is an
/// authority for the domain name in question section.
///
/// Note that the contents of the answer section may have
/// multiple owner names because of aliases. The AA bit
/// corresponds to the name which matches the query name, or
/// the first owner name in the answer section.
///
/// TC TrunCation - specifies that this message was truncated
/// due to length greater than that permitted on the
/// transmission channel.
///
/// RD Recursion Desired - this bit may be set in a query and
/// is copied into the response. If RD is set, it directs
/// the name server to pursue the query recursively.
/// Recursive query support is optional.
///
/// RA Recursion Available - this be is set or cleared in a
/// response, and denotes whether recursive query support is
/// available in the name server.
///
/// Z Reserved for future use. Must be zero in all queries
/// and responses.
///
/// RCODE Response code - this 4 bit field is set as part of
/// responses. The values have the following
/// interpretation: <see super::response_code>
///
/// QDCOUNT an unsigned 16 bit integer specifying the number of
/// entries in the question section.
///
/// ANCOUNT an unsigned 16 bit integer specifying the number of
/// resource records in the answer section.
///
/// NSCOUNT an unsigned 16 bit integer specifying the number of name
/// server resource records in the authority records
/// section.
///
/// ARCOUNT an unsigned 16 bit integer specifying the number of
/// resource records in the additional records section.
/*
* RFC 1035 Domain Implementation and Specification November 1987
*
* 4.1.1. Header section format
*
* The header contains the following fields
*
* 1 1 1 1 1 1
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | ID |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | QDCOUNT |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | ANCOUNT |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | NSCOUNT |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | ARCOUNT |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
*
* where
*
* ID A 16 bit identifier assigned by the program that
* generates any kind of query. This identifier is copied
* the corresponding reply and can be used by the requester
* to match up replies to outstanding queries.
*
* QR A one bit field that specifies whether this message is a
* query (0), or a response (1).
*
* OPCODE A four bit field that specifies kind of query in this
* message. This value is set by the originator of a query
* and copied into the response. The values are: <see super::op_code>
*
* AA Authoritative Answer - this bit is valid in responses,
* and specifies that the responding name server is an
* authority for the domain name in question section.
*
* Note that the contents of the answer section may have
* multiple owner names because of aliases. The AA bit
* corresponds to the name which matches the query name, or
* the first owner name in the answer section.
*
* TC TrunCation - specifies that this message was truncated
* due to length greater than that permitted on the
* transmission channel.
*
* RD Recursion Desired - this bit may be set in a query and
* is copied into the response. If RD is set, it directs
* the name server to pursue the query recursively.
* Recursive query support is optional.
*
* RA Recursion Available - this be is set or cleared in a
* response, and denotes whether recursive query support is
* available in the name server.
*
* Z Reserved for future use. Must be zero in all queries
* and responses.
*
* RCODE Response code - this 4 bit field is set as part of
* responses. The values have the following
* interpretation: <see super::response_code>
*
* QDCOUNT an unsigned 16 bit integer specifying the number of
* entries in the question section.
*
* ANCOUNT an unsigned 16 bit integer specifying the number of
* resource records in the answer section.
*
* NSCOUNT an unsigned 16 bit integer specifying the number of name
* server resource records in the authority records
* section.
*
* ARCOUNT an unsigned 16 bit integer specifying the number of
* resource records in the additional records section.
*/
#[derive(Debug, PartialEq, PartialOrd)]
pub struct Header {
id: u16, message_type: MessageType, op_code: OpCode,
authoritative: bool, truncation: bool, recursion_desired: bool, recursion_available: bool,
@ -86,6 +89,7 @@ pub struct Header {
question_count: u16, answer_count: u16, name_server_count: u16, additional_count: u16
}
#[derive(Debug, PartialEq, PartialOrd)]
enum MessageType {
Query, Response
}
@ -94,7 +98,7 @@ impl Header {
pub fn parse(data: &mut Vec<u8>) -> Self {
let id = util::parse_u16(data);
let q_opcd_a_t_r = data.pop().unwrap_or(0);
let q_opcd_a_t_r = data.pop().unwrap(); // fail fast...
// if the first bit is set
let message_type = if ((0x80 & q_opcd_a_t_r) == 0x80) { MessageType::Response } else { MessageType::Query };
// the 4bit opcode, masked and then shifted right 3bits for the u8...
@ -103,7 +107,7 @@ impl Header {
let truncation = (0x2 & q_opcd_a_t_r) == 0x2;
let recursion_desired = (0x1 & q_opcd_a_t_r) == 0x1;
let r_zzz_rcod = data.pop().unwrap_or(0);
let r_zzz_rcod = data.pop().unwrap(); // fail fast...
let recursion_available = (0x80 & r_zzz_rcod) == 0x80;
// TODO the > 16 codes in ResponseCode come from somewhere, (zzz?) need to better understand RFC
let response_code: ResponseCode = (0x7 & r_zzz_rcod).into();
@ -119,3 +123,24 @@ impl Header {
name_server_count: name_server_count, additional_count: additional_count }
}
}
#[test]
fn test_parse() {
let mut data: Vec<u8> = vec![0x01, 0x10,
0xAA, 0x83, // 0b1010 1010 1000 0011
0x88, 0x77,
0x66, 0x55,
0x44, 0x33,
0x22, 0x11];
data.reverse();
let expect = Header { id: 0x0110, message_type: MessageType::Response, op_code: OpCode::Update,
authoritative: false, truncation: true, recursion_desired: false,
recursion_available: true, response_code: ResponseCode::NXDomain,
question_count: 0x8877, answer_count: 0x6655, name_server_count: 0x4433, additional_count: 0x2211};
let got = Header::parse(&mut data);
assert_eq!(got, expect);
}

View File

@ -1,40 +1,42 @@
use super::header::Header;
/// RFC 1035 Domain Implementation and Specification November 1987
///
/// 4.1. Format
///
/// All communications inside of the domain protocol are carried in a single
/// format called a message. The top level format of message is divided
/// into 5 sections (some of which are empty in certain cases) shown below:
///
/// +---------------------+
/// | Header |
/// +---------------------+
/// | Question | the question for the name server
/// +---------------------+
/// | Answer | RRs answering the question
/// +---------------------+
/// | Authority | RRs pointing toward an authority
/// +---------------------+
/// | Additional | RRs holding additional information
/// +---------------------+
///
/// The header section is always present. The header includes fields that
/// specify which of the remaining sections are present, and also specify
/// whether the message is a query or a response, a standard query or some
/// other opcode, etc.
///
/// The names of the sections after the header are derived from their use in
/// standard queries. The question section contains fields that describe a
/// question to a name server. These fields are a query type (QTYPE), a
/// query class (QCLASS), and a query domain name (QNAME). The last three
/// sections have the same format: a possibly empty list of concatenated
/// resource records (RRs). The answer section contains RRs that answer the
/// question; the authority section contains RRs that point toward an
/// authoritative name server; the additional records section contains RRs
/// which relate to the query, but are not strictly answers for the
/// question.
/*
* RFC 1035 Domain Implementation and Specification November 1987
*
* 4.1. Format
*
* All communications inside of the domain protocol are carried in a single
* format called a message. The top level format of message is divided
* into 5 sections (some of which are empty in certain cases) shown below:
*
* +---------------------+
* | Header |
* +---------------------+
* | Question | the question for the name server
* +---------------------+
* | Answer | RRs answering the question
* +---------------------+
* | Authority | RRs pointing toward an authority
* +---------------------+
* | Additional | RRs holding additional information
* +---------------------+
*
* The header section is always present. The header includes fields that
* specify which of the remaining sections are present, and also specify
* whether the message is a query or a response, a standard query or some
* other opcode, etc.
*
* The names of the sections after the header are derived from their use in
* standard queries. The question section contains fields that describe a
* question to a name server. These fields are a query type (QTYPE), a
* query class (QCLASS), and a query domain name (QNAME). The last three
* sections have the same format: a possibly empty list of concatenated
* resource records (RRs). The answer section contains RRs that answer the
* question; the authority section contains RRs that point toward an
* authoritative name server; the additional records section contains RRs
* which relate to the query, but are not strictly answers for the
* question.
*/
pub struct Message {
header: Header, /*question: Question, answer: Answer, authority: domain::Name, additional: Additional*/
}

View File

@ -1,18 +1,20 @@
use std::convert::From;
/// RFC 1035 Domain Implementation and Specification November 1987
///
/// OPCODE A four bit field that specifies kind of query in this
/// message. This value is set by the originator of a query
/// and copied into the response. The values are:
///
/// 0 a standard query (QUERY)
///
/// 1 an inverse query (IQUERY)
///
/// 2 a server status request (STATUS)
///
/// 3-15 reserved for future use
/*
* RFC 1035 Domain Implementation and Specification November 1987
*
* OPCODE A four bit field that specifies kind of query in this
* message. This value is set by the originator of a query
* and copied into the response. The values are:
*
* 0 a standard query (QUERY)
*
* 1 an inverse query (IQUERY)
*
* 2 a server status request (STATUS)
*
* 3-15 reserved for future use
*/
#[derive(Debug, PartialEq, PartialOrd)]
#[allow(dead_code)]
pub enum OpCode {

View File

@ -1,38 +1,40 @@
/// RFC 1035 Domain Implementation and Specification November 1987
///
/// RCODE Response code - this 4 bit field is set as part of
/// responses. The values have the following
/// interpretation:
///
/// 0 No error condition
///
/// 1 Format error - The name server was
/// unable to interpret the query.
///
/// 2 Server failure - The name server was
/// unable to process this query due to a
/// problem with the name server.
///
/// 3 Name Error - Meaningful only for
/// responses from an authoritative name
/// server, this code signifies that the
/// domain name referenced in the query does
/// not exist.
///
/// 4 Not Implemented - The name server does
/// not support the requested kind of query.
///
/// 5 Refused - The name server refuses to
/// perform the specified operation for
/// policy reasons. For example, a name
/// server may not wish to provide the
/// information to the particular requester,
/// or a name server may not wish to perform
/// a particular operation (e.g., zone
///
/// transfer) for particular data.
///
/// 6-15 Reserved for future use.
/*
* RFC 1035 Domain Implementation and Specification November 1987
*
* RCODE Response code - this 4 bit field is set as part of
* responses. The values have the following
* interpretation:
*
* 0 No error condition
*
* 1 Format error - The name server was
* unable to interpret the query.
*
* 2 Server failure - The name server was
* unable to process this query due to a
* problem with the name server.
*
* 3 Name Error - Meaningful only for
* responses from an authoritative name
* server, this code signifies that the
* domain name referenced in the query does
* not exist.
*
* 4 Not Implemented - The name server does
* not support the requested kind of query.
*
* 5 Refused - The name server refuses to
* perform the specified operation for
* policy reasons. For example, a name
* server may not wish to provide the
* information to the particular requester,
* or a name server may not wish to perform
* a particular operation (e.g., zone
*
* transfer) for particular data.
*
* 6-15 Reserved for future use.
*/
#[derive(Debug, PartialEq, PartialOrd)]
#[allow(dead_code)]
pub enum ResponseCode {
@ -64,18 +66,20 @@ pub enum ResponseCode {
// 65535 Reserved, can be allocated by Standards Action [RFC6895]
}
/// Convert from ResponseCode to u8
///
/// ```
/// use std::convert::From;
/// use trust_dns::op::result_code::ResponseCode;
///
/// let var: ResponseCode = From::from(0);
/// assert_eq!(ResponseCode::NoError, var);
///
/// let var: ResponseCode = 0.into();
/// assert_eq!(ResponseCode::NoError, var);
/// ```
/**
* Convert from ResponseCode to u8
*
* ```
* use std::convert::From;
* use trust_dns::op::response_code::ResponseCode;
*
* let var: ResponseCode = From::from(0);
* assert_eq!(ResponseCode::NoError, var);
*
* let var: ResponseCode = 0.into();
* assert_eq!(ResponseCode::NoError, var);
* ```
*/
impl From<ResponseCode> for u8 {
fn from(rt: ResponseCode) -> Self {
match rt {
@ -103,18 +107,20 @@ impl From<ResponseCode> for u8 {
}
}
/// Convert from u8 to ResponseCode
///
/// ```
/// use std::convert::From;
/// use trust_dns::op::result_code::ResponseCode;
///
/// let var: u8 = From::from(ResponseCode::NoError);
/// assert_eq!(0, var);
///
/// let var: u8 = ResponseCode::NoError.into();
/// assert_eq!(0, var);
/// ```
/**
* Convert from u8 to ResponseCode
*
* ```
* use std::convert::From;
* use trust_dns::op::response_code::ResponseCode;
*
* let var: u8 = From::from(ResponseCode::NoError);
* assert_eq!(0, var);
*
* let var: u8 = ResponseCode::NoError.into();
* assert_eq!(0, var);
* ```
*/
impl From<u8> for ResponseCode {
fn from(value: u8) -> Self {
match value {