Reducing published peer timeout to 5 min on NAT

This commit is contained in:
Dennis Schwerdel 2019-12-04 10:34:08 +01:00
parent ee8542307f
commit 9cd7e53880
5 changed files with 40 additions and 21 deletions

View File

@ -4,6 +4,8 @@ This project follows [semantic versioning](http://semver.org).
### Unreleased ### Unreleased
- [added] Exchange peer timeout and adapt keepalive accordingly
- [added] Reducing published peer timeout to 5 min when NAT is detected
- [changed] Rust version 1.41.0 - [changed] Rust version 1.41.0
- [changed] Updated dependencies - [changed] Updated dependencies

View File

@ -227,6 +227,7 @@ pub struct GenericCloud<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSou
device: D, device: D,
crypto: Crypto, crypto: Crypto,
next_peerlist: Time, next_peerlist: Time,
peer_timeout_publish: u16,
update_freq: u16, update_freq: u16,
buffer_out: [u8; 64 * 1024], buffer_out: [u8; 64 * 1024],
next_housekeep: Time, next_housekeep: Time,
@ -255,15 +256,22 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
Err(err) => fail!("Failed to open ipv6 address ::{}: {}", config.port, err) Err(err) => fail!("Failed to open ipv6 address ::{}: {}", config.port, err)
}; };
let now = TS::now(); let now = TS::now();
let peer_timeout_publish = if S::detect_nat() {
info!("Private IP detected, setting published peer timeout to 300s");
300
} else {
config.peer_timeout as u16
};
let mut res = GenericCloud { let mut res = GenericCloud {
magic: config.get_magic(), magic: config.get_magic(),
node_id: random(), node_id: random(),
peers: PeerList::new(config.peer_timeout as Duration), peers: PeerList::new(config.peer_timeout),
addresses, addresses,
learning, learning,
broadcast, broadcast,
reconnect_peers: Vec::new(), reconnect_peers: Vec::new(),
own_addresses: Vec::new(), own_addresses: Vec::new(),
peer_timeout_publish,
table, table,
socket4, socket4,
socket6, socket6,
@ -414,7 +422,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
// Send a message to each resolved address // Send a message to each resolved address
for a in resolve(&addr)? { for a in resolve(&addr)? {
// Ignore error this time // Ignore error this time
let mut msg = Message::Init(0, node_id, subnets.clone(), self.config.peer_timeout as u16); let mut msg = Message::Init(0, node_id, subnets.clone(), self.peer_timeout_publish);
self.send_msg(a, &mut msg).ok(); self.send_msg(a, &mut msg).ok();
} }
Ok(()) Ok(())
@ -435,7 +443,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
debug!("Connecting to {:?}", addr); debug!("Connecting to {:?}", addr);
let subnets = self.addresses.clone(); let subnets = self.addresses.clone();
let node_id = self.node_id; let node_id = self.node_id;
let mut msg = Message::Init(0, node_id, subnets.clone(), self.config.peer_timeout as u16); let mut msg = Message::Init(0, node_id, subnets.clone(), self.peer_timeout_publish);
self.send_msg(addr, &mut msg) self.send_msg(addr, &mut msg)
} }
@ -725,7 +733,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
let own_node_id = self.node_id; let own_node_id = self.node_id;
self.send_msg( self.send_msg(
peer, peer,
&mut Message::Init(stage + 1, own_node_id, own_addrs, self.config.peer_timeout as u16) &mut Message::Init(stage + 1, own_node_id, own_addrs, self.peer_timeout_publish)
)?; )?;
} }
// Send peers in any case // Send peers in any case

View File

