Compare commits
1 commit
82a8418b82
...
c6cd325748
| Author | SHA1 | Date | |
|---|---|---|---|
| c6cd325748 |
1 changed files with 5 additions and 52 deletions
|
|
@ -70,15 +70,6 @@ struct Args {
|
||||||
/// connect via ws:// instead.
|
/// connect via ws:// instead.
|
||||||
#[arg(long, default_value_t = 8081, value_name = "PORT")]
|
#[arg(long, default_value_t = 8081, value_name = "PORT")]
|
||||||
http_port: u16,
|
http_port: u16,
|
||||||
|
|
||||||
/// Trust proxy headers (X-Forwarded-For, X-Real-IP) for client IPs
|
|
||||||
///
|
|
||||||
/// Enable this when running behind a reverse proxy (e.g. nginx, caddy,
|
|
||||||
/// traefik). The server will use the IP from proxy headers instead of
|
|
||||||
/// the direct connection address. Do NOT enable this without a trusted
|
|
||||||
/// proxy, as clients can spoof these headers.
|
|
||||||
#[arg(long)]
|
|
||||||
trust_proxy: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Messages sent between peers via the signaling server
|
/// Messages sent between peers via the signaling server
|
||||||
|
|
@ -164,14 +155,12 @@ struct PeerState {
|
||||||
/// Application state shared across all connections
|
/// Application state shared across all connections
|
||||||
struct AppState {
|
struct AppState {
|
||||||
peers: DashMap<String, PeerState>,
|
peers: DashMap<String, PeerState>,
|
||||||
trust_proxy: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppState {
|
impl AppState {
|
||||||
fn new(trust_proxy: bool) -> Self {
|
fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
peers: DashMap::new(),
|
peers: DashMap::new(),
|
||||||
trust_proxy,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -213,7 +202,7 @@ async fn main() {
|
||||||
)
|
)
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
let state = Arc::new(AppState::new(args.trust_proxy));
|
let state = Arc::new(AppState::new());
|
||||||
|
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route("/", get(serve_index))
|
.route("/", get(serve_index))
|
||||||
|
|
@ -255,9 +244,6 @@ async fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if args.trust_proxy {
|
|
||||||
println!(" \x1b[1;36mProxy mode:\x1b[0m trusting X-Forwarded-For / X-Real-IP headers");
|
|
||||||
}
|
|
||||||
println!();
|
println!();
|
||||||
println!(" \x1b[90mOpen this URL in browsers on your local network.\x1b[0m");
|
println!(" \x1b[90mOpen this URL in browsers on your local network.\x1b[0m");
|
||||||
println!(" \x1b[90mPress Ctrl+C to stop the server.\x1b[0m");
|
println!(" \x1b[90mPress Ctrl+C to stop the server.\x1b[0m");
|
||||||
|
|
@ -304,47 +290,14 @@ async fn serve_index() -> impl IntoResponse {
|
||||||
async fn ws_handler(
|
async fn ws_handler(
|
||||||
ws: WebSocketUpgrade,
|
ws: WebSocketUpgrade,
|
||||||
ConnectInfo(addr): ConnectInfo<SocketAddr>,
|
ConnectInfo(addr): ConnectInfo<SocketAddr>,
|
||||||
headers: axum::http::HeaderMap,
|
|
||||||
State(state): State<Arc<AppState>>,
|
State(state): State<Arc<AppState>>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let peer_ip = if state.trust_proxy {
|
ws.on_upgrade(move |socket| handle_socket(socket, state, addr))
|
||||||
extract_proxy_ip(&headers).unwrap_or_else(|| addr.ip().to_string())
|
|
||||||
} else {
|
|
||||||
addr.ip().to_string()
|
|
||||||
};
|
|
||||||
ws.on_upgrade(move |socket| handle_socket(socket, state, peer_ip))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extract the client IP from proxy headers.
|
async fn handle_socket(socket: WebSocket, state: Arc<AppState>, addr: SocketAddr) {
|
||||||
/// Checks X-Forwarded-For first (uses the leftmost/first IP), then X-Real-IP.
|
|
||||||
fn extract_proxy_ip(headers: &axum::http::HeaderMap) -> Option<String> {
|
|
||||||
// X-Forwarded-For: client, proxy1, proxy2
|
|
||||||
if let Some(forwarded_for) = headers.get("x-forwarded-for") {
|
|
||||||
if let Ok(value) = forwarded_for.to_str() {
|
|
||||||
if let Some(first_ip) = value.split(',').next() {
|
|
||||||
let trimmed = first_ip.trim();
|
|
||||||
if !trimmed.is_empty() {
|
|
||||||
return Some(trimmed.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// X-Real-IP: client
|
|
||||||
if let Some(real_ip) = headers.get("x-real-ip") {
|
|
||||||
if let Ok(value) = real_ip.to_str() {
|
|
||||||
let trimmed = value.trim();
|
|
||||||
if !trimmed.is_empty() {
|
|
||||||
return Some(trimmed.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn handle_socket(socket: WebSocket, state: Arc<AppState>, peer_ip: String) {
|
|
||||||
let peer_id = Uuid::new_v4().to_string();
|
let peer_id = Uuid::new_v4().to_string();
|
||||||
|
let peer_ip = addr.ip().to_string();
|
||||||
let (tx, _) = broadcast::channel::<SignalMessage>(64);
|
let (tx, _) = broadcast::channel::<SignalMessage>(64);
|
||||||
|
|
||||||
// Add peer to state with default name
|
// Add peer to state with default name
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue