From 2c98d0694235aba3ee89e8b43d639af2e6d1651d Mon Sep 17 00:00:00 2001 From: Toralf Wittner Date: Mon, 15 Oct 2018 16:29:32 +0200 Subject: [PATCH] Change some `nat_traversal`s to consider a prefix. (#550) Change some `nat_traversal`s to consider a prefix. Transports should consider only the relevant address prefix. --- core/src/transport/mod.rs | 8 +++- misc/multiaddr/src/lib.rs | 5 +++ transports/tcp/src/lib.rs | 42 ++++++-------------- transports/websocket/src/browser.rs | 61 ++++++++++++----------------- transports/websocket/src/desktop.rs | 20 +--------- 5 files changed, 49 insertions(+), 87 deletions(-) diff --git a/core/src/transport/mod.rs b/core/src/transport/mod.rs index da50b339..77354f20 100644 --- a/core/src/transport/mod.rs +++ b/core/src/transport/mod.rs @@ -116,8 +116,12 @@ pub trait Transport { /// a remote node observes for one of our dialers. /// /// For example, if `server` is `/ip4/0.0.0.0/tcp/3000` and `observed` is - /// `/ip4/80.81.82.83/tcp/29601`, then we should return `/ip4/80.81.82.83/tcp/3000`. Each - /// implementation of `Transport` is only responsible for handling the protocols it supports. + /// `/ip4/80.81.82.83/tcp/29601`, then we should return `/ip4/80.81.82.83/tcp/3000`. + /// + /// Each implementation of `Transport` is only responsible for handling the protocols it + /// supports and should only consider the prefix of `observed` necessary to perform the + /// address translation (e.g. `/ip4/80.81.82.83`) but should otherwise preserve `server` + /// as is. /// /// Returns `None` if nothing can be determined. This happens if this trait implementation /// doesn't recognize the protocols, or if `server` and `observed` are related. diff --git a/misc/multiaddr/src/lib.rs b/misc/multiaddr/src/lib.rs index eb7051c4..04c4c560 100644 --- a/misc/multiaddr/src/lib.rs +++ b/misc/multiaddr/src/lib.rs @@ -120,6 +120,11 @@ impl fmt::Display for Multiaddr { } impl Multiaddr { + /// Create a new, empty multiaddress. + pub fn empty() -> Multiaddr { + Multiaddr { bytes: Vec::new() } + } + /// Returns the raw bytes representation of the multiaddr. #[inline] pub fn into_bytes(self) -> Vec { diff --git a/transports/tcp/src/lib.rs b/transports/tcp/src/lib.rs index aa92aa2e..01f8498f 100644 --- a/transports/tcp/src/lib.rs +++ b/transports/tcp/src/lib.rs @@ -54,7 +54,6 @@ use futures::{future, future::FutureResult, prelude::*, Async, Poll}; use multiaddr::{Protocol, Multiaddr, ToMultiaddr}; use std::fmt; use std::io::{Error as IoError, Read, Write}; -use std::iter; use std::net::SocketAddr; use std::time::Duration; use swarm::Transport; @@ -194,40 +193,21 @@ impl Transport for TcpConfig { } fn nat_traversal(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { - // Check that `server` only has two components and retreive them. - let mut server_protocols_iter = server.iter(); - let server_proto1 = server_protocols_iter.next()?; - let server_proto2 = server_protocols_iter.next()?; - if server_protocols_iter.next().is_some() { - return None; + let mut address = Multiaddr::empty(); + + // Use the observed IP address. + match server.iter().zip(observed.iter()).next() { + Some((Protocol::Ip4(_), x@Protocol::Ip4(_))) => address.append(x), + Some((Protocol::Ip6(_), x@Protocol::Ip6(_))) => address.append(x), + _ => return None } - // Check that `observed` only has two components and retreive them. - let mut observed_protocols_iter = observed.iter(); - let observed_proto1 = observed_protocols_iter.next()?; - let observed_proto2 = observed_protocols_iter.next()?; - if observed_protocols_iter.next().is_some() { - return None; + // Carry over everything else from the server address. + for proto in server.iter().skip(1) { + address.append(proto) } - // Check that `server` is a valid TCP/IP address. - match (&server_proto1, &server_proto2) { - (&Protocol::Ip4(_), &Protocol::Tcp(_)) - | (&Protocol::Ip6(_), &Protocol::Tcp(_)) => {} - _ => return None, - } - - // Check that `observed` is a valid TCP/IP address. - match (&observed_proto1, &observed_proto2) { - (&Protocol::Ip4(_), &Protocol::Tcp(_)) - | (&Protocol::Ip6(_), &Protocol::Tcp(_)) => {} - _ => return None, - } - - let result = iter::once(observed_proto1.clone()) - .chain(iter::once(server_proto2.clone())) - .collect(); - Some(result) + Some(address) } } diff --git a/transports/websocket/src/browser.rs b/transports/websocket/src/browser.rs index d8a0bb5f..e62a69c1 100644 --- a/transports/websocket/src/browser.rs +++ b/transports/websocket/src/browser.rs @@ -209,49 +209,40 @@ impl Transport for BrowserWsConfig { } fn nat_traversal(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { - let mut server_protocols = server.iter(); - let server_proto0 = server_protocols.next()?; - let server_proto1 = server_protocols.next()?; - let server_proto2 = server_protocols.next()?; - if server_protocols.next().is_some() { - return None; + let mut address = Multiaddr::empty(); + + let mut iter = server.iter().zip(observed.iter()); + + // Use the observed IP address. + match iter.next() { + Some((Protocol::Ip4(_), x@Protocol::Ip4(_))) => address.append(x), + Some((Protocol::Ip6(_), x@Protocol::Ip6(_))) => address.append(x), + _ => return None } - let mut observed_protocols = observed.iter(); - let obs_proto0 = observed_protocols.next()?; - let obs_proto1 = observed_protocols.next()?; - let obs_proto2 = observed_protocols.next()?; - if observed_protocols.next().is_some() { - return None; + // Skip over next protocol (assumed to contain port information). + if iter.next().is_none() { + return None } - // Check that `server` is a valid TCP/IP address. - match (&server_proto0, &server_proto1, &server_proto2) { - (&Protocol::Ip4(_), &Protocol::Tcp(_), &Protocol::Ws) - | (&Protocol::Ip6(_), &Protocol::Tcp(_), &Protocol::Ws) - | (&Protocol::Ip4(_), &Protocol::Tcp(_), &Protocol::Wss) - | (&Protocol::Ip6(_), &Protocol::Tcp(_), &Protocol::Wss) => {} - _ => return None, + // Check for WS/WSS. + // + // Note that it will still work if the server uses WSS while the client uses + // WS, or vice-versa. + match iter.next() { + Some((x@Protocol::Ws, Protocol::Ws)) => address.append(x), + Some((x@Protocol::Ws, Protocol::Wss)) => address.append(x), + Some((x@Protocol::Wss, Protocol::Ws)) => address.append(x), + Some((x@Protocol::Wss, Protocol::Wss)) => address.append(x), + _ => return None } - // Check that `observed` is a valid TCP/IP address. - match (&obs_proto0, &obs_proto1, &obs_proto2) { - (&Protocol::Ip4(_), &Protocol::Tcp(_), &Protocol::Ws) - | (&Protocol::Ip6(_), &Protocol::Tcp(_), &Protocol::Ws) - | (&Protocol::Ip4(_), &Protocol::Tcp(_), &Protocol::Wss) - | (&Protocol::Ip6(_), &Protocol::Tcp(_), &Protocol::Wss) => {} - _ => return None, + // Carry over everything else from the server address. + for proto in server.iter().skip(3) { + address.append(proto) } - // Note that it will still work if the server uses WSS while the client uses WS, - // or vice-versa. - - let result = iter::once(obs_proto0) - .chain(iter::once(server_proto1)) - .chain(iter::once(server_proto2)) - .collect(); - - Some(result) + Some(address) } } diff --git a/transports/websocket/src/desktop.rs b/transports/websocket/src/desktop.rs index 4e6321f3..a86d4636 100644 --- a/transports/websocket/src/desktop.rs +++ b/transports/websocket/src/desktop.rs @@ -236,25 +236,7 @@ where } fn nat_traversal(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { - let mut server = server.clone(); - let last_proto = match server.pop() { - Some(v @ Protocol::Ws) | Some(v @ Protocol::Wss) => v, - _ => return None, - }; - - let mut observed = observed.clone(); - match observed.pop() { - Some(Protocol::Ws) => false, - Some(Protocol::Wss) => true, - _ => return None, - }; - - self.transport - .nat_traversal(&server, &observed) - .map(move |mut result| { - result.append(last_proto); - result - }) + self.transport.nat_traversal(server, observed) } }