xref: /relibc/src/header/netdb/lookup.rs (revision 041d1604b526a0b908d4222e39baa0030a94fd8f)
1 use alloc::{
2     boxed::Box,
3     string::{String, ToString},
4     vec::{IntoIter, Vec},
5 };
6 use core::mem;
7 
8 use crate::platform::{types::*, Pal, Sys};
9 
10 use crate::header::{
11     arpa_inet::htons,
12     errno::*,
13     netinet_in::{in_addr, sockaddr_in, IPPROTO_UDP},
14     sys_socket::{
15         self,
16         constants::{AF_INET, SOCK_DGRAM},
17         sockaddr, socklen_t,
18     },
19     time::{self, timespec},
20 };
21 
22 use super::{
23     dns::{Dns, DnsQuery},
24     sys::get_dns_server,
25 };
26 
27 pub struct LookupHost(IntoIter<in_addr>);
28 
29 impl Iterator for LookupHost {
30     type Item = in_addr;
31     fn next(&mut self) -> Option<Self::Item> {
32         self.0.next()
33     }
34 }
35 
36 pub fn lookup_host(host: &str) -> Result<LookupHost, c_int> {
37     let dns_string = get_dns_server();
38 
39     let dns_vec: Vec<u8> = dns_string
40         .trim()
41         .split('.')
42         .map(|octet| octet.parse::<u8>().unwrap_or(0))
43         .collect();
44 
45     if dns_vec.len() == 4 {
46         let mut dns_arr = [0u8; 4];
47         for (i, octet) in dns_vec.iter().enumerate() {
48             dns_arr[i] = *octet;
49         }
50         let dns_addr = unsafe { mem::transmute::<[u8; 4], u32>(dns_arr) };
51 
52         let mut timespec = timespec::default();
53         Sys::clock_gettime(time::constants::CLOCK_REALTIME, &mut timespec);
54         let tid = (timespec.tv_nsec >> 16) as u16;
55 
56         let packet = Dns {
57             transaction_id: tid,
58             flags: 0x0100,
59             queries: vec![DnsQuery {
60                 name: host.to_string(),
61                 q_type: 0x0001,
62                 q_class: 0x0001,
63             }],
64             answers: vec![],
65         };
66 
67         let packet_data = packet.compile();
68         let packet_data_len = packet_data.len();
69 
70         let packet_data_box = packet_data.into_boxed_slice();
71         let packet_data_ptr = Box::into_raw(packet_data_box) as *mut _ as *mut c_void;
72 
73         let dest = sockaddr_in {
74             sin_family: AF_INET as u16,
75             sin_port: htons(53),
76             sin_addr: in_addr { s_addr: dns_addr },
77             ..Default::default()
78         };
79         let dest_ptr = &dest as *const _ as *const sockaddr;
80 
81         let sock = unsafe {
82             let sock = sys_socket::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP as i32);
83             if sys_socket::connect(sock, dest_ptr, mem::size_of_val(&dest) as socklen_t) < 0 {
84                 return Err(EIO);
85             }
86             if sys_socket::send(sock, packet_data_ptr, packet_data_len, 0) < 0 {
87                 Box::from_raw(packet_data_ptr);
88                 return Err(EIO);
89             }
90             sock
91         };
92 
93         unsafe {
94             Box::from_raw(packet_data_ptr);
95         }
96 
97         let i = 0 as socklen_t;
98         let mut buf = vec![0u8; 65536];
99         let buf_ptr = buf.as_mut_ptr() as *mut c_void;
100 
101         let count = unsafe { sys_socket::recv(sock, buf_ptr, 65536, 0) };
102         if count < 0 {
103             return Err(EIO);
104         }
105 
106         match Dns::parse(&buf[..count as usize]) {
107             Ok(response) => {
108                 let mut addrs = vec![];
109                 for answer in response.answers.iter() {
110                     if answer.a_type == 0x0001 && answer.a_class == 0x0001 && answer.data.len() == 4
111                     {
112                         let addr = in_addr {
113                             s_addr: unsafe {
114                                 mem::transmute::<[u8; 4], u32>([
115                                     answer.data[0],
116                                     answer.data[1],
117                                     answer.data[2],
118                                     answer.data[3],
119                                 ])
120                             },
121                         };
122                         addrs.push(addr);
123                     }
124                 }
125                 Ok(LookupHost(addrs.into_iter()))
126             }
127             Err(_err) => Err(EINVAL),
128         }
129     } else {
130         Err(EINVAL)
131     }
132 }
133 
134 pub fn lookup_addr(addr: in_addr) -> Result<Vec<Vec<u8>>, c_int> {
135     let dns_string = get_dns_server();
136 
137     let dns_vec: Vec<u8> = dns_string
138         .trim()
139         .split('.')
140         .map(|octet| octet.parse::<u8>().unwrap_or(0))
141         .collect();
142 
143     let mut dns_arr = [0u8; 4];
144 
145     for (i, octet) in dns_vec.iter().enumerate() {
146         dns_arr[i] = *octet;
147     }
148 
149     let mut addr_vec: Vec<u8> = unsafe { mem::transmute::<u32, [u8; 4]>(addr.s_addr).to_vec() };
150     addr_vec.reverse();
151     let mut name: Vec<u8> = vec![];
152     for octet in addr_vec {
153         for ch in format!("{}", octet).as_bytes() {
154             name.push(*ch);
155         }
156         name.push(b"."[0]);
157     }
158     name.pop();
159     for ch in b".IN-ADDR.ARPA" {
160         name.push(*ch);
161     }
162 
163     if dns_vec.len() == 4 {
164         let mut timespec = timespec::default();
165         Sys::clock_gettime(time::constants::CLOCK_REALTIME, &mut timespec);
166         let tid = (timespec.tv_nsec >> 16) as u16;
167 
168         let packet = Dns {
169             transaction_id: tid,
170             flags: 0x0100,
171             queries: vec![DnsQuery {
172                 name: String::from_utf8(name).unwrap(),
173                 q_type: 0x000C,
174                 q_class: 0x0001,
175             }],
176             answers: vec![],
177         };
178 
179         let packet_data = packet.compile();
180         let packet_data_len = packet_data.len();
181         let packet_data_box = packet_data.into_boxed_slice();
182         let packet_data_ptr = Box::into_raw(packet_data_box) as *mut _ as *mut c_void;
183 
184         let dest = sockaddr_in {
185             sin_family: AF_INET as u16,
186             sin_port: htons(53),
187             sin_addr: in_addr {
188                 s_addr: unsafe { mem::transmute::<[u8; 4], u32>(dns_arr) },
189             },
190             ..Default::default()
191         };
192 
193         let dest_ptr = &dest as *const _ as *const sockaddr;
194 
195         let sock = unsafe {
196             let sock = sys_socket::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP as i32);
197             if sys_socket::connect(sock, dest_ptr, mem::size_of_val(&dest) as socklen_t) < 0 {
198                 return Err(EIO);
199             }
200             sock
201         };
202 
203         unsafe {
204             if sys_socket::send(sock, packet_data_ptr, packet_data_len, 0) < 0 {
205                 return Err(EIO);
206             }
207         }
208 
209         unsafe {
210             Box::from_raw(packet_data_ptr);
211         }
212 
213         let i = mem::size_of::<sockaddr_in>() as socklen_t;
214         let mut buf = [0u8; 65536];
215         let buf_ptr = buf.as_mut_ptr() as *mut c_void;
216 
217         let count = unsafe { sys_socket::recv(sock, buf_ptr, 65536, 0) };
218         if count < 0 {
219             return Err(EIO);
220         }
221 
222         match Dns::parse(&buf[..count as usize]) {
223             Ok(response) => {
224                 let mut names = vec![];
225                 for answer in response.answers.iter() {
226                     if answer.a_type == 0x000C && answer.a_class == 0x0001 {
227                         // answer.data is encoded kinda weird.
228                         // Basically length-prefixed strings for each
229                         // subsection of the domain.
230                         // We need to parse this to insert periods where
231                         // they belong (ie at the end of each string)
232                         let data = parse_revdns_answer(&answer.data);
233                         names.push(data);
234                     }
235                 }
236                 Ok(names)
237             }
238             Err(_err) => Err(EINVAL),
239         }
240     } else {
241         Err(EINVAL)
242     }
243 }
244 
245 fn parse_revdns_answer(data: &[u8]) -> Vec<u8> {
246     let mut cursor = 0;
247     let mut index = 0;
248     let mut output = data.to_vec();
249     while index < data.len() - 1 {
250         let offset = data[index] as usize;
251         index = cursor + offset + 1;
252         output[index] = b'.';
253         cursor = index;
254     }
255     //we don't want an extra period at the end
256     output.pop();
257     output
258 }
259