validate upnp map

This commit is contained in:
John Smith 2022-08-24 22:03:30 -04:00
parent c0f94ea2b3
commit 317db3cf44
2 changed files with 74 additions and 12 deletions

View File

@ -170,6 +170,43 @@ impl IGDManager {
format!("{} map {} for port {}", self.config.get().program_name, convert_llpt(llpt), local_port ) 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( pub async fn map_any_port(
&self, &self,
llpt: LowLevelProtocolType, llpt: LowLevelProtocolType,

View File

@ -219,14 +219,15 @@ impl DiscoveryContext {
}; };
if enable_upnp { 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 inner = self.inner.lock();
let pt = inner.protocol_type.unwrap(); let pt = inner.protocol_type.unwrap();
let llpt = pt.low_level_protocol_type(); let llpt = pt.low_level_protocol_type();
let at = inner.address_type.unwrap(); let at = inner.address_type.unwrap();
let external_address_1 = inner.external_1_address.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); 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 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())) .map_any_port(llpt, at, local_port, Some(external_address_1.to_ip_addr()))
.await .await
{ {
// make dial info from the port // make dial info from the port mapping
return Some( let external_mapped_dial_info = self
self.make_dial_info( .make_dial_info(SocketAddress::from_socket_addr(mapped_external_address), pt);
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 // Add public dial info with Direct dialinfo class
self.set_detected_public_dial_info(external_1_dial_info, DialInfoClass::Direct); 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 // Attempt a port mapping via all available and enabled mechanisms
else if let Some(external_mapped_dial_info) = self.try_port_mapping().await { else if let Some(external_mapped_dial_info) = self.try_port_mapping().await {
// Got a port mapping, let's use it // Got a port mapping, let's use it
self.set_detected_public_dial_info(external_mapped_dial_info, DialInfoClass::Mapped); self.set_detected_public_dial_info(external_mapped_dial_info, DialInfoClass::Mapped);
self.set_detected_network_class(NetworkClass::InboundCapable);
} else { } else {
// Add public dial info with Blocked dialinfo class // Add public dial info with Blocked dialinfo class
self.set_detected_public_dial_info(external_1_dial_info, DialInfoClass::Blocked); 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(()) Ok(())
} }
@ -362,8 +377,18 @@ impl DiscoveryContext {
) )
}; };
// Attempt a UDP port mapping via all available and enabled mechanisms // Do a validate_dial_info on the external address from a redirected node
if let Some(external_mapped_dial_info) = self.try_port_mapping().await { 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 // Got a port mapping, let's use it
self.set_detected_public_dial_info(external_mapped_dial_info, DialInfoClass::Mapped); self.set_detected_public_dial_info(external_mapped_dial_info, DialInfoClass::Mapped);
self.set_detected_network_class(NetworkClass::InboundCapable); self.set_detected_network_class(NetworkClass::InboundCapable);