Add UPnP support for Lighthouse (#1587)

Adding UPnP support will help grow the DHT by allowing NAT traversal for peers with UPnP supported routers.

## Issue Addressed

#927 

## Proposed Changes

Using IGD library: https://docs.rs/igd/0.10.0/igd/

Adding the  the libp2p tcp port and discovery udp port. If this fails it simply logs the attempt and moves on

## Additional Info



Co-authored-by: Age Manning <Age@AgeManning.com>
This commit is contained in:
Sean
2020-10-02 08:47:00 +00:00
parent 2cc20101d4
commit 94b17ce02b
29 changed files with 342 additions and 33 deletions

View File

@@ -15,7 +15,7 @@ eth2_ssz = "0.1.2"
eth2_ssz_derive = "0.1.0"
slog = { version = "2.5.2", features = ["max_level_trace"] }
lighthouse_version = { path = "../../common/lighthouse_version" }
tokio = { version = "0.2.21", features = ["time", "macros"] }
tokio = { version = "0.2.22", features = ["time", "macros"] }
futures = "0.3.5"
error-chain = "0.12.2"
dirs = "2.0.2"
@@ -46,7 +46,7 @@ default-features = false
features = ["websocket", "identify", "mplex", "noise", "gossipsub", "dns", "tcp-tokio"]
[dev-dependencies]
tokio = { version = "0.2.21", features = ["full"] }
tokio = { version = "0.2.22", features = ["full"] }
slog-stdlog = "4.0.0"
slog-term = "2.5.0"
slog-async = "2.5.0"

View File

@@ -67,6 +67,9 @@ pub struct Config {
/// Disables the discovery protocol from starting.
pub disable_discovery: bool,
/// Attempt to construct external port mappings with UPnP.
pub upnp_enabled: bool,
/// List of extra topics to initially subscribe to as strings.
pub topics: Vec<GossipKind>,
}
@@ -136,6 +139,7 @@ impl Default for Config {
trusted_peers: vec![],
client_version: lighthouse_version::version_with_platform(),
disable_discovery: false,
upnp_enabled: true,
topics: Vec::new(),
}
}

View File

@@ -155,7 +155,7 @@ pub struct Discovery<TSpec: EthSpec> {
/// Indicates if the discovery service has been started. When the service is disabled, this is
/// always false.
started: bool,
pub started: bool,
/// Logger for the discovery behaviour.
log: slog::Logger,
@@ -358,6 +358,54 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
}
}
/// Updates the local ENR TCP port.
/// There currently isn't a case to update the address here. We opt for discovery to
/// automatically update the external address.
///
/// If the external address needs to be modified, use `update_enr_udp_socket.
pub fn update_enr_tcp_port(&mut self, port: u16) -> Result<(), String> {
self.discv5
.enr_insert("tcp", port.to_be_bytes().into())
.map_err(|e| format!("{:?}", e))?;
// replace the global version
*self.network_globals.local_enr.write() = self.discv5.local_enr();
// persist modified enr to disk
enr::save_enr_to_disk(Path::new(&self.enr_dir), &self.local_enr(), &self.log);
Ok(())
}
/// Updates the local ENR UDP socket.
///
/// This is with caution. Discovery should automatically maintain this. This should only be
/// used when automatic discovery is disabled.
pub fn update_enr_udp_socket(&mut self, socket_addr: SocketAddr) -> Result<(), String> {
match socket_addr {
SocketAddr::V4(socket) => {
self.discv5
.enr_insert("ip", socket.ip().octets().into())
.map_err(|e| format!("{:?}", e))?;
self.discv5
.enr_insert("udp", socket.port().to_be_bytes().into())
.map_err(|e| format!("{:?}", e))?;
}
SocketAddr::V6(socket) => {
self.discv5
.enr_insert("ip6", socket.ip().octets().into())
.map_err(|e| format!("{:?}", e))?;
self.discv5
.enr_insert("udp6", socket.port().to_be_bytes().into())
.map_err(|e| format!("{:?}", e))?;
}
}
// replace the global version
*self.network_globals.local_enr.write() = self.discv5.local_enr();
// persist modified enr to disk
enr::save_enr_to_disk(Path::new(&self.enr_dir), &self.local_enr(), &self.log);
Ok(())
}
/// Adds/Removes a subnet from the ENR Bitfield
pub fn update_enr_bitfield(&mut self, subnet_id: SubnetId, value: bool) -> Result<(), String> {
let id = *subnet_id as usize;
@@ -390,9 +438,9 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
.map_err(|_| String::from("Subnet ID out of bounds, could not set subnet ID"))?;
// insert the bitfield into the ENR record
let _ = self
.discv5
.enr_insert(BITFIELD_ENR_KEY, current_bitfield.as_ssz_bytes());
self.discv5
.enr_insert(BITFIELD_ENR_KEY, current_bitfield.as_ssz_bytes())
.map_err(|e| format!("{:?}", e))?;
// replace the global version
*self.network_globals.local_enr.write() = self.discv5.local_enr();