Skip to content

Make it suitable for editing and writing packets #41

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions src/enums.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use {Error};
use rdata::Record;
use rdata::*;

/// The TYPE value according to RFC 1035
///
/// All "EXPERIMENTAL" markers here are from the RFC
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Ord, PartialOrd)]
pub enum Type {
/// a host addresss
A = a::Record::TYPE,
Expand Down Expand Up @@ -50,7 +49,7 @@ pub enum Type {
/// The QTYPE value according to RFC 1035
///
/// All "EXPERIMENTAL" markers here are from the RFC
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Ord, PartialOrd, Hash)]
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
pub enum QueryType {
/// a host addresss
Expand Down Expand Up @@ -99,7 +98,7 @@ pub enum QueryType {


/// The CLASS value according to RFC 1035
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Ord, PartialOrd)]
pub enum Class {
/// the Internet
IN = 1,
Expand All @@ -113,7 +112,7 @@ pub enum Class {
}

/// The QCLASS value according to RFC 1035
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Ord, PartialOrd)]
pub enum QueryClass {
/// the Internet
IN = 1,
Expand All @@ -129,7 +128,7 @@ pub enum QueryClass {
}

/// The OPCODE value according to RFC 1035
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Ord, PartialOrd)]
pub enum Opcode {
/// Normal query
StandardQuery,
Expand All @@ -143,7 +142,7 @@ pub enum Opcode {

quick_error! {
/// The RCODE value according to RFC 1035
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Ord, PartialOrd)]
#[allow(missing_docs)] // names are from spec
pub enum ResponseCode {
NoError
Expand Down
9 changes: 8 additions & 1 deletion src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ mod flag {
}

/// Represents parsed header of the packet
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Ord, PartialOrd)]
#[allow(missing_docs)] // fields are from the spec I think
pub struct Header {
pub id: u16,
Expand Down Expand Up @@ -64,6 +64,13 @@ impl Header {
};
Ok(header)
}

/// Similar to `write`, doing the same
pub fn write_to<W: ::std::io::Write>(&self,mut w: W) -> ::std::io::Result<()> {
let mut buf = [0; 12];
self.write(&mut buf);
w.write_all(&buf)
}
/// Write a header to a buffer slice
///
/// # Panics
Expand Down
5 changes: 3 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ pub mod rdata;

pub use enums::{Type, QueryType, Class, QueryClass, ResponseCode, Opcode};
pub use structs::{Question, ResourceRecord, Packet};
pub use name::{Name};
pub use structs::{QuestionBuf, ResourceRecordBuf, PacketBuf};
pub use name::{Name, write_name_to};
pub use error::{Error};
pub use header::{Header};
pub use rdata::{RData};
pub use rdata::{RData,RDataBuf};
pub use builder::{Builder};
14 changes: 14 additions & 0 deletions src/name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,20 @@ pub struct Name<'a>{
original: &'a [u8],
}

/// Turn name (represented as string) back into a part of a DNS packet
/// no compression is implemented, the packet may be larger than original
/// Each part between dots must be less than 128 bytes, lest panic.
pub fn write_name_to<W: ::std::io::Write>(n: &str, mut w: W) -> ::std::io::Result<()> {
use byteorder::WriteBytesExt;
for l in n.split('.') {
assert!(l.len() < 128);
w.write_u8(l.len() as u8)?;
w.write_all(l.as_bytes())?;
}
w.write_u8(0)?;
Ok(())
}

