vpncloud/src/ethernet.rs

151 lines
4.9 KiB
Rust
Raw Normal View History

// VpnCloud - Peer-to-Peer VPN
// Copyright (C) 2015-2016 Dennis Schwerdel
// This software is licensed under GPL-3 or newer (see LICENSE.md)
2015-11-21 15:50:50 +00:00
use std::net::SocketAddr;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
2016-03-29 08:45:54 +00:00
use std::hash::BuildHasherDefault;
use fnv::FnvHasher;
2015-11-19 15:34:20 +00:00
2015-11-23 00:04:30 +00:00
use super::types::{Error, Table, Protocol, Address};
2015-11-25 20:55:30 +00:00
use super::util::{now, Time, Duration};
2015-11-22 16:28:04 +00:00
2016-06-26 17:18:38 +00:00
/// An ethernet frame dissector
///
/// This dissector is able to extract the source and destination addresses of ethernet frames.
///
/// If the ethernet frame contains a VLAN tag, both addresses will be prefixed with that tag,
/// resulting in 8-byte addresses. Additional nested tags will be ignored.
2015-11-22 17:05:15 +00:00
pub struct Frame;
2015-11-21 17:09:13 +00:00
2015-11-22 17:05:15 +00:00
impl Protocol for Frame {
2016-06-26 17:18:38 +00:00
/// Parses an ethernet frame and extracts the source and destination addresses
///
/// # Errors
/// This method will fail when the given data is not a valid ethernet frame.
2015-11-22 23:49:58 +00:00
fn parse(data: &[u8]) -> Result<(Address, Address), Error> {
2015-11-22 15:48:01 +00:00
if data.len() < 14 {
2016-07-06 19:14:09 +00:00
return Err(Error::Parse("Frame is too short"));
2015-11-22 15:48:01 +00:00
}
let mut pos = 0;
2015-11-22 23:49:58 +00:00
let dst_data = &data[pos..pos+6];
pos += 6;
let src_data = &data[pos..pos+6];
pos += 6;
2015-11-22 15:48:01 +00:00
if data[pos] == 0x81 && data[pos+1] == 0x00 {
pos += 2;
if data.len() < pos + 2 {
2016-07-06 19:14:09 +00:00
return Err(Error::Parse("Vlan frame is too short"));
2015-11-22 15:48:01 +00:00
}
let mut src = [0; 16];
let mut dst = [0; 16];
2015-11-26 09:45:25 +00:00
src[0] = data[pos]; src[1] = data[pos+1];
dst[0] = data[pos]; dst[1] = data[pos+1];
2016-07-06 16:48:58 +00:00
src[2..8].copy_from_slice(src_data);
dst[2..8].copy_from_slice(dst_data);
2015-11-26 09:45:25 +00:00
Ok((Address{data: src, len: 8}, Address{data: dst, len: 8}))
2015-11-22 23:49:58 +00:00
} else {
2017-05-04 05:26:21 +00:00
let src = try!(Address::read_from_fixed(src_data, 6));
let dst = try!(Address::read_from_fixed(dst_data, 6));
2015-11-26 09:45:25 +00:00
Ok((src, dst))
2015-11-22 15:48:01 +00:00
}
}
}
2015-11-22 16:28:04 +00:00
2015-11-23 00:40:47 +00:00
struct SwitchTableValue {
2015-11-21 15:50:50 +00:00
address: SocketAddr,
2015-11-25 20:55:30 +00:00
timeout: Time
2015-11-21 15:50:50 +00:00
}
2016-03-29 08:45:54 +00:00
type Hash = BuildHasherDefault<FnvHasher>;
2016-06-26 17:18:38 +00:00
/// A table used to implement a learning switch
///
/// This table is a simple hash map between an address and the destination peer. It learns
/// addresses as they are seen and forgets them after some time.
2015-11-23 00:40:47 +00:00
pub struct SwitchTable {
2016-06-26 17:18:38 +00:00
/// The table storing the actual mapping
2016-03-29 08:45:54 +00:00
table: HashMap<Address, SwitchTableValue, Hash>,
2016-06-26 17:18:38 +00:00
/// Timeout period for forgetting learnt addresses
2016-11-28 11:14:56 +00:00
timeout: Duration,
// Timeout period for not overwriting learnt addresses
protection_period: Duration,
2015-11-21 15:50:50 +00:00
}
2015-11-23 00:40:47 +00:00
impl SwitchTable {
2016-06-26 17:18:38 +00:00
/// Creates a new switch table
2016-11-28 11:14:56 +00:00
pub fn new(timeout: Duration, protection_period: Duration) -> Self {
SwitchTable{table: HashMap::default(), timeout: timeout, protection_period: protection_period}
2015-11-21 15:50:50 +00:00
}
2015-11-21 17:09:13 +00:00
}
2015-11-23 00:40:47 +00:00
impl Table for SwitchTable {
2016-06-26 17:18:38 +00:00
/// Forget addresses that have not been seen for the configured timeout
2015-11-21 17:09:13 +00:00
fn housekeep(&mut self) {
2015-11-25 20:55:30 +00:00
let now = now();
2015-11-22 23:49:58 +00:00
let mut del: Vec<Address> = Vec::new();
for (key, val) in &self.table {
2015-11-21 15:50:50 +00:00
if val.timeout < now {
2016-06-11 14:08:57 +00:00
del.push(*key);
2015-11-21 15:50:50 +00:00
}
}
for key in del {
2015-11-26 21:16:51 +00:00
info!("Forgot address {}", key);
2015-11-21 15:50:50 +00:00
self.table.remove(&key);
}
}
2016-06-26 17:18:38 +00:00
/// Learns the given address, inserting it in the hash map
#[inline]
2015-11-22 23:49:58 +00:00
fn learn(&mut self, key: Address, _prefix_len: Option<u8>, addr: SocketAddr) {
let deadline = now() + self.timeout as Time;
match self.table.entry(key) {
Entry::Vacant(entry) => {
entry.insert(SwitchTableValue{address: addr, timeout: deadline});
info!("Learned address {} => {}", key, addr);
},
Entry::Occupied(mut entry) => {
let mut entry = entry.get_mut();
2016-11-28 11:14:56 +00:00
if entry.timeout + self.protection_period as Time > deadline {
// Do not override recently learnt entries
return
}
entry.timeout = deadline;
entry.address = addr;
}
2015-11-25 18:23:25 +00:00
}
2015-11-21 15:50:50 +00:00
}
2016-06-26 17:18:38 +00:00
/// Retrieves a peer for an address if it is inside the hash map
#[inline]
2015-11-25 18:23:25 +00:00
fn lookup(&mut self, key: &Address) -> Option<SocketAddr> {
match self.table.get(key) {
Some(value) => Some(value.address),
None => None
}
2015-11-21 15:50:50 +00:00
}
2015-11-22 21:00:34 +00:00
2016-06-26 17:18:38 +00:00
/// Removes an address from the map and returns whether something has been removed
#[inline]
fn remove(&mut self, key: &Address) -> bool {
self.table.remove(key).is_some()
}
2016-06-26 17:18:38 +00:00
/// Removed all addresses associated with a certain peer
fn remove_all(&mut self, addr: &SocketAddr) {
let mut remove = Vec::new();
2016-06-11 14:08:57 +00:00
for (key, val) in &self.table {
if &val.address == addr {
2016-06-11 14:08:57 +00:00
remove.push(*key);
}
}
for key in remove {
self.table.remove(&key);
}
2015-11-22 21:00:34 +00:00
}
2015-11-21 15:50:50 +00:00
}