diff --git a/src/header/netdb/lookup.rs b/src/header/netdb/lookup.rs index 039a508304..1f83e8f682 100644 --- a/src/header/netdb/lookup.rs +++ b/src/header/netdb/lookup.rs @@ -32,15 +32,17 @@ impl Iterator for LookupHost { } } +impl From for LookupHost { + /// from ipv4 address + fn from(s_addr: u32) -> Self { + LookupHost(vec![in_addr { s_addr }].into_iter()) + } +} + pub fn lookup_host(host: &str) -> Result { if let Some(host_direct_addr) = parse_ipv4_string(host) { // already an ip address - return Ok(LookupHost( - vec![in_addr { - s_addr: host_direct_addr, - }] - .into_iter(), - )); + return Ok(host_direct_addr.into()); } let dns_string = get_dns_server().map_err(|e| e.0)?; diff --git a/src/header/netdb/mod.rs b/src/header/netdb/mod.rs index 92f7975231..3bcd1ed7e8 100644 --- a/src/header/netdb/mod.rs +++ b/src/header/netdb/mod.rs @@ -771,7 +771,6 @@ pub unsafe extern "C" fn getaddrinfo( hints: *const addrinfo, res: *mut *mut addrinfo, ) -> c_int { - //TODO: getaddrinfo let node_opt = CStr::from_nullable_ptr(node); let service_opt = CStr::from_nullable_ptr(service); @@ -800,55 +799,71 @@ pub unsafe extern "C" fn getaddrinfo( Err(_err) => (), } } + let node = node_opt.unwrap_or_else(|| { + //TODO: Optimize by bypassing string parsing + if ai_flags & AI_PASSIVE > 0 { + c"0.0.0.0".into() + } else { + c"127.0.0.1".into() + } + }); - //TODO: Check hosts file - if let Some(node) = node_opt { - //TODO: Support AI_NUMERICHOST - let lookuphost = match lookup_host(str::from_utf8_unchecked(node.to_bytes())) { + let lookuphost = if ai_flags & AI_NUMERICHOST > 0 { + match parse_ipv4_string(str::from_utf8_unchecked(node.to_bytes())) { + Some(s_addr) => s_addr.into(), + None => { + return EAI_NONAME; + } + } + } else { + match lookup_host(str::from_utf8_unchecked(node.to_bytes())) { Ok(lookuphost) => lookuphost, Err(e) => { platform::ERRNO.set(e); return EAI_SYSTEM; } + } + }; + + for in_addr in lookuphost { + ai_family = AF_INET; + ai_protocol = 0; + + let ai_addr = Box::into_raw(Box::new(sockaddr_in { + sin_family: ai_family as sa_family_t, + sin_port: htons(port), + sin_addr: in_addr, + sin_zero: [0; 8], + })) as *mut sockaddr; + + let ai_addrlen = mem::size_of::(); + + let ai_canonname = if ai_flags & AI_CANONNAME > 0 { + if node_opt.is_none() { + return EAI_BADFLAGS; + } + ai_flags &= !AI_CANONNAME; + node.to_owned_cstring().into_raw() + } else { + ptr::null_mut() }; - for in_addr in lookuphost { - ai_family = AF_INET; - ai_protocol = 0; + let addrinfo = Box::new(addrinfo { + ai_flags: 0, + ai_family, + ai_socktype, + ai_protocol, + ai_addrlen, + ai_canonname, + ai_addr, + ai_next: ptr::null_mut(), + }); - let ai_addr = Box::into_raw(Box::new(sockaddr_in { - sin_family: ai_family as sa_family_t, - sin_port: htons(port), - sin_addr: in_addr, - sin_zero: [0; 8], - })) as *mut sockaddr; - - let ai_addrlen = mem::size_of::(); - - let ai_canonname = if ai_flags & AI_CANONNAME > 0 { - ai_flags &= !AI_CANONNAME; - node.to_owned_cstring().into_raw() - } else { - ptr::null_mut() - }; - - let addrinfo = Box::new(addrinfo { - ai_flags: 0, - ai_family, - ai_socktype, - ai_protocol, - ai_addrlen, - ai_canonname, - ai_addr, - ai_next: ptr::null_mut(), - }); - - let mut indirect = res; - while !(*indirect).is_null() { - indirect = &mut (**indirect).ai_next; - } - *indirect = Box::into_raw(addrinfo); + let mut indirect = res; + while !(*indirect).is_null() { + indirect = &mut (**indirect).ai_next; } + *indirect = Box::into_raw(addrinfo); } 0 diff --git a/tests/netdb/getaddrinfo_null.c b/tests/netdb/getaddrinfo_null.c new file mode 100644 index 0000000000..b874a9270a --- /dev/null +++ b/tests/netdb/getaddrinfo_null.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_helpers.h" + +int test_getaddrinfo(int ai_flags, size_t* ipv4_addr) { + struct addrinfo hints, *res; + int status; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = ai_flags; + + if ((status = getaddrinfo(NULL, "8080", &hints, &res)) != 0) { + return status; + } + + *ipv4_addr = ((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr; + freeaddrinfo(res); + return 0; +} + +int main() { + size_t ipv4_addr; + char addrstr[INET_ADDRSTRLEN]; + + int status = test_getaddrinfo(0, &ipv4_addr); + ERROR_IF(getaddrinfo, status, != 0); + ERROR_IF(getaddrinfo_ai_addr, ipv4_addr, == 0); + inet_ntop(AF_INET, &ipv4_addr, addrstr, INET_ADDRSTRLEN); + printf("local IPv4 address 1: %s\n", addrstr); + + status = test_getaddrinfo(AI_PASSIVE, &ipv4_addr); + ERROR_IF(getaddrinfo, status, != 0); + ERROR_IF(getaddrinfo_ai_addr, ipv4_addr, != 0); + inet_ntop(AF_INET, &ipv4_addr, addrstr, INET_ADDRSTRLEN); + printf("local IPv4 address 2: %s\n", addrstr); +}