impl<'a> Name<'a> {
/// Scan the data to get Name object
///
Expand Down
76 changes: 76 additions & 0 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,44 @@ use std::i32;
use byteorder::{BigEndian, ByteOrder};

use {Header, Packet, Error, Question, Name, QueryType, QueryClass};
use {PacketBuf, QuestionBuf, ResourceRecordBuf, write_name_to};
use {Type, Class, ResourceRecord, RData};
use rdata::opt::Record as Opt;

const OPT_RR_START: [u8; 3] = [0, 0, 41];

impl PacketBuf {
/// Get DNS packet as bytes, writing it to specified writer
pub fn write_to<W: ::std::io::Write>(&self,mut w: W) -> ::std::io::Result<()> {
let mut header = self.header.clone();
assert!(self.questions.len() < 65536);
assert!(self.answers.len() < 65536);
assert!(self.nameservers.len() < 65536);
assert!(self.additional.len() < 65536);

header.questions = self.questions.len() as u16;
header.answers = self.answers.len() as u16;
header.nameservers = self.nameservers.len() as u16;
header.additional = self.additional.len() as u16;

header.write_to(&mut w)?;

for q in &self.questions {
q.write_to(&mut w)?;
}
for a in &self.answers {
a.write_to(&mut w)?;
}
for ns in &self.nameservers {
ns.write_to(&mut w)?;
}
for ad in &self.additional {
ad.write_to(&mut w)?;
}
Ok(())
}
}

impl<'a> Packet<'a> {
/// Parse a full DNS Packet and return a structure that has all the
/// data borrowed from the passed buffer.
Expand Down Expand Up @@ -68,6 +101,23 @@ impl<'a> Packet<'a> {
}
}

impl QuestionBuf {
/// Get DNS packet as bytes, writing it to specified writer
pub fn write_to<W: ::std::io::Write>(&self,mut w: W) -> ::std::io::Result<()> {
use byteorder::WriteBytesExt;

let qtype = self.qtype as u16;
let mut qclass = self.qclass as u16;
if self.prefer_unicast { qclass |= 0x8000; }

write_name_to(&self.qname, &mut w)?;
w.write_u16::<BigEndian>(qtype)?;
w.write_u16::<BigEndian>(qclass)?;

Ok(())
}
}

fn parse_qclass_code(value: u16) -> Result<(bool, QueryClass), Error> {
let prefer_unicast = value & 0x8000 == 0x8000;
let qclass_code = value & 0x7FFF;
Expand All @@ -84,6 +134,32 @@ fn parse_class_code(value: u16) -> Result<(bool, Class), Error> {
Ok((is_unique, cls))
}

impl ResourceRecordBuf {
/// Get DNS packet as bytes, writing it to specified writer
pub fn write_to<W: ::std::io::Write>(&self,mut w: W) -> ::std::io::Result<()> {
use byteorder::WriteBytesExt;

let typ = self.data.type_code() as u16;
let mut clscode = self.cls as u16;
if self.multicast_unique { clscode |= 0x8000; }
let ttl = self.ttl;

write_name_to(&self.name, &mut w)?;
w.write_u16::<BigEndian>(typ)?;
w.write_u16::<BigEndian>(clscode)?;
w.write_u32::<BigEndian>(ttl)?;

let mut v = Vec::with_capacity(16);
self.data.write_to(&mut v)?;

assert!(v.len() < 65536);
w.write_u16::<BigEndian>(v.len() as u16)?;
w.write_all(&v)?;

Ok(())
}
}

// Generic function to parse answer, nameservers, and additional records.
fn parse_record<'a>(data: &'a [u8], offset: &mut usize) -> Result<ResourceRecord<'a>, Error> {
let name = try!(Name::scan(&data[*offset..], data));
Expand Down
12 changes: 10 additions & 2 deletions src/rdata/a.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,21 @@ use std::net::Ipv4Addr;
use Error;
use byteorder::{BigEndian, ByteOrder};

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Ord, PartialOrd, Hash)]
pub struct Record(pub Ipv4Addr);

