diff --git a/core/src/net/host/address.rs b/core/src/net/host/address.rs index aa2db3d55..6e73cfc28 100644 --- a/core/src/net/host/address.rs +++ b/core/src/net/host/address.rs @@ -14,6 +14,7 @@ use crate::hostname::ServerHostname; use crate::net::acme::AcmeProvider; use crate::net::gateway::{CheckDnsParams, CheckPortParams, CheckPortRes, check_dns, check_port}; use crate::net::host::{HostApiKind, all_hosts}; +use crate::net::service_interface::HostnameMetadata; use crate::prelude::*; use crate::util::serde::{HandlerExtSerde, display_serializable}; @@ -246,8 +247,50 @@ pub async fn add_public_domain( .and_then(|a| a.port) .ok_or_else(|| Error::new(eyre!("no public address found for {fqdn} on port {internal_port}"), ErrorKind::NotFound))?; - // Disable the domain on all other bindings + // On the target binding, enable the WAN IPv4 and all + // public domains on the same gateway+port (no SNI without SSL). host.as_bindings_mut().mutate(|b| { + if let Some(bind) = b.get_mut(&internal_port) { + let non_ssl_port = bind.addresses.available.iter().find_map(|a| { + if a.ssl || !a.public || a.hostname != fqdn { + return None; + } + if let HostnameMetadata::PublicDomain { gateway: gw } = &a.metadata { + if *gw == gateway { + return a.port; + } + } + None + }); + if let Some(dp) = non_ssl_port { + for a in &bind.addresses.available { + if a.ssl || !a.public { + continue; + } + if let HostnameMetadata::Ipv4 { gateway: gw } = &a.metadata { + if *gw == gateway { + if let Some(sa) = a.to_socket_addr() { + if sa.port() == dp { + bind.addresses.enabled.insert(sa); + } + } + } + } + } + for a in &bind.addresses.available { + if a.ssl { + continue; + } + if let HostnameMetadata::PublicDomain { gateway: gw } = &a.metadata { + if *gw == gateway && a.port == Some(dp) { + bind.addresses.disabled.remove(&(a.hostname.clone(), dp)); + } + } + } + } + } + + // Disable the domain on all other bindings for (&port, bind) in b.iter_mut() { if port == internal_port { continue; diff --git a/core/src/net/host/binding.rs b/core/src/net/host/binding.rs index 0ee00bfe8..59ce1f902 100644 --- a/core/src/net/host/binding.rs +++ b/core/src/net/host/binding.rs @@ -13,7 +13,7 @@ use crate::context::{CliContext, RpcContext}; use crate::db::prelude::Map; use crate::net::forward::AvailablePorts; use crate::net::host::HostApiKind; -use crate::net::service_interface::HostnameInfo; +use crate::net::service_interface::{HostnameInfo, HostnameMetadata}; use crate::net::vhost::AlpnInfo; use crate::prelude::*; use crate::util::FromStrParser; @@ -344,6 +344,41 @@ pub async fn set_address_enabled( } else { bind.addresses.enabled.remove(&sa); } + // Non-SSL Ipv4: cascade to PublicDomains on same gateway + if !address.ssl { + if let HostnameMetadata::Ipv4 { gateway } = + &address.metadata + { + let port = sa.port(); + for a in &bind.addresses.available { + if a.ssl { + continue; + } + if let HostnameMetadata::PublicDomain { + gateway: gw, + } = &a.metadata + { + if gw == gateway + && a.port.unwrap_or(80) == port + { + let k = ( + a.hostname.clone(), + a.port.unwrap_or(80), + ); + if enabled { + bind.addresses + .disabled + .remove(&k); + } else { + bind.addresses + .disabled + .insert(k); + } + } + } + } + } + } } else { // Domains and private IPs: toggle via (host, port) in `disabled` set let port = address.port.unwrap_or(if address.ssl { 443 } else { 80 }); @@ -353,6 +388,61 @@ pub async fn set_address_enabled( } else { bind.addresses.disabled.insert(key); } + // Non-SSL PublicDomain: cascade to Ipv4 + other PublicDomains on same gateway + if !address.ssl { + if let HostnameMetadata::PublicDomain { gateway } = + &address.metadata + { + for a in &bind.addresses.available { + if a.ssl { + continue; + } + match &a.metadata { + HostnameMetadata::Ipv4 { gateway: gw } + if a.public + && gw == gateway => + { + if let Some(sa) = + a.to_socket_addr() + { + if sa.port() == port { + if enabled { + bind.addresses + .enabled + .insert(sa); + } else { + bind.addresses + .enabled + .remove(&sa); + } + } + } + } + HostnameMetadata::PublicDomain { + gateway: gw, + } if gw == gateway => { + let dp = a.port.unwrap_or(80); + if dp == port { + let k = ( + a.hostname.clone(), + dp, + ); + if enabled { + bind.addresses + .disabled + .remove(&k); + } else { + bind.addresses + .disabled + .insert(k); + } + } + } + _ => {} + } + } + } + } } Ok(()) })