From ae2e1e16b7dd201d383fb50b54a87cb3d8c468d8 Mon Sep 17 00:00:00 2001 From: Erdem Meydanli Date: Wed, 10 Apr 2024 05:27:22 +0000 Subject: [PATCH] vsock_proxy: Use hickory_resolver for DNS resolution Replace the existing DNS lookup implementation with hickory_resolver. This allows accessing additional information from DNS records, such as TTL values, and enhances the functionality of the dns module. Signed-off-by: Erdem Meydanli --- Cargo.lock | 174 ++++++++++++++++++++++++++++++++++++++- vsock_proxy/Cargo.toml | 1 + vsock_proxy/src/dns.rs | 57 +++++++------ vsock_proxy/src/lib.rs | 4 +- vsock_proxy/src/proxy.rs | 26 ++++-- 5 files changed, 226 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 36bbe62c1..fcc7f4018 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,6 +32,17 @@ dependencies = [ "libc", ] +[[package]] +name = "async-trait" +version = "0.1.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "531b97fb4cd3dfdce92c35dedbfdc1f0b9d8091c8ca943d6dae340ef5012d514" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + [[package]] name = "atty" version = "0.2.14" @@ -353,6 +364,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "data-encoding" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" + [[package]] name = "digest" version = "0.9.0" @@ -415,6 +432,18 @@ dependencies = [ "url", ] +[[package]] +name = "enum-as-inner" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.37", +] + [[package]] name = "env_logger" version = "0.10.0" @@ -668,6 +697,12 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -689,6 +724,62 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hickory-proto" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "091a6fbccf4860009355e3efc52ff4acf37a63489aad7435372d44ceeb6fbbcf" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna 0.4.0", + "ipnet", + "once_cell", + "rand", + "thiserror", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35b8f021164e6a984c9030023544c57789c51760065cd510572fedcfb04164e8" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "lru-cache", + "once_cell", + "parking_lot", + "rand", + "resolv-conf", + "smallvec", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + [[package]] name = "http" version = "0.2.6" @@ -878,6 +969,24 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "ipconfig" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +dependencies = [ + "socket2 0.5.4", + "widestring", + "windows-sys 0.48.0", + "winreg", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + [[package]] name = "is-terminal" version = "0.4.5" @@ -987,6 +1096,21 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + [[package]] name = "memchr" version = "2.4.1" @@ -1233,9 +1357,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.10.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" @@ -1421,6 +1545,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quote" version = "1.0.33" @@ -1495,6 +1625,16 @@ version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error", +] + [[package]] name = "rustc-hash" version = "1.1.0" @@ -1857,6 +1997,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" dependencies = [ "autocfg", + "bytes 1.1.0", "libc", "mio", "num_cpus", @@ -1897,9 +2038,21 @@ checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f" dependencies = [ "cfg-if", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + [[package]] name = "tracing-core" version = "0.1.23" @@ -2000,6 +2153,7 @@ dependencies = [ "ctor", "dns-lookup", "env_logger", + "hickory-resolver", "idna 0.3.0", "log", "nix 0.26.2", @@ -2091,6 +2245,12 @@ dependencies = [ "libc", ] +[[package]] +name = "widestring" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" + [[package]] name = "winapi" version = "0.3.9" @@ -2297,6 +2457,16 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "xattr" version = "0.2.2" diff --git a/vsock_proxy/Cargo.toml b/vsock_proxy/Cargo.toml index 3daf60f21..6f5e64a79 100644 --- a/vsock_proxy/Cargo.toml +++ b/vsock_proxy/Cargo.toml @@ -12,6 +12,7 @@ chrono = "0.4" clap = "3.2" dns-lookup = "2.0.3" env_logger = "0.10" +hickory-resolver = "0.24" idna = "0.3.0" log = "0.4" nix = "0.26" diff --git a/vsock_proxy/src/dns.rs b/vsock_proxy/src/dns.rs index a9c650627..9aa3e6d1e 100644 --- a/vsock_proxy/src/dns.rs +++ b/vsock_proxy/src/dns.rs @@ -1,13 +1,13 @@ -// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// Copyright 2019-2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 #![deny(warnings)] /// Contains code for Proxy, a library used for translating vsock traffic to /// TCP traffic /// -use dns_lookup::lookup_host; +use hickory_resolver::config::*; +use hickory_resolver::Resolver; use idna::domain_to_ascii; -use std::net::IpAddr; use crate::{DnsResolveResult, IpAddrType, VsockProxyResult}; @@ -18,35 +18,42 @@ pub fn resolve(addr: &str, ip_addr_type: IpAddrType) -> VsockProxyResult = resolver + .lookup_ip(addr) + .map_err(|error| format!("DNS lookup failed! {:?}", error))? + .as_lookup() + .records() + .iter() + .filter_map(|record| { + if let Some(rdata) = record.data() { + if let Some(ip) = rdata.ip_addr() { + let ttl = record.ttl(); + return Some(DnsResolveResult { ip, ttl }); + } + } + None + }) + .collect(); - if ips.is_empty() { + if rresults.is_empty() { return Err("DNS lookup returned no IP addresses!".into()); } - let ttl = 60; //TODO: update hardcoded value - // If there is no restriction, choose randomly if IpAddrType::IPAddrMixed == ip_addr_type { - return Ok(ips - .into_iter() - .map(|ip| DnsResolveResult { ip, ttl }) - .collect()); + return Ok(rresults); } - // Split the IPs in v4 and v6 - let (ips_v4, ips_v6): (Vec<_>, Vec<_>) = ips.into_iter().partition(IpAddr::is_ipv4); - - if IpAddrType::IPAddrV4Only == ip_addr_type && !ips_v4.is_empty() { - Ok(ips_v4 - .into_iter() - .map(|ip| DnsResolveResult { ip, ttl }) - .collect()) - } else if IpAddrType::IPAddrV6Only == ip_addr_type && !ips_v6.is_empty() { - Ok(ips_v6 - .into_iter() - .map(|ip| DnsResolveResult { ip, ttl }) - .collect()) + //Partition the resolution results into groups that use IPv4 or IPv6 addresses. + let (rresults_with_ipv4, rresults_with_ipv6): (Vec<_>, Vec<_>) = + rresults.into_iter().partition(|result| result.ip.is_ipv4()); + + if IpAddrType::IPAddrV4Only == ip_addr_type && !rresults_with_ipv4.is_empty() { + Ok(rresults_with_ipv4) + } else if IpAddrType::IPAddrV6Only == ip_addr_type && !rresults_with_ipv6.is_empty() { + Ok(rresults_with_ipv6) } else { Err("No accepted IP was found.".to_string()) } @@ -65,8 +72,8 @@ mod tests { use super::*; use ctor::ctor; - use std::sync::Once; use std::env; + use std::sync::Once; static TEST_INIT: Once = Once::new(); diff --git a/vsock_proxy/src/lib.rs b/vsock_proxy/src/lib.rs index 1662b0ad5..b6c4e3a35 100644 --- a/vsock_proxy/src/lib.rs +++ b/vsock_proxy/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// Copyright 2019-2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 pub mod dns; @@ -16,7 +16,7 @@ pub enum IpAddrType { IPAddrMixed, } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct DnsResolveResult { ///Resolved address pub ip: IpAddr, diff --git a/vsock_proxy/src/proxy.rs b/vsock_proxy/src/proxy.rs index 6d754ba71..2696dcddb 100644 --- a/vsock_proxy/src/proxy.rs +++ b/vsock_proxy/src/proxy.rs @@ -1,11 +1,11 @@ -// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// Copyright 2019-2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 //#![deny(warnings)] /// Contains code for Proxy, a library used for translating vsock traffic to /// TCP traffic use chrono::{DateTime, Duration, Utc}; -use log::info; +use log::{info, warn}; use nix::sys::select::{select, FdSet}; use nix::sys::socket::SockType; use std::fs::File; @@ -64,11 +64,23 @@ pub fn check_allowlist( } // If hostname matching failed, attempt to match against IPs. - let rresults = dns::resolve(addr, ip_addr_type)?; - for rresult in rresults.into_iter() { - if rresult.ip == remote_addr { - info!("Matched with host IP \"{}\" and port \"{}\"", addr, port); - return Ok(remote_addr); + let rresults = dns::resolve(addr, ip_addr_type); + let remote_addr_matched = rresults.clone().ok().and_then(|rresults| { + rresults + .into_iter() + .find(|rresult| rresult.ip == remote_addr) + .map(|_| { + info!("Matched with host IP \"{}\" and port \"{}\"", addr, port); + remote_addr + }) + }); + + match remote_addr_matched { + Some(matched_addr) => return Ok(matched_addr), + None => { + if rresults.is_err() { + warn!("Unable to resolve allow listed host: {:?}.", addr); + } } } }