| pub use self::answer::DnsAnswer; |
| pub use self::query::DnsQuery; |
| |
| use crate::slice; |
| use crate::u16; |
| use crate::string::String; |
| use crate::vec::Vec; |
| |
| mod answer; |
| mod query; |
| |
| #[unstable(feature = "n16", issue="0")] |
| #[allow(non_camel_case_types)] |
| #[derive(Copy, Clone, Debug, Default)] |
| #[repr(packed)] |
| pub struct n16 { |
| inner: u16 |
| } |
| |
| impl n16 { |
| #[unstable(feature = "n16", issue="0")] |
| pub fn as_bytes(&self) -> &[u8] { |
| unsafe { slice::from_raw_parts((&self.inner as *const u16) as *const u8, 2) } |
| } |
| |
| #[unstable(feature = "n16", issue="0")] |
| pub fn from_bytes(bytes: &[u8]) -> Self { |
| n16 { |
| inner: unsafe { slice::from_raw_parts(bytes.as_ptr() as *const u16, bytes.len()/2)[0] } |
| } |
| } |
| } |
| |
| #[unstable(feature = "n16", issue="0")] |
| impl From<u16> for n16 { |
| fn from(value: u16) -> Self { |
| n16 { |
| inner: value.to_be() |
| } |
| } |
| } |
| |
| #[unstable(feature = "n16", issue="0")] |
| impl From<n16> 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<DnsQuery>, |
| pub answers: Vec<DnsAnswer> |
| } |
| |
| impl Dns { |
| pub fn compile(&self) -> Vec<u8> { |
| 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<Self, String> { |
| let name_ind = 0b11000000; |
| 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, |
| }) |
| } |
| } |