Start implementing and testing gethostbyname4_r
This commit is contained in:
parent
9ce503e052
commit
37ef5d4e65
11 changed files with 287 additions and 49 deletions
|
@ -6,15 +6,23 @@
|
|||
#![allow(non_snake_case)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::str::FromStr;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
||||
|
||||
use {
|
||||
anyhow::{ensure, Result},
|
||||
anyhow::{anyhow, bail, ensure, Result},
|
||||
libc::{freeaddrinfo, gai_strerror, getaddrinfo},
|
||||
nix::sys::socket::{SockaddrLike as _, SockaddrStorage},
|
||||
std::env,
|
||||
std::ffi::CString,
|
||||
std::ffi::{CStr, CString},
|
||||
std::net::{IpAddr, Ipv4Addr, Ipv6Addr},
|
||||
std::path::PathBuf,
|
||||
std::process::Command,
|
||||
std::sync::Once,
|
||||
};
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
||||
pub type Eai = EaiRetcode;
|
||||
|
||||
static SETUP: Once = Once::new();
|
||||
|
||||
|
@ -31,7 +39,7 @@ pub fn setup() -> Result<()> {
|
|||
});
|
||||
|
||||
let db = CString::new("hosts").unwrap();
|
||||
let resolvers = CString::new("malcontent [UNAVAIL=return] dns").unwrap();
|
||||
let resolvers = CString::new("malcontent dns").unwrap();
|
||||
__nss_configure_lookup(db.as_ptr(), resolvers.as_ptr())
|
||||
};
|
||||
|
||||
|
@ -43,3 +51,58 @@ pub fn setup() -> Result<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn system_resolve(host: &str) -> Result<IpAddr> {
|
||||
let process = Command::new("getent").arg("hosts").arg(host).output()?;
|
||||
ensure!(
|
||||
process.status.success(),
|
||||
"Failed to run getent to check host IP"
|
||||
);
|
||||
let output = String::from_utf8(process.stdout)?;
|
||||
let addr_string = output
|
||||
.as_str()
|
||||
.split(' ')
|
||||
.next()
|
||||
.ok_or(anyhow!("Unparseable output from getent"))?;
|
||||
Ok(IpAddr::from_str(&addr_string)?)
|
||||
}
|
||||
|
||||
pub fn convert_addrinfo(sa: &SockaddrStorage) -> Result<IpAddr> {
|
||||
if let Some(addr) = sa.as_sockaddr_in() {
|
||||
Ok(IpAddr::V4(Ipv4Addr::from(addr.ip())))
|
||||
} else if let Some(addr) = sa.as_sockaddr_in6() {
|
||||
Ok(IpAddr::V6(Ipv6Addr::from(addr.ip())))
|
||||
} else {
|
||||
bail!("addrinfo is not either an IPv4 or IPv6 address")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve_system_and_us(hostname: &str) -> Result<(IpAddr, IpAddr)> {
|
||||
setup()?;
|
||||
let ip_from_system = system_resolve(hostname)?;
|
||||
|
||||
let c_hostname = CString::new(hostname).unwrap();
|
||||
unsafe {
|
||||
let mut addr = std::ptr::null_mut();
|
||||
let getaddrinfo_status = getaddrinfo(
|
||||
c_hostname.as_ptr(),
|
||||
std::ptr::null(),
|
||||
std::ptr::null(),
|
||||
&mut addr,
|
||||
);
|
||||
|
||||
let error = CStr::from_ptr(gai_strerror(getaddrinfo_status));
|
||||
assert_eq!(
|
||||
getaddrinfo_status,
|
||||
Eai::Success.0,
|
||||
"Should have gotten hostname for {}, instead got {}",
|
||||
hostname,
|
||||
error.to_str().unwrap()
|
||||
);
|
||||
let addr_storage = SockaddrStorage::from_raw((*addr).ai_addr, Some((*addr).ai_addrlen))
|
||||
.ok_or(anyhow!("Garbled addrinfo from getaddrinfo()"))?;
|
||||
let ip_from_us = convert_addrinfo(&addr_storage)?;
|
||||
freeaddrinfo(addr);
|
||||
Ok((ip_from_system, ip_from_us))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,32 +4,88 @@
|
|||
mod common;
|
||||
|
||||
use {
|
||||
anyhow::{bail, Result},
|
||||
crate::common::Eai,
|
||||
anyhow::Result,
|
||||
libc::{freeaddrinfo, gai_strerror, getaddrinfo},
|
||||
std::net::{IpAddr, Ipv4Addr},
|
||||
};
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "not yet implemented")]
|
||||
fn nss_module_is_loaded() {
|
||||
common::setup().unwrap();
|
||||
fn nss_module_is_loaded() -> Result<()> {
|
||||
common::setup()?;
|
||||
|
||||
let hostname = std::ffi::CString::new("gnome.org").unwrap();
|
||||
unsafe {
|
||||
let mut addr = std::ptr::null_mut();
|
||||
match getaddrinfo(
|
||||
let getaddrinfo_status = getaddrinfo(
|
||||
hostname.as_ptr(),
|
||||
std::ptr::null(),
|
||||
std::ptr::null(),
|
||||
&mut addr,
|
||||
) {
|
||||
0 => freeaddrinfo(addr),
|
||||
status => {
|
||||
let error = std::ffi::CStr::from_ptr(gai_strerror(status));
|
||||
panic!(
|
||||
"Unable to resolve hostname, getaddrinfo returned {}",
|
||||
error.to_str().unwrap()
|
||||
)
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
let error = std::ffi::CStr::from_ptr(gai_strerror(getaddrinfo_status));
|
||||
assert_eq!(
|
||||
getaddrinfo_status,
|
||||
0,
|
||||
"Unable to resolve hostname, getaddrinfo failed: {}",
|
||||
error.to_str().unwrap()
|
||||
);
|
||||
freeaddrinfo(addr);
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn application_dns_is_nxdomain() -> Result<()> {
|
||||
common::setup()?;
|
||||
|
||||
let hostname = std::ffi::CString::new("use-application-dns.net").unwrap();
|
||||
unsafe {
|
||||
let mut addr = std::ptr::null_mut();
|
||||
let getaddrinfo_status = getaddrinfo(
|
||||
hostname.as_ptr(),
|
||||
std::ptr::null(),
|
||||
std::ptr::null(),
|
||||
&mut addr,
|
||||
);
|
||||
|
||||
let error = std::ffi::CStr::from_ptr(gai_strerror(getaddrinfo_status));
|
||||
assert_eq!(
|
||||
getaddrinfo_status,
|
||||
Eai::NoName.0,
|
||||
"Should have gotten no hostname (NXDOMAIN), instead got {}",
|
||||
error.to_str().unwrap()
|
||||
);
|
||||
freeaddrinfo(addr);
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
fn wikipedia_is_unrestricted() -> Result<()> {
|
||||
let (system_addr, our_addr) = common::resolve_system_and_us("wikipedia.org")?;
|
||||
assert_eq!(system_addr, our_addr);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn adultsite_is_restricted() -> Result<()> {
|
||||
let (system_addr, our_addr) = common::resolve_system_and_us("pornhub.com")?;
|
||||
assert_ne!(system_addr, our_addr);
|
||||
assert_eq!(our_addr, IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn root_user_bypasses_restrictions() -> Result<()> {
|
||||
// TODO fake root
|
||||
|
||||
let (system_addr, our_addr) = common::resolve_system_and_us("pornhub.com")?;
|
||||
assert_eq!(system_addr, our_addr);
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue