Adding CLI options: port shift and unsafe expose. (#5677)

* Adding CLI option for port shift and unsafe expose.

* Fixing IPC path.

* Fix hosts when attempting to expose on all interfaces.

* Fixing test.

* Fix typo.
This commit is contained in:
Tomasz Drwięga 2017-05-23 12:24:32 +02:00 committed by Arkadiy Paronyan
parent 532801f9d6
commit f47cbe0be6
8 changed files with 159 additions and 58 deletions

View File

@ -40,7 +40,7 @@ const TRANSITION_BLOCK_1: usize = 2; // block at which the contract becomes acti
const TRANSITION_BLOCK_2: usize = 6; // block at which the second contract activates.
macro_rules! secret {
($e: expr) => { Secret::from_slice(&$e.sha3()).expect(format!("sha3({}) not valid secret.", $e).as_str()) }
($e: expr) => { Secret::from_slice(&$e.sha3()) }
}
lazy_static! {

View File

@ -81,3 +81,5 @@ jit = false
logging = "own_tx=trace"
log_file = "/var/log/parity.log"
color = true
ports_shift = 0
unsafe_expose = false

View File

@ -98,6 +98,13 @@ usage! {
flag_no_persistent_txqueue: bool = false,
or |c: &Config| otry!(c.parity).no_persistent_txqueue,
// -- Convenience Options
flag_config: String = "$BASE/config.toml", or |_| None,
flag_ports_shift: u16 = 0u16,
or |c: &Config| otry!(c.misc).ports_shift,
flag_unsafe_expose: bool = false,
or |c: &Config| otry!(c.misc).unsafe_expose,
// -- Account Options
flag_unlock: Option<String> = None,
or |c: &Config| otry!(c.account).unlock.as_ref().map(|vec| Some(vec.join(","))),
@ -189,7 +196,7 @@ usage! {
// IPC
flag_no_ipc: bool = false,
or |c: &Config| otry!(c.ipc).disable.clone(),
flag_ipc_path: String = "$BASE/jsonrpc.ipc",
flag_ipc_path: String = if cfg!(windows) { r"\\.\pipe\jsonrpc.ipc" } else { "$BASE/jsonrpc.ipc" },
or |c: &Config| otry!(c.ipc).path.clone(),
flag_ipc_apis: String = "web3,eth,net,parity,parity_accounts,traces,rpc,secretstore",
or |c: &Config| otry!(c.ipc).apis.as_ref().map(|vec| vec.join(",")),
@ -339,7 +346,6 @@ usage! {
or |c: &Config| otry!(c.vm).jit.clone(),
// -- Miscellaneous Options
flag_config: String = "$BASE/config.toml", or |_| None,
flag_logging: Option<String> = None,
or |c: &Config| otry!(c.misc).logging.clone().map(Some),
flag_log_file: Option<String> = None,
@ -575,6 +581,8 @@ struct Misc {
logging: Option<String>,
log_file: Option<String>,
color: Option<bool>,
ports_shift: Option<u16>,
unsafe_expose: Option<bool>,
}
#[cfg(test)]
@ -686,6 +694,11 @@ mod tests {
flag_light: false,
flag_no_persistent_txqueue: false,
// -- Convenience Options
flag_config: "$BASE/config.toml".into(),
flag_ports_shift: 0,
flag_unsafe_expose: false,
// -- Account Options
flag_unlock: Some("0xdeadbeefcafe0000000000000000000000000000".into()),
flag_password: vec!["~/.safe/password.file".into()],
@ -862,7 +875,6 @@ mod tests {
// -- Miscellaneous Options
flag_version: false,
flag_config: "$BASE/config.toml".into(),
flag_logging: Some("own_tx=trace".into()),
flag_log_file: Some("/var/log/parity.log".into()),
flag_no_color: false,
@ -1037,6 +1049,8 @@ mod tests {
logging: Some("own_tx=trace".into()),
log_file: Some("/var/log/parity.log".into()),
color: Some(true),
ports_shift: Some(0),
unsafe_expose: Some(false),
}),
stratum: None,
});

View File

@ -76,6 +76,18 @@ Operating Options:
potentially higher in bandwidth. Has no effect with
subcommands (default: {flag_light}).
Convenience Options:
-c --config CONFIG Specify a filename containing a configuration file.
(default: {flag_config})
--ports-shift SHIFT Add SHIFT to all port numbers Parity is listening on.
Includes network port and all servers (RPC, WebSockets, UI, IPFS, SecretStore).
(default: {flag_ports_shift})
--unsafe-expose All servers will listen on external interfaces and will
be remotely accessible. It's equivalent with setting
the following: --{{ws,jsonrpc,ui,ipfs,secret_store,stratum}}-interface=all --*-hosts=all
This option is UNSAFE and should be used with great care!
(default: {flag_unsafe_expose})
Account Options:
--unlock ACCOUNTS Unlock ACCOUNTS for the duration of the execution.
ACCOUNTS is a comma-delimited list of addresses.
@ -441,8 +453,6 @@ Internal Options:
--can-restart Executable will auto-restart if exiting with 69.
Miscellaneous Options:
-c --config CONFIG Specify a filename containing a configuration file.
(default: {flag_config})
-l --logging LOGGING Specify the logging level. Must conform to the same
format as RUST_LOG. (default: {flag_logging:?})
--log-file FILENAME Specify a filename into which logging should be

View File

@ -373,7 +373,7 @@ impl Configuration {
public_node: public_node,
geth_compatibility: geth_compatibility,
ui_address: ui_address,
net_settings: self.network_settings(),
net_settings: self.network_settings()?,
dapps_conf: dapps_conf,
ipfs_conf: ipfs_conf,
signer_conf: signer_conf,
@ -513,7 +513,7 @@ impl Configuration {
Ok(Some(StratumOptions {
io_path: self.directories().db,
listen_addr: self.stratum_interface(),
port: self.args.flag_stratum_port,
port: self.args.flag_ports_shift + self.args.flag_stratum_port,
secret: self.args.flag_stratum_secret.as_ref().map(|s| s.parse::<H256>().unwrap_or_else(|_| s.sha3())),
}))
} else { Ok(None) }
@ -556,10 +556,10 @@ impl Configuration {
fn signer_config(&self) -> SignerConfiguration {
SignerConfiguration {
enabled: self.ui_enabled(),
port: self.args.flag_ui_port,
port: self.args.flag_ports_shift + self.args.flag_ui_port,
interface: self.ui_interface(),
signer_path: self.directories().signer,
skip_origin_validation: self.args.flag_ui_no_validation,
skip_origin_validation: self.args.flag_unsafe_expose || self.args.flag_ui_no_validation,
}
}
@ -581,9 +581,9 @@ impl Configuration {
self_secret: self.secretstore_self_secret()?,
nodes: self.secretstore_nodes()?,
interface: self.secretstore_interface(),
port: self.args.flag_secretstore_port,
port: self.args.flag_ports_shift + self.args.flag_secretstore_port,
http_interface: self.secretstore_http_interface(),
http_port: self.args.flag_secretstore_http_port,
http_port: self.args.flag_ports_shift + self.args.flag_secretstore_http_port,
data_path: self.directories().secretstore,
})
}
@ -591,7 +591,7 @@ impl Configuration {
fn ipfs_config(&self) -> IpfsConfiguration {
IpfsConfiguration {
enabled: self.args.flag_ipfs_api,
port: self.args.flag_ipfs_api_port,
port: self.args.flag_ports_shift + self.args.flag_ipfs_api_port,
interface: self.ipfs_interface(),
cors: self.ipfs_cors(),
hosts: self.ipfs_hosts(),
@ -674,9 +674,9 @@ impl Configuration {
}
}
fn net_addresses(&self) -> Result<(Option<SocketAddr>, Option<SocketAddr>), String> {
let port = self.args.flag_port;
let listen_address = Some(SocketAddr::new("0.0.0.0".parse().unwrap(), port));
fn net_addresses(&self) -> Result<(SocketAddr, Option<SocketAddr>), String> {
let port = self.args.flag_ports_shift + self.args.flag_port;
let listen_address = SocketAddr::new("0.0.0.0".parse().unwrap(), port);
let public_address = if self.args.flag_nat.starts_with("extip:") {
let host = &self.args.flag_nat[6..];
let host = host.parse().map_err(|_| format!("Invalid host given with `--nat extip:{}`", host))?;
@ -692,7 +692,7 @@ impl Configuration {
ret.nat_enabled = self.args.flag_nat == "any" || self.args.flag_nat == "upnp";
ret.boot_nodes = to_bootnodes(&self.args.flag_bootnodes)?;
let (listen, public) = self.net_addresses()?;
ret.listen_address = listen.map(|l| format!("{}", l));
ret.listen_address = Some(format!("{}", listen));
ret.public_address = public.map(|p| format!("{}", p));
ret.use_secret = match self.args.flag_node_key.as_ref()
.map(|s| s.parse::<Secret>().or_else(|_| Secret::from_unsafe_slice(&s.sha3())).map_err(|e| format!("Invalid key: {:?}", e))
@ -746,7 +746,19 @@ impl Configuration {
Self::cors(self.args.flag_ipfs_api_cors.as_ref())
}
fn hosts(hosts: &str) -> Option<Vec<String>> {
fn hosts(&self, hosts: &str, interface: &str) -> Option<Vec<String>> {
if self.args.flag_unsafe_expose {
return None;
}
if interface == "0.0.0.0" && hosts == "none" {
return None;
}
Self::parse_hosts(hosts)
}
fn parse_hosts(hosts: &str) -> Option<Vec<String>> {
match hosts {
"none" => return Some(Vec::new()),
"*" | "all" | "any" => return None,
@ -757,19 +769,19 @@ impl Configuration {
}
fn rpc_hosts(&self) -> Option<Vec<String>> {
Self::hosts(&self.args.flag_jsonrpc_hosts)
self.hosts(&self.args.flag_jsonrpc_hosts, &self.rpc_interface())
}
fn ws_hosts(&self) -> Option<Vec<String>> {
Self::hosts(&self.args.flag_ws_hosts)
self.hosts(&self.args.flag_ws_hosts, &self.ws_interface())
}
fn ws_origins(&self) -> Option<Vec<String>> {
Self::hosts(&self.args.flag_ws_origins)
Self::parse_hosts(&self.args.flag_ws_origins)
}
fn ipfs_hosts(&self) -> Option<Vec<String>> {
Self::hosts(&self.args.flag_ipfs_api_hosts)
self.hosts(&self.args.flag_ipfs_api_hosts, &self.ipfs_interface())
}
fn ipc_config(&self) -> Result<IpcConfiguration, String> {
@ -795,7 +807,7 @@ impl Configuration {
let conf = HttpConfiguration {
enabled: self.rpc_enabled(),
interface: self.rpc_interface(),
port: self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port),
port: self.args.flag_ports_shift + self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port),
apis: match self.args.flag_public_node {
false => self.rpc_apis().parse()?,
true => self.rpc_apis().parse::<ApiSet>()?.retain(ApiSet::PublicContext),
@ -816,7 +828,7 @@ impl Configuration {
let conf = WsConfiguration {
enabled: self.ws_enabled(),
interface: self.ws_interface(),
port: self.args.flag_ws_port,
port: self.args.flag_ports_shift + self.args.flag_ws_port,
apis: self.args.flag_ws_apis.parse()?,
hosts: self.ws_hosts(),
origins: self.ws_origins()
@ -825,15 +837,17 @@ impl Configuration {
Ok(conf)
}
fn network_settings(&self) -> NetworkSettings {
NetworkSettings {
fn network_settings(&self) -> Result<NetworkSettings, String> {
let http_conf = self.http_config()?;
let net_addresses = self.net_addresses()?;
Ok(NetworkSettings {
name: self.args.flag_identity.clone(),
chain: self.chain(),
network_port: self.args.flag_port,
rpc_enabled: self.rpc_enabled(),
rpc_interface: self.args.flag_rpcaddr.clone().unwrap_or(self.args.flag_jsonrpc_interface.clone()),
rpc_port: self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port),
}
network_port: net_addresses.0.port(),
rpc_enabled: http_conf.enabled,
rpc_interface: http_conf.interface,
rpc_port: http_conf.port,
})
}
fn update_policy(&self) -> Result<UpdatePolicy, String> {
@ -906,7 +920,11 @@ impl Configuration {
if self.args.flag_geth {
geth_ipc_path(self.args.flag_testnet)
} else {
parity_ipc_path(&self.directories().base, &self.args.flag_ipcpath.clone().unwrap_or(self.args.flag_ipc_path.clone()))
parity_ipc_path(
&self.directories().base,
&self.args.flag_ipcpath.clone().unwrap_or(self.args.flag_ipc_path.clone()),
self.args.flag_ports_shift,
)
}
}
@ -919,13 +937,14 @@ impl Configuration {
}
fn ui_interface(&self) -> String {
match self.args.flag_ui_interface.as_str() {
"local" => "127.0.0.1",
x => x,
}.into()
self.interface(&self.args.flag_ui_interface)
}
fn interface(interface: &str) -> String {
fn interface(&self, interface: &str) -> String {
if self.args.flag_unsafe_expose {
return "0.0.0.0".into();
}
match interface {
"all" => "0.0.0.0",
"local" => "127.0.0.1",
@ -934,23 +953,24 @@ impl Configuration {
}
fn rpc_interface(&self) -> String {
Self::interface(&self.network_settings().rpc_interface)
let rpc_interface = self.args.flag_rpcaddr.clone().unwrap_or(self.args.flag_jsonrpc_interface.clone());
self.interface(&rpc_interface)
}
fn ws_interface(&self) -> String {
Self::interface(&self.args.flag_ws_interface)
self.interface(&self.args.flag_ws_interface)
}
fn ipfs_interface(&self) -> String {
Self::interface(&self.args.flag_ipfs_api_interface)
self.interface(&self.args.flag_ipfs_api_interface)
}
fn secretstore_interface(&self) -> String {
Self::interface(&self.args.flag_secretstore_interface)
self.interface(&self.args.flag_secretstore_interface)
}
fn secretstore_http_interface(&self) -> String {
Self::interface(&self.args.flag_secretstore_http_interface)
self.interface(&self.args.flag_secretstore_http_interface)
}
fn secretstore_self_secret(&self) -> Result<Option<Secret>, String> {
@ -986,7 +1006,7 @@ impl Configuration {
}
fn stratum_interface(&self) -> String {
Self::interface(&self.args.flag_stratum_interface)
self.interface(&self.args.flag_stratum_interface)
}
fn rpc_enabled(&self) -> bool {
@ -1322,23 +1342,23 @@ mod tests {
let conf = parse(&["parity", "--testnet", "--identity", "testname"]);
// then
assert_eq!(conf.network_settings(), NetworkSettings {
assert_eq!(conf.network_settings(), Ok(NetworkSettings {
name: "testname".to_owned(),
chain: "testnet".to_owned(),
network_port: 30303,
rpc_enabled: true,
rpc_interface: "local".to_owned(),
rpc_interface: "127.0.0.1".to_owned(),
rpc_port: 8545,
});
}));
}
#[test]
fn should_parse_rpc_settings_with_geth_compatiblity() {
// given
fn assert(conf: Configuration) {
let net = conf.network_settings();
let net = conf.network_settings().unwrap();
assert_eq!(net.rpc_enabled, true);
assert_eq!(net.rpc_interface, "all".to_owned());
assert_eq!(net.rpc_interface, "0.0.0.0".to_owned());
assert_eq!(net.rpc_port, 8000);
assert_eq!(conf.rpc_cors(), Some(vec!["*".to_owned()]));
assert_eq!(conf.rpc_apis(), "web3,eth".to_owned());
@ -1516,4 +1536,57 @@ mod tests {
_ => panic!("Should be Cmd::Run"),
}
}
#[test]
fn should_apply_ports_shift() {
// given
// when
let conf0 = parse(&["parity", "--ports-shift", "1", "--stratum"]);
let conf1 = parse(&["parity", "--ports-shift", "1", "--jsonrpc-port", "8544"]);
// then
assert_eq!(conf0.net_addresses().unwrap().0.port(), 30304);
assert_eq!(conf0.network_settings().unwrap().network_port, 30304);
assert_eq!(conf0.network_settings().unwrap().rpc_port, 8546);
assert_eq!(conf0.http_config().unwrap().port, 8546);
assert_eq!(conf0.ws_config().unwrap().port, 8547);
assert_eq!(conf0.signer_config().port, 8181);
assert_eq!(conf0.secretstore_config().unwrap().port, 8084);
assert_eq!(conf0.secretstore_config().unwrap().http_port, 8083);
assert_eq!(conf0.ipfs_config().port, 5002);
assert_eq!(conf0.stratum_options().unwrap().unwrap().port, 8009);
assert_eq!(conf1.net_addresses().unwrap().0.port(), 30304);
assert_eq!(conf1.network_settings().unwrap().network_port, 30304);
assert_eq!(conf1.network_settings().unwrap().rpc_port, 8545);
assert_eq!(conf1.http_config().unwrap().port, 8545);
assert_eq!(conf1.ws_config().unwrap().port, 8547);
assert_eq!(conf1.signer_config().port, 8181);
assert_eq!(conf1.secretstore_config().unwrap().port, 8084);
assert_eq!(conf1.secretstore_config().unwrap().http_port, 8083);
assert_eq!(conf1.ipfs_config().port, 5002);
}
#[test]
fn should_expose_all_servers() {
// given
// when
let conf0 = parse(&["parity", "--unsafe-expose"]);
// then
assert_eq!(&conf0.network_settings().unwrap().rpc_interface, "0.0.0.0");
assert_eq!(&conf0.http_config().unwrap().interface, "0.0.0.0");
assert_eq!(conf0.http_config().unwrap().hosts, None);
assert_eq!(&conf0.ws_config().unwrap().interface, "0.0.0.0");
assert_eq!(conf0.ws_config().unwrap().hosts, None);
assert_eq!(&conf0.signer_config().interface, "0.0.0.0");
assert_eq!(conf0.signer_config().skip_origin_validation, true);
assert_eq!(&conf0.secretstore_config().unwrap().interface, "0.0.0.0");
assert_eq!(&conf0.secretstore_config().unwrap().http_interface, "0.0.0.0");
assert_eq!(&conf0.ipfs_config().interface, "0.0.0.0");
assert_eq!(conf0.ipfs_config().hosts, None);
}
}

View File

@ -166,13 +166,12 @@ pub fn geth_ipc_path(testnet: bool) -> String {
}
/// Formats and returns parity ipc path.
pub fn parity_ipc_path(base: &str, s: &str) -> String {
// Windows path should not be hardcoded here.
if cfg!(windows) {
return r"\\.\pipe\parity.jsonrpc".to_owned();
pub fn parity_ipc_path(base: &str, path: &str, shift: u16) -> String {
let mut path = path.to_owned();
if shift != 0 {
path = path.replace("jsonrpc.ipc", &format!("jsonrpc-{}.ipc", shift));
}
replace_home(base, s)
replace_home(base, &path)
}
/// Validates and formats bootnodes option.

View File

@ -18,7 +18,6 @@ use std::io;
use std::sync::Arc;
use dapps;
use dir::default_data_path;
use parity_rpc::informant::{RpcStats, Middleware};
use parity_rpc::{self as rpc, HttpServerError, Metadata, Origin, DomainsValidation};
use helpers::parity_ipc_path;
@ -63,10 +62,14 @@ pub struct IpcConfiguration {
impl Default for IpcConfiguration {
fn default() -> Self {
let data_dir = default_data_path();
IpcConfiguration {
enabled: true,
socket_addr: parity_ipc_path(&data_dir, "$BASE/jsonrpc.ipc"),
socket_addr: if cfg!(windows) {
r"\\.\pipe\jsonrpc.ipc".into()
} else {
let data_dir = ::dir::default_data_path();
parity_ipc_path(&data_dir, "$BASE/jsonrpc.ipc", 0)
},
apis: ApiSet::IpcContext,
}
}

View File

@ -39,7 +39,7 @@ impl Default for NetworkSettings {
chain: "foundation".into(),
network_port: 30303,
rpc_enabled: true,
rpc_interface: "local".into(),
rpc_interface: "127.0.0.1".into(),
rpc_port: 8545
}
}