mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 04:01:58 +00:00
enabling support for wireguard and firewall (#2713)
* wip: enabling support for wireguard and firewall * wip * wip * wip * wip * wip * implement some things * fix warning * wip * alpha.23 * misc fixes * remove ufw since no longer required * remove debug info * add cli bindings * debugging * fixes * individualized acme and privacy settings for domains and bindings * sdk version bump * migration * misc fixes * refactor Host::update * debug info * refactor webserver * misc fixes * misc fixes * refactor port forwarding * recheck interfaces every 5 min if no dbus event * misc fixes and cleanup * misc fixes
This commit is contained in:
@@ -5,6 +5,7 @@ use std::sync::{Arc, Weak};
|
||||
use color_eyre::eyre::eyre;
|
||||
use imbl::OrdMap;
|
||||
use imbl_value::InternedString;
|
||||
use ipnet::IpNet;
|
||||
use models::{HostId, OptionExt, PackageId};
|
||||
use torut::onion::{OnionAddressV3, TorSecretKeyV3};
|
||||
use tracing::instrument;
|
||||
@@ -15,11 +16,13 @@ use crate::hostname::Hostname;
|
||||
use crate::net::dns::DnsController;
|
||||
use crate::net::forward::LanPortForwardController;
|
||||
use crate::net::host::address::HostAddress;
|
||||
use crate::net::host::binding::{AddSslOptions, BindId, BindOptions, LanInfo};
|
||||
use crate::net::host::binding::{BindId, BindOptions};
|
||||
use crate::net::host::{host_for, Host, HostKind, Hosts};
|
||||
use crate::net::network_interface::NetworkInterfaceController;
|
||||
use crate::net::service_interface::{HostnameInfo, IpHostname, OnionHostname};
|
||||
use crate::net::tor::TorController;
|
||||
use crate::net::vhost::{AlpnInfo, VHostController};
|
||||
use crate::net::utils::ipv6_is_local;
|
||||
use crate::net::vhost::{AlpnInfo, TargetInfo, VHostController};
|
||||
use crate::prelude::*;
|
||||
use crate::util::serde::MaybeUtf8String;
|
||||
use crate::HOST_IP;
|
||||
@@ -28,6 +31,7 @@ pub struct PreInitNetController {
|
||||
pub db: TypedPatchDb<Database>,
|
||||
tor: TorController,
|
||||
vhost: VHostController,
|
||||
pub net_iface: Arc<NetworkInterfaceController>,
|
||||
os_bindings: Vec<Arc<()>>,
|
||||
server_hostnames: Vec<Option<InternedString>>,
|
||||
}
|
||||
@@ -40,10 +44,12 @@ impl PreInitNetController {
|
||||
hostname: &Hostname,
|
||||
os_tor_key: TorSecretKeyV3,
|
||||
) -> Result<Self, Error> {
|
||||
let net_iface = Arc::new(NetworkInterfaceController::new(db.clone()));
|
||||
let mut res = Self {
|
||||
db: db.clone(),
|
||||
tor: TorController::new(tor_control, tor_socks),
|
||||
vhost: VHostController::new(db),
|
||||
vhost: VHostController::new(db, net_iface.clone()),
|
||||
net_iface,
|
||||
os_bindings: Vec::new(),
|
||||
server_hostnames: Vec::new(),
|
||||
};
|
||||
@@ -56,11 +62,6 @@ impl PreInitNetController {
|
||||
hostname: &Hostname,
|
||||
tor_key: TorSecretKeyV3,
|
||||
) -> Result<(), Error> {
|
||||
let alpn = Err(AlpnInfo::Specified(vec![
|
||||
MaybeUtf8String("http/1.1".into()),
|
||||
MaybeUtf8String("h2".into()),
|
||||
]));
|
||||
|
||||
self.server_hostnames = vec![
|
||||
// LAN IP
|
||||
None,
|
||||
@@ -74,27 +75,29 @@ impl PreInitNetController {
|
||||
Some(hostname.local_domain_name()),
|
||||
];
|
||||
|
||||
let vhost_target = TargetInfo {
|
||||
public: false,
|
||||
acme: None,
|
||||
addr: ([127, 0, 0, 1], 80).into(),
|
||||
connect_ssl: Err(AlpnInfo::Specified(vec![
|
||||
MaybeUtf8String("http/1.1".into()),
|
||||
MaybeUtf8String("h2".into()),
|
||||
])),
|
||||
};
|
||||
|
||||
for hostname in self.server_hostnames.iter().cloned() {
|
||||
self.os_bindings.push(
|
||||
self.vhost
|
||||
.add(hostname, 443, ([127, 0, 0, 1], 80).into(), alpn.clone())
|
||||
.await?,
|
||||
);
|
||||
self.os_bindings
|
||||
.push(self.vhost.add(hostname, 443, vhost_target.clone())?);
|
||||
}
|
||||
|
||||
// Tor
|
||||
self.os_bindings.push(
|
||||
self.vhost
|
||||
.add(
|
||||
Some(InternedString::from_display(
|
||||
&tor_key.public().get_onion_address(),
|
||||
)),
|
||||
443,
|
||||
([127, 0, 0, 1], 80).into(),
|
||||
alpn.clone(),
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
self.os_bindings.push(self.vhost.add(
|
||||
Some(InternedString::from_display(
|
||||
&tor_key.public().get_onion_address(),
|
||||
)),
|
||||
443,
|
||||
vhost_target,
|
||||
)?);
|
||||
self.os_bindings.extend(
|
||||
self.tor
|
||||
.add(
|
||||
@@ -115,6 +118,7 @@ pub struct NetController {
|
||||
db: TypedPatchDb<Database>,
|
||||
pub(super) tor: TorController,
|
||||
pub(super) vhost: VHostController,
|
||||
pub net_iface: Arc<NetworkInterfaceController>,
|
||||
pub(super) dns: DnsController,
|
||||
pub(super) forward: LanPortForwardController,
|
||||
pub(super) os_bindings: Vec<Arc<()>>,
|
||||
@@ -127,6 +131,7 @@ impl NetController {
|
||||
db,
|
||||
tor,
|
||||
vhost,
|
||||
net_iface,
|
||||
os_bindings,
|
||||
server_hostnames,
|
||||
}: PreInitNetController,
|
||||
@@ -137,7 +142,8 @@ impl NetController {
|
||||
tor,
|
||||
vhost,
|
||||
dns: DnsController::init(dns_bind).await?,
|
||||
forward: LanPortForwardController::new(),
|
||||
forward: LanPortForwardController::new(net_iface.subscribe()),
|
||||
net_iface,
|
||||
os_bindings,
|
||||
server_hostnames,
|
||||
};
|
||||
@@ -169,15 +175,8 @@ impl NetController {
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct HostBinds {
|
||||
lan: BTreeMap<
|
||||
u16,
|
||||
(
|
||||
LanInfo,
|
||||
Option<AddSslOptions>,
|
||||
BTreeSet<InternedString>,
|
||||
Vec<Arc<()>>,
|
||||
),
|
||||
>,
|
||||
forwards: BTreeMap<u16, (SocketAddr, bool, Arc<()>)>,
|
||||
vhosts: BTreeMap<(Option<InternedString>, u16), (TargetInfo, Arc<()>)>,
|
||||
tor: BTreeMap<OnionAddressV3, (OrdMap<u16, SocketAddr>, Vec<Arc<()>>)>,
|
||||
}
|
||||
|
||||
@@ -206,7 +205,7 @@ impl NetService {
|
||||
internal_port: u16,
|
||||
options: BindOptions,
|
||||
) -> Result<(), Error> {
|
||||
dbg!("bind", &kind, &id, internal_port, &options);
|
||||
crate::dbg!("bind", &kind, &id, internal_port, &options);
|
||||
let pkg_id = &self.id;
|
||||
let host = self
|
||||
.net_controller()?
|
||||
@@ -263,134 +262,161 @@ impl NetService {
|
||||
|
||||
pub async fn update(&mut self, id: HostId, host: Host) -> Result<(), Error> {
|
||||
let ctrl = self.net_controller()?;
|
||||
let mut hostname_info = BTreeMap::new();
|
||||
let mut forwards: BTreeMap<u16, (SocketAddr, bool)> = BTreeMap::new();
|
||||
let mut vhosts: BTreeMap<(Option<InternedString>, u16), TargetInfo> = BTreeMap::new();
|
||||
let mut tor: BTreeMap<OnionAddressV3, (TorSecretKeyV3, OrdMap<u16, SocketAddr>)> =
|
||||
BTreeMap::new();
|
||||
let mut hostname_info: BTreeMap<u16, Vec<HostnameInfo>> = BTreeMap::new();
|
||||
let binds = self.binds.entry(id.clone()).or_default();
|
||||
|
||||
let peek = ctrl.db.peek().await;
|
||||
|
||||
// LAN
|
||||
let server_info = peek.as_public().as_server_info();
|
||||
let ip_info = server_info.as_ip_info().de()?;
|
||||
let net_ifaces = server_info.as_network_interfaces().de()?;
|
||||
let hostname = server_info.as_hostname().de()?;
|
||||
for (port, bind) in &host.bindings {
|
||||
if !bind.enabled {
|
||||
continue;
|
||||
}
|
||||
let old_lan_bind = binds.lan.remove(port);
|
||||
let lan_bind = old_lan_bind
|
||||
.as_ref()
|
||||
.filter(|(external, ssl, _, _)| {
|
||||
ssl == &bind.options.add_ssl && bind.lan == *external
|
||||
})
|
||||
.cloned(); // only keep existing binding if relevant details match
|
||||
if bind.lan.assigned_port.is_some() || bind.lan.assigned_ssl_port.is_some() {
|
||||
let new_lan_bind = if let Some(b) = lan_bind {
|
||||
b
|
||||
} else {
|
||||
let mut rcs = Vec::with_capacity(2 + host.addresses.len());
|
||||
let mut hostnames = BTreeSet::new();
|
||||
if let Some(ssl) = &bind.options.add_ssl {
|
||||
let external = bind
|
||||
.lan
|
||||
.assigned_ssl_port
|
||||
.or_not_found("assigned ssl port")?;
|
||||
let target = (self.ip, *port).into();
|
||||
let connect_ssl = if let Some(alpn) = ssl.alpn.clone() {
|
||||
Err(alpn)
|
||||
if bind.net.assigned_port.is_some() || bind.net.assigned_ssl_port.is_some() {
|
||||
let mut hostnames = BTreeSet::new();
|
||||
if let Some(ssl) = &bind.options.add_ssl {
|
||||
let external = bind
|
||||
.net
|
||||
.assigned_ssl_port
|
||||
.or_not_found("assigned ssl port")?;
|
||||
let addr = (self.ip, *port).into();
|
||||
let connect_ssl = if let Some(alpn) = ssl.alpn.clone() {
|
||||
Err(alpn)
|
||||
} else {
|
||||
if bind.options.secure.as_ref().map_or(false, |s| s.ssl) {
|
||||
Ok(())
|
||||
} else {
|
||||
if bind.options.secure.as_ref().map_or(false, |s| s.ssl) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(AlpnInfo::Reflect)
|
||||
}
|
||||
};
|
||||
for hostname in ctrl.server_hostnames.iter().cloned() {
|
||||
rcs.push(
|
||||
ctrl.vhost
|
||||
.add(hostname, external, target, connect_ssl.clone())
|
||||
.await?,
|
||||
);
|
||||
Err(AlpnInfo::Reflect)
|
||||
}
|
||||
for address in host.addresses() {
|
||||
match address {
|
||||
HostAddress::Onion { address } => {
|
||||
let hostname = InternedString::from_display(address);
|
||||
if hostnames.insert(hostname.clone()) {
|
||||
rcs.push(
|
||||
ctrl.vhost
|
||||
.add(
|
||||
Some(hostname),
|
||||
external,
|
||||
target,
|
||||
connect_ssl.clone(),
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
}
|
||||
};
|
||||
for hostname in ctrl.server_hostnames.iter().cloned() {
|
||||
vhosts.insert(
|
||||
(hostname, external),
|
||||
TargetInfo {
|
||||
public: bind.net.public,
|
||||
acme: None,
|
||||
addr,
|
||||
connect_ssl: connect_ssl.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
for address in host.addresses() {
|
||||
match address {
|
||||
HostAddress::Onion { address } => {
|
||||
let hostname = InternedString::from_display(&address);
|
||||
if hostnames.insert(hostname.clone()) {
|
||||
vhosts.insert(
|
||||
(Some(hostname), external),
|
||||
TargetInfo {
|
||||
public: false,
|
||||
acme: None,
|
||||
addr,
|
||||
connect_ssl: connect_ssl.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
HostAddress::Domain { address } => {
|
||||
if hostnames.insert(address.clone()) {
|
||||
let address = Some(address.clone());
|
||||
rcs.push(
|
||||
ctrl.vhost
|
||||
.add(
|
||||
address.clone(),
|
||||
external,
|
||||
target,
|
||||
connect_ssl.clone(),
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
if ssl.preferred_external_port == 443 {
|
||||
rcs.push(
|
||||
ctrl.vhost
|
||||
.add(
|
||||
address.clone(),
|
||||
5443,
|
||||
target,
|
||||
connect_ssl.clone(),
|
||||
)
|
||||
.await?,
|
||||
}
|
||||
HostAddress::Domain {
|
||||
address,
|
||||
public,
|
||||
acme,
|
||||
} => {
|
||||
if hostnames.insert(address.clone()) {
|
||||
let address = Some(address.clone());
|
||||
if ssl.preferred_external_port == 443 {
|
||||
if public && bind.net.public {
|
||||
vhosts.insert(
|
||||
(address.clone(), 5443),
|
||||
TargetInfo {
|
||||
public: false,
|
||||
acme: acme.clone(),
|
||||
addr,
|
||||
connect_ssl: connect_ssl.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
vhosts.insert(
|
||||
(address.clone(), 443),
|
||||
TargetInfo {
|
||||
public: public && bind.net.public,
|
||||
acme,
|
||||
addr,
|
||||
connect_ssl: connect_ssl.clone(),
|
||||
},
|
||||
);
|
||||
} else {
|
||||
vhosts.insert(
|
||||
(address.clone(), external),
|
||||
TargetInfo {
|
||||
public: public && bind.net.public,
|
||||
acme,
|
||||
addr,
|
||||
connect_ssl: connect_ssl.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(security) = bind.options.secure {
|
||||
if bind.options.add_ssl.is_some() && security.ssl {
|
||||
// doesn't make sense to have 2 listening ports, both with ssl
|
||||
} else {
|
||||
let external =
|
||||
bind.lan.assigned_port.or_not_found("assigned lan port")?;
|
||||
rcs.push(ctrl.forward.add(external, (self.ip, *port).into()).await?);
|
||||
}
|
||||
}
|
||||
if let Some(security) = bind.options.secure {
|
||||
if bind.options.add_ssl.is_some() && security.ssl {
|
||||
// doesn't make sense to have 2 listening ports, both with ssl
|
||||
} else {
|
||||
let external = bind.net.assigned_port.or_not_found("assigned lan port")?;
|
||||
forwards.insert(external, ((self.ip, *port).into(), bind.net.public));
|
||||
}
|
||||
(bind.lan, bind.options.add_ssl.clone(), hostnames, rcs)
|
||||
};
|
||||
}
|
||||
let mut bind_hostname_info: Vec<HostnameInfo> =
|
||||
hostname_info.remove(port).unwrap_or_default();
|
||||
for (interface, ip_info) in &ip_info {
|
||||
bind_hostname_info.push(HostnameInfo::Ip {
|
||||
network_interface_id: interface.clone(),
|
||||
public: false,
|
||||
hostname: IpHostname::Local {
|
||||
value: InternedString::from_display(&{
|
||||
let hostname = &hostname;
|
||||
lazy_format!("{hostname}.local")
|
||||
}),
|
||||
port: new_lan_bind.0.assigned_port,
|
||||
ssl_port: new_lan_bind.0.assigned_ssl_port,
|
||||
},
|
||||
});
|
||||
for (interface, public, ip_info) in
|
||||
net_ifaces.iter().filter_map(|(interface, info)| {
|
||||
if let Some(ip_info) = &info.ip_info {
|
||||
Some((interface, info.public(), ip_info))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
{
|
||||
if !public {
|
||||
bind_hostname_info.push(HostnameInfo::Ip {
|
||||
network_interface_id: interface.clone(),
|
||||
public: false,
|
||||
hostname: IpHostname::Local {
|
||||
value: InternedString::from_display(&{
|
||||
let hostname = &hostname;
|
||||
lazy_format!("{hostname}.local")
|
||||
}),
|
||||
port: bind.net.assigned_port,
|
||||
ssl_port: bind.net.assigned_ssl_port,
|
||||
},
|
||||
});
|
||||
}
|
||||
for address in host.addresses() {
|
||||
if let HostAddress::Domain { address } = address {
|
||||
if let Some(ssl) = &new_lan_bind.1 {
|
||||
if ssl.preferred_external_port == 443 {
|
||||
if let HostAddress::Domain {
|
||||
address,
|
||||
public: domain_public,
|
||||
..
|
||||
} = address
|
||||
{
|
||||
if !public || (domain_public && bind.net.public) {
|
||||
if bind
|
||||
.options
|
||||
.add_ssl
|
||||
.as_ref()
|
||||
.map_or(false, |ssl| ssl.preferred_external_port == 443)
|
||||
{
|
||||
bind_hostname_info.push(HostnameInfo::Ip {
|
||||
network_interface_id: interface.clone(),
|
||||
public: false,
|
||||
public: public && domain_public && bind.net.public, // TODO: check if port forward is active
|
||||
hostname: IpHostname::Domain {
|
||||
domain: address.clone(),
|
||||
subdomain: None,
|
||||
@@ -398,71 +424,65 @@ impl NetService {
|
||||
ssl_port: Some(443),
|
||||
},
|
||||
});
|
||||
} else {
|
||||
bind_hostname_info.push(HostnameInfo::Ip {
|
||||
network_interface_id: interface.clone(),
|
||||
public,
|
||||
hostname: IpHostname::Domain {
|
||||
domain: address.clone(),
|
||||
subdomain: None,
|
||||
port: bind.net.assigned_port,
|
||||
ssl_port: bind.net.assigned_ssl_port,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(ipv4) = ip_info.ipv4 {
|
||||
bind_hostname_info.push(HostnameInfo::Ip {
|
||||
network_interface_id: interface.clone(),
|
||||
public: false,
|
||||
hostname: IpHostname::Ipv4 {
|
||||
value: ipv4,
|
||||
port: new_lan_bind.0.assigned_port,
|
||||
ssl_port: new_lan_bind.0.assigned_ssl_port,
|
||||
},
|
||||
});
|
||||
}
|
||||
if let Some(ipv6) = ip_info.ipv6 {
|
||||
bind_hostname_info.push(HostnameInfo::Ip {
|
||||
network_interface_id: interface.clone(),
|
||||
public: false,
|
||||
hostname: IpHostname::Ipv6 {
|
||||
value: ipv6,
|
||||
port: new_lan_bind.0.assigned_port,
|
||||
ssl_port: new_lan_bind.0.assigned_ssl_port,
|
||||
},
|
||||
});
|
||||
if !public || bind.net.public {
|
||||
if let Some(wan_ip) = ip_info.wan_ip.filter(|_| public) {
|
||||
bind_hostname_info.push(HostnameInfo::Ip {
|
||||
network_interface_id: interface.clone(),
|
||||
public,
|
||||
hostname: IpHostname::Ipv4 {
|
||||
value: wan_ip,
|
||||
port: bind.net.assigned_port,
|
||||
ssl_port: bind.net.assigned_ssl_port,
|
||||
},
|
||||
});
|
||||
}
|
||||
for ipnet in &ip_info.subnets {
|
||||
match ipnet {
|
||||
IpNet::V4(net) => {
|
||||
if !public {
|
||||
bind_hostname_info.push(HostnameInfo::Ip {
|
||||
network_interface_id: interface.clone(),
|
||||
public,
|
||||
hostname: IpHostname::Ipv4 {
|
||||
value: net.addr(),
|
||||
port: bind.net.assigned_port,
|
||||
ssl_port: bind.net.assigned_ssl_port,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
IpNet::V6(net) => {
|
||||
bind_hostname_info.push(HostnameInfo::Ip {
|
||||
network_interface_id: interface.clone(),
|
||||
public: public && !ipv6_is_local(net.addr()),
|
||||
hostname: IpHostname::Ipv6 {
|
||||
value: net.addr(),
|
||||
scope_id: ip_info.scope_id,
|
||||
port: bind.net.assigned_port,
|
||||
ssl_port: bind.net.assigned_ssl_port,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
hostname_info.insert(*port, bind_hostname_info);
|
||||
binds.lan.insert(*port, new_lan_bind);
|
||||
}
|
||||
if let Some((lan, _, hostnames, _)) = old_lan_bind {
|
||||
if let Some(external) = lan.assigned_ssl_port {
|
||||
for hostname in ctrl.server_hostnames.iter().cloned() {
|
||||
ctrl.vhost.gc(hostname, external).await?;
|
||||
}
|
||||
for hostname in hostnames {
|
||||
ctrl.vhost.gc(Some(hostname), external).await?;
|
||||
}
|
||||
}
|
||||
if let Some(external) = lan.assigned_port {
|
||||
ctrl.forward.gc(external).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut removed = BTreeSet::new();
|
||||
binds.lan.retain(|internal, (external, _, hostnames, _)| {
|
||||
if host.bindings.get(internal).map_or(false, |b| b.enabled) {
|
||||
true
|
||||
} else {
|
||||
removed.insert((*external, std::mem::take(hostnames)));
|
||||
|
||||
false
|
||||
}
|
||||
});
|
||||
for (lan, hostnames) in removed {
|
||||
if let Some(external) = lan.assigned_ssl_port {
|
||||
for hostname in ctrl.server_hostnames.iter().cloned() {
|
||||
ctrl.vhost.gc(hostname, external).await?;
|
||||
}
|
||||
for hostname in hostnames {
|
||||
ctrl.vhost.gc(Some(hostname), external).await?;
|
||||
}
|
||||
}
|
||||
if let Some(external) = lan.assigned_port {
|
||||
ctrl.forward.gc(external).await?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -481,7 +501,7 @@ impl NetService {
|
||||
SocketAddr::from((self.ip, *internal)),
|
||||
);
|
||||
if let (Some(ssl), Some(ssl_internal)) =
|
||||
(&info.options.add_ssl, info.lan.assigned_ssl_port)
|
||||
(&info.options.add_ssl, info.net.assigned_ssl_port)
|
||||
{
|
||||
tor_binds.insert(
|
||||
ssl.preferred_external_port,
|
||||
@@ -506,31 +526,13 @@ impl NetService {
|
||||
}
|
||||
}
|
||||
|
||||
let mut keep_tor_addrs = BTreeSet::new();
|
||||
for tor_addr in host.addresses().filter_map(|a| {
|
||||
if let HostAddress::Onion { address } = a {
|
||||
Some(address)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) {
|
||||
keep_tor_addrs.insert(tor_addr);
|
||||
let old_tor_bind = binds.tor.remove(tor_addr);
|
||||
let tor_bind = old_tor_bind.filter(|(ports, _)| ports == &tor_binds);
|
||||
let new_tor_bind = if let Some(tor_bind) = tor_bind {
|
||||
tor_bind
|
||||
} else {
|
||||
let key = peek
|
||||
.as_private()
|
||||
.as_key_store()
|
||||
.as_onion()
|
||||
.get_key(tor_addr)?;
|
||||
let rcs = ctrl
|
||||
.tor
|
||||
.add(key, tor_binds.clone().into_iter().collect())
|
||||
.await?;
|
||||
(tor_binds.clone(), rcs)
|
||||
};
|
||||
for tor_addr in host.onions.iter() {
|
||||
let key = peek
|
||||
.as_private()
|
||||
.as_key_store()
|
||||
.as_onion()
|
||||
.get_key(tor_addr)?;
|
||||
tor.insert(key.public().get_onion_address(), (key, tor_binds.clone()));
|
||||
for (internal, ports) in &tor_hostname_ports {
|
||||
let mut bind_hostname_info = hostname_info.remove(internal).unwrap_or_default();
|
||||
bind_hostname_info.push(HostnameInfo::Onion {
|
||||
@@ -542,16 +544,91 @@ impl NetService {
|
||||
});
|
||||
hostname_info.insert(*internal, bind_hostname_info);
|
||||
}
|
||||
binds.tor.insert(tor_addr.clone(), new_tor_bind);
|
||||
}
|
||||
for addr in binds.tor.keys() {
|
||||
if !keep_tor_addrs.contains(addr) {
|
||||
ctrl.tor.gc(Some(addr.clone()), None).await?;
|
||||
|
||||
let all = binds
|
||||
.forwards
|
||||
.keys()
|
||||
.chain(forwards.keys())
|
||||
.copied()
|
||||
.collect::<BTreeSet<_>>();
|
||||
for external in all {
|
||||
let mut prev = binds.forwards.remove(&external);
|
||||
if let Some((internal, public)) = forwards.remove(&external) {
|
||||
prev = prev.filter(|(i, p, _)| i == &internal && *p == public);
|
||||
binds.forwards.insert(
|
||||
external,
|
||||
if let Some(prev) = prev {
|
||||
prev
|
||||
} else {
|
||||
(
|
||||
internal,
|
||||
public,
|
||||
ctrl.forward.add(external, public, internal).await?,
|
||||
)
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
ctrl.forward.gc().await?;
|
||||
|
||||
let all = binds
|
||||
.vhosts
|
||||
.keys()
|
||||
.chain(vhosts.keys())
|
||||
.cloned()
|
||||
.collect::<BTreeSet<_>>();
|
||||
for key in all {
|
||||
let mut prev = binds.vhosts.remove(&key);
|
||||
if let Some(target) = vhosts.remove(&key) {
|
||||
prev = prev.filter(|(t, _)| t == &target);
|
||||
binds.vhosts.insert(
|
||||
key.clone(),
|
||||
if let Some(prev) = prev {
|
||||
prev
|
||||
} else {
|
||||
(target.clone(), ctrl.vhost.add(key.0, key.1, target)?)
|
||||
},
|
||||
);
|
||||
} else {
|
||||
if let Some((_, rc)) = prev {
|
||||
drop(rc);
|
||||
ctrl.vhost.gc(key.0, key.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.net_controller()?
|
||||
.db
|
||||
let all = binds
|
||||
.tor
|
||||
.keys()
|
||||
.chain(tor.keys())
|
||||
.cloned()
|
||||
.collect::<BTreeSet<_>>();
|
||||
for onion in all {
|
||||
let mut prev = binds.tor.remove(&onion);
|
||||
if let Some((key, tor_binds)) = tor.remove(&onion) {
|
||||
prev = prev.filter(|(b, _)| b == &tor_binds);
|
||||
binds.tor.insert(
|
||||
onion,
|
||||
if let Some(prev) = prev {
|
||||
prev
|
||||
} else {
|
||||
let rcs = ctrl
|
||||
.tor
|
||||
.add(key, tor_binds.iter().map(|(k, v)| (*k, *v)).collect())
|
||||
.await?;
|
||||
(tor_binds, rcs)
|
||||
},
|
||||
);
|
||||
} else {
|
||||
if let Some((_, rc)) = prev {
|
||||
drop(rc);
|
||||
ctrl.tor.gc(Some(onion), None).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctrl.db
|
||||
.mutate(|db| {
|
||||
host_for(db, &self.id, &id, host.kind)?
|
||||
.as_hostname_info_mut()
|
||||
@@ -579,29 +656,6 @@ impl NetService {
|
||||
pub fn get_ip(&self) -> Ipv4Addr {
|
||||
self.ip
|
||||
}
|
||||
|
||||
pub fn get_lan_port(&self, host_id: HostId, internal_port: u16) -> Result<LanInfo, Error> {
|
||||
let host_id_binds = self.binds.get_key_value(&host_id);
|
||||
match host_id_binds {
|
||||
Some((_, binds)) => {
|
||||
if let Some((lan, _, _, _)) = binds.lan.get(&internal_port) {
|
||||
Ok(*lan)
|
||||
} else {
|
||||
Err(Error::new(
|
||||
eyre!(
|
||||
"Internal Port {} not found in NetService binds",
|
||||
internal_port
|
||||
),
|
||||
crate::ErrorKind::NotFound,
|
||||
))
|
||||
}
|
||||
}
|
||||
None => Err(Error::new(
|
||||
eyre!("HostID {} not found in NetService binds", host_id),
|
||||
crate::ErrorKind::NotFound,
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for NetService {
|
||||
|
||||
Reference in New Issue
Block a user