mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 17:30:23 +08:00
feat(proxy): 支持配置 private 目标地址放行
This commit is contained in:
@@ -76,6 +76,7 @@ sudo aether-proxy uninstall
|
|||||||
| `--node-region` | `AETHER_PROXY_NODE_REGION` | 自动检测 | 地区标识 |
|
| `--node-region` | `AETHER_PROXY_NODE_REGION` | 自动检测 | 地区标识 |
|
||||||
| `--heartbeat-interval` | `AETHER_PROXY_HEARTBEAT_INTERVAL` | `5` | 心跳间隔(秒) |
|
| `--heartbeat-interval` | `AETHER_PROXY_HEARTBEAT_INTERVAL` | `5` | 心跳间隔(秒) |
|
||||||
| `--allowed-ports` | `AETHER_PROXY_ALLOWED_PORTS` | `80,443,8080,8443` | 允许代理的目标端口 |
|
| `--allowed-ports` | `AETHER_PROXY_ALLOWED_PORTS` | `80,443,8080,8443` | 允许代理的目标端口 |
|
||||||
|
| `--allow-private-targets` | `AETHER_PROXY_ALLOW_PRIVATE_TARGETS` | `true` | 允许 private/reserved 目标地址,通过后仍受 `allowed_ports` 限制;设为 `false` 可恢复严格拦截 |
|
||||||
|
|
||||||
#### Tunnel 连接
|
#### Tunnel 连接
|
||||||
|
|
||||||
@@ -121,6 +122,7 @@ sudo aether-proxy uninstall
|
|||||||
|
|
||||||
| 参数 | 环境变量 | 默认值 | 说明 |
|
| 参数 | 环境变量 | 默认值 | 说明 |
|
||||||
|------|----------|--------|------|
|
|------|----------|--------|------|
|
||||||
|
| `--allow-private-targets` | `AETHER_PROXY_ALLOW_PRIVATE_TARGETS` | `true` | 默认允许 private/reserved 目标地址;设为 `false` 可恢复拦截,且仅影响重启后的进程 |
|
||||||
| `--dns-cache-ttl-secs` | `AETHER_PROXY_DNS_CACHE_TTL_SECS` | `60` | DNS 缓存 TTL(秒) |
|
| `--dns-cache-ttl-secs` | `AETHER_PROXY_DNS_CACHE_TTL_SECS` | `60` | DNS 缓存 TTL(秒) |
|
||||||
| `--dns-cache-capacity` | `AETHER_PROXY_DNS_CACHE_CAPACITY` | `1024` | DNS 缓存容量(条目数) |
|
| `--dns-cache-capacity` | `AETHER_PROXY_DNS_CACHE_CAPACITY` | `1024` | DNS 缓存容量(条目数) |
|
||||||
|
|
||||||
|
|||||||
@@ -940,6 +940,7 @@ mod tests {
|
|||||||
node_region: None,
|
node_region: None,
|
||||||
heartbeat_interval: 1,
|
heartbeat_interval: 1,
|
||||||
allowed_ports: vec![80, 443],
|
allowed_ports: vec![80, 443],
|
||||||
|
allow_private_targets: false,
|
||||||
aether_request_timeout_secs: 10,
|
aether_request_timeout_secs: 10,
|
||||||
aether_connect_timeout_secs: 2,
|
aether_connect_timeout_secs: 2,
|
||||||
aether_pool_max_idle_per_host: 8,
|
aether_pool_max_idle_per_host: 8,
|
||||||
|
|||||||
@@ -284,6 +284,14 @@ pub struct Config {
|
|||||||
)]
|
)]
|
||||||
pub allowed_ports: Vec<u16>,
|
pub allowed_ports: Vec<u16>,
|
||||||
|
|
||||||
|
/// Allow private/reserved upstream IP targets. Enabled by default.
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
env = "AETHER_PROXY_ALLOW_PRIVATE_TARGETS",
|
||||||
|
default_value_t = true
|
||||||
|
)]
|
||||||
|
pub allow_private_targets: bool,
|
||||||
|
|
||||||
/// Aether API request timeout in seconds
|
/// Aether API request timeout in seconds
|
||||||
#[arg(
|
#[arg(
|
||||||
long,
|
long,
|
||||||
@@ -808,6 +816,8 @@ pub struct ConfigFile {
|
|||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub allowed_ports: Option<Vec<u16>>,
|
pub allowed_ports: Option<Vec<u16>>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub allow_private_targets: Option<bool>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub aether_request_timeout_secs: Option<u64>,
|
pub aether_request_timeout_secs: Option<u64>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub aether_connect_timeout_secs: Option<u64>,
|
pub aether_connect_timeout_secs: Option<u64>,
|
||||||
@@ -950,6 +960,10 @@ impl ConfigFile {
|
|||||||
set!("AETHER_PROXY_NODE_NAME", node_name);
|
set!("AETHER_PROXY_NODE_NAME", node_name);
|
||||||
set!("AETHER_PROXY_NODE_REGION", self.node_region);
|
set!("AETHER_PROXY_NODE_REGION", self.node_region);
|
||||||
set!("AETHER_PROXY_HEARTBEAT_INTERVAL", self.heartbeat_interval);
|
set!("AETHER_PROXY_HEARTBEAT_INTERVAL", self.heartbeat_interval);
|
||||||
|
set!(
|
||||||
|
"AETHER_PROXY_ALLOW_PRIVATE_TARGETS",
|
||||||
|
self.allow_private_targets
|
||||||
|
);
|
||||||
set!(
|
set!(
|
||||||
"AETHER_PROXY_AETHER_REQUEST_TIMEOUT",
|
"AETHER_PROXY_AETHER_REQUEST_TIMEOUT",
|
||||||
self.aether_request_timeout_secs
|
self.aether_request_timeout_secs
|
||||||
@@ -1182,6 +1196,12 @@ mod tests {
|
|||||||
assert_eq!(stringy.redirect_replay_budget_bytes.as_deref(), Some("6M"));
|
assert_eq!(stringy.redirect_replay_budget_bytes.as_deref(), Some("6M"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn config_file_deserializes_allow_private_targets() {
|
||||||
|
let cfg: ConfigFile = toml::from_str("allow_private_targets = true").expect("bool toml");
|
||||||
|
assert_eq!(cfg.allow_private_targets, Some(true));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn config_file_rejects_removed_tunnel_seconds_keys() {
|
fn config_file_rejects_removed_tunnel_seconds_keys() {
|
||||||
let error = reject_removed_config_keys("tunnel_ping_interval_secs = 5")
|
let error = reject_removed_config_keys("tunnel_ping_interval_secs = 5")
|
||||||
@@ -1224,6 +1244,20 @@ mod tests {
|
|||||||
assert!(node_name.get_default_values().is_empty());
|
assert!(node_name.get_default_values().is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cli_defaults_private_targets_to_enabled() {
|
||||||
|
let config = Config::parse_from([
|
||||||
|
"aether-proxy",
|
||||||
|
"--aether-url",
|
||||||
|
"https://example.com",
|
||||||
|
"--management-token",
|
||||||
|
"ae_test",
|
||||||
|
"--node-name",
|
||||||
|
"proxy-test",
|
||||||
|
]);
|
||||||
|
assert!(config.allow_private_targets);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn tunnel_fast_recovery_defaults_use_millisecond_values() {
|
fn tunnel_fast_recovery_defaults_use_millisecond_values() {
|
||||||
let config = Config::parse_from([
|
let config = Config::parse_from([
|
||||||
|
|||||||
@@ -166,6 +166,15 @@ impl App {
|
|||||||
required: false,
|
required: false,
|
||||||
help: "Write pretty .log files with daily rotation and 7-day retention",
|
help: "Write pretty .log files with daily rotation and 7-day retention",
|
||||||
},
|
},
|
||||||
|
Field {
|
||||||
|
label: "Allow Private Targets",
|
||||||
|
key: "allow_private_targets",
|
||||||
|
value: "true".into(),
|
||||||
|
kind: FieldKind::Bool,
|
||||||
|
required: false,
|
||||||
|
help:
|
||||||
|
"Allow proxying private/reserved upstream IPs by default; takes effect after restart",
|
||||||
|
},
|
||||||
Field {
|
Field {
|
||||||
label: "Heartbeat Interval",
|
label: "Heartbeat Interval",
|
||||||
key: "heartbeat_interval",
|
key: "heartbeat_interval",
|
||||||
@@ -254,6 +263,7 @@ impl App {
|
|||||||
)
|
)
|
||||||
.to_string()
|
.to_string()
|
||||||
}),
|
}),
|
||||||
|
"allow_private_targets" => cfg.allow_private_targets.map(|v| v.to_string()),
|
||||||
"heartbeat_interval" => cfg.heartbeat_interval.map(|v| v.to_string()),
|
"heartbeat_interval" => cfg.heartbeat_interval.map(|v| v.to_string()),
|
||||||
"redirect_replay_budget_bytes" => cfg.redirect_replay_budget_bytes.clone(),
|
"redirect_replay_budget_bytes" => cfg.redirect_replay_budget_bytes.clone(),
|
||||||
_ => None,
|
_ => None,
|
||||||
@@ -362,6 +372,7 @@ impl App {
|
|||||||
let save_logs_to_file = self.toggle_enabled("save_logs_to_file");
|
let save_logs_to_file = self.toggle_enabled("save_logs_to_file");
|
||||||
let mut cfg = ConfigFile {
|
let mut cfg = ConfigFile {
|
||||||
log_level: get_global("log_level"),
|
log_level: get_global("log_level"),
|
||||||
|
allow_private_targets: Some(self.toggle_enabled("allow_private_targets")),
|
||||||
heartbeat_interval: self.parse_optional_heartbeat_interval()?,
|
heartbeat_interval: self.parse_optional_heartbeat_interval()?,
|
||||||
redirect_replay_budget_bytes: self.parse_optional_redirect_replay_budget()?,
|
redirect_replay_budget_bytes: self.parse_optional_redirect_replay_budget()?,
|
||||||
log_destination: Some(if save_logs_to_file {
|
log_destination: Some(if save_logs_to_file {
|
||||||
@@ -1089,10 +1100,12 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn to_config_persists_optional_heartbeat_interval() {
|
fn to_config_persists_optional_heartbeat_interval() {
|
||||||
let mut app = sample_app();
|
let mut app = sample_app();
|
||||||
|
set_global_field(&mut app, "allow_private_targets", "true");
|
||||||
set_global_field(&mut app, "heartbeat_interval", "45");
|
set_global_field(&mut app, "heartbeat_interval", "45");
|
||||||
set_global_field(&mut app, "redirect_replay_budget_bytes", "6m");
|
set_global_field(&mut app, "redirect_replay_budget_bytes", "6m");
|
||||||
|
|
||||||
let cfg = app.to_config().expect("config should serialize");
|
let cfg = app.to_config().expect("config should serialize");
|
||||||
|
assert_eq!(cfg.allow_private_targets, Some(true));
|
||||||
assert_eq!(cfg.heartbeat_interval, Some(45));
|
assert_eq!(cfg.heartbeat_interval, Some(45));
|
||||||
assert_eq!(cfg.redirect_replay_budget_bytes.as_deref(), Some("6M"));
|
assert_eq!(cfg.redirect_replay_budget_bytes.as_deref(), Some("6M"));
|
||||||
}
|
}
|
||||||
@@ -1131,7 +1144,12 @@ mod tests {
|
|||||||
let config_path = unique_temp_config_path("ctrl-s");
|
let config_path = unique_temp_config_path("ctrl-s");
|
||||||
let mut app = sample_app();
|
let mut app = sample_app();
|
||||||
app.config_path = config_path.clone();
|
app.config_path = config_path.clone();
|
||||||
app.selected = app.server_field_count() + 3;
|
let heartbeat_idx = app
|
||||||
|
.global_fields
|
||||||
|
.iter()
|
||||||
|
.position(|field| field.key == "heartbeat_interval")
|
||||||
|
.expect("heartbeat field");
|
||||||
|
app.selected = app.server_field_count() + heartbeat_idx;
|
||||||
app.mode = Mode::Editing;
|
app.mode = Mode::Editing;
|
||||||
app.edit_buffer = "45".to_string();
|
app.edit_buffer = "45".to_string();
|
||||||
app.edit_cursor = 2;
|
app.edit_cursor = 2;
|
||||||
|
|||||||
@@ -210,13 +210,15 @@ impl DnsCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve a hostname to public (non-private) socket addresses.
|
/// Resolve a hostname to validated socket addresses.
|
||||||
///
|
///
|
||||||
/// Results are cached in `dns_cache`. Private/reserved IPs are filtered out.
|
/// Results are cached in `dns_cache`. Private/reserved IPs are filtered out
|
||||||
/// Returns an error if no public addresses remain after filtering.
|
/// unless `allow_private` is enabled. Returns an error if filtering removes
|
||||||
|
/// every resolved address.
|
||||||
pub async fn resolve_public_addrs(
|
pub async fn resolve_public_addrs(
|
||||||
host: &str,
|
host: &str,
|
||||||
port: u16,
|
port: u16,
|
||||||
|
allow_private: bool,
|
||||||
dns_cache: &DnsCache,
|
dns_cache: &DnsCache,
|
||||||
) -> Result<Vec<SocketAddr>, FilterError> {
|
) -> Result<Vec<SocketAddr>, FilterError> {
|
||||||
// Cache hit
|
// Cache hit
|
||||||
@@ -235,11 +237,15 @@ pub async fn resolve_public_addrs(
|
|||||||
return Err(FilterError::DnsResolutionFailed(host.to_string()));
|
return Err(FilterError::DnsResolutionFailed(host.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter out private/reserved addresses
|
// Filter out private/reserved addresses unless explicitly allowed.
|
||||||
let public: Vec<SocketAddr> = resolved
|
let public: Vec<SocketAddr> = if allow_private {
|
||||||
.into_iter()
|
resolved
|
||||||
.filter(|addr| !is_private_ip(&addr.ip()))
|
} else {
|
||||||
.collect();
|
resolved
|
||||||
|
.into_iter()
|
||||||
|
.filter(|addr| !is_private_ip(&addr.ip()))
|
||||||
|
.collect()
|
||||||
|
};
|
||||||
|
|
||||||
if public.is_empty() {
|
if public.is_empty() {
|
||||||
return Err(FilterError::NoPublicAddrs(host.to_string()));
|
return Err(FilterError::NoPublicAddrs(host.to_string()));
|
||||||
@@ -260,6 +266,7 @@ pub async fn validate_target(
|
|||||||
host: &str,
|
host: &str,
|
||||||
port: u16,
|
port: u16,
|
||||||
allowed_ports: &HashSet<u16>,
|
allowed_ports: &HashSet<u16>,
|
||||||
|
allow_private: bool,
|
||||||
dns_cache: &DnsCache,
|
dns_cache: &DnsCache,
|
||||||
) -> Result<Vec<SocketAddr>, FilterError> {
|
) -> Result<Vec<SocketAddr>, FilterError> {
|
||||||
// Port whitelist check
|
// Port whitelist check
|
||||||
@@ -269,14 +276,14 @@ pub async fn validate_target(
|
|||||||
|
|
||||||
// Try parsing as IP directly (no DNS needed)
|
// Try parsing as IP directly (no DNS needed)
|
||||||
if let Ok(ip) = host.parse::<IpAddr>() {
|
if let Ok(ip) = host.parse::<IpAddr>() {
|
||||||
if is_private_ip(&ip) {
|
if !allow_private && is_private_ip(&ip) {
|
||||||
return Err(FilterError::PrivateIp(ip));
|
return Err(FilterError::PrivateIp(ip));
|
||||||
}
|
}
|
||||||
return Ok(vec![SocketAddr::new(ip, port)]);
|
return Ok(vec![SocketAddr::new(ip, port)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve and validate DNS (populates cache for SafeDnsResolver)
|
// Resolve and validate DNS (populates cache for SafeDnsResolver)
|
||||||
resolve_public_addrs(host, port, dns_cache).await
|
resolve_public_addrs(host, port, allow_private, dns_cache).await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -333,27 +340,54 @@ mod tests {
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_port_not_allowed() {
|
async fn test_port_not_allowed() {
|
||||||
let cache = cache();
|
let cache = cache();
|
||||||
let result = validate_target("8.8.8.8", 22, &ports(), &cache).await;
|
let result = validate_target("8.8.8.8", 22, &ports(), false, &cache).await;
|
||||||
assert!(matches!(result, Err(FilterError::PortNotAllowed(22))));
|
assert!(matches!(result, Err(FilterError::PortNotAllowed(22))));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_private_ip_blocked() {
|
async fn test_private_ip_blocked() {
|
||||||
let cache = cache();
|
let cache = cache();
|
||||||
let result = validate_target("127.0.0.1", 80, &ports(), &cache).await;
|
let result = validate_target("127.0.0.1", 80, &ports(), false, &cache).await;
|
||||||
assert!(matches!(result, Err(FilterError::PrivateIp(_))));
|
assert!(matches!(result, Err(FilterError::PrivateIp(_))));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_public_ip_allowed() {
|
async fn test_public_ip_allowed() {
|
||||||
let cache = cache();
|
let cache = cache();
|
||||||
let result = validate_target("8.8.8.8", 443, &ports(), &cache).await;
|
let result = validate_target("8.8.8.8", 443, &ports(), false, &cache).await;
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
let addrs = result.unwrap();
|
let addrs = result.unwrap();
|
||||||
assert_eq!(addrs.len(), 1);
|
assert_eq!(addrs.len(), 1);
|
||||||
assert_eq!(addrs[0].ip(), IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8)));
|
assert_eq!(addrs[0].ip(), IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_private_ip_allowed_when_enabled() {
|
||||||
|
let cache = cache();
|
||||||
|
let result = validate_target("127.0.0.1", 80, &ports(), true, &cache).await;
|
||||||
|
assert!(result.is_ok());
|
||||||
|
let addrs = result.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
addrs,
|
||||||
|
vec![SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 80)]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_localhost_hostname_blocked_by_default() {
|
||||||
|
let cache = cache();
|
||||||
|
let result = validate_target("localhost", 80, &ports(), false, &cache).await;
|
||||||
|
assert!(matches!(result, Err(FilterError::NoPublicAddrs(_))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_localhost_hostname_allowed_when_enabled() {
|
||||||
|
let cache = cache();
|
||||||
|
let result = validate_target("localhost", 80, &ports(), true, &cache).await;
|
||||||
|
assert!(result.is_ok());
|
||||||
|
assert!(!result.unwrap().is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_cache_stores_multiple_addrs() {
|
async fn test_cache_stores_multiple_addrs() {
|
||||||
let cache = cache();
|
let cache = cache();
|
||||||
|
|||||||
@@ -479,6 +479,7 @@ mod tests {
|
|||||||
node_region: None,
|
node_region: None,
|
||||||
heartbeat_interval: 1,
|
heartbeat_interval: 1,
|
||||||
allowed_ports: vec![80, 443],
|
allowed_ports: vec![80, 443],
|
||||||
|
allow_private_targets: false,
|
||||||
aether_request_timeout_secs: 10,
|
aether_request_timeout_secs: 10,
|
||||||
aether_connect_timeout_secs: 2,
|
aether_connect_timeout_secs: 2,
|
||||||
aether_pool_max_idle_per_host: 8,
|
aether_pool_max_idle_per_host: 8,
|
||||||
|
|||||||
@@ -381,8 +381,14 @@ async fn execute_upstream_request(
|
|||||||
let dns_start = Instant::now();
|
let dns_start = Instant::now();
|
||||||
{
|
{
|
||||||
let allowed_ports = Arc::clone(&server.dynamic.load().allowed_ports);
|
let allowed_ports = Arc::clone(&server.dynamic.load().allowed_ports);
|
||||||
if let Err(error) =
|
if let Err(error) = target_filter::validate_target(
|
||||||
target_filter::validate_target(host, port, &allowed_ports, &state.dns_cache).await
|
host,
|
||||||
|
port,
|
||||||
|
&allowed_ports,
|
||||||
|
state.config.allow_private_targets,
|
||||||
|
&state.dns_cache,
|
||||||
|
)
|
||||||
|
.await
|
||||||
{
|
{
|
||||||
server.metrics.dns_failures.fetch_add(1, Ordering::Release);
|
server.metrics.dns_failures.fetch_add(1, Ordering::Release);
|
||||||
return Err(format!("target blocked: {error}"));
|
return Err(format!("target blocked: {error}"));
|
||||||
@@ -1560,6 +1566,7 @@ mod tests {
|
|||||||
node_region: None,
|
node_region: None,
|
||||||
heartbeat_interval: 30,
|
heartbeat_interval: 30,
|
||||||
allowed_ports: vec![80, 443],
|
allowed_ports: vec![80, 443],
|
||||||
|
allow_private_targets: false,
|
||||||
aether_request_timeout_secs: 10,
|
aether_request_timeout_secs: 10,
|
||||||
aether_connect_timeout_secs: 10,
|
aether_connect_timeout_secs: 10,
|
||||||
aether_pool_max_idle_per_host: 8,
|
aether_pool_max_idle_per_host: 8,
|
||||||
|
|||||||
@@ -61,11 +61,15 @@ pub struct RequestTiming {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ValidatedResolver {
|
pub struct ValidatedResolver {
|
||||||
dns_cache: Arc<DnsCache>,
|
dns_cache: Arc<DnsCache>,
|
||||||
|
allow_private: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ValidatedResolver {
|
impl ValidatedResolver {
|
||||||
pub fn new(dns_cache: Arc<DnsCache>) -> Self {
|
pub fn new(dns_cache: Arc<DnsCache>, allow_private: bool) -> Self {
|
||||||
Self { dns_cache }
|
Self {
|
||||||
|
dns_cache,
|
||||||
|
allow_private,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,6 +96,7 @@ impl Service<Name> for ValidatedResolver {
|
|||||||
|
|
||||||
fn call(&mut self, name: Name) -> Self::Future {
|
fn call(&mut self, name: Name) -> Self::Future {
|
||||||
let dns_cache = Arc::clone(&self.dns_cache);
|
let dns_cache = Arc::clone(&self.dns_cache);
|
||||||
|
let allow_private = self.allow_private;
|
||||||
let host = name.as_str().to_string();
|
let host = name.as_str().to_string();
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
if let Some(addrs) = dns_cache.get_by_host(&host).await {
|
if let Some(addrs) = dns_cache.get_by_host(&host).await {
|
||||||
@@ -100,9 +105,10 @@ impl Service<Name> for ValidatedResolver {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let resolved = target_filter::resolve_public_addrs(&host, 0, dns_cache.as_ref())
|
let resolved =
|
||||||
.await
|
target_filter::resolve_public_addrs(&host, 0, allow_private, dns_cache.as_ref())
|
||||||
.map_err(|err| io::Error::other(err.to_string()))?;
|
.await
|
||||||
|
.map_err(|err| io::Error::other(err.to_string()))?;
|
||||||
Ok(ValidatedAddrs {
|
Ok(ValidatedAddrs {
|
||||||
inner: resolved.into_iter(),
|
inner: resolved.into_iter(),
|
||||||
})
|
})
|
||||||
@@ -184,7 +190,10 @@ fn build_upstream_client_with_protocol(
|
|||||||
dns_cache: Arc<DnsCache>,
|
dns_cache: Arc<DnsCache>,
|
||||||
http1_only: bool,
|
http1_only: bool,
|
||||||
) -> UpstreamClient {
|
) -> UpstreamClient {
|
||||||
let mut http = HttpConnector::new_with_resolver(ValidatedResolver::new(dns_cache));
|
let mut http = HttpConnector::new_with_resolver(ValidatedResolver::new(
|
||||||
|
dns_cache,
|
||||||
|
config.allow_private_targets,
|
||||||
|
));
|
||||||
http.enforce_http(false);
|
http.enforce_http(false);
|
||||||
http.set_connect_timeout(Some(Duration::from_secs(
|
http.set_connect_timeout(Some(Duration::from_secs(
|
||||||
config.upstream_connect_timeout_secs,
|
config.upstream_connect_timeout_secs,
|
||||||
|
|||||||
Reference in New Issue
Block a user