From a194bb6c6f33576e5fc38f1489c47487a35cf457 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 9 Feb 2019 10:40:38 +0100 Subject: [PATCH] Add support for running behind firewall and NAT --- Cargo.lock | 73 ++++++++++++++++++++++++++++++++++++++++------- Cargo.toml | 2 +- README.md | 4 +-- src/connection.rs | 33 +++++++++++++++++---- src/main.rs | 45 ++++++++++++++++++++++++++++- 5 files changed, 137 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 50bea7e..e703488 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -74,7 +74,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "block-buffer" -version = "0.7.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "block-padding 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -291,11 +291,53 @@ dependencies = [ "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "gio-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "glib" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "glib-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "glob" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "gobject-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "handy_async" version = "0.2.13" @@ -381,21 +423,28 @@ dependencies = [ [[package]] name = "libnice" version = "0.1.0" -source = "git+https://github.com/johni0702/rust-libnice?rev=f60d748#f60d748c03ef1027e95e82a09a2beba7c98bb32d" +source = "git+https://github.com/johni0702/rust-libnice?rev=1053c81#1053c81b549011b783dd33c1ce7967477800b783" dependencies = [ - "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libnice-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glib 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "libnice-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "webrtc-sdp 0.1.0 (git+https://github.com/nils-ohlmeier/rsdparsa/?rev=ccf6249)", ] [[package]] name = "libnice-sys" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bindgen 0.42.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gio-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -495,7 +544,7 @@ dependencies = [ "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libnice 0.1.0 (git+https://github.com/johni0702/rust-libnice?rev=f60d748)", + "libnice 0.1.0 (git+https://github.com/johni0702/rust-libnice?rev=1053c81)", "mumble-protocol 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "openssl 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -987,7 +1036,7 @@ name = "sha-1" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "block-buffer 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1469,7 +1518,7 @@ dependencies = [ "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum bindgen 0.42.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e0f199ccbabf5e9f9e13a3096534e80c9ce37aee440789dafaa47190e283245c" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" -"checksum block-buffer 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "509de513cca6d92b6aacf9c61acfe7eaa160837323a81068d690cc1f8e5740da" +"checksum block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d" "checksum block-padding 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d75255892aeb580d3c566f213a2b6fdc1c66667839f45719ee1d30ebf2aea591" "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" @@ -1497,7 +1546,11 @@ dependencies = [ "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" "checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" +"checksum gio-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6975ada29f7924dc1c90b30ed3b32d777805a275556c05e420da4fbdc22eb250" +"checksum glib 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a333edf5b9f1411c246ef14e7881b087255f04c56dbef48c64a0cb039b4b340" +"checksum glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3573351e846caed9f11207b275cd67bc07f0c2c94fb628e5d7c92ca056c7882d" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" +"checksum gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08475e4a08f27e6e2287005950114735ed61cec2cb8c1187682a5aec8c69b715" "checksum handy_async 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "165d5c5434dd3b9b3b3fa7ad58a895f13ee34f9aa42f3e5d13bc0ac544be7232" "checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83" "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" @@ -1509,8 +1562,8 @@ dependencies = [ "checksum lazycell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddba4c30a78328befecec92fc94970e53b3ae385827d28620f0f5bb2493081e0" "checksum libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)" = "10923947f84a519a45c8fefb7dd1b3e8c08747993381adee176d7a82b4195311" "checksum libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3ad660d7cb8c5822cd83d10897b0f1f1526792737a179e73896152f85b88c2" -"checksum libnice 0.1.0 (git+https://github.com/johni0702/rust-libnice?rev=f60d748)" = "" -"checksum libnice-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4c14f86d71d491b61486e5609bc6d5c5acf5d3f34e399b4881dde51c3e53f7cd" +"checksum libnice 0.1.0 (git+https://github.com/johni0702/rust-libnice?rev=1053c81)" = "" +"checksum libnice-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4076d4216144459cf21253dd351471bb58e0cbbb0e47f93768bb7d4428ccb149" "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" diff --git a/Cargo.toml b/Cargo.toml index d8c899b..04f2926 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ tokio-tungstenite = "0.6" tungstenite = "0.6" rtp = { git = "https://github.com/johni0702/rtp", rev = "ee8be93", features = ["openssl", "tokio"] } # libnice = "0.2" -libnice = { git = "https://github.com/johni0702/rust-libnice", rev = "f60d748" } +libnice = { git = "https://github.com/johni0702/rust-libnice", rev = "1053c81" } # webrtc-sdp = "0.2" webrtc-sdp = { git = "https://github.com/nils-ohlmeier/rsdparsa/", rev = "ccf6249" } openssl = "0.10" diff --git a/README.md b/README.md index f3113c9..ba67b6e 100644 --- a/README.md +++ b/README.md @@ -39,11 +39,9 @@ mumble-web-proxy --listen-ws 64737 --server mumbleserver:64738 ``` #### Firewalls or NAT -Note: Not yet implemented. - If your mumble-web-proxy is running behind a firewall or NAT, you need to allocate a range of ports to it which it can use for ICE connection establishment. ``` -mumble-web-proxy --listen-ws 64737 --server mumbleserver:64738 --ice-start 20000 --ice-end 21000 +mumble-web-proxy --listen-ws 64737 --server mumbleserver:64738 --ice-port-min 20000 --ice-port-max 21000 ``` For NATs, you additionally need to provide it with its publicly reachable IP address(es): ``` diff --git a/src/connection.rs b/src/connection.rs index 257483b..0220545 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -22,6 +22,7 @@ use rtp::rfc5764::{DtlsSrtp, DtlsSrtpHandshakeResult}; use rtp::traits::{ReadPacket, WritePacket}; use std::collections::BTreeMap; use std::ffi::CString; +use std::net::IpAddr; use std::time::{Duration, Instant}; use tokio::io; use tokio::prelude::*; @@ -30,6 +31,7 @@ use webrtc_sdp::attribute_type::SdpAttribute; use error::Error; use utils::EitherS; +use Config; type SessionId = u32; @@ -82,6 +84,7 @@ impl User { } pub struct Connection { + config: Config, inbound_client: Box, Error = Error>>, outbound_client: Box, SinkError = Error>>, inbound_server: Box, Error = Error>>, @@ -109,6 +112,7 @@ pub struct Connection { impl Connection { pub fn new( + config: Config, client_sink: CSi, client_stream: CSt, server_sink: SSi, @@ -135,6 +139,7 @@ impl Connection { let cert = cert_builder.build(); Self { + config, inbound_client: Box::new(client_stream), outbound_client: Box::new(client_sink), inbound_server: Box::new(server_stream), @@ -192,7 +197,13 @@ impl Connection { agent.set_software("mumble-web-proxy"); // Setup ICE stream - let mut stream = match agent.stream_builder(1).build() { + let mut stream = match { + let mut builder = agent.stream_builder(1); + if self.config.min_port != 1 || self.config.max_port != u16::max_value() { + builder.set_port_range(self.config.min_port, self.config.max_port); + } + builder.build() + } { Ok(stream) => stream, Err(err) => { return stream::once(Err(io::Error::new(io::ErrorKind::Other, err).into())); @@ -531,12 +542,24 @@ impl Future for Connection { // Poll ice stream for new candidates if let Some((_, stream)) = &mut self.ice { - if let Async::Ready(Some(candidate)) = stream.poll()? { - let candidate = format!("candidate:{}", candidate.to_string()); - println!("Local ice candidate: {}", candidate); + if let Async::Ready(Some(mut candidate)) = stream.poll()? { + println!("Local ice candidate: {}", candidate.to_string()); + + // Map to public addresses (if configured) + let config = &self.config; + match (&mut candidate.address, config.public_v4, config.public_v6) { + (IpAddr::V4(addr), Some(public), _) => { + *addr = public; + } + (IpAddr::V6(addr), _, Some(public)) => { + *addr = public; + } + _ => {} // non configured + }; + // Got a new candidate, send it to the client let mut msg = msgs::IceCandidate::new(); - msg.set_content(candidate.to_string()); + msg.set_content(format!("candidate:{}", candidate.to_string())); let frame = Frame::Client(msg.into()); self.stream_to_be_sent = Some(Box::new(stream::once(Ok(frame)))); continue 'poll; diff --git a/src/main.rs b/src/main.rs index 9c0301f..4e0ab0e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,6 +19,7 @@ extern crate tokio_tungstenite; extern crate tungstenite; extern crate webrtc_sdp; +use argparse::StoreOption; use argparse::StoreTrue; use argparse::{ArgumentParser, Store}; use byteorder::{BigEndian, ByteOrder}; @@ -30,6 +31,7 @@ use mumble_protocol::control::RawControlPacket; use mumble_protocol::Clientbound; use std::convert::Into; use std::convert::TryInto; +use std::net::Ipv4Addr; use std::net::Ipv6Addr; use std::net::ToSocketAddrs; use tokio::net::TcpListener; @@ -48,10 +50,24 @@ mod utils; use connection::Connection; use error::Error; +#[derive(Debug, Clone)] +pub struct Config { + pub min_port: u16, + pub max_port: u16, + pub public_v4: Option, + pub public_v6: Option, +} + fn main() { let mut ws_port = 0_u16; let mut upstream = "".to_string(); let mut accept_invalid_certs = false; + let mut config = Config { + min_port: 1, + max_port: u16::max_value(), + public_v4: None, + public_v6: None, + }; { let mut ap = ArgumentParser::new(); @@ -76,6 +92,26 @@ fn main() { "Connect to upstream server even when its certificate is invalid. Only ever use this if know that your server is using a self-signed certificate!", ); + ap.refer(&mut config.min_port).add_option( + &["--ice-port-min"], + Store, + "Minimum port number to use for ICE host candidates.", + ); + ap.refer(&mut config.max_port).add_option( + &["--ice-port-max"], + Store, + "Maximum port number to use for ICE host candidates.", + ); + ap.refer(&mut config.public_v4).add_option( + &["--ice-ipv4"], + StoreOption, + "Set a public IPv4 address to be used for ICE host candidates.", + ); + ap.refer(&mut config.public_v6).add_option( + &["--ice-ipv6"], + StoreOption, + "Set a public IPv6 address to be used for ICE host candidates.", + ); ap.parse_args_or_exit(); } @@ -138,6 +174,7 @@ fn main() { .from_err(); // Once both are done, begin proxy duty + let config = config.clone(); let f = client .join(server) .and_then(move |(client, server)| { @@ -164,7 +201,13 @@ fn main() { let server_sink = server_sink.sink_from_err(); let server_stream = server_stream.from_err(); - Connection::new(client_sink, client_stream, server_sink, server_stream) + Connection::new( + config, + client_sink, + client_stream, + server_sink, + server_stream, + ) }) .or_else(move |err| { if err.is_connection_closed() {