pub mod auth;
pub mod paths;
pub mod segments;
pub mod sni;
pub mod uplinks;
#[cfg(test)]
mod test_util;
#[allow(dead_code)]
#[allow(clippy::unit_arg)]
mod sketch {
use crate::pg_wap2::{
auth::AuthService,
paths::PathManager,
segments::SegmentManager,
sni::WapSNI,
uplinks::{GenericUplink, UplinkEstablisher, UplinkManager},
};
pub struct WAPControlPlane<Establisher: UplinkEstablisher> {
pub auth: AuthService,
pub segments: SegmentManager,
pub paths: PathManager,
pub uplinks: UplinkManager<Establisher>,
}
use std::{net::IpAddr, time::SystemTime};
use anyhow::Context;
use sciparse::{
address::{ip_socket_addr::ScionSocketIpAddr, socket_addr::ScionSocketAddr},
identifier::isd_asn::IsdAsn,
path::ScionPath,
};
use tokio::select;
use tokio_util::sync::CancellationToken;
async fn main_loop_proto(cp: &WAPControlPlane<MockDataplane>) -> anyhow::Result<()> {
const CFG_LOCAL_AS: IsdAsn = IsdAsn(1);
let client_tcp_stream = ();
let client_ip = IpAddr::V4(std::net::Ipv4Addr::new(192, 168, 1, 1));
let now = SystemTime::now();
if !cp.auth.ip_is_authorized(client_ip, now) {
anyhow::bail!("Client IP {} is not authorized", client_ip);
}
let sni = tls_extract_sni_from_connection(client_tcp_stream)
.await
.context("Failed to extract SNI from connection")?;
let gateway_domain = sni.gateway_domain();
let dst_addr: ScionSocketIpAddr = resolve_tsar(gateway_domain.as_str())
.await
.context("Failed to resolve TSAR for SNI")?
.try_to_scion_sock_ip_addr()
.context("TSAR did not resolve to a SCION socket IP address")?;
let used_path = cp
.paths
.best_path(client_ip, &sni, CFG_LOCAL_AS, dst_addr.isd_asn(), now)
.await
.context("Failed to get best path")?
.context("No path found")?;
let mut up_stream = cp
.uplinks
.establish_stream(client_ip, &sni, used_path, dst_addr, now)
.await
.context("Failed to establish uplink stream")?;
let forward_future = start_forwarding(
client_ip,
&sni,
up_stream
.take_stream()
.expect("stream has already been taken"),
client_tcp_stream,
);
select! {
_ = forward_future => {
tracing::info!("Forwarding future completed");
}
_ = up_stream.grant_expired() => {
tracing::info!(%client_ip, %sni, "Authorization lost, closing connection");
}
_ = up_stream.uplink_closed() => {
tracing::info!(%client_ip, %sni, "Uplink was closed, closing connection");
}
}
Ok(())
}
async fn resolve_tsar(_sni: &str) -> anyhow::Result<ScionSocketAddr> {
todo!()
}
async fn tls_extract_sni_from_connection(_client_tcp_stream: ()) -> anyhow::Result<WapSNI> {
todo!()
}
async fn start_forwarding(
_client_ip: IpAddr,
_sni: &WapSNI,
_uplink_stream: <MockUplink as GenericUplink>::StreamType,
_client_stream: (),
) -> anyhow::Result<()> {
todo!()
}
struct MockDataplane;
#[async_trait::async_trait]
impl UplinkEstablisher for MockDataplane {
type Uplink = MockUplink;
async fn establish_connection(
&self,
_path: ScionPath,
_dst_addr: ScionSocketIpAddr,
_closed: CancellationToken,
) -> anyhow::Result<Self::Uplink> {
todo!("Implement the uplink connection establishment")
}
}
struct MockUplink;
#[async_trait::async_trait]
impl GenericUplink for MockUplink {
type StreamType = ();
async fn establish_stream(&self, _dst_sni: &WapSNI) -> anyhow::Result<Self::StreamType> {
todo!("Implement the uplink stream establishment")
}
fn replace_path(&self, _new_path: ScionPath) -> anyhow::Result<()> {
todo!("Implement the uplink path replacement")
}
}
}