Skip to content

Commit 7614614

Browse files
authored
Merge pull request #1211 from stlankes/dns
add basic DNS support
2 parents 28c0458 + c28cb48 commit 7614614

File tree

4 files changed

+200
-2
lines changed

4 files changed

+200
-2
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ rtl8139 = ["tcp", "pci"]
6262
smp = []
6363
tcp = ["smoltcp", "smoltcp/socket-tcp"]
6464
udp = ["smoltcp", "smoltcp/socket-udp"]
65+
dns = ["smoltcp", "smoltcp/socket-dns"]
6566
trace = []
6667
vga = []
6768
common-os = []

src/executor/device.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,14 @@ use smoltcp::iface::{Config, Interface, SocketSet};
77
use smoltcp::phy::{self, ChecksumCapabilities, Device, DeviceCapabilities, Medium};
88
#[cfg(feature = "dhcpv4")]
99
use smoltcp::socket::dhcpv4;
10+
#[cfg(all(feature = "dns", not(feature = "dhcpv4")))]
11+
use smoltcp::socket::dns;
1012
use smoltcp::time::Instant;
13+
#[cfg(any(feature = "dns", not(feature = "dhcpv4")))]
14+
use smoltcp::wire::Ipv4Address;
1115
use smoltcp::wire::{EthernetAddress, HardwareAddress};
1216
#[cfg(not(feature = "dhcpv4"))]
13-
use smoltcp::wire::{IpAddress, IpCidr, Ipv4Address};
17+
use smoltcp::wire::{IpAddress, IpCidr};
1418

1519
use super::network::{NetworkInterface, NetworkState};
1620
use crate::arch;
@@ -74,6 +78,8 @@ impl<'a> NetworkInterface<'a> {
7478
sockets,
7579
device,
7680
dhcp_handle,
81+
#[cfg(feature = "dns")]
82+
dns_handle: None,
7783
}))
7884
}
7985

@@ -150,10 +156,26 @@ impl<'a> NetworkInterface<'a> {
150156
});
151157
iface.routes_mut().add_default_ipv4_route(mygw).unwrap();
152158

159+
#[allow(unused_mut)]
160+
let mut sockets = SocketSet::new(vec![]);
161+
162+
#[cfg(feature = "dns")]
163+
let dns_handle = {
164+
// use Google's DNS servers
165+
let servers = &[
166+
Ipv4Address::new(8, 8, 4, 4).into(),
167+
Ipv4Address::new(8, 8, 8, 8).into(),
168+
];
169+
let dns_socket = dns::Socket::new(servers, vec![]);
170+
sockets.add(dns_socket)
171+
};
172+
153173
NetworkState::Initialized(Box::new(Self {
154174
iface,
155-
sockets: SocketSet::new(vec![]),
175+
sockets,
156176
device,
177+
#[cfg(feature = "dns")]
178+
dns_handle: Some(dns_handle),
157179
}))
158180
}
159181
}

src/executor/network.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use alloc::boxed::Box;
2+
#[cfg(feature = "dns")]
3+
use alloc::vec::Vec;
24
use core::future;
35
use core::ops::DerefMut;
46
use core::sync::atomic::{AtomicU16, Ordering};
@@ -8,18 +10,24 @@ use hermit_sync::InterruptTicketMutex;
810
use smoltcp::iface::{SocketHandle, SocketSet};
911
#[cfg(feature = "dhcpv4")]
1012
use smoltcp::socket::dhcpv4;
13+
#[cfg(feature = "dns")]
14+
use smoltcp::socket::dns::{self, GetQueryResultError, QueryHandle};
1115
#[cfg(feature = "tcp")]
1216
use smoltcp::socket::tcp;
1317
#[cfg(feature = "udp")]
1418
use smoltcp::socket::udp;
1519
use smoltcp::socket::AnySocket;
1620
use smoltcp::time::{Duration, Instant};
21+
#[cfg(feature = "dns")]
22+
use smoltcp::wire::{DnsQueryType, IpAddress};
1723
#[cfg(feature = "dhcpv4")]
1824
use smoltcp::wire::{IpCidr, Ipv4Address, Ipv4Cidr};
1925

