1use alloc::{boxed::Box, string::ToString, vec::Vec};
2use core::{mem, ptr};
3
4use crate::{
5 out::Out,
6 platform::{
7 Pal, Sys,
8 types::{c_int, c_void},
9 },
10};
11
12use crate::header::{
13 bits_arpainet::htons,
14 errno::*,
15 netinet_in::{IPPROTO_UDP, in_addr, sockaddr_in},
16 sys_socket::{
17 self,
18 constants::{AF_INET, SOCK_DGRAM},
19 sockaddr, socklen_t,
20 },
21 time::{self, timespec},
22};
23
24use super::{
25 dns::{Dns, DnsQuery},
26 sys::get_dns_server,
27};
28
29pub type LookupHost = Vec<in_addr>;
30
31pub fn lookup_host(host: &str) -> Result<LookupHost, c_int> {
32 if let Some(host_direct_addr) = parse_ipv4_string(host) {
33 return Ok(vec![in_addr {
35 s_addr: host_direct_addr,
36 }]);
37 }
38
39 let dns_string = get_dns_server().map_err(|e| e.0)?;
40
41 if let Some(dns_addr) = parse_ipv4_string(&dns_string) {
42 let mut timespec = timespec::default();
43 if let Ok(()) = Sys::clock_gettime(
44 time::constants::CLOCK_REALTIME,
45 Out::from_mut(&mut timespec),
46 ) {}; let tid = (timespec.tv_nsec >> 16) as u16;
48
49 let packet = Dns {
50 transaction_id: tid,
51 flags: 0x0100,
52 queries: vec![DnsQuery {
53 name: host.to_string(),
54 q_type: 0x0001,
55 q_class: 0x0001,
56 }],
57 answers: vec![],
58 };
59
60 let packet_data = packet.compile();
61 let packet_data_len = packet_data.len();
62
63 let packet_data_box = packet_data.into_boxed_slice();
64 let packet_data_ptr = Box::into_raw(packet_data_box).cast::<c_void>();
65
66 let dest = sockaddr_in {
67 sin_family: AF_INET as u16,
68 sin_port: htons(53),
69 sin_addr: in_addr { s_addr: dns_addr },
70 ..Default::default()
71 };
72 let dest_ptr = ptr::from_ref(&dest).cast::<sockaddr>();
73
74 let sock = unsafe {
75 let sock = sys_socket::socket(AF_INET, SOCK_DGRAM, i32::from(IPPROTO_UDP));
76 if sys_socket::connect(sock, dest_ptr, mem::size_of_val(&dest) as socklen_t) < 0 {
77 return Err(EIO);
78 }
79 if sys_socket::send(sock, packet_data_ptr, packet_data_len, 0) < 0 {
80 drop(Box::from_raw(packet_data_ptr));
81 return Err(EIO);
82 }
83 sock
84 };
85
86 unsafe {
87 drop(Box::from_raw(packet_data_ptr));
88 }
89
90 let i = 0 as socklen_t;
91 let mut buf = vec![0u8; 65536];
92 let buf_ptr = buf.as_mut_ptr().cast::<c_void>();
93
94 let count = unsafe { sys_socket::recv(sock, buf_ptr, 65536, 0) };
95 if count < 0 {
96 return Err(EIO);
97 }
98
99 match Dns::parse(&buf[..count as usize]) {
100 Ok(response) => {
101 let addrs: Vec<_> = response
102 .answers
103 .into_iter()
104 .filter_map(|answer| {
105 if answer.a_type == 0x0001
106 && answer.a_class == 0x0001
107 && answer.data.len() == 4
108 {
109 let addr = in_addr {
110 s_addr: u32::from_ne_bytes([
111 answer.data[0],
112 answer.data[1],
113 answer.data[2],
114 answer.data[3],
115 ]),
116 };
117 Some(addr)
118 } else {
119 None
120 }
121 })
122 .collect();
123
124 Ok(addrs)
125 }
126 Err(_err) => Err(EINVAL),
127 }
128 } else {
129 Err(EINVAL)
130 }
131}
132
133pub fn lookup_addr(addr: in_addr) -> Result<Vec<Vec<u8>>, c_int> {
134 let dns_string = get_dns_server().map_err(|e| e.0)?;
135
136 if let Some(dns_addr) = parse_ipv4_string(&dns_string) {
137 let addr: [u8; 4] = addr.s_addr.to_ne_bytes();
138 let name = format!(
140 "{}.{}.{}.{}.in-addr.arpa",
141 addr[3], addr[2], addr[1], addr[0]
142 );
143
144 let mut timespec = timespec::default();
145 if let Ok(()) = Sys::clock_gettime(
146 time::constants::CLOCK_REALTIME,
147 Out::from_mut(&mut timespec),
148 ) {}; let tid = (timespec.tv_nsec >> 16) as u16;
150
151 let packet = Dns {
152 transaction_id: tid,
153 flags: 0x0100,
154 queries: vec![DnsQuery {
155 name,
156 q_type: 0x000C,
157 q_class: 0x0001,
158 }],
159 answers: vec![],
160 };
161
162 let packet_data = packet.compile();
163 let packet_data_len = packet_data.len();
164 let packet_data_box = packet_data.into_boxed_slice();
165 let packet_data_ptr = Box::into_raw(packet_data_box).cast::<c_void>();
166
167 let dest = sockaddr_in {
168 sin_family: AF_INET as u16,
169 sin_port: htons(53),
170 sin_addr: in_addr { s_addr: dns_addr },
171 ..Default::default()
172 };
173
174 let dest_ptr = ptr::from_ref(&dest).cast::<sockaddr>();
175
176 let sock = unsafe {
177 let sock = sys_socket::socket(AF_INET, SOCK_DGRAM, i32::from(IPPROTO_UDP));
178 if sys_socket::connect(sock, dest_ptr, mem::size_of_val(&dest) as socklen_t) < 0 {
179 return Err(EIO);
180 }
181 sock
182 };
183
184 unsafe {
185 if sys_socket::send(sock, packet_data_ptr, packet_data_len, 0) < 0 {
186 return Err(EIO);
187 }
188 }
189
190 unsafe {
191 drop(Box::from_raw(packet_data_ptr));
192 }
193
194 let i = mem::size_of::<sockaddr_in>() as socklen_t;
195 let mut buf = [0u8; 65536];
196 let buf_ptr = buf.as_mut_ptr().cast::<c_void>();
197
198 let count = unsafe { sys_socket::recv(sock, buf_ptr, 65536, 0) };
199 if count < 0 {
200 return Err(EIO);
201 }
202
203 match Dns::parse(&buf[..count as usize]) {
204 Ok(response) => {
205 let names = response
206 .answers
207 .into_iter()
208 .filter_map(|answer| {
209 if answer.a_type == 0x000C && answer.a_class == 0x0001 {
210 Some(parse_revdns_answer(&answer.data))
216 } else {
217 None
218 }
219 })
220 .collect();
221 Ok(names)
222 }
223 Err(_err) => Err(EINVAL),
224 }
225 } else {
226 Err(EINVAL)
227 }
228}
229
230fn parse_revdns_answer(data: &[u8]) -> Vec<u8> {
231 if data.is_empty() || data[0] == 0 {
232 return vec![0];
233 }
234
235 let mut cursor = 0;
236 let mut index = 0;
237 let mut output = data[1..].to_vec();
239 let length = data.len() - 1;
240 while index < length {
241 let offset = data[index] as usize;
242 if offset > length {
244 return vec![0];
245 }
246 index = cursor + offset + 1;
247 output[index - 1] = b'.';
249 cursor = index;
250 }
251 match output.last_mut() {
253 Some(nul) => *nul = b'\0',
254 None => {
256 debug_assert!(output.is_empty());
257 output = vec![0];
258 }
259 }
260 output
261}
262
263pub fn parse_ipv4_string(ip_string: &str) -> Option<u32> {
264 let dns_vec: Vec<u8> = ip_string
265 .trim()
266 .split('.')
267 .map(|octet| octet.parse::<u8>().unwrap_or(0))
268 .collect();
269
270 if dns_vec.len() != 4 {
271 return None;
272 }
273
274 let mut dns_arr = [0u8; 4];
275
276 for (i, octet) in dns_vec.iter().enumerate() {
277 dns_arr[i] = *octet;
278 }
279
280 Some(u32::from_ne_bytes(dns_arr))
281}
282
283#[cfg(test)]
284mod tests {
285 use alloc::str;
286 use core::ffi::CStr;
287
288 use super::parse_revdns_answer;
289
290 const DNS_GOOGLE: &[u8] = &[3, 100, 110, 115, 6, 103, 111, 111, 103, 108, 101, 0];
292 const EXPECTED_DNS_GOOGLE: &str = "dns.google\0";
293 const EXPECTED_DNS_GOOGLE_RT: &str = "dns.google";
294
295 const FAKE_WITH_NUMS: &[u8] = &[
297 14, 102, 97, 107, 101, 45, 49, 48, 48, 45, 50, 45, 51, 45, 52, 8, 102, 111, 111, 98, 97,
298 114, 50, 52, 4, 102, 97, 107, 101, 0,
299 ];
300 const EXPECTED_FAKE_RESPONSE: &str = "fake-100-2-3-4.foobar24.fake\0";
301 const EXPECTED_FAKE_RESPONSE_RT: &str = "fake-100-2-3-4.foobar24.fake";
302
303 const EMPTY_RESPONSE: &[u8] = &[0];
304 const EXPECTED_EMPTY_RESPONSE: &str = "\0";
305 const EXPECTED_EMPTY_RESPONSE_RT: &str = "";
306
307 #[test]
308 fn dns_response_dns_google() {
309 let response = parse_revdns_answer(DNS_GOOGLE);
310 assert_eq!(
311 0,
312 *response.last().unwrap(),
313 "Response should end with a NUL byte"
314 );
315
316 let response_str = str::from_utf8(&response)
317 .expect("Response is valid UTF-8; parsing shouldn't change that");
318 assert_eq!(EXPECTED_DNS_GOOGLE, response_str);
319
320 let response_cstr = CStr::from_bytes_with_nul(&response)
321 .expect("Parsed response should have only one NUL byte");
322 let response_cstr_str = response_cstr
323 .to_str()
324 .expect("Valid UTF-8 bytes to CStr to Rust str should be valid");
325 assert_eq!(EXPECTED_DNS_GOOGLE_RT, response_cstr_str);
326 }
327
328 #[test]
329 fn dns_response_fake_with_nums() {
330 let response = parse_revdns_answer(FAKE_WITH_NUMS);
331 assert_eq!(
332 0,
333 *response.last().unwrap(),
334 "Response should end with a NUL byte"
335 );
336
337 let response_str = str::from_utf8(&response)
338 .expect("Response is valid UTF-8; parsing shouldn't change that");
339 assert_eq!(EXPECTED_FAKE_RESPONSE, response_str);
340
341 let response_cstr = CStr::from_bytes_with_nul(&response)
342 .expect("Parsed response should have only one NUL byte");
343 let response_cstr_str = response_cstr
344 .to_str()
345 .expect("Valid UTF-8 bytes to CStr to Rust str should be valid");
346 assert_eq!(EXPECTED_FAKE_RESPONSE_RT, response_cstr_str);
347 }
348
349 #[test]
350 fn dns_response_empty() {
351 let response = parse_revdns_answer(EMPTY_RESPONSE);
352 assert_eq!(
353 0,
354 *response.last().unwrap(),
355 "Response should end with a NUL byte"
356 );
357
358 let response_str = str::from_utf8(&response)
359 .expect("Response is valid UTF-8; parsing shouldn't change that");
360 assert_eq!(EXPECTED_EMPTY_RESPONSE, response_str);
361
362 let response_cstr = CStr::from_bytes_with_nul(&response)
363 .expect("Parsed response should have only one NUL byte");
364 let response_cstr_str = response_cstr
365 .to_str()
366 .expect("Valid UTF-8 bytes to CStr to Rust str should be valid");
367 assert_eq!(EXPECTED_EMPTY_RESPONSE_RT, response_cstr_str);
368 }
369}