impl<'a> super::Record<'a> for Record {
impl Record {
pub fn write_to<W: ::std::io::Write>(&self,mut w: W) -> ::std::io::Result<()> {
w.write_all(&self.0.octets())?;
Ok(())
}
}

impl super::RecordType for Record {
const TYPE: isize = 1;
}

impl<'a> super::Record<'a> for Record {
fn parse(rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
if rdata.len() != 4 {
return Err(Error::WrongRdataLength);
Expand Down
12 changes: 10 additions & 2 deletions src/rdata/aaaa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,21 @@ use std::net::Ipv6Addr;
use Error;
use byteorder::{BigEndian, ByteOrder};

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Ord, PartialOrd, Hash)]
pub struct Record(pub Ipv6Addr);

impl<'a> super::Record<'a> for Record {
impl Record {
pub fn write_to<W: ::std::io::Write>(&self,mut w: W) -> ::std::io::Result<()> {
w.write_all(&self.0.octets())?;
Ok(())
}
}

impl super::RecordType for Record {
const TYPE: isize = 28;
}

impl<'a> super::Record<'a> for Record {
fn parse(rdata: &'a [u8], _record: &'a [u8]) -> super::RDataResult<'a> {
if rdata.len() != 16 {
return Err(Error::WrongRdataLength);
Expand Down
5 changes: 3 additions & 2 deletions src/rdata/all.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Record;

impl<'a> super::Record<'a> for Record {

impl super::RecordType for Record {
const TYPE: isize = 255;
}

impl<'a> super::Record<'a> for Record {
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
unimplemented!();
}
Expand Down
4 changes: 3 additions & 1 deletion src/rdata/axfr.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Record;

impl super::RecordType for Record {
const TYPE: isize = 252;
}
impl<'a> super::Record<'a> for Record {

const TYPE: isize = 252;

fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
unimplemented!();
Expand Down
24 changes: 22 additions & 2 deletions src/rdata/cname.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,36 @@ use Name;
#[derive(Debug, Clone, Copy)]
pub struct Record<'a>(pub Name<'a>);

#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct RecordBuf(String);

impl<'a> Record<'a> {
pub fn deep_clone(&self) -> RecordBuf {
RecordBuf(self.to_string())
}
}

impl RecordBuf {
pub fn write_to<W: ::std::io::Write>(&self,w: W) -> ::std::io::Result<()> {
super::super::write_name_to(&self.0, w)?;
Ok(())
}
}

impl<'a> ToString for Record<'a> {
#[inline]
fn to_string(&self) -> String {
self.0.to_string()
}
}

impl<'a> super::RecordType for Record<'a> {
const TYPE: isize = 5;
}
impl super::RecordType for RecordBuf {
const TYPE: isize = 5;
}
impl<'a> super::Record<'a> for Record<'a> {

const TYPE: isize = 5;

fn parse(rdata: &'a [u8], original: &'a [u8]) -> super::RDataResult<'a> {
let name = Name::scan(rdata, original)?;
Expand Down
4 changes: 3 additions & 1 deletion src/rdata/hinfo.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Record;

impl super::RecordType for Record {
const TYPE: isize = 13;
}
impl<'a> super::Record<'a> for Record {

const TYPE: isize = 13;

fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
unimplemented!();
Expand Down
4 changes: 3 additions & 1 deletion src/rdata/maila.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Record;

impl super::RecordType for Record {
const TYPE: isize = 254;
}
impl<'a> super::Record<'a> for Record {

const TYPE: isize = 254;

fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
unimplemented!();
Expand Down
4 changes: 3 additions & 1 deletion src/rdata/mailb.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Record;

impl super::RecordType for Record {
const TYPE: isize = 253;
}
impl<'a> super::Record<'a> for Record {

const TYPE: isize = 253;

fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
unimplemented!();
Expand Down
4 changes: 3 additions & 1 deletion src/rdata/mb.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Record;

impl super::RecordType for Record {
const TYPE: isize = 7;
}
impl<'a> super::Record<'a> for Record {

const TYPE: isize = 7;

fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
unimplemented!();
Expand Down
4 changes: 3 additions & 1 deletion src/rdata/mf.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Record;

impl super::RecordType for Record {
const TYPE: isize = 4;
}
impl<'a> super::Record<'a> for Record {

const TYPE: isize = 4;

fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
unimplemented!();
Expand Down
Loading