Header parsing complete, tests still needed

This commit is contained in:
Benjamin Fry 2015-08-14 00:51:58 -07:00
parent 49cd2d6730
commit 7dc08e7664
7 changed files with 323 additions and 112 deletions

121
src/op/header.rs Normal file
View File

@ -0,0 +1,121 @@
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.
pub struct Header {
id: u16, message_type: MessageType, op_code: OpCode,
authoritative: bool, truncation: bool, recursion_desired: bool, recursion_available: bool,
response_code: ResponseCode,
question_count: u16, answer_count: u16, name_server_count: u16, additional_count: u16
}
enum MessageType {
Query, Response
}
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);
// 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...
let op_code: OpCode = ((0x78 & q_opcd_a_t_r) >> 3).into();
let authoritative = (0x4 & q_opcd_a_t_r) == 0x4;
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 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();
let question_count = util::parse_u16(data);
let answer_count = util::parse_u16(data);
let name_server_count = util::parse_u16(data);
let additional_count = util::parse_u16(data);
Header { id: id, message_type: message_type, op_code: op_code, authoritative: authoritative,
truncation: truncation, recursion_desired: recursion_desired,
recursion_available: recursion_available, response_code: response_code,
question_count: question_count, answer_count: answer_count,
name_server_count: name_server_count, additional_count: additional_count }
}
}

40
src/op/message.rs Normal file
View File

@ -0,0 +1,40 @@
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.
pub struct Message {
header: Header, /*question: Question, answer: Answer, authority: domain::Name, additional: Additional*/
}

View File

@ -1,2 +1,4 @@
pub mod op_code;
pub mod result_code;
pub mod response_code;
pub mod message;
pub mod header;

View File

