Tests for the message Header
This commit is contained in:
parent
7dc08e7664
commit
2d2822edc6
1
LICENSE
1
LICENSE
@ -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.
|
||||
|
||||
|
36
README.md
36
README.md
@ -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.
|
||||
|
183
src/op/header.rs
183
src/op/header.rs
@ -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);
|
||||
}
|
||||
|
@ -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*/
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user