Beginings of the RR parser, not compiling

This commit is contained in:
Benjamin Fry 2015-08-10 08:24:50 -07:00
parent f8f7a96b36
commit 1c86e24806
9 changed files with 380 additions and 123 deletions

View File

@ -1,4 +1,5 @@
pub mod rr;
pub mod op;
#[test]
fn it_works() {

2
src/op/mod.rs Normal file
View File

@ -0,0 +1,2 @@
pub mod op_code;
pub mod result_code;

60
src/op/op_code.rs Normal file
View File

@ -0,0 +1,60 @@
use std::convert::From;
#[derive(Debug, PartialEq, PartialOrd)]
#[allow(dead_code)]
pub enum OpCode {
Query, // 0 Query [RFC1035]
// 1 IQuery (Inverse Query, OBSOLETE) [RFC3425]
Status, // 2 Status [RFC1035]
// 3 Unassigned
Notify, // 4 Notify [RFC1996]
Update, // 5 Update [RFC2136]
// 6-15 Unassigned
}
/// Convert from OpCode to u8
///
/// ```
/// use std::convert::From;
/// use trust_dns::op::op_code::OpCode;
///
/// let var: OpCode = From::from(0);
/// assert_eq!(OpCode::Query, var);
///
/// let var: OpCode = 0.into();
/// assert_eq!(OpCode::Query, var);
/// ```
impl From<OpCode> for u8 {
fn from(rt: OpCode) -> Self {
match rt {
OpCode::Query => 0,
OpCode::Status => 2,
OpCode::Notify => 4,
OpCode::Update => 5,
}
}
}
/// Convert from u8 to OpCode
///
/// ```
/// use std::convert::From;
/// use trust_dns::op::op_code::OpCode;
///
/// let var: u8 = From::from(OpCode::Query);
/// assert_eq!(0, var);
///
/// let var: u8 = OpCode::Query.into();
/// assert_eq!(0, var);
/// ```
impl From<u8> for OpCode {
fn from(value: u8) -> Self {
match value {
0 => OpCode::Query,
2 => OpCode::Status,
4 => OpCode::Notify,
5 => OpCode::Update,
_ => unimplemented!(),
}
}
}

110
src/op/result_code.rs Normal file
View File

@ -0,0 +1,110 @@
#[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

@ -1,114 +0,0 @@
use std::convert::From;
#[derive(Debug, PartialEq, PartialOrd)]
#[allow(dead_code)]
pub enum RecordClass {
IN, // 1 RFC 1035 Internet (IN)
CH, // 3 Chaos (CH)
HS, // 4 Hesiod (HS)
NONE, // 254 QCLASS NONE
ANY, // 255 QCLASS * (ANY)
}
// TODO make these a macro...
/// Convert from RecordClass to &str
///
/// ```
/// use std::convert::From;
/// use trust_dns::rr::record_types::RecordClass;
///
/// let var: &'static str = From::from(RecordClass::IN);
/// assert_eq!("IN", var);
///
/// let var: &'static str = RecordClass::IN.into();
/// assert_eq!("IN", var);
/// ```
impl From<RecordClass> for &'static str {
fn from(rt: RecordClass) -> &'static str {
match rt {
RecordClass::IN => "IN",
RecordClass::CH => "CH",
RecordClass::HS => "HS",
RecordClass::NONE => "NONE",
RecordClass::ANY => "ANY",
_ => unimplemented!(),
}
}
}
/// Convert from RecordClass to &str
///
/// ```
/// use std::convert::From;
/// use trust_dns::rr::record_types::RecordClass;
///
/// let var: RecordClass = From::from("A");
/// assert_eq!(RecordClass::A, var);
///
/// let var: RecordClass = "A".into();
/// assert_eq!(RecordClass::A, var);
/// ```
impl<'a> From<&'a str> for RecordClass {
fn from(str: &'a str) -> Self {
match str {
"IN" => RecordClass::IN,
"CH" => RecordClass::CH,
"HS" => RecordClass::HS,
"NONE" => RecordClass::NONE,
"ANY" => RecordClass::ANY,
"*" => RecordClass::ANY,
_ => unimplemented!(),
}
}
}
/// Convert from RecordClass to &str
///
/// ```
/// use std::convert::From;
/// use trust_dns::rr::record_types::RecordClass;
///
/// let var: RecordClass = From::from(1);
/// assert_eq!(RecordClass::A, var);
///
/// let var: RecordClass = 1.into();
/// assert_eq!(RecordClass::A, var);
/// ```
impl From<RecordClass> for u16 {
fn from(rt: RecordClass) -> Self {
match rt {
RecordClass::IN => 1,
RecordClass::CH => 3,
RecordClass::HS => 4,
RecordClass::NONE => 254,
RecordClass::ANY => 255,
_ => unimplemented!(),
}
}
}
/// Convert from RecordClass to &str
///
/// ```
/// use std::convert::From;
/// use trust_dns::rr::record_types::RecordClass;
///
/// let var: u16 = From::from(RecordClass::A);
/// assert_eq!(1, var);
///
/// let var: u16 = RecordClass::A.into();
/// assert_eq!(1, var);
/// ```
impl From<u16> for RecordClass {
fn from(value: u16) -> Self {
match value {
1 => RecordClass::IN,
3 => RecordClass::CH,
4 => RecordClass::HS,
254 => RecordClass::NONE,
255 => RecordClass::ANY,
_ => unimplemented!(),
}
}
}

