From c0dd239753ab22d059531472b3895669ce44a875 Mon Sep 17 00:00:00 2001 From: Murarth Date: Mon, 16 Mar 2015 13:04:31 -0700 Subject: [PATCH] Add `std::net::lookup_addr` for reverse DNS lookup Closes #22608 --- src/libstd/net/addr.rs | 9 ++++++++ src/libstd/net/mod.rs | 10 +++++++++ src/libstd/sys/common/net2.rs | 39 ++++++++++++++++++++++++++++++++++- 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index dafca974bec0e..a08b33b342bec 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -47,6 +47,15 @@ pub struct SocketAddrV4 { inner: libc::sockaddr_in } pub struct SocketAddrV6 { inner: libc::sockaddr_in6 } impl SocketAddr { + /// Creates a new socket address from the (ip, port) pair. + #[unstable(feature = "ip_addr", reason = "recent addition")] + pub fn new(ip: IpAddr, port: u16) -> SocketAddr { + match ip { + IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)), + IpAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a, port, 0, 0)), + } + } + /// Gets the IP address associated with this socket address. #[unstable(feature = "ip_addr", reason = "recent addition")] pub fn ip(&self) -> IpAddr { diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index 7f51b1cba3fe7..68f3098d993c0 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -111,3 +111,13 @@ impl Iterator for LookupHost { pub fn lookup_host(host: &str) -> io::Result { net_imp::lookup_host(host).map(LookupHost) } + +/// Resolve the given address to a hostname. +/// +/// This function may perform a DNS query to resolve `addr` and may also inspect +/// system configuration to resolve the specified address. If the address +/// cannot be resolved, it is returned in string format. +#[unstable(feature = "lookup_addr", reason = "recent addition")] +pub fn lookup_addr(addr: &IpAddr) -> io::Result { + net_imp::lookup_addr(addr) +} diff --git a/src/libstd/sys/common/net2.rs b/src/libstd/sys/common/net2.rs index e213a86644fe1..a8ee40639e32e 100644 --- a/src/libstd/sys/common/net2.rs +++ b/src/libstd/sys/common/net2.rs @@ -10,11 +10,12 @@ use prelude::v1::*; -use ffi::CString; +use ffi::{CStr, CString}; use io::{self, Error, ErrorKind}; use libc::{self, c_int, c_char, c_void, socklen_t}; use mem; use net::{SocketAddr, Shutdown, IpAddr}; +use str::from_utf8; use sys::c; use sys::net::{cvt, cvt_r, cvt_gai, Socket, init, wrlen_t}; use sys_common::{AsInner, FromInner, IntoInner}; @@ -126,6 +127,42 @@ pub fn lookup_host(host: &str) -> io::Result { } } +//////////////////////////////////////////////////////////////////////////////// +// lookup_addr +//////////////////////////////////////////////////////////////////////////////// + +extern "system" { + fn getnameinfo(sa: *const libc::sockaddr, salen: socklen_t, + host: *mut c_char, hostlen: libc::size_t, + serv: *mut c_char, servlen: libc::size_t, + flags: c_int) -> c_int; +} + +const NI_MAXHOST: usize = 1025; + +pub fn lookup_addr(addr: &IpAddr) -> io::Result { + init(); + + let saddr = SocketAddr::new(*addr, 0); + let (inner, len) = saddr.into_inner(); + let mut hostbuf = [0 as c_char; NI_MAXHOST]; + + let data = unsafe { + try!(cvt_gai(getnameinfo(inner, len, + hostbuf.as_mut_ptr(), NI_MAXHOST as libc::size_t, + 0 as *mut _, 0, 0))); + + CStr::from_ptr(hostbuf.as_ptr()) + }; + + match from_utf8(data.to_bytes()) { + Ok(name) => Ok(name.to_string()), + Err(_) => Err(io::Error::new(io::ErrorKind::Other, + "failed to lookup address information", + Some("invalid host name".to_string()))) + } +} + //////////////////////////////////////////////////////////////////////////////// // TCP streams ////////////////////////////////////////////////////////////////////////////////