xref: /relibc/src/header/netdb/dns/mod.rs (revision be35961d82cd98f2a2e61c4f1869271b9f4af571)
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 {
27     pub fn as_bytes(&self) -> &[u8] {
28         unsafe { slice::from_raw_parts((&self.inner as *const u16) as *const u8, 2) }
29     }
30 
31     pub fn from_bytes(bytes: &[u8]) -> Self {
32         n16 {
33             inner: unsafe {
34                 slice::from_raw_parts(bytes.as_ptr() as *const u16, bytes.len() / 2)[0]
35             },
36         }
37     }
38 }
39 
40 impl From<u16> for n16 {
41     fn from(value: u16) -> Self {
42         n16 {
43             inner: value.to_be(),
44         }
45     }
46 }
47 
48 impl From<n16> for u16 {
49     fn from(value: n16) -> Self {
50         u16::from_be(value.inner)
51     }
52 }
53 
54 #[derive(Clone, Debug)]
55 pub struct Dns {
56     pub transaction_id: u16,
57     pub flags: u16,
58     pub queries: Vec<DnsQuery>,
59     pub answers: Vec<DnsAnswer>,
60 }
61 
62 impl Dns {
63     pub fn compile(&self) -> Vec<u8> {
64         let mut data = Vec::new();
65 
66         macro_rules! push_u8 {
67             ($value:expr) => {
68                 data.push($value);
69             };
70         };
71 
72         macro_rules! push_n16 {
73             ($value:expr) => {
74                 data.extend_from_slice(n16::from($value).as_bytes());
75             };
76         };
77 
78         push_n16!(self.transaction_id);
79         push_n16!(self.flags);
80         push_n16!(self.queries.len() as u16);
81         push_n16!(self.answers.len() as u16);
82         push_n16!(0);
83         push_n16!(0);
84 
85         for query in self.queries.iter() {
86             for part in query.name.split('.') {
87                 push_u8!(part.len() as u8);
88                 data.extend_from_slice(part.as_bytes());
89             }
90             push_u8!(0);
91             push_n16!(query.q_type);
92             push_n16!(query.q_class);
93         }
94         data
95     }
96 
97     pub fn parse(data: &[u8]) -> Result<Self, String> {
98         let name_ind = 0b1100_0000;
99         let mut i = 0;
100 
101         macro_rules! pop_u8 {
102             () => {{
103                 i += 1;
104                 if i > data.len() {
105                     return Err(format!("{}: {}: pop_u8", file!(), line!()));
106                 }
107                 data[i - 1]
108             }};
109         };
110 
111         macro_rules! pop_n16 {
112             () => {{
113                 i += 2;
114                 if i > data.len() {
115                     return Err(format!("{}: {}: pop_n16", file!(), line!()));
116                 }
117                 u16::from(n16::from_bytes(&data[i - 2..i]))
118             }};
119         };
120 
121         macro_rules! pop_data {
122             () => {{
123                 let mut data = Vec::new();
124 
125                 let data_len = pop_n16!();
126                 for _data_i in 0..data_len {
127                     data.push(pop_u8!());
128                 }
129 
130                 data
131             }};
132         };
133 
134         macro_rules! pop_name {
135             () => {{
136                 let mut name = String::new();
137                 let old_i = i;
138 
139                 loop {
140                     let name_len = pop_u8!();
141                     if name_len & name_ind == name_ind {
142                         i -= 1;
143                         i = (pop_n16!() - ((name_ind as u16) << 8)) as usize;
144                         continue;
145                     }
146                     if name_len == 0 {
147                         break;
148                     }
149                     if !name.is_empty() {
150                         name.push('.');
151                     }
152                     for _name_i in 0..name_len {
153                         name.push(pop_u8!() as char);
154                     }
155                 }
156 
157                 if i <= old_i {
158                     i = old_i + 2;
159                 }
160 
161                 name
162             }};
163         };
164 
165         let transaction_id = pop_n16!();
166         let flags = pop_n16!();
167         let queries_len = pop_n16!();
168         let answers_len = pop_n16!();
169         pop_n16!();
170         pop_n16!();
171 
172         let mut queries = Vec::new();
173         for _query_i in 0..queries_len {
174             queries.push(DnsQuery {
175                 name: pop_name!(),
176                 q_type: pop_n16!(),
177                 q_class: pop_n16!(),
178             });
179         }
180 
181         let mut answers = Vec::new();
182         for _answer_i in 0..answers_len {
183             answers.push(DnsAnswer {
184                 name: pop_name!(),
185                 a_type: pop_n16!(),
186                 a_class: pop_n16!(),
187                 ttl_a: pop_n16!(),
188                 ttl_b: pop_n16!(),
189                 data: pop_data!(),
190             });
191         }
192 
193         Ok(Dns {
194             transaction_id,
195             flags,
196             queries,
197             answers,
198         })
199     }
200 }
201