malcontent-dns-parental-con.../src/helpers.rs

100 lines
3.1 KiB
Rust

// SPDX-FileCopyrightText: 2022 Matteo Settenvini <matteo.settenvini@montecristosoftware.eu>
// SPDX-License-Identifier: GPL-3.0-or-later
use {
crate::nss_bindings::gaih_addrtuple,
anyhow::{bail, Result},
libc::{AF_INET, AF_INET6},
nix::errno::Errno,
once_cell::sync::Lazy,
std::ffi::CString,
std::mem::{align_of, size_of},
std::net::IpAddr,
trust_dns_resolver::lookup_ip::LookupIp,
};
static RUNTIME: Lazy<std::io::Result<tokio::runtime::Handle>> = Lazy::new(|| {
// The runtime should remain single-threaded, some
// programs depend on it (e.g. programs calling unshare())
let rt = tokio::runtime::Builder::new_current_thread().build()?;
Ok(rt.handle().clone())
});
pub unsafe fn ips_to_gaih_addr(
ips: LookupIp,
mut buf: &mut [u8],
) -> std::io::Result<*mut gaih_addrtuple> {
const GAIH_ADDRTUPLE_SZ: usize = size_of::<gaih_addrtuple>();
let mut ret = std::ptr::null_mut();
let query = ips.query();
let name = CString::new(query.name().to_utf8()).unwrap(); // TODO: .map_err() and fail more graciously
let mut prev_link: *mut *mut gaih_addrtuple = std::ptr::null_mut();
for addr in ips {
// First add the name to the buffer
let offset = buf.as_ptr().align_offset(align_of::<libc::c_char>());
let name_src = name.as_bytes_with_nul();
let name_dest = buf.as_mut_ptr().add(offset);
let l = name_src.len();
if buf.len() < offset + l {
return Err(Errno::ERANGE.into());
}
std::ptr::copy_nonoverlapping(name_src.as_ptr(), name_dest, l);
buf = &mut buf[(offset + l)..];
// Then add the tuple with the address
let offset = buf.as_ptr().align_offset(align_of::<gaih_addrtuple>());
let l = GAIH_ADDRTUPLE_SZ;
if buf.len() < offset + l {
return Err(Errno::ERANGE.into());
}
let tuple = &mut *(buf.as_mut_ptr().add(offset) as *mut gaih_addrtuple);
tuple.next = std::ptr::null_mut();
tuple.name = name_dest as *mut i8;
tuple.scopeid = 0; // how to set tuple.scopeid ????
set_if_valid(prev_link, &mut *tuple); // link from previous tuple to this tuple
prev_link = &mut (*tuple).next;
match addr {
IpAddr::V4(addr) => {
tuple.family = AF_INET;
tuple.addr[0] = std::mem::transmute_copy(&addr.octets());
}
IpAddr::V6(addr) => {
tuple.family = AF_INET6;
tuple.addr = std::mem::transmute_copy(&addr.octets());
}
}
if ret == std::ptr::null_mut() {
ret = tuple;
}
buf = &mut buf[(offset + l)..];
}
Ok(ret)
}
pub fn set_if_valid<T>(ptr: *mut T, val: T) {
if !ptr.is_null() {
unsafe { *ptr = val };
}
}
pub fn block_on<F>(f: F) -> Result<F::Output>
where
F: std::future::Future,
{
use std::ops::Deref;
match RUNTIME.deref() {
Ok(rt_handle) => Ok(rt_handle.block_on(async { f.await })),
Err(e) => bail!("Unable to start tokio runtime: {}", e),
}
}