mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-06-22 22:31:33 +00:00
core/src/translation: Support dns4 and dns6 (#1204)
* core/src/translation: Add unit tests * core/src/translation: Support dns4 and dns6 Add dns4 and dns6 as valid protocol replacements for the origin address to construct external addresses of a given node. * core/nodes/network: %s/nat_translation/address_translation/ When receiving an observed address on a tcp connection that we initiated, the observed address contains our tcp dial port, not our tcp listen port. We know which port we are listening on, thereby we can replace the port within the observed address. When receiving an observed address on a tcp connection that we did **not** initiated, the observed address should contain our listening port. In case it differs from our listening port there might be a NAT along the path. With the above in mind, the function name `nat_translation` is misleading.
This commit is contained in:
committed by
Pierre Krieger
parent
cde93f5432
commit
5861474d99
@ -714,14 +714,23 @@ where
|
||||
self.incoming_limit
|
||||
}
|
||||
|
||||
/// Call this function in order to know which address remotes should dial in order to access
|
||||
/// your local node.
|
||||
/// Call this function in order to know which address remotes should dial to
|
||||
/// access your local node.
|
||||
///
|
||||
/// `observed_addr` should be an address a remote observes you as, which can be obtained for
|
||||
/// When receiving an observed address on a tcp connection that we initiated, the observed
|
||||
/// address contains our tcp dial port, not our tcp listen port. We know which port we are
|
||||
/// listening on, thereby we can replace the port within the observed address.
|
||||
///
|
||||
/// When receiving an observed address on a tcp connection that we did **not** initiated, the
|
||||
/// observed address should contain our listening port. In case it differs from our listening
|
||||
/// port there might be a proxy along the path.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `observed_addr` - should be an address a remote observes you as, which can be obtained for
|
||||
/// example with the identify protocol.
|
||||
///
|
||||
/// For each listener, calls `nat_traversal` with the observed address and returns the outcome.
|
||||
pub fn nat_traversal<'a>(&'a self, observed_addr: &'a Multiaddr)
|
||||
pub fn address_translation<'a>(&'a self, observed_addr: &'a Multiaddr)
|
||||
-> impl Iterator<Item = Multiaddr> + 'a
|
||||
where
|
||||
TMuxer: 'a,
|
||||
|
@ -22,22 +22,88 @@ use multiaddr::{Multiaddr, Protocol};
|
||||
|
||||
/// Perform IP address translation.
|
||||
///
|
||||
/// Given an `original` [`Multiaddr`] and some `observed` [`Multiaddr`], return
|
||||
/// a translated [`Multiaddr`] which has the first IP address translated by the
|
||||
/// corresponding one from `observed`.
|
||||
/// Given an `original` [`Multiaddr`] and some `observed` [`Multiaddr`], replace the first protocol
|
||||
/// of the `original` with the first protocol of the `observed` [`Multiaddr`] and return this
|
||||
/// translated [`Multiaddr`].
|
||||
///
|
||||
/// This is a mixed-mode translation, i.e. an IPv4 address may be replaced by
|
||||
/// an IPv6 address and vice versa.
|
||||
/// This function can for example be useful when handling tcp connections. Tcp does not listen and
|
||||
/// dial on the same port by default. Thus when receiving an observed address on a connection that
|
||||
/// we initiated, it will contain our dialing port, not our listening port. We need to take the ip
|
||||
/// address or dns address from the observed address and the port from the original address.
|
||||
///
|
||||
/// This is a mixed-mode translation, i.e. an IPv4 / DNS4 address may be replaced by an IPv6 / DNS6
|
||||
/// address and vice versa.
|
||||
///
|
||||
/// If the first [`Protocol`]s are not IP addresses, `None` is returned instead.
|
||||
pub fn address_translation(original: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
|
||||
original.replace(0, move |proto| match proto {
|
||||
Protocol::Ip4(_) | Protocol::Ip6(_) => match observed.iter().next() {
|
||||
Protocol::Ip4(_) | Protocol::Ip6(_) | Protocol::Dns4(_) | Protocol::Dns6(_) => match observed.iter().next() {
|
||||
x @ Some(Protocol::Ip4(_)) => x,
|
||||
x @ Some(Protocol::Ip6(_)) => x,
|
||||
_ => None
|
||||
}
|
||||
_ => None
|
||||
x @ Some(Protocol::Dns4(_)) => x,
|
||||
x @ Some(Protocol::Dns6(_)) => x,
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
// TODO: add tests
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_address_translation() {
|
||||
struct Test {
|
||||
original: Multiaddr,
|
||||
observed: Multiaddr,
|
||||
expected: Multiaddr,
|
||||
}
|
||||
|
||||
let tests = vec![
|
||||
// Basic ipv4.
|
||||
Test {
|
||||
original: "/ip4/192.0.2.1/tcp/1".parse().unwrap(),
|
||||
observed: "/ip4/192.0.2.2/tcp/2".parse().unwrap(),
|
||||
expected: "/ip4/192.0.2.2/tcp/1".parse().unwrap(),
|
||||
},
|
||||
// Basic ipv6.
|
||||
Test {
|
||||
original: "/ip6/2001:db8:0:0:0:0:0:0/tcp/1".parse().unwrap(),
|
||||
observed: "/ip6/2001:db8:0:0:0:0:0:1/tcp/2".parse().unwrap(),
|
||||
expected: "/ip6/2001:db8:0:0:0:0:0:1/tcp/1".parse().unwrap(),
|
||||
},
|
||||
// Ipv4 ipv6 mix.
|
||||
Test {
|
||||
original: "/ip4/192.0.2.1/tcp/1".parse().unwrap(),
|
||||
observed: "/ip6/2001:db8:0:0:0:0:0:1/tcp/2".parse().unwrap(),
|
||||
expected: "/ip6/2001:db8:0:0:0:0:0:1/tcp/1".parse().unwrap(),
|
||||
},
|
||||
// Ipv6 ipv4 mix.
|
||||
Test {
|
||||
original: "/ip6/2001:db8:0:0:0:0:0:0/tcp/1".parse().unwrap(),
|
||||
observed: "/ip4/192.0.2.2/tcp/2".parse().unwrap(),
|
||||
expected: "/ip4/192.0.2.2/tcp/1".parse().unwrap(),
|
||||
},
|
||||
// Dns.
|
||||
Test {
|
||||
original: "/dns4/foo/tcp/1".parse().unwrap(),
|
||||
observed: "/dns4/bar/tcp/2".parse().unwrap(),
|
||||
expected: "/dns4/bar/tcp/1".parse().unwrap(),
|
||||
},
|
||||
// Ipv4 Dns mix.
|
||||
Test {
|
||||
original: "/ip4/192.0.2.1/tcp/1".parse().unwrap(),
|
||||
observed: "/dns4/bar/tcp/2".parse().unwrap(),
|
||||
expected: "/dns4/bar/tcp/1".parse().unwrap(),
|
||||
},
|
||||
];
|
||||
|
||||
for test in tests.iter() {
|
||||
assert_eq!(
|
||||
address_translation(&test.original, &test.observed),
|
||||
Some(test.expected.clone())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -116,7 +116,9 @@ impl Multiaddr {
|
||||
|
||||
/// Returns the components of this multiaddress.
|
||||
///
|
||||
/// ```
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::net::Ipv4Addr;
|
||||
/// use parity_multiaddr::{Multiaddr, Protocol};
|
||||
///
|
||||
@ -174,7 +176,7 @@ impl fmt::Debug for Multiaddr {
|
||||
impl fmt::Display for Multiaddr {
|
||||
/// Convert a Multiaddr to a string
|
||||
///
|
||||
/// # Examples
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use parity_multiaddr::Multiaddr;
|
||||
|
@ -443,7 +443,7 @@ where TBehaviour: NetworkBehaviour<ProtocolsHandler = THandler>,
|
||||
}
|
||||
},
|
||||
Async::Ready(NetworkBehaviourAction::ReportObservedAddr { address }) => {
|
||||
for addr in self.network.nat_traversal(&address) {
|
||||
for addr in self.network.address_translation(&address) {
|
||||
if self.external_addrs.iter().all(|a| *a != addr) {
|
||||
self.behaviour.inject_new_external_addr(&addr);
|
||||
}
|
||||
|
Reference in New Issue
Block a user