Compare commits

...

2 Commits

Author SHA1 Message Date
Dennis Schwerdel 2fcf2c1e01 Fixed problem with TUN on dynamic host addresses 2020-07-20 23:56:48 +02:00
Dennis Schwerdel 86223fb4f9 Potential fix for port-forwarding 2020-07-20 22:58:55 +02:00
6 changed files with 47 additions and 31 deletions

View File

@ -8,7 +8,10 @@ This project follows [semantic versioning](http://semver.org).
- [added] Added crypto option AES128
- [added] Default port for peers
- [changed] Updated dependencies
- [changed] Removed C code, now 100% Rust
- [fixed] Fixed keepalive for small timeouts
- [fixed] Fixed problem with port forwarding
- [fixed] Fixed problem with TUN on dynamic host addresses
### v1.4.0 (2020-06-03)

View File

@ -3,7 +3,7 @@
// This software is licensed under GPL-3 or newer (see LICENSE.md)
use std::{
cmp::{min, max},
cmp::{max, min},
collections::HashMap,
fmt,
fs::{self, File},
@ -109,7 +109,6 @@ impl<TS: TimeSource> PeerList<TS> {
self.nodes.contains_key(node_id)
}
#[inline]
fn add(&mut self, node_id: NodeId, addr: SocketAddr, peer_timeout: u16) {
if self.nodes.insert(node_id, addr).is_none() {
@ -366,7 +365,8 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
/// connect to the peer if it is not already connected.
pub fn add_reconnect_peer(&mut self, mut add: String) {
let now = TS::now();
if add.find(':').unwrap_or(0) <= add.find(']').unwrap_or(0) { // : not present or only in IPv6 address
if add.find(':').unwrap_or(0) <= add.find(']').unwrap_or(0) {
// : not present or only in IPv6 address
add = format!("{}:{}", add, DEFAULT_PORT)
}
let resolved = match resolve(&add as &str) {
@ -476,7 +476,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
let mut msg = Message::Peers(peers);
self.broadcast_msg(&mut msg)?;
// Reschedule for next update
let interval = min(self.update_freq as u16, max(self.peers.min_peer_timeout()/2-60, 1));
let interval = min(self.update_freq as u16, max(self.peers.min_peer_timeout() / 2 - 60, 1));
self.next_peerlist = now + Time::from(interval);
}
// Connect to those reconnect_peers that are due
@ -753,7 +753,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
}
if self.learning {
// Learn single address
self.table.learn(src, None, peer);
self.table.learn(src, None, self.node_id, peer);
}
// Not adding peer in this case to increase performance
}
@ -787,7 +787,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
warn!("Ignoring claimed addresses received from {} in learning mode.", addr_nice(peer));
} else {
for range in ranges {
self.table.learn(range.base, Some(range.prefix_len), peer);
self.table.learn(range.base, Some(range.prefix_len), node_id, peer);
}
}
}

View File

@ -13,7 +13,7 @@ use std::{
use fnv::FnvHasher;
use super::{
types::{Address, Error, Protocol, Table},
types::{Address, Error, NodeId, Protocol, Table},
util::{addr_nice, Duration, Time, TimeSource}
};
@ -125,7 +125,7 @@ impl<TS: TimeSource> Table for SwitchTable<TS> {
/// Learns the given address, inserting it in the hash map
#[inline]
fn learn(&mut self, key: Address, _prefix_len: Option<u8>, addr: SocketAddr) {
fn learn(&mut self, key: Address, _prefix_len: Option<u8>, _: NodeId, addr: SocketAddr) {
let deadline = TS::now() + Time::from(self.timeout);
match self.table.entry(key) {
Entry::Vacant(entry) => {
@ -212,16 +212,17 @@ fn switch() {
MockTimeSource::set_time(1000);
let mut table = SwitchTable::<MockTimeSource>::new(10, 1);
let addr = Address::from_str("12:34:56:78:90:ab").unwrap();
let node_id = [0; 16];
let peer = "1.2.3.4:5678".to_socket_addrs().unwrap().next().unwrap();
let peer2 = "1.2.3.5:7890".to_socket_addrs().unwrap().next().unwrap();
assert!(table.lookup(&addr).is_none());
MockTimeSource::set_time(1000);
table.learn(addr, None, peer);
table.learn(addr, None, node_id, peer);
assert_eq!(table.lookup(&addr), Some(peer));
MockTimeSource::set_time(1000);
table.learn(addr, None, peer2);
table.learn(addr, None, node_id, peer2);
assert_eq!(table.lookup(&addr), Some(peer));
MockTimeSource::set_time(1010);
table.learn(addr, None, peer2);
table.learn(addr, None, node_id, peer2);
assert_eq!(table.lookup(&addr), Some(peer2));
}

View File

@ -12,7 +12,7 @@ use std::{
use fnv::FnvHasher;
use super::{
types::{Address, Error, Protocol, Table},
types::{Address, Error, NodeId, Protocol, Table},
util::addr_nice
};
@ -59,6 +59,7 @@ impl Protocol for Packet {
struct RoutingEntry {
address: SocketAddr,
node_id: NodeId,
bytes: Address,
prefix_len: u8
}
@ -82,7 +83,7 @@ impl RoutingTable {
impl Table for RoutingTable {
/// Learns the given address, inserting it in the hash map
fn learn(&mut self, addr: Address, prefix_len: Option<u8>, address: SocketAddr) {
fn learn(&mut self, addr: Address, prefix_len: Option<u8>, node_id: NodeId, address: SocketAddr) {
// If prefix length is not set, treat the whole address as significant
let prefix_len = match prefix_len {
Some(val) => val,
@ -96,10 +97,14 @@ impl Table for RoutingTable {
let mut group_bytes = [0; 16];
group_bytes[..group_len].copy_from_slice(&addr.data[..group_len]);
// Create an entry
let routing_entry = RoutingEntry { address, bytes: addr, prefix_len };
let routing_entry = RoutingEntry { address, bytes: addr, node_id, prefix_len };
// Add the entry to the routing table, creating a new list if the prefix group is empty.
match self.0.entry(group_bytes) {
hash_map::Entry::Occupied(mut entry) => entry.get_mut().push(routing_entry),
hash_map::Entry::Occupied(mut entry) => {
let list = entry.get_mut();
list.retain(|e| e.node_id != routing_entry.node_id || e.address == routing_entry.address);
list.push(routing_entry)
}
hash_map::Entry::Vacant(entry) => {
entry.insert(vec![routing_entry]);
}
@ -241,33 +246,36 @@ fn decode_invalid_packet() {
fn routing_table_ipv4() {
let mut table = RoutingTable::new();
let peer1 = "1.2.3.4:1".to_socket_addrs().unwrap().next().unwrap();
let node1 = [1; 16];
let peer2 = "1.2.3.4:2".to_socket_addrs().unwrap().next().unwrap();
let node2 = [2; 16];
let peer3 = "1.2.3.4:3".to_socket_addrs().unwrap().next().unwrap();
let node3 = [3; 16];
assert!(table.lookup(&Address::from_str("192.168.1.1").unwrap()).is_none());
table.learn(Address::from_str("192.168.1.1").unwrap(), Some(32), peer1);
table.learn(Address::from_str("192.168.1.1").unwrap(), Some(32), node1, peer1);
assert_eq!(table.lookup(&Address::from_str("192.168.1.1").unwrap()), Some(peer1));
table.learn(Address::from_str("192.168.1.2").unwrap(), None, peer2);
table.learn(Address::from_str("192.168.1.2").unwrap(), None, node2, peer2);
assert_eq!(table.lookup(&Address::from_str("192.168.1.1").unwrap()), Some(peer1));
assert_eq!(table.lookup(&Address::from_str("192.168.1.2").unwrap()), Some(peer2));
table.learn(Address::from_str("192.168.1.0").unwrap(), Some(24), peer3);
table.learn(Address::from_str("192.168.1.0").unwrap(), Some(24), node3, peer3);
assert_eq!(table.lookup(&Address::from_str("192.168.1.1").unwrap()), Some(peer1));
assert_eq!(table.lookup(&Address::from_str("192.168.1.2").unwrap()), Some(peer2));
assert_eq!(table.lookup(&Address::from_str("192.168.1.3").unwrap()), Some(peer3));
table.learn(Address::from_str("192.168.0.0").unwrap(), Some(16), peer1);
table.learn(Address::from_str("192.168.0.0").unwrap(), Some(16), node1, peer1);
assert_eq!(table.lookup(&Address::from_str("192.168.2.1").unwrap()), Some(peer1));
assert_eq!(table.lookup(&Address::from_str("192.168.1.1").unwrap()), Some(peer1));
assert_eq!(table.lookup(&Address::from_str("192.168.1.2").unwrap()), Some(peer2));
assert_eq!(table.lookup(&Address::from_str("192.168.1.3").unwrap()), Some(peer3));
table.learn(Address::from_str("0.0.0.0").unwrap(), Some(0), peer2);
table.learn(Address::from_str("0.0.0.0").unwrap(), Some(0), node2, peer2);
assert_eq!(table.lookup(&Address::from_str("192.168.2.1").unwrap()), Some(peer1));
assert_eq!(table.lookup(&Address::from_str("192.168.1.1").unwrap()), Some(peer1));
assert_eq!(table.lookup(&Address::from_str("192.168.1.2").unwrap()), Some(peer2));
assert_eq!(table.lookup(&Address::from_str("192.168.1.3").unwrap()), Some(peer3));
assert_eq!(table.lookup(&Address::from_str("1.2.3.4").unwrap()), Some(peer2));
table.learn(Address::from_str("192.168.2.0").unwrap(), Some(27), peer3);
table.learn(Address::from_str("192.168.2.0").unwrap(), Some(27), node3, peer3);
assert_eq!(table.lookup(&Address::from_str("192.168.2.31").unwrap()), Some(peer3));
assert_eq!(table.lookup(&Address::from_str("192.168.2.32").unwrap()), Some(peer1));
table.learn(Address::from_str("192.168.2.0").unwrap(), Some(28), peer3);
table.learn(Address::from_str("192.168.2.0").unwrap(), Some(28), node3, peer3);
assert_eq!(table.lookup(&Address::from_str("192.168.2.1").unwrap()), Some(peer3));
}
@ -275,34 +283,37 @@ fn routing_table_ipv4() {
fn routing_table_ipv6() {
let mut table = RoutingTable::new();
let peer1 = "::1:1".to_socket_addrs().unwrap().next().unwrap();
let node1 = [1; 16];
let peer2 = "::1:2".to_socket_addrs().unwrap().next().unwrap();
let node2 = [2; 16];
let peer3 = "::1:3".to_socket_addrs().unwrap().next().unwrap();
let node3 = [3; 16];
assert!(table.lookup(&Address::from_str("::1").unwrap()).is_none());
table.learn(Address::from_str("dead:beef:dead:beef:dead:beef:dead:1").unwrap(), Some(128), peer1);
table.learn(Address::from_str("dead:beef:dead:beef:dead:beef:dead:1").unwrap(), Some(128), node1, peer1);
assert_eq!(table.lookup(&Address::from_str("dead:beef:dead:beef:dead:beef:dead:1").unwrap()), Some(peer1));
table.learn(Address::from_str("dead:beef:dead:beef:dead:beef:dead:2").unwrap(), None, peer2);
table.learn(Address::from_str("dead:beef:dead:beef:dead:beef:dead:2").unwrap(), None, node2, peer2);
assert_eq!(table.lookup(&Address::from_str("dead:beef:dead:beef:dead:beef:dead:1").unwrap()), Some(peer1));
assert_eq!(table.lookup(&Address::from_str("dead:beef:dead:beef:dead:beef:dead:2").unwrap()), Some(peer2));
table.learn(Address::from_str("dead:beef:dead:beef::").unwrap(), Some(64), peer3);
table.learn(Address::from_str("dead:beef:dead:beef::").unwrap(), Some(64), node3, peer3);
assert_eq!(table.lookup(&Address::from_str("dead:beef:dead:beef:dead:beef:dead:1").unwrap()), Some(peer1));
assert_eq!(table.lookup(&Address::from_str("dead:beef:dead:beef:dead:beef:dead:2").unwrap()), Some(peer2));
assert_eq!(table.lookup(&Address::from_str("dead:beef:dead:beef:dead:beef:dead:3").unwrap()), Some(peer3));
table.learn(Address::from_str("dead:beef:dead:be00::").unwrap(), Some(56), peer1);
table.learn(Address::from_str("dead:beef:dead:be00::").unwrap(), Some(56), node1, peer1);
assert_eq!(table.lookup(&Address::from_str("dead:beef:dead:beef:dead:beef:1::").unwrap()), Some(peer3));
assert_eq!(table.lookup(&Address::from_str("dead:beef:dead:be01::").unwrap()), Some(peer1));
assert_eq!(table.lookup(&Address::from_str("dead:beef:dead:beef:dead:beef:dead:1").unwrap()), Some(peer1));
assert_eq!(table.lookup(&Address::from_str("dead:beef:dead:beef:dead:beef:dead:2").unwrap()), Some(peer2));
assert_eq!(table.lookup(&Address::from_str("dead:beef:dead:beef:dead:beef:dead:3").unwrap()), Some(peer3));
table.learn(Address::from_str("::").unwrap(), Some(0), peer2);
table.learn(Address::from_str("::").unwrap(), Some(0), node2, peer2);
assert_eq!(table.lookup(&Address::from_str("dead:beef:dead:beef:dead:beef:1::").unwrap()), Some(peer3));
assert_eq!(table.lookup(&Address::from_str("dead:beef:dead:be01::").unwrap()), Some(peer1));
assert_eq!(table.lookup(&Address::from_str("dead:beef:dead:beef:dead:beef:dead:1").unwrap()), Some(peer1));
assert_eq!(table.lookup(&Address::from_str("dead:beef:dead:beef:dead:beef:dead:2").unwrap()), Some(peer2));
assert_eq!(table.lookup(&Address::from_str("dead:beef:dead:beef:dead:beef:dead:3").unwrap()), Some(peer3));
assert_eq!(table.lookup(&Address::from_str("::1").unwrap()), Some(peer2));
table.learn(Address::from_str("dead:beef:dead:beef:dead:beef:dead:be00").unwrap(), Some(123), peer2);
table.learn(Address::from_str("dead:beef:dead:beef:dead:beef:dead:be00").unwrap(), Some(123), node2, peer2);
assert_eq!(table.lookup(&Address::from_str("dead:beef:dead:beef:dead:beef:dead:be1f").unwrap()), Some(peer2));
assert_eq!(table.lookup(&Address::from_str("dead:beef:dead:beef:dead:beef:dead:be20").unwrap()), Some(peer3));
table.learn(Address::from_str("dead:beef:dead:beef:dead:beef:dead:be00").unwrap(), Some(124), peer3);
table.learn(Address::from_str("dead:beef:dead:beef:dead:beef:dead:be00").unwrap(), Some(124), node3, peer3);
assert_eq!(table.lookup(&Address::from_str("dead:beef:dead:beef:dead:beef:dead:be01").unwrap()), Some(peer3));
}

View File

@ -52,7 +52,7 @@ mod internal {
if let Ok((port, timeout)) = Self::get_any_forwarding(&gateway, internal_addr, port) {
info!("Port-forwarding: external IP is {}", external_ip);
let external_addr = SocketAddrV4::new(external_ip, port);
info!("Port-forwarding: sucessfully activated port forward on {}, timeout: {}", external_addr, timeout);
info!("Port-forwarding: successfully activated port forward on {}, timeout: {}", external_addr, timeout);
let next_extension =
if timeout > 0 { Some(SystemTimeSource::now() + Time::from(timeout) - 60) } else { None };
Some(PortForwarding { internal_addr, external_addr, gateway, next_extension })
@ -101,6 +101,7 @@ mod internal {
}
}
} else {
gateway.remove_port(PortMappingProtocol::UDP, port).ok();
match gateway.add_port(PortMappingProtocol::UDP, port, addr, LEASE_TIME, DESCRIPTION) {
Ok(()) => Ok((port, LEASE_TIME)),
Err(AddPortError::OnlyPermanentLeasesSupported) => {

View File

@ -221,7 +221,7 @@ impl FromStr for Mode {
}
pub trait Table {
fn learn(&mut self, _: Address, _: Option<u8>, _: SocketAddr);
fn learn(&mut self, _: Address, _: Option<u8>, _: NodeId, _: SocketAddr);
fn lookup(&mut self, _: &Address) -> Option<SocketAddr>;
fn housekeep(&mut self);
fn write_out<W: Write>(&self, out: &mut W) -> Result<(), io::Error>;