2026
use crate::arch;
2127
use crate::executor::device::HermitNet;
2228
use crate::executor::spawn;
29+
#[cfg(feature = "dns")]
30+
use crate::fd::IoError;
2331
use crate::scheduler::PerCoreSchedulerExt;
2432

2533
pub(crate) enum NetworkState<'a> {
@@ -49,6 +57,8 @@ pub(crate) struct NetworkInterface<'a> {
4957
pub(super) device: HermitNet,
5058
#[cfg(feature = "dhcpv4")]
5159
pub(super) dhcp_handle: SocketHandle,
60+
#[cfg(feature = "dns")]
61+
pub(super) dns_handle: Option<SocketHandle>,
5262
}
5363

5464
#[cfg(target_arch = "x86_64")]
@@ -104,6 +114,34 @@ async fn network_run() {
104114
.await
105115
}
106116

117+
#[cfg(feature = "dns")]
118+
pub(crate) async fn get_query_result(query: QueryHandle) -> Result<Vec<IpAddress>, IoError> {
119+
future::poll_fn(|cx| {
120+
let mut guard = NIC.lock();
121+
let nic = guard.as_nic_mut().unwrap();
122+
let socket = nic.get_mut_dns_socket()?;
123+
match socket.get_query_result(query) {
124+
Ok(addrs) => {
125+
let mut ips = Vec::new();
126+
for x in &addrs {
127+
ips.push(*x);
128+
}
129+
130+
Poll::Ready(Ok(ips))
131+
}
132+
Err(GetQueryResultError::Pending) => {
133+
socket.register_query_waker(query, cx.waker());
134+
Poll::Pending
135+
}
136+
Err(e) => {
137+
warn!("DNS query failed: {e:?}");
138+
Poll::Ready(Err(IoError::ENOENT))
139+
}
140+
}
141+
})
142+
.await
143+
}
144+
107145
pub(crate) fn init() {
108146
info!("Try to initialize network!");
109147

@@ -183,8 +221,18 @@ impl<'a> NetworkInterface<'a> {
183221
self.iface.routes_mut().remove_default_ipv4_route();
184222
}
185223

224+
#[cfg(feature = "dns")]
225+
let mut dns_servers: Vec<IpAddress> = Vec::new();
186226
for (i, s) in config.dns_servers.iter().enumerate() {
187227
info!("DNS server {}: {}", i, s);
228+
#[cfg(feature = "dns")]
229+
dns_servers.push(IpAddress::Ipv4(*s));
230+
}
231+
232+
#[cfg(feature = "dns")]
233+
if dns_servers.len() > 0 {
234+
let dns_socket = dns::Socket::new(dns_servers.as_slice(), vec![]);
235+
self.dns_handle = Some(self.sockets.add(dns_socket));
188236
}
189237
}
190238
Some(dhcpv4::Event::Deconfigured) => {
@@ -196,6 +244,15 @@ impl<'a> NetworkInterface<'a> {
196244
}
197245
});
198246
self.iface.routes_mut().remove_default_ipv4_route();
247+
248+
#[cfg(feature = "dns")]
249+
{
250+
if let Some(dns_handle) = self.dns_handle {
251+
self.sockets.remove(dns_handle);
252+
}
253+
254+
self.dns_handle = None;
255+
}
199256
}
200257
};
201258
}
@@ -224,6 +281,32 @@ impl<'a> NetworkInterface<'a> {
224281
// This deallocates the socket's buffers
225282
self.sockets.remove(handle);
226283
}
284+
285+
#[cfg(feature = "dns")]
286+
pub(crate) fn start_query(
287+
&mut self,
288+
name: &str,
289+
query_type: DnsQueryType,
290+
) -> Result<QueryHandle, IoError> {
291+
let dns_handle = self.dns_handle.ok_or(IoError::EINVAL)?;
292+
let socket: &mut dns::Socket<'a> = self.sockets.get_mut(dns_handle);
293+
socket
294+
.start_query(self.iface.context(), name, query_type)
295+
.map_err(|_| IoError::EIO)
296+
}
297+
298+
#[allow(dead_code)]
299+
#[cfg(feature = "dns")]
300+
pub(crate) fn get_dns_socket(&self) -> Result<&dns::Socket<'a>, IoError> {
301+
let dns_handle = self.dns_handle.ok_or(IoError::EINVAL)?;
302+
Ok(self.sockets.get(dns_handle))
303+
}
304+
305+
#[cfg(feature = "dns")]
306+
pub(crate) fn get_mut_dns_socket(&mut self) -> Result<&mut dns::Socket<'a>, IoError> {
307+
let dns_handle = self.dns_handle.ok_or(IoError::EINVAL)?;
308+
Ok(self.sockets.get_mut(dns_handle))
309+
}
227310
}
228311