112
src/rr/dns_class.rs Normal file
View File

@ -0,0 +1,112 @@
use std::convert::From;
#[derive(Debug, PartialEq, PartialOrd)]
#[allow(dead_code)]
pub enum DNSClass {
IN, // 1 RFC 1035 Internet (IN)
CH, // 3 Chaos (CH)
HS, // 4 Hesiod (HS)
NONE, // 254 QCLASS NONE
ANY, // 255 QCLASS * (ANY)
}
// TODO make these a macro or annotation
/// Convert from DNSClass to &str
///
/// ```
/// use std::convert::From;
/// use trust_dns::rr::dns_class::DNSClass;
///
/// let var: &'static str = From::from(DNSClass::IN);
/// assert_eq!("IN", var);
///
/// let var: &'static str = DNSClass::IN.into();
/// assert_eq!("IN", var);
/// ```
impl From<DNSClass> for &'static str {
fn from(rt: DNSClass) -> &'static str {
match rt {
DNSClass::IN => "IN",
DNSClass::CH => "CH",
DNSClass::HS => "HS",
DNSClass::NONE => "NONE",
DNSClass::ANY => "ANY",
}
}
}
/// Convert from &str to DNSClass
///
/// ```
/// use std::convert::From;
/// use trust_dns::rr::dns_class::DNSClass;
///
/// let var: DNSClass = From::from("IN");
/// assert_eq!(DNSClass::IN, var);
///
/// let var: DNSClass = "IN".into();
/// assert_eq!(DNSClass::IN, var);
/// ```
impl<'a> From<&'a str> for DNSClass {
fn from(str: &'a str) -> Self {
match str {
"IN" => DNSClass::IN,
"CH" => DNSClass::CH,
"HS" => DNSClass::HS,
"NONE" => DNSClass::NONE,
"ANY" => DNSClass::ANY,
"*" => DNSClass::ANY,
_ => unimplemented!(),
}
}
}
/// Convert from DNSClass to u16
///
/// ```
/// use std::convert::From;
/// use trust_dns::rr::dns_class::DNSClass;
///
/// let var: DNSClass = From::from(1);
/// assert_eq!(DNSClass::IN, var);
///
/// let var: DNSClass = 1.into();
/// assert_eq!(DNSClass::IN, var);
/// ```
impl From<DNSClass> for u16 {
fn from(rt: DNSClass) -> Self {
match rt {
DNSClass::IN => 1,
DNSClass::CH => 3,
DNSClass::HS => 4,
DNSClass::NONE => 254,
DNSClass::ANY => 255,
}
}
}
/// Convert from u16 to DNSClass
///
/// ```
/// use std::convert::From;
/// use trust_dns::rr::dns_class::DNSClass;
///
/// let var: u16 = From::from(DNSClass::IN);
/// assert_eq!(1, var);
///
/// let var: u16 = DNSClass::IN.into();
/// assert_eq!(1, var);
/// ```
impl From<u16> for DNSClass {
fn from(value: u16) -> Self {
match value {
1 => DNSClass::IN,
3 => DNSClass::CH,
4 => DNSClass::HS,
254 => DNSClass::NONE,
255 => DNSClass::ANY,
_ => unimplemented!(),
}
}
}

View File

@ -1 +1,3 @@
pub mod type;
pub mod record_type;
pub mod dns_class;
pub mod resource;

View File

