Skip to content

Commit

Permalink
Use Arc for HTTP proxy data and fix admin interface
Browse files Browse the repository at this point in the history
  • Loading branch information
EpicEric committed Dec 19, 2024
1 parent a4d756f commit c33de68
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 145 deletions.
10 changes: 10 additions & 0 deletions book/src/advanced_uses.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Advanced uses

## Connecting to the HTTPS port

In some networks, outbound connections to 22 (or 2222) may be blocked by the operator. In Sandhole, it's possible to get around this with the `--connect-ssh-on-https-port` option.

Once your administrator has configured it, you can then expose your services with:

```bash
ssh -R test:80:localhost:3000 server.com -p 443
```

## Local forwarding and aliasing

In addition to remote port forwarding, Sandhole also supports local port forwarding. This allows you to create SSH-based tunnels to connect to a service.
Expand Down
10 changes: 0 additions & 10 deletions book/src/exposing_your_first_service.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,3 @@ ssh -R localhost:4321:localhost:3000 server.com -p 2222
## Automatic reconnection

If you'd like to have persistent tunnels, use a tool like `autossh` with the `-M 0` option to automatically reconnect when disconnected. Note that you'll be assigned a new subdomain/port if the option above is not enabled, depending on the server configuration.

## Connecting to the HTTPS port

In some networks, outbound connections to 22 (or 2222) may be blocked by the operator. In Sandhole, it's possible to get around this with the `--connect-ssh-on-https-port` option.

Once your administrator has configured it, you can then expose your services with:

```bash
ssh -R test:80:localhost:3000 server.com -p 443
```
19 changes: 3 additions & 16 deletions src/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,6 @@ struct AdminState {
vertical_scroll: ScrollbarState,
}

fn remove_user_namespace(user: &str) -> &str {
&user[2..]
}

