Files
RedBear-OS/local/patches/relibc/absorbed/P3-dns-aaaa-getaddrinfo-ipv6.patch
T
vasilito 5851974b20 feat: build system transition to release fork + archive hardening
Release fork infrastructure:
- REDBEAR_RELEASE=0.1.1 with offline enforcement (fetch/distclean/unfetch blocked)
- 195 BLAKE3-verified source archives in standard format
- Atomic provisioning via provision-release.sh (staging + .complete sentry)
- 5-phase improvement plan: restore format auto-detection, source tree
  validation (validate-source-trees.py), archive-map.json, REPO_BINARY fallback

Archive normalization:
- Removed 87 duplicate/unversioned archives from shared pool
- Regenerated all archives in consistent format with source/ + recipe.toml
- BLAKE3SUMS and manifest.json generated from stable tarball set

Patch management:
- verify-patches.sh: pre-sync dry-run report (OK/REVERSED/CONFLICT)
- 121 upstream-absorbed patches moved to absorbed/ directories
- 43 active patches verified clean against rebased sources
- Stress test: base updated to upstream HEAD, relibc reset and patched

Compilation fixes:
- relibc: Vec imports in redox-rt (proc.rs, lib.rs, sys.rs)
- relibc: unsafe from_raw_parts in mod.rs (2024 edition)
- fetch.rs: rev comparison handles short/full hash prefixes
- kibi recipe: corrected rev mismatch

New scripts: restore-sources.sh, provision-release.sh, verify-sources-archived.sh,
check-upstream-releases.sh, validate-source-trees.py, verify-patches.sh,
repair-archive-format.sh, generate-manifest.py

Documentation: AGENTS.md, README.md, local/AGENTS.md updated for release fork model
2026-05-02 01:41:17 +01:00

397 lines
13 KiB
Diff

