Pass tunnel info into sec-websocket-protocol header

This commit is contained in:
Σrebe - Romain GERARD 2023-12-26 21:16:34 +01:00
parent f752ce67fb
commit 259da14d4d
No known key found for this signature in database
GPG key ID: 7A42B4B97E0332F4
3 changed files with 29 additions and 24 deletions

View file

@ -1,4 +1,4 @@
use super::{to_host_port, JwtTunnelConfig, JWT_KEY};
use super::{to_host_port, JwtTunnelConfig, JWT_HEADER_PREFIX, JWT_KEY};
use crate::{LocalToRemote, WsClientConfig};
use anyhow::{anyhow, Context};
@ -8,7 +8,7 @@ use fastwebsockets::WebSocket;
use futures_util::pin_mut;
use http_body_util::Empty;
use hyper::body::Incoming;
use hyper::header::{AUTHORIZATION, COOKIE, SEC_WEBSOCKET_VERSION, UPGRADE};
use hyper::header::{AUTHORIZATION, COOKIE, SEC_WEBSOCKET_PROTOCOL, SEC_WEBSOCKET_VERSION, UPGRADE};
use hyper::header::{CONNECTION, HOST, SEC_WEBSOCKET_KEY};
use hyper::upgrade::Upgraded;
use hyper::{Request, Response};
@ -42,16 +42,16 @@ pub async fn connect(
let mut req = Request::builder()
.method("GET")
.uri(format!(
"/{}/events?bearer={}",
&client_cfg.http_upgrade_path_prefix,
tunnel_to_jwt_token(request_id, tunnel_cfg)
))
.uri(format!("/{}/events", &client_cfg.http_upgrade_path_prefix,))
.header(HOST, &client_cfg.http_header_host)
.header(UPGRADE, "websocket")
.header(CONNECTION, "upgrade")
.header(SEC_WEBSOCKET_KEY, fastwebsockets::handshake::generate_key())
.header(SEC_WEBSOCKET_VERSION, "13")
.header(
SEC_WEBSOCKET_PROTOCOL,
format!("v1, {}{}", JWT_HEADER_PREFIX, tunnel_to_jwt_token(request_id, tunnel_cfg)),
)
.version(hyper::Version::HTTP_11);
for (k, v) in &client_cfg.http_headers {

View file

@ -49,6 +49,7 @@ impl JwtTunnelConfig {
}
}
static JWT_HEADER_PREFIX: &str = "authorization.bearer.";
static JWT_SECRET: &[u8; 15] = b"champignonfrais";
static JWT_KEY: Lazy<(Header, EncodingKey)> =
Lazy::new(|| (Header::new(Algorithm::HS256), EncodingKey::from_secret(JWT_SECRET)));

View file

@ -10,10 +10,10 @@ use std::pin::Pin;
use std::sync::Arc;
use std::time::Duration;
use super::{JwtTunnelConfig, JWT_DECODE};
use super::{JwtTunnelConfig, JWT_DECODE, JWT_HEADER_PREFIX};
use crate::{socks5, tcp, tls, udp, LocalProtocol, WsServerConfig};
use hyper::body::Incoming;
use hyper::header::COOKIE;
use hyper::header::{COOKIE, SEC_WEBSOCKET_PROTOCOL};
use hyper::http::HeaderValue;
use hyper::server::conn::http1;
use hyper::service::service_fn;
@ -221,22 +221,23 @@ fn validate_url(
#[inline]
fn extract_tunnel_info(req: &Request<Incoming>) -> Result<TokenData<JwtTunnelConfig>, Response<String>> {
let jwt: TokenData<JwtTunnelConfig> = match req.uri().query().unwrap_or_default().split_once('=') {
Some(("bearer", jwt)) => {
let (validation, decode_key) = JWT_DECODE.deref();
match jsonwebtoken::decode(jwt, decode_key, validation) {
Ok(jwt) => jwt,
err => {
error!("error while decoding jwt for tunnel info {:?}", err);
return Err(http::Response::builder()
.status(StatusCode::BAD_REQUEST)
.body("Invalid upgrade request".to_string())
.unwrap());
}
}
}
let jwt = req
.headers()
.get(SEC_WEBSOCKET_PROTOCOL)
.and_then(|header| header.to_str().ok())
.and_then(|header| header.split_once(JWT_HEADER_PREFIX))
.map(|(_prefix, jwt)| jwt)
.unwrap_or_default();
let (validation, decode_key) = JWT_DECODE.deref();
let jwt = match jsonwebtoken::decode(jwt, decode_key, validation) {
Ok(jwt) => jwt,
err => {
error!("Missing jwt tunnel config from request {:?}", err);
warn!(
"error while decoding jwt for tunnel info {:?} header {:?}",
err,
req.headers().get(SEC_WEBSOCKET_PROTOCOL)
);
return Err(http::Response::builder()
.status(StatusCode::BAD_REQUEST)
.body("Invalid upgrade request".to_string())
@ -358,6 +359,9 @@ async fn server_upgrade(server_config: Arc<WsServerConfig>, mut req: Request<Inc
};
response.headers_mut().insert(COOKIE, header_val);
}
response
.headers_mut()
.insert(SEC_WEBSOCKET_PROTOCOL, HeaderValue::from_static("v1"));
Response::from_parts(response.into_parts().0, "".to_string())
}