Merge branch 'netdb-openssh' into 'master'

Implement getnameinfo and getaddrinfo loopback

See merge request redox-os/relibc!693
This commit is contained in:
Jeremy Soller
2025-08-20 06:59:31 -06:00
2 changed files with 113 additions and 71 deletions
+39 -35
View File
@@ -33,21 +33,19 @@ impl Iterator for LookupHost {
}
pub fn lookup_host(host: &str) -> Result<LookupHost, c_int> {
if let Some(host_direct_addr) = parse_ipv4_string(host) {
// already an ip address
return Ok(LookupHost(
vec![in_addr {
s_addr: host_direct_addr,
}]
.into_iter(),
));
}
let dns_string = get_dns_server().map_err(|e| e.0)?;
let dns_vec: Vec<u8> = dns_string
.trim()
.split('.')
.map(|octet| octet.parse::<u8>().unwrap_or(0))
.collect();
if dns_vec.len() == 4 {
let mut dns_arr = [0u8; 4];
for (i, octet) in dns_vec.iter().enumerate() {
dns_arr[i] = *octet;
}
let dns_addr = u32::from_ne_bytes(dns_arr);
if let Some(dns_addr) = parse_ipv4_string(&dns_string) {
let mut timespec = timespec::default();
unsafe {
Sys::clock_gettime(time::constants::CLOCK_REALTIME, &mut timespec);
@@ -140,26 +138,14 @@ pub fn lookup_host(host: &str) -> Result<LookupHost, c_int> {
pub fn lookup_addr(addr: in_addr) -> Result<Vec<Vec<u8>>, c_int> {
let dns_string = get_dns_server().map_err(|e| e.0)?;
let dns_vec: Vec<u8> = dns_string
.trim()
.split('.')
.map(|octet| octet.parse::<u8>().unwrap_or(0))
.collect();
if let Some(dns_addr) = parse_ipv4_string(&dns_string) {
let addr: [u8; 4] = addr.s_addr.to_ne_bytes();
// Address intentionally backwards for reverse lookup
let name = format!(
"{}.{}.{}.{}.in-addr.arpa",
addr[3], addr[2], addr[1], addr[0]
);
let mut dns_arr = [0u8; 4];
for (i, octet) in dns_vec.iter().enumerate() {
dns_arr[i] = *octet;
}
let addr: [u8; 4] = addr.s_addr.to_ne_bytes();
// Address intentionally backwards for reverse lookup
let name = format!(
"{}.{}.{}.{}.in-addr.arpa",
addr[3], addr[2], addr[1], addr[0]
);
if dns_vec.len() == 4 {
let mut timespec = timespec::default();
unsafe { Sys::clock_gettime(time::constants::CLOCK_REALTIME, &mut timespec) };
let tid = (timespec.tv_nsec >> 16) as u16;
@@ -183,9 +169,7 @@ pub fn lookup_addr(addr: in_addr) -> Result<Vec<Vec<u8>>, c_int> {
let dest = sockaddr_in {
sin_family: AF_INET as u16,
sin_port: htons(53),
sin_addr: in_addr {
s_addr: u32::from_ne_bytes(dns_arr),
},
sin_addr: in_addr { s_addr: dns_addr },
..Default::default()
};
@@ -278,6 +262,26 @@ fn parse_revdns_answer(data: &[u8]) -> Vec<u8> {
output
}
pub fn parse_ipv4_string(ip_string: &str) -> Option<u32> {
let dns_vec: Vec<u8> = ip_string
.trim()
.split('.')
.map(|octet| octet.parse::<u8>().unwrap_or(0))
.collect();
if dns_vec.len() != 4 {
return None;
}
let mut dns_arr = [0u8; 4];
for (i, octet) in dns_vec.iter().enumerate() {
dns_arr[i] = *octet;
}
Some(u32::from_ne_bytes(dns_arr))
}
#[cfg(test)]
mod tests {
use alloc::str;
+74 -36
View File
@@ -5,11 +5,13 @@ mod dns;
use core::{
cell::Cell,
fmt::Write,
mem, ptr, slice,
mem,
net::Ipv4Addr,
ptr, slice,
str::{self, FromStr},
};
use alloc::{borrow::ToOwned, boxed::Box, str::SplitWhitespace, vec::Vec};
use alloc::{borrow::ToOwned, boxed::Box, str::SplitWhitespace, string::ToString, vec::Vec};
use crate::{
c_str::{CStr, CString},
@@ -323,23 +325,7 @@ pub unsafe extern "C" fn gethostbyname(name: *const c_char) -> *mut hostent {
// Addresses and hostnames are both valid, so we'll check addresses first
// The standard doesn't define what to do when called with addresses
// Some implementations just skip resolution and copy the address to h_name
let mut octets = name_str.split('.');
let mut s_addr = [0u8; 4];
let mut is_addr = true;
for item in &mut s_addr {
if let Some(n) = octets.next().and_then(|x| u8::from_str(x).ok()) {
*item = n;
} else {
is_addr = false;
break;
}
}
if octets.next() != None {
is_addr = false;
}
if is_addr {
let s_addr = u32::from_ne_bytes(s_addr);
if let Some(s_addr) = parse_ipv4_string(name_str) {
let addr = in_addr { s_addr };
return gethostbyaddr(&addr as *const _ as *const c_void, 4, AF_INET);
}
@@ -878,29 +864,81 @@ pub unsafe extern "C" fn getnameinfo(
servlen: socklen_t,
flags: c_int,
) -> c_int {
//TODO: getnameinfo
if addrlen as usize != mem::size_of::<sockaddr_in>() {
if addr.is_null() || addrlen as usize != mem::size_of::<sockaddr_in>() {
return EAI_FAMILY;
}
let addr = &*(addr as *const sockaddr_in);
let sa = &*(addr as *const sockaddr_in);
let host_opt = if host.is_null() {
None
} else {
Some(slice::from_raw_parts_mut(host, hostlen as usize))
};
if !serv.is_null() && servlen > 0 {
if flags & NI_NUMERICSERV != 0 {
let port_str = sa.sin_port.to_be().to_string();
let port_bytes = port_str.as_bytes();
if (servlen as usize) <= port_bytes.len() {
return EAI_MEMORY; // Buffer too small
}
ptr::copy_nonoverlapping(port_bytes.as_ptr() as *const c_char, serv, port_bytes.len());
*serv.add(port_bytes.len()) = 0;
} else {
// TODO: Implement service name lookup (e.g., from /etc/services)
*serv = 0;
}
}
let serv_opt = if serv.is_null() {
None
} else {
Some(slice::from_raw_parts_mut(serv, servlen as usize))
};
if !host.is_null() && hostlen > 0 {
if flags & NI_NUMERICHOST != 0 {
let ip_addr = Ipv4Addr::from(sa.sin_addr.s_addr.to_be());
let ip_str = ip_addr.to_string();
let ip_bytes = ip_str.as_bytes();
if (hostlen as usize) <= ip_bytes.len() {
return EAI_MEMORY; // Buffer too small
}
ptr::copy_nonoverlapping(ip_bytes.as_ptr() as *const c_char, host, ip_bytes.len());
*host.add(ip_bytes.len()) = 0;
} else {
match lookup_addr(sa.sin_addr.clone()).map(|host_names| host_names.into_iter().next()) {
Ok(Some(hostname)) => {
if (hostlen as usize) <= hostname.len() {
return EAI_MEMORY; // Buffer too small
}
unsafe {
ptr::copy_nonoverlapping(
hostname.as_ptr() as *const c_char,
host,
hostname.len(),
);
*host.add(hostname.len()) = 0;
}
}
Ok(None) => {
if flags & NI_NAMEREQD != 0 {
return EAI_NONAME;
}
}
Err(_) => {
if flags & NI_NAMEREQD != 0 {
return EAI_NONAME;
}
let ip_addr = Ipv4Addr::from(sa.sin_addr.s_addr.to_be());
let ip_str = ip_addr.to_string();
let ip_bytes = ip_str.as_bytes();
if (hostlen as usize) <= ip_bytes.len() {
return EAI_MEMORY;
}
unsafe {
ptr::copy_nonoverlapping(
ip_bytes.as_ptr() as *const c_char,
host,
ip_bytes.len(),
);
*host.add(ip_bytes.len()) = 0;
}
}
}
}
}
eprintln!("getnameinfo({:p}, {}, {:#x})", addr, addrlen, flags);
platform::ERRNO.set(ENOSYS);
EAI_SYSTEM
0
}
#[no_mangle]