123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793 |
- #![allow(dead_code)]
- use bitflags::bitflags;
- use byteorder::{ByteOrder, NetworkEndian};
- use core::iter;
- use core::iter::Iterator;
- use super::{Error, Result};
- #[cfg(feature = "proto-ipv4")]
- use crate::wire::Ipv4Address;
- #[cfg(feature = "proto-ipv6")]
- use crate::wire::Ipv6Address;
- enum_with_unknown! {
- /// DNS OpCodes
- pub enum Opcode(u8) {
- Query = 0x00,
- Status = 0x01,
- }
- }
- enum_with_unknown! {
- /// DNS OpCodes
- pub enum Rcode(u8) {
- NoError = 0x00,
- FormErr = 0x01,
- ServFail = 0x02,
- NXDomain = 0x03,
- NotImp = 0x04,
- Refused = 0x05,
- YXDomain = 0x06,
- YXRRSet = 0x07,
- NXRRSet = 0x08,
- NotAuth = 0x09,
- NotZone = 0x0a,
- }
- }
- enum_with_unknown! {
- /// DNS record types
- pub enum Type(u16) {
- A = 0x0001,
- Ns = 0x0002,
- Cname = 0x0005,
- Soa = 0x0006,
- Aaaa = 0x001c,
- }
- }
- bitflags! {
- #[cfg_attr(feature = "defmt", derive(defmt::Format))]
- pub struct Flags: u16 {
- const RESPONSE = 0b1000_0000_0000_0000;
- const AUTHORITATIVE = 0b0000_0100_0000_0000;
- const TRUNCATED = 0b0000_0010_0000_0000;
- const RECURSION_DESIRED = 0b0000_0001_0000_0000;
- const RECURSION_AVAILABLE = 0b0000_0000_1000_0000;
- const AUTHENTIC_DATA = 0b0000_0000_0010_0000;
- const CHECK_DISABLED = 0b0000_0000_0001_0000;
- }
- }
- mod field {
- use crate::wire::field::*;
- pub const ID: Field = 0..2;
- pub const FLAGS: Field = 2..4;
- pub const QDCOUNT: Field = 4..6;
- pub const ANCOUNT: Field = 6..8;
- pub const NSCOUNT: Field = 8..10;
- pub const ARCOUNT: Field = 10..12;
- pub const HEADER_END: usize = 12;
- }
- // DNS class IN (Internet)
- const CLASS_IN: u16 = 1;
- /// A read/write wrapper around a DNS packet buffer.
- #[derive(Debug, PartialEq, Eq)]
- pub struct Packet<T: AsRef<[u8]>> {
- buffer: T,
- }
- impl<T: AsRef<[u8]>> Packet<T> {
- /// Imbue a raw octet buffer with DNS packet structure.
- pub const fn new_unchecked(buffer: T) -> Packet<T> {
- Packet { buffer }
- }
- /// Shorthand for a combination of [new_unchecked] and [check_len].
- ///
- /// [new_unchecked]: #method.new_unchecked
- /// [check_len]: #method.check_len
- pub fn new_checked(buffer: T) -> Result<Packet<T>> {
- let packet = Self::new_unchecked(buffer);
- packet.check_len()?;
- Ok(packet)
- }
- /// Ensure that no accessor method will panic if called.
- /// Returns `Err(Error)` if the buffer is smaller than
- /// the header length.
- pub fn check_len(&self) -> Result<()> {
- let len = self.buffer.as_ref().len();
- if len < field::HEADER_END {
- Err(Error)
- } else {
- Ok(())
- }
- }
- /// Consume the packet, returning the underlying buffer.
- pub fn into_inner(self) -> T {
- self.buffer
- }
- pub fn payload(&self) -> &[u8] {
- &self.buffer.as_ref()[field::HEADER_END..]
- }
- pub fn transaction_id(&self) -> u16 {
- let field = &self.buffer.as_ref()[field::ID];
- NetworkEndian::read_u16(field)
- }
- pub fn flags(&self) -> Flags {
- let field = &self.buffer.as_ref()[field::FLAGS];
- Flags::from_bits_truncate(NetworkEndian::read_u16(field))
- }
- pub fn opcode(&self) -> Opcode {
- let field = &self.buffer.as_ref()[field::FLAGS];
- let flags = NetworkEndian::read_u16(field);
- Opcode::from((flags >> 11 & 0xF) as u8)
- }
- pub fn rcode(&self) -> Rcode {
- let field = &self.buffer.as_ref()[field::FLAGS];
- let flags = NetworkEndian::read_u16(field);
- Rcode::from((flags & 0xF) as u8)
- }
- pub fn question_count(&self) -> u16 {
- let field = &self.buffer.as_ref()[field::QDCOUNT];
- NetworkEndian::read_u16(field)
- }
- pub fn answer_record_count(&self) -> u16 {
- let field = &self.buffer.as_ref()[field::ANCOUNT];
- NetworkEndian::read_u16(field)
- }
- pub fn authority_record_count(&self) -> u16 {
- let field = &self.buffer.as_ref()[field::NSCOUNT];
- NetworkEndian::read_u16(field)
- }
- pub fn additional_record_count(&self) -> u16 {
- let field = &self.buffer.as_ref()[field::ARCOUNT];
- NetworkEndian::read_u16(field)
- }
- /// Parse part of a name from `bytes`, following pointers if any.
- pub fn parse_name<'a>(&'a self, mut bytes: &'a [u8]) -> impl Iterator<Item = Result<&'a [u8]>> {
- let mut packet = self.buffer.as_ref();
- iter::from_fn(move || loop {
- if bytes.is_empty() {
- return Some(Err(Error));
- }
- match bytes[0] {
- 0x00 => return None,
- x if x & 0xC0 == 0x00 => {
- let len = (x & 0x3F) as usize;
- if bytes.len() < 1 + len {
- return Some(Err(Error));
- }
- let label = &bytes[1..1 + len];
- bytes = &bytes[1 + len..];
- return Some(Ok(label));
- }
- x if x & 0xC0 == 0xC0 => {
- if bytes.len() < 2 {
- return Some(Err(Error));
- }
- let y = bytes[1];
- let ptr = ((x & 0x3F) as usize) << 8 | (y as usize);
- if packet.len() <= ptr {
- return Some(Err(Error));
- }
- // RFC1035 says: "In this scheme, an entire domain name or a list of labels at
- // the end of a domain name is replaced with a pointer to a ***prior*** occurrence
- // of the same name.
- //
- // Is it unclear if this means the pointer MUST point backwards in the packet or not. Either way,
- // pointers that don't point backwards are never seen in the fields, so use this to check that
- // there are no pointer loops.
- // Split packet into parts before and after `ptr`.
- // parse the part after, keep only the part before in `packet`. This ensure we never
- // parse the same byte twice, therefore eliminating pointer loops.
- bytes = &packet[ptr..];
- packet = &packet[..ptr];
- }
- _ => return Some(Err(Error)),
- }
- })
- }
- }
- impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
- pub fn payload_mut(&mut self) -> &mut [u8] {
- let data = self.buffer.as_mut();
- &mut data[field::HEADER_END..]
- }
- pub fn set_transaction_id(&mut self, val: u16) {
- let field = &mut self.buffer.as_mut()[field::ID];
- NetworkEndian::write_u16(field, val)
- }
- pub fn set_flags(&mut self, val: Flags) {
- let field = &mut self.buffer.as_mut()[field::FLAGS];
- let mask = Flags::all().bits;
- let old = NetworkEndian::read_u16(field);
- NetworkEndian::write_u16(field, (old & !mask) | val.bits());
- }
- pub fn set_opcode(&mut self, val: Opcode) {
- let field = &mut self.buffer.as_mut()[field::FLAGS];
- let mask = 0x3800;
- let val: u8 = val.into();
- let val = (val as u16) << 11;
- let old = NetworkEndian::read_u16(field);
- NetworkEndian::write_u16(field, (old & !mask) | val);
- }
- pub fn set_question_count(&mut self, val: u16) {
- let field = &mut self.buffer.as_mut()[field::QDCOUNT];
- NetworkEndian::write_u16(field, val)
- }
- pub fn set_answer_record_count(&mut self, val: u16) {
- let field = &mut self.buffer.as_mut()[field::ANCOUNT];
- NetworkEndian::write_u16(field, val)
- }
- pub fn set_authority_record_count(&mut self, val: u16) {
- let field = &mut self.buffer.as_mut()[field::NSCOUNT];
- NetworkEndian::write_u16(field, val)
- }
- pub fn set_additional_record_count(&mut self, val: u16) {
- let field = &mut self.buffer.as_mut()[field::ARCOUNT];
- NetworkEndian::write_u16(field, val)
- }
- }
- /// Parse part of a name from `bytes`, not following pointers.
- /// Returns the unused part of `bytes`, and the pointer offset if the sequence ends with a pointer.
- fn parse_name_part<'a>(
- mut bytes: &'a [u8],
- mut f: impl FnMut(&'a [u8]),
- ) -> Result<(&'a [u8], Option<usize>)> {
- loop {
- let x = *bytes.first().ok_or(Error)?;
- bytes = &bytes[1..];
- match x {
- 0x00 => return Ok((bytes, None)),
- x if x & 0xC0 == 0x00 => {
- let len = (x & 0x3F) as usize;
- let label = bytes.get(..len).ok_or(Error)?;
- bytes = &bytes[len..];
- f(label);
- }
- x if x & 0xC0 == 0xC0 => {
- let y = *bytes.first().ok_or(Error)?;
- bytes = &bytes[1..];
- let ptr = ((x & 0x3F) as usize) << 8 | (y as usize);
- return Ok((bytes, Some(ptr)));
- }
- _ => return Err(Error),
- }
- }
- }
- #[derive(Debug, PartialEq, Eq)]
- #[cfg_attr(feature = "defmt", derive(defmt::Format))]
- pub struct Question<'a> {
- pub name: &'a [u8],
- pub type_: Type,
- }
- impl<'a> Question<'a> {
- pub fn parse(buffer: &'a [u8]) -> Result<(&'a [u8], Question<'a>)> {
- let (rest, _) = parse_name_part(buffer, |_| ())?;
- let name = &buffer[..buffer.len() - rest.len()];
- if rest.len() < 4 {
- return Err(Error);
- }
- let type_ = NetworkEndian::read_u16(&rest[0..2]).into();
- let class = NetworkEndian::read_u16(&rest[2..4]);
- let rest = &rest[4..];
- if class != CLASS_IN {
- return Err(Error);
- }
- Ok((rest, Question { name, type_ }))
- }
- /// Return the length of a packet that will be emitted from this high-level representation.
- pub const fn buffer_len(&self) -> usize {
- self.name.len() + 4
- }
- /// Emit a high-level representation into a DNS packet.
- pub fn emit(&self, packet: &mut [u8]) {
- packet[..self.name.len()].copy_from_slice(self.name);
- let rest = &mut packet[self.name.len()..];
- NetworkEndian::write_u16(&mut rest[0..2], self.type_.into());
- NetworkEndian::write_u16(&mut rest[2..4], CLASS_IN);
- }
- }
- #[derive(Debug, PartialEq, Eq)]
- #[cfg_attr(feature = "defmt", derive(defmt::Format))]
- pub struct Record<'a> {
- pub name: &'a [u8],
- pub ttl: u32,
- pub data: RecordData<'a>,
- }
- impl<'a> RecordData<'a> {
- pub fn parse(type_: Type, data: &'a [u8]) -> Result<RecordData<'a>> {
- match type_ {
- #[cfg(feature = "proto-ipv4")]
- Type::A => {
- if data.len() != 4 {
- return Err(Error);
- }
- Ok(RecordData::A(Ipv4Address::from_bytes(data)))
- }
- #[cfg(feature = "proto-ipv6")]
- Type::Aaaa => {
- if data.len() != 16 {
- return Err(Error);
- }
- Ok(RecordData::Aaaa(Ipv6Address::from_bytes(data)))
- }
- Type::Cname => Ok(RecordData::Cname(data)),
- x => Ok(RecordData::Other(x, data)),
- }
- }
- }
- #[derive(Debug, PartialEq, Eq)]
- #[cfg_attr(feature = "defmt", derive(defmt::Format))]
- pub enum RecordData<'a> {
- #[cfg(feature = "proto-ipv4")]
- A(Ipv4Address),
- #[cfg(feature = "proto-ipv6")]
- Aaaa(Ipv6Address),
- Cname(&'a [u8]),
- Other(Type, &'a [u8]),
- }
- impl<'a> Record<'a> {
- pub fn parse(buffer: &'a [u8]) -> Result<(&'a [u8], Record<'a>)> {
- let (rest, _) = parse_name_part(buffer, |_| ())?;
- let name = &buffer[..buffer.len() - rest.len()];
- if rest.len() < 10 {
- return Err(Error);
- }
- let type_ = NetworkEndian::read_u16(&rest[0..2]).into();
- let class = NetworkEndian::read_u16(&rest[2..4]);
- let ttl = NetworkEndian::read_u32(&rest[4..8]);
- let len = NetworkEndian::read_u16(&rest[8..10]) as usize;
- let rest = &rest[10..];
- if class != CLASS_IN {
- return Err(Error);
- }
- let data = rest.get(..len).ok_or(Error)?;
- let rest = &rest[len..];
- Ok((
- rest,
- Record {
- name,
- ttl,
- data: RecordData::parse(type_, data)?,
- },
- ))
- }
- }
- /// High-level DNS packet representation.
- ///
- /// Currently only supports query packets.
- #[derive(Debug, PartialEq, Eq)]
- #[cfg_attr(feature = "defmt", derive(defmt::Format))]
- pub struct Repr<'a> {
- pub transaction_id: u16,
- pub opcode: Opcode,
- pub flags: Flags,
- pub question: Question<'a>,
- }
- impl<'a> Repr<'a> {
- /// Return the length of a packet that will be emitted from this high-level representation.
- pub const fn buffer_len(&self) -> usize {
- field::HEADER_END + self.question.buffer_len()
- }
- /// Emit a high-level representation into a DNS packet.
- pub fn emit<T: ?Sized>(&self, packet: &mut Packet<&mut T>)
- where
- T: AsRef<[u8]> + AsMut<[u8]>,
- {
- packet.set_transaction_id(self.transaction_id);
- packet.set_flags(self.flags);
- packet.set_opcode(self.opcode);
- packet.set_question_count(1);
- packet.set_answer_record_count(0);
- packet.set_authority_record_count(0);
- packet.set_additional_record_count(0);
- self.question.emit(packet.payload_mut())
- }
- }
- #[cfg(feature = "proto-ipv4")] // tests assume ipv4
- #[cfg(test)]
- mod test {
- use super::*;
- use std::vec::Vec;
- #[test]
- fn test_parse_name() {
- let bytes = &[
- 0x78, 0x6c, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x77,
- 0x77, 0x77, 0x08, 0x66, 0x61, 0x63, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x03, 0x63, 0x6f,
- 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00,
- 0x05, 0xf3, 0x00, 0x11, 0x09, 0x73, 0x74, 0x61, 0x72, 0x2d, 0x6d, 0x69, 0x6e, 0x69,
- 0x04, 0x63, 0x31, 0x30, 0x72, 0xc0, 0x10, 0xc0, 0x2e, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x00, 0x00, 0x05, 0x00, 0x04, 0x1f, 0x0d, 0x53, 0x24,
- ];
- let packet = Packet::new_unchecked(bytes);
- let name_vec = |bytes| {
- let mut v = Vec::new();
- packet
- .parse_name(bytes)
- .try_for_each(|label| label.map(|label| v.push(label)))
- .map(|_| v)
- };
- //assert_eq!(parse_name_len(bytes, 0x0c), Ok(18));
- assert_eq!(
- name_vec(&bytes[0x0c..]),
- Ok(vec![&b"www"[..], &b"facebook"[..], &b"com"[..]])
- );
- //assert_eq!(parse_name_len(bytes, 0x22), Ok(2));
- assert_eq!(
- name_vec(&bytes[0x22..]),
- Ok(vec![&b"www"[..], &b"facebook"[..], &b"com"[..]])
- );
- //assert_eq!(parse_name_len(bytes, 0x2e), Ok(17));
- assert_eq!(
- name_vec(&bytes[0x2e..]),
- Ok(vec![
- &b"star-mini"[..],
- &b"c10r"[..],
- &b"facebook"[..],
- &b"com"[..]
- ])
- );
- //assert_eq!(parse_name_len(bytes, 0x3f), Ok(2));
- assert_eq!(
- name_vec(&bytes[0x3f..]),
- Ok(vec![
- &b"star-mini"[..],
- &b"c10r"[..],
- &b"facebook"[..],
- &b"com"[..]
- ])
- );
- }
- struct Parsed<'a> {
- packet: Packet<&'a [u8]>,
- questions: Vec<Question<'a>>,
- answers: Vec<Record<'a>>,
- authorities: Vec<Record<'a>>,
- additionals: Vec<Record<'a>>,
- }
- impl<'a> Parsed<'a> {
- fn parse(bytes: &'a [u8]) -> Result<Self> {
- let packet = Packet::new_unchecked(bytes);
- let mut questions = Vec::new();
- let mut answers = Vec::new();
- let mut authorities = Vec::new();
- let mut additionals = Vec::new();
- let mut payload = &bytes[12..];
- for _ in 0..packet.question_count() {
- let (p, r) = Question::parse(payload)?;
- questions.push(r);
- payload = p;
- }
- for _ in 0..packet.answer_record_count() {
- let (p, r) = Record::parse(payload)?;
- answers.push(r);
- payload = p;
- }
- for _ in 0..packet.authority_record_count() {
- let (p, r) = Record::parse(payload)?;
- authorities.push(r);
- payload = p;
- }
- for _ in 0..packet.additional_record_count() {
- let (p, r) = Record::parse(payload)?;
- additionals.push(r);
- payload = p;
- }
- // Check that there are no bytes left
- assert_eq!(payload.len(), 0);
- Ok(Parsed {
- packet,
- questions,
- answers,
- authorities,
- additionals,
- })
- }
- }
- #[test]
- fn test_parse_request() {
- let p = Parsed::parse(&[
- 0x51, 0x84, 0x01, 0x20, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x67,
- 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
- ])
- .unwrap();
- assert_eq!(p.packet.transaction_id(), 0x5184);
- assert_eq!(
- p.packet.flags(),
- Flags::RECURSION_DESIRED | Flags::AUTHENTIC_DATA
- );
- assert_eq!(p.packet.opcode(), Opcode::Query);
- assert_eq!(p.packet.question_count(), 1);
- assert_eq!(p.packet.answer_record_count(), 0);
- assert_eq!(p.packet.authority_record_count(), 0);
- assert_eq!(p.packet.additional_record_count(), 0);
- assert_eq!(p.questions.len(), 1);
- assert_eq!(
- p.questions[0].name,
- &[0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00]
- );
- assert_eq!(p.questions[0].type_, Type::A);
- assert_eq!(p.answers.len(), 0);
- assert_eq!(p.authorities.len(), 0);
- assert_eq!(p.additionals.len(), 0);
- }
- #[test]
- fn test_parse_response() {
- let p = Parsed::parse(&[
- 0x51, 0x84, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x67,
- 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
- 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xca, 0x00, 0x04, 0xac, 0xd9,
- 0xa8, 0xae,
- ])
- .unwrap();
- assert_eq!(p.packet.transaction_id(), 0x5184);
- assert_eq!(
- p.packet.flags(),
- Flags::RESPONSE | Flags::RECURSION_DESIRED | Flags::RECURSION_AVAILABLE
- );
- assert_eq!(p.packet.opcode(), Opcode::Query);
- assert_eq!(p.packet.rcode(), Rcode::NoError);
- assert_eq!(p.packet.question_count(), 1);
- assert_eq!(p.packet.answer_record_count(), 1);
- assert_eq!(p.packet.authority_record_count(), 0);
- assert_eq!(p.packet.additional_record_count(), 0);
- assert_eq!(
- p.questions[0].name,
- &[0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00]
- );
- assert_eq!(p.questions[0].type_, Type::A);
- assert_eq!(p.answers[0].name, &[0xc0, 0x0c]);
- assert_eq!(p.answers[0].ttl, 202);
- assert_eq!(
- p.answers[0].data,
- RecordData::A(Ipv4Address::new(0xac, 0xd9, 0xa8, 0xae))
- );
- }
- #[test]
- fn test_parse_response_multiple_a() {
- let p = Parsed::parse(&[
- 0x4b, 0x9e, 0x81, 0x80, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x72,
- 0x75, 0x73, 0x74, 0x2d, 0x6c, 0x61, 0x6e, 0x67, 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00,
- 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00,
- 0x04, 0x0d, 0xe0, 0x77, 0x35, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x09, 0x00, 0x04, 0x0d, 0xe0, 0x77, 0x28, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x00, 0x00, 0x09, 0x00, 0x04, 0x0d, 0xe0, 0x77, 0x43, 0xc0, 0x0c, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x04, 0x0d, 0xe0, 0x77, 0x62,
- ])
- .unwrap();
- assert_eq!(p.packet.transaction_id(), 0x4b9e);
- assert_eq!(
- p.packet.flags(),
- Flags::RESPONSE | Flags::RECURSION_DESIRED | Flags::RECURSION_AVAILABLE
- );
- assert_eq!(p.packet.opcode(), Opcode::Query);
- assert_eq!(p.packet.rcode(), Rcode::NoError);
- assert_eq!(p.packet.question_count(), 1);
- assert_eq!(p.packet.answer_record_count(), 4);
- assert_eq!(p.packet.authority_record_count(), 0);
- assert_eq!(p.packet.additional_record_count(), 0);
- assert_eq!(
- p.questions[0].name,
- &[
- 0x09, 0x72, 0x75, 0x73, 0x74, 0x2d, 0x6c, 0x61, 0x6e, 0x67, 0x03, 0x6f, 0x72, 0x67,
- 0x00
- ]
- );
- assert_eq!(p.questions[0].type_, Type::A);
- assert_eq!(p.answers[0].name, &[0xc0, 0x0c]);
- assert_eq!(p.answers[0].ttl, 9);
- assert_eq!(
- p.answers[0].data,
- RecordData::A(Ipv4Address::new(0x0d, 0xe0, 0x77, 0x35))
- );
- assert_eq!(p.answers[1].name, &[0xc0, 0x0c]);
- assert_eq!(p.answers[1].ttl, 9);
- assert_eq!(
- p.answers[1].data,
- RecordData::A(Ipv4Address::new(0x0d, 0xe0, 0x77, 0x28))
- );
- assert_eq!(p.answers[2].name, &[0xc0, 0x0c]);
- assert_eq!(p.answers[2].ttl, 9);
- assert_eq!(
- p.answers[2].data,
- RecordData::A(Ipv4Address::new(0x0d, 0xe0, 0x77, 0x43))
- );
- assert_eq!(p.answers[3].name, &[0xc0, 0x0c]);
- assert_eq!(p.answers[3].ttl, 9);
- assert_eq!(
- p.answers[3].data,
- RecordData::A(Ipv4Address::new(0x0d, 0xe0, 0x77, 0x62))
- );
- }
- #[test]
- fn test_parse_response_cname() {
- let p = Parsed::parse(&[
- 0x78, 0x6c, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x77,
- 0x77, 0x77, 0x08, 0x66, 0x61, 0x63, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x03, 0x63, 0x6f,
- 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00,
- 0x05, 0xf3, 0x00, 0x11, 0x09, 0x73, 0x74, 0x61, 0x72, 0x2d, 0x6d, 0x69, 0x6e, 0x69,
- 0x04, 0x63, 0x31, 0x30, 0x72, 0xc0, 0x10, 0xc0, 0x2e, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x00, 0x00, 0x05, 0x00, 0x04, 0x1f, 0x0d, 0x53, 0x24,
- ])
- .unwrap();
- assert_eq!(p.packet.transaction_id(), 0x786c);
- assert_eq!(
- p.packet.flags(),
- Flags::RESPONSE | Flags::RECURSION_DESIRED | Flags::RECURSION_AVAILABLE
- );
- assert_eq!(p.packet.opcode(), Opcode::Query);
- assert_eq!(p.packet.rcode(), Rcode::NoError);
- assert_eq!(p.packet.question_count(), 1);
- assert_eq!(p.packet.answer_record_count(), 2);
- assert_eq!(p.packet.authority_record_count(), 0);
- assert_eq!(p.packet.additional_record_count(), 0);
- assert_eq!(
- p.questions[0].name,
- &[
- 0x03, 0x77, 0x77, 0x77, 0x08, 0x66, 0x61, 0x63, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x03,
- 0x63, 0x6f, 0x6d, 0x00
- ]
- );
- assert_eq!(p.questions[0].type_, Type::A);
- // cname
- assert_eq!(p.answers[0].name, &[0xc0, 0x0c]);
- assert_eq!(p.answers[0].ttl, 1523);
- assert_eq!(
- p.answers[0].data,
- RecordData::Cname(&[
- 0x09, 0x73, 0x74, 0x61, 0x72, 0x2d, 0x6d, 0x69, 0x6e, 0x69, 0x04, 0x63, 0x31, 0x30,
- 0x72, 0xc0, 0x10
- ])
- );
- // a
- assert_eq!(p.answers[1].name, &[0xc0, 0x2e]);
- assert_eq!(p.answers[1].ttl, 5);
- assert_eq!(
- p.answers[1].data,
- RecordData::A(Ipv4Address::new(0x1f, 0x0d, 0x53, 0x24))
- );
- }
- #[test]
- fn test_parse_response_nxdomain() {
- let p = Parsed::parse(&[
- 0x63, 0xc4, 0x81, 0x83, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x13, 0x61,
- 0x68, 0x61, 0x73, 0x64, 0x67, 0x68, 0x6c, 0x61, 0x6b, 0x73, 0x6a, 0x68, 0x62, 0x61,
- 0x61, 0x73, 0x6c, 0x64, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0,
- 0x20, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x03, 0x83, 0x00, 0x3d, 0x01, 0x61, 0x0c,
- 0x67, 0x74, 0x6c, 0x64, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x03, 0x6e,
- 0x65, 0x74, 0x00, 0x05, 0x6e, 0x73, 0x74, 0x6c, 0x64, 0x0c, 0x76, 0x65, 0x72, 0x69,
- 0x73, 0x69, 0x67, 0x6e, 0x2d, 0x67, 0x72, 0x73, 0xc0, 0x20, 0x5f, 0xce, 0x8b, 0x85,
- 0x00, 0x00, 0x07, 0x08, 0x00, 0x00, 0x03, 0x84, 0x00, 0x09, 0x3a, 0x80, 0x00, 0x01,
- 0x51, 0x80,
- ])
- .unwrap();
- assert_eq!(p.packet.transaction_id(), 0x63c4);
- assert_eq!(
- p.packet.flags(),
- Flags::RESPONSE | Flags::RECURSION_DESIRED | Flags::RECURSION_AVAILABLE
- );
- assert_eq!(p.packet.opcode(), Opcode::Query);
- assert_eq!(p.packet.rcode(), Rcode::NXDomain);
- assert_eq!(p.packet.question_count(), 1);
- assert_eq!(p.packet.answer_record_count(), 0);
- assert_eq!(p.packet.authority_record_count(), 1);
- assert_eq!(p.packet.additional_record_count(), 0);
- assert_eq!(p.questions[0].type_, Type::A);
- // SOA authority
- assert_eq!(p.authorities[0].name, &[0xc0, 0x20]); // com.
- assert_eq!(p.authorities[0].ttl, 899);
- assert!(matches!(
- p.authorities[0].data,
- RecordData::Other(Type::Soa, _)
- ));
- }
- #[test]
- fn test_emit() {
- let name = &[
- 0x09, 0x72, 0x75, 0x73, 0x74, 0x2d, 0x6c, 0x61, 0x6e, 0x67, 0x03, 0x6f, 0x72, 0x67,
- 0x00,
- ];
- let repr = Repr {
- transaction_id: 0x1234,
- flags: Flags::RECURSION_DESIRED,
- opcode: Opcode::Query,
- question: Question {
- name,
- type_: Type::A,
- },
- };
- let mut buf = Vec::new();
- buf.resize(repr.buffer_len(), 0);
- repr.emit(&mut Packet::new_unchecked(&mut buf));
- let want = &[
- 0x12, 0x34, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x72,
- 0x75, 0x73, 0x74, 0x2d, 0x6c, 0x61, 0x6e, 0x67, 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00,
- 0x01, 0x00, 0x01,
- ];
- assert_eq!(&buf, want);
- }
- }
|