mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-06-22 14:21: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
|
self.incoming_limit
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call this function in order to know which address remotes should dial in order to access
|
/// Call this function in order to know which address remotes should dial to
|
||||||
/// your local node.
|
/// 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.
|
/// example with the identify protocol.
|
||||||
///
|
///
|
||||||
/// For each listener, calls `nat_traversal` with the observed address and returns the outcome.
|
pub fn address_translation<'a>(&'a self, observed_addr: &'a Multiaddr)
|
||||||
pub fn nat_traversal<'a>(&'a self, observed_addr: &'a Multiaddr)
|
|
||||||
-> impl Iterator<Item = Multiaddr> + 'a
|
-> impl Iterator<Item = Multiaddr> + 'a
|
||||||
where
|
where
|
||||||
TMuxer: 'a,
|
TMuxer: 'a,
|
||||||
|
@ -22,22 +22,88 @@ use multiaddr::{Multiaddr, Protocol};
|
|||||||
|
|
||||||
/// Perform IP address translation.
|
/// Perform IP address translation.
|
||||||
///
|
///
|
||||||
/// Given an `original` [`Multiaddr`] and some `observed` [`Multiaddr`], return
|
/// Given an `original` [`Multiaddr`] and some `observed` [`Multiaddr`], replace the first protocol
|
||||||
/// a translated [`Multiaddr`] which has the first IP address translated by the
|
/// of the `original` with the first protocol of the `observed` [`Multiaddr`] and return this
|
||||||
/// corresponding one from `observed`.
|
/// translated [`Multiaddr`].
|
||||||
///
|
///
|
||||||
/// This is a mixed-mode translation, i.e. an IPv4 address may be replaced by
|
/// This function can for example be useful when handling tcp connections. Tcp does not listen and
|
||||||
/// an IPv6 address and vice versa.
|
/// 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.
|
/// If the first [`Protocol`]s are not IP addresses, `None` is returned instead.
|
||||||
pub fn address_translation(original: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
|
pub fn address_translation(original: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
|
||||||
original.replace(0, move |proto| match proto {
|
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::Ip4(_)) => x,
|
||||||
x@Some(Protocol::Ip6(_)) => x,
|
x @ Some(Protocol::Ip6(_)) => x,
|
||||||
_ => None
|
x @ Some(Protocol::Dns4(_)) => x,
|
||||||
}
|
x @ Some(Protocol::Dns6(_)) => x,
|
||||||
_ => None
|
_ => 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.
|
/// Returns the components of this multiaddress.
|
||||||
///
|
///
|
||||||
/// ```
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
/// use std::net::Ipv4Addr;
|
/// use std::net::Ipv4Addr;
|
||||||
/// use parity_multiaddr::{Multiaddr, Protocol};
|
/// use parity_multiaddr::{Multiaddr, Protocol};
|
||||||
///
|
///
|
||||||
@ -174,7 +176,7 @@ impl fmt::Debug for Multiaddr {
|
|||||||
impl fmt::Display for Multiaddr {
|
impl fmt::Display for Multiaddr {
|
||||||
/// Convert a Multiaddr to a string
|
/// Convert a Multiaddr to a string
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use parity_multiaddr::Multiaddr;
|
/// use parity_multiaddr::Multiaddr;
|
||||||
|
@ -443,7 +443,7 @@ where TBehaviour: NetworkBehaviour<ProtocolsHandler = THandler>,
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Async::Ready(NetworkBehaviourAction::ReportObservedAddr { address }) => {
|
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) {
|
if self.external_addrs.iter().all(|a| *a != addr) {
|
||||||
self.behaviour.inject_new_external_addr(&addr);
|
self.behaviour.inject_new_external_addr(&addr);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user