@ -1,5 +1,18 @@
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
#[derive(Debug, PartialEq, PartialOrd)]
#[allow(dead_code)]
pub enum OpCode {

145
src/op/response_code.rs Normal file
View File

@ -0,0 +1,145 @@
/// 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 {
NoError, // 0 NoError No Error [RFC1035]
FormErr, // 1 FormErr Format Error [RFC1035]
ServFail, // 2 ServFail Server Failure [RFC1035]
NXDomain, // 3 NXDomain Non-Existent Domain [RFC1035]
NotImp, // 4 NotImp Not Implemented [RFC1035]
Refused, // 5 Refused Query Refused [RFC1035]
YXDomain, // 6 YXDomain Name Exists when it should not [RFC2136][RFC6672]
YXRRSet, // 7 YXRRSet RR Set Exists when it should not [RFC2136]
NXRRSet, // 8 NXRRSet RR Set that should exist does not [RFC2136]
NotAuth, // 9 NotAuth Server Not Authoritative for zone [RFC2136]
// 9 NotAuth Not Authorized [RFC2845]
NotZone, // 10 NotZone Name not contained in zone [RFC2136]
// 11-15 Unassigned
BADVERS, // 16 BADVERS Bad OPT Version [RFC6891]
BADSIG, // 16 BADSIG TSIG Signature Failure [RFC2845]
BADKEY, // 17 BADKEY Key not recognized [RFC2845]
BADTIME, // 18 BADTIME Signature out of time window [RFC2845]
BADMODE, // 19 BADMODE Bad TKEY Mode [RFC2930]
BADNAME, // 20 BADNAME Duplicate key name [RFC2930]
BADALG, // 21 BADALG Algorithm not supported [RFC2930]
BADTRUNC, // 22 BADTRUNC Bad Truncation [RFC4635]
BADCOOKIE, // 23 BADCOOKIE (TEMPORARY - registered 2015-07-26, expires 2016-07-26) Bad/missing server cookie [draft-ietf-dnsop-cookies]
// 24-3840 Unassigned
// 3841-4095 Reserved for Private Use [RFC6895]
// 4096-65534 Unassigned
// 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);
/// ```
impl From<ResponseCode> for u8 {
fn from(rt: ResponseCode) -> Self {
match rt {
ResponseCode::NoError => 0, // 0 NoError No Error [RFC1035]
ResponseCode::FormErr => 1, // 1 FormErr Format Error [RFC1035]
ResponseCode::ServFail => 2, // 2 ServFail Server Failure [RFC1035]
ResponseCode::NXDomain => 3, // 3 NXDomain Non-Existent Domain [RFC1035]
ResponseCode::NotImp => 4, // 4 NotImp Not Implemented [RFC1035]
ResponseCode::Refused => 5, // 5 Refused Query Refused [RFC1035]
ResponseCode::YXDomain => 6, // 6 YXDomain Name Exists when it should not [RFC2136][RFC6672]
ResponseCode::YXRRSet => 7, // 7 YXRRSet RR Set Exists when it should not [RFC2136]
ResponseCode::NXRRSet => 8, // 8 NXRRSet RR Set that should exist does not [RFC2136]
ResponseCode::NotAuth => 9, // 9 NotAuth Server Not Authoritative for zone [RFC2136]
ResponseCode::NotZone => 10, // 10 NotZone Name not contained in zone [RFC2136]
ResponseCode::BADVERS => 16, // 16 BADVERS Bad OPT Version [RFC6891]
ResponseCode::BADSIG => 16, // 16 BADSIG TSIG Signature Failure [RFC2845]
ResponseCode::BADKEY => 17, // 17 BADKEY Key not recognized [RFC2845]
ResponseCode::BADTIME => 18, // 18 BADTIME Signature out of time window [RFC2845]
ResponseCode::BADMODE => 19, // 19 BADMODE Bad TKEY Mode [RFC2930]
ResponseCode::BADNAME => 20, // 20 BADNAME Duplicate key name [RFC2930]
ResponseCode::BADALG => 21, // 21 BADALG Algorithm not supported [RFC2930]
ResponseCode::BADTRUNC => 22, // 22 BADTRUNC Bad Truncation [RFC4635]
ResponseCode::BADCOOKIE => 23, // 23 BADCOOKIE (TEMPORARY - registered 2015-07-26, expires 2016-07-26) Bad/missing server cookie [draft-ietf-dnsop-cookies]
}
}
}
/// 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);
/// ```
impl From<u8> for ResponseCode {
fn from(value: u8) -> Self {
match value {
0 => ResponseCode::NoError, // 0 NoError No Error [RFC1035]
1 => ResponseCode::FormErr, // 1 FormErr Format Error [RFC1035]
2 => ResponseCode::ServFail, // 2 ServFail Server Failure [RFC1035]
3 => ResponseCode::NXDomain, // 3 NXDomain Non-Existent Domain [RFC1035]
4 => ResponseCode::NotImp, // 4 NotImp Not Implemented [RFC1035]
5 => ResponseCode::Refused, // 5 Refused Query Refused [RFC1035]
6 => ResponseCode::YXDomain, // 6 YXDomain Name Exists when it should not [RFC2136][RFC6672]
7 => ResponseCode::YXRRSet, // 7 YXRRSet RR Set Exists when it should not [RFC2136]
8 => ResponseCode::NXRRSet, // 8 NXRRSet RR Set that should exist does not [RFC2136]
9 => ResponseCode::NotAuth, // 9 NotAuth Server Not Authoritative for zone [RFC2136]
10 => ResponseCode::NotZone, // 10 NotZone Name not contained in zone [RFC2136]
// this looks to be backwards compat for 4 bit ResponseCodes.
//16 => ResponseCode::BADVERS, // 16 BADVERS Bad OPT Version [RFC6891]
16 => ResponseCode::BADSIG, // 16 BADSIG TSIG Signature Failure [RFC2845]
17 => ResponseCode::BADKEY, // 17 BADKEY Key not recognized [RFC2845]
18 => ResponseCode::BADTIME, // 18 BADTIME Signature out of time window [RFC2845]
19 => ResponseCode::BADMODE, // 19 BADMODE Bad TKEY Mode [RFC2930]
20 => ResponseCode::BADNAME, // 20 BADNAME Duplicate key name [RFC2930]
21 => ResponseCode::BADALG, // 21 BADALG Algorithm not supported [RFC2930]
22 => ResponseCode::BADTRUNC, // 22 BADTRUNC Bad Truncation [RFC4635]
23 => ResponseCode::BADCOOKIE, // 23 BADCOOKIE (TEMPORARY - registered 2015-07-26, expires 2016-07-26) Bad/missing server cookie [draft-ietf-dnsop-cookies]
_ => unimplemented!(),
}
}
}

View File

@ -1,110 +0,0 @@
#[derive(Debug, PartialEq, PartialOrd)]
#[allow(dead_code)]
pub enum ResultCode {
NoError, // 0 NoError No Error [RFC1035]
FormErr, // 1 FormErr Format Error [RFC1035]
ServFail, // 2 ServFail Server Failure [RFC1035]
NXDomain, // 3 NXDomain Non-Existent Domain [RFC1035]
NotImp, // 4 NotImp Not Implemented [RFC1035]
Refused, // 5 Refused Query Refused [RFC1035]
YXDomain, // 6 YXDomain Name Exists when it should not [RFC2136][RFC6672]
YXRRSet, // 7 YXRRSet RR Set Exists when it should not [RFC2136]
NXRRSet, // 8 NXRRSet RR Set that should exist does not [RFC2136]
NotAuth, // 9 NotAuth Server Not Authoritative for zone [RFC2136]
// 9 NotAuth Not Authorized [RFC2845]
NotZone, // 10 NotZone Name not contained in zone [RFC2136]
// 11-15 Unassigned
BADVERS, // 16 BADVERS Bad OPT Version [RFC6891]
BADSIG, // 16 BADSIG TSIG Signature Failure [RFC2845]
BADKEY, // 17 BADKEY Key not recognized [RFC2845]
BADTIME, // 18 BADTIME Signature out of time window [RFC2845]
BADMODE, // 19 BADMODE Bad TKEY Mode [RFC2930]
BADNAME, // 20 BADNAME Duplicate key name [RFC2930]
BADALG, // 21 BADALG Algorithm not supported [RFC2930]
BADTRUNC, // 22 BADTRUNC Bad Truncation [RFC4635]
BADCOOKIE, // 23 BADCOOKIE (TEMPORARY - registered 2015-07-26, expires 2016-07-26) Bad/missing server cookie [draft-ietf-dnsop-cookies]
// 24-3840 Unassigned
// 3841-4095 Reserved for Private Use [RFC6895]
// 4096-65534 Unassigned
// 65535 Reserved, can be allocated by Standards Action [RFC6895]
}
/// Convert from ResultCode to u8
///
/// ```
/// use std::convert::From;
/// use trust_dns::op::result_code::ResultCode;
///
/// let var: ResultCode = From::from(0);
/// assert_eq!(ResultCode::NoError, var);
///
/// let var: ResultCode = 0.into();
/// assert_eq!(ResultCode::NoError, var);
/// ```
impl From<ResultCode> for u8 {
fn from(rt: ResultCode) -> Self {
match rt {
ResultCode::NoError => 0, // 0 NoError No Error [RFC1035]
ResultCode::FormErr => 1, // 1 FormErr Format Error [RFC1035]
ResultCode::ServFail => 2, // 2 ServFail Server Failure [RFC1035]
ResultCode::NXDomain => 3, // 3 NXDomain Non-Existent Domain [RFC1035]
ResultCode::NotImp => 4, // 4 NotImp Not Implemented [RFC1035]
ResultCode::Refused => 5, // 5 Refused Query Refused [RFC1035]
ResultCode::YXDomain => 6, // 6 YXDomain Name Exists when it should not [RFC2136][RFC6672]
ResultCode::YXRRSet => 7, // 7 YXRRSet RR Set Exists when it should not [RFC2136]
ResultCode::NXRRSet => 8, // 8 NXRRSet RR Set that should exist does not [RFC2136]
ResultCode::NotAuth => 9, // 9 NotAuth Server Not Authoritative for zone [RFC2136]
ResultCode::NotZone => 10, // 10 NotZone Name not contained in zone [RFC2136]
ResultCode::BADVERS => 16, // 16 BADVERS Bad OPT Version [RFC6891]
ResultCode::BADSIG => 16, // 16 BADSIG TSIG Signature Failure [RFC2845]
ResultCode::BADKEY => 17, // 17 BADKEY Key not recognized [RFC2845]
ResultCode::BADTIME => 18, // 18 BADTIME Signature out of time window [RFC2845]
ResultCode::BADMODE => 19, // 19 BADMODE Bad TKEY Mode [RFC2930]
ResultCode::BADNAME => 20, // 20 BADNAME Duplicate key name [RFC2930]
ResultCode::BADALG => 21, // 21 BADALG Algorithm not supported [RFC2930]
ResultCode::BADTRUNC => 22, // 22 BADTRUNC Bad Truncation [RFC4635]
ResultCode::BADCOOKIE => 23, // 23 BADCOOKIE (TEMPORARY - registered 2015-07-26, expires 2016-07-26) Bad/missing server cookie [draft-ietf-dnsop-cookies]
}
}
}
/// Convert from u8 to ResultCode
///
/// ```
/// use std::convert::From;
/// use trust_dns::op::result_code::ResultCode;
///
/// let var: u8 = From::from(ResultCode::NoError);
/// assert_eq!(0, var);
///
/// let var: u8 = ResultCode::NoError.into();
/// assert_eq!(0, var);
/// ```
impl From<u8> for ResultCode {
fn from(value: u8) -> Self {
match value {
0 => ResultCode::NoError, // 0 NoError No Error [RFC1035]
1 => ResultCode::FormErr, // 1 FormErr Format Error [RFC1035]
2 => ResultCode::ServFail, // 2 ServFail Server Failure [RFC1035]
3 => ResultCode::NXDomain, // 3 NXDomain Non-Existent Domain [RFC1035]
4 => ResultCode::NotImp, // 4 NotImp Not Implemented [RFC1035]
5 => ResultCode::Refused, // 5 Refused Query Refused [RFC1035]
6 => ResultCode::YXDomain, // 6 YXDomain Name Exists when it should not [RFC2136][RFC6672]
7 => ResultCode::YXRRSet, // 7 YXRRSet RR Set Exists when it should not [RFC2136]
8 => ResultCode::NXRRSet, // 8 NXRRSet RR Set that should exist does not [RFC2136]
9 => ResultCode::NotAuth, // 9 NotAuth Server Not Authoritative for zone [RFC2136]
10 => ResultCode::NotZone, // 10 NotZone Name not contained in zone [RFC2136]
// this looks to be backwards compat for 4 bit ResultCodes.
//16 => ResultCode::BADVERS, // 16 BADVERS Bad OPT Version [RFC6891]
16 => ResultCode::BADSIG, // 16 BADSIG TSIG Signature Failure [RFC2845]
17 => ResultCode::BADKEY, // 17 BADKEY Key not recognized [RFC2845]
18 => ResultCode::BADTIME, // 18 BADTIME Signature out of time window [RFC2845]
19 => ResultCode::BADMODE, // 19 BADMODE Bad TKEY Mode [RFC2930]
20 => ResultCode::BADNAME, // 20 BADNAME Duplicate key name [RFC2930]
21 => ResultCode::BADALG, // 21 BADALG Algorithm not supported [RFC2930]
22 => ResultCode::BADTRUNC, // 22 BADTRUNC Bad Truncation [RFC4635]
23 => ResultCode::BADCOOKIE, // 23 BADCOOKIE (TEMPORARY - registered 2015-07-26, expires 2016-07-26) Bad/missing server cookie [draft-ietf-dnsop-cookies]
_ => unimplemented!(),
}
}
}

View File

@ -5,4 +5,4 @@ pub mod record_data;
pub mod domain;
mod rdata;
mod util;
pub mod util;