Allow arguments to be specified in toml file (closes #10)

This commit is contained in:
Jonas Herzig 2020-07-05 12:07:43 +02:00
parent 2a95f11d30
commit ab58196ee5
6 changed files with 167 additions and 61 deletions

31
Cargo.lock generated
View file

@ -650,10 +650,12 @@ dependencies = [
"native-tls 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl 0.10.28 (registry+https://github.com/rust-lang/crates.io-index)", "openssl 0.10.28 (registry+https://github.com/rust-lang/crates.io-index)",
"rtp 0.1.0 (git+https://github.com/johni0702/rtp?rev=1444b3c)", "rtp 0.1.0 (git+https://github.com/johni0702/rtp?rev=1444b3c)",
"serde 1.0.113 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-tls 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-tls 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-tungstenite 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-tungstenite 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tungstenite 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "tungstenite 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"webrtc-sdp 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "webrtc-sdp 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1093,6 +1095,24 @@ dependencies = [
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "serde"
version = "1.0.113"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde_derive 1.0.113 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive"
version = "1.0.113"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "sha-1" name = "sha-1"
version = "0.8.2" version = "0.8.2"
@ -1288,6 +1308,14 @@ dependencies = [
"tokio 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "toml"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 1.0.113 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "trackable" name = "trackable"
version = "0.1.8" version = "0.1.8"
@ -1573,6 +1601,8 @@ dependencies = [
"checksum schannel 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "039c25b130bd8c1321ee2d7de7fde2659fa9c2744e4bb29711cfc852ea53cd19" "checksum schannel 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "039c25b130bd8c1321ee2d7de7fde2659fa9c2744e4bb29711cfc852ea53cd19"
"checksum security-framework 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "572dfa3a0785509e7a44b5b4bebcf94d41ba34e9ed9eb9df722545c3b3c4144a" "checksum security-framework 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "572dfa3a0785509e7a44b5b4bebcf94d41ba34e9ed9eb9df722545c3b3c4144a"
"checksum security-framework-sys 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8ddb15a5fec93b7021b8a9e96009c5d8d51c15673569f7c0f6b7204e5b7b404f" "checksum security-framework-sys 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8ddb15a5fec93b7021b8a9e96009c5d8d51c15673569f7c0f6b7204e5b7b404f"
"checksum serde 1.0.113 (registry+https://github.com/rust-lang/crates.io-index)" = "6135c78461981c79497158ef777264c51d9d0f4f3fc3a4d22b915900e42dac6a"
"checksum serde_derive 1.0.113 (registry+https://github.com/rust-lang/crates.io-index)" = "93c5eaa17d0954cb481cdcfffe9d84fcfa7a1a9f2349271e678677be4c26ae31"
"checksum sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" "checksum sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
"checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" "checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
"checksum signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94f478ede9f64724c5d173d7bb56099ec3e2d9fc2774aac65d34b8b890405f41" "checksum signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94f478ede9f64724c5d173d7bb56099ec3e2d9fc2774aac65d34b8b890405f41"
@ -1593,6 +1623,7 @@ dependencies = [
"checksum tokio-tls 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7bde02a3a5291395f59b06ec6945a3077602fac2b07eeeaf0dee2122f3619828" "checksum tokio-tls 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7bde02a3a5291395f59b06ec6945a3077602fac2b07eeeaf0dee2122f3619828"
"checksum tokio-tungstenite 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b8fe88007ebc363512449868d7da4389c9400072a3f666f212c7280082882a" "checksum tokio-tungstenite 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b8fe88007ebc363512449868d7da4389c9400072a3f666f212c7280082882a"
"checksum tokio-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" "checksum tokio-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499"
"checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a"
"checksum trackable 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "65defd0876240a5301307e55ada18dea77372391c65cee3a421fac482be3a25a" "checksum trackable 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "65defd0876240a5301307e55ada18dea77372391c65cee3a421fac482be3a25a"
"checksum tungstenite 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cfea31758bf674f990918962e8e5f07071a3161bd7c4138ed23e416e1ac4264e" "checksum tungstenite 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cfea31758bf674f990918962e8e5f07071a3161bd7c4138ed23e416e1ac4264e"
"checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" "checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9"

View file

@ -9,6 +9,8 @@ argparse = "0.2.2"
bytes = "0.5" bytes = "0.5"
byteorder = "1.2" byteorder = "1.2"
futures = { version = "0.3", features = ["compat", "io-compat"] } futures = { version = "0.3", features = ["compat", "io-compat"] }
toml = "0.5"
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "0.2", features = ["full"] } tokio = { version = "0.2", features = ["full"] }
tokio-util = { version = "0.3", features = ["codec"] } tokio-util = { version = "0.3", features = ["codec"] }
tokio-tls = "0.3" tokio-tls = "0.3"

View file

@ -38,6 +38,12 @@ E.g. if you want the proxy to listen on port `64737` and connect to your Mumble
mumble-web-proxy --listen-ws 64737 --server mumbleserver:64738 mumble-web-proxy --listen-ws 64737 --server mumbleserver:64738
``` ```
Instead of specifying all the options directly in the arguments, you can also use `--config <file>` to point mumble-web-proxy at a toml file which contains them:
```
listen-ws = 64737
server = 'mumbleserver:64738'
```
#### Firewalls or NAT #### Firewalls or NAT
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. 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.
``` ```

View file

@ -204,8 +204,8 @@ impl Connection {
// Setup ICE stream // Setup ICE stream
let mut stream = match { let mut stream = match {
let mut builder = agent.stream_builder(1); let mut builder = agent.stream_builder(1);
if self.config.min_port != 1 || self.config.max_port != u16::max_value() { if self.config.ice_min_port != 1 || self.config.ice_max_port != u16::max_value() {
builder.set_port_range(self.config.min_port, self.config.max_port); builder.set_port_range(self.config.ice_min_port, self.config.ice_max_port);
} }
builder.build() builder.build()
} { } {
@ -259,7 +259,11 @@ impl Connection {
// Map to public addresses (if configured) // Map to public addresses (if configured)
let config = &self.config; let config = &self.config;
match (&mut candidate.address, config.public_v4, config.public_v6) { match (
&mut candidate.address,
config.ice_public_v4,
config.ice_public_v6,
) {
(webrtc_sdp::address::Address::Ip(IpAddr::V4(addr)), Some(public), _) => { (webrtc_sdp::address::Address::Ip(IpAddr::V4(addr)), Some(public), _) => {
*addr = public; *addr = public;
} }

View file

@ -49,6 +49,12 @@ impl From<rtp::Error> for Error {
} }
} }
impl From<toml::de::Error> for Error {
fn from(e: toml::de::Error) -> Self {
Error::Misc(Box::new(e))
}
}
impl From<()> for Error { impl From<()> for Error {
fn from(_: ()) -> Self { fn from(_: ()) -> Self {
panic!(); panic!();

View file

@ -12,6 +12,7 @@ use mumble_protocol::control::ClientControlCodec;
use mumble_protocol::control::ControlPacket; use mumble_protocol::control::ControlPacket;
use mumble_protocol::control::RawControlPacket; use mumble_protocol::control::RawControlPacket;
use mumble_protocol::Clientbound; use mumble_protocol::Clientbound;
use serde::Deserialize;
use std::convert::Into; use std::convert::Into;
use std::convert::TryInto; use std::convert::TryInto;
use std::io::ErrorKind; use std::io::ErrorKind;
@ -32,72 +33,128 @@ mod error;
use connection::Connection; use connection::Connection;
use error::Error; use error::Error;
#[derive(Debug, Clone)] #[derive(Debug, Clone, Deserialize)]
#[serde(default, rename_all = "kebab-case")]
pub struct Config { pub struct Config {
pub min_port: u16, pub file: Option<String>,
pub max_port: u16, #[serde(rename = "listen-ws")]
pub public_v4: Option<Ipv4Addr>, pub ws_port: u16,
pub public_v6: Option<Ipv6Addr>, #[serde(rename = "server")]
pub upstream: String,
#[serde(rename = "accept-invalid-certificate")]
pub accept_invalid_certs: bool,
pub ice_min_port: u16,
pub ice_max_port: u16,
pub ice_public_v4: Option<Ipv4Addr>,
pub ice_public_v6: Option<Ipv6Addr>,
} }
#[tokio::main] impl Default for Config {
async fn main() -> Result<(), Error> { fn default() -> Config {
let mut ws_port = 0_u16; Config {
let mut upstream = "".to_string(); file: None,
let mut accept_invalid_certs = false; ws_port: 0_u16,
let mut config = Config { upstream: "".to_string(),
min_port: 1, accept_invalid_certs: false,
max_port: u16::max_value(), ice_min_port: 1,
public_v4: None, ice_max_port: u16::max_value(),
public_v6: None, ice_public_v4: None,
}; ice_public_v6: None,
}
}
}
{ fn create_argparser(config: &mut Config) -> ArgumentParser {
let mut ap = ArgumentParser::new(); let mut ap = ArgumentParser::new();
ap.set_description("Run the Mumble-WebRTC proxy"); ap.set_description("Run the Mumble-WebRTC proxy");
ap.refer(&mut ws_port) ap.refer(&mut config.file).add_option(
.add_option( &["--config"],
StoreOption,
"Toml file to read options from",
);
ap.refer(&mut config.ws_port).add_option(
&["--listen-ws"], &["--listen-ws"],
Store, Store,
"Port to listen for WebSocket (non TLS) connections on", "Port to listen for WebSocket (non TLS) connections on",
) );
.required(); ap.refer(&mut config.upstream).add_option(
ap.refer(&mut upstream)
.add_option(
&["--server"], &["--server"],
Store, Store,
"Hostname and (optionally) port of the upstream Mumble server", "Hostname and (optionally) port of the upstream Mumble server",
) );
.required(); ap.refer(&mut config.accept_invalid_certs).add_option(
ap.refer(&mut accept_invalid_certs).add_option(
&["--accept-invalid-certificate"], &["--accept-invalid-certificate"],
StoreTrue, StoreTrue,
"Connect to upstream server even when its certificate is invalid. "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!", Only ever use this if know that your server is using a self-signed certificate!",
); );
ap.refer(&mut config.min_port).add_option( ap.refer(&mut config.ice_min_port).add_option(
&["--ice-port-min"], &["--ice-port-min"],
Store, Store,
"Minimum port number to use for ICE host candidates.", "Minimum port number to use for ICE host candidates.",
); );
ap.refer(&mut config.max_port).add_option( ap.refer(&mut config.ice_max_port).add_option(
&["--ice-port-max"], &["--ice-port-max"],
Store, Store,
"Maximum port number to use for ICE host candidates.", "Maximum port number to use for ICE host candidates.",
); );
ap.refer(&mut config.public_v4).add_option( ap.refer(&mut config.ice_public_v4).add_option(
&["--ice-ipv4"], &["--ice-ipv4"],
StoreOption, StoreOption,
"Set a public IPv4 address to be used for ICE host candidates.", "Set a public IPv4 address to be used for ICE host candidates.",
); );
ap.refer(&mut config.public_v6).add_option( ap.refer(&mut config.ice_public_v6).add_option(
&["--ice-ipv6"], &["--ice-ipv6"],
StoreOption, StoreOption,
"Set a public IPv6 address to be used for ICE host candidates.", "Set a public IPv6 address to be used for ICE host candidates.",
); );
ap.parse_args_or_exit(); ap
} }
fn error_missing_arg(arg: &str) {
let args: Vec<String> = std::env::args().collect();
let name = if args.len() > 0 {
&args[0][..]
} else {
"unknown"
};
let mut config = Config::default();
let ap = create_argparser(&mut config);
ap.error(
name,
&format!("Option [\"--{}\"] is required", arg),
&mut std::io::stderr(),
);
std::process::exit(2);
}
#[tokio::main]
async fn main() -> Result<(), Error> {
let mut config = Config::default();
// First pass to get the config file path
create_argparser(&mut config).parse_args_or_exit();
if let Some(file) = config.file {
// Then read in the config defaults
config = toml::from_str(&std::fs::read_to_string(file)?)?;
// Second pass to allow for overwrites
create_argparser(&mut config).parse_args_or_exit();
}
if config.ws_port == 0 {
error_missing_arg("listen-ws");
}
if config.upstream == "" {
error_missing_arg("server");
}
let Config {
ws_port,
upstream,
accept_invalid_certs,
..
} = config.clone();
// Try parsing as raw IPv6 address first // Try parsing as raw IPv6 address first
let (upstream_host, upstream_port) = match upstream.parse::<Ipv6Addr>() { let (upstream_host, upstream_port) = match upstream.parse::<Ipv6Addr>() {
Ok(_) => (upstream.as_ref(), 64738), Ok(_) => (upstream.as_ref(), 64738),