diff --git a/src/header/netdb/lookup.rs b/src/header/netdb/lookup.rs
index aaaaaaa..bbbbbbb 100644
--- a/src/header/netdb/lookup.rs
+++ b/src/header/netdb/lookup.rs
@@ -14,7 +14,7 @@ use crate::header::{
bits_socklen_t::socklen_t,
bits_timespec::timespec,
errno::*,
- netinet_in::{IPPROTO_UDP, in_addr, sockaddr_in},
+ netinet_in::{IPPROTO_UDP, in6_addr, in_addr, sockaddr_in},
sys_socket::{
self,
constants::{AF_INET, SOCK_DGRAM, SOL_SOCKET, SO_RCVTIMEO},
@@ -30,6 +30,7 @@ use super::{
};
pub type LookupHost = Vec<in_addr>;
+pub type LookupHostV6 = Vec<in6_addr>;
pub fn lookup_host(host: &str) -> Result<LookupHost, c_int> {
if let Some(host_direct_addr) = parse_ipv4_string(host) {
@@ -157,6 +158,123 @@ pub fn lookup_host(host: &str) -> Result<LookupHost, c_int> {
}
}
+/// Look up IPv6 (AAAA) addresses for a host via DNS.
+pub fn lookup_host_v6(host: &str) -> Result<LookupHostV6, c_int> {
+ if let Some(addr6) = parse_ipv6_string(host) {
+ return Ok(vec![addr6]);
+ }
+
+ let dns_string = get_dns_server().map_err(|e| e.0)?;
+
+ if let Some(dns_addr) = parse_ipv4_string(&dns_string) {
+ let mut timespec = timespec::default();
+ if let Ok(()) = Sys::clock_gettime(
+ time::constants::CLOCK_REALTIME,
+ Out::from_mut(&mut timespec),
+ ) {};
+ let tid = (timespec.tv_nsec >> 16) as u16;
+
+ let packet = Dns {
+ transaction_id: tid,
+ flags: 0x0100,
+ queries: vec![DnsQuery {
+ name: host.to_string(),
+ q_type: 0x001c,
+ q_class: 0x0001,
+ }],
+ answers: vec![],
+ };
+
+ let packet_data = packet.compile();
+ let packet_data_len = packet_data.len();
+
+ let packet_data_box = packet_data.into_boxed_slice();
+ let packet_data_ptr = Box::into_raw(packet_data_box) as *mut _ as *mut c_void;
+
+ let dest = sockaddr_in {
+ sin_family: AF_INET as u16,
+ sin_port: htons(53),
+ sin_addr: in_addr { s_addr: dns_addr },
+ ..Default::default()
+ };
+ let dest_ptr = ptr::from_ref(&dest).cast::<sockaddr>();
+
+ let sock = unsafe {
+ let sock = sys_socket::socket(AF_INET, SOCK_DGRAM, i32::from(IPPROTO_UDP));
+ if sys_socket::connect(sock, dest_ptr, mem::size_of_val(&dest) as socklen_t) < 0 {
+ return Err(EIO);
+ }
+ if sys_socket::send(sock, packet_data_ptr, packet_data_len, 0) < 0 {
+ drop(Box::from_raw(packet_data_ptr));
+ return Err(EIO);
+ }
+ sock
+ };
+
+ unsafe {
+ drop(Box::from_raw(packet_data_ptr));
+ }
+
+ let mut buf = vec![0u8; 65536];
+ let buf_ptr = buf.as_mut_ptr().cast::<c_void>();
+
+ // Set 5s recv timeout (best-effort; if this fails, recv may block longer).
+ let tv = timeval {
+ tv_sec: 5,
+ tv_usec: 0,
+ };
+ unsafe {
+ sys_socket::setsockopt(
+ sock,
+ SOL_SOCKET,
+ SO_RCVTIMEO,
+ &tv as *const timeval as *const c_void,
+ core::mem::size_of::<timeval>() as socklen_t,
+ );
+ }
+
+ let mut count: isize = -1;
+ for _attempt in 0..2 {
+ count = unsafe { sys_socket::recv(sock, buf_ptr, 65536, 0) };
+ if count >= 0 {
+ break;
+ }
+ if unsafe { sys_socket::send(sock, packet_data_ptr, packet_data_len, 0) } < 0 {
+ break;
+ }
+ }
+ if count < 0 {
+ return Err(EIO);
+ }
+
+ match Dns::parse(&buf[..count as usize]) {
+ Ok(response) => {
+ let addrs: Vec<_> = response
+ .answers
+ .into_iter()
+ .filter_map(|answer| {
+ if answer.a_type == 0x001c
+ && answer.a_class == 0x0001
+ && answer.data.len() == 16
+ {
+ let mut s6_addr = [0u8; 16];
+ s6_addr.copy_from_slice(&answer.data[..16]);
+ Some(in6_addr { s6_addr })
+ } else {
+ None
+ }
+ })
+ .collect();
+
+ Ok(addrs)
+ }
+ Err(_err) => Err(EINVAL),
+ }
+ } else {
+ Err(EINVAL)
+ }
+}
+
pub fn lookup_addr(addr: in_addr) -> Result<Vec<Vec<u8>>, c_int> {
let dns_string = get_dns_server().map_err(|e| e.0)?;
@@ -282,6 +400,23 @@ pub fn parse_ipv4_string(ip_string: &str) -> Option<u32> {
Some(u32::from_ne_bytes(dns_arr))
}
+pub fn parse_ipv6_string(ip_string: &str) -> Option<in6_addr> {
+ let trimmed = ip_string.trim();
+
+ let s = if trimmed.starts_with('[') && trimmed.ends_with(']') {
+ &trimmed[1..trimmed.len() - 1]
+ } else {
+ trimmed
+ };
+
+ let ip: core::net::Ipv6Addr = s.parse().ok()?;
+ let mut addr = in6_addr {
+ s6_addr: [0u8; 16],
+ };
+ addr.s6_addr.copy_from_slice(&ip.octets());
+ Some(addr)
+}
+
#[cfg(test)]
mod tests {
use alloc::str;
diff --git a/src/header/netdb/mod.rs b/src/header/netdb/mod.rs
index ccccccc..ddddddd 100644
--- a/src/header/netdb/mod.rs
+++ b/src/header/netdb/mod.rs
@@ -4,7 +4,7 @@
mod dns;
-use core::{cell::Cell, fmt::Write, mem, net::Ipv4Addr, ptr, str};
+use core::{cell::Cell, fmt::Write, mem, net::Ipv4Addr, net::Ipv6Addr, ptr, str};
use alloc::{boxed::Box, str::SplitWhitespace, string::ToString, vec::Vec};
@@ -18,10 +18,10 @@ use crate::{
bits_socklen_t::socklen_t,
errno::*,
fcntl::O_RDONLY,
- netinet_in::{in_addr, sockaddr_in, sockaddr_in6},
+ netinet_in::{in6_addr, in_addr, sockaddr_in, sockaddr_in6},
stdlib::atoi,
strings::strcasecmp,
- sys_socket::{constants::AF_INET, sockaddr},
+ sys_socket::{constants::{AF_INET, AF_INET6, AF_UNSPEC}, sockaddr},
unistd::SEEK_SET,
},
platform::{
@@ -871,11 +871,16 @@ pub unsafe extern "C" fn getaddrinfo(
hints_opt
);
+ let requested_family = hints_opt.map_or(AF_UNSPEC, |hints| hints.ai_family);
+
+ if requested_family != AF_INET && requested_family != AF_INET6 && requested_family != AF_UNSPEC
+ {
+ return EAI_FAMILY;
+ }
+
//TODO: Use hints
let mut ai_flags = hints_opt.map_or(0, |hints| hints.ai_flags);
- let mut ai_family; // = hints_opt.map_or(AF_UNSPEC, |hints| hints.ai_family);
let ai_socktype = hints_opt.map_or(0, |hints| hints.ai_socktype);
- let mut ai_protocol; // = hints_opt.map_or(0, |hints| hints.ai_protocol);
unsafe { *res = ptr::null_mut() };
@@ -896,31 +901,52 @@ pub unsafe extern "C" fn getaddrinfo(
}
});
- let lookuphost = if ai_flags & AI_NUMERICHOST > 0 {
- match parse_ipv4_string(unsafe { str::from_utf8_unchecked(node.to_bytes()) }) {
- Some(s_addr) => vec![in_addr { s_addr }],
- None => {
- return EAI_NONAME;
+ let node_str = unsafe { str::from_utf8_unchecked(node.to_bytes()) };
+
+ let want_inet4 = requested_family == AF_INET || requested_family == AF_UNSPEC;
+ let want_inet6 = requested_family == AF_INET6 || requested_family == AF_UNSPEC;
+
+ let lookuphost_v4: Vec<in_addr> = if want_inet4 {
+ if ai_flags & AI_NUMERICHOST > 0 {
+ match parse_ipv4_string(node_str) {
+ Some(s_addr) => vec![in_addr { s_addr }],
+ None => vec![],
+ }
+ } else {
+ match lookup_host(node_str) {
+ Ok(addrs) => addrs,
+ Err(_) => vec![],
}
}
} else {
- match lookup_host(unsafe { str::from_utf8_unchecked(node.to_bytes()) }) {
- Ok(lookuphost) => lookuphost,
- Err(e) => {
- platform::ERRNO.set(e);
- return EAI_SYSTEM;
+ vec![]
+ };
+
+ let lookuphost_v6: Vec<in6_addr> = if want_inet6 {
+ if ai_flags & AI_NUMERICHOST > 0 {
+ match parse_ipv6_string(node_str) {
+ Some(addr) => vec![addr],
+ None => vec![],
+ }
+ } else {
+ match lookup_host_v6(node_str) {
+ Ok(addrs) => addrs,
+ Err(_) => vec![],
}
}
+ } else {
+ vec![]
};
- for in_addr in lookuphost {
- ai_family = AF_INET;
- ai_protocol = 0;
+ if lookuphost_v4.is_empty() && lookuphost_v6.is_empty() {
+ return EAI_NONAME;
+ }
+ for addr in lookuphost_v4 {
let ai_addr = Box::into_raw(Box::new(sockaddr_in {
- sin_family: ai_family as sa_family_t,
+ sin_family: AF_INET as sa_family_t,
sin_port: htons(port),
- sin_addr: in_addr,
+ sin_addr: addr,
sin_zero: [0; 8],
}))
.cast::<sockaddr>();
@@ -939,9 +965,53 @@ pub unsafe extern "C" fn getaddrinfo(
let addrinfo = Box::new(addrinfo {
ai_flags: 0,
- ai_family,
+ ai_family: AF_INET,
ai_socktype,
- ai_protocol,
+ ai_protocol: 0,
+ ai_addrlen,
+ ai_canonname,
+ ai_addr,
+ ai_next: ptr::null_mut(),
+ });
+ unsafe {
+ let mut indirect = res;
+ while !(*indirect).is_null() {
+ indirect = &raw mut (**indirect).ai_next;
+ }
+ *indirect = Box::into_raw(addrinfo)
+ }
+ }
+
+ for addr in lookuphost_v6 {
+ let mut s6_addr = [0u8; 16];
+ s6_addr.copy_from_slice(&addr.s6_addr);
+
+ let ai_addr = Box::into_raw(Box::new(sockaddr_in6 {
+ sin6_family: AF_INET6 as sa_family_t,
+ sin6_port: htons(port),
+ sin6_flowinfo: 0,
+ sin6_addr: in6_addr { s6_addr },
+ sin6_scope_id: 0,
+ }))
+ .cast::<sockaddr>();
+
+ let ai_addrlen = mem::size_of::<sockaddr_in6>() as socklen_t;
+
+ let ai_canonname = if ai_flags & AI_CANONNAME > 0 {
+ if node_opt.is_none() {
+ return EAI_BADFLAGS;
+ }
+ ai_flags &= !AI_CANONNAME;
+ node.to_owned_cstring().into_raw()
+ } else {
+ ptr::null_mut()
+ };
+
+ let addrinfo = Box::new(addrinfo {
+ ai_flags: 0,
+ ai_family: AF_INET6,
+ ai_socktype,
+ ai_protocol: 0,
ai_addrlen,
ai_canonname,
ai_addr,
@@ -970,10 +1040,56 @@ pub unsafe extern "C" fn getnameinfo(
servlen: socklen_t,
flags: c_int,
) -> c_int {
- if addr.is_null() || addrlen as usize != mem::size_of::<sockaddr_in>() {
+ if addr.is_null() {
+ return EAI_FAMILY;
+ }
+
+ let addrlen_usize = addrlen as usize;
+ if addrlen_usize != mem::size_of::<sockaddr_in>()
+ && addrlen_usize != mem::size_of::<sockaddr_in6>()
+ {
return EAI_FAMILY;
}
+ if addrlen_usize == mem::size_of::<sockaddr_in6>() {
+ let sa = unsafe { &*(addr.cast::<sockaddr_in6>()) };
+
+ if !serv.is_null() && servlen > 0 {
+ if flags & NI_NUMERICSERV != 0 {
+ let port_str = sa.sin6_port.to_be().to_string();
+ let port_bytes = port_str.as_bytes();
+ if (servlen as usize) <= port_bytes.len() {
+ return EAI_MEMORY;
+ }
+ unsafe {
+ ptr::copy_nonoverlapping(
+ port_bytes.as_ptr().cast::<c_char>(),
+ serv,
+ port_bytes.len(),
+ )
+ };
+ unsafe { *serv.add(port_bytes.len()) = 0 };
+ } else {
+ unsafe { *serv = 0 };
+ }
+ }
+
+ if !host.is_null() && hostlen > 0 {
+ let ip_addr = Ipv6Addr::from(sa.sin6_addr.s6_addr);
+ 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().cast::<c_char>(), host, ip_bytes.len())
+ };
+ unsafe { *host.add(ip_bytes.len()) = 0 };
+ }
+
+ return 0;
+ }
+
let sa = unsafe { &*(addr.cast::<sockaddr_in>()) };
if !serv.is_null() && servlen > 0 {