// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. pub use self::{answer::DnsAnswer, query::DnsQuery}; use alloc::{string::String, vec::Vec}; use core::{slice, u16}; mod answer; mod query; use core::ptr; use mem; use alloc::boxed::Box; #[allow(non_camel_case_types)] #[derive(Copy, Clone, Debug, Default)] #[repr(packed)] pub struct n16 { inner: u16, } impl n16 { pub fn as_bytes(&self) -> &[u8] { let left_8bits = (self.inner >> 8) as u8; let right_8bits = self.inner as u8; unsafe { let bytes: [u8; 2] = [left_8bits, right_8bits]; slice::from_raw_parts(bytes.as_ptr(), 2) } } // pub fn as_bytes(&self) -> &[u8] { // unsafe { slice::from_raw_parts((&self.inner as *const u16) as *const u8, 2) } // } pub fn from_bytes(bytes: &[u8]) -> Self { n16 { inner: unsafe { slice::from_raw_parts(bytes.as_ptr() as *const u16, bytes.len() / 2)[0] }, } } } impl From for n16 { fn from(value: u16) -> Self { n16 { inner: value.to_be(), } } } impl From for u16 { fn from(value: n16) -> Self { u16::from_be(value.inner) } } #[derive(Clone, Debug)] pub struct Dns { pub transaction_id: u16, pub flags: u16, pub queries: Vec, pub answers: Vec, } impl Dns { pub fn compile(&self) -> Vec { let mut data = Vec::new(); macro_rules! push_u8 { ($value:expr) => { data.push($value); }; }; macro_rules! push_n16 { ($value:expr) => { data.extend_from_slice(n16::from($value).as_bytes()); }; }; push_n16!(self.transaction_id); push_n16!(self.flags); push_n16!(self.queries.len() as u16); push_n16!(self.answers.len() as u16); push_n16!(0); push_n16!(0); for query in self.queries.iter() { for part in query.name.split('.') { push_u8!(part.len() as u8); data.extend_from_slice(part.as_bytes()); } push_u8!(0); push_n16!(query.q_type); push_n16!(query.q_class); } data } pub fn parse(data: &[u8]) -> Result { let name_ind = 0b1100_0000; let mut i = 0; macro_rules! pop_u8 { () => {{ i += 1; if i > data.len() { return Err(format!("{}: {}: pop_u8", file!(), line!())); } data[i - 1] }}; }; macro_rules! pop_n16 { () => {{ i += 2; if i > data.len() { return Err(format!("{}: {}: pop_n16", file!(), line!())); } u16::from(n16::from_bytes(&data[i - 2..i])) }}; }; macro_rules! pop_data { () => {{ let mut data = Vec::new(); let data_len = pop_n16!(); for _data_i in 0..data_len { data.push(pop_u8!()); } data }}; }; macro_rules! pop_name { () => {{ let mut name = String::new(); let old_i = i; loop { let name_len = pop_u8!(); if name_len & name_ind == name_ind { i -= 1; i = (pop_n16!() - ((name_ind as u16) << 8)) as usize; continue; } if name_len == 0 { break; } if !name.is_empty() { name.push('.'); } for _name_i in 0..name_len { name.push(pop_u8!() as char); } } if i <= old_i { i = old_i + 2; } name }}; }; let transaction_id = pop_n16!(); let flags = pop_n16!(); let queries_len = pop_n16!(); let answers_len = pop_n16!(); pop_n16!(); pop_n16!(); let mut queries = Vec::new(); for _query_i in 0..queries_len { queries.push(DnsQuery { name: pop_name!(), q_type: pop_n16!(), q_class: pop_n16!(), }); } let mut answers = Vec::new(); for _answer_i in 0..answers_len { answers.push(DnsAnswer { name: pop_name!(), a_type: pop_n16!(), a_class: pop_n16!(), ttl_a: pop_n16!(), ttl_b: pop_n16!(), data: pop_data!(), }); } Ok(Dns { transaction_id, flags, queries, answers, }) } }