Refactor --allow-ips to handle custom ip-ranges (#6144)
* Add checks for additional reserved ip addresses 100.64.0.0/10 and 240.0.0.0/4 are both reserved but not currently filtered. * Add check for special purpose addresses 192.0.0.0/24 - Used for the IANA IPv4 Special Purpose Address Registry * Refactor ip_utils (#5872) * Add checks for all ipv4 special use addresses * Add comprehensive ipv4 test cases * Refactor Ipv6 address checks (#5872) * Refactor AllowIP (#5872) * Add IpFilter struct to wrap predefined filter (AllowIP) with custom allow/block filters. * Refactor parsing of --allow-ips to handle custom filters. * Move AllowIP/IpFilter from ethsync to ethcore-network where they are used. * Revert Cargo.lock * Tests for custom ip filters (#5872) * Add "none" as a valid argument for --allow-ips to allow narrow custom ranges, eg.: --allow-ips="none 10.0.0.0/8" * Add tests for parsing filter arguments and node endpoints. * Add ipnetwork crate to dev dependencies for testing. * Add ipv6 filter tests (#5872) * Revert parity-ui-precompiled to master * Fix minor detail in usage.txt (#5872) * Spaces to tabs * Rename IpFilter::new() to ::default() * Small readability improvements * Test (#5872) * Revert "Test (#5872)" This reverts commit 7a8906430a6dad633fe29df3dca57f1630851fa9.
This commit is contained in:
parent
ad30a6899b
commit
b5f1524e78
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -656,6 +656,7 @@ dependencies = [
|
|||||||
"ethcrypto 0.1.0",
|
"ethcrypto 0.1.0",
|
||||||
"ethkey 0.2.0",
|
"ethkey 0.2.0",
|
||||||
"igd 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"igd 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ipnetwork 0.12.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"mio 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"mio 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -862,6 +863,7 @@ dependencies = [
|
|||||||
"ethcore-util 1.8.0",
|
"ethcore-util 1.8.0",
|
||||||
"ethkey 0.2.0",
|
"ethkey 0.2.0",
|
||||||
"heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ipnetwork 0.12.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1149,6 +1151,11 @@ dependencies = [
|
|||||||
"semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ipnetwork"
|
||||||
|
version = "0.12.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "isatty"
|
name = "isatty"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@ -1763,6 +1770,7 @@ dependencies = [
|
|||||||
"ethcore-ipc-tests 0.1.0",
|
"ethcore-ipc-tests 0.1.0",
|
||||||
"ethcore-light 1.8.0",
|
"ethcore-light 1.8.0",
|
||||||
"ethcore-logger 1.8.0",
|
"ethcore-logger 1.8.0",
|
||||||
|
"ethcore-network 1.8.0",
|
||||||
"ethcore-secretstore 1.0.0",
|
"ethcore-secretstore 1.0.0",
|
||||||
"ethcore-stratum 1.8.0",
|
"ethcore-stratum 1.8.0",
|
||||||
"ethcore-util 1.8.0",
|
"ethcore-util 1.8.0",
|
||||||
@ -1771,6 +1779,7 @@ dependencies = [
|
|||||||
"fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"futures-cpupool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures-cpupool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ipnetwork 0.12.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
||||||
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -3226,6 +3235,7 @@ dependencies = [
|
|||||||
"checksum igd 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "356a0dc23a4fa0f8ce4777258085d00a01ea4923b2efd93538fc44bf5e1bda76"
|
"checksum igd 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "356a0dc23a4fa0f8ce4777258085d00a01ea4923b2efd93538fc44bf5e1bda76"
|
||||||
"checksum integer-encoding 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a053c9c7dcb7db1f2aa012c37dc176c62e4cdf14898dee0eecc606de835b8acb"
|
"checksum integer-encoding 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a053c9c7dcb7db1f2aa012c37dc176c62e4cdf14898dee0eecc606de835b8acb"
|
||||||
"checksum iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29d062ee61fccdf25be172e70f34c9f6efc597e1fb8f6526e8437b2046ab26be"
|
"checksum iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29d062ee61fccdf25be172e70f34c9f6efc597e1fb8f6526e8437b2046ab26be"
|
||||||
|
"checksum ipnetwork 0.12.6 (registry+https://github.com/rust-lang/crates.io-index)" = "232e76922883005380e831068f731ef0305541c9f77b30df3a1635047b16f370"
|
||||||
"checksum isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7408a548dc0e406b7912d9f84c261cc533c1866e047644a811c133c56041ac0c"
|
"checksum isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7408a548dc0e406b7912d9f84c261cc533c1866e047644a811c133c56041ac0c"
|
||||||
"checksum itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d95557e7ba6b71377b0f2c3b3ae96c53f1b75a926a6901a500f557a370af730a"
|
"checksum itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d95557e7ba6b71377b0f2c3b3ae96c53f1b75a926a6901a500f557a370af730a"
|
||||||
"checksum itoa 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "91fd9dc2c587067de817fec4ad355e3818c3d893a78cab32a0a474c7a15bb8d5"
|
"checksum itoa 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "91fd9dc2c587067de817fec4ad355e3818c3d893a78cab32a0a474c7a15bb8d5"
|
||||||
|
@ -41,6 +41,7 @@ ethcore-ipc-hypervisor = { path = "ipc/hypervisor" }
|
|||||||
ethcore-light = { path = "ethcore/light" }
|
ethcore-light = { path = "ethcore/light" }
|
||||||
ethcore-logger = { path = "logger" }
|
ethcore-logger = { path = "logger" }
|
||||||
ethcore-stratum = { path = "stratum" }
|
ethcore-stratum = { path = "stratum" }
|
||||||
|
ethcore-network = { path = "util/network" }
|
||||||
ethkey = { path = "ethkey" }
|
ethkey = { path = "ethkey" }
|
||||||
rlp = { path = "util/rlp" }
|
rlp = { path = "util/rlp" }
|
||||||
rpc-cli = { path = "rpc_cli" }
|
rpc-cli = { path = "rpc_cli" }
|
||||||
@ -65,6 +66,7 @@ rustc_version = "0.2"
|
|||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
ethcore-ipc-tests = { path = "ipc/tests" }
|
ethcore-ipc-tests = { path = "ipc/tests" }
|
||||||
pretty_assertions = "0.1"
|
pretty_assertions = "0.1"
|
||||||
|
ipnetwork = "0.12.6"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winapi = "0.2"
|
winapi = "0.2"
|
||||||
|
@ -148,11 +148,15 @@ Networking Options:
|
|||||||
These nodes will always have a reserved slot on top
|
These nodes will always have a reserved slot on top
|
||||||
of the normal maximum peers. (default: {flag_reserved_peers:?})
|
of the normal maximum peers. (default: {flag_reserved_peers:?})
|
||||||
--reserved-only Connect only to reserved nodes. (default: {flag_reserved_only})
|
--reserved-only Connect only to reserved nodes. (default: {flag_reserved_only})
|
||||||
--allow-ips FILTER Filter outbound connections. Must be one of:
|
--allow-ips FILTER Filter outbound connections. FILTER can be one of:
|
||||||
private - connect to private network IP addresses only;
|
private - connect to private network IP addresses only;
|
||||||
public - connect to public network IP addresses only;
|
public - connect to public network IP addresses only;
|
||||||
all - connect to any IP address.
|
all - connect to any IP address;
|
||||||
(default: {flag_allow_ips})
|
none - block all (for use with a custom filter as below);
|
||||||
|
a custom filter list in the format: "private ip_range1 -ip_range2 ...".
|
||||||
|
Where ip_range1 would be allowed and ip_range2 blocked;
|
||||||
|
Custom blocks ("-ip_range") override custom allows ("ip_range");
|
||||||
|
(default: {flag_allow_ips}).
|
||||||
--max-pending-peers NUM Allow up to NUM pending connections. (default: {flag_max_pending_peers})
|
--max-pending-peers NUM Allow up to NUM pending connections. (default: {flag_max_pending_peers})
|
||||||
--no-ancient-blocks Disable downloading old blocks after snapshot restoration
|
--no-ancient-blocks Disable downloading old blocks after snapshot restoration
|
||||||
or warp sync. (default: {flag_no_ancient_blocks})
|
or warp sync. (default: {flag_no_ancient_blocks})
|
||||||
|
@ -24,7 +24,7 @@ use cli::{Args, ArgsError};
|
|||||||
use util::{Hashable, H256, U256, Bytes, version_data, Address};
|
use util::{Hashable, H256, U256, Bytes, version_data, Address};
|
||||||
use util::journaldb::Algorithm;
|
use util::journaldb::Algorithm;
|
||||||
use util::Colour;
|
use util::Colour;
|
||||||
use ethsync::{NetworkConfiguration, is_valid_node_url, AllowIP};
|
use ethsync::{NetworkConfiguration, is_valid_node_url};
|
||||||
use ethcore::ethstore::ethkey::{Secret, Public};
|
use ethcore::ethstore::ethkey::{Secret, Public};
|
||||||
use ethcore::client::{VMType};
|
use ethcore::client::{VMType};
|
||||||
use ethcore::miner::{MinerOptions, Banning, StratumOptions};
|
use ethcore::miner::{MinerOptions, Banning, StratumOptions};
|
||||||
@ -48,6 +48,7 @@ use blockchain::{BlockchainCmd, ImportBlockchain, ExportBlockchain, KillBlockcha
|
|||||||
use presale::ImportWallet;
|
use presale::ImportWallet;
|
||||||
use account::{AccountCmd, NewAccount, ListAccounts, ImportAccounts, ImportFromGethAccounts};
|
use account::{AccountCmd, NewAccount, ListAccounts, ImportAccounts, ImportFromGethAccounts};
|
||||||
use snapshot::{self, SnapshotCommand};
|
use snapshot::{self, SnapshotCommand};
|
||||||
|
use network::{IpFilter};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Cmd {
|
pub enum Cmd {
|
||||||
@ -461,12 +462,10 @@ impl Configuration {
|
|||||||
max(self.min_peers(), peers)
|
max(self.min_peers(), peers)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allow_ips(&self) -> Result<AllowIP, String> {
|
fn ip_filter(&self) -> Result<IpFilter, String> {
|
||||||
match self.args.flag_allow_ips.as_str() {
|
match IpFilter::parse(self.args.flag_allow_ips.as_str()) {
|
||||||
"all" => Ok(AllowIP::All),
|
Ok(allow_ip) => Ok(allow_ip),
|
||||||
"public" => Ok(AllowIP::Public),
|
Err(_) => Err("Invalid IP filter value".to_owned()),
|
||||||
"private" => Ok(AllowIP::Private),
|
|
||||||
_ => Err("Invalid IP filter value".to_owned()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -712,7 +711,7 @@ impl Configuration {
|
|||||||
ret.max_peers = self.max_peers();
|
ret.max_peers = self.max_peers();
|
||||||
ret.min_peers = self.min_peers();
|
ret.min_peers = self.min_peers();
|
||||||
ret.snapshot_peers = self.snapshot_peers();
|
ret.snapshot_peers = self.snapshot_peers();
|
||||||
ret.allow_ips = self.allow_ips()?;
|
ret.ip_filter = self.ip_filter()?;
|
||||||
ret.max_pending_peers = self.max_pending_peers();
|
ret.max_pending_peers = self.max_pending_peers();
|
||||||
let mut net_path = PathBuf::from(self.directories().base);
|
let mut net_path = PathBuf::from(self.directories().base);
|
||||||
net_path.push("network");
|
net_path.push("network");
|
||||||
@ -968,7 +967,6 @@ impl Configuration {
|
|||||||
}.into()
|
}.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn ui_interface(&self) -> String {
|
fn ui_interface(&self) -> String {
|
||||||
self.interface(&self.args.flag_ui_interface)
|
self.interface(&self.args.flag_ui_interface)
|
||||||
}
|
}
|
||||||
@ -1080,6 +1078,7 @@ impl Configuration {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::fs::{File, create_dir};
|
use std::fs::{File, create_dir};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
use devtools::{RandomTempPath};
|
use devtools::{RandomTempPath};
|
||||||
use ethcore::client::{VMType, BlockId};
|
use ethcore::client::{VMType, BlockId};
|
||||||
@ -1097,6 +1096,11 @@ mod tests {
|
|||||||
use rpc::{WsConfiguration, UiConfiguration};
|
use rpc::{WsConfiguration, UiConfiguration};
|
||||||
use run::RunCmd;
|
use run::RunCmd;
|
||||||
|
|
||||||
|
use network::{AllowIP, IpFilter};
|
||||||
|
|
||||||
|
extern crate ipnetwork;
|
||||||
|
use self::ipnetwork::IpNetwork;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
@ -1752,4 +1756,50 @@ mod tests {
|
|||||||
assert_eq!(&conf0.ipfs_config().interface, "0.0.0.0");
|
assert_eq!(&conf0.ipfs_config().interface, "0.0.0.0");
|
||||||
assert_eq!(conf0.ipfs_config().hosts, None);
|
assert_eq!(conf0.ipfs_config().hosts, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn allow_ips() {
|
||||||
|
let all = parse(&["parity", "--allow-ips", "all"]);
|
||||||
|
let private = parse(&["parity", "--allow-ips", "private"]);
|
||||||
|
let block_custom = parse(&["parity", "--allow-ips", "-10.0.0.0/8"]);
|
||||||
|
let combo = parse(&["parity", "--allow-ips", "public 10.0.0.0/8 -1.0.0.0/8"]);
|
||||||
|
let ipv6_custom_public = parse(&["parity", "--allow-ips", "public fc00::/7"]);
|
||||||
|
let ipv6_custom_private = parse(&["parity", "--allow-ips", "private -fc00::/7"]);
|
||||||
|
|
||||||
|
assert_eq!(all.ip_filter().unwrap(), IpFilter {
|
||||||
|
predefined: AllowIP::All,
|
||||||
|
custom_allow: vec![],
|
||||||
|
custom_block: vec![],
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(private.ip_filter().unwrap(), IpFilter {
|
||||||
|
predefined: AllowIP::Private,
|
||||||
|
custom_allow: vec![],
|
||||||
|
custom_block: vec![],
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(block_custom.ip_filter().unwrap(), IpFilter {
|
||||||
|
predefined: AllowIP::All,
|
||||||
|
custom_allow: vec![],
|
||||||
|
custom_block: vec![IpNetwork::from_str("10.0.0.0/8").unwrap()],
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(combo.ip_filter().unwrap(), IpFilter {
|
||||||
|
predefined: AllowIP::Public,
|
||||||
|
custom_allow: vec![IpNetwork::from_str("10.0.0.0/8").unwrap()],
|
||||||
|
custom_block: vec![IpNetwork::from_str("1.0.0.0/8").unwrap()],
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(ipv6_custom_public.ip_filter().unwrap(), IpFilter {
|
||||||
|
predefined: AllowIP::Public,
|
||||||
|
custom_allow: vec![IpNetwork::from_str("fc00::/7").unwrap()],
|
||||||
|
custom_block: vec![],
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(ipv6_custom_private.ip_filter().unwrap(), IpFilter {
|
||||||
|
predefined: AllowIP::Private,
|
||||||
|
custom_allow: vec![],
|
||||||
|
custom_block: vec![IpNetwork::from_str("fc00::/7").unwrap()],
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,8 @@ pub fn to_bootnodes(bootnodes: &Option<String>) -> Result<Vec<String>, String> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn default_network_config() -> ::ethsync::NetworkConfiguration {
|
pub fn default_network_config() -> ::ethsync::NetworkConfiguration {
|
||||||
use ethsync::{NetworkConfiguration, AllowIP};
|
use ethsync::{NetworkConfiguration};
|
||||||
|
use super::network::IpFilter;
|
||||||
NetworkConfiguration {
|
NetworkConfiguration {
|
||||||
config_path: Some(replace_home(&::dir::default_data_path(), "$BASE/network")),
|
config_path: Some(replace_home(&::dir::default_data_path(), "$BASE/network")),
|
||||||
net_config_path: None,
|
net_config_path: None,
|
||||||
@ -206,7 +207,7 @@ pub fn default_network_config() -> ::ethsync::NetworkConfiguration {
|
|||||||
min_peers: 25,
|
min_peers: 25,
|
||||||
snapshot_peers: 0,
|
snapshot_peers: 0,
|
||||||
max_pending_peers: 64,
|
max_pending_peers: 64,
|
||||||
allow_ips: AllowIP::All,
|
ip_filter: IpFilter::default(),
|
||||||
reserved_nodes: Vec::new(),
|
reserved_nodes: Vec::new(),
|
||||||
allow_non_reserved: true,
|
allow_non_reserved: true,
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,7 @@ extern crate ethcore_ipc_nano as nanoipc;
|
|||||||
extern crate ethcore_light as light;
|
extern crate ethcore_light as light;
|
||||||
extern crate ethcore_logger;
|
extern crate ethcore_logger;
|
||||||
extern crate ethcore_util as util;
|
extern crate ethcore_util as util;
|
||||||
|
extern crate ethcore_network as network;
|
||||||
extern crate ethkey;
|
extern crate ethkey;
|
||||||
extern crate ethsync;
|
extern crate ethsync;
|
||||||
extern crate panic_hook;
|
extern crate panic_hook;
|
||||||
|
@ -31,6 +31,7 @@ ethcore-ipc-nano = { path = "../ipc/nano" }
|
|||||||
ethcore-devtools = { path = "../devtools" }
|
ethcore-devtools = { path = "../devtools" }
|
||||||
ethkey = { path = "../ethkey" }
|
ethkey = { path = "../ethkey" }
|
||||||
parking_lot = "0.4"
|
parking_lot = "0.4"
|
||||||
|
ipnetwork = "0.12.6"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
|
@ -19,8 +19,7 @@ use std::collections::{HashMap, BTreeMap};
|
|||||||
use std::io;
|
use std::io;
|
||||||
use util::Bytes;
|
use util::Bytes;
|
||||||
use network::{NetworkProtocolHandler, NetworkService, NetworkContext, HostInfo, PeerId, ProtocolId,
|
use network::{NetworkProtocolHandler, NetworkService, NetworkContext, HostInfo, PeerId, ProtocolId,
|
||||||
NetworkConfiguration as BasicNetworkConfiguration, NonReservedPeerMode, NetworkError,
|
NetworkConfiguration as BasicNetworkConfiguration, NonReservedPeerMode, NetworkError};
|
||||||
AllowIP as NetworkAllowIP};
|
|
||||||
use util::{U256, H256, H512};
|
use util::{U256, H256, H512};
|
||||||
use io::{TimerToken};
|
use io::{TimerToken};
|
||||||
use ethcore::ethstore::ethkey::Secret;
|
use ethcore::ethstore::ethkey::Secret;
|
||||||
@ -37,6 +36,7 @@ use chain::{ETH_PACKET_COUNT, SNAPSHOT_SYNC_PACKET_COUNT};
|
|||||||
use light::client::AsLightClient;
|
use light::client::AsLightClient;
|
||||||
use light::Provider;
|
use light::Provider;
|
||||||
use light::net::{self as light_net, LightProtocol, Params as LightParams, Capabilities, Handler as LightHandler, EventContext};
|
use light::net::{self as light_net, LightProtocol, Params as LightParams, Capabilities, Handler as LightHandler, EventContext};
|
||||||
|
use network::IpFilter;
|
||||||
|
|
||||||
/// Parity sync protocol
|
/// Parity sync protocol
|
||||||
pub const WARP_SYNC_PROTOCOL_ID: ProtocolId = *b"par";
|
pub const WARP_SYNC_PROTOCOL_ID: ProtocolId = *b"par";
|
||||||
@ -539,30 +539,6 @@ impl ManageNetwork for EthSync {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// IP fiter
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
||||||
#[cfg_attr(feature = "ipc", binary)]
|
|
||||||
pub enum AllowIP {
|
|
||||||
/// Connect to any address
|
|
||||||
All,
|
|
||||||
/// Connect to private network only
|
|
||||||
Private,
|
|
||||||
/// Connect to public network only
|
|
||||||
Public,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AllowIP {
|
|
||||||
/// Attempt to parse the peer mode from a string.
|
|
||||||
pub fn parse(s: &str) -> Option<Self> {
|
|
||||||
match s {
|
|
||||||
"all" => Some(AllowIP::All),
|
|
||||||
"private" => Some(AllowIP::Private),
|
|
||||||
"public" => Some(AllowIP::Public),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "ipc", binary)]
|
#[cfg_attr(feature = "ipc", binary)]
|
||||||
/// Network service configuration
|
/// Network service configuration
|
||||||
@ -598,7 +574,7 @@ pub struct NetworkConfiguration {
|
|||||||
/// The non-reserved peer mode.
|
/// The non-reserved peer mode.
|
||||||
pub allow_non_reserved: bool,
|
pub allow_non_reserved: bool,
|
||||||
/// IP Filtering
|
/// IP Filtering
|
||||||
pub allow_ips: AllowIP,
|
pub ip_filter: IpFilter,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NetworkConfiguration {
|
impl NetworkConfiguration {
|
||||||
@ -629,11 +605,7 @@ impl NetworkConfiguration {
|
|||||||
max_handshakes: self.max_pending_peers,
|
max_handshakes: self.max_pending_peers,
|
||||||
reserved_protocols: hash_map![WARP_SYNC_PROTOCOL_ID => self.snapshot_peers],
|
reserved_protocols: hash_map![WARP_SYNC_PROTOCOL_ID => self.snapshot_peers],
|
||||||
reserved_nodes: self.reserved_nodes,
|
reserved_nodes: self.reserved_nodes,
|
||||||
allow_ips: match self.allow_ips {
|
ip_filter: self.ip_filter,
|
||||||
AllowIP::All => NetworkAllowIP::All,
|
|
||||||
AllowIP::Private => NetworkAllowIP::Private,
|
|
||||||
AllowIP::Public => NetworkAllowIP::Public,
|
|
||||||
},
|
|
||||||
non_reserved_mode: if self.allow_non_reserved { NonReservedPeerMode::Accept } else { NonReservedPeerMode::Deny },
|
non_reserved_mode: if self.allow_non_reserved { NonReservedPeerMode::Accept } else { NonReservedPeerMode::Deny },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -656,11 +628,7 @@ impl From<BasicNetworkConfiguration> for NetworkConfiguration {
|
|||||||
max_pending_peers: other.max_handshakes,
|
max_pending_peers: other.max_handshakes,
|
||||||
snapshot_peers: *other.reserved_protocols.get(&WARP_SYNC_PROTOCOL_ID).unwrap_or(&0),
|
snapshot_peers: *other.reserved_protocols.get(&WARP_SYNC_PROTOCOL_ID).unwrap_or(&0),
|
||||||
reserved_nodes: other.reserved_nodes,
|
reserved_nodes: other.reserved_nodes,
|
||||||
allow_ips: match other.allow_ips {
|
ip_filter: other.ip_filter,
|
||||||
NetworkAllowIP::All => AllowIP::All,
|
|
||||||
NetworkAllowIP::Private => AllowIP::Private,
|
|
||||||
NetworkAllowIP::Public => AllowIP::Public,
|
|
||||||
},
|
|
||||||
allow_non_reserved: match other.non_reserved_mode { NonReservedPeerMode::Accept => true, _ => false } ,
|
allow_non_reserved: match other.non_reserved_mode { NonReservedPeerMode::Accept => true, _ => false } ,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@ extern crate semver;
|
|||||||
extern crate parking_lot;
|
extern crate parking_lot;
|
||||||
extern crate smallvec;
|
extern crate smallvec;
|
||||||
extern crate rlp;
|
extern crate rlp;
|
||||||
|
extern crate ipnetwork;
|
||||||
|
|
||||||
extern crate ethcore_light as light;
|
extern crate ethcore_light as light;
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ ethcrypto = { path = "../../ethcrypto" }
|
|||||||
rlp = { path = "../rlp" }
|
rlp = { path = "../rlp" }
|
||||||
path = { path = "../path" }
|
path = { path = "../path" }
|
||||||
ethcore-logger = { path ="../../logger" }
|
ethcore-logger = { path ="../../logger" }
|
||||||
|
ipnetwork = "0.12.6"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
|
@ -30,7 +30,7 @@ use node_table::*;
|
|||||||
use error::NetworkError;
|
use error::NetworkError;
|
||||||
use io::{StreamToken, IoContext};
|
use io::{StreamToken, IoContext};
|
||||||
use ethkey::{Secret, KeyPair, sign, recover};
|
use ethkey::{Secret, KeyPair, sign, recover};
|
||||||
use AllowIP;
|
use IpFilter;
|
||||||
|
|
||||||
use PROTOCOL_VERSION;
|
use PROTOCOL_VERSION;
|
||||||
|
|
||||||
@ -99,7 +99,7 @@ pub struct Discovery {
|
|||||||
send_queue: VecDeque<Datagramm>,
|
send_queue: VecDeque<Datagramm>,
|
||||||
check_timestamps: bool,
|
check_timestamps: bool,
|
||||||
adding_nodes: Vec<NodeEntry>,
|
adding_nodes: Vec<NodeEntry>,
|
||||||
allow_ips: AllowIP,
|
ip_filter: IpFilter,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TableUpdates {
|
pub struct TableUpdates {
|
||||||
@ -108,7 +108,7 @@ pub struct TableUpdates {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Discovery {
|
impl Discovery {
|
||||||
pub fn new(key: &KeyPair, listen: SocketAddr, public: NodeEndpoint, token: StreamToken, allow_ips: AllowIP) -> Discovery {
|
pub fn new(key: &KeyPair, listen: SocketAddr, public: NodeEndpoint, token: StreamToken, ip_filter: IpFilter) -> Discovery {
|
||||||
let socket = UdpSocket::bind(&listen).expect("Error binding UDP socket");
|
let socket = UdpSocket::bind(&listen).expect("Error binding UDP socket");
|
||||||
Discovery {
|
Discovery {
|
||||||
id: key.public().clone(),
|
id: key.public().clone(),
|
||||||
@ -124,7 +124,7 @@ impl Discovery {
|
|||||||
send_queue: VecDeque::new(),
|
send_queue: VecDeque::new(),
|
||||||
check_timestamps: true,
|
check_timestamps: true,
|
||||||
adding_nodes: Vec::new(),
|
adding_nodes: Vec::new(),
|
||||||
allow_ips: allow_ips,
|
ip_filter: ip_filter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,7 +400,7 @@ impl Discovery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_allowed(&self, entry: &NodeEntry) -> bool {
|
fn is_allowed(&self, entry: &NodeEntry) -> bool {
|
||||||
entry.endpoint.is_allowed(self.allow_ips) && entry.id != self.id
|
entry.endpoint.is_allowed(&self.ip_filter) && entry.id != self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_ping(&mut self, rlp: &UntrustedRlp, node: &NodeId, from: &SocketAddr) -> Result<Option<TableUpdates>, NetworkError> {
|
fn on_ping(&mut self, rlp: &UntrustedRlp, node: &NodeId, from: &SocketAddr) -> Result<Option<TableUpdates>, NetworkError> {
|
||||||
@ -561,7 +561,6 @@ mod tests {
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use rustc_hex::FromHex;
|
use rustc_hex::FromHex;
|
||||||
use ethkey::{Random, Generator};
|
use ethkey::{Random, Generator};
|
||||||
use AllowIP;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn find_node() {
|
fn find_node() {
|
||||||
@ -586,8 +585,8 @@ mod tests {
|
|||||||
let key2 = Random.generate().unwrap();
|
let key2 = Random.generate().unwrap();
|
||||||
let ep1 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40444").unwrap(), udp_port: 40444 };
|
let ep1 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40444").unwrap(), udp_port: 40444 };
|
||||||
let ep2 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40445").unwrap(), udp_port: 40445 };
|
let ep2 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40445").unwrap(), udp_port: 40445 };
|
||||||
let mut discovery1 = Discovery::new(&key1, ep1.address.clone(), ep1.clone(), 0, AllowIP::All);
|
let mut discovery1 = Discovery::new(&key1, ep1.address.clone(), ep1.clone(), 0, IpFilter::default());
|
||||||
let mut discovery2 = Discovery::new(&key2, ep2.address.clone(), ep2.clone(), 0, AllowIP::All);
|
let mut discovery2 = Discovery::new(&key2, ep2.address.clone(), ep2.clone(), 0, IpFilter::default());
|
||||||
|
|
||||||
let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7770").unwrap();
|
let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7770").unwrap();
|
||||||
let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7771").unwrap();
|
let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7771").unwrap();
|
||||||
@ -619,7 +618,7 @@ mod tests {
|
|||||||
fn removes_expired() {
|
fn removes_expired() {
|
||||||
let key = Random.generate().unwrap();
|
let key = Random.generate().unwrap();
|
||||||
let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40446").unwrap(), udp_port: 40447 };
|
let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40446").unwrap(), udp_port: 40447 };
|
||||||
let mut discovery = Discovery::new(&key, ep.address.clone(), ep.clone(), 0, AllowIP::All);
|
let mut discovery = Discovery::new(&key, ep.address.clone(), ep.clone(), 0, IpFilter::default());
|
||||||
for _ in 0..1200 {
|
for _ in 0..1200 {
|
||||||
discovery.add_node(NodeEntry { id: NodeId::random(), endpoint: ep.clone() });
|
discovery.add_node(NodeEntry { id: NodeId::random(), endpoint: ep.clone() });
|
||||||
}
|
}
|
||||||
@ -648,7 +647,7 @@ mod tests {
|
|||||||
fn packets() {
|
fn packets() {
|
||||||
let key = Random.generate().unwrap();
|
let key = Random.generate().unwrap();
|
||||||
let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40447").unwrap(), udp_port: 40447 };
|
let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40447").unwrap(), udp_port: 40447 };
|
||||||
let mut discovery = Discovery::new(&key, ep.address.clone(), ep.clone(), 0, AllowIP::All);
|
let mut discovery = Discovery::new(&key, ep.address.clone(), ep.clone(), 0, IpFilter::default());
|
||||||
discovery.check_timestamps = false;
|
discovery.check_timestamps = false;
|
||||||
let from = SocketAddr::from_str("99.99.99.99:40445").unwrap();
|
let from = SocketAddr::from_str("99.99.99.99:40445").unwrap();
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ use rlp::*;
|
|||||||
use session::{Session, SessionInfo, SessionData};
|
use session::{Session, SessionInfo, SessionData};
|
||||||
use error::*;
|
use error::*;
|
||||||
use io::*;
|
use io::*;
|
||||||
use {NetworkProtocolHandler, NonReservedPeerMode, AllowIP, PROTOCOL_VERSION};
|
use {NetworkProtocolHandler, NonReservedPeerMode, PROTOCOL_VERSION, IpFilter};
|
||||||
use node_table::*;
|
use node_table::*;
|
||||||
use stats::NetworkStats;
|
use stats::NetworkStats;
|
||||||
use discovery::{Discovery, TableUpdates, NodeEntry};
|
use discovery::{Discovery, TableUpdates, NodeEntry};
|
||||||
@ -106,7 +106,7 @@ pub struct NetworkConfiguration {
|
|||||||
/// The non-reserved peer mode.
|
/// The non-reserved peer mode.
|
||||||
pub non_reserved_mode: NonReservedPeerMode,
|
pub non_reserved_mode: NonReservedPeerMode,
|
||||||
/// IP filter
|
/// IP filter
|
||||||
pub allow_ips: AllowIP,
|
pub ip_filter: IpFilter,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for NetworkConfiguration {
|
impl Default for NetworkConfiguration {
|
||||||
@ -132,7 +132,7 @@ impl NetworkConfiguration {
|
|||||||
max_peers: 50,
|
max_peers: 50,
|
||||||
max_handshakes: 64,
|
max_handshakes: 64,
|
||||||
reserved_protocols: HashMap::new(),
|
reserved_protocols: HashMap::new(),
|
||||||
allow_ips: AllowIP::All,
|
ip_filter: IpFilter::default(),
|
||||||
reserved_nodes: Vec::new(),
|
reserved_nodes: Vec::new(),
|
||||||
non_reserved_mode: NonReservedPeerMode::Accept,
|
non_reserved_mode: NonReservedPeerMode::Accept,
|
||||||
}
|
}
|
||||||
@ -566,7 +566,7 @@ impl Host {
|
|||||||
}
|
}
|
||||||
let local_endpoint = self.info.read().local_endpoint.clone();
|
let local_endpoint = self.info.read().local_endpoint.clone();
|
||||||
let public_address = self.info.read().config.public_address.clone();
|
let public_address = self.info.read().config.public_address.clone();
|
||||||
let allow_ips = self.info.read().config.allow_ips;
|
let allow_ips = self.info.read().config.ip_filter.clone();
|
||||||
let public_endpoint = match public_address {
|
let public_endpoint = match public_address {
|
||||||
None => {
|
None => {
|
||||||
let public_address = select_public_address(local_endpoint.address.port());
|
let public_address = select_public_address(local_endpoint.address.port());
|
||||||
@ -660,7 +660,7 @@ impl Host {
|
|||||||
}
|
}
|
||||||
let config = &info.config;
|
let config = &info.config;
|
||||||
|
|
||||||
(config.min_peers, config.non_reserved_mode == NonReservedPeerMode::Deny, config.max_handshakes as usize, config.allow_ips, info.id().clone())
|
(config.min_peers, config.non_reserved_mode == NonReservedPeerMode::Deny, config.max_handshakes as usize, config.ip_filter.clone(), info.id().clone())
|
||||||
};
|
};
|
||||||
|
|
||||||
let session_count = self.session_count();
|
let session_count = self.session_count();
|
||||||
|
@ -21,55 +21,193 @@ use std::io;
|
|||||||
use igd::{PortMappingProtocol, search_gateway_from_timeout};
|
use igd::{PortMappingProtocol, search_gateway_from_timeout};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use node_table::{NodeEndpoint};
|
use node_table::{NodeEndpoint};
|
||||||
|
use ipnetwork::{IpNetwork};
|
||||||
|
|
||||||
/// Socket address extension for rustc beta. To be replaces with now unstable API
|
/// Socket address extension for rustc beta. To be replaces with now unstable API
|
||||||
pub trait SocketAddrExt {
|
pub trait SocketAddrExt {
|
||||||
/// Returns true for the special 'unspecified' address 0.0.0.0.
|
|
||||||
fn is_unspecified_s(&self) -> bool;
|
|
||||||
/// Returns true if the address appears to be globally routable.
|
/// Returns true if the address appears to be globally routable.
|
||||||
fn is_global_s(&self) -> bool;
|
fn is_global_s(&self) -> bool;
|
||||||
|
|
||||||
|
// Ipv4 specific
|
||||||
|
fn is_shared_space(&self) -> bool { false }
|
||||||
|
fn is_special_purpose(&self) -> bool { false }
|
||||||
|
fn is_benchmarking(&self) -> bool { false }
|
||||||
|
fn is_future_use(&self) -> bool { false }
|
||||||
|
|
||||||
|
// Ipv6 specific
|
||||||
|
fn is_unique_local_s(&self) -> bool { false }
|
||||||
|
fn is_unicast_link_local_s(&self) -> bool { false }
|
||||||
|
fn is_documentation_s(&self) -> bool { false }
|
||||||
|
fn is_global_multicast(&self) -> bool { false }
|
||||||
|
fn is_other_multicast(&self) -> bool { false }
|
||||||
|
|
||||||
|
fn is_reserved(&self) -> bool;
|
||||||
|
fn is_usable_public(&self) -> bool;
|
||||||
|
fn is_usable_private(&self) -> bool;
|
||||||
|
|
||||||
|
fn is_within(&self, ipnet: &IpNetwork) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SocketAddrExt for Ipv4Addr {
|
impl SocketAddrExt for Ipv4Addr {
|
||||||
fn is_unspecified_s(&self) -> bool {
|
fn is_global_s(&self) -> bool {
|
||||||
self.octets() == [0, 0, 0, 0]
|
!self.is_private() &&
|
||||||
|
!self.is_loopback() &&
|
||||||
|
!self.is_link_local() &&
|
||||||
|
!self.is_broadcast() &&
|
||||||
|
!self.is_documentation()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_global_s(&self) -> bool {
|
// Used for communications between a service provider and its subscribers when using a carrier-grade NAT
|
||||||
!self.is_private() && !self.is_loopback() && !self.is_link_local() &&
|
// see: https://en.wikipedia.org/wiki/Reserved_IP_addresses
|
||||||
!self.is_broadcast() && !self.is_documentation()
|
fn is_shared_space(&self) -> bool {
|
||||||
|
*self >= Ipv4Addr::new(100, 64, 0, 0) &&
|
||||||
|
*self <= Ipv4Addr::new(100, 127, 255, 255)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used for the IANA IPv4 Special Purpose Address Registry
|
||||||
|
// see: https://en.wikipedia.org/wiki/Reserved_IP_addresses
|
||||||
|
fn is_special_purpose(&self) -> bool {
|
||||||
|
*self >= Ipv4Addr::new(192, 0, 0, 0) &&
|
||||||
|
*self <= Ipv4Addr::new(192, 0, 0, 255)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used for testing of inter-network communications between two separate subnets
|
||||||
|
// see: https://en.wikipedia.org/wiki/Reserved_IP_addresses
|
||||||
|
fn is_benchmarking(&self) -> bool {
|
||||||
|
*self >= Ipv4Addr::new(198, 18, 0, 0) &&
|
||||||
|
*self <= Ipv4Addr::new(198, 19, 255, 255)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reserved for future use
|
||||||
|
// see: https://en.wikipedia.org/wiki/Reserved_IP_addresses
|
||||||
|
fn is_future_use(&self) -> bool {
|
||||||
|
*self >= Ipv4Addr::new(240, 0, 0, 0) &&
|
||||||
|
*self <= Ipv4Addr::new(255, 255, 255, 254)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_reserved(&self) -> bool {
|
||||||
|
self.is_unspecified() ||
|
||||||
|
self.is_loopback() ||
|
||||||
|
self.is_link_local() ||
|
||||||
|
self.is_broadcast() ||
|
||||||
|
self.is_documentation() ||
|
||||||
|
self.is_multicast() ||
|
||||||
|
self.is_shared_space() ||
|
||||||
|
self.is_special_purpose() ||
|
||||||
|
self.is_benchmarking() ||
|
||||||
|
self.is_future_use()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_usable_public(&self) -> bool {
|
||||||
|
!self.is_reserved() &&
|
||||||
|
!self.is_private()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_usable_private(&self) -> bool {
|
||||||
|
self.is_private()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_within(&self, ipnet: &IpNetwork) -> bool {
|
||||||
|
match ipnet {
|
||||||
|
&IpNetwork::V4(ipnet) => ipnet.contains(*self),
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SocketAddrExt for Ipv6Addr {
|
impl SocketAddrExt for Ipv6Addr {
|
||||||
fn is_unspecified_s(&self) -> bool {
|
fn is_global_s(&self) -> bool {
|
||||||
self.segments() == [0, 0, 0, 0, 0, 0, 0, 0]
|
self.is_global_multicast() ||
|
||||||
|
(!self.is_loopback() &&
|
||||||
|
!self.is_unique_local_s() &&
|
||||||
|
!self.is_unicast_link_local_s() &&
|
||||||
|
!self.is_documentation_s() &&
|
||||||
|
!self.is_other_multicast())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_global_s(&self) -> bool {
|
// unique local address (fc00::/7).
|
||||||
if self.is_multicast() {
|
fn is_unique_local_s(&self) -> bool {
|
||||||
self.segments()[0] & 0x000f == 14
|
(self.segments()[0] & 0xfe00) == 0xfc00
|
||||||
} else {
|
}
|
||||||
!self.is_loopback() && !((self.segments()[0] & 0xffc0) == 0xfe80) &&
|
|
||||||
!((self.segments()[0] & 0xffc0) == 0xfec0) && !((self.segments()[0] & 0xfe00) == 0xfc00)
|
// unicast and link-local (fe80::/10).
|
||||||
|
fn is_unicast_link_local_s(&self) -> bool {
|
||||||
|
(self.segments()[0] & 0xffc0) == 0xfe80
|
||||||
|
}
|
||||||
|
|
||||||
|
// reserved for documentation (2001:db8::/32).
|
||||||
|
fn is_documentation_s(&self) -> bool {
|
||||||
|
(self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_global_multicast(&self) -> bool {
|
||||||
|
self.segments()[0] & 0x000f == 14
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_other_multicast(&self) -> bool {
|
||||||
|
self.is_multicast() && !self.is_global_multicast()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_reserved(&self) -> bool {
|
||||||
|
self.is_unspecified() ||
|
||||||
|
self.is_loopback() ||
|
||||||
|
self.is_unicast_link_local_s() ||
|
||||||
|
self.is_documentation_s() ||
|
||||||
|
self.is_other_multicast()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_usable_public(&self) -> bool {
|
||||||
|
!self.is_reserved() &&
|
||||||
|
!self.is_unique_local_s()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_usable_private(&self) -> bool {
|
||||||
|
self.is_unique_local_s()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_within(&self, ipnet: &IpNetwork) -> bool {
|
||||||
|
match ipnet {
|
||||||
|
&IpNetwork::V6(ipnet) => ipnet.contains(*self),
|
||||||
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SocketAddrExt for IpAddr {
|
impl SocketAddrExt for IpAddr {
|
||||||
fn is_unspecified_s(&self) -> bool {
|
|
||||||
match *self {
|
|
||||||
IpAddr::V4(ref ip) => ip.is_unspecified_s(),
|
|
||||||
IpAddr::V6(ref ip) => ip.is_unspecified_s(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_global_s(&self) -> bool {
|
fn is_global_s(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
IpAddr::V4(ref ip) => ip.is_global_s(),
|
IpAddr::V4(ref ip) => ip.is_global_s(),
|
||||||
IpAddr::V6(ref ip) => ip.is_global_s(),
|
IpAddr::V6(ref ip) => ip.is_global_s(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_reserved(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
IpAddr::V4(ref ip) => ip.is_reserved(),
|
||||||
|
IpAddr::V6(ref ip) => ip.is_reserved(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_usable_public(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
IpAddr::V4(ref ip) => ip.is_usable_public(),
|
||||||
|
IpAddr::V6(ref ip) => ip.is_usable_public(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_usable_private(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
IpAddr::V4(ref ip) => ip.is_usable_private(),
|
||||||
|
IpAddr::V6(ref ip) => ip.is_usable_private(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_within(&self, ipnet: &IpNetwork) -> bool {
|
||||||
|
match *self {
|
||||||
|
IpAddr::V4(ref ip) => ip.is_within(ipnet),
|
||||||
|
IpAddr::V6(ref ip) => ip.is_within(ipnet)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
@ -79,7 +217,7 @@ mod getinterfaces {
|
|||||||
use libc::{getifaddrs, freeifaddrs, ifaddrs, sockaddr, sockaddr_in, sockaddr_in6};
|
use libc::{getifaddrs, freeifaddrs, ifaddrs, sockaddr, sockaddr_in, sockaddr_in6};
|
||||||
use std::net::{Ipv4Addr, Ipv6Addr, IpAddr};
|
use std::net::{Ipv4Addr, Ipv6Addr, IpAddr};
|
||||||
|
|
||||||
fn convert_sockaddr (sa: *mut sockaddr) -> Option<IpAddr> {
|
fn convert_sockaddr(sa: *mut sockaddr) -> Option<IpAddr> {
|
||||||
if sa == ptr::null_mut() { return None; }
|
if sa == ptr::null_mut() { return None; }
|
||||||
|
|
||||||
let (addr, _) = match unsafe { *sa }.sa_family as i32 {
|
let (addr, _) = match unsafe { *sa }.sa_family as i32 {
|
||||||
@ -115,7 +253,7 @@ mod getinterfaces {
|
|||||||
Some(addr)
|
Some(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_ifaddrs (ifa: *mut ifaddrs) -> Option<IpAddr> {
|
fn convert_ifaddrs(ifa: *mut ifaddrs) -> Option<IpAddr> {
|
||||||
let ifa = unsafe { &mut *ifa };
|
let ifa = unsafe { &mut *ifa };
|
||||||
convert_sockaddr(ifa.ifa_addr)
|
convert_sockaddr(ifa.ifa_addr)
|
||||||
}
|
}
|
||||||
@ -158,16 +296,16 @@ pub fn select_public_address(port: u16) -> SocketAddr {
|
|||||||
Ok(list) => {
|
Ok(list) => {
|
||||||
//prefer IPV4 bindings
|
//prefer IPV4 bindings
|
||||||
for addr in &list { //TODO: use better criteria than just the first in the list
|
for addr in &list { //TODO: use better criteria than just the first in the list
|
||||||
match *addr {
|
match addr {
|
||||||
IpAddr::V4(a) if !a.is_unspecified_s() && !a.is_loopback() && !a.is_link_local() => {
|
&IpAddr::V4(a) if !a.is_reserved() => {
|
||||||
return SocketAddr::V4(SocketAddrV4::new(a, port));
|
return SocketAddr::V4(SocketAddrV4::new(a, port));
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for addr in list {
|
for addr in &list {
|
||||||
match addr {
|
match addr {
|
||||||
IpAddr::V6(a) if !a.is_unspecified_s() && !a.is_loopback() => {
|
&IpAddr::V6(a) if !a.is_reserved() => {
|
||||||
return SocketAddr::V6(SocketAddrV6::new(a, port, 0, 0));
|
return SocketAddr::V6(SocketAddrV6::new(a, port, 0, 0));
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
@ -227,7 +365,6 @@ fn can_map_external_address_or_fail() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ipv4_properties() {
|
fn ipv4_properties() {
|
||||||
|
|
||||||
#![cfg_attr(feature="dev", allow(too_many_arguments))]
|
#![cfg_attr(feature="dev", allow(too_many_arguments))]
|
||||||
fn check(octets: &[u8; 4], unspec: bool, loopback: bool,
|
fn check(octets: &[u8; 4], unspec: bool, loopback: bool,
|
||||||
private: bool, link_local: bool, global: bool,
|
private: bool, link_local: bool, global: bool,
|
||||||
@ -235,7 +372,7 @@ fn ipv4_properties() {
|
|||||||
let ip = Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]);
|
let ip = Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]);
|
||||||
assert_eq!(octets, &ip.octets());
|
assert_eq!(octets, &ip.octets());
|
||||||
|
|
||||||
assert_eq!(ip.is_unspecified_s(), unspec);
|
assert_eq!(ip.is_unspecified(), unspec);
|
||||||
assert_eq!(ip.is_loopback(), loopback);
|
assert_eq!(ip.is_loopback(), loopback);
|
||||||
assert_eq!(ip.is_private(), private);
|
assert_eq!(ip.is_private(), private);
|
||||||
assert_eq!(ip.is_link_local(), link_local);
|
assert_eq!(ip.is_link_local(), link_local);
|
||||||
@ -264,13 +401,131 @@ fn ipv4_properties() {
|
|||||||
check(&[255, 255, 255, 255], false, false, false, false, false, false, true, false);
|
check(&[255, 255, 255, 255], false, false, false, false, false, false, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ipv4_shared_space() {
|
||||||
|
assert!(!Ipv4Addr::new(100, 63, 255, 255).is_shared_space());
|
||||||
|
assert!(Ipv4Addr::new(100, 64, 0, 0).is_shared_space());
|
||||||
|
assert!(Ipv4Addr::new(100, 127, 255, 255).is_shared_space());
|
||||||
|
assert!(!Ipv4Addr::new(100, 128, 0, 0).is_shared_space());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ipv4_special_purpose() {
|
||||||
|
assert!(!Ipv4Addr::new(191, 255, 255, 255).is_special_purpose());
|
||||||
|
assert!(Ipv4Addr::new(192, 0, 0, 0).is_special_purpose());
|
||||||
|
assert!(Ipv4Addr::new(192, 0, 0, 255).is_special_purpose());
|
||||||
|
assert!(!Ipv4Addr::new(192, 0, 1, 255).is_special_purpose());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ipv4_benchmarking() {
|
||||||
|
assert!(!Ipv4Addr::new(198, 17, 255, 255).is_benchmarking());
|
||||||
|
assert!(Ipv4Addr::new(198, 18, 0, 0).is_benchmarking());
|
||||||
|
assert!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking());
|
||||||
|
assert!(!Ipv4Addr::new(198, 20, 0, 0).is_benchmarking());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ipv4_future_use() {
|
||||||
|
assert!(!Ipv4Addr::new(239, 255, 255, 255).is_future_use());
|
||||||
|
assert!(Ipv4Addr::new(240, 0, 0, 0).is_future_use());
|
||||||
|
assert!(Ipv4Addr::new(255, 255, 255, 254).is_future_use());
|
||||||
|
assert!(!Ipv4Addr::new(255, 255, 255, 255).is_future_use());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ipv4_usable_public() {
|
||||||
|
assert!(!Ipv4Addr::new(0,0,0,0).is_usable_public()); // unspecified
|
||||||
|
assert!(Ipv4Addr::new(0,0,0,1).is_usable_public());
|
||||||
|
|
||||||
|
assert!(Ipv4Addr::new(9,255,255,255).is_usable_public());
|
||||||
|
assert!(!Ipv4Addr::new(10,0,0,0).is_usable_public()); // private intra-network
|
||||||
|
assert!(!Ipv4Addr::new(10,255,255,255).is_usable_public()); // private intra-network
|
||||||
|
assert!(Ipv4Addr::new(11,0,0,0).is_usable_public());
|
||||||
|
|
||||||
|
assert!(Ipv4Addr::new(100, 63, 255, 255).is_usable_public());
|
||||||
|
assert!(!Ipv4Addr::new(100, 64, 0, 0).is_usable_public()); // shared space
|
||||||
|
assert!(!Ipv4Addr::new(100, 127, 255, 255).is_usable_public()); // shared space
|
||||||
|
assert!(Ipv4Addr::new(100, 128, 0, 0).is_usable_public());
|
||||||
|
|
||||||
|
assert!(Ipv4Addr::new(126,255,255,255).is_usable_public());
|
||||||
|
assert!(!Ipv4Addr::new(127,0,0,0).is_usable_public()); // loopback
|
||||||
|
assert!(!Ipv4Addr::new(127,255,255,255).is_usable_public()); // loopback
|
||||||
|
assert!(Ipv4Addr::new(128,0,0,0).is_usable_public());
|
||||||
|
|
||||||
|
assert!(Ipv4Addr::new(169,253,255,255).is_usable_public());
|
||||||
|
assert!(!Ipv4Addr::new(169,254,0,0).is_usable_public()); // link-local
|
||||||
|
assert!(!Ipv4Addr::new(169,254,255,255).is_usable_public()); // link-local
|
||||||
|
assert!(Ipv4Addr::new(169,255,0,0).is_usable_public());
|
||||||
|
|
||||||
|
assert!(Ipv4Addr::new(172,15,255,255).is_usable_public());
|
||||||
|
assert!(!Ipv4Addr::new(172,16,0,0).is_usable_public()); // private intra-network
|
||||||
|
assert!(!Ipv4Addr::new(172,31,255,255).is_usable_public()); // private intra-network
|
||||||
|
assert!(Ipv4Addr::new(172,32,255,255).is_usable_public());
|
||||||
|
|
||||||
|
assert!(Ipv4Addr::new(191,255,255,255).is_usable_public());
|
||||||
|
assert!(!Ipv4Addr::new(192,0,0,0).is_usable_public()); // special purpose
|
||||||
|
assert!(!Ipv4Addr::new(192,0,0,255).is_usable_public()); // special purpose
|
||||||
|
assert!(Ipv4Addr::new(192,0,1,0).is_usable_public());
|
||||||
|
|
||||||
|
assert!(Ipv4Addr::new(192,0,1,255).is_usable_public());
|
||||||
|
assert!(!Ipv4Addr::new(192,0,2,0).is_usable_public()); // documentation
|
||||||
|
assert!(!Ipv4Addr::new(192,0,2,255).is_usable_public()); // documentation
|
||||||
|
assert!(Ipv4Addr::new(192,0,3,0).is_usable_public());
|
||||||
|
|
||||||
|
assert!(Ipv4Addr::new(192,167,255,255).is_usable_public());
|
||||||
|
assert!(!Ipv4Addr::new(192,168,0,0).is_usable_public()); // private intra-network
|
||||||
|
assert!(!Ipv4Addr::new(192,168,255,255).is_usable_public()); // private intra-network
|
||||||
|
assert!(Ipv4Addr::new(192,169,0,0).is_usable_public());
|
||||||
|
|
||||||
|
assert!(Ipv4Addr::new(198,17,255,255).is_usable_public());
|
||||||
|
assert!(!Ipv4Addr::new(198,18,0,0).is_usable_public()); // benchmarking
|
||||||
|
assert!(!Ipv4Addr::new(198,19,255,255).is_usable_public()); // benchmarking
|
||||||
|
assert!(Ipv4Addr::new(198,20,0,0).is_usable_public());
|
||||||
|
|
||||||
|
assert!(Ipv4Addr::new(198,51,99,255).is_usable_public());
|
||||||
|
assert!(!Ipv4Addr::new(198,51,100,0).is_usable_public()); // documentation
|
||||||
|
assert!(!Ipv4Addr::new(198,51,100,255).is_usable_public()); // documentation
|
||||||
|
assert!(Ipv4Addr::new(198,51,101,0).is_usable_public());
|
||||||
|
|
||||||
|
assert!(Ipv4Addr::new(203,0,112,255).is_usable_public());
|
||||||
|
assert!(!Ipv4Addr::new(203,0,113,0).is_usable_public()); // documentation
|
||||||
|
assert!(!Ipv4Addr::new(203,0,113,255).is_usable_public()); // documentation
|
||||||
|
assert!(Ipv4Addr::new(203,0,114,0).is_usable_public());
|
||||||
|
|
||||||
|
assert!(Ipv4Addr::new(223,255,255,255).is_usable_public());
|
||||||
|
assert!(!Ipv4Addr::new(224,0,0,0).is_usable_public()); // multicast
|
||||||
|
assert!(!Ipv4Addr::new(239, 255, 255, 255).is_usable_public()); // multicast
|
||||||
|
assert!(!Ipv4Addr::new(240, 0, 0, 0).is_usable_public()); // future use
|
||||||
|
assert!(!Ipv4Addr::new(255, 255, 255, 254).is_usable_public()); // future use
|
||||||
|
assert!(!Ipv4Addr::new(255, 255, 255, 255).is_usable_public()); // limited broadcast
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ipv4_usable_private() {
|
||||||
|
assert!(!Ipv4Addr::new(9,255,255,255).is_usable_private());
|
||||||
|
assert!(Ipv4Addr::new(10,0,0,0).is_usable_private()); // private intra-network
|
||||||
|
assert!(Ipv4Addr::new(10,255,255,255).is_usable_private()); // private intra-network
|
||||||
|
assert!(!Ipv4Addr::new(11,0,0,0).is_usable_private());
|
||||||
|
|
||||||
|
assert!(!Ipv4Addr::new(172,15,255,255).is_usable_private());
|
||||||
|
assert!(Ipv4Addr::new(172,16,0,0).is_usable_private()); // private intra-network
|
||||||
|
assert!(Ipv4Addr::new(172,31,255,255).is_usable_private()); // private intra-network
|
||||||
|
assert!(!Ipv4Addr::new(172,32,255,255).is_usable_private());
|
||||||
|
|
||||||
|
assert!(!Ipv4Addr::new(192,167,255,255).is_usable_private());
|
||||||
|
assert!(Ipv4Addr::new(192,168,0,0).is_usable_private()); // private intra-network
|
||||||
|
assert!(Ipv4Addr::new(192,168,255,255).is_usable_private()); // private intra-network
|
||||||
|
assert!(!Ipv4Addr::new(192,169,0,0).is_usable_private());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ipv6_properties() {
|
fn ipv6_properties() {
|
||||||
fn check(str_addr: &str, unspec: bool, loopback: bool, global: bool) {
|
fn check(str_addr: &str, unspec: bool, loopback: bool, global: bool) {
|
||||||
let ip: Ipv6Addr = str_addr.parse().unwrap();
|
let ip: Ipv6Addr = str_addr.parse().unwrap();
|
||||||
assert_eq!(str_addr, ip.to_string());
|
assert_eq!(str_addr, ip.to_string());
|
||||||
|
|
||||||
assert_eq!(ip.is_unspecified_s(), unspec);
|
assert_eq!(ip.is_unspecified(), unspec);
|
||||||
assert_eq!(ip.is_loopback(), loopback);
|
assert_eq!(ip.is_loopback(), loopback);
|
||||||
assert_eq!(ip.is_global_s(), global);
|
assert_eq!(ip.is_global_s(), global);
|
||||||
}
|
}
|
||||||
@ -279,3 +534,5 @@ fn ipv6_properties() {
|
|||||||
check("::", true, false, true);
|
check("::", true, false, true);
|
||||||
check("::1", false, true, false);
|
check("::1", false, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,6 +77,7 @@ extern crate rlp;
|
|||||||
extern crate bytes;
|
extern crate bytes;
|
||||||
extern crate path;
|
extern crate path;
|
||||||
extern crate ethcore_logger;
|
extern crate ethcore_logger;
|
||||||
|
extern crate ipnetwork;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
@ -106,6 +107,8 @@ pub use session::SessionInfo;
|
|||||||
|
|
||||||
pub use io::TimerToken;
|
pub use io::TimerToken;
|
||||||
pub use node_table::{is_valid_node_url, NodeId};
|
pub use node_table::{is_valid_node_url, NodeId};
|
||||||
|
use ipnetwork::{IpNetwork, IpNetworkError};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
const PROTOCOL_VERSION: u32 = 4;
|
const PROTOCOL_VERSION: u32 = 4;
|
||||||
|
|
||||||
@ -145,8 +148,49 @@ impl NonReservedPeerMode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "ipc", binary)]
|
||||||
|
pub struct IpFilter {
|
||||||
|
pub predefined: AllowIP,
|
||||||
|
pub custom_allow: Vec<IpNetwork>,
|
||||||
|
pub custom_block: Vec<IpNetwork>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for IpFilter {
|
||||||
|
fn default() -> Self {
|
||||||
|
IpFilter {
|
||||||
|
predefined: AllowIP::All,
|
||||||
|
custom_allow: vec![],
|
||||||
|
custom_block: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IpFilter {
|
||||||
|
/// Attempt to parse the peer mode from a string.
|
||||||
|
pub fn parse(s: &str) -> Result<IpFilter, IpNetworkError> {
|
||||||
|
let mut filter = IpFilter::default();
|
||||||
|
for f in s.split_whitespace() {
|
||||||
|
match f {
|
||||||
|
"all" => filter.predefined = AllowIP::All,
|
||||||
|
"private" => filter.predefined = AllowIP::Private,
|
||||||
|
"public" => filter.predefined = AllowIP::Public,
|
||||||
|
"none" => filter.predefined = AllowIP::None,
|
||||||
|
custom => {
|
||||||
|
if custom.starts_with("-") {
|
||||||
|
filter.custom_block.push(IpNetwork::from_str(&custom.to_owned().split_off(1))?)
|
||||||
|
} else {
|
||||||
|
filter.custom_allow.push(IpNetwork::from_str(custom)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(filter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// IP fiter
|
/// IP fiter
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Copy)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum AllowIP {
|
pub enum AllowIP {
|
||||||
/// Connect to any address
|
/// Connect to any address
|
||||||
All,
|
All,
|
||||||
@ -154,5 +198,7 @@ pub enum AllowIP {
|
|||||||
Private,
|
Private,
|
||||||
/// Connect to public network only
|
/// Connect to public network only
|
||||||
Public,
|
Public,
|
||||||
|
/// Block all addresses
|
||||||
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ use util::UtilError;
|
|||||||
use rlp::*;
|
use rlp::*;
|
||||||
use time::Tm;
|
use time::Tm;
|
||||||
use error::NetworkError;
|
use error::NetworkError;
|
||||||
use AllowIP;
|
use {AllowIP, IpFilter};
|
||||||
use discovery::{TableUpdates, NodeEntry};
|
use discovery::{TableUpdates, NodeEntry};
|
||||||
use ip_utils::*;
|
use ip_utils::*;
|
||||||
pub use rustc_serialize::json::Json;
|
pub use rustc_serialize::json::Json;
|
||||||
@ -55,11 +55,21 @@ impl NodeEndpoint {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_allowed(&self, filter: AllowIP) -> bool {
|
pub fn is_allowed(&self, filter: &IpFilter) -> bool {
|
||||||
|
(self.is_allowed_by_predefined(&filter.predefined) || filter.custom_allow.iter().any(|ipnet| {
|
||||||
|
self.address.ip().is_within(ipnet)
|
||||||
|
}))
|
||||||
|
&& !filter.custom_block.iter().any(|ipnet| {
|
||||||
|
self.address.ip().is_within(ipnet)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_allowed_by_predefined(&self, filter: &AllowIP) -> bool {
|
||||||
match filter {
|
match filter {
|
||||||
AllowIP::All => true,
|
&AllowIP::All => true,
|
||||||
AllowIP::Private => !self.address.ip().is_global_s(),
|
&AllowIP::Private => self.address.ip().is_usable_private(),
|
||||||
AllowIP::Public => self.address.ip().is_global_s(),
|
&AllowIP::Public => self.address.ip().is_usable_public(),
|
||||||
|
&AllowIP::None => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,8 +111,8 @@ impl NodeEndpoint {
|
|||||||
pub fn is_valid(&self) -> bool {
|
pub fn is_valid(&self) -> bool {
|
||||||
self.udp_port != 0 && self.address.port() != 0 &&
|
self.udp_port != 0 && self.address.port() != 0 &&
|
||||||
match self.address {
|
match self.address {
|
||||||
SocketAddr::V4(a) => !a.ip().is_unspecified_s(),
|
SocketAddr::V4(a) => !a.ip().is_unspecified(),
|
||||||
SocketAddr::V6(a) => !a.ip().is_unspecified_s()
|
SocketAddr::V6(a) => !a.ip().is_unspecified()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -219,8 +229,8 @@ impl NodeTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns node ids sorted by number of failures
|
/// Returns node ids sorted by number of failures
|
||||||
pub fn nodes(&self, filter: AllowIP) -> Vec<NodeId> {
|
pub fn nodes(&self, filter: IpFilter) -> Vec<NodeId> {
|
||||||
let mut refs: Vec<&Node> = self.nodes.values().filter(|n| !self.useless_nodes.contains(&n.id) && n.endpoint.is_allowed(filter)).collect();
|
let mut refs: Vec<&Node> = self.nodes.values().filter(|n| !self.useless_nodes.contains(&n.id) && n.endpoint.is_allowed(&filter)).collect();
|
||||||
refs.sort_by(|a, b| a.failures.cmp(&b.failures));
|
refs.sort_by(|a, b| a.failures.cmp(&b.failures));
|
||||||
refs.iter().map(|n| n.id.clone()).collect()
|
refs.iter().map(|n| n.id.clone()).collect()
|
||||||
}
|
}
|
||||||
@ -283,7 +293,7 @@ impl NodeTable {
|
|||||||
let mut json = String::new();
|
let mut json = String::new();
|
||||||
json.push_str("{\n");
|
json.push_str("{\n");
|
||||||
json.push_str("\"nodes\": [\n");
|
json.push_str("\"nodes\": [\n");
|
||||||
let node_ids = self.nodes(AllowIP::All);
|
let node_ids = self.nodes(IpFilter::default());
|
||||||
for i in 0 .. node_ids.len() {
|
for i in 0 .. node_ids.len() {
|
||||||
let node = self.nodes.get(&node_ids[i]).expect("self.nodes() only returns node IDs from self.nodes");
|
let node = self.nodes.get(&node_ids[i]).expect("self.nodes() only returns node IDs from self.nodes");
|
||||||
json.push_str(&format!("\t{{ \"url\": \"{}\", \"failures\": {} }}{}\n", node, node.failures, if i == node_ids.len() - 1 {""} else {","}))
|
json.push_str(&format!("\t{{ \"url\": \"{}\", \"failures\": {} }}{}\n", node, node.failures, if i == node_ids.len() - 1 {""} else {","}))
|
||||||
@ -366,7 +376,7 @@ mod tests {
|
|||||||
use util::H512;
|
use util::H512;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use devtools::*;
|
use devtools::*;
|
||||||
use AllowIP;
|
use ipnetwork::IpNetwork;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn endpoint_parse() {
|
fn endpoint_parse() {
|
||||||
@ -412,7 +422,7 @@ mod tests {
|
|||||||
table.note_failure(&id1);
|
table.note_failure(&id1);
|
||||||
table.note_failure(&id2);
|
table.note_failure(&id2);
|
||||||
|
|
||||||
let r = table.nodes(AllowIP::All);
|
let r = table.nodes(IpFilter::default());
|
||||||
assert_eq!(r[0][..], id3[..]);
|
assert_eq!(r[0][..], id3[..]);
|
||||||
assert_eq!(r[1][..], id2[..]);
|
assert_eq!(r[1][..], id2[..]);
|
||||||
assert_eq!(r[2][..], id1[..]);
|
assert_eq!(r[2][..], id1[..]);
|
||||||
@ -434,9 +444,55 @@ mod tests {
|
|||||||
|
|
||||||
{
|
{
|
||||||
let table = NodeTable::new(Some(temp_path.as_path().to_str().unwrap().to_owned()));
|
let table = NodeTable::new(Some(temp_path.as_path().to_str().unwrap().to_owned()));
|
||||||
let r = table.nodes(AllowIP::All);
|
let r = table.nodes(IpFilter::default());
|
||||||
assert_eq!(r[0][..], id1[..]);
|
assert_eq!(r[0][..], id1[..]);
|
||||||
assert_eq!(r[1][..], id2[..]);
|
assert_eq!(r[1][..], id2[..]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn custom_allow() {
|
||||||
|
let filter = IpFilter {
|
||||||
|
predefined: AllowIP::None,
|
||||||
|
custom_allow: vec![IpNetwork::from_str(&"10.0.0.0/8").unwrap(), IpNetwork::from_str(&"1.0.0.0/8").unwrap()],
|
||||||
|
custom_block: vec![],
|
||||||
|
};
|
||||||
|
assert!(!NodeEndpoint::from_str("123.99.55.44:7770").unwrap().is_allowed(&filter));
|
||||||
|
assert!(NodeEndpoint::from_str("10.0.0.1:7770").unwrap().is_allowed(&filter));
|
||||||
|
assert!(NodeEndpoint::from_str("1.0.0.55:5550").unwrap().is_allowed(&filter));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn custom_block() {
|
||||||
|
let filter = IpFilter {
|
||||||
|
predefined: AllowIP::All,
|
||||||
|
custom_allow: vec![],
|
||||||
|
custom_block: vec![IpNetwork::from_str(&"10.0.0.0/8").unwrap(), IpNetwork::from_str(&"1.0.0.0/8").unwrap()],
|
||||||
|
};
|
||||||
|
assert!(NodeEndpoint::from_str("123.99.55.44:7770").unwrap().is_allowed(&filter));
|
||||||
|
assert!(!NodeEndpoint::from_str("10.0.0.1:7770").unwrap().is_allowed(&filter));
|
||||||
|
assert!(!NodeEndpoint::from_str("1.0.0.55:5550").unwrap().is_allowed(&filter));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn custom_allow_ipv6() {
|
||||||
|
let filter = IpFilter {
|
||||||
|
predefined: AllowIP::None,
|
||||||
|
custom_allow: vec![IpNetwork::from_str(&"fc00::/8").unwrap()],
|
||||||
|
custom_block: vec![],
|
||||||
|
};
|
||||||
|
assert!(NodeEndpoint::from_str("[fc00::]:5550").unwrap().is_allowed(&filter));
|
||||||
|
assert!(!NodeEndpoint::from_str("[fd00::]:5550").unwrap().is_allowed(&filter));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn custom_block_ipv6() {
|
||||||
|
let filter = IpFilter {
|
||||||
|
predefined: AllowIP::All,
|
||||||
|
custom_allow: vec![],
|
||||||
|
custom_block: vec![IpNetwork::from_str(&"fc00::/8").unwrap()],
|
||||||
|
};
|
||||||
|
assert!(!NodeEndpoint::from_str("[fc00::]:5550").unwrap().is_allowed(&filter));
|
||||||
|
assert!(NodeEndpoint::from_str("[fd00::]:5550").unwrap().is_allowed(&filter));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user