fn to_socket_addr_string(addr: SocketAddr) -> String {
let ip = addr.ip().to_canonical();
if ip.is_ipv4() {
Expand Down Expand Up @@ -162,10 +158,7 @@ impl AdminState {
Row::new(vec![
host,
req_per_min.to_string(),
users
.iter()
.map(|user| remove_user_namespace(user))
.join("\n"),
users.iter().join("\n"),
peers.into_iter().map(to_socket_addr_string).join("\n"),
])
.height(len)
Expand Down Expand Up @@ -194,10 +187,7 @@ impl AdminState {
let (peers, users): (Vec<_>, Vec<_>) = connections.into_iter().unzip();
Row::new(vec![
host,
users
.iter()
.map(|user| remove_user_namespace(user))
.join("\n"),
users.iter().join("\n"),
peers.into_iter().map(to_socket_addr_string).join("\n"),
])
.height(len)
Expand Down Expand Up @@ -228,10 +218,7 @@ impl AdminState {
Row::new(vec![
alias,
port.to_string(),
users
.iter()
.map(|user| remove_user_namespace(user))
.join("\n"),
users.iter().join("\n"),
peers.into_iter().map(to_socket_addr_string).join("\n"),
])
.height(len)
Expand Down
78 changes: 38 additions & 40 deletions src/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ where
pub(crate) async fn proxy_handler<B, H, T, R>(
mut request: Request<B>,
tcp_address: SocketAddr,
proxy_data: ProxyData<H, T, R>,
proxy_data: Arc<ProxyData<H, T, R>>,
) -> anyhow::Result<Response<AxumBody>>
where
H: ConnectionHandler<T>,
Expand All @@ -135,16 +135,11 @@ where
<B as Body>::Data: Send + Sync + 'static,
<B as Body>::Error: Error + Send + Sync + 'static,
{
let ProxyData {
conn_manager,
telemetry,
domain_redirect,
protocol,
http_request_timeout,
websocket_timeout,
disable_http_logs,
..
} = proxy_data;
let conn_manager = &proxy_data.conn_manager;
let telemetry = &proxy_data.telemetry;
let domain_redirect = &proxy_data.domain_redirect;
let protocol = &proxy_data.protocol;
let disable_http_logs = proxy_data.disable_http_logs;
let timer = Instant::now();
let host = request
.headers()
Expand Down Expand Up @@ -183,13 +178,9 @@ where
let elapsed_time = timer.elapsed();
let response = Redirect::permanent(
format!(
"https://{}{}{}",
"https://{}:{}{}",
host,
if to_port == 443 {
"".into()
} else {
format!(":{to_port}")
},
to_port,
request
.uri()
.path_and_query()
Expand Down Expand Up @@ -243,9 +234,12 @@ where
warn!("Connection failed: {:?}", err);
}
});
let response = timeout(http_request_timeout, sender.send_request(request))
.await
.map_err(|_| ServerError::RequestTimeout)??;
let response = timeout(
proxy_data.http_request_timeout,
sender.send_request(request),
)
.await
.map_err(|_| ServerError::RequestTimeout)??;
let elapsed_time = timer.elapsed();
http_log(
HttpLog {
Expand All @@ -270,9 +264,12 @@ where
});
let request_type = request_upgrade.to_str()?.to_string();
let upgraded_request = hyper::upgrade::on(&mut request);
let mut response = timeout(http_request_timeout, sender.send_request(request))
.await
.map_err(|_| ServerError::RequestTimeout)??;
let mut response = timeout(
proxy_data.http_request_timeout,
sender.send_request(request),
)
.await
.map_err(|_| ServerError::RequestTimeout)??;
let elapsed_time = timer.elapsed();
http_log(
HttpLog {
Expand All @@ -296,6 +293,7 @@ where
.to_str()?
{
let upgraded_response = hyper::upgrade::on(&mut response).await?;
let websocket_timeout = proxy_data.websocket_timeout;
tokio::spawn(async move {
let mut upgraded_request =
TokioIo::new(upgraded_request.await.unwrap());
Expand Down Expand Up @@ -372,7 +370,7 @@ mod proxy_handler_tests {
let response = proxy_handler(
request,
"127.0.0.1:12345".parse().unwrap(),
ProxyData {
Arc::new(ProxyData {
conn_manager: Arc::clone(&conn_manager),
telemetry: Arc::new(Telemetry::new()),
domain_redirect: Arc::new(DomainRedirect {
Expand All @@ -384,7 +382,7 @@ mod proxy_handler_tests {
websocket_timeout: None,
disable_http_logs: false,
_phantom_data: PhantomData,
},
}),
)
.await;
assert!(response.is_err(), "should error on missing host header");
Expand Down Expand Up @@ -412,7 +410,7 @@ mod proxy_handler_tests {
let response = proxy_handler(
request,
"127.0.0.1:12345".parse().unwrap(),
ProxyData {
Arc::new(ProxyData {
conn_manager: Arc::clone(&conn_manager),
telemetry: Arc::new(Telemetry::new()),
domain_redirect: Arc::new(DomainRedirect {
Expand All @@ -424,7 +422,7 @@ mod proxy_handler_tests {
websocket_timeout: None,
disable_http_logs: false,
_phantom_data: PhantomData,
},
}),
)
.await;
assert!(response.is_ok(), "should return response when not found");
Expand Down Expand Up @@ -454,7 +452,7 @@ mod proxy_handler_tests {
let response = proxy_handler(
request,
"127.0.0.1:12345".parse().unwrap(),
ProxyData {
Arc::new(ProxyData {
conn_manager: Arc::clone(&conn_manager),
telemetry: Arc::new(Telemetry::new()),
domain_redirect: Arc::new(DomainRedirect {
Expand All @@ -466,7 +464,7 @@ mod proxy_handler_tests {
websocket_timeout: None,
disable_http_logs: false,
_phantom_data: PhantomData,
},
}),
)
.await;
assert!(response.is_ok(), "should return response when redirect");
Expand Down Expand Up @@ -511,7 +509,7 @@ mod proxy_handler_tests {
let response = proxy_handler(
request,
"127.0.0.1:12345".parse().unwrap(),
ProxyData {
Arc::new(ProxyData {
conn_manager: Arc::clone(&conn_manager),
telemetry: Arc::new(Telemetry::new()),
domain_redirect: Arc::new(DomainRedirect {
Expand All @@ -523,7 +521,7 @@ mod proxy_handler_tests {
websocket_timeout: None,
disable_http_logs: false,
_phantom_data: PhantomData,
},
}),
)
.await;
assert!(
Expand All @@ -534,7 +532,7 @@ mod proxy_handler_tests {
assert_eq!(response.status(), hyper::StatusCode::PERMANENT_REDIRECT);
assert_eq!(
response.headers().get("location").unwrap(),
"https://with.handler/api/endpoint"
"https://with.handler:443/api/endpoint"
);
}

Expand Down Expand Up @@ -571,7 +569,7 @@ mod proxy_handler_tests {
let response = proxy_handler(
request,
"127.0.0.1:12345".parse().unwrap(),
ProxyData {
Arc::new(ProxyData {
conn_manager: Arc::clone(&conn_manager),
telemetry: Arc::new(Telemetry::new()),
domain_redirect: Arc::new(DomainRedirect {
Expand All @@ -583,7 +581,7 @@ mod proxy_handler_tests {
websocket_timeout: None,
disable_http_logs: false,
_phantom_data: PhantomData,
},
}),
)
.await;
assert!(
Expand Down Expand Up @@ -663,7 +661,7 @@ mod proxy_handler_tests {
let response = proxy_handler(
request,
"127.0.0.1:12345".parse().unwrap(),
ProxyData {
Arc::new(ProxyData {
conn_manager: Arc::clone(&conn_manager),
telemetry: Arc::new(Telemetry::new()),
domain_redirect: Arc::new(DomainRedirect {
Expand All @@ -675,7 +673,7 @@ mod proxy_handler_tests {
websocket_timeout: None,
disable_http_logs: false,
_phantom_data: PhantomData,
},
}),
)
.await;
assert!(!logging_rx.is_empty(), "should log after proxying request");
Expand Down Expand Up @@ -753,7 +751,7 @@ mod proxy_handler_tests {
let response = proxy_handler(
request,
"192.168.0.1:12345".parse().unwrap(),
ProxyData {
Arc::new(ProxyData {
conn_manager: Arc::clone(&conn_manager),
telemetry: Arc::new(Telemetry::new()),
domain_redirect: Arc::new(DomainRedirect {
Expand All @@ -765,7 +763,7 @@ mod proxy_handler_tests {
websocket_timeout: None,
disable_http_logs: false,
_phantom_data: PhantomData,
},
}),
)
.await;
assert!(!logging_rx.is_empty(), "should log after proxying request");
Expand Down Expand Up @@ -837,7 +835,7 @@ mod proxy_handler_tests {
proxy_handler(
request,
"127.0.0.1:12345".parse().unwrap(),
ProxyData {
Arc::new(ProxyData {
conn_manager: Arc::clone(&conn_manager),
telemetry: Arc::new(Telemetry::new()),
domain_redirect: Arc::new(DomainRedirect {
Expand All @@ -849,7 +847,7 @@ mod proxy_handler_tests {
websocket_timeout: None,
disable_http_logs: false,
_phantom_data: PhantomData,
},
}),
)
});
let jh2 = tokio::spawn(async move {
Expand Down
Loading

0 comments on commit c33de68

Please sign in to comment.