xref: /drstd/dlibc/src/unix/header/netdb/dns/mod.rs (revision a1cd34728e2d4a5d4cf41974e4db28602cbb1b1c)
1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10 
11 pub use self::{answer::DnsAnswer, query::DnsQuery};
12 
13 use alloc::{string::String, vec::Vec};
14 use core::{slice, u16};
15 
16 mod answer;
17 mod query;
18 
19 #[allow(non_camel_case_types)]
20 #[derive(Copy, Clone, Debug, Default)]
21 #[repr(packed)]
22 pub struct n16 {
23     inner: u16,
24 }
25 
26 impl n16 {
as_bytes(&self) -> &[u8]27     pub fn as_bytes(&self) -> &[u8] {
28         let left_8bits = (self.inner >> 8) as u8;
29         let right_8bits = self.inner as u8;
30         unsafe {
31             let bytes: [u8; 2] = [left_8bits, right_8bits];
32             slice::from_raw_parts(bytes.as_ptr(), 2)
33         }
34     }
35     // pub fn as_bytes(&self) -> &[u8] {
36     //     unsafe { slice::from_raw_parts((&self.inner as *const u16) as *const u8, 2) }
37     // }
38 
from_bytes(bytes: &[u8]) -> Self39     pub fn from_bytes(bytes: &[u8]) -> Self {
40         n16 {
41             inner: unsafe {
42                 slice::from_raw_parts(bytes.as_ptr() as *const u16, bytes.len() / 2)[0]
43             },
44         }
45     }
46 }
47 
48 impl From<u16> for n16 {
from(value: u16) -> Self49     fn from(value: u16) -> Self {
50         n16 {
51             inner: value.to_be(),
52         }
53     }
54 }
55 
56 impl From<n16> for u16 {
from(value: n16) -> Self57     fn from(value: n16) -> Self {
58         u16::from_be(value.inner)
59     }
60 }
61 
62 #[derive(Clone, Debug)]
63 pub struct Dns {
64     pub transaction_id: u16,
65     pub flags: u16,
66     pub queries: Vec<DnsQuery>,
67     pub answers: Vec<DnsAnswer>,
68 }
69 
70 impl Dns {
compile(&self) -> Vec<u8>71     pub fn compile(&self) -> Vec<u8> {
72         let mut data = Vec::new();
73 
74         macro_rules! push_u8 {
75             ($value:expr) => {
76                 data.push($value);
77             };
78         };
79 
80         macro_rules! push_n16 {
81             ($value:expr) => {
82                 data.extend_from_slice(n16::from($value).as_bytes());
83             };
84         };
85 
86         push_n16!(self.transaction_id);
87         push_n16!(self.flags);
88         push_n16!(self.queries.len() as u16);
89         push_n16!(self.answers.len() as u16);
90         push_n16!(0);
91         push_n16!(0);
92 
93         for query in self.queries.iter() {
94             for part in query.name.split('.') {
95                 push_u8!(part.len() as u8);
96                 data.extend_from_slice(part.as_bytes());
97             }
98             push_u8!(0);
99             push_n16!(query.q_type);
100             push_n16!(query.q_class);
101         }
102         data
103     }
104 
parse(data: &[u8]) -> Result<Self, String>105     pub fn parse(data: &[u8]) -> Result<Self, String> {
106         let name_ind = 0b1100_0000;
107         let mut i = 0;
108 
109         macro_rules! pop_u8 {
110             () => {{
111                 i += 1;
112                 if i > data.len() {
113                     return Err(format!("{}: {}: pop_u8", file!(), line!()));
114                 }
115                 data[i - 1]
116             }};
117         };
118 
119         macro_rules! pop_n16 {
120             () => {{
121                 i += 2;
122                 if i > data.len() {
123                     return Err(format!("{}: {}: pop_n16", file!(), line!()));
124                 }
125                 let x = u16::from(n16::from_bytes(&data[i - 2..i]));
126                 x
127             }};
128         };
129 
130         macro_rules! pop_data {
131             () => {{
132                 let mut data = Vec::new();
133 
134                 let data_len = pop_n16!();
135                 for _data_i in 0..data_len {
136                     data.push(pop_u8!());
137                 }
138 
139                 data
140             }};
141         };
142 
143         macro_rules! pop_name {
144             () => {{
145                 let mut name = String::new();
146                 let old_i = i;
147 
148                 loop {
149                     let name_len = pop_u8!();
150                     if name_len & name_ind == name_ind {
151                         i -= 1;
152                         i = (pop_n16!() - ((name_ind as u16) << 8)) as usize;
153                         continue;
154                     }
155                     if name_len == 0 {
156                         break;
157                     }
158                     if !name.is_empty() {
159                         name.push('.');
160                     }
161                     for _name_i in 0..name_len {
162                         name.push(pop_u8!() as char);
163                     }
164                 }
165 
166                 if i <= old_i {
167                     i = old_i + 2;
168                 }
169 
170                 name
171             }};
172         };
173 
174         let transaction_id = pop_n16!();
175         let flags = pop_n16!();
176         let queries_len = pop_n16!();
177         let answers_len = pop_n16!();
178         pop_n16!();
179         pop_n16!();
180 
181         let mut queries = Vec::new();
182         for _query_i in 0..queries_len {
183             queries.push(DnsQuery {
184                 name: pop_name!(),
185                 q_type: pop_n16!(),
186                 q_class: pop_n16!(),
187             });
188         }
189 
190         let mut answers = Vec::new();
191         for _answer_i in 0..answers_len {
192             answers.push(DnsAnswer {
193                 name: pop_name!(),
194                 a_type: pop_n16!(),
195                 a_class: pop_n16!(),
196                 ttl_a: pop_n16!(),
197                 ttl_b: pop_n16!(),
198                 data: pop_data!(),
199             });
200         }
201 
202         Ok(Dns {
203             transaction_id,
204             flags,
205             queries,
206             answers,
207         })
208     }
209 }
210