From a2557b5542da2d26c5bc6d645a40f1d095801b43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Baylac=20Jacqu=C3=A9?= Date: Sun, 8 Oct 2023 11:25:04 +0200 Subject: [PATCH] gethostbyname/gethostbyaddr: use proper glibc function We internally used getai to restpond to the gethostbyname/gethostbyaddr operations. Sadly, it does not behave as expected and breaks some tools (like hostname --fqdn, see https://github.com/nix-community/nsncd/issues/4. We FFI the right Glibc gethostbyname_2r/gethostbyaddr_2r (now deprecated) functions and use it to back the GETHOSTBYNAME, GETHOSTBYNAME6, GETHOSTBYADDR, and GETHOSTBYADDR6 Nscd interfaces. Using sockburp, we realized the hostent serialization function was bogus: we totally forgot to serialize the aliases. This commit fixes this and makes sure we're producing bit-to-bit identical results with Nscd for gethostbyname/getaddrinfo. Took me three try to get this right. This is actually the third full rewrite. The Nscd behaviour for these two legacy functions is *really* confusing. We're supposed to ignore the herrno (herrno != errno!!) and set it to 0 if gethostbyaddr/name returns a non-null hostent. If we end up with a null hostent, we return the herrno together with a dummy hostent header. I tried to keep things as safe as possible by extracting the glibc hostent to a proper rust structure. This structure mirrors the libc hostent in a Rust idiomatic way. We should probably try to upstream the FFI part of this commit to the Nix crate at some point. Fixes https://github.com/nix-community/nsncd/issues/4 --- Cargo.toml | 2 +- src/ffi.rs | 271 +++++++++++++++++++++++++++++++++++++++++++++++- src/handlers.rs | 237 ++++++++++++++++++++---------------------- src/protocol.rs | 29 ------ 4 files changed, 381 insertions(+), 158 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index daff366..497d2a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ authors = [ "Geoffrey Thomas ", "Leif Walsh ", ] -edition = "2018" +edition = "2021" description = "The name service non-caching daemon" readme = "README.md" repository = "https://github.com/twosigma/nsncd" diff --git a/src/ffi.rs b/src/ffi.rs index 78a549d..5c2f701 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -14,7 +14,10 @@ * limitations under the License. */ -use nix::libc; +use anyhow::bail; +use nix::libc::{self}; +use std::ffi::{CStr, CString}; +use std::ptr; #[allow(non_camel_case_types)] type size_t = ::std::os::raw::c_ulonglong; @@ -40,3 +43,269 @@ pub fn disable_internal_nscd() { __nss_disable_nscd(do_nothing); } } + +pub enum LibcIp { + V4([u8; 4]), + V6([u8; 16]) +} + +mod glibcffi { + use nix::libc; + extern "C" { + pub fn gethostbyname2_r ( + name: *const libc::c_char, + af: libc::c_int, + result_buf: *mut libc::hostent, + buf: *mut libc::c_char, + buflen: libc::size_t, + result: *mut *mut libc::hostent, + h_errnop: *mut libc::c_int, + ) -> libc::c_int; + + pub fn gethostbyaddr_r ( + addr: *const libc::c_void, + len: libc::socklen_t, + af: libc::c_int, + ret: *mut libc::hostent, + buf: *mut libc::c_char, + buflen: libc::size_t, + result: *mut *mut libc::hostent, + h_errnop: *mut libc::c_int, + ) -> libc::c_int; + } +} + +/// This structure is the Rust counterpart of the `libc::hostent` C +/// function the Libc hostent struct. +/// +/// It's mostly used to perform the gethostbyaddr and gethostbyname +/// operations. +/// +/// This struct can be serialized to the wire through the +/// `serialize` function or retrieved from the C boundary using the +/// TryFrom `libc:hostent` trait. +#[derive(Clone, Debug)] +pub struct Hostent { + pub name: String, + pub aliases: Vec, + pub addr_type: i32, + pub addr_list: Vec, + pub herrno: i32 +} + +fn from_libc_hostent(value: libc::hostent) -> Result { + // validate value.h_addtype, and bail out if it's unsupported + if value.h_addrtype != libc::AF_INET && value.h_addrtype != libc::AF_INET6 { + bail!("unsupported address type: {}", value.h_addrtype); + } + + // ensure value.h_length matches what we know from this address family + if value.h_addrtype == libc::AF_INET && value.h_length != 4 { + bail!("unsupported h_length for AF_INET: {}", value.h_length); + } + if value.h_addrtype == libc::AF_INET6 && value.h_length != 16 { + bail!("unsupported h_length for AF_INET6: {}", value.h_length); + } + + let name = unsafe { CStr::from_ptr(value.h_name).to_str().unwrap().to_string() }; + + Ok({ + // construct the list of aliases. keep adding to value.h_aliases until we encounter a null pointer. + let mut aliases: Vec = Vec::new(); + let mut h_alias_ptr = value.h_aliases as *const *const libc::c_char; + while !(unsafe { *h_alias_ptr }).is_null() { + aliases.push(unsafe { CStr::from_ptr(*h_alias_ptr).to_str().unwrap().to_string() }); + // increment + unsafe { + h_alias_ptr = h_alias_ptr.add(1); + } + } + // value.h_addrtype + + // construct the list of addresses. + let mut addr_list: Vec = Vec::new(); + + // copy the pointer into a private variable that we can mutate + // h_addr_list is a pointer to a list of pointers to addresses. + // h_addr_list[0] => ptr to first address + // h_addr_list[1] => null pointer (end of list) + let mut h_addr_ptr = value.h_addr_list as *const *const libc::c_void; + while !(unsafe { *h_addr_ptr }).is_null() { + if value.h_addrtype == libc::AF_INET { + let octets: [u8; 4] = + unsafe { std::ptr::read((*h_addr_ptr) as *const [u8; 4]) }; + addr_list.push(std::net::IpAddr::V4(std::net::Ipv4Addr::from(octets))); + } else { + let octets: [u8; 16] = + unsafe { std::ptr::read((*h_addr_ptr) as *const [u8; 16]) }; + addr_list.push(std::net::IpAddr::V6(std::net::Ipv6Addr::from(octets))); + } + unsafe { h_addr_ptr = h_addr_ptr.add(1) }; + } + + Hostent { + name, + aliases, + addr_type: value.h_addrtype, + addr_list, + herrno: 0 + } + }) +} + +pub fn gethostbyaddr_r(addr: LibcIp) -> anyhow::Result { + + let (addr, len, af) = match addr { + LibcIp::V4(ref ipv4) => (ipv4 as &[u8], 4, libc::AF_INET), + LibcIp::V6(ref ipv6) => (ipv6 as &[u8], 16, libc::AF_INET6) + }; + + let mut ret_hostent: libc::hostent = libc::hostent { + h_name: ptr::null_mut(), + h_aliases: ptr::null_mut(), + h_addrtype: 0, + h_length: 0, + h_addr_list: ptr::null_mut(), + }; + let mut herrno: libc::c_int = 0; + let mut hostent_result = ptr::null_mut(); + let mut buf: Vec = Vec::with_capacity(200); + loop { + let ret = unsafe { + glibcffi::gethostbyaddr_r( + addr.as_ptr() as *const libc::c_void, + len, + af, + &mut ret_hostent, + buf.as_mut_ptr() as *mut i8, + (buf.capacity() as size_t).try_into().unwrap(), + &mut hostent_result, + &mut herrno + ) + }; + + if ret == libc::ERANGE { + buf.reserve(buf.capacity() * 2); + } else { + break; + } + }; + if !hostent_result.is_null() { + unsafe { + let res = from_libc_hostent(*hostent_result)?; + Ok(res) + } + } else { + Ok( + // This is a default hostent header we're supposed to use + // to convey a lookup error. This is a glibc quirk, I have + // nothing to do with that, don't blame me :) + Hostent { + name: "".to_string(), + aliases: Vec::new(), + addr_type: -1, + addr_list: Vec::new(), + herrno + } + ) + } +} + +/// +/// +/// The stream is positioned at the first entry in the directory. +/// +/// af is nix::libc::AF_INET6 or nix::libc::AF_INET6 +pub fn gethostbyname2_r(name: String, af: libc::c_int) -> anyhow::Result { + let name = CString::new(name).unwrap(); + + // Prepare a libc::hostent and the pointer to the result list, + // which will passed to the ffi::gethostbyname2_r call. + let mut ret_hostent: libc::hostent = libc::hostent { + h_name: ptr::null_mut(), // <- points to buf + h_aliases: ptr::null_mut(), + h_addrtype: 0, + h_length: 0, + h_addr_list: ptr::null_mut(), + }; + let mut herrno: libc::c_int = 0; + let mut buf: Vec = Vec::with_capacity(200); + // We absolutely need to point hostent_result to the start of the + // result buffer. Glibc segfaults if we don't. + let mut hostent_result = ptr::null_mut(); + let _: i32 = loop { + let ret = unsafe { + glibcffi::gethostbyname2_r( + name.as_ptr(), + af, + &mut ret_hostent, + buf.as_mut_ptr() as *mut i8, + (buf.capacity() as size_t).try_into().unwrap(), + &mut hostent_result, + &mut herrno, + ) + }; + if ret == libc::ERANGE { + // The buffer is too small. Let's x2 its capacity and retry. + buf.reserve(buf.capacity() * 2); + } else { + break ret; + } + }; + if !hostent_result.is_null() { + unsafe { + let res = from_libc_hostent(*hostent_result)?; + Ok(res) + } + } else { + Ok( + // This is a default hostent header we're supposed to use + // to convey a lookup error. This is a glibc quirk, I have + // nothing to do with that, don't blame me :) + Hostent { + name: "".to_string(), + aliases: Vec::new(), + addr_type: -1, + addr_list: Vec::new(), + herrno + } + ) + } +} + +#[test] +fn test_gethostbyname2_r() { + disable_internal_nscd(); + + let result: Result = gethostbyname2_r( + "localhost.".to_string(), + libc::AF_INET, + ); + + result.expect("Should resolve IPv4 localhost."); + + let result: Result = gethostbyname2_r( + "localhost.".to_string(), + libc::AF_INET6, + ); + let res = result.expect("Should resolve IPv6 localhost."); + println!("{:?}", res); + + let trantortest: Result = gethostbyname2_r( + "trantor".to_string(), + libc::AF_INET, + ); + let res = trantortest.expect("Should get trantor name"); + println!("{:?}", res); +} + +#[test] +fn test_gethostbyaddr_r() { + disable_internal_nscd(); + + let v4test = LibcIp::V4([127,0,0,1]); + let _ = gethostbyaddr_r(v4test).expect("Should resolve IPv4 localhost with gethostbyaddr"); + + let v6test = LibcIp::V6([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]); + let _ = gethostbyaddr_r(v6test).expect("Should resolve IPv6 localhost with gethostbyaddr"); +} diff --git a/src/handlers.rs b/src/handlers.rs index 075f4b3..0913c46 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -17,18 +17,17 @@ use std::collections::HashSet; use std::convert::TryInto; use std::ffi::{CStr, CString}; -use std::net::{IpAddr, SocketAddr}; +use std::net::IpAddr; use std::os::unix::ffi::OsStrExt; use anyhow::{bail, Context, Result}; use atoi::atoi; -use dns_lookup::{getaddrinfo, getnameinfo, AddrInfoHints}; -use nix::libc::{AF_INET6, NI_NUMERICSERV, SOCK_STREAM}; use nix::sys::socket::AddressFamily; use nix::unistd::{getgrouplist, Gid, Group, Uid, User}; use slog::{debug, error, Logger}; use std::mem::size_of; +use crate::ffi::{gethostbyname2_r, gethostbyaddr_r, LibcIp, Hostent}; use crate::protocol::{AiResponse, AiResponseHeader}; use super::config::Config; @@ -177,20 +176,16 @@ pub fn handle_request( bail!("Invalid key len: {}, expected 4", key.len()); } let address_bytes: [u8; 4] = key.try_into()?; - let address = IpAddr::from(address_bytes); - - let sock = SocketAddr::new(address, 0); - let host = match getnameinfo(&sock, NI_NUMERICSERV) { - Ok((hostname, _service)) => Ok(Some(Host { - addresses: vec![address], - hostname, - })), - Err(e) => match e.kind() { - dns_lookup::LookupErrorKind::NoName => Ok(None), - _ => bail!("error during lookup: {:?}", e), - }, + let hostent = match gethostbyaddr_r(LibcIp::V4(address_bytes)) { + Ok(hostent) => hostent, + Err(e) => + // We shouldn't end up in that branch. Something + // got very very wrong on the glibc client side if + // we do. It's okay to bail, there's nothing much + // we can do. + bail!("unexpected gethostbyaddr error: {}", e) }; - Ok(serialize_host(log, host)) + hostent.serialize() } RequestType::GETHOSTBYADDRv6 => { let key = request.key; @@ -199,78 +194,46 @@ pub fn handle_request( bail!("Invalid key len: {}, expected 16", key.len()); } let address_bytes: [u8; 16] = key.try_into()?; - let address = IpAddr::from(address_bytes); - - let sock = SocketAddr::new(address, 0); - let host = match getnameinfo(&sock, NI_NUMERICSERV) { - Ok((hostname, _service)) => Ok(Some(Host { - addresses: vec![address], - hostname, - })), - Err(e) => match e.kind() { - dns_lookup::LookupErrorKind::NoName => Ok(None), - _ => bail!("error during lookup: {:?}", e), - }, + let hostent = match gethostbyaddr_r (LibcIp::V6(address_bytes)){ + Ok(hostent) => hostent, + Err(e) => + // We shouldn't end up in that branch. Something + // got very very wrong on the glibc client side if + // we do. It's okay to bail, there's nothing much + // we can do. + bail!("unexpected gethostbyaddrv6 error: {}", e) }; - Ok(serialize_host(log, host)) + hostent.serialize() } RequestType::GETHOSTBYNAME => { let hostname = CStr::from_bytes_with_nul(request.key)?.to_str()?; - let hints = AddrInfoHints { - socktype: SOCK_STREAM, - ..AddrInfoHints::default() + println!("gethostbyname2_r({}, AF_INET)", hostname); + let hostent = match gethostbyname2_r(hostname.to_string(), nix::libc::AF_INET) { + Ok(hostent) => hostent, + Err(e) => + // We shouldn't end up in that branch. Something + // got very very wrong on the glibc client side if + // we do. It's okay to bail, there's nothing much + // we can do. + bail!("unexpected gethostbyname error: {:?}", e) }; - - let host = match getaddrinfo(Some(hostname), None, Some(hints)).map(|addrs| { - addrs - .filter_map(|r| r.ok()) - .filter(|r| r.sockaddr.is_ipv4()) - .map(|a| a.sockaddr.ip()) - .collect::>() - }) { - // no matches found - Ok(addresses) if addresses.len() == 0 => Ok(None), - Ok(addresses) => Ok(Some(Host { - addresses, - hostname: hostname.to_string(), - })), - Err(e) => match e.kind() { - dns_lookup::LookupErrorKind::NoName => Ok(None), - _ => bail!("error during lookup: {:?}", e), - }, - }; - Ok(serialize_host(log, host)) + hostent.serialize() } RequestType::GETHOSTBYNAMEv6 => { let hostname = CStr::from_bytes_with_nul(request.key)?.to_str()?; - - let hints = AddrInfoHints { - socktype: SOCK_STREAM, - address: AF_INET6, // ai_family - ..AddrInfoHints::default() + println!("gethostbyname2_r({}, AF_INET6)", hostname); + let hostent = match gethostbyname2_r(hostname.to_string(), nix::libc::AF_INET6) { + Ok(hostent) => hostent, + Err(e) => + // We shouldn't end up in that branch. Something + // got very very wrong on the glibc client side if + // we do. It's okay to bail, there's nothing much + // we can do. + bail!("unexpected gethostbynamev6 error: {:?}", e) }; - - let host = match getaddrinfo(Some(hostname), None, Some(hints)).map(|addrs| { - addrs - .filter_map(|r| r.ok()) - .filter(|r| r.sockaddr.is_ipv6()) - .map(|a| a.sockaddr.ip()) - .collect::>() - }) { - // No matches found - Ok(addresses) if addresses.len() == 0 => Ok(None), - Ok(addresses) => Ok(Some(Host { - addresses, - hostname: hostname.to_string(), - })), - Err(e) => match e.kind() { - dns_lookup::LookupErrorKind::NoName => Ok(None), - _ => bail!("error during lookup: {:?}", e), - }, - }; - Ok(serialize_host(log, host)) + hostent.serialize() } // These will normally send an FD pointing to the internal cache structure, @@ -396,13 +359,7 @@ fn serialize_initgroups(groups: Vec) -> Result> { Ok(result) } -pub struct Host { - pub addresses: Vec, - // aliases is unused so far - pub hostname: String, -} - -impl Host { +impl Hostent { fn serialize(&self) -> Result> { // Loop over all addresses. // Serialize them into a slice, which is used later in the payload. @@ -410,8 +367,13 @@ impl Host { let mut num_v4 = 0; let mut num_v6 = 0; let mut buf_addrs = vec![]; + let mut buf_aliases = vec![]; + // Memory segment used to convey the size of the different + // aliases. The sizes are expressed in big endian encoded 32 + // bits integer. + let mut buf_aliases_size = vec![]; - for address in self.addresses.iter() { + for address in self.addr_list.iter() { match address { IpAddr::V4(ip4) => { num_v4 += 1; @@ -428,6 +390,13 @@ impl Host { } } + for alias in self.aliases.iter() { + let alias_bytes = CString::new(alias.clone())?.into_bytes_with_nul(); + let size_in_bytes: i32 = alias_bytes.len() as i32; + buf_aliases_size.extend_from_slice(&size_in_bytes.to_ne_bytes()); + buf_aliases.extend_from_slice(alias_bytes.as_slice()); + } + // this can only ever express one address family if num_v4 != 0 && num_v6 != 0 { bail!("unable to serialize mixed AF") @@ -436,7 +405,7 @@ impl Host { let num_addrs = num_v4 + num_v6; let has_addrs = num_addrs > 0; - let hostname_c_string_bytes = CString::new(self.hostname.clone())?.into_bytes_with_nul(); + let hostname_c_string_bytes = CString::new(self.name.clone())?.into_bytes_with_nul(); let hostname_c_string_len = if has_addrs { hostname_c_string_bytes.len() as i32 } else { @@ -447,7 +416,7 @@ impl Host { version: protocol::VERSION, found: if has_addrs { 1 } else { 0 }, h_name_len: hostname_c_string_len, - h_aliases_cnt: 0, + h_aliases_cnt: self.aliases.len() as i32, h_addrtype: if !has_addrs { -1 } else if num_v4 != 0 { @@ -462,15 +431,11 @@ impl Host { } else { 16 }, - h_addr_list_cnt: num_addrs as i32, - error: if has_addrs { - 0 - } else { - protocol::H_ERRNO_HOST_NOT_FOUND - }, + h_addr_list_cnt: num_addrs, + error: self.herrno, }; - let total_len = 4 * 8 + hostname_c_string_len as i32 + buf_addrs.len() as i32; + let total_len = 4 * 8 + hostname_c_string_len + buf_addrs.len() as i32 + buf_aliases.len() as i32 + buf_aliases_size.len() as i32; let mut buf = Vec::with_capacity(total_len as usize); // add header @@ -480,10 +445,20 @@ impl Host { if has_addrs { buf.extend_from_slice(&hostname_c_string_bytes); + // Add aliases sizes + if !self.aliases.is_empty() { + buf.extend_from_slice(buf_aliases_size.as_slice()); + } + // add serialized addresses from buf_addrs buf.extend_from_slice(buf_addrs.as_slice()); } + // add aliases + if !self.aliases.is_empty() { + buf.extend_from_slice(buf_aliases.as_slice()); + } + debug_assert_eq!(buf.len() as i32, total_len); Ok(buf) @@ -562,27 +537,10 @@ fn serialize_address_info(resp: &AiResponse) -> Result> { } } -/// Send a gethostby{addr,name}{,v6} entry back to the client, -/// or a response indicating the lookup failed. -fn serialize_host(log: &slog::Logger, host: Result>) -> Vec { - // if we didn't get an error take the inner value (Option) and then, - host.and_then(|maybe_host| { - // if it is Some(host) then serialize, else return the error. - maybe_host - .map(|h| h.serialize()) - // if the "host" is None then return a default error response. - .unwrap_or_else(|| Ok(protocol::HstResponseHeader::ERRNO_HOST_NOT_FOUND.to_vec())) - }) - // if after all of the above we still have to deal with an error, - // return the error response. - .unwrap_or_else(|e| { - error!(log, "parsing request"; "err" => %e); - protocol::HstResponseHeader::ERRNO_NETDB_INTERNAL.to_vec() - }) -} - #[cfg(test)] mod test { + use nix::libc::{AF_INET, AF_INET6}; + use super::super::config::Config; use std::net::{Ipv4Addr, Ipv6Addr}; @@ -684,13 +642,13 @@ mod test { key: &[127, 0, 0, 1], }; - let expected = serialize_host( - &test_logger(), - Ok(Some(Host { - addresses: vec![IpAddr::from(Ipv4Addr::new(127, 0, 0, 1))], - hostname: "localhost".to_string(), - })), - ); + let expected = (Hostent { + addr_list: vec![IpAddr::from(Ipv4Addr::new(127, 0, 0, 1))], + name: "localhost".to_string(), + addr_type: AF_INET, + aliases: Vec::new(), + herrno: 0 + }).serialize().expect("must serialize"); let output = handle_request(&test_logger(), &Config::default(), &request) .expect("should handle request with no error"); @@ -717,13 +675,13 @@ mod test { key: &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], }; - let expected = serialize_host( - &test_logger(), - Ok(Some(Host { - addresses: vec![IpAddr::from(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1))], - hostname: "localhost".to_string(), - })), - ); + let expected = (Hostent { + addr_list: vec![IpAddr::from(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1))], + name: "localhost".to_string(), + addr_type: AF_INET6, + aliases: Vec::new(), + herrno: 0 + }).serialize().expect("must serialize"); let output = handle_request(&test_logger(), &Config::default(), &request) .expect("should handle request with no error"); @@ -742,4 +700,29 @@ mod test { assert!(result.is_err(), "should error on invalid length"); } + + #[test] + fn test_hostent_serialization() { + let hostent = Hostent{ + name: String::from("trantor.alternativebit.fr"), + aliases: vec!(String::from("trantor")), + addr_type: AF_INET6, + addr_list: vec!(IpAddr::V6(Ipv6Addr::new(0,0,0,0,0,0,0,1))), + herrno: 0, + }.serialize().expect("should serialize"); + + // Captured through a mismatched sockburp run + let expected_bytes: Vec = + vec!( + 0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x0a,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x74,0x72,0x61,0x6e,0x74,0x6f,0x72,0x2e,0x61,0x6c,0x74,0x65,0x72,0x6e,0x61,0x74, + 0x69,0x76,0x65,0x62,0x69,0x74,0x2e,0x66,0x72,0x00,0x08,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x74,0x72, + 0x61,0x6e,0x74,0x6f,0x72,0x00 + ); + println!("{:x?}", hostent); + println!("{:x?}", expected_bytes); + assert_eq!(hostent, expected_bytes) + } } diff --git a/src/protocol.rs b/src/protocol.rs index 9bde033..bc0a76c 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -38,8 +38,6 @@ pub const VERSION: i32 = 2; /// Errors used in {Ai,Hst}ResponseHeader structs. /// See NSCD's resolv/netdb.h for the complete list. pub const H_ERRNO_NETDB_SUCCESS: i32 = 0; -pub const H_ERRNO_NETDB_INTERNAL: i32 = -1; -pub const H_ERRNO_HOST_NOT_FOUND: i32 = 1; // Authoritative Answer Host not found. #[allow(dead_code)] pub const H_ERRNO_TRY_AGAIN: i32 = 2; // Non-Authoritative Host not found @@ -264,33 +262,6 @@ impl HstResponseHeader { let p = self as *const _ as *const u8; unsafe { std::slice::from_raw_parts(p, size_of::()) } } - - /// Return the serialized header as vector of bytes - pub fn to_vec(&self) -> Vec { - self.as_slice().to_vec() - } - - pub const ERRNO_HOST_NOT_FOUND: Self = Self { - version: VERSION, - found: 0, - h_name_len: 0, - h_aliases_cnt: 0, - h_addrtype: -1 as i32, - h_length: -1 as i32, - h_addr_list_cnt: 0, - error: H_ERRNO_HOST_NOT_FOUND as i32, - }; - - pub const ERRNO_NETDB_INTERNAL: Self = Self { - version: VERSION, - found: 0, - h_name_len: 0, - h_aliases_cnt: 0, - h_addrtype: -1 as i32, - h_length: -1 as i32, - h_addr_list_cnt: H_ERRNO_NETDB_INTERNAL as i32, - error: 0, - }; } #[cfg(test)]