mirror of
https://github.com/NLnetLabs/domain.git
synced 2026-09-29 05:04:58 +02:00
Third part of zonefile parsing.
This commit is contained in:
+1
-1
@@ -45,7 +45,7 @@ pub use self::octets::Octets;
|
||||
pub use self::parse::{ParseBytes};
|
||||
pub use self::question::Question;
|
||||
pub use self::rdata::{GenericRecordData, RecordData};
|
||||
pub use self::record::Record;
|
||||
pub use self::record::{GenericRecord, Record};
|
||||
|
||||
pub mod bytes;
|
||||
pub mod charstr;
|
||||
|
||||
+102
-56
@@ -178,6 +178,15 @@ impl<'a> From<PackedDName<'a>> for DName<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<Cow<'a, DNameSlice>> for DName<'a> {
|
||||
fn from(name: Cow<'a, DNameSlice>) -> DName<'a> {
|
||||
match name {
|
||||
Cow::Borrowed(name) => DName::Slice(name),
|
||||
Cow::Owned(name) => DName::Owned(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--- FromStr
|
||||
|
||||
@@ -543,6 +552,29 @@ impl DNameSlice {
|
||||
}
|
||||
|
||||
|
||||
/// # Scanning from Master Format
|
||||
///
|
||||
impl DNameSlice {
|
||||
pub fn scan<'a, R: io::Read>(stream: &mut master::Stream<R>,
|
||||
origin: Option<&'a DNameSlice>)
|
||||
-> master::Result<Cow<'a, DNameSlice>> {
|
||||
if let Ok(()) = stream.skip_literal(b"@") {
|
||||
if let Some(origin) = origin {
|
||||
stream.ok(Cow::Borrowed(origin))
|
||||
}
|
||||
else {
|
||||
stream.err(master::SyntaxError::NoOrigin)
|
||||
}
|
||||
}
|
||||
else {
|
||||
let mut res = DNameBuf::new();
|
||||
try!(DNameBuf::scan_into(stream, origin, &mut res.inner));
|
||||
Ok(Cow::Owned(res))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--- AsRef
|
||||
|
||||
impl AsRef<DNameSlice> for DNameSlice {
|
||||
@@ -735,77 +767,91 @@ impl DNameBuf {
|
||||
Ok(try!(try!(PackedDName::parse(parser, context)).to_owned()))
|
||||
}
|
||||
|
||||
pub fn scan_absolute<R: io::Read>(stream: &mut master::Stream<R>)
|
||||
-> master::Result<Self> {
|
||||
let res = try!(DNameBuf::_scan(stream));
|
||||
if res.is_relative() {
|
||||
stream.err(master::SyntaxError::RelativeName)
|
||||
}
|
||||
else {
|
||||
stream.ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scan<R, N>(stream: &mut master::Stream<R>, origin: N)
|
||||
-> master::Result<Self>
|
||||
where R: io::Read, N: AsRef<DNameSlice> {
|
||||
let mut res = try!(DNameBuf::_scan(stream));
|
||||
res.append(origin);
|
||||
if res.is_relative() {
|
||||
stream.err(master::SyntaxError::RelativeName)
|
||||
}
|
||||
else {
|
||||
stream.ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn _scan<R: io::Read>(stream: &mut master::Stream<R>)
|
||||
-> master::Result<Self> {
|
||||
// XXX TODO Rewrite using Stream::scan_word_chars().
|
||||
let mut res = DNameBuf::new();
|
||||
let mut label = Vec::new();
|
||||
loop {
|
||||
match try!(stream.read_word_char()) {
|
||||
Some(b'.') => {
|
||||
if label.len() > 63 {
|
||||
return stream.err(master::SyntaxError::LongLabel)
|
||||
/// Scans from `stream` into `target`.
|
||||
///
|
||||
/// Does not progress the stream on success so you can still error out
|
||||
/// at the beginning of the name. Returns whether the resulting
|
||||
/// domain name is absolute.
|
||||
pub fn _scan_into<R: io::Read>(stream: &mut master::Stream<R>,
|
||||
target: &mut Vec<u8>)
|
||||
-> master::Result<bool> {
|
||||
let name_start = target.len();
|
||||
let mut label_start = name_start;
|
||||
target.push_u8(0);
|
||||
try!(stream.scan_word_chars(|ch, escape| {
|
||||
match (ch, escape) {
|
||||
(b'.', false) => {
|
||||
let label_len = target.len() - label_start - 1;
|
||||
if label_len > 63 {
|
||||
return Err(master::SyntaxError::LongLabel)
|
||||
}
|
||||
res.inner.push(label.len() as u8);
|
||||
res.inner.extend(&label);
|
||||
label.clear();
|
||||
target[label_start] = label_len as u8;
|
||||
label_start = target.len();
|
||||
target.push_u8(0);
|
||||
}
|
||||
(ch, _) => {
|
||||
target.push_u8(ch)
|
||||
}
|
||||
Some(b'\\') => label.push(try!(stream.scan_escape())),
|
||||
Some(ch) => label.push(ch),
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
if label.len() > 63 {
|
||||
return stream.err(master::SyntaxError::LongLabel)
|
||||
}
|
||||
res.inner.push(label.len() as u8);
|
||||
res.inner.extend(&label);
|
||||
if res.inner.len() > 255 {
|
||||
Ok(())
|
||||
}));
|
||||
if target.len() - name_start > 255 {
|
||||
stream.err(master::SyntaxError::LongName)
|
||||
}
|
||||
else {
|
||||
Ok(res)
|
||||
Ok(label_start == target.len() -1)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scan_into<R, N, B>(stream: &mut master::Stream<R>, origin: N,
|
||||
target: &mut B) -> master::Result<()>
|
||||
where R: io::Read, N: AsRef<DNameSlice>,
|
||||
B: BytesBuf {
|
||||
// XXX TODO Rewrite without extra allocation.
|
||||
let name = try!(DNameBuf::scan(stream, origin));
|
||||
target.push_bytes(&name.as_bytes());
|
||||
Ok(())
|
||||
pub fn scan_into<R: io::Read>(stream: &mut master::Stream<R>,
|
||||
origin: Option<&DNameSlice>,
|
||||
target: &mut Vec<u8>)
|
||||
-> master::Result<()> {
|
||||
if let Ok(()) = stream.skip_literal(b"@") {
|
||||
if let Some(origin) = origin {
|
||||
target.push_bytes(&origin.as_bytes());
|
||||
}
|
||||
else {
|
||||
return stream.err(master::SyntaxError::NoOrigin)
|
||||
}
|
||||
}
|
||||
else if let false = try!(DNameBuf::_scan_into(stream, target)) {
|
||||
if let Some(origin) = origin {
|
||||
target.push_bytes(&origin.as_bytes());
|
||||
}
|
||||
else {
|
||||
return stream.err(master::SyntaxError::RelativeName)
|
||||
}
|
||||
}
|
||||
stream.ok(())
|
||||
}
|
||||
|
||||
pub fn scan<R: io::Read>(stream: &mut master::Stream<R>,
|
||||
origin: Option<&DNameSlice>)
|
||||
-> master::Result<DNameBuf> {
|
||||
if let Ok(()) = stream.skip_literal(b"@") {
|
||||
if let Some(origin) = origin {
|
||||
stream.ok(origin.to_owned())
|
||||
}
|
||||
else {
|
||||
stream.err(master::SyntaxError::NoOrigin)
|
||||
}
|
||||
}
|
||||
else {
|
||||
let mut res = DNameBuf::new();
|
||||
try!(DNameBuf::scan_into(stream, origin, &mut res.inner));
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a reference to a domain name slice of this domain name.
|
||||
pub fn as_slice(&self) -> &DNameSlice {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn into_vec(self) -> Vec<u8> {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+9
-1
@@ -225,11 +225,19 @@ impl NestBuf {
|
||||
NestBuf(Vec::new())
|
||||
}
|
||||
|
||||
/// Creates a nest as a copy of the given bytes slice.
|
||||
/// Creates an owned nest as a copy of the given bytes slice.
|
||||
pub fn from_bytes(slice: &[u8]) -> Self {
|
||||
NestBuf(Vec::from(slice))
|
||||
}
|
||||
|
||||
/// Creates an owned nest from the given vec.
|
||||
pub fn from_vec(vec: Vec<u8>) -> Self {
|
||||
NestBuf(vec)
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the nest’s content.
|
||||
pub fn as_mut_vec(&mut self) -> &mut Vec<u8> { &mut self.0 }
|
||||
|
||||
/// Parses an owned nest.
|
||||
pub fn parse<'a, P>(p: &mut P, len: usize) -> ParseResult<Self>
|
||||
where P: ParseBytes<'a> {
|
||||
|
||||
+11
-4
@@ -19,7 +19,7 @@ use super::compose::ComposeBytes;
|
||||
use super::error::{ComposeResult, ParseResult};
|
||||
use super::nest::Nest;
|
||||
use super::parse::ParseBytes;
|
||||
use ::bits::bytes::BytesBuf;
|
||||
use bits::bytes::BytesBuf;
|
||||
use ::master;
|
||||
|
||||
|
||||
@@ -96,9 +96,9 @@ impl<'a> GenericRecordData<'a> {
|
||||
///
|
||||
/// [RFC 3597]: https:://tools.ietf.org/html/rfc3597
|
||||
/// [domain::rdata::scan_into()]: ../../rdata/fn.scan_into.html
|
||||
pub fn scan_into<R, B>(stream: &mut master::Stream<R>, target: &mut B)
|
||||
-> master::Result<()>
|
||||
where R: io::Read, B: BytesBuf {
|
||||
pub fn scan_into<R: io::Read>(stream: &mut master::Stream<R>,
|
||||
target: &mut Vec<u8>)
|
||||
-> master::Result<()> {
|
||||
try!(stream.skip_literal(b"\\#"));
|
||||
let mut len = try!(stream.scan_u16());
|
||||
target.reserve(len as usize);
|
||||
@@ -115,6 +115,13 @@ impl<'a> GenericRecordData<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn scan<R: io::Read>(stream: &mut master::Stream<R>)
|
||||
-> master::Result<Vec<u8>> {
|
||||
let mut res = Vec::new();
|
||||
try!(GenericRecordData::scan_into(stream, &mut res));
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Formats the record data as if it were of concrete type `R`.
|
||||
pub fn fmt<'b: 'a, R>(&'b self, f: &mut fmt::Formatter) -> fmt::Result
|
||||
where R: RecordData<'a> + fmt::Display {
|
||||
|
||||
@@ -11,6 +11,7 @@ use super::nest::Nest;
|
||||
use super::parse::ParseBytes;
|
||||
use super::rdata::{GenericRecordData, RecordData};
|
||||
|
||||
|
||||
//------------ Record -------------------------------------------------------
|
||||
|
||||
/// A resource record.
|
||||
@@ -203,6 +204,7 @@ impl<'a> Record<'a, GenericRecordData<'a>> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------ RecordTarget -------------------------------------------------
|
||||
|
||||
/// A helper trait to compose records without creating `Record` values first.
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
|
||||
use std::ascii::AsciiExt;
|
||||
use std::io;
|
||||
use ::bits::name::DNameBuf;
|
||||
use ::master::{Pos, Zonefile};
|
||||
use ::master::error::{Error, Result};
|
||||
use ::master::stream::{Newline, Stream};
|
||||
|
||||
|
||||
pub fn scan_opt_control<R: io::Read>(stream: &mut Stream<R>,
|
||||
file: &mut Zonefile)
|
||||
-> Result<Option<Newline>> {
|
||||
Ok(match try!(ControlType::scan_opt(stream)) {
|
||||
None => None,
|
||||
Some(ControlType::Origin) => Some(try!(scan_origin(stream, file))),
|
||||
Some(ControlType::Include) => Some(try!(scan_include(stream, file))),
|
||||
Some(ControlType::Ttl) => Some(try!(scan_ttl(stream, file))),
|
||||
Some(ControlType::Other(name, pos))
|
||||
=> Some(try!(scan_other(stream, name, pos, file)))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
//------------ ControlType ---------------------------------------------------
|
||||
|
||||
enum ControlType {
|
||||
Origin,
|
||||
Include,
|
||||
Ttl,
|
||||
Other(String, Pos)
|
||||
}
|
||||
|
||||
impl ControlType {
|
||||
pub fn scan_opt<R: io::Read>(stream: &mut Stream<R>)
|
||||
-> Result<Option<Self>> {
|
||||
let pos = stream.pos();
|
||||
match stream.skip_char(b'$') {
|
||||
Ok(()) => { }
|
||||
Err(Error::Syntax(..)) => return Ok(None),
|
||||
Err(err) => return Err(err)
|
||||
}
|
||||
stream.scan_word(|word| {
|
||||
if word.eq_ignore_ascii_case(b"ORIGIN") {
|
||||
Ok(ControlType::Origin)
|
||||
}
|
||||
else if word.eq_ignore_ascii_case(b"INCLUDE") {
|
||||
Ok(ControlType::Include)
|
||||
}
|
||||
else if word.eq_ignore_ascii_case(b"TTL") {
|
||||
Ok(ControlType::Ttl)
|
||||
}
|
||||
else {
|
||||
// XXX Zonefile-encode non-ASCII characters.
|
||||
Ok(ControlType::Other(String::from_utf8_lossy(word)
|
||||
.into_owned(), pos))
|
||||
}
|
||||
}).map(|x| Some(x))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------ Scanner functions for control types ---------------------------
|
||||
|
||||
/// Scans the $ORIGIN control entity.
|
||||
fn scan_origin<R: io::Read>(stream: &mut Stream<R>,
|
||||
file: &mut Zonefile) -> Result<Newline> {
|
||||
try!(stream.skip_opt_space());
|
||||
let origin = try!(DNameBuf::scan_absolute(stream));
|
||||
let res = try!(stream.scan_newline());
|
||||
file.set_origin(origin);
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Scans the $INCLUDE control entity.
|
||||
fn scan_include<R: io::Read>(stream: &mut Stream<R>,
|
||||
file: &mut Zonefile) -> Result<Newline> {
|
||||
try!(stream.skip_opt_space());
|
||||
let path = try!(stream.scan_phrase(|path| Ok(Vec::from(path))));
|
||||
try!(stream.skip_opt_space());
|
||||
let origin = DNameBuf::scan(stream, file.origin()).ok();
|
||||
let res = try!(stream.scan_newline());
|
||||
file.add_include(path, origin);
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Scans the $TTL control entitiy defined in RFC 2308.
|
||||
fn scan_ttl<R: io::Read>(stream: &mut Stream<R>,
|
||||
file: &mut Zonefile) -> Result<Newline> {
|
||||
try!(stream.skip_opt_space());
|
||||
let ttl = try!(stream.scan_u32());
|
||||
let res = try!(stream.scan_newline());
|
||||
file.set_ttl(ttl);
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn scan_other<R: io::Read>(stream: &mut Stream<R>, name: String,
|
||||
pos: Pos, file: &mut Zonefile) -> Result<Newline> {
|
||||
let res = try!(stream.skip_entry());
|
||||
file.add_warning(pos, format!("Unknown control entry '${}'", name));
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
|
||||
use std::ascii::AsciiExt;
|
||||
use std::io;
|
||||
use std::rc::Rc;
|
||||
use ::bits::DNameBuf;
|
||||
use ::iana::Class;
|
||||
use ::master::{Error, Pos, Result, Stream};
|
||||
use ::master::record::{MasterRecord, map_origin};
|
||||
|
||||
|
||||
//------------ Entry ---------------------------------------------------------
|
||||
|
||||
pub enum Entry {
|
||||
Origin(Rc<DNameBuf>),
|
||||
Include { path: Vec<u8>, origin: Option<Rc<DNameBuf>> },
|
||||
Ttl(u32),
|
||||
Control { name: Vec<u8>, start: Pos },
|
||||
Record(MasterRecord)
|
||||
}
|
||||
|
||||
impl Entry {
|
||||
pub fn scan<R: io::Read>(stream: &mut Stream<R>,
|
||||
last_owner: Option<Rc<DNameBuf>>,
|
||||
last_class: Option<Class>,
|
||||
origin: &Option<Rc<DNameBuf>>,
|
||||
default_ttl: Option<u32>)
|
||||
-> Result<Option<Self>> {
|
||||
while let Ok(()) = stream.scan_newline() { }
|
||||
if let Ok(true) = stream.is_eof() {
|
||||
return Ok(None)
|
||||
}
|
||||
let res = match try!(ControlType::scan_opt(stream)) {
|
||||
Some(ControlType::Origin) => {
|
||||
let origin = map_origin(origin);
|
||||
Entry::Origin(Rc::new(try!(DNameBuf::scan(stream, origin))))
|
||||
}
|
||||
Some(ControlType::Include) => {
|
||||
Entry::Include {
|
||||
path: try!(stream.scan_phrase_copy()),
|
||||
origin: DNameBuf::scan(stream, map_origin(origin))
|
||||
.map(|n| Rc::new(n)).ok()
|
||||
}
|
||||
}
|
||||
Some(ControlType::Ttl) => {
|
||||
Entry::Ttl(try!(stream.scan_u32()))
|
||||
}
|
||||
Some(ControlType::Other(name, pos)) => {
|
||||
Entry::Control { name: name, start: pos }
|
||||
}
|
||||
None => {
|
||||
Entry::Record(try!(MasterRecord::scan(stream, last_owner,
|
||||
last_class, origin,
|
||||
default_ttl)))
|
||||
}
|
||||
};
|
||||
try!(stream.scan_newline());
|
||||
Ok(Some(res))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------ ControlType ---------------------------------------------------
|
||||
|
||||
enum ControlType {
|
||||
Origin,
|
||||
Include,
|
||||
Ttl,
|
||||
Other(Vec<u8>, Pos)
|
||||
}
|
||||
|
||||
impl ControlType {
|
||||
pub fn scan_opt<R: io::Read>(stream: &mut Stream<R>)
|
||||
-> Result<Option<Self>> {
|
||||
let pos = stream.pos();
|
||||
match stream.skip_char(b'$') {
|
||||
Ok(()) => { }
|
||||
Err(Error::Syntax(..)) => return Ok(None),
|
||||
Err(err) => return Err(err)
|
||||
}
|
||||
stream.scan_word(|word| {
|
||||
if word.eq_ignore_ascii_case(b"ORIGIN") {
|
||||
Ok(ControlType::Origin)
|
||||
}
|
||||
else if word.eq_ignore_ascii_case(b"INCLUDE") {
|
||||
Ok(ControlType::Include)
|
||||
}
|
||||
else if word.eq_ignore_ascii_case(b"TTL") {
|
||||
Ok(ControlType::Ttl)
|
||||
}
|
||||
else {
|
||||
// XXX Master-encode non-ASCII characters.
|
||||
Ok(ControlType::Other(word.to_owned(), pos))
|
||||
}
|
||||
}).map(|x| Some(x))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ pub enum SyntaxError {
|
||||
NoDefaultTtl,
|
||||
NoLastClass,
|
||||
NoLastOwner,
|
||||
NoOrigin,
|
||||
RelativeName,
|
||||
Unexpected(u8),
|
||||
UnexpectedEof,
|
||||
|
||||
+4
-89
@@ -1,96 +1,11 @@
|
||||
|
||||
use ::bits::{DNameBuf, DNameSlice};
|
||||
use ::bits::record::GenericRecord;
|
||||
use ::iana::Class;
|
||||
//! Reading and writing of master files.
|
||||
|
||||
pub use self::error::{Error, Result, SyntaxError, SyntaxResult};
|
||||
pub use self::stream::{Newline, Stream};
|
||||
pub use self::stream::{Pos, Stream};
|
||||
|
||||
|
||||
pub mod control;
|
||||
pub mod entry;
|
||||
pub mod error;
|
||||
pub mod reader;
|
||||
pub mod record;
|
||||
pub mod stream;
|
||||
|
||||
|
||||
//------------ Zonefile ------------------------------------------------------
|
||||
|
||||
pub struct Zonefile<'a> {
|
||||
includes: Vec<Include>,
|
||||
records: Vec<GenericRecord<'a>>,
|
||||
origin: DNameBuf,
|
||||
ttl: Option<u32>,
|
||||
warnings: Vec<(Pos, String)>
|
||||
}
|
||||
|
||||
impl<'a> Zonefile<'a> {
|
||||
pub fn origin(&self) -> &DNameSlice {
|
||||
&self.origin
|
||||
}
|
||||
|
||||
pub fn set_origin(&mut self, origin: DNameBuf) {
|
||||
self.origin = origin
|
||||
}
|
||||
|
||||
pub fn ttl(&self) -> Option<u32> {
|
||||
self.ttl
|
||||
}
|
||||
|
||||
pub fn set_ttl(&mut self, ttl: u32) {
|
||||
self.ttl = Some(ttl)
|
||||
}
|
||||
|
||||
pub fn last_class(&self) -> Option<Class> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn last_owner(&self) -> Option<DNameBuf> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
|
||||
pub fn add_record(&mut self, record: GenericRecord<'a>) {
|
||||
self.records.push(record)
|
||||
}
|
||||
|
||||
pub fn add_include(&mut self, path: Vec<u8>, origin: Option<DNameBuf>) {
|
||||
self.includes.push(Include { path: path, origin: origin })
|
||||
}
|
||||
|
||||
pub fn add_warning(&mut self, pos: Pos, text: String) {
|
||||
self.warnings.push((pos, text))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------ Include ------------------------------------------------------
|
||||
|
||||
pub struct Include {
|
||||
pub path: Vec<u8>,
|
||||
pub origin: Option<DNameBuf>,
|
||||
}
|
||||
|
||||
|
||||
//------------ Pos -----------------------------------------------------------
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Pos {
|
||||
line: usize,
|
||||
col: usize
|
||||
}
|
||||
|
||||
impl Pos {
|
||||
pub fn new() -> Pos {
|
||||
Pos { line: 1, col: 1 }
|
||||
}
|
||||
|
||||
pub fn update(&mut self, ch: u8) {
|
||||
match ch {
|
||||
b'\n' => self.line += 1,
|
||||
_ => self.col += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
|
||||
use std::io;
|
||||
use std::rc::Rc;
|
||||
use ::bits::name::DNameBuf;
|
||||
use ::iana::Class;
|
||||
use ::master::entry::Entry;
|
||||
use ::master::error::Result;
|
||||
use ::master::record::MasterRecord;
|
||||
use ::master::stream::Stream;
|
||||
|
||||
|
||||
pub struct Reader<R: io::Read> {
|
||||
stream: Stream<R>,
|
||||
origin: Option<Rc<DNameBuf>>,
|
||||
ttl: Option<u32>,
|
||||
last: Option<(Rc<DNameBuf>, Class)>,
|
||||
}
|
||||
|
||||
impl<R: io::Read> Reader<R> {
|
||||
pub fn new(reader: R) -> Self {
|
||||
Reader {
|
||||
stream: Stream::new(reader),
|
||||
origin: None,
|
||||
ttl: None,
|
||||
last: None
|
||||
}
|
||||
}
|
||||
|
||||
fn last_owner(&self) -> Option<Rc<DNameBuf>> {
|
||||
match &self.last {
|
||||
&Some((ref name, _)) => Some(name.clone()),
|
||||
&None => None
|
||||
}
|
||||
}
|
||||
|
||||
fn last_class(&self) -> Option<Class> {
|
||||
match &self.last {
|
||||
&Some((_, class)) => Some(class),
|
||||
&None => None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next_record(&mut self) -> Result<Option<ReaderItem>> {
|
||||
loop {
|
||||
let last_owner = self.last_owner();
|
||||
let last_class = self.last_class();
|
||||
match try!(Entry::scan(&mut self.stream, last_owner,
|
||||
last_class, &self.origin, self.ttl)) {
|
||||
Some(Entry::Origin(origin)) => self.origin = Some(origin),
|
||||
Some(Entry::Include{path, origin}) => {
|
||||
return Ok(Some(ReaderItem::Include { path: path,
|
||||
origin: origin }))
|
||||
}
|
||||
Some(Entry::Ttl(ttl)) => self.ttl = Some(ttl),
|
||||
Some(Entry::Control{..}) => { },
|
||||
Some(Entry::Record(record)) => {
|
||||
return Ok(Some(ReaderItem::Record(record)))
|
||||
}
|
||||
None => return Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: io::Read> Iterator for Reader<R> {
|
||||
type Item = Result<ReaderItem>;
|
||||
|
||||
fn next(&mut self) -> Option<Result<ReaderItem>> {
|
||||
match self.next_record() {
|
||||
Ok(Some(res)) => Some(Ok(res)),
|
||||
Ok(None) => None,
|
||||
Err(err) => Some(Err(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub enum ReaderItem {
|
||||
Record(MasterRecord),
|
||||
Include { path: Vec<u8>, origin: Option<Rc<DNameBuf>> }
|
||||
}
|
||||
+98
-63
@@ -1,79 +1,114 @@
|
||||
|
||||
use std::io;
|
||||
use ::bits::{DName, DNameBuf};
|
||||
use ::bits::nest::{Nest, NestBuf};
|
||||
use ::bits::record::GenericRecord;
|
||||
use std::rc::Rc;
|
||||
use ::bits::{DNameBuf, DNameSlice};
|
||||
use ::iana::{Class, RRType};
|
||||
use ::master::{Newline, Result, Stream, SyntaxError, Zonefile,};
|
||||
use ::rdata;
|
||||
use super::{Result, Stream, SyntaxError};
|
||||
|
||||
|
||||
pub fn scan_record<R: io::Read>(stream: &mut Stream<R>, file: &mut Zonefile)
|
||||
-> Result<Newline> {
|
||||
let owner = DName::Owned(try!(scan_owner(stream, file)));
|
||||
let (ttl, class) = try!(scan_ttl_class(stream, file));
|
||||
let rtype = try!(RRType::scan(stream));
|
||||
let mut rdata = NestBuf::new();
|
||||
try!(rdata::scan_into(rtype, stream, file.origin(), &mut rdata));
|
||||
let res = try!(stream.scan_newline());
|
||||
file.add_record(GenericRecord::new_generic(owner, class, rtype, ttl,
|
||||
Nest::Owned(rdata)));
|
||||
Ok(res)
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct MasterRecord {
|
||||
owner: Rc<DNameBuf>,
|
||||
rtype: RRType,
|
||||
class: Class,
|
||||
ttl: u32,
|
||||
rdata: Vec<u8>,
|
||||
}
|
||||
|
||||
fn scan_owner<R: io::Read>(stream: &mut Stream<R>, file: &mut Zonefile)
|
||||
-> Result<DNameBuf> {
|
||||
if try!(stream.skip_opt_space()) {
|
||||
if let Some(name) = file.last_owner() {
|
||||
stream.ok(name)
|
||||
impl MasterRecord {
|
||||
pub fn new(owner: Rc<DNameBuf>, rtype: RRType, class: Class, ttl: u32,
|
||||
rdata: Vec<u8>) -> Self {
|
||||
MasterRecord { owner: owner, rtype: rtype, class: class,
|
||||
ttl: ttl, rdata: rdata }
|
||||
}
|
||||
}
|
||||
|
||||
impl MasterRecord {
|
||||
pub fn scan<R: io::Read>(stream: &mut Stream<R>,
|
||||
last_owner: Option<Rc<DNameBuf>>,
|
||||
last_class: Option<Class>,
|
||||
origin: &Option<Rc<DNameBuf>>,
|
||||
default_ttl: Option<u32>) -> Result<Self> {
|
||||
let owner = try!(MasterRecord::scan_owner(stream, last_owner,
|
||||
&origin));
|
||||
let (ttl, class) = try!(MasterRecord::scan_ttl_class(stream,
|
||||
default_ttl,
|
||||
last_class));
|
||||
let rtype = try!(RRType::scan(stream));
|
||||
let rdata = try!(rdata::scan(rtype, stream, map_origin(origin)));
|
||||
try!(stream.scan_newline());
|
||||
Ok(MasterRecord::new(owner, rtype, class, ttl, rdata))
|
||||
}
|
||||
|
||||
/// Scans the owner.
|
||||
///
|
||||
/// Returns new owner and origin.
|
||||
fn scan_owner<R: io::Read>(stream: &mut Stream<R>,
|
||||
last_owner: Option<Rc<DNameBuf>>,
|
||||
origin: &Option<Rc<DNameBuf>>)
|
||||
-> Result<Rc<DNameBuf>> {
|
||||
if try!(stream.skip_opt_space()) {
|
||||
if let Some(owner) = last_owner { Ok(owner) }
|
||||
else { stream.err(SyntaxError::NoLastOwner) }
|
||||
}
|
||||
else if let Ok(()) = stream.skip_literal(b"@") {
|
||||
if let &Some(ref origin) = origin { Ok(origin.clone()) }
|
||||
else { stream.err(SyntaxError::NoOrigin) }
|
||||
}
|
||||
else {
|
||||
stream.err(SyntaxError::NoLastOwner)
|
||||
Ok(Rc::new(try!(DNameBuf::scan(stream, map_origin(origin)))))
|
||||
}
|
||||
}
|
||||
else {
|
||||
let res = try!(DNameBuf::scan(stream, file.origin()));
|
||||
try!(stream.skip_opt_space());
|
||||
Ok(res)
|
||||
|
||||
fn scan_ttl_class<R: io::Read>(stream: &mut Stream<R>,
|
||||
default_ttl: Option<u32>,
|
||||
last_class: Option<Class>)
|
||||
-> Result<(u32, Class)> {
|
||||
let (ttl, class) = match stream.scan_u32() {
|
||||
Ok(ttl) => {
|
||||
try!(stream.skip_opt_space());
|
||||
match Class::scan(stream) {
|
||||
Ok(class) => {
|
||||
try!(stream.skip_opt_space());
|
||||
(Some(ttl), Some(class))
|
||||
}
|
||||
Err(_) => (Some(ttl), None)
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
match Class::scan(stream) {
|
||||
Ok(class) => {
|
||||
try!(stream.skip_opt_space());
|
||||
match stream.scan_u32() {
|
||||
Ok(ttl) => {
|
||||
try!(stream.skip_opt_space());
|
||||
(Some(ttl), Some(class))
|
||||
}
|
||||
Err(_) => (None, Some(class))
|
||||
}
|
||||
}
|
||||
Err(_) => (None, None)
|
||||
}
|
||||
}
|
||||
};
|
||||
let ttl = match ttl.or(default_ttl) {
|
||||
Some(ttl) => ttl,
|
||||
None => return stream.err(SyntaxError::NoDefaultTtl)
|
||||
};
|
||||
let class = match class.or(last_class) {
|
||||
Some(class) => class,
|
||||
None => return stream.err(SyntaxError::NoLastClass)
|
||||
};
|
||||
Ok((ttl, class))
|
||||
}
|
||||
}
|
||||
|
||||
fn scan_ttl_class<R: io::Read>(stream: &mut Stream<R>, file: &mut Zonefile)
|
||||
-> Result<(u32, Class)> {
|
||||
let (ttl, class) = match stream.scan_u32() {
|
||||
Ok(ttl) => {
|
||||
try!(stream.skip_opt_space());
|
||||
match Class::scan(stream) {
|
||||
Ok(class) => {
|
||||
try!(stream.skip_opt_space());
|
||||
(Some(ttl), Some(class))
|
||||
}
|
||||
Err(_) => (Some(ttl), None)
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
match Class::scan(stream) {
|
||||
Ok(class) => {
|
||||
try!(stream.skip_opt_space());
|
||||
match stream.scan_u32() {
|
||||
Ok(ttl) => {
|
||||
try!(stream.skip_opt_space());
|
||||
(Some(ttl), Some(class))
|
||||
}
|
||||
Err(_) => (None, Some(class))
|
||||
}
|
||||
}
|
||||
Err(_) => (None, None)
|
||||
}
|
||||
}
|
||||
};
|
||||
let ttl = match ttl.or(file.ttl()) {
|
||||
Some(ttl) => ttl,
|
||||
None => return stream.err(SyntaxError::NoDefaultTtl)
|
||||
};
|
||||
let class = match class.or(file.last_class()) {
|
||||
Some(class) => class,
|
||||
None => return stream.err(SyntaxError::NoLastClass)
|
||||
};
|
||||
Ok((ttl, class))
|
||||
|
||||
pub fn map_origin<'a>(origin: &'a Option<Rc<DNameBuf>>)
|
||||
-> Option<&'a DNameSlice> {
|
||||
match origin {
|
||||
&Some(ref rc) => Some(rc),
|
||||
&None => None
|
||||
}
|
||||
}
|
||||
|
||||
+49
-21
@@ -3,7 +3,6 @@
|
||||
use std::io;
|
||||
use std::str;
|
||||
use ::master::error::{Error, Result, SyntaxError, SyntaxResult};
|
||||
use ::master::Pos;
|
||||
|
||||
|
||||
//------------ Stream ---------------------------------------------------
|
||||
@@ -13,6 +12,11 @@ pub struct Stream<R: io::Read> {
|
||||
paren: bool,
|
||||
}
|
||||
|
||||
impl<R: io::Read> Stream<R> {
|
||||
pub fn new(reader: R) -> Self {
|
||||
Stream { buf: Buffer::new(reader), paren: false }
|
||||
}
|
||||
}
|
||||
|
||||
/// Reading.
|
||||
///
|
||||
@@ -30,6 +34,11 @@ impl<R: io::Read> Stream<R> {
|
||||
self.buf.peek_char()
|
||||
}
|
||||
|
||||
pub fn is_eof(&mut self) -> io::Result<bool> {
|
||||
if let Some(_) = try!(self.peek_char()) { Ok(false) }
|
||||
else { Ok(true) }
|
||||
}
|
||||
|
||||
pub fn cond_read_char<F>(&mut self, f: F) -> Result<Option<u8>>
|
||||
where F: Fn(u8) -> bool {
|
||||
match try!(self.buf.peek_char()) {
|
||||
@@ -332,9 +341,7 @@ impl<R: io::Read> Stream<R> {
|
||||
self.paren = false
|
||||
}
|
||||
Some(b';') => {
|
||||
if let Newline::Eof = try!(self.skip_comment()) {
|
||||
return self.ok(true)
|
||||
}
|
||||
try!(self.skip_comment());
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
@@ -355,27 +362,27 @@ impl<R: io::Read> Stream<R> {
|
||||
}
|
||||
}
|
||||
|
||||
fn skip_comment(&mut self) -> Result<Newline> {
|
||||
fn skip_comment(&mut self) -> Result<()> {
|
||||
match self.skip_until(is_newline) {
|
||||
Ok(_) => self.ok(Newline::Real),
|
||||
Err(ref err) if err.is_eof() => self.ok(Newline::Eof),
|
||||
Ok(_) => self.ok(()),
|
||||
Err(ref err) if err.is_eof() => self.ok(()),
|
||||
Err(err) => Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scan_newline(&mut self) -> Result<Newline> {
|
||||
pub fn scan_newline(&mut self) -> Result<()> {
|
||||
try!(self.skip_opt_space());
|
||||
match try!(self.read_char()) {
|
||||
Some(b';') => {
|
||||
self.skip_comment()
|
||||
}
|
||||
Some(ch) if is_newline(ch) => self.ok(Newline::Real),
|
||||
None => self.ok(Newline::Eof),
|
||||
Some(ch) if is_newline(ch) => self.ok(()),
|
||||
None => self.ok(()),
|
||||
_ => self.err(SyntaxError::ExpectedNewline)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn skip_entry(&mut self) -> Result<Newline> {
|
||||
pub fn skip_entry(&mut self) -> Result<()> {
|
||||
// We try to skip over space, then break if we find a newline
|
||||
// or try to scan a phrase and start again.
|
||||
//
|
||||
@@ -386,8 +393,8 @@ impl<R: io::Read> Stream<R> {
|
||||
try!(self.skip_opt_space());
|
||||
match try!(self.read_char()) {
|
||||
Some(b';') => return self.skip_comment(),
|
||||
Some(ch) if is_newline(ch) => return self.ok(Newline::Real),
|
||||
None => return self.ok(Newline::Eof),
|
||||
Some(ch) if is_newline(ch) => return self.ok(()),
|
||||
None => return self.ok(()),
|
||||
_ => { }
|
||||
}
|
||||
try!(self.scan_phrase(|_| Ok(())));
|
||||
@@ -417,14 +424,6 @@ impl<R: io::Read> Stream<R> {
|
||||
}
|
||||
|
||||
|
||||
//------------ Newline -------------------------------------------------------
|
||||
|
||||
pub enum Newline {
|
||||
Real,
|
||||
Eof
|
||||
}
|
||||
|
||||
|
||||
//------------ Buffer --------------------------------------------------------
|
||||
|
||||
pub struct Buffer<R: io::Read> {
|
||||
@@ -436,6 +435,13 @@ pub struct Buffer<R: io::Read> {
|
||||
curr_pos: Pos
|
||||
}
|
||||
|
||||
impl<R: io::Read> Buffer<R> {
|
||||
pub fn new(reader: R) -> Self {
|
||||
Buffer { reader: reader, buf: Vec::new(), start: 0, curr: 0,
|
||||
start_pos: Pos::new(), curr_pos: Pos::new() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: io::Read> Buffer<R> {
|
||||
pub fn ok(&mut self) {
|
||||
if self.buf.len() == self.curr {
|
||||
@@ -484,6 +490,28 @@ impl<R: io::Read> Buffer<R> {
|
||||
}
|
||||
|
||||
|
||||
//------------ Pos -----------------------------------------------------------
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Pos {
|
||||
line: usize,
|
||||
col: usize
|
||||
}
|
||||
|
||||
impl Pos {
|
||||
pub fn new() -> Pos {
|
||||
Pos { line: 1, col: 1 }
|
||||
}
|
||||
|
||||
pub fn update(&mut self, ch: u8) {
|
||||
match ch {
|
||||
b'\n' => self.line += 1,
|
||||
_ => self.col += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------ Tests for character classes ----------------------------------
|
||||
|
||||
fn is_digit(ch: u8) -> bool {
|
||||
|
||||
+12
-11
@@ -6,26 +6,27 @@ macro_rules! master_types {
|
||||
pub use self::$module::{ $( $rtype ),* };
|
||||
)*
|
||||
|
||||
pub fn scan_into<R, B>(rtype: ::iana::RRType,
|
||||
stream: &mut ::master::Stream<R>,
|
||||
origin: &::bits::name::DNameSlice,
|
||||
target: &mut B)
|
||||
-> ::master::Result<()>
|
||||
where R: ::std::io::Read,
|
||||
B: ::bits::bytes::BytesBuf {
|
||||
pub fn scan<'a, R>(rtype: ::iana::RRType,
|
||||
stream: &mut ::master::Stream<R>,
|
||||
origin: Option<&'a ::bits::name::DNameSlice>)
|
||||
-> ::master::Result<Vec<u8>>
|
||||
where R: ::std::io::Read {
|
||||
use ::bits::rdata::GenericRecordData;
|
||||
|
||||
// First try the generic format for everything.
|
||||
let err = match GenericRecordData::scan_into(stream, target) {
|
||||
Ok(()) => return Ok(()),
|
||||
let err = match GenericRecordData::scan(stream) {
|
||||
Ok(some) => return Ok(some),
|
||||
Err(err) => err
|
||||
};
|
||||
// Now see if we have a master type that can parse this for real.
|
||||
match rtype {
|
||||
$(
|
||||
$(
|
||||
::iana::RRType::$rtype =>
|
||||
$rtype::scan_into(stream, origin, target),
|
||||
::iana::RRType::$rtype => {
|
||||
let mut res = Vec::new();
|
||||
try!($rtype::scan_into(stream, origin, &mut res));
|
||||
Ok(res)
|
||||
}
|
||||
)*
|
||||
)*
|
||||
// We don’t. Good thing we kept the error.
|
||||
|
||||
+34
-34
@@ -53,10 +53,10 @@ macro_rules! dname_type {
|
||||
|target| target.push_dname_compressed(value))
|
||||
}
|
||||
|
||||
pub fn scan_into<R, B>(stream: &mut master::Stream<R>,
|
||||
origin: &DNameSlice, target: &mut B)
|
||||
-> master::Result<()>
|
||||
where R: io::Read, B: BytesBuf {
|
||||
pub fn scan_into<R: io::Read>(stream: &mut master::Stream<R>,
|
||||
origin: Option<&DNameSlice>,
|
||||
target: &mut Vec<u8>)
|
||||
-> master::Result<()> {
|
||||
DNameBuf::scan_into(stream, origin, target)
|
||||
}
|
||||
}
|
||||
@@ -79,6 +79,7 @@ macro_rules! dname_type {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'a> fmt::Display for $target<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.$field.fmt(f)
|
||||
@@ -143,10 +144,10 @@ impl A {
|
||||
try!(parser.parse_u8()))))
|
||||
}
|
||||
|
||||
pub fn scan_into<R, B>(stream: &mut master::Stream<R>,
|
||||
_origin: &DNameSlice, target: &mut B)
|
||||
-> master::Result<()>
|
||||
where R: io::Read, B: BytesBuf {
|
||||
pub fn scan_into<R: io::Read>(stream: &mut master::Stream<R>,
|
||||
_origin: Option<&DNameSlice>,
|
||||
target: &mut Vec<u8>)
|
||||
-> master::Result<()> {
|
||||
stream.scan_str_phrase(|slice| {
|
||||
let addr = try!(Ipv4Addr::from_str(slice));
|
||||
target.push_bytes(&addr.octets()[..]);
|
||||
@@ -172,6 +173,7 @@ impl<'a> RecordData<'a> for A {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl fmt::Display for A {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.addr.fmt(f)
|
||||
@@ -230,10 +232,10 @@ impl<'a> Hinfo<'a> {
|
||||
try!(parser.parse_charstr())))
|
||||
}
|
||||
|
||||
pub fn scan_into<R, B>(stream: &mut master::Stream<R>,
|
||||
_origin: &DNameSlice, target: &mut B)
|
||||
-> master::Result<()>
|
||||
where R: io::Read, B: BytesBuf {
|
||||
pub fn scan_into<R: io::Read>(stream: &mut master::Stream<R>,
|
||||
_origin: Option<&DNameSlice>,
|
||||
target: &mut Vec<u8>)
|
||||
-> master::Result<()> {
|
||||
try!(CharStr::scan_into(stream, target));
|
||||
CharStr::scan_into(stream, target)
|
||||
}
|
||||
@@ -255,7 +257,6 @@ impl<'a> RecordData<'a> for Hinfo<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'a> fmt::Display for Hinfo<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{} {}", self.cpu, self.os)
|
||||
@@ -381,10 +382,10 @@ impl<'a> Minfo<'a> {
|
||||
try!(parser.parse_dname())))
|
||||
}
|
||||
|
||||
pub fn scan_into<R, B>(stream: &mut master::Stream<R>,
|
||||
origin: &DNameSlice, target: &mut B)
|
||||
-> master::Result<()>
|
||||
where R: io::Read, B: BytesBuf {
|
||||
pub fn scan_into<R: io::Read>(stream: &mut master::Stream<R>,
|
||||
origin: Option<&DNameSlice>,
|
||||
target: &mut Vec<u8>)
|
||||
-> master::Result<()> {
|
||||
try!(DNameBuf::scan_into(stream, origin, target));
|
||||
DNameBuf::scan_into(stream, origin, target)
|
||||
}
|
||||
@@ -470,10 +471,10 @@ impl<'a> Mx<'a> {
|
||||
try!(parser.parse_dname())))
|
||||
}
|
||||
|
||||
pub fn scan_into<R, B>(stream: &mut master::Stream<R>,
|
||||
origin: &DNameSlice, target: &mut B)
|
||||
-> master::Result<()>
|
||||
where R: io::Read, B: BytesBuf {
|
||||
pub fn scan_into<R: io::Read>(stream: &mut master::Stream<R>,
|
||||
origin: Option<&DNameSlice>,
|
||||
target: &mut Vec<u8>)
|
||||
-> master::Result<()> {
|
||||
target.push_u16(try!(stream.scan_u16()));
|
||||
DNameBuf::scan_into(stream, origin, target)
|
||||
}
|
||||
@@ -664,10 +665,10 @@ impl<'a> Soa<'a> {
|
||||
try!(parser.parse_u32())))
|
||||
}
|
||||
|
||||
pub fn scan_into<R, B>(stream: &mut master::Stream<R>,
|
||||
origin: &DNameSlice, target: &mut B)
|
||||
-> master::Result<()>
|
||||
where R: io::Read, B: BytesBuf {
|
||||
pub fn scan_into<R: io::Read>(stream: &mut master::Stream<R>,
|
||||
origin: Option<&DNameSlice>,
|
||||
target: &mut Vec<u8>)
|
||||
-> master::Result<()> {
|
||||
try!(DNameBuf::scan_into(stream, origin, target));
|
||||
try!(DNameBuf::scan_into(stream, origin, target));
|
||||
target.push_u32(try!(stream.scan_u32()));
|
||||
@@ -760,10 +761,10 @@ impl<'a> Txt<'a> {
|
||||
Ok(Txt::new(Cow::Borrowed(try!(parser.parse_bytes(len)))))
|
||||
}
|
||||
|
||||
pub fn scan_into<R, B>(stream: &mut master::Stream<R>,
|
||||
_origin: &DNameSlice, target: &mut B)
|
||||
-> master::Result<()>
|
||||
where R: io::Read, B: BytesBuf {
|
||||
pub fn scan_into<R: io::Read>(stream: &mut master::Stream<R>,
|
||||
_origin: Option<&DNameSlice>,
|
||||
target: &mut Vec<u8>)
|
||||
-> master::Result<()> {
|
||||
// XXX Try to get rid of the allocation, please.
|
||||
let text = try!(stream.scan_phrase_copy());
|
||||
let mut text = &text[..];
|
||||
@@ -900,10 +901,10 @@ impl<'a> Wks<'a> {
|
||||
|
||||
/// Scan the master file representation of a WKS record into a target.
|
||||
///
|
||||
pub fn scan_into<R, B>(stream: &mut master::Stream<R>,
|
||||
_origin: &DNameSlice, target: &mut B)
|
||||
-> master::Result<()>
|
||||
where R: io::Read, B: BytesBuf {
|
||||
pub fn scan_into<R: io::Read>(stream: &mut master::Stream<R>,
|
||||
_origin: Option<&DNameSlice>,
|
||||
target: &mut Vec<u8>)
|
||||
-> master::Result<()> {
|
||||
try!(A::scan_into(stream, _origin, target));
|
||||
try!(stream.scan_str_phrase(|s| {
|
||||
if let Some(ent) = ProtoEnt::by_name(s) {
|
||||
@@ -938,7 +939,6 @@ impl<'a> Wks<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'a> RecordData<'a> for Wks<'a> {
|
||||
fn rtype(&self) -> RRType { RRType::Wks }
|
||||
|
||||
|
||||
+13
-13
@@ -45,19 +45,6 @@ impl Aaaa {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn scan_into<R, B>(stream: &mut master::Stream<R>,
|
||||
_origin: &DNameSlice, target: &mut B)
|
||||
-> master::Result<()>
|
||||
where R: io::Read, B: BytesBuf {
|
||||
stream.scan_str_phrase(|slice| {
|
||||
let addr = try!(Ipv6Addr::from_str(slice));
|
||||
for i in addr.segments().iter() {
|
||||
target.push_u16(*i)
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_always<'a, P>(parser: &mut P) -> ParseResult<Self>
|
||||
where P: ParseBytes<'a> {
|
||||
Ok(Aaaa::new(Ipv6Addr::new(try!(parser.parse_u16()),
|
||||
@@ -69,6 +56,19 @@ impl Aaaa {
|
||||
try!(parser.parse_u16()),
|
||||
try!(parser.parse_u16()))))
|
||||
}
|
||||
|
||||
pub fn scan_into<R: io::Read>(stream: &mut master::Stream<R>,
|
||||
_origin: Option<&DNameSlice>,
|
||||
target: &mut Vec<u8>)
|
||||
-> master::Result<()> {
|
||||
stream.scan_str_phrase(|slice| {
|
||||
let addr = try!(Ipv6Addr::from_str(slice));
|
||||
for i in addr.segments().iter() {
|
||||
target.push_u16(*i)
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> RecordData<'a> for Aaaa {
|
||||
|
||||
Reference in New Issue
Block a user