229312
#[inline]

src/syscalls/socket.rs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,98 @@ pub struct linger {
257257
pub l_linger: i32,
258258
}
259259

260+
#[cfg(not(feature = "dns"))]
261+
#[hermit_macro::system]
262+
#[no_mangle]
263+
pub unsafe extern "C" fn sys_getaddrbyname(
264+
_name: *const c_char,
265+
_inaddr: *mut u8,
266+
_len: usize,
267+
) -> i32 {
268+
error!("Please enable the feature 'dns' to determine the network ip by name.");
269+
-ENOSYS
270+
}
271+
272+
/// The system call `sys_getaddrbyname` determine the network host entry.
273+
/// It expects an array of u8 with a size of in_addr or of in6_addr.
274+
/// The result of the DNS request will be stored in this array.
275+
///
276+
/// # Example
277+
///
278+
/// ```
279+
/// use hermit_abi::in_addr;
280+
/// let c_string = std::ffi::CString::new("rust-lang.org").expect("CString::new failed");
281+
/// let name = c_string.into_raw();
282+
/// let mut inaddr: in_addr = Default::default();
283+
/// let _ = unsafe {
284+
/// hermit_abi::getaddrbyname(
285+
/// name,
286+
/// &mut inaddr as *mut _ as *mut u8,
287+
/// std::mem::size_of::<in_addr>(),
288+
/// )
289+
/// };
290+
///
291+
/// // retake pointer to free memory
292+
/// let _ = CString::from_raw(name);
293+
/// ```
294+
#[cfg(feature = "dns")]
295+
#[hermit_macro::system]
296+
#[no_mangle]
297+
pub unsafe extern "C" fn sys_getaddrbyname(
298+
name: *const c_char,
299+
inaddr: *mut u8,
300+
len: usize,
301+
) -> i32 {
302+
use alloc::borrow::ToOwned;
303+
304+
use smoltcp::wire::DnsQueryType;
305+
306+
use crate::executor::block_on;
307+
use crate::executor::network::get_query_result;
308+
309+
if len != size_of::<in_addr>().try_into().unwrap()
310+
&& len != size_of::<in6_addr>().try_into().unwrap()
311+
{
312+
return -EINVAL;
313+
}
314+
315+
if inaddr.is_null() {
316+
return -EINVAL;
317+
}
318+
319+
let query_type = if len == size_of::<in6_addr>().try_into().unwrap() {
320+
DnsQueryType::Aaaa
321+
} else {
322+
DnsQueryType::A
323+
};
324+
325+
let name = unsafe { core::ffi::CStr::from_ptr(name) };
326+
let name = if let Ok(name) = name.to_str() {
327+
name.to_owned()
328+
} else {
329+
return -EINVAL;
330+
};
331+
332+
let query = {
333+
let mut guard = NIC.lock();
334+
let nic = guard.as_nic_mut().unwrap();
335+
let query = nic.start_query(&name, query_type).unwrap();
336+
nic.poll_common(crate::executor::network::now());
337+
338+
query
339+
};
340+
341+
match block_on(get_query_result(query), None) {
342+
Ok(addr_vec) => {
343+
let slice = unsafe { core::slice::from_raw_parts_mut(inaddr, len) };
344+
slice.copy_from_slice(addr_vec[0].as_bytes());
345+
346+
0
347+
}
348+
Err(e) => -num::ToPrimitive::to_i32(&e).unwrap(),
349+
}
350+
}
351+
260352
#[hermit_macro::system]
261353
#[no_mangle]
262354
pub extern "C" fn sys_socket(domain: i32, type_: SockType, protocol: i32) -> i32 {

0 commit comments

Comments
 (0)