minor refactor so that parsers can be used across RData

This commit is contained in:
Benjamin Fry 2015-08-12 13:34:12 -07:00
parent 1def967dfc
commit ac7f9b025f
5 changed files with 124 additions and 92 deletions

View File

@ -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

View File

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

View File

@ -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 {

View File

@ -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
View 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);
}
}
}