0.3.0: converge relibc to upstream 0.6.0 + Red Bear patches
This commit is contained in:
@@ -1,9 +1,18 @@
|
||||
sys_includes = ["sys/socket.h", "netinet/in.h"]
|
||||
# netinet/in.h brings in sys/socket.h
|
||||
sys_includes = ["inttypes.h", "netinet/in.h", "features.h"]
|
||||
include_guard = "_RELIBC_NETDB_H"
|
||||
trailer = "#include <bits/netdb.h>"
|
||||
trailer = """
|
||||
#ifndef _RELIBC_BITS_NETDB_H
|
||||
#define _RELIBC_BITS_NETDB_H
|
||||
|
||||
#define h_errno (*__h_errno_location())
|
||||
#define h_addr h_addr_list[0] /* Address, for backward compatibility.*/
|
||||
|
||||
#endif // _RELIBC_BITS_NETDB_H
|
||||
"""
|
||||
language = "C"
|
||||
style = "Tag"
|
||||
no_includes = true
|
||||
no_includes = false
|
||||
cpp_compat = true
|
||||
|
||||
[export.rename]
|
||||
|
||||
+12
-46
@@ -11,46 +11,10 @@
|
||||
pub use self::{answer::DnsAnswer, query::DnsQuery};
|
||||
|
||||
use alloc::{string::String, vec::Vec};
|
||||
use core::{slice, u16};
|
||||
|
||||
mod answer;
|
||||
mod query;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[repr(packed)]
|
||||
pub struct n16 {
|
||||
inner: u16,
|
||||
}
|
||||
|
||||
impl n16 {
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
unsafe { slice::from_raw_parts((&self.inner as *const u16) as *const u8, 2) }
|
||||
}
|
||||
|
||||
pub fn from_bytes(bytes: &[u8]) -> Self {
|
||||
n16 {
|
||||
inner: unsafe {
|
||||
slice::from_raw_parts(bytes.as_ptr() as *const u16, bytes.len() / 2)[0]
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u16> for n16 {
|
||||
fn from(value: u16) -> Self {
|
||||
n16 {
|
||||
inner: value.to_be(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<n16> for u16 {
|
||||
fn from(value: n16) -> Self {
|
||||
u16::from_be(value.inner)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Dns {
|
||||
pub transaction_id: u16,
|
||||
@@ -67,13 +31,13 @@ impl Dns {
|
||||
($value:expr) => {
|
||||
data.push($value);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! push_n16 {
|
||||
($value:expr) => {
|
||||
data.extend_from_slice(n16::from($value).as_bytes());
|
||||
data.extend_from_slice(&u16::to_be_bytes($value));
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
push_n16!(self.transaction_id);
|
||||
push_n16!(self.flags);
|
||||
@@ -106,17 +70,19 @@ impl Dns {
|
||||
}
|
||||
data[i - 1]
|
||||
}};
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! pop_n16 {
|
||||
() => {{
|
||||
use core::convert::TryInto;
|
||||
i += 2;
|
||||
if i > data.len() {
|
||||
return Err(format!("{}: {}: pop_n16", file!(), line!()));
|
||||
}
|
||||
u16::from(n16::from_bytes(&data[i - 2..i]))
|
||||
let bytes: [u8; 2] = data[i - 2..i].try_into().unwrap();
|
||||
u16::from_be_bytes(bytes)
|
||||
}};
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! pop_data {
|
||||
() => {{
|
||||
@@ -129,7 +95,7 @@ impl Dns {
|
||||
|
||||
data
|
||||
}};
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! pop_name {
|
||||
() => {{
|
||||
@@ -160,14 +126,14 @@ impl Dns {
|
||||
|
||||
name
|
||||
}};
|
||||
};
|
||||
}
|
||||
|
||||
let transaction_id = pop_n16!();
|
||||
let flags = pop_n16!();
|
||||
let queries_len = pop_n16!();
|
||||
let answers_len = pop_n16!();
|
||||
pop_n16!();
|
||||
pop_n16!();
|
||||
let _ = pop_n16!();
|
||||
let _ = pop_n16!();
|
||||
|
||||
let mut queries = Vec::new();
|
||||
for _query_i in 0..queries_len {
|
||||
|
||||
+71
-66
@@ -2,16 +2,17 @@ use alloc::{boxed::Box, str::SplitWhitespace, vec::Vec};
|
||||
use core::{mem, ptr};
|
||||
|
||||
use crate::{
|
||||
c_str::CString,
|
||||
error::ResultExt,
|
||||
header::{
|
||||
arpa_inet::inet_aton, fcntl::O_RDONLY, netinet_in::in_addr, sys_socket::constants::AF_INET,
|
||||
unistd::SEEK_SET,
|
||||
},
|
||||
platform::{
|
||||
rlb::{Line, RawLineBuffer},
|
||||
types::*,
|
||||
Pal, Sys,
|
||||
rlb::{Line, RawLineBuffer},
|
||||
types::{c_char, c_int},
|
||||
},
|
||||
raw_cell::RawCell,
|
||||
};
|
||||
|
||||
use super::{bytes_to_box_str, hostent};
|
||||
@@ -24,104 +25,108 @@ pub static mut HOST_ENTRY: hostent = hostent {
|
||||
h_length: 0,
|
||||
h_addr_list: ptr::null_mut(),
|
||||
};
|
||||
pub static mut HOST_NAME: Option<Vec<u8>> = None;
|
||||
pub static mut HOST_ALIASES: Option<Vec<Vec<u8>>> = None;
|
||||
static mut _HOST_ALIASES: Option<Vec<*mut i8>> = None;
|
||||
pub static HOST_NAME: RawCell<Option<Vec<u8>>> = RawCell::new(None);
|
||||
pub static HOST_ALIASES: RawCell<Option<Vec<Vec<u8>>>> = RawCell::new(None);
|
||||
static _HOST_ALIASES: RawCell<Option<Vec<*mut c_char>>> = RawCell::new(None);
|
||||
pub static mut HOST_ADDR: Option<in_addr> = None;
|
||||
pub static mut HOST_ADDR_LIST: [*mut c_char; 2] = [ptr::null_mut(); 2];
|
||||
pub static mut _HOST_ADDR_LIST: [u8; 4] = [0u8; 4];
|
||||
static mut H_POS: usize = 0;
|
||||
pub static mut HOST_STAYOPEN: c_int = 0;
|
||||
|
||||
#[no_mangle]
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn endhostent() {
|
||||
if HOSTDB >= 0 {
|
||||
Sys::close(HOSTDB);
|
||||
}
|
||||
HOSTDB = -1;
|
||||
if unsafe { HOSTDB } >= 0
|
||||
&& let Ok(()) = Sys::close(unsafe { HOSTDB })
|
||||
{} // TODO handle error
|
||||
unsafe { HOSTDB = -1 };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn sethostent(stayopen: c_int) {
|
||||
HOST_STAYOPEN = stayopen;
|
||||
if HOSTDB < 0 {
|
||||
HOSTDB = Sys::open(&CString::new("/etc/hosts").unwrap(), O_RDONLY, 0)
|
||||
} else {
|
||||
Sys::lseek(HOSTDB, 0, SEEK_SET);
|
||||
}
|
||||
H_POS = 0;
|
||||
unsafe { HOST_STAYOPEN = stayopen };
|
||||
if unsafe { HOSTDB } < 0 {
|
||||
unsafe { HOSTDB = Sys::open(c"/etc/hosts".into(), O_RDONLY, 0).or_minus_one_errno() }
|
||||
} else if Sys::lseek(unsafe { HOSTDB }, 0, SEEK_SET).is_ok() {
|
||||
} // TODO handle error
|
||||
unsafe { H_POS = 0 };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn gethostent() -> *mut hostent {
|
||||
if HOSTDB < 0 {
|
||||
HOSTDB = Sys::open(&CString::new("/etc/hosts").unwrap(), O_RDONLY, 0);
|
||||
if unsafe { HOSTDB } < 0 {
|
||||
unsafe { HOSTDB = Sys::open(c"/etc/hosts".into(), O_RDONLY, 0).or_minus_one_errno() };
|
||||
}
|
||||
let mut rlb = RawLineBuffer::new(HOSTDB);
|
||||
rlb.seek(H_POS);
|
||||
let mut rlb = RawLineBuffer::new(unsafe { HOSTDB });
|
||||
rlb.seek(unsafe { H_POS });
|
||||
|
||||
let mut r: Box<str> = Box::default();
|
||||
while r.is_empty() || r.split_whitespace().next() == None || r.starts_with('#') {
|
||||
while r.is_empty() || r.split_whitespace().next().is_none() || r.starts_with('#') {
|
||||
r = match rlb.next() {
|
||||
Line::Some(s) => bytes_to_box_str(s),
|
||||
_ => {
|
||||
if HOST_STAYOPEN == 0 {
|
||||
endhostent();
|
||||
if unsafe { HOST_STAYOPEN } == 0 {
|
||||
unsafe { endhostent() };
|
||||
}
|
||||
return ptr::null_mut();
|
||||
}
|
||||
};
|
||||
}
|
||||
rlb.next();
|
||||
H_POS = rlb.line_pos();
|
||||
unsafe { H_POS = rlb.line_pos() };
|
||||
|
||||
let mut iter: SplitWhitespace = r.split_whitespace();
|
||||
|
||||
let mut addr_vec = iter.next().unwrap().as_bytes().to_vec();
|
||||
addr_vec.push(b'\0');
|
||||
let addr_cstr = addr_vec.as_slice().as_ptr() as *const i8;
|
||||
let addr_vec: Vec<u8> = iter.next().unwrap().bytes().chain(Some(b'\0')).collect();
|
||||
let addr_cstr = addr_vec.as_slice().as_ptr().cast::<c_char>();
|
||||
let mut addr = mem::MaybeUninit::uninit();
|
||||
inet_aton(addr_cstr, addr.as_mut_ptr());
|
||||
let addr = addr.assume_init();
|
||||
unsafe { inet_aton(addr_cstr, addr.as_mut_ptr()) };
|
||||
let addr = unsafe { addr.assume_init() };
|
||||
|
||||
_HOST_ADDR_LIST = mem::transmute::<u32, [u8; 4]>(addr.s_addr);
|
||||
HOST_ADDR_LIST = [_HOST_ADDR_LIST.as_mut_ptr() as *mut c_char, ptr::null_mut()];
|
||||
unsafe {
|
||||
_HOST_ADDR_LIST = addr.s_addr.to_ne_bytes();
|
||||
HOST_ADDR_LIST = [(&raw mut _HOST_ADDR_LIST).cast::<c_char>(), ptr::null_mut()];
|
||||
|
||||
HOST_ADDR = Some(addr);
|
||||
|
||||
let mut host_name = iter.next().unwrap().as_bytes().to_vec();
|
||||
host_name.push(b'\0');
|
||||
|
||||
let mut _host_aliases: Vec<Vec<u8>> = Vec::new();
|
||||
|
||||
for s in iter {
|
||||
let mut alias = s.as_bytes().to_vec();
|
||||
alias.push(b'\0');
|
||||
_host_aliases.push(alias);
|
||||
HOST_ADDR = Some(addr);
|
||||
}
|
||||
HOST_ALIASES = Some(_host_aliases);
|
||||
|
||||
let mut host_aliases: Vec<*mut i8> = HOST_ALIASES
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.iter_mut()
|
||||
.map(|x| x.as_mut_ptr() as *mut i8)
|
||||
let host_name = iter.next().unwrap().bytes().chain(Some(b'\0')).collect();
|
||||
|
||||
let mut _host_aliases: Vec<Vec<u8>> = iter
|
||||
.map(|alias| alias.bytes().chain(Some(b'\0')).collect())
|
||||
.collect();
|
||||
host_aliases.push(ptr::null_mut());
|
||||
host_aliases.push(ptr::null_mut());
|
||||
unsafe { HOST_ALIASES.unsafe_set(Some(_host_aliases)) };
|
||||
|
||||
HOST_NAME = Some(host_name);
|
||||
|
||||
HOST_ENTRY = hostent {
|
||||
h_name: HOST_NAME.as_mut().unwrap().as_mut_ptr() as *mut c_char,
|
||||
h_aliases: host_aliases.as_mut_slice().as_mut_ptr() as *mut *mut i8,
|
||||
h_addrtype: AF_INET,
|
||||
h_length: 4,
|
||||
h_addr_list: HOST_ADDR_LIST.as_mut_ptr(),
|
||||
let mut host_aliases: Vec<*mut c_char> = unsafe {
|
||||
HOST_ALIASES
|
||||
.unsafe_mut()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.iter_mut()
|
||||
.map(|x| x.as_mut_ptr().cast::<c_char>())
|
||||
.chain([ptr::null_mut(), ptr::null_mut()])
|
||||
.collect()
|
||||
};
|
||||
_HOST_ALIASES = Some(host_aliases);
|
||||
if HOST_STAYOPEN == 0 {
|
||||
endhostent();
|
||||
|
||||
unsafe { HOST_NAME.unsafe_set(Some(host_name)) };
|
||||
|
||||
unsafe {
|
||||
HOST_ENTRY = hostent {
|
||||
h_name: HOST_NAME
|
||||
.unsafe_mut()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.as_mut_ptr()
|
||||
.cast::<c_char>(),
|
||||
h_aliases: host_aliases.as_mut_slice().as_mut_ptr(),
|
||||
h_addrtype: AF_INET,
|
||||
h_length: 4,
|
||||
h_addr_list: (&raw mut HOST_ADDR_LIST).cast(),
|
||||
};
|
||||
_HOST_ALIASES.unsafe_set(Some(host_aliases));
|
||||
}
|
||||
&mut HOST_ENTRY as *mut hostent
|
||||
if unsafe { HOST_STAYOPEN } == 0 {
|
||||
unsafe { endhostent() };
|
||||
}
|
||||
(&raw mut HOST_ENTRY).cast::<hostent>()
|
||||
}
|
||||
|
||||
@@ -1,29 +1,19 @@
|
||||
use crate::{
|
||||
c_str::CString,
|
||||
error::Errno,
|
||||
fs::File,
|
||||
header::fcntl,
|
||||
header::{errno, fcntl},
|
||||
io::{BufRead, BufReader},
|
||||
};
|
||||
use alloc::string::String;
|
||||
|
||||
pub fn get_dns_server() -> String {
|
||||
let file = match File::open(&CString::new("/etc/resolv.conf").unwrap(), fcntl::O_RDONLY) {
|
||||
Ok(file) => file,
|
||||
Err(_) => return String::new(), // TODO: better error handling
|
||||
};
|
||||
let file = BufReader::new(file);
|
||||
pub fn get_dns_server() -> Result<String, Errno> {
|
||||
let file = File::open(c"/etc/resolv.conf".into(), fcntl::O_RDONLY).map(BufReader::new)?;
|
||||
|
||||
for line in file.split(b'\n') {
|
||||
let mut line = match line {
|
||||
Ok(line) => line,
|
||||
Err(_) => return String::new(), // TODO: pls handle errors
|
||||
};
|
||||
if line.starts_with(b"nameserver ") {
|
||||
line.drain(..11);
|
||||
return String::from_utf8(line).unwrap_or_default();
|
||||
for line in file.lines().map_while(Result::ok) {
|
||||
if let Some(dns) = line.strip_prefix("nameserver ") {
|
||||
return Ok(dns.into());
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: better error handling
|
||||
String::new()
|
||||
Err(Errno(errno::EIO).sync())
|
||||
}
|
||||
|
||||
+219
-106
@@ -1,22 +1,26 @@
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
string::{String, ToString},
|
||||
vec::{IntoIter, Vec},
|
||||
};
|
||||
use core::mem;
|
||||
use alloc::{boxed::Box, string::ToString, vec::Vec};
|
||||
use core::{mem, ptr};
|
||||
|
||||
use crate::platform::{types::*, Pal, Sys};
|
||||
use crate::{
|
||||
out::Out,
|
||||
platform::{
|
||||
Pal, Sys,
|
||||
types::{c_int, c_void},
|
||||
},
|
||||
};
|
||||
|
||||
use crate::header::{
|
||||
arpa_inet::htons,
|
||||
bits_arpainet::htons,
|
||||
bits_socklen_t::socklen_t,
|
||||
bits_timespec::timespec,
|
||||
errno::*,
|
||||
netinet_in::{in_addr, sockaddr_in, IPPROTO_UDP},
|
||||
netinet_in::{IPPROTO_UDP, in_addr, sockaddr_in},
|
||||
sys_socket::{
|
||||
self,
|
||||
constants::{AF_INET, SOCK_DGRAM},
|
||||
sockaddr, socklen_t,
|
||||
sockaddr,
|
||||
},
|
||||
time::{self, timespec},
|
||||
time,
|
||||
};
|
||||
|
||||
use super::{
|
||||
@@ -24,33 +28,24 @@ use super::{
|
||||
sys::get_dns_server,
|
||||
};
|
||||
|
||||
pub struct LookupHost(IntoIter<in_addr>);
|
||||
|
||||
impl Iterator for LookupHost {
|
||||
type Item = in_addr;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.0.next()
|
||||
}
|
||||
}
|
||||
pub type LookupHost = Vec<in_addr>;
|
||||
|
||||
pub fn lookup_host(host: &str) -> Result<LookupHost, c_int> {
|
||||
let dns_string = get_dns_server();
|
||||
if let Some(host_direct_addr) = parse_ipv4_string(host) {
|
||||
// already an ip address
|
||||
return Ok(vec![in_addr {
|
||||
s_addr: host_direct_addr,
|
||||
}]);
|
||||
}
|
||||
|
||||
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 = unsafe { mem::transmute::<[u8; 4], u32>(dns_arr) };
|
||||
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();
|
||||
Sys::clock_gettime(time::constants::CLOCK_REALTIME, &mut timespec);
|
||||
if let Ok(()) = Sys::clock_gettime(
|
||||
time::constants::CLOCK_REALTIME,
|
||||
Out::from_mut(&mut timespec),
|
||||
) {}; // TODO handle error
|
||||
let tid = (timespec.tv_nsec >> 16) as u16;
|
||||
|
||||
let packet = Dns {
|
||||
@@ -76,27 +71,27 @@ pub fn lookup_host(host: &str) -> Result<LookupHost, c_int> {
|
||||
sin_addr: in_addr { s_addr: dns_addr },
|
||||
..Default::default()
|
||||
};
|
||||
let dest_ptr = &dest as *const _ as *const sockaddr;
|
||||
let dest_ptr = ptr::from_ref(&dest).cast::<sockaddr>();
|
||||
|
||||
let sock = unsafe {
|
||||
let sock = sys_socket::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP as i32);
|
||||
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 {
|
||||
Box::from_raw(packet_data_ptr);
|
||||
drop(Box::from_raw(packet_data_ptr));
|
||||
return Err(EIO);
|
||||
}
|
||||
sock
|
||||
};
|
||||
|
||||
unsafe {
|
||||
Box::from_raw(packet_data_ptr);
|
||||
drop(Box::from_raw(packet_data_ptr));
|
||||
}
|
||||
|
||||
let i = 0 as socklen_t;
|
||||
let mut buf = [0u8; 65536];
|
||||
let buf_ptr = buf.as_mut_ptr() as *mut c_void;
|
||||
let mut buf = vec![0u8; 65536];
|
||||
let buf_ptr = buf.as_mut_ptr().cast::<c_void>();
|
||||
|
||||
let count = unsafe { sys_socket::recv(sock, buf_ptr, 65536, 0) };
|
||||
if count < 0 {
|
||||
@@ -105,24 +100,30 @@ pub fn lookup_host(host: &str) -> Result<LookupHost, c_int> {
|
||||
|
||||
match Dns::parse(&buf[..count as usize]) {
|
||||
Ok(response) => {
|
||||
let mut addrs = vec![];
|
||||
for answer in response.answers.iter() {
|
||||
if answer.a_type == 0x0001 && answer.a_class == 0x0001 && answer.data.len() == 4
|
||||
{
|
||||
let addr = in_addr {
|
||||
s_addr: unsafe {
|
||||
mem::transmute::<[u8; 4], u32>([
|
||||
let addrs: Vec<_> = response
|
||||
.answers
|
||||
.into_iter()
|
||||
.filter_map(|answer| {
|
||||
if answer.a_type == 0x0001
|
||||
&& answer.a_class == 0x0001
|
||||
&& answer.data.len() == 4
|
||||
{
|
||||
let addr = in_addr {
|
||||
s_addr: u32::from_ne_bytes([
|
||||
answer.data[0],
|
||||
answer.data[1],
|
||||
answer.data[2],
|
||||
answer.data[3],
|
||||
])
|
||||
},
|
||||
};
|
||||
addrs.push(addr);
|
||||
}
|
||||
}
|
||||
Ok(LookupHost(addrs.into_iter()))
|
||||
]),
|
||||
};
|
||||
Some(addr)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(addrs)
|
||||
}
|
||||
Err(_err) => Err(EINVAL),
|
||||
}
|
||||
@@ -132,44 +133,28 @@ 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();
|
||||
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 mut addr_vec: Vec<u8> = unsafe { mem::transmute::<u32, [u8; 4]>(addr.s_addr).to_vec() };
|
||||
addr_vec.reverse();
|
||||
let mut name: Vec<u8> = vec![];
|
||||
for octet in addr_vec {
|
||||
for ch in format!("{}", octet).as_bytes() {
|
||||
name.push(*ch);
|
||||
}
|
||||
name.push(b"."[0]);
|
||||
}
|
||||
name.pop();
|
||||
for ch in b".IN-ADDR.ARPA" {
|
||||
name.push(*ch);
|
||||
}
|
||||
|
||||
if dns_vec.len() == 4 {
|
||||
let mut timespec = timespec::default();
|
||||
Sys::clock_gettime(time::constants::CLOCK_REALTIME, &mut timespec);
|
||||
if let Ok(()) = Sys::clock_gettime(
|
||||
time::constants::CLOCK_REALTIME,
|
||||
Out::from_mut(&mut timespec),
|
||||
) {}; // TODO handle error
|
||||
let tid = (timespec.tv_nsec >> 16) as u16;
|
||||
|
||||
let packet = Dns {
|
||||
transaction_id: tid,
|
||||
flags: 0x0100,
|
||||
queries: vec![DnsQuery {
|
||||
name: String::from_utf8(name).unwrap(),
|
||||
name,
|
||||
q_type: 0x000C,
|
||||
q_class: 0x0001,
|
||||
}],
|
||||
@@ -184,16 +169,14 @@ 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: unsafe { mem::transmute::<[u8; 4], u32>(dns_arr) },
|
||||
},
|
||||
sin_addr: in_addr { s_addr: dns_addr },
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let dest_ptr = &dest as *const _ as *const sockaddr;
|
||||
let dest_ptr = ptr::from_ref(&dest).cast::<sockaddr>();
|
||||
|
||||
let sock = unsafe {
|
||||
let sock = sys_socket::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP as i32);
|
||||
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);
|
||||
}
|
||||
@@ -207,12 +190,12 @@ pub fn lookup_addr(addr: in_addr) -> Result<Vec<Vec<u8>>, c_int> {
|
||||
}
|
||||
|
||||
unsafe {
|
||||
Box::from_raw(packet_data_ptr);
|
||||
drop(Box::from_raw(packet_data_ptr));
|
||||
}
|
||||
|
||||
let i = mem::size_of::<sockaddr_in>() as socklen_t;
|
||||
let mut buf = [0u8; 65536];
|
||||
let buf_ptr = buf.as_mut_ptr() as *mut c_void;
|
||||
let buf_ptr = buf.as_mut_ptr().cast::<c_void>();
|
||||
|
||||
let count = unsafe { sys_socket::recv(sock, buf_ptr, 65536, 0) };
|
||||
if count < 0 {
|
||||
@@ -221,18 +204,22 @@ pub fn lookup_addr(addr: in_addr) -> Result<Vec<Vec<u8>>, c_int> {
|
||||
|
||||
match Dns::parse(&buf[..count as usize]) {
|
||||
Ok(response) => {
|
||||
let mut names = vec![];
|
||||
for answer in response.answers.iter() {
|
||||
if answer.a_type == 0x000C && answer.a_class == 0x0001 {
|
||||
// answer.data is encoded kinda weird.
|
||||
// Basically length-prefixed strings for each
|
||||
// subsection of the domain.
|
||||
// We need to parse this to insert periods where
|
||||
// they belong (ie at the end of each string)
|
||||
let data = parse_revdns_answer(&answer.data);
|
||||
names.push(data);
|
||||
}
|
||||
}
|
||||
let names = response
|
||||
.answers
|
||||
.into_iter()
|
||||
.filter_map(|answer| {
|
||||
if answer.a_type == 0x000C && answer.a_class == 0x0001 {
|
||||
// answer.data is encoded kinda weird.
|
||||
// Basically length-prefixed strings for each
|
||||
// subsection of the domain.
|
||||
// We need to parse this to insert periods where
|
||||
// they belong (ie at the end of each string)
|
||||
Some(parse_revdns_answer(&answer.data))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
Ok(names)
|
||||
}
|
||||
Err(_err) => Err(EINVAL),
|
||||
@@ -243,16 +230,142 @@ pub fn lookup_addr(addr: in_addr) -> Result<Vec<Vec<u8>>, c_int> {
|
||||
}
|
||||
|
||||
fn parse_revdns_answer(data: &[u8]) -> Vec<u8> {
|
||||
if data.is_empty() || data[0] == 0 {
|
||||
return vec![0];
|
||||
}
|
||||
|
||||
let mut cursor = 0;
|
||||
let mut index = 0;
|
||||
let mut output = data.to_vec();
|
||||
while index < data.len() - 1 {
|
||||
// First byte is a length; discard
|
||||
let mut output = data[1..].to_vec();
|
||||
let length = data.len() - 1;
|
||||
while index < length {
|
||||
let offset = data[index] as usize;
|
||||
// CVE-2024-21342
|
||||
if offset > length {
|
||||
return vec![0];
|
||||
}
|
||||
index = cursor + offset + 1;
|
||||
output[index] = b'.';
|
||||
// First byte was skipped so index is one less
|
||||
output[index - 1] = b'.';
|
||||
cursor = index;
|
||||
}
|
||||
//we don't want an extra period at the end
|
||||
output.pop();
|
||||
// Response is NUL terminated so we must preserve that for C
|
||||
match output.last_mut() {
|
||||
Some(nul) => *nul = b'\0',
|
||||
// XXX: Likely unreachable
|
||||
None => {
|
||||
debug_assert!(output.is_empty());
|
||||
output = vec![0];
|
||||
}
|
||||
}
|
||||
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;
|
||||
use core::ffi::CStr;
|
||||
|
||||
use super::parse_revdns_answer;
|
||||
|
||||
// Actual response from a query
|
||||
const DNS_GOOGLE: &[u8] = &[3, 100, 110, 115, 6, 103, 111, 111, 103, 108, 101, 0];
|
||||
const EXPECTED_DNS_GOOGLE: &str = "dns.google\0";
|
||||
const EXPECTED_DNS_GOOGLE_RT: &str = "dns.google";
|
||||
|
||||
// Fake response that has numbers within the name (e.g. like CDNs)
|
||||
const FAKE_WITH_NUMS: &[u8] = &[
|
||||
14, 102, 97, 107, 101, 45, 49, 48, 48, 45, 50, 45, 51, 45, 52, 8, 102, 111, 111, 98, 97,
|
||||
114, 50, 52, 4, 102, 97, 107, 101, 0,
|
||||
];
|
||||
const EXPECTED_FAKE_RESPONSE: &str = "fake-100-2-3-4.foobar24.fake\0";
|
||||
const EXPECTED_FAKE_RESPONSE_RT: &str = "fake-100-2-3-4.foobar24.fake";
|
||||
|
||||
const EMPTY_RESPONSE: &[u8] = &[0];
|
||||
const EXPECTED_EMPTY_RESPONSE: &str = "\0";
|
||||
const EXPECTED_EMPTY_RESPONSE_RT: &str = "";
|
||||
|
||||
#[test]
|
||||
fn dns_response_dns_google() {
|
||||
let response = parse_revdns_answer(DNS_GOOGLE);
|
||||
assert_eq!(
|
||||
0,
|
||||
*response.last().unwrap(),
|
||||
"Response should end with a NUL byte"
|
||||
);
|
||||
|
||||
let response_str = str::from_utf8(&response)
|
||||
.expect("Response is valid UTF-8; parsing shouldn't change that");
|
||||
assert_eq!(EXPECTED_DNS_GOOGLE, response_str);
|
||||
|
||||
let response_cstr = CStr::from_bytes_with_nul(&response)
|
||||
.expect("Parsed response should have only one NUL byte");
|
||||
let response_cstr_str = response_cstr
|
||||
.to_str()
|
||||
.expect("Valid UTF-8 bytes to CStr to Rust str should be valid");
|
||||
assert_eq!(EXPECTED_DNS_GOOGLE_RT, response_cstr_str);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dns_response_fake_with_nums() {
|
||||
let response = parse_revdns_answer(FAKE_WITH_NUMS);
|
||||
assert_eq!(
|
||||
0,
|
||||
*response.last().unwrap(),
|
||||
"Response should end with a NUL byte"
|
||||
);
|
||||
|
||||
let response_str = str::from_utf8(&response)
|
||||
.expect("Response is valid UTF-8; parsing shouldn't change that");
|
||||
assert_eq!(EXPECTED_FAKE_RESPONSE, response_str);
|
||||
|
||||
let response_cstr = CStr::from_bytes_with_nul(&response)
|
||||
.expect("Parsed response should have only one NUL byte");
|
||||
let response_cstr_str = response_cstr
|
||||
.to_str()
|
||||
.expect("Valid UTF-8 bytes to CStr to Rust str should be valid");
|
||||
assert_eq!(EXPECTED_FAKE_RESPONSE_RT, response_cstr_str);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dns_response_empty() {
|
||||
let response = parse_revdns_answer(EMPTY_RESPONSE);
|
||||
assert_eq!(
|
||||
0,
|
||||
*response.last().unwrap(),
|
||||
"Response should end with a NUL byte"
|
||||
);
|
||||
|
||||
let response_str = str::from_utf8(&response)
|
||||
.expect("Response is valid UTF-8; parsing shouldn't change that");
|
||||
assert_eq!(EXPECTED_EMPTY_RESPONSE, response_str);
|
||||
|
||||
let response_cstr = CStr::from_bytes_with_nul(&response)
|
||||
.expect("Parsed response should have only one NUL byte");
|
||||
let response_cstr_str = response_cstr
|
||||
.to_str()
|
||||
.expect("Valid UTF-8 bytes to CStr to Rust str should be valid");
|
||||
assert_eq!(EXPECTED_EMPTY_RESPONSE_RT, response_cstr_str);
|
||||
}
|
||||
}
|
||||
|
||||
+629
-366
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,16 @@
|
||||
use crate::{c_str::CString, fs::File, header::fcntl, io::Read};
|
||||
use crate::{
|
||||
error::Errno,
|
||||
fs::File,
|
||||
header::{errno, fcntl},
|
||||
io::Read,
|
||||
};
|
||||
use alloc::string::String;
|
||||
|
||||
pub fn get_dns_server() -> String {
|
||||
pub fn get_dns_server() -> Result<String, Errno> {
|
||||
let mut string = String::new();
|
||||
let mut file = File::open(&CString::new("/etc/net/dns").unwrap(), fcntl::O_RDONLY).unwrap(); // TODO: error handling
|
||||
file.read_to_string(&mut string).unwrap(); // TODO: error handling
|
||||
string
|
||||
let mut file = File::open(c"/etc/net/dns".into(), fcntl::O_RDONLY)?;
|
||||
file.read_to_string(&mut string)
|
||||
.map_err(|_| Errno(errno::EIO).sync())?;
|
||||
|
||||
Ok(string)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user