mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 10:21:52 +00:00
support http2 alpn handshake (#2354)
* support http2 alpn handshake * fix protocol name * switch to https for tor * update setup wizard and main ui to accommodate https (#2356) * update setup wizard and main ui to accommodate https * update wording in download doc * fix accidential conversion of tor https for services and allow ws still * redirect to https if available * fix replaces to only search at beginning and ignore localhost when checking for https --------- Co-authored-by: Lucy <12953208+elvece@users.noreply.github.com>
This commit is contained in:
@@ -49,7 +49,7 @@ impl Database {
|
||||
last_wifi_region: None,
|
||||
eos_version_compat: Current::new().compat().clone(),
|
||||
lan_address,
|
||||
tor_address: format!("http://{}", account.key.tor_address())
|
||||
tor_address: format!("https://{}", account.key.tor_address())
|
||||
.parse()
|
||||
.unwrap(),
|
||||
ip_info: BTreeMap::new(),
|
||||
|
||||
@@ -21,6 +21,7 @@ use tracing::instrument;
|
||||
use crate::context::RpcContext;
|
||||
use crate::manager::sync::synchronizer;
|
||||
use crate::net::net_controller::NetService;
|
||||
use crate::net::vhost::AlpnInfo;
|
||||
use crate::procedure::docker::{DockerContainer, DockerProcedure, LongRunning};
|
||||
#[cfg(feature = "js_engine")]
|
||||
use crate::procedure::js_scripts::JsProcedure;
|
||||
@@ -573,8 +574,14 @@ async fn add_network_for_main(
|
||||
let mut tx = secrets.begin().await?;
|
||||
for (id, interface) in &seed.manifest.interfaces.0 {
|
||||
for (external, internal) in interface.lan_config.iter().flatten() {
|
||||
svc.add_lan(&mut tx, id.clone(), external.0, internal.internal, false)
|
||||
.await?;
|
||||
svc.add_lan(
|
||||
&mut tx,
|
||||
id.clone(),
|
||||
external.0,
|
||||
internal.internal,
|
||||
Err(AlpnInfo::Specified(vec![])),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
for (external, internal) in interface.tor_config.iter().flat_map(|t| &t.port_mapping) {
|
||||
svc.add_tor(&mut tx, id.clone(), external.0, internal.0)
|
||||
|
||||
@@ -15,7 +15,7 @@ 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::VHostController;
|
||||
use crate::net::vhost::{AlpnInfo, VHostController};
|
||||
use crate::s9pk::manifest::PackageId;
|
||||
use crate::volume::cert_dir;
|
||||
use crate::{Error, HOST_IP};
|
||||
@@ -55,6 +55,8 @@ impl NetController {
|
||||
}
|
||||
|
||||
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(
|
||||
@@ -62,7 +64,7 @@ impl NetController {
|
||||
Some("embassy".into()),
|
||||
443,
|
||||
([127, 0, 0, 1], 80).into(),
|
||||
false,
|
||||
alpn.clone(),
|
||||
)
|
||||
.await?;
|
||||
self.os_bindings
|
||||
@@ -71,7 +73,13 @@ impl NetController {
|
||||
// LAN IP
|
||||
self.os_bindings.push(
|
||||
self.vhost
|
||||
.add(key.clone(), None, 443, ([127, 0, 0, 1], 80).into(), false)
|
||||
.add(
|
||||
key.clone(),
|
||||
None,
|
||||
443,
|
||||
([127, 0, 0, 1], 80).into(),
|
||||
alpn.clone(),
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
|
||||
@@ -83,7 +91,7 @@ impl NetController {
|
||||
Some("localhost".into()),
|
||||
443,
|
||||
([127, 0, 0, 1], 80).into(),
|
||||
false,
|
||||
alpn.clone(),
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
@@ -94,7 +102,7 @@ impl NetController {
|
||||
Some(hostname.no_dot_host_name()),
|
||||
443,
|
||||
([127, 0, 0, 1], 80).into(),
|
||||
false,
|
||||
alpn.clone(),
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
@@ -107,7 +115,7 @@ impl NetController {
|
||||
Some(hostname.local_domain_name()),
|
||||
443,
|
||||
([127, 0, 0, 1], 80).into(),
|
||||
false,
|
||||
alpn.clone(),
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
@@ -127,7 +135,7 @@ impl NetController {
|
||||
Some(key.tor_address().to_string()),
|
||||
443,
|
||||
([127, 0, 0, 1], 80).into(),
|
||||
false,
|
||||
alpn.clone(),
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
@@ -179,7 +187,7 @@ impl NetController {
|
||||
key: Key,
|
||||
external: u16,
|
||||
target: SocketAddr,
|
||||
connect_ssl: bool,
|
||||
connect_ssl: Result<(), AlpnInfo>,
|
||||
) -> Result<Vec<Arc<()>>, Error> {
|
||||
let mut rcs = Vec::with_capacity(2);
|
||||
rcs.push(
|
||||
@@ -261,7 +269,7 @@ impl NetService {
|
||||
id: InterfaceId,
|
||||
external: u16,
|
||||
internal: u16,
|
||||
connect_ssl: bool,
|
||||
connect_ssl: Result<(), AlpnInfo>,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
for<'a> &'a mut Ex: PgExecutor<'a>,
|
||||
|
||||
@@ -41,7 +41,7 @@ impl VHostController {
|
||||
hostname: Option<String>,
|
||||
external: u16,
|
||||
target: SocketAddr,
|
||||
connect_ssl: bool,
|
||||
connect_ssl: Result<(), AlpnInfo>,
|
||||
) -> Result<Arc<()>, Error> {
|
||||
let mut writable = self.servers.lock().await;
|
||||
let server = if let Some(server) = writable.remove(&external) {
|
||||
@@ -77,10 +77,16 @@ impl VHostController {
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
struct TargetInfo {
|
||||
addr: SocketAddr,
|
||||
connect_ssl: bool,
|
||||
connect_ssl: Result<(), AlpnInfo>,
|
||||
key: Key,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum AlpnInfo {
|
||||
Reflect,
|
||||
Specified(Vec<Vec<u8>>),
|
||||
}
|
||||
|
||||
struct VHostServer {
|
||||
mapping: Weak<RwLock<BTreeMap<Option<String>, BTreeMap<TargetInfo, Weak<()>>>>>,
|
||||
_thread: NonDetachingJoinHandle<()>,
|
||||
@@ -178,7 +184,7 @@ impl VHostServer {
|
||||
let cfg = ServerConfig::builder()
|
||||
.with_safe_defaults()
|
||||
.with_no_client_auth();
|
||||
let cfg =
|
||||
let mut cfg =
|
||||
if mid.client_hello().signature_schemes().contains(
|
||||
&tokio_rustls::rustls::SignatureScheme::ED25519,
|
||||
) {
|
||||
@@ -213,48 +219,86 @@ impl VHostServer {
|
||||
.private_key_to_der()?,
|
||||
),
|
||||
)
|
||||
};
|
||||
let mut tls_stream = mid
|
||||
.into_stream(Arc::new(
|
||||
cfg.with_kind(crate::ErrorKind::OpenSsl)?,
|
||||
))
|
||||
.await?;
|
||||
tls_stream.get_mut().0.stop_buffering();
|
||||
if target.connect_ssl {
|
||||
tokio::io::copy_bidirectional(
|
||||
&mut tls_stream,
|
||||
&mut TlsConnector::from(Arc::new(
|
||||
}
|
||||
.with_kind(crate::ErrorKind::OpenSsl)?;
|
||||
match target.connect_ssl {
|
||||
Ok(()) => {
|
||||
let mut client_cfg =
|
||||
tokio_rustls::rustls::ClientConfig::builder()
|
||||
.with_safe_defaults()
|
||||
.with_root_certificates({
|
||||
let mut store = RootCertStore::empty();
|
||||
store.add(
|
||||
&tokio_rustls::rustls::Certificate(
|
||||
key.root_ca().to_der()?,
|
||||
),
|
||||
).with_kind(crate::ErrorKind::OpenSsl)?;
|
||||
&tokio_rustls::rustls::Certificate(
|
||||
key.root_ca().to_der()?,
|
||||
),
|
||||
).with_kind(crate::ErrorKind::OpenSsl)?;
|
||||
store
|
||||
})
|
||||
.with_no_client_auth(),
|
||||
))
|
||||
.connect(
|
||||
key.key()
|
||||
.internal_address()
|
||||
.as_str()
|
||||
.try_into()
|
||||
.with_kind(crate::ErrorKind::OpenSsl)?,
|
||||
tcp_stream,
|
||||
.with_no_client_auth();
|
||||
client_cfg.alpn_protocols = mid
|
||||
.client_hello()
|
||||
.alpn()
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.map(|x| x.to_vec())
|
||||
.collect();
|
||||
let mut target_stream =
|
||||
TlsConnector::from(Arc::new(client_cfg))
|
||||
.connect_with(
|
||||
key.key()
|
||||
.internal_address()
|
||||
.as_str()
|
||||
.try_into()
|
||||
.with_kind(
|
||||
crate::ErrorKind::OpenSsl,
|
||||
)?,
|
||||
tcp_stream,
|
||||
|conn| {
|
||||
cfg.alpn_protocols.extend(
|
||||
conn.alpn_protocol()
|
||||
.into_iter()
|
||||
.map(|p| p.to_vec()),
|
||||
)
|
||||
},
|
||||
)
|
||||
.await
|
||||
.with_kind(crate::ErrorKind::OpenSsl)?;
|
||||
let mut tls_stream =
|
||||
mid.into_stream(Arc::new(cfg)).await?;
|
||||
tls_stream.get_mut().0.stop_buffering();
|
||||
tokio::io::copy_bidirectional(
|
||||
&mut tls_stream,
|
||||
&mut target_stream,
|
||||
)
|
||||
.await
|
||||
.with_kind(crate::ErrorKind::OpenSsl)?,
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
tokio::io::copy_bidirectional(
|
||||
&mut tls_stream,
|
||||
&mut tcp_stream,
|
||||
)
|
||||
.await?;
|
||||
.await?;
|
||||
}
|
||||
Err(AlpnInfo::Reflect) => {
|
||||
for proto in
|
||||
mid.client_hello().alpn().into_iter().flatten()
|
||||
{
|
||||
cfg.alpn_protocols.push(proto.into());
|
||||
}
|
||||
let mut tls_stream =
|
||||
mid.into_stream(Arc::new(cfg)).await?;
|
||||
tls_stream.get_mut().0.stop_buffering();
|
||||
tokio::io::copy_bidirectional(
|
||||
&mut tls_stream,
|
||||
&mut tcp_stream,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
Err(AlpnInfo::Specified(alpn)) => {
|
||||
cfg.alpn_protocols = alpn;
|
||||
let mut tls_stream =
|
||||
mid.into_stream(Arc::new(cfg)).await?;
|
||||
tls_stream.get_mut().0.stop_buffering();
|
||||
tokio::io::copy_bidirectional(
|
||||
&mut tls_stream,
|
||||
&mut tcp_stream,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 503
|
||||
|
||||
@@ -144,7 +144,7 @@ pub async fn attach(
|
||||
}
|
||||
let (hostname, tor_addr, root_ca) = setup_init(&ctx, password).await?;
|
||||
*ctx.setup_result.write().await = Some((guid, SetupResult {
|
||||
tor_address: format!("http://{}", tor_addr),
|
||||
tor_address: format!("https://{}", tor_addr),
|
||||
lan_address: hostname.lan_address(),
|
||||
root_ca: String::from_utf8(root_ca.to_pem()?)?,
|
||||
}));
|
||||
@@ -281,7 +281,7 @@ pub async fn execute(
|
||||
*ctx.setup_result.write().await = Some((
|
||||
guid,
|
||||
SetupResult {
|
||||
tor_address: format!("http://{}", tor_addr),
|
||||
tor_address: format!("https://{}", tor_addr),
|
||||
lan_address: hostname.lan_address(),
|
||||
root_ca: String::from_utf8(
|
||||
root_ca.to_pem().expect("failed to serialize root ca"),
|
||||
|
||||
Reference in New Issue
Block a user