vpncloud/src/port_forwarding.rs

133 lines
5.2 KiB
Rust
Raw Normal View History

2017-07-22 14:49:53 +00:00
// VpnCloud - Peer-to-Peer VPN
2019-02-19 21:04:21 +00:00
// Copyright (C) 2015-2019 Dennis Schwerdel
2017-07-22 14:49:53 +00:00
// This software is licensed under GPL-3 or newer (see LICENSE.md)
use std::{io, net::SocketAddrV4};
use igd::*;
use super::util::{get_internal_ip, SystemTimeSource, Time, TimeSource};
const LEASE_TIME: u32 = 1800;
2019-01-01 23:35:14 +00:00
const DESCRIPTION: &str = "VpnCloud";
pub struct PortForwarding {
pub internal_addr: SocketAddrV4,
pub external_addr: SocketAddrV4,
pub gateway: Gateway,
2019-12-04 08:32:35 +00:00
pub next_extension: Option<Time>
}
impl PortForwarding {
pub fn new(port: u16) -> Option<Self> {
// Get the gateway
2019-12-04 08:32:35 +00:00
let gateway = match search_gateway(Default::default()) {
Ok(gateway) => gateway,
Err(err) => {
if let SearchError::IoError(ref err) = err {
2019-12-04 08:32:35 +00:00
if err.kind() == io::ErrorKind::WouldBlock {
// Why this code?
warn!("Port-forwarding: no router found");
return None
}
}
error!("Port-forwarding: failed to find router: {}", err);
return None
}
};
info!("Port-forwarding: found router at {}", gateway.addr);
let internal_addr = SocketAddrV4::new(get_internal_ip(), port);
// Query the external address
let external_ip = match gateway.get_external_ip() {
Ok(ip) => ip,
Err(err) => {
error!("Port-forwarding: failed to obtain external IP: {}", err);
return None
}
};
// Try to activate the port forwarding
// - First with external port = internal port and timeout
// - If the port is used, request any port
// - If timeout is denied, try permanent forwarding
info!("Port-forwarding: external IP is {}", external_ip);
2019-12-04 08:32:35 +00:00
let (external_addr, timeout) = match gateway.add_port(
PortMappingProtocol::UDP,
internal_addr.port(),
internal_addr,
LEASE_TIME,
DESCRIPTION
) {
Ok(()) => (SocketAddrV4::new(external_ip, internal_addr.port()), LEASE_TIME),
2019-12-04 08:32:35 +00:00
Err(AddPortError::PortInUse) => {
match gateway.add_any_port(PortMappingProtocol::UDP, internal_addr, LEASE_TIME, DESCRIPTION) {
Ok(port) => (SocketAddrV4::new(external_ip, port), LEASE_TIME),
Err(AddAnyPortError::OnlyPermanentLeasesSupported) => {
match gateway.add_any_port(PortMappingProtocol::UDP, internal_addr, 0, DESCRIPTION) {
Ok(port) => (SocketAddrV4::new(external_ip, port), 0),
Err(err) => {
error!("Port-forwarding: failed to activate port forwarding: {}", err);
return None
}
}
}
Err(err) => {
error!("Port-forwarding: failed to activate port forwarding: {}", err);
return None
}
}
2019-12-04 08:32:35 +00:00
}
Err(AddPortError::OnlyPermanentLeasesSupported) => {
match gateway.add_port(PortMappingProtocol::UDP, internal_addr.port(), internal_addr, 0, DESCRIPTION) {
Ok(()) => (SocketAddrV4::new(external_ip, internal_addr.port()), 0),
Err(err) => {
error!("Port-forwarding: failed to activate port forwarding: {}", err);
return None
}
}
2019-12-04 08:32:35 +00:00
}
Err(err) => {
error!("Port-forwarding: failed to activate port forwarding: {}", err);
return None
}
};
info!("Port-forwarding: sucessfully activated port forward on {}, timeout: {}", external_addr, timeout);
2019-12-04 08:32:35 +00:00
let next_extension = if timeout > 0 { Some(SystemTimeSource::now() + Time::from(timeout) - 60) } else { None };
Some(PortForwarding { internal_addr, external_addr, gateway, next_extension })
}
pub fn check_extend(&mut self) {
if let Some(deadline) = self.next_extension {
2019-02-24 19:01:32 +00:00
if deadline > SystemTimeSource::now() {
return
}
} else {
return
}
2019-12-04 08:32:35 +00:00
match self.gateway.add_port(
PortMappingProtocol::UDP,
self.external_addr.port(),
self.internal_addr,
LEASE_TIME,
DESCRIPTION
) {
Ok(()) => debug!("Port-forwarding: extended port forwarding"),
Err(err) => error!("Port-forwarding: failed to extend port forwarding: {}", err)
};
2019-02-24 19:01:32 +00:00
self.next_extension = Some(SystemTimeSource::now() + Time::from(LEASE_TIME) - 60);
}
fn deactivate(&self) {
match self.gateway.remove_port(PortMappingProtocol::UDP, self.external_addr.port()) {
Ok(()) => info!("Port-forwarding: successfully deactivated port forwarding"),
Err(err) => error!("Port-forwarding: failed to deactivate port forwarding: {}", err)
}
}
}
impl Drop for PortForwarding {
fn drop(&mut self) {
self.deactivate()
}
}