minor refactor so that parsers can be used across RData
This commit is contained in:
parent
1def967dfc
commit
ac7f9b025f
@ -1,5 +1,7 @@
|
||||
use std::string::FromUtf8Error;
|
||||
|
||||
use super::util;
|
||||
|
||||
pub struct Name {
|
||||
labels: Vec<String>
|
||||
}
|
||||
@ -30,27 +32,7 @@ impl Name {
|
||||
}
|
||||
},
|
||||
LabelParseState::Label(count) => {
|
||||
//let label_slice: &mut [u8] = &mut Vec::with_capacity(count as usize)[..];
|
||||
//let mut label_slice = Vec::with_capacity(count as usize);
|
||||
//let mut label_vec: Vec<u8> = iter::FromIterator::from_iter(iter::repeat(0).take(count as usize));
|
||||
//let mut label_slice: &mut [u8] = &mut label_vec[..];
|
||||
|
||||
// TODO once Drain stabalizes on Vec, this should be replaced...
|
||||
let mut label_slice: Vec<u8> = Vec::with_capacity(count as usize);
|
||||
for i in 0..count as usize {
|
||||
label_slice.push(slice.remove(i-i)); // get rid of the unused i warning...
|
||||
}
|
||||
|
||||
//println!("count: {} slice: {} label_slice: {}", count, slice.len(), label_slice.len());
|
||||
//let label_slice: Vec<u8> = iter::FromIterator::from_iter(iter.take(count as usize).map(|&i| i).collect::<Vec<u8>>());
|
||||
//assert_eq!((&*slice).read(label_slice).ok().unwrap(), count as usize);
|
||||
println!("count: {} slice: {} label_slice: {}", count, slice.len(), label_slice.len());
|
||||
|
||||
// translate bytes to string, then lowercase...
|
||||
//let label_slice = &*label_slice;
|
||||
//let label = try!(String::from_utf8(label_slice.into())).to_lowercase();
|
||||
let label = try!(String::from_utf8(label_slice)).to_lowercase();
|
||||
labels.push(label);
|
||||
labels.push(try!(util::parse_label(slice, count)));
|
||||
|
||||
// reset to collect more data
|
||||
LabelParseState::LabelLengthOrPointer
|
||||
|
@ -5,3 +5,4 @@ pub mod record_data;
|
||||
pub mod domain;
|
||||
|
||||
mod rdata;
|
||||
mod util;
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
|
||||
use super::domain::Name;
|
||||
use super::record_type::RecordType;
|
||||
|
||||
@ -250,7 +252,7 @@ pub enum RData {
|
||||
// an A line in a master file is an Internet address expressed as four
|
||||
// decimal numbers separated by dots without any imbedded spaces (e.g.,
|
||||
// "10.2.0.52" or "192.0.5.6").
|
||||
A { address: u32 },
|
||||
A { address: Ipv4Addr },
|
||||
|
||||
// 3.4.2. WKS RDATA format
|
||||
//
|
||||
@ -294,7 +296,7 @@ pub enum RData {
|
||||
//
|
||||
// In master files, both ports and protocols are expressed using mnemonics
|
||||
// or decimal numbers.
|
||||
WKS { address: u32, protocol: u8, bitmap: Vec<u8> },
|
||||
WKS { address: Ipv4Addr, protocol: u8, bitmap: Vec<u8> },
|
||||
|
||||
//-- RFC 1886 -- IPv6 DNS Extensions December 1995
|
||||
|
||||
@ -302,8 +304,7 @@ pub enum RData {
|
||||
//
|
||||
// A 128 bit IPv6 address is encoded in the data portion of an AAAA
|
||||
// resource record in network byte order (high-order byte first).
|
||||
AAAA { high: u64, low: u64 }
|
||||
|
||||
AAAA { address: Ipv6Addr },
|
||||
}
|
||||
|
||||
impl RData {
|
||||
|
@ -9,6 +9,7 @@ use super::record_data::RData;
|
||||
use super::record_type::RecordType;
|
||||
use super::dns_class::DNSClass;
|
||||
use super::domain;
|
||||
use super::util;
|
||||
|
||||
pub struct Record {
|
||||
name_labels: domain::Name,
|
||||
@ -30,10 +31,10 @@ impl Record {
|
||||
let name_labels: domain::Name = try!(domain::Name::parse(&mut data));
|
||||
|
||||
// TYPE two octets containing one of the RR TYPE codes.
|
||||
let record_type: RecordType = RecordType::from(Self::parse_u16(&mut data));
|
||||
let record_type: RecordType = RecordType::from(util::parse_u16(&mut data));
|
||||
|
||||
// CLASS two octets containing one of the RR CLASS codes.
|
||||
let class: DNSClass = DNSClass::from(Self::parse_u16(&mut data));
|
||||
let class: DNSClass = DNSClass::from(util::parse_u16(&mut data));
|
||||
|
||||
// TTL a 32 bit signed integer that specifies the time interval
|
||||
// that the resource record may be cached before the source
|
||||
@ -43,11 +44,11 @@ impl Record {
|
||||
// cached. For example, SOA records are always distributed
|
||||
// with a zero TTL to prohibit caching. Zero values can
|
||||
// also be used for extremely volatile data.
|
||||
let ttl: i32 = Self::parse_i32(&mut data);
|
||||
let ttl: i32 = util::parse_i32(&mut data);
|
||||
|
||||
// RDLENGTH an unsigned 16 bit integer that specifies the length in
|
||||
// octets of the RDATA field.
|
||||
let rd_length: u16 = Self::parse_u16(&mut data);
|
||||
let rd_length: u16 = util::parse_u16(&mut data);
|
||||
|
||||
// RDATA a variable length string of octets that describes the
|
||||
// resource. The format of this information varies
|
||||
@ -56,71 +57,8 @@ impl Record {
|
||||
|
||||
Ok(Record{ name_labels: name_labels, rr_type: record_type, dns_class: class, ttl: ttl, rdata: rdata })
|
||||
}
|
||||
|
||||
/// parses the next 2 bytes into u16. This performs a byte-by-byte manipulation, there
|
||||
/// which means endianness is implicitly handled (i.e. no network to little endian (intel), issues)
|
||||
fn parse_u16(data: &mut Vec<u8>) -> u16 {
|
||||
// TODO use Drain once it stabalizes...
|
||||
let b1: u8 = data.remove(0);
|
||||
let b2: u8 = data.remove(0);
|
||||
|
||||
// translate from network byte order, i.e. big endian
|
||||
((b1 as u16) << 8) + (b2 as u16)
|
||||
}
|
||||
|
||||
/// parses the next four bytes into i32. This performs a byte-by-byte manipulation, there
|
||||
/// which means endianness is implicitly handled (i.e. no network to little endian (intel), issues)
|
||||
fn parse_i32(data: &mut Vec<u8>) -> i32 {
|
||||
// TODO use Drain once it stabalizes...
|
||||
let b1: u8 = data.remove(0);
|
||||
let b2: u8 = data.remove(0);
|
||||
let b3: u8 = data.remove(0);
|
||||
let b4: u8 = data.remove(0);
|
||||
|
||||
// translate from network byte order, i.e. big endian
|
||||
((b1 as i32) << 24) + ((b2 as i32) << 16) + ((b3 as i32) << 8) + (b4 as i32)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parse_u16() {
|
||||
let data: Vec<(Vec<u8>, u16)> = vec![
|
||||
(vec![0x00,0x00], 0),
|
||||
(vec![0x00,0x01], 1),
|
||||
(vec![0x01,0x00], 256),
|
||||
(vec![0xFF,0xFF], u16::max_value()),
|
||||
];
|
||||
|
||||
let mut test_num = 0;
|
||||
for (mut binary, expect) in data {
|
||||
test_num += 1;
|
||||
println!("test: {}", test_num);
|
||||
assert_eq!(Record::parse_u16(&mut binary), expect);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_i32() {
|
||||
let data: Vec<(Vec<u8>, i32)> = vec![
|
||||
(vec![0x00,0x00,0x00,0x00], 0),
|
||||
(vec![0x00,0x00,0x00,0x01], 1),
|
||||
(vec![0x00,0x00,0x01,0x00], 256),
|
||||
(vec![0x00,0x01,0x00,0x00], 256*256),
|
||||
(vec![0x01,0x00,0x00,0x00], 256*256*256),
|
||||
(vec![0xFF,0xFF,0xFF,0xFF], -1),
|
||||
(vec![0x80,0x00,0x00,0x00], i32::min_value()),
|
||||
(vec![0x7F,0xFF,0xFF,0xFF], i32::max_value()),
|
||||
];
|
||||
|
||||
let mut test_num = 0;
|
||||
for (mut binary, expect) in data {
|
||||
test_num += 1;
|
||||
println!("test: {}", test_num);
|
||||
assert_eq!(Record::parse_i32(&mut binary), expect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
110
src/rr/util.rs
Normal file
110
src/rr/util.rs
Normal file
@ -0,0 +1,110 @@
|
||||
use std::string::FromUtf8Error;
|
||||
|
||||
///<character-string> is a single
|
||||
/// length octet followed by that number of characters. <character-string>
|
||||
/// is treated as binary information, and can be up to 256 characters in
|
||||
/// length (including the length octet).
|
||||
pub fn parse_character_data(data: &mut Vec<u8>) -> Result<String, FromUtf8Error> {
|
||||
let length: u8 = data.remove(0);
|
||||
parse_label(data, length)
|
||||
}
|
||||
|
||||
/// parse a label of a particular length (it's a portion of the vector)
|
||||
///```
|
||||
/// assert_eq(parse_lable(b"aaabbb", 6).ok().unwrap(), "aaabbb".to_string());
|
||||
///```
|
||||
pub fn parse_label(data: &mut Vec<u8>, length: u8) -> Result<String, FromUtf8Error> {
|
||||
// TODO once Drain stabalizes on Vec, this should be replaced...
|
||||
let mut label_vec: Vec<u8> = Vec::with_capacity(length as usize);
|
||||
for i in 0..length as usize {
|
||||
// TODO reverse the data at the top level so that we can use pop() for more performance
|
||||
label_vec.push(data.remove(i-i)); // get rid of the unused i warning...
|
||||
}
|
||||
|
||||
// translate bytes to string, then lowercase...
|
||||
Ok(try!(String::from_utf8(label_vec)).to_lowercase())
|
||||
}
|
||||
|
||||
|
||||
/// parses the next 2 bytes into u16. This performs a byte-by-byte manipulation, there
|
||||
/// which means endianness is implicitly handled (i.e. no network to little endian (intel), issues)
|
||||
pub fn parse_u16(data: &mut Vec<u8>) -> u16 {
|
||||
// TODO use Drain once it stabalizes...
|
||||
let b1: u8 = data.remove(0);
|
||||
let b2: u8 = data.remove(0);
|
||||
|
||||
// translate from network byte order, i.e. big endian
|
||||
((b1 as u16) << 8) + (b2 as u16)
|
||||
}
|
||||
|
||||
/// parses the next four bytes into i32. This performs a byte-by-byte manipulation, there
|
||||
/// which means endianness is implicitly handled (i.e. no network to little endian (intel), issues)
|
||||
pub fn parse_i32(data: &mut Vec<u8>) -> i32 {
|
||||
// TODO use Drain once it stabalizes...
|
||||
let b1: u8 = data.remove(0);
|
||||
let b2: u8 = data.remove(0);
|
||||
let b3: u8 = data.remove(0);
|
||||
let b4: u8 = data.remove(0);
|
||||
|
||||
// translate from network byte order, i.e. big endian
|
||||
((b1 as i32) << 24) + ((b2 as i32) << 16) + ((b3 as i32) << 8) + (b4 as i32)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn parse_character_data() {
|
||||
let data: Vec<(Vec<u8>, String)> = vec![
|
||||
(vec![0], "".to_string()), // base case, only the root
|
||||
(vec![1,b'a'], "a".to_string()), // a single 'a' label
|
||||
(vec![2,b'b',b'c'], "bc".to_string()), // two labels, 'a.bc'
|
||||
(vec![3,0xE2,0x99,0xA5], "♥".to_string()), // two labels utf8, 'a.♥'
|
||||
(vec![1,b'A'], "a".to_string()), // a single 'a' label, lowercased
|
||||
];
|
||||
|
||||
let mut test_num = 0;
|
||||
for (mut binary, expect) in data {
|
||||
test_num += 1;
|
||||
println!("test: {}", test_num);
|
||||
assert_eq!(super::parse_character_data(&mut binary).ok().unwrap(), expect);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_u16() {
|
||||
let data: Vec<(Vec<u8>, u16)> = vec![
|
||||
(vec![0x00,0x00], 0),
|
||||
(vec![0x00,0x01], 1),
|
||||
(vec![0x01,0x00], 256),
|
||||
(vec![0xFF,0xFF], u16::max_value()),
|
||||
];
|
||||
|
||||
let mut test_num = 0;
|
||||
for (mut binary, expect) in data {
|
||||
test_num += 1;
|
||||
println!("test: {}", test_num);
|
||||
assert_eq!(super::parse_u16(&mut binary), expect);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_i32() {
|
||||
let data: Vec<(Vec<u8>, i32)> = vec![
|
||||
(vec![0x00,0x00,0x00,0x00], 0),
|
||||
(vec![0x00,0x00,0x00,0x01], 1),
|
||||
(vec![0x00,0x00,0x01,0x00], 256),
|
||||
(vec![0x00,0x01,0x00,0x00], 256*256),
|
||||
(vec![0x01,0x00,0x00,0x00], 256*256*256),
|
||||
(vec![0xFF,0xFF,0xFF,0xFF], -1),
|
||||
(vec![0x80,0x00,0x00,0x00], i32::min_value()),
|
||||
(vec![0x7F,0xFF,0xFF,0xFF], i32::max_value()),
|
||||
];
|
||||
|
||||
let mut test_num = 0;
|
||||
for (mut binary, expect) in data {
|
||||
test_num += 1;
|
||||
println!("test: {}", test_num);
|
||||
assert_eq!(super::parse_i32(&mut binary), expect);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user