// SPDX-FileCopyrightText: 2022 Matteo Settenvini // 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> = 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::(); 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::()); 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::()); 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(ptr: *mut T, val: T) { if !ptr.is_null() { unsafe { *ptr = val }; } } pub fn block_on(f: F) -> Result 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), } }