Skip to content

Commit

Permalink
Merge pull request #1211 from stlankes/dns
Browse files Browse the repository at this point in the history
add basic DNS support
  • Loading branch information
stlankes authored May 22, 2024
2 parents 28c0458 + c28cb48 commit 7614614
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 2 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ rtl8139 = ["tcp", "pci"]
smp = []
tcp = ["smoltcp", "smoltcp/socket-tcp"]
udp = ["smoltcp", "smoltcp/socket-udp"]
dns = ["smoltcp", "smoltcp/socket-dns"]
trace = []
vga = []
common-os = []
Expand Down
26 changes: 24 additions & 2 deletions src/executor/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@ use smoltcp::iface::{Config, Interface, SocketSet};
use smoltcp::phy::{self, ChecksumCapabilities, Device, DeviceCapabilities, Medium};
#[cfg(feature = "dhcpv4")]
use smoltcp::socket::dhcpv4;
#[cfg(all(feature = "dns", not(feature = "dhcpv4")))]
use smoltcp::socket::dns;
use smoltcp::time::Instant;
#[cfg(any(feature = "dns", not(feature = "dhcpv4")))]
use smoltcp::wire::Ipv4Address;
use smoltcp::wire::{EthernetAddress, HardwareAddress};
#[cfg(not(feature = "dhcpv4"))]
use smoltcp::wire::{IpAddress, IpCidr, Ipv4Address};
use smoltcp::wire::{IpAddress, IpCidr};

use super::network::{NetworkInterface, NetworkState};
use crate::arch;
Expand Down Expand Up @@ -74,6 +78,8 @@ impl<'a> NetworkInterface<'a> {
sockets,
device,
dhcp_handle,
#[cfg(feature = "dns")]
dns_handle: None,
}))
}

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

#[allow(unused_mut)]
let mut sockets = SocketSet::new(vec![]);

#[cfg(feature = "dns")]
let dns_handle = {
// use Google's DNS servers
let servers = &[
Ipv4Address::new(8, 8, 4, 4).into(),
Ipv4Address::new(8, 8, 8, 8).into(),
];
let dns_socket = dns::Socket::new(servers, vec![]);
sockets.add(dns_socket)
};

NetworkState::Initialized(Box::new(Self {
iface,
sockets: SocketSet::new(vec![]),
sockets,
device,
#[cfg(feature = "dns")]
dns_handle: Some(dns_handle),
}))
}
}
Expand Down
83 changes: 83 additions & 0 deletions src/executor/network.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use alloc::boxed::Box;
#[cfg(feature = "dns")]
use alloc::vec::Vec;
use core::future;
use core::ops::DerefMut;
use core::sync::atomic::{AtomicU16, Ordering};
Expand All @@ -8,18 +10,24 @@ use hermit_sync::InterruptTicketMutex;
use smoltcp::iface::{SocketHandle, SocketSet};
#[cfg(feature = "dhcpv4")]
use smoltcp::socket::dhcpv4;
#[cfg(feature = "dns")]
use smoltcp::socket::dns::{self, GetQueryResultError, QueryHandle};
#[cfg(feature = "tcp")]
use smoltcp::socket::tcp;
#[cfg(feature = "udp")]
use smoltcp::socket::udp;
use smoltcp::socket::AnySocket;
use smoltcp::time::{Duration, Instant};
#[cfg(feature = "dns")]
use smoltcp::wire::{DnsQueryType, IpAddress};
#[cfg(feature = "dhcpv4")]
use smoltcp::wire::{IpCidr, Ipv4Address, Ipv4Cidr};

use crate::arch;
use crate::executor::device::HermitNet;
use crate::executor::spawn;
#[cfg(feature = "dns")]
use crate::fd::IoError;
use crate::scheduler::PerCoreSchedulerExt;

pub(crate) enum NetworkState<'a> {
Expand Down Expand Up @@ -49,6 +57,8 @@ pub(crate) struct NetworkInterface<'a> {
pub(super) device: HermitNet,
#[cfg(feature = "dhcpv4")]
pub(super) dhcp_handle: SocketHandle,
#[cfg(feature = "dns")]
pub(super) dns_handle: Option<SocketHandle>,
}

#[cfg(target_arch = "x86_64")]
Expand Down Expand Up @@ -104,6 +114,34 @@ async fn network_run() {
.await
}

#[cfg(feature = "dns")]
pub(crate) async fn get_query_result(query: QueryHandle) -> Result<Vec<IpAddress>, IoError> {
future::poll_fn(|cx| {
let mut guard = NIC.lock();
let nic = guard.as_nic_mut().unwrap();
let socket = nic.get_mut_dns_socket()?;
match socket.get_query_result(query) {
Ok(addrs) => {
let mut ips = Vec::new();
for x in &addrs {
ips.push(*x);
}

Poll::Ready(Ok(ips))
}
Err(GetQueryResultError::Pending) => {
socket.register_query_waker(query, cx.waker());
Poll::Pending
}
Err(e) => {
warn!("DNS query failed: {e:?}");
Poll::Ready(Err(IoError::ENOENT))
}
}
})
.await
}

