From 317db3cf44c3afa985bf4bbafce08a4c1ef53f08 Mon Sep 17 00:00:00 2001 From: John Smith Date: Wed, 24 Aug 2022 22:03:30 -0400 Subject: [PATCH] validate upnp map --- .../src/network_manager/native/igd_manager.rs | 37 ++++++++++++++ .../native/network_class_discovery.rs | 49 ++++++++++++++----- 2 files changed, 74 insertions(+), 12 deletions(-) diff --git a/veilid-core/src/network_manager/native/igd_manager.rs b/veilid-core/src/network_manager/native/igd_manager.rs index 7dedc8e6..6c4f4a7f 100644 --- a/veilid-core/src/network_manager/native/igd_manager.rs +++ b/veilid-core/src/network_manager/native/igd_manager.rs @@ -170,6 +170,43 @@ impl IGDManager { format!("{} map {} for port {}", self.config.get().program_name, convert_llpt(llpt), local_port ) } + pub async fn unmap_port(&self, + llpt: LowLevelProtocolType, + at: AddressType, + mapped_port: u16, + ) -> Option<()> { + let this = self.clone(); + intf::blocking_wrapper(move || { + let mut inner = this.inner.lock(); + + // If we already have this port mapped, just return the existing portmap + let mut found = None; + for (pmk, pmv) in &inner.port_maps { + if pmk.llpt == llpt && pmk.at == at && pmv.mapped_port == mapped_port { + found = Some(pmk.clone()); + break; + } + } + let pmk = found?; + let pmv = inner.port_maps.remove(&pmk).unwrap(); + + // Find gateway + let gw = Self::find_gateway(&mut *inner, at)?; + + // Unmap port + match gw.remove_port(convert_llpt(llpt), mapped_port) { + Ok(()) => (), + Err(e) => { + // Failed to map external port + log_net!(debug "upnp failed to remove external port: {}", e); + return None; + } + }; + Some(()) + }, None) + .await + } + pub async fn map_any_port( &self, llpt: LowLevelProtocolType, diff --git a/veilid-core/src/network_manager/native/network_class_discovery.rs b/veilid-core/src/network_manager/native/network_class_discovery.rs index 5d7ae6a7..89b85829 100644 --- a/veilid-core/src/network_manager/native/network_class_discovery.rs +++ b/veilid-core/src/network_manager/native/network_class_discovery.rs @@ -219,14 +219,15 @@ impl DiscoveryContext { }; if enable_upnp { - let (pt, llpt, at, external_address_1, local_port) = { + let (pt, llpt, at, external_address_1, node_1, local_port) = { let inner = self.inner.lock(); let pt = inner.protocol_type.unwrap(); let llpt = pt.low_level_protocol_type(); let at = inner.address_type.unwrap(); let external_address_1 = inner.external_1_address.unwrap(); + let node_1 = inner.node_1.as_ref().unwrap().clone(); let local_port = self.net.get_local_port(pt); - (pt, llpt, at, external_address_1, local_port) + (pt, llpt, at, external_address_1, node_1, local_port) }; if let Some(mapped_external_address) = self @@ -236,13 +237,25 @@ impl DiscoveryContext { .map_any_port(llpt, at, local_port, Some(external_address_1.to_ip_addr())) .await { - // make dial info from the port - return Some( - self.make_dial_info( - SocketAddress::from_socket_addr(mapped_external_address), - pt, - ), - ); + // make dial info from the port mapping + let external_mapped_dial_info = self + .make_dial_info(SocketAddress::from_socket_addr(mapped_external_address), pt); + + // ensure people can reach us. if we're firewalled off, this is useless + if self + .validate_dial_info(node_1.clone(), external_mapped_dial_info.clone(), false) + .await + { + return Some(external_mapped_dial_info); + } else { + // release the mapping if we're still unreachable + let _ = self + .net + .unlocked_inner + .igd_manager + .unmap_port(llpt, at, external_address_1.port()) + .await; + } } } @@ -335,16 +348,18 @@ impl DiscoveryContext { { // Add public dial info with Direct dialinfo class self.set_detected_public_dial_info(external_1_dial_info, DialInfoClass::Direct); + self.set_detected_network_class(NetworkClass::InboundCapable); } // Attempt a port mapping via all available and enabled mechanisms else if let Some(external_mapped_dial_info) = self.try_port_mapping().await { // Got a port mapping, let's use it self.set_detected_public_dial_info(external_mapped_dial_info, DialInfoClass::Mapped); + self.set_detected_network_class(NetworkClass::InboundCapable); } else { // Add public dial info with Blocked dialinfo class self.set_detected_public_dial_info(external_1_dial_info, DialInfoClass::Blocked); + self.set_detected_network_class(NetworkClass::InboundCapable); } - self.set_detected_network_class(NetworkClass::InboundCapable); Ok(()) } @@ -362,8 +377,18 @@ impl DiscoveryContext { ) }; - // Attempt a UDP port mapping via all available and enabled mechanisms - if let Some(external_mapped_dial_info) = self.try_port_mapping().await { + // Do a validate_dial_info on the external address from a redirected node + if self + .validate_dial_info(node_1.clone(), external_1_dial_info.clone(), true) + .await + { + // Add public dial info with Direct dialinfo class + self.set_detected_public_dial_info(external_1_dial_info, DialInfoClass::Direct); + self.set_detected_network_class(NetworkClass::InboundCapable); + return Ok(true); + } + // Attempt a port mapping via all available and enabled mechanisms + else if let Some(external_mapped_dial_info) = self.try_port_mapping().await { // Got a port mapping, let's use it self.set_detected_public_dial_info(external_mapped_dial_info, DialInfoClass::Mapped); self.set_detected_network_class(NetworkClass::InboundCapable);