@ -5,6 +5,8 @@ use std::{
os::unix::io::{AsRawFd, RawFd} os::unix::io::{AsRawFd, RawFd}
}; };
use super::util::get_internal_ip;
use net2::UdpBuilder; use net2::UdpBuilder;
@ -14,6 +16,7 @@ pub trait Socket: AsRawFd + Sized {
fn receive(&mut self, buffer: &mut [u8]) -> Result<(usize, SocketAddr), io::Error>; fn receive(&mut self, buffer: &mut [u8]) -> Result<(usize, SocketAddr), io::Error>;
fn send(&mut self, data: &[u8], addr: SocketAddr) -> Result<usize, io::Error>; fn send(&mut self, data: &[u8], addr: SocketAddr) -> Result<usize, io::Error>;
fn address(&self) -> Result<SocketAddr, io::Error>; fn address(&self) -> Result<SocketAddr, io::Error>;
fn detect_nat() -> bool;
} }
impl Socket for UdpSocket { impl Socket for UdpSocket {
@ -42,6 +45,9 @@ impl Socket for UdpSocket {
fn address(&self) -> Result<SocketAddr, io::Error> { fn address(&self) -> Result<SocketAddr, io::Error> {
self.local_addr() self.local_addr()
} }
fn detect_nat() -> bool {
get_internal_ip().is_private()
}
} }
@ -95,4 +101,7 @@ impl Socket for MockSocket {
fn address(&self) -> Result<SocketAddr, io::Error> { fn address(&self) -> Result<SocketAddr, io::Error> {
Ok(self.address) Ok(self.address)
} }
fn detect_nat() -> bool {
false
}
} }

View File

@ -2,16 +2,13 @@
// Copyright (C) 2015-2019 Dennis Schwerdel // Copyright (C) 2015-2019 Dennis Schwerdel
// This software is licensed under GPL-3 or newer (see LICENSE.md) // This software is licensed under GPL-3 or newer (see LICENSE.md)
use std::{ use std::{io, net::SocketAddrV4};
io,
net::{SocketAddr, SocketAddrV4, UdpSocket}
};
use igd::*; use igd::*;
use super::util::{SystemTimeSource, Time, TimeSource}; use super::util::{get_internal_ip, SystemTimeSource, Time, TimeSource};
const LEASE_TIME: u32 = 300; const LEASE_TIME: u32 = 1800;
const DESCRIPTION: &str = "VpnCloud"; const DESCRIPTION: &str = "VpnCloud";
@ -40,16 +37,7 @@ impl PortForwarding {
} }
}; };
info!("Port-forwarding: found router at {}", gateway.addr); info!("Port-forwarding: found router at {}", gateway.addr);
// Get the internal address (this trick gets the address by opening a UDP connection which let internal_addr = SocketAddrV4::new(get_internal_ip(), port);
// does not really open anything but returns the correct address)
let dummy_sock = UdpSocket::bind("0.0.0.0:0").expect("Failed to bind");
dummy_sock.connect(gateway.addr).expect("Failed to connect");
let internal_addr;
if let SocketAddr::V4(addr) = dummy_sock.local_addr().expect("Failed to get local address") {
internal_addr = SocketAddrV4::new(*addr.ip(), port);
} else {
unreachable!()
}
// Query the external address // Query the external address
let external_ip = match gateway.get_external_ip() { let external_ip = match gateway.get_external_ip() {
Ok(ip) => ip, Ok(ip) => ip,

View File

@ -4,7 +4,7 @@
use std::{ use std::{
fmt, fmt,
net::{SocketAddr, ToSocketAddrs}, net::{Ipv4Addr, SocketAddr, ToSocketAddrs, UdpSocket},
sync::atomic::{AtomicIsize, Ordering} sync::atomic::{AtomicIsize, Ordering}
}; };
@ -115,6 +115,18 @@ macro_rules! try_fail {
} ); } );
} }
pub fn get_internal_ip() -> Ipv4Addr {
// Get the internal address (this trick gets the address by opening a UDP connection which
// does not really open anything but returns the correct address)
let dummy_sock = UdpSocket::bind("0.0.0.0:0").expect("Failed to bind");
dummy_sock.connect("8.8.8.8:53").expect("Failed to connect");
if let SocketAddr::V4(addr) = dummy_sock.local_addr().expect("Failed to get local address") {
*addr.ip()
} else {
unreachable!()
}
}
#[allow(unknown_lints, clippy::needless_pass_by_value)] #[allow(unknown_lints, clippy::needless_pass_by_value)]
pub fn resolve<Addr: ToSocketAddrs + fmt::Debug>(addr: Addr) -> Result<Vec<SocketAddr>, Error> { pub fn resolve<Addr: ToSocketAddrs + fmt::Debug>(addr: Addr) -> Result<Vec<SocketAddr>, Error> {