1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
use core::convert::{TryFrom, TryInto};
use crate::io;
use crate::net::{Ipv4Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use crate::os::xous::ffi::lend_mut;
use crate::os::xous::services::{DnsLendMut, dns_server};
pub struct DnsError {
pub code: u8,
}
#[repr(C, align(4096))]
struct LookupHostQuery([u8; 4096]);
pub struct LookupHost {
data: LookupHostQuery,
port: u16,
offset: usize,
count: usize,
}
impl LookupHost {
pub fn port(&self) -> u16 {
self.port
}
}
impl Iterator for LookupHost {
type Item = SocketAddr;
fn next(&mut self) -> Option<SocketAddr> {
if self.offset >= self.data.0.len() {
return None;
}
match self.data.0.get(self.offset) {
Some(&4) => {
self.offset += 1;
if self.offset + 4 > self.data.0.len() {
return None;
}
let result = Some(SocketAddr::V4(SocketAddrV4::new(
Ipv4Addr::new(
self.data.0[self.offset],
self.data.0[self.offset + 1],
self.data.0[self.offset + 2],
self.data.0[self.offset + 3],
),
self.port,
)));
self.offset += 4;
result
}
Some(&6) => {
self.offset += 1;
if self.offset + 16 > self.data.0.len() {
return None;
}
let mut new_addr = [0u8; 16];
for (src, octet) in self.data.0[(self.offset + 1)..(self.offset + 16 + 1)]
.iter()
.zip(new_addr.iter_mut())
{
*octet = *src;
}
let result =
Some(SocketAddr::V6(SocketAddrV6::new(new_addr.into(), self.port, 0, 0)));
self.offset += 16;
result
}
_ => None,
}
}
}
pub fn lookup(query: &str, port: u16) -> Result<LookupHost, DnsError> {
let mut result = LookupHost { data: LookupHostQuery([0u8; 4096]), offset: 0, count: 0, port };
// Copy the query into the message that gets sent to the DNS server
for (query_byte, result_byte) in query.as_bytes().iter().zip(result.data.0.iter_mut()) {
*result_byte = *query_byte;
}
lend_mut(
dns_server(),
DnsLendMut::RawLookup.into(),
&mut result.data.0,
0,
query.as_bytes().len(),
)
.unwrap();
if result.data.0[0] != 0 {
return Err(DnsError { code: result.data.0[1] });
}
assert_eq!(result.offset, 0);
result.count = result.data.0[1] as usize;
// Advance the offset to the first record
result.offset = 2;
Ok(result)
}
impl TryFrom<&str> for LookupHost {
type Error = io::Error;
fn try_from(s: &str) -> io::Result<LookupHost> {
macro_rules! try_opt {
($e:expr, $msg:expr) => {
match $e {
Some(r) => r,
None => return Err(io::const_io_error!(io::ErrorKind::InvalidInput, &$msg)),
}
};
}
// split the string by ':' and convert the second part to u16
let (host, port_str) = try_opt!(s.rsplit_once(':'), "invalid socket address");
let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value");
(host, port).try_into()
}
}
impl TryFrom<(&str, u16)> for LookupHost {
type Error = io::Error;
fn try_from(v: (&str, u16)) -> io::Result<LookupHost> {
lookup(v.0, v.1)
.map_err(|_e| io::const_io_error!(io::ErrorKind::InvalidInput, &"DNS failure"))
}
}
|