Compare commits
1 Commits
main
...
fix/self-r
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
25ebdb311f |
@@ -13,7 +13,7 @@
|
|||||||
//! servers, with TCP fallback on UDP timeout (for networks that block
|
//! servers, with TCP fallback on UDP timeout (for networks that block
|
||||||
//! outbound UDP:53 — see memory: `project_network_udp_hostile.md`).
|
//! outbound UDP:53 — see memory: `project_network_udp_hostile.md`).
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::BTreeMap;
|
||||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ const DEFAULT_BOOTSTRAP: &[SocketAddr] = &[
|
|||||||
|
|
||||||
pub struct NumaResolver {
|
pub struct NumaResolver {
|
||||||
bootstrap: Vec<SocketAddr>,
|
bootstrap: Vec<SocketAddr>,
|
||||||
overrides: HashMap<String, Vec<IpAddr>>,
|
overrides: BTreeMap<String, Vec<IpAddr>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NumaResolver {
|
impl NumaResolver {
|
||||||
@@ -44,7 +44,7 @@ impl NumaResolver {
|
|||||||
/// `fallback` entries are filtered to IP literals only — hostnames would
|
/// `fallback` entries are filtered to IP literals only — hostnames would
|
||||||
/// re-introduce the self-loop inside the resolver itself. Empty or
|
/// re-introduce the self-loop inside the resolver itself. Empty or
|
||||||
/// unusable fallback yields the hardcoded default (Quad9 + Cloudflare).
|
/// unusable fallback yields the hardcoded default (Quad9 + Cloudflare).
|
||||||
pub fn new(fallback: &[String], overrides: HashMap<String, Vec<IpAddr>>) -> Self {
|
pub fn new(fallback: &[String], overrides: BTreeMap<String, Vec<IpAddr>>) -> Self {
|
||||||
let mut bootstrap: Vec<SocketAddr> = Vec::with_capacity(fallback.len());
|
let mut bootstrap: Vec<SocketAddr> = Vec::with_capacity(fallback.len());
|
||||||
for entry in fallback {
|
for entry in fallback {
|
||||||
match crate::forward::parse_upstream_addr(entry, 53) {
|
match crate::forward::parse_upstream_addr(entry, 53) {
|
||||||
@@ -71,11 +71,10 @@ impl NumaResolver {
|
|||||||
source
|
source
|
||||||
);
|
);
|
||||||
if !overrides.is_empty() {
|
if !overrides.is_empty() {
|
||||||
let mut pairs: Vec<String> = overrides
|
let pairs: Vec<String> = overrides
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|(host, ips)| ips.iter().map(move |ip| format!("{}={}", host, ip)))
|
.flat_map(|(host, addrs)| addrs.iter().map(move |ip| format!("{}={}", host, ip)))
|
||||||
.collect();
|
.collect();
|
||||||
pairs.sort();
|
|
||||||
info!(
|
info!(
|
||||||
"bootstrap resolver: host overrides (skip DNS, connect direct): {}",
|
"bootstrap resolver: host overrides (skip DNS, connect direct): {}",
|
||||||
pairs.join(", ")
|
pairs.join(", ")
|
||||||
@@ -185,7 +184,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_fallback_uses_defaults() {
|
fn empty_fallback_uses_defaults() {
|
||||||
let r = NumaResolver::new(&[], HashMap::new());
|
let r = NumaResolver::new(&[], BTreeMap::new());
|
||||||
let got: Vec<String> = r.bootstrap().iter().map(|s| s.to_string()).collect();
|
let got: Vec<String> = r.bootstrap().iter().map(|s| s.to_string()).collect();
|
||||||
assert_eq!(got, vec!["9.9.9.9:53", "1.1.1.1:53"]);
|
assert_eq!(got, vec!["9.9.9.9:53", "1.1.1.1:53"]);
|
||||||
}
|
}
|
||||||
@@ -197,14 +196,14 @@ mod tests {
|
|||||||
"dns.quad9.net".to_string(),
|
"dns.quad9.net".to_string(),
|
||||||
"1.1.1.1:5353".to_string(),
|
"1.1.1.1:5353".to_string(),
|
||||||
];
|
];
|
||||||
let r = NumaResolver::new(&fallback, HashMap::new());
|
let r = NumaResolver::new(&fallback, BTreeMap::new());
|
||||||
let got: Vec<String> = r.bootstrap().iter().map(|s| s.to_string()).collect();
|
let got: Vec<String> = r.bootstrap().iter().map(|s| s.to_string()).collect();
|
||||||
assert_eq!(got, vec!["9.9.9.9:53", "1.1.1.1:5353"]);
|
assert_eq!(got, vec!["9.9.9.9:53", "1.1.1.1:5353"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn override_returns_configured_ips_without_dns() {
|
fn override_returns_configured_ips_without_dns() {
|
||||||
let mut overrides = HashMap::new();
|
let mut overrides = BTreeMap::new();
|
||||||
overrides.insert(
|
overrides.insert(
|
||||||
"odoh-relay.example".to_string(),
|
"odoh-relay.example".to_string(),
|
||||||
vec![IpAddr::V4(Ipv4Addr::new(178, 104, 229, 30))],
|
vec![IpAddr::V4(Ipv4Addr::new(178, 104, 229, 30))],
|
||||||
@@ -220,7 +219,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn override_supports_multiple_ips_including_ipv6() {
|
fn override_supports_multiple_ips_including_ipv6() {
|
||||||
let mut overrides = HashMap::new();
|
let mut overrides = BTreeMap::new();
|
||||||
overrides.insert(
|
overrides.insert(
|
||||||
"dual.example".to_string(),
|
"dual.example".to_string(),
|
||||||
vec![
|
vec![
|
||||||
|
|||||||
@@ -245,8 +245,8 @@ impl OdohUpstream {
|
|||||||
/// Per-host IP overrides for the bootstrap resolver, lifted from
|
/// Per-host IP overrides for the bootstrap resolver, lifted from
|
||||||
/// `relay_ip`/`target_ip`. Keeps the "zero plain-DNS leak for ODoH
|
/// `relay_ip`/`target_ip`. Keeps the "zero plain-DNS leak for ODoH
|
||||||
/// endpoints" property when numa is its own system resolver.
|
/// endpoints" property when numa is its own system resolver.
|
||||||
pub fn host_ip_overrides(&self) -> std::collections::HashMap<String, Vec<std::net::IpAddr>> {
|
pub fn host_ip_overrides(&self) -> std::collections::BTreeMap<String, Vec<std::net::IpAddr>> {
|
||||||
let mut out = std::collections::HashMap::new();
|
let mut out = std::collections::BTreeMap::new();
|
||||||
if let Some(addr) = self.relay_bootstrap {
|
if let Some(addr) = self.relay_bootstrap {
|
||||||
out.entry(self.relay_host.clone())
|
out.entry(self.relay_host.clone())
|
||||||
.or_insert_with(Vec::new)
|
.or_insert_with(Vec::new)
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ pub async fn run(config_path: String) -> crate::Result<()> {
|
|||||||
.odoh_upstream()
|
.odoh_upstream()
|
||||||
.map(|o| o.host_ip_overrides())
|
.map(|o| o.host_ip_overrides())
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
_ => std::collections::HashMap::new(),
|
_ => std::collections::BTreeMap::new(),
|
||||||
};
|
};
|
||||||
let bootstrap_resolver: Arc<NumaResolver> = Arc::new(NumaResolver::new(
|
let bootstrap_resolver: Arc<NumaResolver> = Arc::new(NumaResolver::new(
|
||||||
&config.upstream.fallback,
|
&config.upstream.fallback,
|
||||||
|
|||||||
@@ -975,11 +975,10 @@ check "Same-host relay+target rejected at startup" \
|
|||||||
"same host" \
|
"same host" \
|
||||||
"$STARTUP_OUT"
|
"$STARTUP_OUT"
|
||||||
|
|
||||||
# relay_ip / target_ip must land in the bootstrap resolver's override map,
|
# Guards ODoH's zero-plain-DNS-leak property: relay_ip / target_ip must
|
||||||
# so reqwest connects direct to the configured IPs instead of resolving the
|
# land in the bootstrap resolver's override map so reqwest connects direct
|
||||||
# hostnames via plain DNS (ODoH's zero-plain-DNS-leak property). Using
|
# to the configured IPs instead of resolving the hostnames via plain DNS.
|
||||||
# RFC 5737 TEST-NET-1 IPs — never routable, so the OdohConfigCache won't
|
# RFC 5737 TEST-NET-1 IPs (unroutable).
|
||||||
# actually connect, but the override-map wiring is visible in the startup log.
|
|
||||||
cat > "$CONFIG" << 'CONF'
|
cat > "$CONFIG" << 'CONF'
|
||||||
[server]
|
[server]
|
||||||
bind_addr = "127.0.0.1:5354"
|
bind_addr = "127.0.0.1:5354"
|
||||||
@@ -1019,7 +1018,6 @@ check "target_ip wired into bootstrap override map" \
|
|||||||
|
|
||||||
kill "$NUMA_PID" 2>/dev/null || true
|
kill "$NUMA_PID" 2>/dev/null || true
|
||||||
wait "$NUMA_PID" 2>/dev/null || true
|
wait "$NUMA_PID" 2>/dev/null || true
|
||||||
sleep 1
|
|
||||||
|
|
||||||
fi # end Suite 8
|
fi # end Suite 8
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user