Spliting host into explicit address and port(s)

This commit is contained in:
Jędrzej Stuczyński
2021-06-22 16:39:07 +01:00
parent 29ac119127
commit a6be3e763f
16 changed files with 270 additions and 391 deletions
+2 -2
View File
@@ -88,7 +88,7 @@ async fn register_with_gateway(
) -> SharedKeys {
let timeout = Duration::from_millis(1500);
let mut gateway_client = GatewayClient::new_init(
gateway.client_listener.clone(),
gateway.clients_address(),
gateway.identity_key,
our_identity.clone(),
timeout,
@@ -215,7 +215,7 @@ pub fn execute(matches: &ArgMatches) {
.with_gateway_id(gate_details.identity_key.to_base58_string());
let shared_keys =
register_with_gateway(&gate_details, key_manager.identity_keypair()).await;
(shared_keys, gate_details.client_listener)
(shared_keys, gate_details.clients_address())
};
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
+2 -2
View File
@@ -89,7 +89,7 @@ async fn register_with_gateway(
) -> SharedKeys {
let timeout = Duration::from_millis(1500);
let mut gateway_client = GatewayClient::new_init(
gateway.client_listener.clone(),
gateway.clients_address(),
gateway.identity_key,
our_identity.clone(),
timeout,
@@ -217,7 +217,7 @@ pub fn execute(matches: &ArgMatches) {
.with_gateway_id(gate_details.identity_key.to_base58_string());
let shared_keys =
register_with_gateway(&gate_details, key_manager.identity_keypair()).await;
(shared_keys, gate_details.client_listener)
(shared_keys, gate_details.clients_address())
};
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
+1 -1
View File
@@ -120,7 +120,7 @@ impl NymClient {
let (ack_sender, ack_receiver) = mpsc::unbounded();
let mut gateway_client = GatewayClient::new(
gateway.client_listener.clone(),
gateway.clients_address(),
Arc::clone(&client.identity),
gateway.identity_key,
None,
+15 -14
View File
@@ -6,13 +6,12 @@ use cosmwasm_std::{Addr, Coin};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::fmt::Display;
use std::io;
use std::net::{SocketAddr, ToSocketAddrs};
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
pub struct Gateway {
pub mix_host: String,
pub clients_host: String,
pub host: String,
pub mix_port: u16,
pub clients_port: u16,
pub location: String,
pub sphinx_key: SphinxKey,
/// Base58 encoded ed25519 EdDSA public key of the gateway used to derive shared keys with clients
@@ -22,16 +21,18 @@ pub struct Gateway {
impl Gateway {
pub fn new(
mix_host: String,
clients_host: String,
host: String,
mix_port: u16,
clients_port: u16,
location: String,
sphinx_key: SphinxKey,
identity_key: IdentityKey,
version: String,
) -> Self {
Gateway {
mix_host,
clients_host,
host,
mix_port,
clients_port,
location,
sphinx_key,
identity_key,
@@ -39,12 +40,12 @@ impl Gateway {
}
}
pub fn try_resolve_hostname(&self) -> Result<SocketAddr, io::Error> {
self.mix_host
.to_socket_addrs()?
.next()
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "no valid socket address"))
}
// pub fn try_resolve_hostname(&self) -> Result<SocketAddr, io::Error> {
// self.mix_host
// .to_socket_addrs()?
// .next()
// .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "no valid socket address"))
// }
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
+3 -16
View File
@@ -6,12 +6,11 @@ use cosmwasm_std::{Addr, Coin};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::fmt::Display;
use std::io;
use std::net::{SocketAddr, ToSocketAddrs};
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
pub struct MixNode {
pub host: String,
pub mix_port: u16,
pub layer: u64,
pub location: String,
pub sphinx_key: SphinxKey,
@@ -23,6 +22,7 @@ pub struct MixNode {
impl MixNode {
pub fn new(
host: String,
mix_port: u16,
layer: u64,
location: String,
sphinx_key: SphinxKey,
@@ -31,6 +31,7 @@ impl MixNode {
) -> Self {
MixNode {
host,
mix_port,
layer,
location,
sphinx_key,
@@ -38,20 +39,8 @@ impl MixNode {
version,
}
}
pub fn try_resolve_hostname(&self) -> Result<SocketAddr, io::Error> {
self.host
.to_socket_addrs()?
.next()
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "no valid socket address"))
}
}
/*
By the way, I've also been thinking of some potential changes in the contract we could introduce once we have to make an incompatible upgrade (say to cosmwasm 0.14+). Is there some place I could write them down so that we would not forget about them? Should I make a GitHub issue, a google doc or maybe put it on GitLab?
*/
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
pub struct MixNodeBond {
// TODO:
@@ -62,8 +51,6 @@ pub struct MixNodeBond {
//
// I would also modify the `MixNode` struct:
// - remove `location` field
// - repurpose `host` field to hold either ip or hostname (WITHOUT port information)
// - introduce `mix_port` field
// - introduce `rest_api_port` field
// - [POTENTIALLY] introduce `verloc_port` field or keep it accessible via http api
//
+25 -8
View File
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::filter;
use crate::{filter, NetworkAddress};
use crypto::asymmetric::{encryption, identity};
use mixnet_contract::GatewayBond;
use nymsphinx_addressing::nodes::{NodeIdentity, NymNodeRoutingAddress};
@@ -84,8 +84,11 @@ pub struct Node {
// on the network at a type, right?
pub stake: u128,
pub location: String,
pub client_listener: String,
pub mixnet_listener: SocketAddr,
pub host: NetworkAddress,
// we're keeping this as separate resolved field since we do not want to be resolving the potential
// hostname every time we want to construct a path via this node
pub mix_host: SocketAddr,
pub clients_port: u16,
pub identity_key: identity::PublicKey,
pub sphinx_key: encryption::PublicKey, // TODO: or nymsphinx::PublicKey? both are x25519
pub version: String,
@@ -95,6 +98,10 @@ impl Node {
pub fn identity(&self) -> &NodeIdentity {
&self.identity_key
}
pub fn clients_address(&self) -> String {
format!("ws://{}:{}", self.host, self.clients_port)
}
}
impl filter::Versioned for Node {
@@ -105,7 +112,7 @@ impl filter::Versioned for Node {
impl<'a> From<&'a Node> for SphinxNode {
fn from(node: &'a Node) -> Self {
let node_address_bytes = NymNodeRoutingAddress::from(node.mixnet_listener)
let node_address_bytes = NymNodeRoutingAddress::from(node.mix_host)
.try_into()
.unwrap();
@@ -120,6 +127,17 @@ impl<'a> TryFrom<&'a GatewayBond> for Node {
if bond.amount.len() > 1 {
return Err(GatewayConversionError::InvalidStake);
}
let host: NetworkAddress = bond.gateway.host.parse().map_err(|err| {
GatewayConversionError::InvalidAddress(bond.gateway.host.clone(), err)
})?;
// try to completely resolve the host in the mix situation to avoid doing it every
// single time we want to construct a path
let mix_host = host.to_socket_addrs(bond.gateway.mix_port).map_err(|err| {
GatewayConversionError::InvalidAddress(bond.gateway.host.clone(), err)
})?[0];
Ok(Node {
owner: bond.owner.as_str().to_owned(),
stake: bond
@@ -128,10 +146,9 @@ impl<'a> TryFrom<&'a GatewayBond> for Node {
.map(|stake| stake.amount.into())
.unwrap_or(0),
location: bond.gateway.location.clone(),
client_listener: bond.gateway.clients_host.clone(),
mixnet_listener: bond.gateway.try_resolve_hostname().map_err(|err| {
GatewayConversionError::InvalidAddress(bond.gateway.mix_host.clone(), err)
})?,
host,
mix_host,
clients_port: bond.gateway.clients_port,
identity_key: identity::PublicKey::from_base58_string(&bond.gateway.identity_key)?,
sphinx_key: encryption::PublicKey::from_base58_string(&bond.gateway.sphinx_key)?,
version: bond.gateway.version.clone(),
+41
View File
@@ -20,6 +20,10 @@ use nymsphinx_types::Node as SphinxNode;
use rand::Rng;
use std::collections::HashMap;
use std::convert::TryInto;
use std::fmt::{self, Display, Formatter};
use std::io;
use std::net::{IpAddr, SocketAddr, ToSocketAddrs};
use std::str::FromStr;
pub mod filter;
pub mod gateway;
@@ -35,6 +39,43 @@ pub enum NymTopologyError {
NoMixesOnLayerAvailable(MixLayer),
}
#[derive(Debug, Clone)]
pub enum NetworkAddress {
IpAddr(IpAddr),
Hostname(String),
}
impl NetworkAddress {
pub fn to_socket_addrs(&self, port: u16) -> io::Result<Vec<SocketAddr>> {
match self {
NetworkAddress::IpAddr(addr) => Ok(vec![SocketAddr::new(*addr, port)]),
NetworkAddress::Hostname(hostname) => {
Ok((hostname.as_str(), port).to_socket_addrs()?.collect())
}
}
}
}
impl FromStr for NetworkAddress {
type Err = std::io::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Ok(ip_addr) = s.parse() {
return Ok(NetworkAddress::IpAddr(ip_addr));
}
todo!()
}
}
impl Display for NetworkAddress {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
NetworkAddress::IpAddr(ip_addr) => ip_addr.fmt(f),
NetworkAddress::Hostname(hostname) => hostname.fmt(f),
}
}
}
pub type MixLayer = u8;
#[derive(Debug, Clone)]
+23 -6
View File
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::filter;
use crate::{filter, NetworkAddress};
use crypto::asymmetric::{encryption, identity};
use mixnet_contract::MixNodeBond;
use nymsphinx_addressing::nodes::NymNodeRoutingAddress;
@@ -84,7 +84,10 @@ pub struct Node {
// on the network at a type, right?
pub stake: u128,
pub location: String,
pub host: SocketAddr,
pub host: NetworkAddress,
// we're keeping this as separate resolved field since we do not want to be resolving the potential
// hostname every time we want to construct a path via this node
pub mix_host: SocketAddr,
pub identity_key: identity::PublicKey,
pub sphinx_key: encryption::PublicKey, // TODO: or nymsphinx::PublicKey? both are x25519
pub layer: u64,
@@ -99,7 +102,9 @@ impl filter::Versioned for Node {
impl<'a> From<&'a Node> for SphinxNode {
fn from(node: &'a Node) -> Self {
let node_address_bytes = NymNodeRoutingAddress::from(node.host).try_into().unwrap();
let node_address_bytes = NymNodeRoutingAddress::from(node.mix_host)
.try_into()
.unwrap();
SphinxNode::new(node_address_bytes, (&node.sphinx_key).into())
}
@@ -112,6 +117,19 @@ impl<'a> TryFrom<&'a MixNodeBond> for Node {
if bond.amount.len() > 1 {
return Err(MixnodeConversionError::InvalidStake);
}
let host: NetworkAddress = bond.mix_node.host.parse().map_err(|err| {
MixnodeConversionError::InvalidAddress(bond.mix_node.host.clone(), err)
})?;
// try to completely resolve the host in the mix situation to avoid doing it every
// single time we want to construct a path
let mix_host = host
.to_socket_addrs(bond.mix_node.mix_port)
.map_err(|err| {
MixnodeConversionError::InvalidAddress(bond.mix_node.host.clone(), err)
})?[0];
Ok(Node {
owner: bond.owner.as_str().to_owned(),
stake: bond
@@ -120,9 +138,8 @@ impl<'a> TryFrom<&'a MixNodeBond> for Node {
.map(|stake| stake.amount.into())
.unwrap_or(0),
location: bond.mix_node.location.clone(),
host: bond.mix_node.try_resolve_hostname().map_err(|err| {
MixnodeConversionError::InvalidAddress(bond.mix_node.host.clone(), err)
})?,
host,
mix_host,
identity_key: identity::PublicKey::from_base58_string(&bond.mix_node.identity_key)?,
sphinx_key: encryption::PublicKey::from_base58_string(&bond.mix_node.sphinx_key)?,
layer: bond.mix_node.layer,
+7 -5
View File
@@ -106,21 +106,23 @@ fn show_bonding_info(config: &Config) {
"\nTo bond your gateway you will [most likely] need to provide the following:
Identity key: {}
Sphinx key: {}
Mix Host: {}
Clients Host: {}
Host: {}
Mix Port: {}
Clients Port: {}
Location: [physical location of your node's server]
Version: {}
",
identity_keypair.public_key().to_base58_string(),
sphinx_keypair.public_key().to_base58_string(),
config.get_mix_announce_address(),
config.get_clients_announce_address(),
config.get_announce_address(),
config.get_mix_port(),
config.get_clients_port(),
config.get_version(),
);
}
pub fn execute(matches: &ArgMatches) {
let id = matches.value_of("id").unwrap();
let id = matches.value_of(ID_ARG_NAME).unwrap();
println!("Initialising gateway {}...", id);
let already_init = if Config::default_config_file_path(id).exists() {
+6 -21
View File
@@ -156,14 +156,8 @@ pub fn execute(matches: &ArgMatches) {
let sphinx_keypair = load_sphinx_keys(&pathfinder);
let identity = load_identity_keys(&pathfinder);
let mix_listening_ip_string = config.get_mix_listening_address().ip().to_string();
if special_addresses().contains(&mix_listening_ip_string.as_ref()) {
show_binding_warning(mix_listening_ip_string);
}
let clients_listening_ip_string = config.get_clients_listening_address().ip().to_string();
if special_addresses().contains(&clients_listening_ip_string.as_ref()) {
show_binding_warning(clients_listening_ip_string);
if special_addresses().contains(&&*config.get_listening_address()) {
show_binding_warning(config.get_listening_address());
}
println!(
@@ -172,21 +166,12 @@ pub fn execute(matches: &ArgMatches) {
);
println!(
"Listening for incoming sphinx packets on {}",
config.get_mix_listening_address()
"Listening for incoming packets on {}",
config.get_listening_address()
);
println!(
"Announcing the following socket address for sphinx packets: {}",
config.get_mix_announce_address()
);
println!(
"Listening for incoming clients packets on {}",
config.get_clients_listening_address()
);
println!(
"Announcing the following socket address for clients packets: {}",
config.get_clients_announce_address()
"Announcing the following address: {}",
config.get_announce_address()
);
println!(
+45 -204
View File
@@ -3,11 +3,8 @@
use crate::config::template::config_template;
use config::{deserialize_duration, deserialize_validators, NymConfig};
use log::*;
use serde::{Deserialize, Serialize};
use std::net::{IpAddr, SocketAddr};
use std::path::PathBuf;
use std::str::FromStr;
use std::time::Duration;
pub mod persistence;
@@ -58,8 +55,6 @@ pub fn missing_vec_string_value() -> Vec<String> {
pub struct Config {
gateway: Gateway,
mixnet_endpoint: MixnetEndpoint,
clients_endpoint: ClientsEndpoint,
#[serde(default)]
@@ -155,169 +150,38 @@ impl Config {
self
}
pub fn with_mix_listening_host<S: Into<String>>(mut self, host: S) -> Self {
// see if the provided `host` is just an ip address or ip:port
let host = host.into();
// is it ip:port?
match SocketAddr::from_str(host.as_ref()) {
Ok(socket_addr) => {
self.mixnet_endpoint.listening_address = socket_addr;
self
}
// try just for ip
Err(_) => match IpAddr::from_str(host.as_ref()) {
Ok(ip_addr) => {
self.mixnet_endpoint.listening_address.set_ip(ip_addr);
self
}
Err(_) => {
error!(
"failed to make any changes to config - invalid host {}",
host
);
self
}
},
}
}
pub fn with_mix_listening_port(mut self, port: u16) -> Self {
self.mixnet_endpoint.listening_address.set_port(port);
pub fn with_listening_address<S: Into<String>>(mut self, listening_address: S) -> Self {
self.gateway.listening_address = listening_address.into();
self
}
pub fn with_mix_announce_host<S: Into<String>>(mut self, host: S) -> Self {
// this is slightly more complicated as we store announce information as String,
// since it might not necessarily be a valid SocketAddr (say `nymtech.net:8080` is a valid
// announce address, yet invalid SocketAddr`
// first let's see if we received host:port or just host part of an address
let host = host.into();
match host.split(':').count() {
1 => {
// we provided only 'host' part so we are going to reuse existing port
self.mixnet_endpoint.announce_address =
format!("{}:{}", host, self.mixnet_endpoint.listening_address.port());
self
}
2 => {
// we provided 'host:port' so just put the whole thing there
self.mixnet_endpoint.announce_address = host;
self
}
_ => {
// we provided something completely invalid, so don't try to parse it
error!(
"failed to make any changes to config - invalid announce host {}",
host
);
self
}
}
}
pub fn mix_announce_host_from_listening_host(mut self) -> Self {
self.mixnet_endpoint.announce_address = self.mixnet_endpoint.listening_address.to_string();
pub fn with_announce_address<S: Into<String>>(mut self, announce_address: S) -> Self {
self.gateway.announce_address = announce_address.into();
self
}
pub fn with_mix_announce_port(mut self, port: u16) -> Self {
let current_host: Vec<_> = self.mixnet_endpoint.announce_address.split(':').collect();
debug_assert_eq!(current_host.len(), 2);
self.mixnet_endpoint.announce_address = format!("{}:{}", current_host[0], port);
pub fn with_mix_port(mut self, port: u16) -> Self {
self.gateway.mix_port = port;
self
}
pub fn with_clients_listening_host<S: Into<String>>(mut self, host: S) -> Self {
// see if the provided `host` is just an ip address or ip:port
let host = host.into();
// is it ip:port?
match SocketAddr::from_str(host.as_ref()) {
Ok(socket_addr) => {
self.clients_endpoint.listening_address = socket_addr;
self
}
// try just for ip
Err(_) => match IpAddr::from_str(host.as_ref()) {
Ok(ip_addr) => {
self.clients_endpoint.listening_address.set_ip(ip_addr);
self
}
Err(_) => {
error!(
"failed to make any changes to config - invalid host {}",
host
);
self
}
},
}
}
pub fn clients_announce_host_from_listening_host(mut self) -> Self {
self.clients_endpoint.announce_address = format!(
"ws://{}",
self.clients_endpoint.listening_address.to_string()
);
pub fn with_clients_port(mut self, port: u16) -> Self {
self.gateway.clients_port = port;
self
}
pub fn with_clients_listening_port(mut self, port: u16) -> Self {
self.clients_endpoint.listening_address.set_port(port);
pub fn announce_host_from_listening_host(mut self) -> Self {
self.gateway.announce_address = self.gateway.listening_address.clone();
self
}
pub fn with_clients_announce_host<S: Into<String>>(mut self, host: S) -> Self {
// this is slightly more complicated as we store announce information as String,
// since it might not necessarily be a valid SocketAddr (say `nymtech.net:8080` is a valid
// announce address, yet invalid SocketAddr`
// first let's see if we received host:port or just host part of an address
let host = host.into();
match host.split(':').count() {
1 => {
// we provided only 'host' part so we are going to reuse existing port
self.clients_endpoint.announce_address = format!(
"{}:{}",
host,
self.clients_endpoint.listening_address.port()
);
// make sure it has 'ws' prefix (by extension it also includes 'wss')
if !self.clients_endpoint.announce_address.starts_with("ws") {
self.clients_endpoint.announce_address =
format!("ws://{}", self.clients_endpoint.announce_address);
}
self
}
2 => {
// we provided 'host:port' so just put the whole thing there
self.clients_endpoint.announce_address = host;
// make sure it has 'ws' prefix (by extension it also includes 'wss')
if !self.clients_endpoint.announce_address.starts_with("ws") {
self.clients_endpoint.announce_address =
format!("ws://{}", self.clients_endpoint.announce_address);
}
self
}
_ => {
// we provided something completely invalid, so don't try to parse it
error!(
"failed to make any changes to config - invalid announce host {}",
host
);
self
}
}
}
pub fn with_clients_announce_port(mut self, port: u16) -> Self {
let current_host: Vec<_> = self.clients_endpoint.announce_address.split(':').collect();
debug_assert_eq!(current_host.len(), 2);
self.clients_endpoint.announce_address = format!("{}:{}", current_host[0], port);
self
}
// pub fn clients_announce_host_from_listening_host(mut self) -> Self {
// self.clients_endpoint.announce_address = format!(
// "ws://{}",
// self.clients_endpoint.listening_address.to_string()
// );
// self
// }
pub fn with_custom_clients_inboxes<S: Into<String>>(mut self, inboxes_dir: S) -> Self {
self.clients_endpoint.inboxes_directory = PathBuf::from(inboxes_dir.into());
@@ -363,20 +227,20 @@ impl Config {
self.gateway.mixnet_contract_address.clone()
}
pub fn get_mix_listening_address(&self) -> SocketAddr {
self.mixnet_endpoint.listening_address
pub fn get_listening_address(&self) -> String {
self.gateway.listening_address.clone()
}
pub fn get_mix_announce_address(&self) -> String {
self.mixnet_endpoint.announce_address.clone()
pub fn get_announce_address(&self) -> String {
self.gateway.announce_address.clone()
}
pub fn get_clients_listening_address(&self) -> SocketAddr {
self.clients_endpoint.listening_address
pub fn get_mix_port(&self) -> u16 {
self.gateway.mix_port
}
pub fn get_clients_announce_address(&self) -> String {
self.clients_endpoint.announce_address.clone()
pub fn get_clients_port(&self) -> u16 {
self.gateway.clients_port
}
pub fn get_clients_inboxes_dir(&self) -> PathBuf {
@@ -429,6 +293,22 @@ pub struct Gateway {
/// ID specifies the human readable ID of this particular gateway.
id: String,
/// Address to which this mixnode will bind to and will be listening for packets.
listening_address: String,
/// Optional address announced to the validator for the clients to connect to.
/// It is useful, say, in NAT scenarios or wanting to more easily update actual IP address
/// later on by using name resolvable with a DNS query, such as `nymtech.net`.
announce_address: String,
/// Port used for listening for all mixnet traffic.
/// (default: 1789)
mix_port: u16,
/// Port used for listening for all client-related traffic.
/// (default: 9000)
clients_port: u16,
/// Path to file containing private identity key.
private_identity_key_file: PathBuf,
@@ -481,6 +361,10 @@ impl Default for Gateway {
Gateway {
version: env!("CARGO_PKG_VERSION").to_string(),
id: "".to_string(),
listening_address: "0.0.0.0".to_string(),
announce_address: "127.0.0.1".to_string(),
mix_port: DEFAULT_MIX_LISTENING_PORT,
clients_port: DEFAULT_CLIENT_LISTENING_PORT,
private_identity_key_file: Default::default(),
public_identity_key_file: Default::default(),
private_sphinx_key_file: Default::default(),
@@ -492,48 +376,9 @@ impl Default for Gateway {
}
}
#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct MixnetEndpoint {
/// Socket address to which this gateway will bind to
/// and will be listening for sphinx packets coming from the mixnet.
listening_address: SocketAddr,
/// Optional address announced to the directory server for the clients to connect to.
/// It is useful, say, in NAT scenarios or wanting to more easily update actual IP address
/// later on by using name resolvable with a DNS query, such as `nymtech.net:8080`.
/// Additionally a custom port can be provided, so both `nymtech.net:8080` and `nymtech.net`
/// are valid announce addresses, while the later will default to whatever port is used for
/// `listening_address`.
announce_address: String,
}
impl Default for MixnetEndpoint {
fn default() -> Self {
MixnetEndpoint {
listening_address: format!("0.0.0.0:{}", DEFAULT_MIX_LISTENING_PORT)
.parse()
.unwrap(),
announce_address: format!("127.0.0.1:{}", DEFAULT_MIX_LISTENING_PORT),
}
}
}
#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ClientsEndpoint {
/// Socket address to which this gateway will bind to
/// and will be listening for data packets coming from the clients.
listening_address: SocketAddr,
/// Optional address announced to the directory server for the clients to connect to.
/// It is useful, say, in NAT scenarios or wanting to more easily update actual IP address
/// later on by using name resolvable with a DNS query, such as `nymtech.net:8080`.
/// Additionally a custom port can be provided, so both `nymtech.net:8080` and `nymtech.net`
/// are valid announce addresses, while the later will default to whatever port is used for
/// `listening_address`.
announce_address: String,
/// Path to the directory with clients inboxes containing messages stored for them.
inboxes_directory: PathBuf,
@@ -555,10 +400,6 @@ impl ClientsEndpoint {
impl Default for ClientsEndpoint {
fn default() -> Self {
ClientsEndpoint {
listening_address: format!("0.0.0.0:{}", DEFAULT_CLIENT_LISTENING_PORT)
.parse()
.unwrap(),
announce_address: format!("ws://127.0.0.1:{}", DEFAULT_CLIENT_LISTENING_PORT),
inboxes_directory: Default::default(),
ledger_path: Default::default(),
}
+32 -13
View File
@@ -70,9 +70,21 @@ impl Gateway {
ack_sender,
);
let listener = mixnet_handling::Listener::new(self.config.get_mix_listening_address());
let listening_address = match format!(
"{}:{}",
self.config.get_listening_address(),
self.config.get_mix_port()
)
.parse()
{
Ok(addr) => addr,
Err(err) => {
error!("Failed to correctly parse socket address - {}", err);
process::exit(1);
}
};
listener.start(connection_handler);
mixnet_handling::Listener::new(listening_address).start(connection_handler);
}
fn start_client_websocket_listener(
@@ -82,11 +94,22 @@ impl Gateway {
) {
info!("Starting client [web]socket listener...");
websocket::Listener::new(
self.config.get_clients_listening_address(),
Arc::clone(&self.identity),
let listening_address = match format!(
"{}:{}",
self.config.get_listening_address(),
self.config.get_clients_port()
)
.start(clients_handler_sender, forwarding_channel);
.parse()
{
Ok(addr) => addr,
Err(err) => {
error!("Failed to correctly parse socket address - {}", err);
process::exit(1);
}
};
websocket::Listener::new(listening_address, Arc::clone(&self.identity))
.start(clients_handler_sender, forwarding_channel);
}
fn start_packet_forwarder(&self) -> MixForwardingSender {
@@ -127,9 +150,6 @@ impl Gateway {
// TODO: ask DH whether this function still makes sense in ^0.10
async fn check_if_same_ip_gateway_exists(&self) -> Option<String> {
let announced_mix_host = self.config.get_mix_announce_address();
let announced_clients_host = self.config.get_clients_announce_address();
let validator_client_config = validator_client::Config::new(
self.config.get_validator_rest_endpoints(),
self.config.get_validator_mixnet_contract_address(),
@@ -144,12 +164,11 @@ impl Gateway {
}
};
let our_host = self.config.get_announce_address();
existing_gateways
.iter()
.find(|node| {
node.gateway.mix_host == announced_mix_host
|| node.gateway.clients_host == announced_clients_host
})
.find(|node| node.gateway.host == our_host)
.map(|node| node.gateway().identity_key.clone())
}
+6 -5
View File
@@ -136,9 +136,8 @@ pub fn execute(matches: &ArgMatches) {
let identity_keypair = load_identity_keys(&pathfinder);
let sphinx_keypair = load_sphinx_keys(&pathfinder);
let listening_ip_string = config.get_listening_address().ip().to_string();
if special_addresses().contains(&listening_ip_string.as_ref()) {
show_binding_warning(listening_ip_string);
if special_addresses().contains(&&*config.get_listening_address()) {
show_binding_warning(config.get_listening_address());
}
println!(
@@ -150,7 +149,7 @@ pub fn execute(matches: &ArgMatches) {
config.get_listening_address()
);
println!(
"Announcing the following socket address: {}",
"Announcing the following address: {}",
config.get_announce_address()
);
@@ -158,7 +157,8 @@ pub fn execute(matches: &ArgMatches) {
"\nTo bond your mixnode, go to https://web-wallet-finney.nymtech.net/. You will need to provide the following:
Identity key: {}
Sphinx key: {}
Host: {}
Address: {}
Mix port: {}
Layer: {}
Location: [physical location of your node's server]
Version: {}
@@ -166,6 +166,7 @@ pub fn execute(matches: &ArgMatches) {
identity_keypair.public_key().to_base58_string(),
sphinx_keypair.public_key().to_base58_string(),
config.get_announce_address(),
config.get_mix_port(),
config.get_layer(),
config.get_version(),
);
+29 -82
View File
@@ -3,11 +3,8 @@
use crate::config::template::config_template;
use config::{deserialize_duration, deserialize_validators, NymConfig};
use log::error;
use serde::{Deserialize, Serialize};
use std::net::{IpAddr, SocketAddr};
use std::path::PathBuf;
use std::str::FromStr;
use std::time::Duration;
pub mod persistence;
@@ -16,7 +13,7 @@ mod template;
pub(crate) const MISSING_VALUE: &str = "MISSING VALUE";
// 'MIXNODE'
const DEFAULT_LISTENING_PORT: u16 = 1789;
const DEFAULT_MIX_LISTENING_PORT: u16 = 1789;
pub(crate) const DEFAULT_VALIDATOR_REST_ENDPOINTS: &[&str] = &[
"http://testnet-finney-validator.nymtech.net:1317",
"http://testnet-finney-validator2.nymtech.net:1317",
@@ -152,77 +149,23 @@ impl Config {
self
}
pub fn with_listening_host<S: Into<String>>(mut self, host: S) -> Self {
// see if the provided `host` is just an ip address or ip:port
let host = host.into();
// is it ip:port?
match SocketAddr::from_str(host.as_ref()) {
Ok(socket_addr) => {
self.mixnode.listening_address = socket_addr;
self
}
// try just for ip
Err(_) => match IpAddr::from_str(host.as_ref()) {
Ok(ip_addr) => {
self.mixnode.listening_address.set_ip(ip_addr);
self
}
Err(_) => {
error!(
"failed to make any changes to config - invalid host {}",
host
);
self
}
},
}
}
pub fn with_listening_port(mut self, port: u16) -> Self {
self.mixnode.listening_address.set_port(port);
pub fn with_listening_address<S: Into<String>>(mut self, listening_address: S) -> Self {
self.mixnode.listening_address = listening_address.into();
self
}
pub fn with_announce_host<S: Into<String>>(mut self, host: S) -> Self {
// this is slightly more complicated as we store announce information as String,
// since it might not necessarily be a valid SocketAddr (say `nymtech.net:8080` is a valid
// announce address, yet invalid SocketAddr`
// first lets see if we received host:port or just host part of an address
let host = host.into();
match host.split(':').count() {
1 => {
// we provided only 'host' part so we are going to reuse existing port
self.mixnode.announce_address =
format!("{}:{}", host, self.mixnode.listening_address.port());
self
}
2 => {
// we provided 'host:port' so just put the whole thing there
self.mixnode.announce_address = host;
self
}
_ => {
// we provided something completely invalid, so don't try to parse it
error!(
"failed to make any changes to config - invalid announce host {}",
host
);
self
}
}
}
pub fn announce_host_from_listening_host(mut self) -> Self {
self.mixnode.announce_address = self.mixnode.listening_address.to_string();
pub fn with_announce_address<S: Into<String>>(mut self, announce_address: S) -> Self {
self.mixnode.announce_address = announce_address.into();
self
}
pub fn with_announce_port(mut self, port: u16) -> Self {
let current_host: Vec<_> = self.mixnode.announce_address.split(':').collect();
debug_assert_eq!(current_host.len(), 2);
self.mixnode.announce_address = format!("{}:{}", current_host[0], port);
pub fn with_mix_port(mut self, port: u16) -> Self {
self.mixnode.mix_port = port;
self
}
pub fn announce_address_from_listening_address(mut self) -> Self {
self.mixnode.announce_address = self.mixnode.listening_address.clone();
self
}
@@ -272,14 +215,18 @@ impl Config {
self.mixnode.layer
}
pub fn get_listening_address(&self) -> SocketAddr {
self.mixnode.listening_address
pub fn get_listening_address(&self) -> String {
self.mixnode.listening_address.clone()
}
pub fn get_announce_address(&self) -> String {
self.mixnode.announce_address.clone()
}
pub fn get_mix_port(&self) -> u16 {
self.mixnode.mix_port
}
pub fn get_packet_forwarding_initial_backoff(&self) -> Duration {
self.debug.packet_forwarding_initial_backoff
}
@@ -349,17 +296,18 @@ pub struct MixNode {
/// Layer of this particular mixnode determining its position in the network.
layer: u64,
/// Socket address to which this mixnode will bind to and will be listening for packets.
listening_address: SocketAddr,
/// Address to which this mixnode will bind to and will be listening for packets.
listening_address: String,
/// Optional address announced to the validator for the clients to connect to.
/// It is useful, say, in NAT scenarios or wanting to more easily update actual IP address
/// later on by using name resolvable with a DNS query, such as `nymtech.net:8080`.
/// Additionally a custom port can be provided, so both `nymtech.net:8080` and `nymtech.net`
/// are valid announce addresses, while the later will default to whatever port is used for
/// `listening_address`.
/// later on by using name resolvable with a DNS query, such as `nymtech.net`.
announce_address: String,
/// Port used for listening for all mixnet traffic.
/// (default: 1789)
mix_port: u16,
/// Path to file containing private identity key.
#[serde(default = "missing_string_value")]
private_identity_key_file: PathBuf,
@@ -374,7 +322,7 @@ pub struct MixNode {
/// Path to file containing public sphinx key.
public_sphinx_key_file: PathBuf,
/// Validator server to which the node will be reporting their presence data.
/// Validator server from which the node gets the view on the network.
#[serde(
deserialize_with = "deserialize_validators",
default = "missing_vec_string_value",
@@ -415,10 +363,9 @@ impl Default for MixNode {
version: env!("CARGO_PKG_VERSION").to_string(),
id: "".to_string(),
layer: 0,
listening_address: format!("0.0.0.0:{}", DEFAULT_LISTENING_PORT)
.parse()
.unwrap(),
announce_address: format!("127.0.0.1:{}", DEFAULT_LISTENING_PORT),
listening_address: "0.0.0.0".to_string(),
announce_address: "127.0.0.1".to_string(),
mix_port: DEFAULT_MIX_LISTENING_PORT,
private_identity_key_file: Default::default(),
public_identity_key_file: Default::default(),
private_sphinx_key_file: Default::default(),
+31 -7
View File
@@ -61,7 +61,7 @@ impl MixNode {
let mut config = rocket::config::Config::release_default();
// bind to the same address as we are using for mixnodes
config.address = self.config.get_listening_address().ip();
config.address = self.config.get_listening_address().parse().unwrap();
let verloc_state = VerlocState::new(atomic_verloc_result);
let descriptor = self.descriptor.clone();
@@ -106,9 +106,21 @@ impl MixNode {
let connection_handler = ConnectionHandler::new(packet_processor, delay_forwarding_channel);
let listener = Listener::new(self.config.get_listening_address());
let listening_address = match format!(
"{}:{}",
self.config.get_listening_address(),
self.config.get_mix_port()
)
.parse()
{
Ok(addr) => addr,
Err(err) => {
error!("Failed to correctly parse socket address - {}", err);
process::exit(1);
}
};
listener.start(connection_handler);
Listener::new(listening_address).start(connection_handler);
}
fn start_packet_delay_forwarder(
@@ -147,10 +159,20 @@ impl MixNode {
// use the same binding address with the HARDCODED port for time being (I don't like that approach personally)
let listening_address = rtt_measurement::replace_port(
let listening_address = match format!(
"{}:{}",
self.config.get_listening_address(),
rtt_measurement::DEFAULT_MEASUREMENT_PORT,
);
rtt_measurement::DEFAULT_MEASUREMENT_PORT
)
.parse()
{
Ok(addr) => addr,
Err(err) => {
error!("Failed to correctly parse socket address - {}", err);
process::exit(1);
}
};
let config = rtt_measurement::ConfigBuilder::new()
.listening_address(listening_address)
.packets_per_node(self.config.get_measurement_packets_per_node())
@@ -186,9 +208,11 @@ impl MixNode {
}
};
let our_host = self.config.get_announce_address();
existing_nodes
.iter()
.find(|node| node.mix_node.host == self.config.get_announce_address())
.find(|node| node.mix_node.host == our_host)
.map(|node| node.mix_node.identity_key.clone())
}
+2 -5
View File
@@ -408,7 +408,7 @@ impl PacketPreparer {
gateway_packets.push(mix_packet.pop().unwrap());
}
packets.push(GatewayPackets::new(
node.client_listener,
node.clients_address(),
node.identity_key,
gateway_packets,
))
@@ -461,10 +461,7 @@ impl PacketPreparer {
// we are not testing the gateway from our 'good' topology -> it's probably
// situation similar to using 'good' qa-topology but testing testnet nodes.
let main_gateway_packets = GatewayPackets::new(
self.tested_network
.main_v4_gateway()
.client_listener
.clone(),
self.tested_network.main_v4_gateway().clients_address(),
main_gateway_id,
mix_packets,
);