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] Added crypto option AES128
- [added] Default port for peers - [added] Default port for peers
- [changed] Updated dependencies - [changed] Updated dependencies
- [changed] Removed C code, now 100% Rust
- [fixed] Fixed keepalive for small timeouts - [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) ### v1.4.0 (2020-06-03)

View File

@ -3,7 +3,7 @@
// 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::{
cmp::{min, max}, cmp::{max, min},
collections::HashMap, collections::HashMap,
fmt, fmt,
fs::{self, File}, fs::{self, File},
@ -109,7 +109,6 @@ impl<TS: TimeSource> PeerList<TS> {
self.nodes.contains_key(node_id) self.nodes.contains_key(node_id)
} }
#[inline] #[inline]
fn add(&mut self, node_id: NodeId, addr: SocketAddr, peer_timeout: u16) { fn add(&mut self, node_id: NodeId, addr: SocketAddr, peer_timeout: u16) {
if self.nodes.insert(node_id, addr).is_none() { 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. /// connect to the peer if it is not already connected.
pub fn add_reconnect_peer(&mut self, mut add: String) { pub fn add_reconnect_peer(&mut self, mut add: String) {
let now = TS::now(); 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) add = format!("{}:{}", add, DEFAULT_PORT)
} }
let resolved = match resolve(&add as &str) { 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); let mut msg = Message::Peers(peers);
self.broadcast_msg(&mut msg)?; self.broadcast_msg(&mut msg)?;
// Reschedule for next update // 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); self.next_peerlist = now + Time::from(interval);
} }
// Connect to those reconnect_peers that are due // 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 { if self.learning {
// Learn single address // 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 // 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)); warn!("Ignoring claimed addresses received from {} in learning mode.", addr_nice(peer));
} else { } else {
for range in ranges { 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 fnv::FnvHasher;
use super::{ use super::{
types::{Address, Error, Protocol, Table}, types::{Address, Error, NodeId, Protocol, Table},
util::{addr_nice, Duration, Time, TimeSource} 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 /// Learns the given address, inserting it in the hash map
#[inline] #[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); let deadline = TS::now() + Time::from(self.timeout);
match self.table.entry(key) { match self.table.entry(key) {
Entry::Vacant(entry) => { Entry::Vacant(entry) => {
@ -212,16 +212,17 @@ fn switch() {
MockTimeSource::set_time(1000); MockTimeSource::set_time(1000);
let mut table = SwitchTable::<MockTimeSource>::new(10, 1); let mut table = SwitchTable::<MockTimeSource>::new(10, 1);
let addr = Address::from_str("12:34:56:78:90:ab").unwrap(); 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 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(); let peer2 = "1.2.3.5:7890".to_socket_addrs().unwrap().next().unwrap();
assert!(table.lookup(&addr).is_none()); assert!(table.lookup(&addr).is_none());
MockTimeSource::set_time(1000); MockTimeSource::set_time(1000);
table.learn(addr, None, peer); table.learn(addr, None, node_id, peer);
assert_eq!(table.lookup(&addr), Some(peer)); assert_eq!(table.lookup(&addr), Some(peer));
MockTimeSource::set_time(1000); MockTimeSource::set_time(1000);
table.learn(addr, None, peer2); table.learn(addr, None, node_id, peer2);
assert_eq!(table.lookup(&addr), Some(peer)); assert_eq!(table.lookup(&addr), Some(peer));
MockTimeSource::set_time(1010); MockTimeSource::set_time(1010);
table.learn(addr, None, peer2); table.learn(addr, None, node_id, peer2);
assert_eq!(table.lookup(&addr), Some(peer2)); assert_eq!(table.lookup(&addr), Some(peer2));
} }

View File

@ -12,7 +12,7 @@ use std::{
use fnv::FnvHasher; use fnv::FnvHasher;
use super::{ use super::{
types::{Address, Error, Protocol, Table}, types::{Address, Error, NodeId, Protocol, Table},
util::addr_nice util::addr_nice
}; };
@ -59,6 +59,7 @@ impl Protocol for Packet {
struct RoutingEntry { struct RoutingEntry {
address: SocketAddr, address: SocketAddr,
node_id: NodeId,
bytes: Address, bytes: Address,
prefix_len: u8 prefix_len: u8
} }
@ -82,7 +83,7 @@ impl RoutingTable {
impl Table for RoutingTable { impl Table for RoutingTable {
/// Learns the given address, inserting it in the hash map /// 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 // If prefix length is not set, treat the whole address as significant
let prefix_len = match prefix_len { let prefix_len = match prefix_len {
Some(val) => val, Some(val) => val,
@ -96,10 +97,14 @@ impl Table for RoutingTable {
let mut group_bytes = [0; 16]; let mut group_bytes = [0; 16];
group_bytes[..group_len].copy_from_slice(&addr.data[..group_len]); group_bytes[..group_len].copy_from_slice(&addr.data[..group_len]);
// Create an entry // 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. // Add the entry to the routing table, creating a new list if the prefix group is empty.
match self.0.entry(group_bytes) { 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) => { hash_map::Entry::Vacant(entry) => {
entry.insert(vec![routing_entry]); entry.insert(vec![routing_entry]);
} }
@ -241,33 +246,36 @@ fn decode_invalid_packet() {
fn routing_table_ipv4() { fn routing_table_ipv4() {
let mut table = RoutingTable::new(); let mut table = RoutingTable::new();
let peer1 = "1.2.3.4:1".to_socket_addrs().unwrap().next().unwrap(); 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 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 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()); 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)); 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.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.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.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.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("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.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.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.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("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.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.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.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("192.168.1.3").unwrap()), Some(peer3));
assert_eq!(table.lookup(&Address::from_str("1.2.3.4").unwrap()), Some(peer2)); 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.31").unwrap()), Some(peer3));
assert_eq!(table.lookup(&Address::from_str("192.168.2.32").unwrap()), Some(peer1)); 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)); 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() { fn routing_table_ipv6() {
let mut table = RoutingTable::new(); let mut table = RoutingTable::new();
let peer1 = "::1:1".to_socket_addrs().unwrap().next().unwrap(); 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 peer2 = "::1:2".to_socket_addrs().unwrap().next().unwrap();
let node2 = [2; 16];
let peer3 = "::1:3".to_socket_addrs().unwrap().next().unwrap(); let peer3 = "::1:3".to_socket_addrs().unwrap().next().unwrap();
let node3 = [3; 16];
assert!(table.lookup(&Address::from_str("::1").unwrap()).is_none()); 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)); 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: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: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: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: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("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: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: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: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: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("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: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: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: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: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("dead:beef:dead:beef:dead:beef:dead:3").unwrap()), Some(peer3));
assert_eq!(table.lookup(&Address::from_str("::1").unwrap()), Some(peer2)); 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:be1f").unwrap()), Some(peer2));
assert_eq!(table.lookup(&Address::from_str("dead:beef:dead:beef:dead:beef:dead:be20").unwrap()), Some(peer3)); 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)); 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) { if let Ok((port, timeout)) = Self::get_any_forwarding(&gateway, internal_addr, port) {
info!("Port-forwarding: external IP is {}", external_ip); info!("Port-forwarding: external IP is {}", external_ip);
let external_addr = SocketAddrV4::new(external_ip, port); 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 = let next_extension =
if timeout > 0 { Some(SystemTimeSource::now() + Time::from(timeout) - 60) } else { None }; if timeout > 0 { Some(SystemTimeSource::now() + Time::from(timeout) - 60) } else { None };
Some(PortForwarding { internal_addr, external_addr, gateway, next_extension }) Some(PortForwarding { internal_addr, external_addr, gateway, next_extension })
@ -101,6 +101,7 @@ mod internal {
} }
} }
} else { } else {
gateway.remove_port(PortMappingProtocol::UDP, port).ok();
match gateway.add_port(PortMappingProtocol::UDP, port, addr, LEASE_TIME, DESCRIPTION) { match gateway.add_port(PortMappingProtocol::UDP, port, addr, LEASE_TIME, DESCRIPTION) {
Ok(()) => Ok((port, LEASE_TIME)), Ok(()) => Ok((port, LEASE_TIME)),
Err(AddPortError::OnlyPermanentLeasesSupported) => { Err(AddPortError::OnlyPermanentLeasesSupported) => {

View File

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