Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion common/client-libs/mixnet-client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,6 @@ impl Client {
Default::default(),
&topology,
epoch_id,
local_identity.public_key(),
local_identity.private_key(),
)
.await
Expand Down
50 changes: 16 additions & 34 deletions common/nymnoise/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ pub mod connection;
pub mod error;
pub mod stream;

const NOISE_PSK_PREFIX: &[u8] = b"NYMTECH_NOISE_dQw4w9WgXcQ";

pub async fn upgrade_noise_initiator(
conn: TcpStream,
pattern: NoisePattern,
local_public_key: Option<&encryption::PublicKey>,
local_private_key: &encryption::PrivateKey,
remote_pub_key: &encryption::PublicKey,
epoch: u32,
Expand All @@ -27,9 +28,7 @@ pub async fn upgrade_noise_initiator(

//In case the local key cannot be known by the remote party, e.g. in a client-gateway connection
let secret = [
local_public_key
.map(|k| k.to_bytes().to_vec())
.unwrap_or_default(),
NOISE_PSK_PREFIX.to_vec(),
remote_pub_key.to_bytes().to_vec(),
epoch.to_be_bytes().to_vec(),
]
Expand All @@ -52,7 +51,6 @@ pub async fn upgrade_noise_initiator_with_topology(
pattern: NoisePattern,
topology: &NymTopology,
epoch: u32,
local_public_key: &encryption::PublicKey,
local_private_key: &encryption::PrivateKey,
) -> Result<Connection, NoiseError> {
//Get init material
Expand All @@ -61,7 +59,7 @@ pub async fn upgrade_noise_initiator_with_topology(
Error::Prereq(Prerequisite::RemotePublicKey)
})?;

let remote_pub_key = match topology.find_node_key_by_mix_host(responder_addr) {
let remote_pub_key = match topology.find_node_key_by_mix_host(responder_addr, true) {
Ok(Some(key)) => encryption::PublicKey::from_base58_string(key)?,
Ok(None) => {
warn!(
Expand All @@ -79,32 +77,21 @@ pub async fn upgrade_noise_initiator_with_topology(
}
};

upgrade_noise_initiator(
conn,
pattern,
Some(local_public_key),
local_private_key,
&remote_pub_key,
epoch,
)
.await
upgrade_noise_initiator(conn, pattern, local_private_key, &remote_pub_key, epoch).await
}

pub async fn upgrade_noise_responder(
conn: TcpStream,
pattern: NoisePattern,
local_public_key: &encryption::PublicKey,
local_private_key: &encryption::PrivateKey,
remote_pub_key: Option<&encryption::PublicKey>,
epoch: u32,
) -> Result<Connection, NoiseError> {
trace!("Perform Noise Handshake, responder side");

//If the remote_key cannot be kwnown, e.g. in a client-gateway connection
let secret = [
remote_pub_key
.map(|k| k.to_bytes().to_vec())
.unwrap_or_default(),
NOISE_PSK_PREFIX.to_vec(),
local_public_key.to_bytes().to_vec(),
epoch.to_be_bytes().to_vec(),
]
Expand Down Expand Up @@ -139,31 +126,26 @@ pub async fn upgrade_noise_responder_with_topology(
};

//SW : for private gateway, we could try to perform the handshake without that key?
let remote_pub_key = match topology.find_node_key_by_mix_host(initiator_addr) {
Ok(Some(key)) => encryption::PublicKey::from_base58_string(key)?,
match topology.find_node_key_by_mix_host(initiator_addr, false) {
Ok(Some(_)) => {
//Existing node supporting Noise
upgrade_noise_responder(conn, pattern, local_public_key, local_private_key, epoch).await
}
Ok(None) => {
//Existing node not supporting Noise yet
warn!(
"{:?} can't speak Noise yet, falling back to TCP",
initiator_addr
);
return Ok(Connection::Tcp(conn));
Ok(Connection::Tcp(conn))
}
Err(_) => {
//Non existing node
error!(
"Cannot find public key for node with address {:?}",
initiator_addr
); //Do we still pursue a TCP connection with that node or not?
return Err(Error::Prereq(Prerequisite::RemotePublicKey).into());
Err(Error::Prereq(Prerequisite::RemotePublicKey).into())
}
};

upgrade_noise_responder(
conn,
pattern,
local_public_key,
local_private_key,
Some(&remote_pub_key),
epoch,
)
.await
}
}
8 changes: 4 additions & 4 deletions common/nymsphinx/src/receiver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ mod message_receiver {
mix_id: 123,
owner: "foomp1".to_string(),
host: "10.20.30.40".parse().unwrap(),
mix_host: "10.20.30.40:1789".parse().unwrap(),
mix_hosts: vec!["10.20.30.40:1789".parse().unwrap()],
identity_key: identity::PublicKey::from_base58_string(
"3ebjp1Fb9hdcS1AR6AZihgeJiMHkB5jjJUsvqNnfQwU7",
)
Expand All @@ -257,7 +257,7 @@ mod message_receiver {
mix_id: 234,
owner: "foomp2".to_string(),
host: "11.21.31.41".parse().unwrap(),
mix_host: "11.21.31.41:1789".parse().unwrap(),
mix_hosts: vec!["11.21.31.41:1789".parse().unwrap()],
identity_key: identity::PublicKey::from_base58_string(
"D6YaMzLSY7mANtSQRKXsmMZpqgqiVkeiagKM4V4oFPFr",
)
Expand All @@ -277,7 +277,7 @@ mod message_receiver {
mix_id: 456,
owner: "foomp3".to_string(),
host: "12.22.32.42".parse().unwrap(),
mix_host: "12.22.32.42:1789".parse().unwrap(),
mix_hosts: vec!["12.22.32.42:1789".parse().unwrap()],
identity_key: identity::PublicKey::from_base58_string(
"GkWDysw4AjESv1KiAiVn7JzzCMJeksxNSXVfr1PpX8wD",
)
Expand All @@ -297,7 +297,7 @@ mod message_receiver {
vec![gateway::Node {
owner: "foomp4".to_string(),
host: "1.2.3.4".parse().unwrap(),
mix_host: "1.2.3.4:1789".parse().unwrap(),
mix_hosts: vec!["1.2.3.4:1789".parse().unwrap()],
clients_ws_port: 9000,
clients_wss_port: None,
identity_key: identity::PublicKey::from_base58_string(
Expand Down
30 changes: 16 additions & 14 deletions common/topology/src/gateway.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ pub enum GatewayConversionError {
pub struct Node {
pub owner: String,
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,
// we're keeping all resolved IPs as a separate field since we do not want to be resolving the potential
// hostname every time we want to construct a path via this node. When we need one, we default to the first one
pub mix_hosts: Vec<SocketAddr>,

// #[serde(alias = "clients_port")]
pub clients_ws_port: u16,
Expand All @@ -66,7 +66,7 @@ impl std::fmt::Debug for Node {
f.debug_struct("gateway::Node")
.field("host", &self.host)
.field("owner", &self.owner)
.field("mix_host", &self.mix_host)
.field("mix_hosts", &self.mix_hosts)
.field("clients_ws_port", &self.clients_ws_port)
.field("clients_wss_port", &self.clients_wss_port)
.field("identity_key", &self.identity_key.to_base58_string())
Expand All @@ -88,13 +88,12 @@ impl Node {
pub fn extract_mix_host(
host: &NetworkAddress,
mix_port: u16,
) -> Result<SocketAddr, GatewayConversionError> {
Ok(host.to_socket_addrs(mix_port).map_err(|err| {
GatewayConversionError::InvalidAddress {
) -> Result<Vec<SocketAddr>, GatewayConversionError> {
host.to_socket_addrs(mix_port)
.map_err(|err| GatewayConversionError::InvalidAddress {
value: host.to_string(),
source: err,
}
})?[0])
})
}

pub fn identity(&self) -> &NodeIdentity {
Expand Down Expand Up @@ -135,7 +134,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.mix_host)
let node_address_bytes = NymNodeRoutingAddress::from(node.mix_hosts[0])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.first()

.try_into()
.unwrap();

Expand All @@ -151,12 +150,12 @@ impl<'a> TryFrom<&'a GatewayBond> for Node {

// 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 = Self::extract_mix_host(&host, bond.gateway.mix_port)?;
let mix_hosts = Self::extract_mix_host(&host, bond.gateway.mix_port)?;

Ok(Node {
owner: bond.owner.as_str().to_owned(),
host,
mix_host,
mix_hosts,
clients_ws_port: bond.gateway.clients_port,
clients_wss_port: None,
identity_key: identity::PublicKey::from_base58_string(&bond.gateway.identity_key)?,
Expand Down Expand Up @@ -196,12 +195,15 @@ impl<'a> TryFrom<&'a DescribedGateway> for Node {

// get ip from the self-reported values so we wouldn't need to do any hostname resolution
// (which doesn't really work in wasm)
let mix_host = SocketAddr::new(ips[0], value.bond.gateway.mix_port);
let mix_hosts = ips
.iter()
.map(|ip| SocketAddr::new(*ip, value.bond.gateway.mix_port))
.collect();

Ok(Node {
owner: value.bond.owner.as_str().to_owned(),
host,
mix_host,
mix_hosts,
clients_ws_port: self_described.mixnet_websockets.unwrap().ws_port, //SW gateway have that field
clients_wss_port: self_described.mixnet_websockets.unwrap().wss_port, //SW gateway have that field
identity_key: identity::PublicKey::from_base58_string(
Expand Down
50 changes: 33 additions & 17 deletions common/topology/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,27 +189,43 @@ impl NymTopology {
pub fn find_node_key_by_mix_host(
&self,
mix_host: SocketAddr,
check_port: bool,
) -> Result<Option<String>, NymTopologyError> {
for node in self.described_nodes.iter() {
let sphinx_key = match node {
DescribedNymNode::Gateway(g) => &g.bond.gateway.sphinx_key,
DescribedNymNode::Mixnode(m) => &m.bond.mix_node.sphinx_key,
let (sphinx_key, socket_addresses, description) = match node {
DescribedNymNode::Gateway(g) => {
let sphinx_key = &g.bond.gateway.sphinx_key;
let gateway_node: Option<gateway::Node> = (&g.bond).try_into().ok();
let mix_hosts = gateway_node.map(|node| node.mix_hosts);
let description = &g.self_described;
(sphinx_key, mix_hosts, description)
}
DescribedNymNode::Mixnode(m) => {
let sphinx_key = &m.bond.mix_node.sphinx_key;
let mix_node: Option<mix::Node> = (&m.bond).try_into().ok();
let mix_hosts = mix_node.map(|node| node.mix_hosts);
let description = &m.self_described;
(sphinx_key, mix_hosts, description)
}
};
if let Some(description) = match node {
DescribedNymNode::Gateway(g) => &g.self_described,
DescribedNymNode::Mixnode(m) => &m.self_described,
} {
if description
.host_information
.ip_address
.contains(&mix_host.ip())
{
if let Some(sock_addr) = socket_addresses {
let existing_node = if check_port {
//Initiator side, we know the port should be correct as well
sock_addr.contains(&mix_host)
} else {
//responder side, we don't know the port.
//SW This can lead to some troubles if two nodes shares the same IP and one support Noise but not the other. This in only for the progressive update though
let ip_addresses = sock_addr.iter().map(|addr| addr.ip()).collect::<Vec<_>>();
ip_addresses.contains(&mix_host.ip())
};
if existing_node {
//we have our node
if description.noise_information.supported {
return Ok(Some(sphinx_key.to_string()));
} else {
return Ok(None);
if let Some(d) = description {
if d.noise_information.supported {
return Ok(Some(sphinx_key.to_string()));
}
}
return Ok(None);
}
}
}
Expand Down Expand Up @@ -539,7 +555,7 @@ mod converting_mixes_to_vec {
mix_id: 42,
owner: "N/A".to_string(),
host: "3.3.3.3".parse().unwrap(),
mix_host: "3.3.3.3:1789".parse().unwrap(),
mix_hosts: vec!["3.3.3.3:1789".parse().unwrap()],
identity_key: identity::PublicKey::from_base58_string(
"3ebjp1Fb9hdcS1AR6AZihgeJiMHkB5jjJUsvqNnfQwU7",
)
Expand Down
23 changes: 11 additions & 12 deletions common/topology/src/mix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ pub struct Node {
pub mix_id: MixId,
pub owner: String,
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,
// we're keeping all resolved IPs as a separate field since we do not want to be resolving the potential
// hostname every time we want to construct a path via this node. When we need one, we default to the first one
pub mix_hosts: Vec<SocketAddr>,
pub identity_key: identity::PublicKey,
pub sphinx_key: encryption::PublicKey, // TODO: or nymsphinx::PublicKey? both are x25519
pub layer: Layer,
Expand All @@ -49,7 +49,7 @@ impl std::fmt::Debug for Node {
.field("mix_id", &self.mix_id)
.field("owner", &self.owner)
.field("host", &self.host)
.field("mix_host", &self.mix_host)
.field("mix_hosts", &self.mix_hosts)
.field("identity_key", &self.identity_key.to_base58_string())
.field("sphinx_key", &self.sphinx_key.to_base58_string())
.field("layer", &self.layer)
Expand All @@ -70,13 +70,12 @@ impl Node {
pub fn extract_mix_host(
host: &NetworkAddress,
mix_port: u16,
) -> Result<SocketAddr, MixnodeConversionError> {
Ok(host.to_socket_addrs(mix_port).map_err(|err| {
MixnodeConversionError::InvalidAddress {
) -> Result<Vec<SocketAddr>, MixnodeConversionError> {
host.to_socket_addrs(mix_port)
.map_err(|err| MixnodeConversionError::InvalidAddress {
value: host.to_string(),
source: err,
}
})?[0])
})
}
}

Expand All @@ -89,7 +88,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.mix_host)
let node_address_bytes = NymNodeRoutingAddress::from(node.mix_hosts[0])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.first()

.try_into()
.unwrap();

Expand All @@ -105,13 +104,13 @@ impl<'a> TryFrom<&'a MixNodeBond> for Node {

// 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 = Self::extract_mix_host(&host, bond.mix_node.mix_port)?;
let mix_hosts = Self::extract_mix_host(&host, bond.mix_node.mix_port)?;

Ok(Node {
mix_id: bond.mix_id,
owner: bond.owner.as_str().to_owned(),
host,
mix_host,
mix_hosts,
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.layer,
Expand Down
Loading