use std::borrow::Cow;
use std::ffi::{CStr, CString};
use std::ptr;
fn do_libc_lookup(hostname: &str) {
let mut addrinfo_ptr: *mut libc::addrinfo = ptr::null_mut();
let addrinfo_ptr_ptr = &mut addrinfo_ptr as *mut *mut libc::addrinfo;
let hints = libc::addrinfo {
ai_flags: libc::AI_CANONNAME,
ai_family: libc::AF_INET,
ai_socktype: libc::SOCK_DGRAM,
ai_protocol: 0,
ai_addr: ptr::null_mut(),
ai_addrlen: 0,
ai_canonname: ptr::null_mut(),
ai_next: ptr::null_mut(),
};
let hints_ptr = &hints as *const libc::addrinfo;
let hostname = CString::new(hostname).expect("parsing hostname");
let hostname_ptr = hostname.as_ptr();
unsafe {
let res = libc::getaddrinfo(hostname_ptr, ptr::null(), hints_ptr, addrinfo_ptr_ptr);
match res {
0 => (),
libc::EAI_NODATA | libc::EAI_NONAME => {
println!("No results");
return;
}
_ => panic!("getaddrinfo({})", res),
};
// out_ptr now contains a linked list of results.
let mut curr_out = addrinfo_ptr;
while !curr_out.is_null() {
let libc::addrinfo {
ai_addr,
ai_family,
ai_canonname,
ai_next,
..
} = *curr_out;
let (fam, ip) = match ai_family {
libc::AF_INET => {
let adr = *(ai_addr as *const libc::sockaddr_in);
let ipaddr = adr.sin_addr.s_addr.to_ne_bytes();
let ip_str = ipaddr
.iter()
.map(u8::to_string)
.collect::<Vec<_>>()
.join(".");
("ipv4", ip_str)
}
_ => continue,
};
let canonname = if !ai_canonname.is_null() {
let canonname_cstr = CStr::from_ptr(ai_canonname);
canonname_cstr.to_string_lossy()
} else {
Cow::from("<unknown canonical addr>")
};
println!("{} {}: {}", fam, ip, canonname);
curr_out = ai_next;
}
libc::freeaddrinfo(addrinfo_ptr);
};
}
fn main() {
let args: Vec<String> = std::env::args().collect();
let hostname = args.get(1).expect("hostname not given").to_owned();
do_libc_lookup(&hostname);
}