mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
rename frontend to web and update contributing guide (#2509)
* rename frontend to web and update contributing guide * rename this time * fix build * restructure rust code * update documentation * update descriptions * Update CONTRIBUTING.md Co-authored-by: J H <2364004+Blu-J@users.noreply.github.com> --------- Co-authored-by: Aiden McClelland <me@drbonez.dev> Co-authored-by: Aiden McClelland <3732071+dr-bonez@users.noreply.github.com> Co-authored-by: J H <2364004+Blu-J@users.noreply.github.com>
This commit is contained in:
369
core/startos/src/net/net_controller.rs
Normal file
369
core/startos/src/net/net_controller.rs
Normal file
@@ -0,0 +1,369 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
use color_eyre::eyre::eyre;
|
||||
use models::InterfaceId;
|
||||
use sqlx::PgExecutor;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::error::ErrorCollection;
|
||||
use crate::hostname::Hostname;
|
||||
use crate::net::dns::DnsController;
|
||||
use crate::net::keys::Key;
|
||||
use crate::net::mdns::MdnsController;
|
||||
use crate::net::ssl::{export_cert, export_key, SslManager};
|
||||
use crate::net::tor::TorController;
|
||||
use crate::net::vhost::{AlpnInfo, VHostController};
|
||||
use crate::s9pk::manifest::PackageId;
|
||||
use crate::volume::cert_dir;
|
||||
use crate::{Error, HOST_IP};
|
||||
|
||||
pub struct NetController {
|
||||
pub(super) tor: TorController,
|
||||
pub(super) mdns: MdnsController,
|
||||
pub(super) vhost: VHostController,
|
||||
pub(super) dns: DnsController,
|
||||
pub(super) ssl: Arc<SslManager>,
|
||||
pub(super) os_bindings: Vec<Arc<()>>,
|
||||
}
|
||||
|
||||
impl NetController {
|
||||
#[instrument(skip_all)]
|
||||
pub async fn init(
|
||||
tor_control: SocketAddr,
|
||||
tor_socks: SocketAddr,
|
||||
dns_bind: &[SocketAddr],
|
||||
ssl: SslManager,
|
||||
hostname: &Hostname,
|
||||
os_key: &Key,
|
||||
) -> Result<Self, Error> {
|
||||
let ssl = Arc::new(ssl);
|
||||
let mut res = Self {
|
||||
tor: TorController::new(tor_control, tor_socks),
|
||||
mdns: MdnsController::init().await?,
|
||||
vhost: VHostController::new(ssl.clone()),
|
||||
dns: DnsController::init(dns_bind).await?,
|
||||
ssl,
|
||||
os_bindings: Vec::new(),
|
||||
};
|
||||
res.add_os_bindings(hostname, os_key).await?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
async fn add_os_bindings(&mut self, hostname: &Hostname, key: &Key) -> Result<(), Error> {
|
||||
let alpn = Err(AlpnInfo::Specified(vec!["http/1.1".into(), "h2".into()]));
|
||||
|
||||
// Internal DNS
|
||||
self.vhost
|
||||
.add(
|
||||
key.clone(),
|
||||
Some("embassy".into()),
|
||||
443,
|
||||
([127, 0, 0, 1], 80).into(),
|
||||
alpn.clone(),
|
||||
)
|
||||
.await?;
|
||||
self.os_bindings
|
||||
.push(self.dns.add(None, HOST_IP.into()).await?);
|
||||
|
||||
// LAN IP
|
||||
self.os_bindings.push(
|
||||
self.vhost
|
||||
.add(
|
||||
key.clone(),
|
||||
None,
|
||||
443,
|
||||
([127, 0, 0, 1], 80).into(),
|
||||
alpn.clone(),
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
|
||||
// localhost
|
||||
self.os_bindings.push(
|
||||
self.vhost
|
||||
.add(
|
||||
key.clone(),
|
||||
Some("localhost".into()),
|
||||
443,
|
||||
([127, 0, 0, 1], 80).into(),
|
||||
alpn.clone(),
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
self.os_bindings.push(
|
||||
self.vhost
|
||||
.add(
|
||||
key.clone(),
|
||||
Some(hostname.no_dot_host_name()),
|
||||
443,
|
||||
([127, 0, 0, 1], 80).into(),
|
||||
alpn.clone(),
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
|
||||
// LAN mDNS
|
||||
self.os_bindings.push(
|
||||
self.vhost
|
||||
.add(
|
||||
key.clone(),
|
||||
Some(hostname.local_domain_name()),
|
||||
443,
|
||||
([127, 0, 0, 1], 80).into(),
|
||||
alpn.clone(),
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
|
||||
// Tor (http)
|
||||
self.os_bindings.push(
|
||||
self.tor
|
||||
.add(key.tor_key(), 80, ([127, 0, 0, 1], 80).into())
|
||||
.await?,
|
||||
);
|
||||
|
||||
// Tor (https)
|
||||
self.os_bindings.push(
|
||||
self.vhost
|
||||
.add(
|
||||
key.clone(),
|
||||
Some(key.tor_address().to_string()),
|
||||
443,
|
||||
([127, 0, 0, 1], 80).into(),
|
||||
alpn.clone(),
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
self.os_bindings.push(
|
||||
self.tor
|
||||
.add(key.tor_key(), 443, ([127, 0, 0, 1], 443).into())
|
||||
.await?,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub async fn create_service(
|
||||
self: &Arc<Self>,
|
||||
package: PackageId,
|
||||
ip: Ipv4Addr,
|
||||
) -> Result<NetService, Error> {
|
||||
let dns = self.dns.add(Some(package.clone()), ip).await?;
|
||||
|
||||
Ok(NetService {
|
||||
shutdown: false,
|
||||
id: package,
|
||||
ip,
|
||||
dns,
|
||||
controller: Arc::downgrade(self),
|
||||
tor: BTreeMap::new(),
|
||||
lan: BTreeMap::new(),
|
||||
})
|
||||
}
|
||||
|
||||
async fn add_tor(
|
||||
&self,
|
||||
key: &Key,
|
||||
external: u16,
|
||||
target: SocketAddr,
|
||||
) -> Result<Vec<Arc<()>>, Error> {
|
||||
let mut rcs = Vec::with_capacity(1);
|
||||
rcs.push(self.tor.add(key.tor_key(), external, target).await?);
|
||||
Ok(rcs)
|
||||
}
|
||||
|
||||
async fn remove_tor(&self, key: &Key, external: u16, rcs: Vec<Arc<()>>) -> Result<(), Error> {
|
||||
drop(rcs);
|
||||
self.tor.gc(Some(key.tor_key()), Some(external)).await
|
||||
}
|
||||
|
||||
async fn add_lan(
|
||||
&self,
|
||||
key: Key,
|
||||
external: u16,
|
||||
target: SocketAddr,
|
||||
connect_ssl: Result<(), AlpnInfo>,
|
||||
) -> Result<Vec<Arc<()>>, Error> {
|
||||
let mut rcs = Vec::with_capacity(2);
|
||||
rcs.push(
|
||||
self.vhost
|
||||
.add(
|
||||
key.clone(),
|
||||
Some(key.local_address()),
|
||||
external,
|
||||
target.into(),
|
||||
connect_ssl,
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
rcs.push(self.mdns.add(key.base_address()).await?);
|
||||
Ok(rcs)
|
||||
}
|
||||
|
||||
async fn remove_lan(&self, key: &Key, external: u16, rcs: Vec<Arc<()>>) -> Result<(), Error> {
|
||||
drop(rcs);
|
||||
self.mdns.gc(key.base_address()).await?;
|
||||
self.vhost.gc(Some(key.local_address()), external).await
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NetService {
|
||||
shutdown: bool,
|
||||
id: PackageId,
|
||||
ip: Ipv4Addr,
|
||||
dns: Arc<()>,
|
||||
controller: Weak<NetController>,
|
||||
tor: BTreeMap<(InterfaceId, u16), (Key, Vec<Arc<()>>)>,
|
||||
lan: BTreeMap<(InterfaceId, u16), (Key, Vec<Arc<()>>)>,
|
||||
}
|
||||
impl NetService {
|
||||
fn net_controller(&self) -> Result<Arc<NetController>, Error> {
|
||||
Weak::upgrade(&self.controller).ok_or_else(|| {
|
||||
Error::new(
|
||||
eyre!("NetController is shutdown"),
|
||||
crate::ErrorKind::Network,
|
||||
)
|
||||
})
|
||||
}
|
||||
pub async fn add_tor<Ex>(
|
||||
&mut self,
|
||||
secrets: &mut Ex,
|
||||
id: InterfaceId,
|
||||
external: u16,
|
||||
internal: u16,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
for<'a> &'a mut Ex: PgExecutor<'a>,
|
||||
{
|
||||
let key = Key::for_interface(secrets, Some((self.id.clone(), id.clone()))).await?;
|
||||
let ctrl = self.net_controller()?;
|
||||
let tor_idx = (id, external);
|
||||
let mut tor = self
|
||||
.tor
|
||||
.remove(&tor_idx)
|
||||
.unwrap_or_else(|| (key.clone(), Vec::new()));
|
||||
tor.1.append(
|
||||
&mut ctrl
|
||||
.add_tor(&key, external, SocketAddr::new(self.ip.into(), internal))
|
||||
.await?,
|
||||
);
|
||||
self.tor.insert(tor_idx, tor);
|
||||
Ok(())
|
||||
}
|
||||
pub async fn remove_tor(&mut self, id: InterfaceId, external: u16) -> Result<(), Error> {
|
||||
let ctrl = self.net_controller()?;
|
||||
if let Some((key, rcs)) = self.tor.remove(&(id, external)) {
|
||||
ctrl.remove_tor(&key, external, rcs).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub async fn add_lan<Ex>(
|
||||
&mut self,
|
||||
secrets: &mut Ex,
|
||||
id: InterfaceId,
|
||||
external: u16,
|
||||
internal: u16,
|
||||
connect_ssl: Result<(), AlpnInfo>,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
for<'a> &'a mut Ex: PgExecutor<'a>,
|
||||
{
|
||||
let key = Key::for_interface(secrets, Some((self.id.clone(), id.clone()))).await?;
|
||||
let ctrl = self.net_controller()?;
|
||||
let lan_idx = (id, external);
|
||||
let mut lan = self
|
||||
.lan
|
||||
.remove(&lan_idx)
|
||||
.unwrap_or_else(|| (key.clone(), Vec::new()));
|
||||
lan.1.append(
|
||||
&mut ctrl
|
||||
.add_lan(
|
||||
key,
|
||||
external,
|
||||
SocketAddr::new(self.ip.into(), internal),
|
||||
connect_ssl,
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
self.lan.insert(lan_idx, lan);
|
||||
Ok(())
|
||||
}
|
||||
pub async fn remove_lan(&mut self, id: InterfaceId, external: u16) -> Result<(), Error> {
|
||||
let ctrl = self.net_controller()?;
|
||||
if let Some((key, rcs)) = self.lan.remove(&(id, external)) {
|
||||
ctrl.remove_lan(&key, external, rcs).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub async fn export_cert<Ex>(
|
||||
&self,
|
||||
secrets: &mut Ex,
|
||||
id: &InterfaceId,
|
||||
ip: IpAddr,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
for<'a> &'a mut Ex: PgExecutor<'a>,
|
||||
{
|
||||
let key = Key::for_interface(secrets, Some((self.id.clone(), id.clone()))).await?;
|
||||
let ctrl = self.net_controller()?;
|
||||
let cert = ctrl.ssl.with_certs(key, ip).await?;
|
||||
let cert_dir = cert_dir(&self.id, id);
|
||||
tokio::fs::create_dir_all(&cert_dir).await?;
|
||||
export_key(
|
||||
&cert.key().openssl_key_nistp256(),
|
||||
&cert_dir.join(format!("{id}.key.pem")),
|
||||
)
|
||||
.await?;
|
||||
export_cert(
|
||||
&cert.fullchain_nistp256(),
|
||||
&cert_dir.join(format!("{id}.cert.pem")),
|
||||
)
|
||||
.await?; // TODO: can upgrade to ed25519?
|
||||
Ok(())
|
||||
}
|
||||
pub async fn remove_all(mut self) -> Result<(), Error> {
|
||||
self.shutdown = true;
|
||||
let mut errors = ErrorCollection::new();
|
||||
if let Some(ctrl) = Weak::upgrade(&self.controller) {
|
||||
for ((_, external), (key, rcs)) in std::mem::take(&mut self.lan) {
|
||||
errors.handle(ctrl.remove_lan(&key, external, rcs).await);
|
||||
}
|
||||
for ((_, external), (key, rcs)) in std::mem::take(&mut self.tor) {
|
||||
errors.handle(ctrl.remove_tor(&key, external, rcs).await);
|
||||
}
|
||||
std::mem::take(&mut self.dns);
|
||||
errors.handle(ctrl.dns.gc(Some(self.id.clone()), self.ip).await);
|
||||
errors.into_result()
|
||||
} else {
|
||||
tracing::warn!("NetService dropped after NetController is shutdown");
|
||||
Err(Error::new(
|
||||
eyre!("NetController is shutdown"),
|
||||
crate::ErrorKind::Network,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for NetService {
|
||||
fn drop(&mut self) {
|
||||
if !self.shutdown {
|
||||
tracing::debug!("Dropping NetService for {}", self.id);
|
||||
let svc = std::mem::replace(
|
||||
self,
|
||||
NetService {
|
||||
shutdown: true,
|
||||
id: Default::default(),
|
||||
ip: Ipv4Addr::new(0, 0, 0, 0),
|
||||
dns: Default::default(),
|
||||
controller: Default::default(),
|
||||
tor: Default::default(),
|
||||
lan: Default::default(),
|
||||
},
|
||||
);
|
||||
tokio::spawn(async move { svc.remove_all().await.unwrap() });
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user