summaryrefslogtreecommitdiffstats
path: root/third_party/rust/dns-parser/src/rdata
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/dns-parser/src/rdata')
-rw-r--r--third_party/rust/dns-parser/src/rdata/a.rs21
-rw-r--r--third_party/rust/dns-parser/src/rdata/aaaa.rs85
-rw-r--r--third_party/rust/dns-parser/src/rdata/all.rs11
-rw-r--r--third_party/rust/dns-parser/src/rdata/axfr.rs11
-rw-r--r--third_party/rust/dns-parser/src/rdata/cname.rs102
-rw-r--r--third_party/rust/dns-parser/src/rdata/hinfo.rs11
-rw-r--r--third_party/rust/dns-parser/src/rdata/maila.rs11
-rw-r--r--third_party/rust/dns-parser/src/rdata/mailb.rs11
-rw-r--r--third_party/rust/dns-parser/src/rdata/mb.rs11
-rw-r--r--third_party/rust/dns-parser/src/rdata/mf.rs11
-rw-r--r--third_party/rust/dns-parser/src/rdata/mg.rs11
-rw-r--r--third_party/rust/dns-parser/src/rdata/minfo.rs11
-rw-r--r--third_party/rust/dns-parser/src/rdata/mod.rs83
-rw-r--r--third_party/rust/dns-parser/src/rdata/mr.rs11
-rw-r--r--third_party/rust/dns-parser/src/rdata/mx.rs92
-rw-r--r--third_party/rust/dns-parser/src/rdata/ns.rs88
-rw-r--r--third_party/rust/dns-parser/src/rdata/nsec.rs11
-rw-r--r--third_party/rust/dns-parser/src/rdata/null.rs11
-rw-r--r--third_party/rust/dns-parser/src/rdata/opt.rs18
-rw-r--r--third_party/rust/dns-parser/src/rdata/ptr.rs74
-rw-r--r--third_party/rust/dns-parser/src/rdata/soa.rs101
-rw-r--r--third_party/rust/dns-parser/src/rdata/srv.rs102
-rw-r--r--third_party/rust/dns-parser/src/rdata/txt.rs125
-rw-r--r--third_party/rust/dns-parser/src/rdata/wks.rs11
24 files changed, 1034 insertions, 0 deletions
diff --git a/third_party/rust/dns-parser/src/rdata/a.rs b/third_party/rust/dns-parser/src/rdata/a.rs
new file mode 100644
index 0000000000..f4196d5ac2
--- /dev/null
+++ b/third_party/rust/dns-parser/src/rdata/a.rs
@@ -0,0 +1,21 @@
+use std::net::Ipv4Addr;
+
+use Error;
+use byteorder::{BigEndian, ByteOrder};
+
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub struct Record(pub Ipv4Addr);
+
+impl<'a> super::Record<'a> for Record {
+
+ const TYPE: isize = 1;
+
+ fn parse(rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
+ if rdata.len() != 4 {
+ return Err(Error::WrongRdataLength);
+ }
+ let address = Ipv4Addr::from(BigEndian::read_u32(rdata));
+ let record = Record(address);
+ Ok(super::RData::A(record))
+ }
+}
diff --git a/third_party/rust/dns-parser/src/rdata/aaaa.rs b/third_party/rust/dns-parser/src/rdata/aaaa.rs
new file mode 100644
index 0000000000..e59937a525
--- /dev/null
+++ b/third_party/rust/dns-parser/src/rdata/aaaa.rs
@@ -0,0 +1,85 @@
+use std::net::Ipv6Addr;
+
+use Error;
+use byteorder::{BigEndian, ByteOrder};
+
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub struct Record(pub Ipv6Addr);
+
+impl<'a> super::Record<'a> for Record {
+
+ const TYPE: isize = 28;
+
+ fn parse(rdata: &'a [u8], _record: &'a [u8]) -> super::RDataResult<'a> {
+ if rdata.len() != 16 {
+ return Err(Error::WrongRdataLength);
+ }
+ let address = Ipv6Addr::new(
+ BigEndian::read_u16(&rdata[0..2]),
+ BigEndian::read_u16(&rdata[2..4]),
+ BigEndian::read_u16(&rdata[4..6]),
+ BigEndian::read_u16(&rdata[6..8]),
+ BigEndian::read_u16(&rdata[8..10]),
+ BigEndian::read_u16(&rdata[10..12]),
+ BigEndian::read_u16(&rdata[12..14]),
+ BigEndian::read_u16(&rdata[14..16]),
+ );
+ let record = Record(address);
+ Ok(super::RData::AAAA(record))
+ }
+}
+
+#[cfg(test)]
+mod test {
+
+ use {Packet, Header};
+ use Opcode::*;
+ use ResponseCode::NoError;
+ use QueryType as QT;
+ use QueryClass as QC;
+ use Class as C;
+ use RData;
+ use super::*;
+
+ #[test]
+ fn parse_response() {
+ let response = b"\xa9\xd9\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\x06\
+ google\x03com\x00\x00\x1c\x00\x01\xc0\x0c\x00\x1c\x00\x01\x00\x00\
+ \x00\x8b\x00\x10*\x00\x14P@\t\x08\x12\x00\x00\x00\x00\x00\x00 \x0e";
+
+ let packet = Packet::parse(response).unwrap();
+ assert_eq!(packet.header, Header {
+ id: 43481,
+ query: false,
+ opcode: StandardQuery,
+ authoritative: false,
+ truncated: false,
+ recursion_desired: true,
+ recursion_available: true,
+ authenticated_data: false,
+ checking_disabled: false,
+ response_code: NoError,
+ questions: 1,
+ answers: 1,
+ nameservers: 0,
+ additional: 0,
+ });
+
+ assert_eq!(packet.questions.len(), 1);
+ assert_eq!(packet.questions[0].qtype, QT::AAAA);
+ assert_eq!(packet.questions[0].qclass, QC::IN);
+ assert_eq!(&packet.questions[0].qname.to_string()[..], "google.com");
+ assert_eq!(packet.answers.len(), 1);
+ assert_eq!(&packet.answers[0].name.to_string()[..], "google.com");
+ assert_eq!(packet.answers[0].cls, C::IN);
+ assert_eq!(packet.answers[0].ttl, 139);
+ match packet.answers[0].data {
+ RData::AAAA(addr) => {
+ assert_eq!(addr.0, Ipv6Addr::new(
+ 0x2A00, 0x1450, 0x4009, 0x812, 0, 0, 0, 0x200e)
+ );
+ }
+ ref x => panic!("Wrong rdata {:?}", x),
+ }
+ }
+}
diff --git a/third_party/rust/dns-parser/src/rdata/all.rs b/third_party/rust/dns-parser/src/rdata/all.rs
new file mode 100644
index 0000000000..106c91b089
--- /dev/null
+++ b/third_party/rust/dns-parser/src/rdata/all.rs
@@ -0,0 +1,11 @@
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub struct Record;
+
+impl<'a> super::Record<'a> for Record {
+
+ const TYPE: isize = 255;
+
+ fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
+ unimplemented!();
+ }
+}
diff --git a/third_party/rust/dns-parser/src/rdata/axfr.rs b/third_party/rust/dns-parser/src/rdata/axfr.rs
new file mode 100644
index 0000000000..b48dc1ae24
--- /dev/null
+++ b/third_party/rust/dns-parser/src/rdata/axfr.rs
@@ -0,0 +1,11 @@
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub struct Record;
+
+impl<'a> super::Record<'a> for Record {
+
+ const TYPE: isize = 252;
+
+ fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
+ unimplemented!();
+ }
+}
diff --git a/third_party/rust/dns-parser/src/rdata/cname.rs b/third_party/rust/dns-parser/src/rdata/cname.rs
new file mode 100644
index 0000000000..0dcb46952f
--- /dev/null
+++ b/third_party/rust/dns-parser/src/rdata/cname.rs
@@ -0,0 +1,102 @@
+use Name;
+
+#[derive(Debug, Clone, Copy)]
+pub struct Record<'a>(pub Name<'a>);
+
+impl<'a> ToString for Record<'a> {
+ #[inline]
+ fn to_string(&self) -> String {
+ self.0.to_string()
+ }
+}
+
+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)?;
+ let record = Record(name);
+ Ok(super::RData::CNAME(record))
+ }
+}
+
+#[cfg(test)]
+mod test {
+
+ use std::net::Ipv4Addr;
+ use {Packet, Header};
+ use Opcode::*;
+ use ResponseCode::NoError;
+ use QueryType as QT;
+ use QueryClass as QC;
+ use Class as C;
+ use RData;
+
+ #[test]
+ fn parse_response() {
+ let response = b"\xfc\x9d\x81\x80\x00\x01\x00\x06\x00\x02\x00\x02\x03\
+ cdn\x07sstatic\x03net\x00\x00\x01\x00\x01\xc0\x0c\x00\x05\x00\x01\
+ \x00\x00\x00f\x00\x02\xc0\x10\xc0\x10\x00\x01\x00\x01\x00\x00\x00\
+ f\x00\x04h\x10g\xcc\xc0\x10\x00\x01\x00\x01\x00\x00\x00f\x00\x04h\
+ \x10k\xcc\xc0\x10\x00\x01\x00\x01\x00\x00\x00f\x00\x04h\x10h\xcc\
+ \xc0\x10\x00\x01\x00\x01\x00\x00\x00f\x00\x04h\x10j\xcc\xc0\x10\
+ \x00\x01\x00\x01\x00\x00\x00f\x00\x04h\x10i\xcc\xc0\x10\x00\x02\
+ \x00\x01\x00\x00\x99L\x00\x0b\x08cf-dns02\xc0\x10\xc0\x10\x00\x02\
+ \x00\x01\x00\x00\x99L\x00\x0b\x08cf-dns01\xc0\x10\xc0\xa2\x00\x01\
+ \x00\x01\x00\x00\x99L\x00\x04\xad\xf5:5\xc0\x8b\x00\x01\x00\x01\x00\
+ \x00\x99L\x00\x04\xad\xf5;\x04";
+
+ let packet = Packet::parse(response).unwrap();
+ assert_eq!(packet.header, Header {
+ id: 64669,
+ query: false,
+ opcode: StandardQuery,
+ authoritative: false,
+ truncated: false,
+ recursion_desired: true,
+ recursion_available: true,
+ authenticated_data: false,
+ checking_disabled: false,
+ response_code: NoError,
+ questions: 1,
+ answers: 6,
+ nameservers: 2,
+ additional: 2,
+ });
+
+ assert_eq!(packet.questions.len(), 1);
+ assert_eq!(packet.questions[0].qtype, QT::A);
+ assert_eq!(packet.questions[0].qclass, QC::IN);
+ assert_eq!(&packet.questions[0].qname.to_string()[..], "cdn.sstatic.net");
+ assert_eq!(packet.answers.len(), 6);
+ assert_eq!(&packet.answers[0].name.to_string()[..], "cdn.sstatic.net");
+ assert_eq!(packet.answers[0].cls, C::IN);
+ assert_eq!(packet.answers[0].ttl, 102);
+ match packet.answers[0].data {
+ RData::CNAME(cname) => {
+ assert_eq!(&cname.0.to_string(), "sstatic.net");
+ }
+ ref x => panic!("Wrong rdata {:?}", x),
+ }
+
+ let ips = vec![
+ Ipv4Addr::new(104, 16, 103, 204),
+ Ipv4Addr::new(104, 16, 107, 204),
+ Ipv4Addr::new(104, 16, 104, 204),
+ Ipv4Addr::new(104, 16, 106, 204),
+ Ipv4Addr::new(104, 16, 105, 204),
+ ];
+ for i in 1..6 {
+ assert_eq!(&packet.answers[i].name.to_string()[..], "sstatic.net");
+ assert_eq!(packet.answers[i].cls, C::IN);
+ assert_eq!(packet.answers[i].ttl, 102);
+ match packet.answers[i].data {
+ RData::A(addr) => {
+ assert_eq!(addr.0, ips[i-1]);
+ }
+ ref x => panic!("Wrong rdata {:?}", x),
+ }
+ }
+ }
+}
diff --git a/third_party/rust/dns-parser/src/rdata/hinfo.rs b/third_party/rust/dns-parser/src/rdata/hinfo.rs
new file mode 100644
index 0000000000..6ee160bb86
--- /dev/null
+++ b/third_party/rust/dns-parser/src/rdata/hinfo.rs
@@ -0,0 +1,11 @@
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub struct Record;
+
+impl<'a> super::Record<'a> for Record {
+
+ const TYPE: isize = 13;
+
+ fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
+ unimplemented!();
+ }
+}
diff --git a/third_party/rust/dns-parser/src/rdata/maila.rs b/third_party/rust/dns-parser/src/rdata/maila.rs
new file mode 100644
index 0000000000..ab1166cf31
--- /dev/null
+++ b/third_party/rust/dns-parser/src/rdata/maila.rs
@@ -0,0 +1,11 @@
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub struct Record;
+
+impl<'a> super::Record<'a> for Record {
+
+ const TYPE: isize = 254;
+
+ fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
+ unimplemented!();
+ }
+}
diff --git a/third_party/rust/dns-parser/src/rdata/mailb.rs b/third_party/rust/dns-parser/src/rdata/mailb.rs
new file mode 100644
index 0000000000..9f043c60c3
--- /dev/null
+++ b/third_party/rust/dns-parser/src/rdata/mailb.rs
@@ -0,0 +1,11 @@
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub struct Record;
+
+impl<'a> super::Record<'a> for Record {
+
+ const TYPE: isize = 253;
+
+ fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
+ unimplemented!();
+ }
+}
diff --git a/third_party/rust/dns-parser/src/rdata/mb.rs b/third_party/rust/dns-parser/src/rdata/mb.rs
new file mode 100644
index 0000000000..d14e7b4fc5
--- /dev/null
+++ b/third_party/rust/dns-parser/src/rdata/mb.rs
@@ -0,0 +1,11 @@
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub struct Record;
+
+impl<'a> super::Record<'a> for Record {
+
+ const TYPE: isize = 7;
+
+ fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
+ unimplemented!();
+ }
+}
diff --git a/third_party/rust/dns-parser/src/rdata/mf.rs b/third_party/rust/dns-parser/src/rdata/mf.rs
new file mode 100644
index 0000000000..11c935d9f7
--- /dev/null
+++ b/third_party/rust/dns-parser/src/rdata/mf.rs
@@ -0,0 +1,11 @@
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub struct Record;
+
+impl<'a> super::Record<'a> for Record {
+
+ const TYPE: isize = 4;
+
+ fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
+ unimplemented!();
+ }
+}
diff --git a/third_party/rust/dns-parser/src/rdata/mg.rs b/third_party/rust/dns-parser/src/rdata/mg.rs
new file mode 100644
index 0000000000..4fce456b7d
--- /dev/null
+++ b/third_party/rust/dns-parser/src/rdata/mg.rs
@@ -0,0 +1,11 @@
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub struct Record;
+
+impl<'a> super::Record<'a> for Record {
+
+ const TYPE: isize = 8;
+
+ fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
+ unimplemented!();
+ }
+}
diff --git a/third_party/rust/dns-parser/src/rdata/minfo.rs b/third_party/rust/dns-parser/src/rdata/minfo.rs
new file mode 100644
index 0000000000..29b3a459b2
--- /dev/null
+++ b/third_party/rust/dns-parser/src/rdata/minfo.rs
@@ -0,0 +1,11 @@
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub struct Record;
+
+impl<'a> super::Record<'a> for Record {
+
+ const TYPE: isize = 14;
+
+ fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
+ unimplemented!();
+ }
+}
diff --git a/third_party/rust/dns-parser/src/rdata/mod.rs b/third_party/rust/dns-parser/src/rdata/mod.rs
new file mode 100644
index 0000000000..72df27c232
--- /dev/null
+++ b/third_party/rust/dns-parser/src/rdata/mod.rs
@@ -0,0 +1,83 @@
+//! Data types and methods for handling the RData field
+
+#![allow(missing_docs)] // resource records are pretty self-descriptive
+
+pub mod a;
+pub mod aaaa;
+pub mod all;
+pub mod axfr;
+pub mod cname;
+pub mod hinfo;
+pub mod maila;
+pub mod mailb;
+pub mod mb;
+pub mod mf;
+pub mod mg;
+pub mod minfo;
+pub mod mr;
+pub mod mx;
+pub mod ns;
+pub mod nsec;
+pub mod null;
+pub mod opt;
+pub mod ptr;
+pub mod soa;
+pub mod srv;
+pub mod txt;
+pub mod wks;
+
+use {Type, Error};
+
+pub use self::a::Record as A;
+pub use self::aaaa::Record as Aaaa;
+pub use self::cname::Record as Cname;
+pub use self::mx::Record as Mx;
+pub use self::ns::Record as Ns;
+pub use self::nsec::Record as Nsec;
+pub use self::opt::Record as Opt;
+pub use self::ptr::Record as Ptr;
+pub use self::soa::Record as Soa;
+pub use self::srv::Record as Srv;
+pub use self::txt::Record as Txt;
+
+pub type RDataResult<'a> = Result<RData<'a>, Error>;
+
+/// The enumeration that represents known types of DNS resource records data
+#[derive(Debug)]
+pub enum RData<'a> {
+ A(A),
+ AAAA(Aaaa),
+ CNAME(Cname<'a>),
+ MX(Mx<'a>),
+ NS(Ns<'a>),
+ PTR(Ptr<'a>),
+ SOA(Soa<'a>),
+ SRV(Srv<'a>),
+ TXT(Txt<'a>),
+ /// Anything that can't be parsed yet
+ Unknown(&'a [u8]),
+}
+
+pub (crate) trait Record<'a> {
+ const TYPE: isize;
+
+ fn parse(rdata: &'a [u8], original: &'a [u8]) -> RDataResult<'a>;
+}
+
+impl<'a> RData<'a> {
+ /// Parse an RR data and return RData enumeration
+ pub fn parse(typ: Type, rdata: &'a [u8], original: &'a [u8]) -> RDataResult<'a> {
+ match typ {
+ Type::A => A::parse(rdata, original),
+ Type::AAAA => Aaaa::parse(rdata, original),
+ Type::CNAME => Cname::parse(rdata, original),
+ Type::NS => Ns::parse(rdata, original),
+ Type::MX => Mx::parse(rdata, original),
+ Type::PTR => Ptr::parse(rdata, original),
+ Type::SOA => Soa::parse(rdata, original),
+ Type::SRV => Srv::parse(rdata, original),
+ Type::TXT => Txt::parse(rdata, original),
+ _ => Ok(RData::Unknown(rdata)),
+ }
+ }
+}
diff --git a/third_party/rust/dns-parser/src/rdata/mr.rs b/third_party/rust/dns-parser/src/rdata/mr.rs
new file mode 100644
index 0000000000..e313372c4a
--- /dev/null
+++ b/third_party/rust/dns-parser/src/rdata/mr.rs
@@ -0,0 +1,11 @@
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub struct Record;
+
+impl<'a> super::Record<'a> for Record {
+
+ const TYPE: isize = 9;
+
+ fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
+ unimplemented!();
+ }
+}
diff --git a/third_party/rust/dns-parser/src/rdata/mx.rs b/third_party/rust/dns-parser/src/rdata/mx.rs
new file mode 100644
index 0000000000..33c5c41dfc
--- /dev/null
+++ b/third_party/rust/dns-parser/src/rdata/mx.rs
@@ -0,0 +1,92 @@
+use {Name, Error};
+use byteorder::{BigEndian, ByteOrder};
+
+#[derive(Debug, Clone, Copy)]
+pub struct Record<'a> {
+ pub preference: u16,
+ pub exchange: Name<'a>,
+}
+
+impl<'a> super::Record<'a> for Record<'a> {
+
+ const TYPE: isize = 15;
+
+ fn parse(rdata: &'a [u8], original: &'a [u8]) -> super::RDataResult<'a> {
+ if rdata.len() < 3 {
+ return Err(Error::WrongRdataLength);
+ }
+ let record = Record {
+ preference: BigEndian::read_u16(&rdata[..2]),
+ exchange: Name::scan(&rdata[2..], original)?,
+ };
+ Ok(super::RData::MX(record))
+ }
+}
+
+#[cfg(test)]
+mod test {
+
+ use {Packet, Header};
+ use Opcode::*;
+ use ResponseCode::NoError;
+ use QueryType as QT;
+ use QueryClass as QC;
+ use Class as C;
+ use RData;
+ use super::*;
+
+ #[test]
+ fn parse_response() {
+ let response = b"\xe3\xe8\x81\x80\x00\x01\x00\x05\x00\x00\x00\x00\
+ \x05gmail\x03com\x00\x00\x0f\x00\x01\xc0\x0c\x00\x0f\x00\x01\
+ \x00\x00\x04|\x00\x1b\x00\x05\rgmail-smtp-in\x01l\x06google\xc0\
+ \x12\xc0\x0c\x00\x0f\x00\x01\x00\x00\x04|\x00\t\x00\
+ \n\x04alt1\xc0)\xc0\x0c\x00\x0f\x00\x01\x00\x00\x04|\
+ \x00\t\x00(\x04alt4\xc0)\xc0\x0c\x00\x0f\x00\x01\x00\
+ \x00\x04|\x00\t\x00\x14\x04alt2\xc0)\xc0\x0c\x00\x0f\
+ \x00\x01\x00\x00\x04|\x00\t\x00\x1e\x04alt3\xc0)";
+ let packet = Packet::parse(response).unwrap();
+ assert_eq!(packet.header, Header {
+ id: 58344,
+ query: false,
+ opcode: StandardQuery,
+ authoritative: false,
+ truncated: false,
+ recursion_desired: true,
+ recursion_available: true,
+ authenticated_data: false,
+ checking_disabled: false,
+ response_code: NoError,
+ questions: 1,
+ answers: 5,
+ nameservers: 0,
+ additional: 0,
+ });
+ assert_eq!(packet.questions.len(), 1);
+ assert_eq!(packet.questions[0].qtype, QT::MX);
+ assert_eq!(packet.questions[0].qclass, QC::IN);
+ assert_eq!(&packet.questions[0].qname.to_string()[..],
+ "gmail.com");
+ assert_eq!(packet.answers.len(), 5);
+ let items = vec![
+ ( 5, "gmail-smtp-in.l.google.com"),
+ (10, "alt1.gmail-smtp-in.l.google.com"),
+ (40, "alt4.gmail-smtp-in.l.google.com"),
+ (20, "alt2.gmail-smtp-in.l.google.com"),
+ (30, "alt3.gmail-smtp-in.l.google.com"),
+ ];
+ for i in 0..5 {
+ assert_eq!(&packet.answers[i].name.to_string()[..],
+ "gmail.com");
+ assert_eq!(packet.answers[i].cls, C::IN);
+ assert_eq!(packet.answers[i].ttl, 1148);
+ match *&packet.answers[i].data {
+ RData::MX( Record { preference, exchange }) => {
+ assert_eq!(preference, items[i].0);
+ assert_eq!(exchange.to_string(), (items[i].1).to_string());
+ }
+ ref x => panic!("Wrong rdata {:?}", x),
+ }
+ }
+ }
+}
diff --git a/third_party/rust/dns-parser/src/rdata/ns.rs b/third_party/rust/dns-parser/src/rdata/ns.rs
new file mode 100644
index 0000000000..42a2f29ab1
--- /dev/null
+++ b/third_party/rust/dns-parser/src/rdata/ns.rs
@@ -0,0 +1,88 @@
+use Name;
+
+#[derive(Debug, Clone, Copy)]
+pub struct Record<'a>(pub Name<'a>);
+
+impl<'a> ToString for Record<'a> {
+ #[inline]
+ fn to_string(&self) -> String {
+ self.0.to_string()
+ }
+}
+
+impl<'a> super::Record<'a> for Record<'a> {
+
+ const TYPE: isize = 2;
+
+ fn parse(rdata: &'a [u8], original: &'a [u8]) -> super::RDataResult<'a> {
+ let name = Name::scan(rdata, original)?;
+ let record = Record(name);
+ Ok(super::RData::NS(record))
+ }
+}
+
+#[cfg(test)]
+mod test {
+
+ use {Packet, Header};
+ use Opcode::*;
+ use ResponseCode::NoError;
+ use QueryType as QT;
+ use QueryClass as QC;
+ use Class as C;
+ use RData;
+
+ #[test]
+ fn parse_response() {
+ let response = b"\x4a\xf0\x81\x80\x00\x01\x00\x01\x00\x01\x00\x00\
+ \x03www\x05skype\x03com\x00\x00\x01\x00\x01\
+ \xc0\x0c\x00\x05\x00\x01\x00\x00\x0e\x10\
+ \x00\x1c\x07\x6c\x69\x76\x65\x63\x6d\x73\x0e\x74\
+ \x72\x61\x66\x66\x69\x63\x6d\x61\x6e\x61\x67\x65\
+ \x72\x03\x6e\x65\x74\x00\
+ \xc0\x42\x00\x02\x00\x01\x00\x01\xd5\xd3\x00\x11\
+ \x01\x67\x0c\x67\x74\x6c\x64\x2d\x73\x65\x72\x76\x65\x72\x73\
+ \xc0\x42";
+ let packet = Packet::parse(response).unwrap();
+ assert_eq!(packet.header, Header {
+ id: 19184,
+ query: false,
+ opcode: StandardQuery,
+ authoritative: false,
+ truncated: false,
+ recursion_desired: true,
+ recursion_available: true,
+ authenticated_data: false,
+ checking_disabled: false,
+ response_code: NoError,
+ questions: 1,
+ answers: 1,
+ nameservers: 1,
+ additional: 0,
+ });
+ assert_eq!(packet.questions.len(), 1);
+ assert_eq!(packet.questions[0].qtype, QT::A);
+ assert_eq!(packet.questions[0].qclass, QC::IN);
+ assert_eq!(&packet.questions[0].qname.to_string()[..], "www.skype.com");
+ assert_eq!(packet.answers.len(), 1);
+ assert_eq!(&packet.answers[0].name.to_string()[..], "www.skype.com");
+ assert_eq!(packet.answers[0].cls, C::IN);
+ assert_eq!(packet.answers[0].ttl, 3600);
+ match packet.answers[0].data {
+ RData::CNAME(cname) => {
+ assert_eq!(&cname.0.to_string()[..], "livecms.trafficmanager.net");
+ }
+ ref x => panic!("Wrong rdata {:?}", x),
+ }
+ assert_eq!(packet.nameservers.len(), 1);
+ assert_eq!(&packet.nameservers[0].name.to_string()[..], "net");
+ assert_eq!(packet.nameservers[0].cls, C::IN);
+ assert_eq!(packet.nameservers[0].ttl, 120275);
+ match packet.nameservers[0].data {
+ RData::NS(ns) => {
+ assert_eq!(&ns.0.to_string()[..], "g.gtld-servers.net");
+ }
+ ref x => panic!("Wrong rdata {:?}", x),
+ }
+ }
+}
diff --git a/third_party/rust/dns-parser/src/rdata/nsec.rs b/third_party/rust/dns-parser/src/rdata/nsec.rs
new file mode 100644
index 0000000000..354c512273
--- /dev/null
+++ b/third_party/rust/dns-parser/src/rdata/nsec.rs
@@ -0,0 +1,11 @@
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub struct Record;
+
+impl<'a> super::Record<'a> for Record {
+
+ const TYPE: isize = 47;
+
+ fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
+ unimplemented!();
+ }
+}
diff --git a/third_party/rust/dns-parser/src/rdata/null.rs b/third_party/rust/dns-parser/src/rdata/null.rs
new file mode 100644
index 0000000000..b3bfcd35ee
--- /dev/null
+++ b/third_party/rust/dns-parser/src/rdata/null.rs
@@ -0,0 +1,11 @@
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub struct Record;
+
+impl<'a> super::Record<'a> for Record {
+
+ const TYPE: isize = 10;
+
+ fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
+ unimplemented!();
+ }
+}
diff --git a/third_party/rust/dns-parser/src/rdata/opt.rs b/third_party/rust/dns-parser/src/rdata/opt.rs
new file mode 100644
index 0000000000..694d393440
--- /dev/null
+++ b/third_party/rust/dns-parser/src/rdata/opt.rs
@@ -0,0 +1,18 @@
+/// RFC 6891 OPT RR
+#[derive(Debug)]
+pub struct Record<'a> {
+ pub udp: u16,
+ pub extrcode: u8,
+ pub version: u8,
+ pub flags: u16,
+ pub data: super::RData<'a>,
+}
+
+impl<'a> super::Record<'a> for Record<'a> {
+
+ const TYPE: isize = 41;
+
+ fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
+ unimplemented!();
+ }
+}
diff --git a/third_party/rust/dns-parser/src/rdata/ptr.rs b/third_party/rust/dns-parser/src/rdata/ptr.rs
new file mode 100644
index 0000000000..315c3795a8
--- /dev/null
+++ b/third_party/rust/dns-parser/src/rdata/ptr.rs
@@ -0,0 +1,74 @@
+use Name;
+
+#[derive(Debug, Clone, Copy)]
+pub struct Record<'a>(pub Name<'a>);
+
+impl<'a> ToString for Record<'a> {
+ #[inline]
+ fn to_string(&self) -> String {
+ self.0.to_string()
+ }
+}
+
+impl<'a> super::Record<'a> for Record<'a> {
+
+ const TYPE: isize = 12;
+
+ fn parse(rdata: &'a [u8], original: &'a [u8]) -> super::RDataResult<'a> {
+ let name = Name::scan(rdata, original)?;
+ let record = Record(name);
+ Ok(super::RData::PTR(record))
+ }
+}
+
+#[cfg(test)]
+mod test {
+
+ use {Packet, Header};
+ use Opcode::*;
+ use ResponseCode::NoError;
+ use QueryType as QT;
+ use QueryClass as QC;
+ use Class as C;
+ use RData;
+
+ #[test]
+ fn parse_response() {
+ let response = b"\x53\xd6\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\
+ \x0269\x0293\x0275\x0272\x07in-addr\x04arpa\x00\
+ \x00\x0c\x00\x01\
+ \xc0\x0c\x00\x0c\x00\x01\x00\x01\x51\x80\x00\x1e\
+ \x10pool-72-75-93-69\x07verizon\x03net\x00";
+ let packet = Packet::parse(response).unwrap();
+ assert_eq!(packet.header, Header {
+ id: 21462,
+ query: false,
+ opcode: StandardQuery,
+ authoritative: false,
+ truncated: false,
+ recursion_desired: true,
+ recursion_available: true,
+ authenticated_data: false,
+ checking_disabled: false,
+ response_code: NoError,
+ questions: 1,
+ answers: 1,
+ nameservers: 0,
+ additional: 0,
+ });
+ assert_eq!(packet.questions.len(), 1);
+ assert_eq!(packet.questions[0].qtype, QT::PTR);
+ assert_eq!(packet.questions[0].qclass, QC::IN);
+ assert_eq!(&packet.questions[0].qname.to_string()[..], "69.93.75.72.in-addr.arpa");
+ assert_eq!(packet.answers.len(), 1);
+ assert_eq!(&packet.answers[0].name.to_string()[..], "69.93.75.72.in-addr.arpa");
+ assert_eq!(packet.answers[0].cls, C::IN);
+ assert_eq!(packet.answers[0].ttl, 86400);
+ match packet.answers[0].data {
+ RData::PTR(name) => {
+ assert_eq!(&name.0.to_string()[..], "pool-72-75-93-69.verizon.net");
+ }
+ ref x => panic!("Wrong rdata {:?}", x),
+ }
+ }
+}
diff --git a/third_party/rust/dns-parser/src/rdata/soa.rs b/third_party/rust/dns-parser/src/rdata/soa.rs
new file mode 100644
index 0000000000..e6d5f1712d
--- /dev/null
+++ b/third_party/rust/dns-parser/src/rdata/soa.rs
@@ -0,0 +1,101 @@
+use {Name, Error};
+use byteorder::{BigEndian, ByteOrder};
+
+/// The SOA (Start of Authority) record
+#[derive(Debug, Clone, Copy)]
+pub struct Record<'a> {
+ pub primary_ns: Name<'a>,
+ pub mailbox: Name<'a>,
+ pub serial: u32,
+ pub refresh: u32,
+ pub retry: u32,
+ pub expire: u32,
+ pub minimum_ttl: u32,
+}
+
+impl<'a> super::Record<'a> for Record<'a> {
+
+ const TYPE: isize = 6;
+
+ fn parse(rdata: &'a [u8], original: &'a [u8]) -> super::RDataResult<'a> {
+ let mut pos = 0;
+ let primary_name_server = try!(Name::scan(rdata, original));
+ pos += primary_name_server.byte_len();
+ let mailbox = try!(Name::scan(&rdata[pos..], original));
+ pos += mailbox.byte_len();
+ if rdata[pos..].len() < 20 {
+ return Err(Error::WrongRdataLength);
+ }
+ let record = Record {
+ primary_ns: primary_name_server,
+ mailbox: mailbox,
+ serial: BigEndian::read_u32(&rdata[pos..(pos+4)]),
+ refresh: BigEndian::read_u32(&rdata[(pos+4)..(pos+8)]),
+ retry: BigEndian::read_u32(&rdata[(pos+8)..(pos+12)]),
+ expire: BigEndian::read_u32(&rdata[(pos+12)..(pos+16)]),
+ minimum_ttl: BigEndian::read_u32(&rdata[(pos+16)..(pos+20)]),
+ };
+ Ok(super::RData::SOA(record))
+ }
+}
+
+#[cfg(test)]
+mod test {
+
+ use {Packet, Header};
+ use Opcode::*;
+ use ResponseCode::NameError;
+ use QueryType as QT;
+ use QueryClass as QC;
+ use Class as C;
+ use RData;
+
+ #[test]
+ fn parse_response() {
+ let response = b"\x9f\xc5\x85\x83\x00\x01\x00\x00\x00\x01\x00\x00\
+ \x0edlkfjkdjdslfkj\x07youtube\x03com\x00\x00\x01\x00\x01\
+ \xc0\x1b\x00\x06\x00\x01\x00\x00\x2a\x30\x00\x1e\xc0\x1b\
+ \x05admin\xc0\x1b\x77\xed\x2a\x73\x00\x00\x51\x80\x00\x00\
+ \x0e\x10\x00\x00\x3a\x80\x00\x00\x2a\x30";
+ let packet = Packet::parse(response).unwrap();
+ assert_eq!(packet.header, Header {
+ id: 40901,
+ query: false,
+ opcode: StandardQuery,
+ authoritative: true,
+ truncated: false,
+ recursion_desired: true,
+ recursion_available: true,
+ authenticated_data: false,
+ checking_disabled: false,
+ response_code: NameError,
+ questions: 1,
+ answers: 0,
+ nameservers: 1,
+ additional: 0,
+ });
+ assert_eq!(packet.questions.len(), 1);
+ assert_eq!(packet.questions[0].qtype, QT::A);
+ assert_eq!(packet.questions[0].qclass, QC::IN);
+ assert_eq!(&packet.questions[0].qname.to_string()[..], "dlkfjkdjdslfkj.youtube.com");
+ assert_eq!(packet.answers.len(), 0);
+
+ assert_eq!(packet.nameservers.len(), 1);
+ assert_eq!(&packet.nameservers[0].name.to_string()[..], "youtube.com");
+ assert_eq!(packet.nameservers[0].cls, C::IN);
+ assert_eq!(packet.nameservers[0].multicast_unique, false);
+ assert_eq!(packet.nameservers[0].ttl, 10800);
+ match packet.nameservers[0].data {
+ RData::SOA(ref soa_rec) => {
+ assert_eq!(&soa_rec.primary_ns.to_string()[..], "youtube.com");
+ assert_eq!(&soa_rec.mailbox.to_string()[..], "admin.youtube.com");
+ assert_eq!(soa_rec.serial, 2012031603);
+ assert_eq!(soa_rec.refresh, 20864);
+ assert_eq!(soa_rec.retry, 3600);
+ assert_eq!(soa_rec.expire, 14976);
+ assert_eq!(soa_rec.minimum_ttl, 10800);
+ }
+ ref x => panic!("Wrong rdata {:?}", x),
+ }
+ }
+}
diff --git a/third_party/rust/dns-parser/src/rdata/srv.rs b/third_party/rust/dns-parser/src/rdata/srv.rs
new file mode 100644
index 0000000000..dbc151d8aa
--- /dev/null
+++ b/third_party/rust/dns-parser/src/rdata/srv.rs
@@ -0,0 +1,102 @@
+use {Name, Error};
+use byteorder::{BigEndian, ByteOrder};
+
+#[derive(Debug, Clone, Copy)]
+pub struct Record<'a> {
+ pub priority: u16,
+ pub weight: u16,
+ pub port: u16,
+ pub target: Name<'a>,
+}
+
+impl<'a> super::Record<'a> for Record<'a> {
+
+ const TYPE: isize = 33;
+
+ fn parse(rdata: &'a [u8], original: &'a [u8]) -> super::RDataResult<'a> {
+ if rdata.len() < 7 {
+ return Err(Error::WrongRdataLength);
+ }
+ let record = Record {
+ priority: BigEndian::read_u16(&rdata[..2]),
+ weight: BigEndian::read_u16(&rdata[2..4]),
+ port: BigEndian::read_u16(&rdata[4..6]),
+ target: Name::scan(&rdata[6..], original)?,
+ };
+ Ok(super::RData::SRV(record))
+ }
+}
+
+#[cfg(test)]
+mod test {
+
+ use {Packet, Header};
+ use Opcode::*;
+ use ResponseCode::NoError;
+ use QueryType as QT;
+ use QueryClass as QC;
+ use Class as C;
+ use RData;
+ use super::*;
+
+ #[test]
+ fn parse_response() {
+ let response = b"[\xd9\x81\x80\x00\x01\x00\x05\x00\x00\x00\x00\
+ \x0c_xmpp-server\x04_tcp\x05gmail\x03com\x00\x00!\x00\x01\
+ \xc0\x0c\x00!\x00\x01\x00\x00\x03\x84\x00 \x00\x05\x00\x00\
+ \x14\x95\x0bxmpp-server\x01l\x06google\x03com\x00\xc0\x0c\x00!\
+ \x00\x01\x00\x00\x03\x84\x00%\x00\x14\x00\x00\x14\x95\
+ \x04alt3\x0bxmpp-server\x01l\x06google\x03com\x00\
+ \xc0\x0c\x00!\x00\x01\x00\x00\x03\x84\x00%\x00\x14\x00\x00\
+ \x14\x95\x04alt1\x0bxmpp-server\x01l\x06google\x03com\x00\
+ \xc0\x0c\x00!\x00\x01\x00\x00\x03\x84\x00%\x00\x14\x00\x00\
+ \x14\x95\x04alt2\x0bxmpp-server\x01l\x06google\x03com\x00\
+ \xc0\x0c\x00!\x00\x01\x00\x00\x03\x84\x00%\x00\x14\x00\x00\
+ \x14\x95\x04alt4\x0bxmpp-server\x01l\x06google\x03com\x00";
+ let packet = Packet::parse(response).unwrap();
+ assert_eq!(packet.header, Header {
+ id: 23513,
+ query: false,
+ opcode: StandardQuery,
+ authoritative: false,
+ truncated: false,
+ recursion_desired: true,
+ recursion_available: true,
+ authenticated_data: false,
+ checking_disabled: false,
+ response_code: NoError,
+ questions: 1,
+ answers: 5,
+ nameservers: 0,
+ additional: 0,
+ });
+ assert_eq!(packet.questions.len(), 1);
+ assert_eq!(packet.questions[0].qtype, QT::SRV);
+ assert_eq!(packet.questions[0].qclass, QC::IN);
+ assert_eq!(&packet.questions[0].qname.to_string()[..],
+ "_xmpp-server._tcp.gmail.com");
+ assert_eq!(packet.answers.len(), 5);
+ let items = vec![
+ (5, 0, 5269, "xmpp-server.l.google.com"),
+ (20, 0, 5269, "alt3.xmpp-server.l.google.com"),
+ (20, 0, 5269, "alt1.xmpp-server.l.google.com"),
+ (20, 0, 5269, "alt2.xmpp-server.l.google.com"),
+ (20, 0, 5269, "alt4.xmpp-server.l.google.com"),
+ ];
+ for i in 0..5 {
+ assert_eq!(&packet.answers[i].name.to_string()[..],
+ "_xmpp-server._tcp.gmail.com");
+ assert_eq!(packet.answers[i].cls, C::IN);
+ assert_eq!(packet.answers[i].ttl, 900);
+ match *&packet.answers[i].data {
+ RData::SRV(Record { priority, weight, port, target }) => {
+ assert_eq!(priority, items[i].0);
+ assert_eq!(weight, items[i].1);
+ assert_eq!(port, items[i].2);
+ assert_eq!(target.to_string(), (items[i].3).to_string());
+ }
+ ref x => panic!("Wrong rdata {:?}", x),
+ }
+ }
+ }
+}
diff --git a/third_party/rust/dns-parser/src/rdata/txt.rs b/third_party/rust/dns-parser/src/rdata/txt.rs
new file mode 100644
index 0000000000..8f5f5fc26d
--- /dev/null
+++ b/third_party/rust/dns-parser/src/rdata/txt.rs
@@ -0,0 +1,125 @@
+use Error;
+
+#[derive(Debug, Clone)]
+pub struct Record<'a> {
+ bytes: &'a [u8],
+}
+
+#[derive(Debug)]
+pub struct RecordIter<'a> {
+ bytes: &'a [u8],
+}
+
+impl<'a> Iterator for RecordIter<'a> {
+ type Item = &'a [u8];
+ fn next(&mut self) -> Option<&'a [u8]> {
+ if self.bytes.len() >= 1 {
+ let len = self.bytes[0] as usize;
+ debug_assert!(self.bytes.len() >= len+1);
+ let (head, tail) = self.bytes[1..].split_at(len);
+ self.bytes = tail;
+ return Some(head);
+ }
+ return None;
+ }
+}
+
+impl<'a> Record<'a> {
+
+ // Returns iterator over text chunks
+ pub fn iter(&self) -> RecordIter<'a> {
+ RecordIter {
+ bytes: self.bytes,
+ }
+ }
+}
+
+impl<'a> super::Record<'a> for Record<'a> {
+
+ const TYPE: isize = 16;
+
+ fn parse(rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
+ // Just a quick check that record is valid
+ let len = rdata.len();
+ if len < 1 {
+ return Err(Error::WrongRdataLength);
+ }
+ let mut pos = 0;
+ while pos < len {
+ let rdlen = rdata[pos] as usize;
+ pos += 1;
+ if len < rdlen + pos {
+ return Err(Error::WrongRdataLength);
+ }
+ pos += rdlen;
+ }
+ Ok(super::RData::TXT(Record {
+ bytes: rdata,
+ }))
+ }
+}
+
+#[cfg(test)]
+mod test {
+
+ use std::str::from_utf8;
+
+ use {Packet, Header};
+ use Opcode::*;
+ use ResponseCode::NoError;
+ use QueryType as QT;
+ use QueryClass as QC;
+ use Class as C;
+ use RData;
+
+ #[test]
+ fn parse_response_multiple_strings() {
+ let response = b"\x06%\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\
+ \x08facebook\x03com\x00\x00\x10\x00\x01\
+ \xc0\x0c\x00\x10\x00\x01\x00\x01\x51\x3d\x00\x23\
+ \x15\x76\x3d\x73\x70\x66\x31\x20\x72\x65\x64\x69\
+ \x72\x65\x63\x74\x3d\x5f\x73\x70\x66\x2e\
+ \x0c\x66\x61\x63\x65\x62\x6f\x6f\x6b\x2e\x63\x6f\x6d";
+
+ let packet = Packet::parse(response).unwrap();
+ assert_eq!(packet.header, Header {
+ id: 1573,
+ query: false,
+ opcode: StandardQuery,
+ authoritative: false,
+ truncated: false,
+ recursion_desired: true,
+ recursion_available: true,
+ authenticated_data: false,
+ checking_disabled: false,
+ response_code: NoError,
+ questions: 1,
+ answers: 1,
+ nameservers: 0,
+ additional: 0,
+ });
+ assert_eq!(packet.questions.len(), 1);
+ assert_eq!(packet.questions[0].qtype, QT::TXT);
+ assert_eq!(packet.questions[0].qclass, QC::IN);
+ assert_eq!(&packet.questions[0].qname.to_string()[..], "facebook.com");
+ assert_eq!(packet.answers.len(), 1);
+ assert_eq!(&packet.answers[0].name.to_string()[..], "facebook.com");
+ assert_eq!(packet.answers[0].multicast_unique, false);
+ assert_eq!(packet.answers[0].cls, C::IN);
+ assert_eq!(packet.answers[0].ttl, 86333);
+ match packet.answers[0].data {
+ RData::TXT(ref text) => {
+ assert_eq!(text.iter()
+ .map(|x| from_utf8(x).unwrap())
+ .collect::<Vec<_>>()
+ .concat(), "v=spf1 redirect=_spf.facebook.com");
+
+ // also assert boundaries are kept
+ assert_eq!(text.iter().collect::<Vec<_>>(),
+ ["v=spf1 redirect=_spf.".as_bytes(),
+ "facebook.com".as_bytes()]);
+ }
+ ref x => panic!("Wrong rdata {:?}", x),
+ }
+ }
+}
diff --git a/third_party/rust/dns-parser/src/rdata/wks.rs b/third_party/rust/dns-parser/src/rdata/wks.rs
new file mode 100644
index 0000000000..ff6e5f1881
--- /dev/null
+++ b/third_party/rust/dns-parser/src/rdata/wks.rs
@@ -0,0 +1,11 @@
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub struct Record;
+
+impl<'a> super::Record<'a> for Record {
+
+ const TYPE: isize = 11;
+
+ fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
+ unimplemented!();
+ }
+}