pub(crate) fn init() {
info!("Try to initialize network!");

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

#[cfg(feature = "dns")]
let mut dns_servers: Vec<IpAddress> = Vec::new();
for (i, s) in config.dns_servers.iter().enumerate() {
info!("DNS server {}: {}", i, s);
#[cfg(feature = "dns")]
dns_servers.push(IpAddress::Ipv4(*s));
}

#[cfg(feature = "dns")]
if dns_servers.len() > 0 {
let dns_socket = dns::Socket::new(dns_servers.as_slice(), vec![]);
self.dns_handle = Some(self.sockets.add(dns_socket));
}
}
Some(dhcpv4::Event::Deconfigured) => {
Expand All @@ -196,6 +244,15 @@ impl<'a> NetworkInterface<'a> {
}
});
self.iface.routes_mut().remove_default_ipv4_route();

#[cfg(feature = "dns")]
{
if let Some(dns_handle) = self.dns_handle {
self.sockets.remove(dns_handle);
}

self.dns_handle = None;
}
}
};
}
Expand Down Expand Up @@ -224,6 +281,32 @@ impl<'a> NetworkInterface<'a> {
// This deallocates the socket's buffers
self.sockets.remove(handle);
}

#[cfg(feature = "dns")]
pub(crate) fn start_query(
&mut self,
name: &str,
query_type: DnsQueryType,
) -> Result<QueryHandle, IoError> {
let dns_handle = self.dns_handle.ok_or(IoError::EINVAL)?;
let socket: &mut dns::Socket<'a> = self.sockets.get_mut(dns_handle);
socket
.start_query(self.iface.context(), name, query_type)
.map_err(|_| IoError::EIO)
}

#[allow(dead_code)]
#[cfg(feature = "dns")]
pub(crate) fn get_dns_socket(&self) -> Result<&dns::Socket<'a>, IoError> {
let dns_handle = self.dns_handle.ok_or(IoError::EINVAL)?;
Ok(self.sockets.get(dns_handle))
}

#[cfg(feature = "dns")]
pub(crate) fn get_mut_dns_socket(&mut self) -> Result<&mut dns::Socket<'a>, IoError> {
let dns_handle = self.dns_handle.ok_or(IoError::EINVAL)?;
Ok(self.sockets.get_mut(dns_handle))
}
}

#[inline]
Expand Down
92 changes: 92 additions & 0 deletions src/syscalls/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,98 @@ pub struct linger {
pub l_linger: i32,
}

#[cfg(not(feature = "dns"))]
#[hermit_macro::system]
#[no_mangle]
pub unsafe extern "C" fn sys_getaddrbyname(
_name: *const c_char,
_inaddr: *mut u8,
_len: usize,
) -> i32 {
error!("Please enable the feature 'dns' to determine the network ip by name.");
-ENOSYS
}

/// The system call `sys_getaddrbyname` determine the network host entry.
/// It expects an array of u8 with a size of in_addr or of in6_addr.
/// The result of the DNS request will be stored in this array.
///
/// # Example
///
/// ```
/// use hermit_abi::in_addr;
/// let c_string = std::ffi::CString::new("rust-lang.org").expect("CString::new failed");
/// let name = c_string.into_raw();
/// let mut inaddr: in_addr = Default::default();
/// let _ = unsafe {
/// hermit_abi::getaddrbyname(
/// name,
/// &mut inaddr as *mut _ as *mut u8,
/// std::mem::size_of::<in_addr>(),
/// )
/// };
///
/// // retake pointer to free memory
/// let _ = CString::from_raw(name);
/// ```
#[cfg(feature = "dns")]
#[hermit_macro::system]
#[no_mangle]
pub unsafe extern "C" fn sys_getaddrbyname(
name: *const c_char,
inaddr: *mut u8,
len: usize,
) -> i32 {
use alloc::borrow::ToOwned;

use smoltcp::wire::DnsQueryType;

use crate::executor::block_on;
use crate::executor::network::get_query_result;

if len != size_of::<in_addr>().try_into().unwrap()
&& len != size_of::<in6_addr>().try_into().unwrap()
{
return -EINVAL;
}

if inaddr.is_null() {
return -EINVAL;
}

let query_type = if len == size_of::<in6_addr>().try_into().unwrap() {
DnsQueryType::Aaaa
} else {
DnsQueryType::A
};

let name = unsafe { core::ffi::CStr::from_ptr(name) };
let name = if let Ok(name) = name.to_str() {
name.to_owned()
} else {
return -EINVAL;
};

let query = {
let mut guard = NIC.lock();
let nic = guard.as_nic_mut().unwrap();
let query = nic.start_query(&name, query_type).unwrap();
nic.poll_common(crate::executor::network::now());

query
};

match block_on(get_query_result(query), None) {
Ok(addr_vec) => {
let slice = unsafe { core::slice::from_raw_parts_mut(inaddr, len) };
slice.copy_from_slice(addr_vec[0].as_bytes());

0
}
Err(e) => -num::ToPrimitive::to_i32(&e).unwrap(),
}
}

#[hermit_macro::system]
#[no_mangle]
pub extern "C" fn sys_socket(domain: i32, type_: SockType, protocol: i32) -> i32 {
Expand Down

0 comments on commit 7614614

Please sign in to comment.