@ -54,7 +54,7 @@ pub enum RecordType {
///
/// ```
/// use std::convert::From;
/// use trust_dns::rr::type::RecordType;
/// use trust_dns::rr::record_type::RecordType;
///
/// let var: &'static str = From::from(RecordType::A);
/// assert_eq!("A", var);
@ -80,7 +80,7 @@ impl From<RecordType> for &'static str {
///
/// ```
/// use std::convert::From;
/// use trust_dns::rr::type::RecordType;
/// use trust_dns::rr::record_type::RecordType;
///
/// let var: RecordType = From::from("A");
/// assert_eq!(RecordType::A, var);
@ -106,7 +106,7 @@ impl<'a> From<&'a str> for RecordType {
///
/// ```
/// use std::convert::From;
/// use trust_dns::rr::type::RecordType;
/// use trust_dns::rr::record_type::RecordType;
///
/// let var: RecordType = From::from(1);
/// assert_eq!(RecordType::A, var);
@ -132,7 +132,7 @@ impl From<RecordType> for u16 {
///
/// ```
/// use std::convert::From;
/// use trust_dns::rr::type::RecordType;
/// use trust_dns::rr::record_type::RecordType;
///
/// let var: u16 = From::from(RecordType::A);
/// assert_eq!(1, var);

View File

@ -1,8 +1,19 @@
use super::type::RecordType;
use std::collections::{VecDeque,HashMap};
use std::iter::Take;
use std::slice::Iter;
use super::record_type::RecordType;
use super::dns_class::DNSClass;
// labels 63 octets or less
// names 255 octets or less
// TTL positive values of a signed 32 bit number.
// UDP messages 512 octets or less
pub struct Record {
type: RecordType;
class: ;
rr_type: RecordType,
dns_class: DNSClass,
name_labels: VecDeque<String>,
}
impl Record {
@ -10,10 +21,83 @@ impl Record {
/// parse a resource record line example:
///
///
fn parse(String line) -> Record {
//fn parse(line: &str) -> Record {
// tokenize the string
//let mut tokens = line.words();
//}
/// parses the chain of labels
/// this has a max of 255 octets, with each label being less than 63.
/// all names will be stored lowercase internally.
fn parse_labels(slice: &[u8]) -> VecDeque<String> {
let mut state: LabelParseState = LabelParseState::LabelLengthOrPointer;
let mut labels: VecDeque<String>;
// let mut label_map: HashMap<u8, usize>; // temporary map for pointers, offset in slice, start location in labels
// get the iterator for the slice, we'll use this for getting all the data
let iter: Iter<_> = slice.iter();
// assume all chars are utf-8. We're doing byte-by-byte operations, no endianess issues...
// reserved: (1000 0000 aka 0800) && (0100 0000 aka 0400)
// pointer: (slice == 1100 0000 aka C0) & C0 == true, then 03FF & slice = offset
// label: 03FF & slice = length; slice.next(length) = label
// root: 0000
loop {
state = match state {
LabelParseState::LabelLengthOrPointer => {
let byte: u8 = *iter.take(1).next().unwrap(); // could default to zero, but it's an error if this doesn't exist, perhaps try! instead
//
match byte {
0 => LabelParseState::Root,
byte if byte & 0xC0 == 0xC0 => LabelParseState::Pointer(byte & 0x3F),
byte if byte <= 0x3F => LabelParseState::Label(byte),
_ => unimplemented!(),
}
},
LabelParseState::Label(count) => {
let label_iter: Take<Iter<u8>> = iter.take(count as usize);
let arr: Vec<u8> = label_iter.collect();
// using lossy, this is safe, but can end up with junk in the name...
// TODO other option
let label = try!(String::from_utf8(arr));
labels.push_back(label);
// reset to collect more data
LabelParseState::LabelLengthOrPointer()
},
LabelParseState::Pointer(offset) => {
// lookup in the hashmap the label to use
unimplemented!()
},
LabelParseState::Root => {
// technically could return here...
break;
}
}
}
return labels;
}
}
/// This is the list of states for the state machine
enum LabelParseState {
LabelLengthOrPointer, // basically the start of the FSM
Label(u8), // storing length of the label, must be < 63
Pointer(u8), // location of pointer in slice,
Root, // root is the end of the labels list, aka null
}
impl LabelParseState {
fn take_count(&self) -> u8 {
match *self {
LabelParseState::LabelLengthOrPointer => 1,
LabelParseState::Label => *self, // unwrap the enum, this is the length of the label
LabelParseState::Pointer => *self,
}
}
}