vpncloud/src/ip.rs

296 lines
14 KiB
Rust
Raw Normal View History

// VpnCloud - Peer-to-Peer VPN
2019-02-19 21:04:21 +00:00
// Copyright (C) 2015-2019 Dennis Schwerdel
// This software is licensed under GPL-3 or newer (see LICENSE.md)
2019-12-04 08:32:35 +00:00
use std::{
collections::{hash_map, HashMap},
hash::BuildHasherDefault,
io::{self, Write},
net::SocketAddr
};
2016-03-29 08:45:54 +00:00
use fnv::FnvHasher;
2015-11-22 18:47:28 +00:00
2019-12-04 08:32:35 +00:00
use super::types::{Address, Error, Protocol, Table};
2015-11-22 18:47:28 +00:00
2016-06-26 17:18:38 +00:00
/// An IP packet dissector
///
/// This dissector is able to extract the source and destination ip addresses of ipv4 packets and
/// ipv6 packets.
2015-11-22 19:02:02 +00:00
#[allow(dead_code)]
2015-11-23 00:40:47 +00:00
pub struct Packet;
2015-11-22 16:28:04 +00:00
2015-11-23 00:40:47 +00:00
impl Protocol for Packet {
2016-06-26 17:18:38 +00:00
/// Parses an ip packet and extracts the source and destination addresses
///
/// # Errors
/// This method will fail when the given data is not a valid ipv4 and ipv6 packet.
2015-11-22 23:49:58 +00:00
fn parse(data: &[u8]) -> Result<(Address, Address), Error> {
2019-01-01 23:35:14 +00:00
if data.is_empty() {
2019-12-04 08:32:35 +00:00
return Err(Error::Parse("Empty header"))
2015-11-22 18:00:56 +00:00
}
let version = data[0] >> 4;
match version {
4 => {
if data.len() < 20 {
2019-12-04 08:32:35 +00:00
return Err(Error::Parse("Truncated IPv4 header"))
}
2019-03-01 22:12:19 +00:00
let src = Address::read_from_fixed(&data[12..], 4)?;
let dst = Address::read_from_fixed(&data[16..], 4)?;
2015-11-26 09:45:25 +00:00
Ok((src, dst))
2019-12-04 08:32:35 +00:00
}
2015-11-22 18:00:56 +00:00
6 => {
if data.len() < 40 {
2019-12-04 08:32:35 +00:00
return Err(Error::Parse("Truncated IPv6 header"))
}
2019-03-01 22:12:19 +00:00
let src = Address::read_from_fixed(&data[8..], 16)?;
let dst = Address::read_from_fixed(&data[24..], 16)?;
2015-11-26 09:45:25 +00:00
Ok((src, dst))
2019-12-04 08:32:35 +00:00
}
2016-07-06 19:14:09 +00:00
_ => Err(Error::Parse("Invalid version"))
2015-11-22 18:00:56 +00:00
}
2015-11-22 16:28:04 +00:00
}
}
2015-11-21 15:50:50 +00:00
struct RoutingEntry {
address: SocketAddr,
2019-01-09 16:45:12 +00:00
bytes: Address,
2015-11-21 15:50:50 +00:00
prefix_len: u8
}
2016-03-29 08:45:54 +00:00
type Hash = BuildHasherDefault<FnvHasher>;
2016-06-26 17:18:38 +00:00
/// A prefix-based routing table
///
/// This table contains a mapping of prefixes associated with peer addresses.
/// To speed up lookup, prefixes are grouped into full bytes and map to a list of prefixes with
/// more fine grained prefixes.
2016-06-27 13:43:30 +00:00
#[derive(Default)]
pub struct RoutingTable(HashMap<[u8; 16], Vec<RoutingEntry>, Hash>);
2015-11-21 15:50:50 +00:00
impl RoutingTable {
2016-06-26 17:18:38 +00:00
/// Creates a new empty routing table
2015-11-21 15:50:50 +00:00
pub fn new() -> Self {
2016-03-29 08:45:54 +00:00
RoutingTable(HashMap::default())
2015-11-21 15:50:50 +00:00
}
2015-11-22 23:49:58 +00:00
}
2015-11-21 15:50:50 +00:00
2015-11-22 23:49:58 +00:00
impl Table for RoutingTable {
2016-06-26 17:18:38 +00:00
/// Learns the given address, inserting it in the hash map
2015-11-22 23:49:58 +00:00
fn learn(&mut self, addr: Address, prefix_len: Option<u8>, address: SocketAddr) {
2016-06-26 17:18:38 +00:00
// If prefix length is not set, treat the whole addess as significant
2015-11-22 23:49:58 +00:00
let prefix_len = match prefix_len {
Some(val) => val,
2015-11-26 09:45:25 +00:00
None => addr.len * 8
2015-11-22 23:49:58 +00:00
};
2015-11-26 21:16:51 +00:00
info!("New routing entry: {}/{} => {}", addr, prefix_len, address);
2016-06-26 17:18:38 +00:00
// Round the prefix length down to the next multiple of 8 and extraxt a prefix of that
// length.
2015-11-26 21:16:51 +00:00
let group_len = prefix_len as usize / 8;
assert!(group_len <= 16);
let mut group_bytes = [0; 16];
group_bytes[..group_len].copy_from_slice(&addr.data[..group_len]);
2016-06-26 17:18:38 +00:00
// Create an entry
2019-12-04 08:32:35 +00:00
let routing_entry = RoutingEntry { address, bytes: addr, prefix_len };
2016-06-26 17:18:38 +00:00
// Add the entry to the routing table, creating a new list of the prefix group is empty.
2015-11-21 15:50:50 +00:00
match self.0.entry(group_bytes) {
hash_map::Entry::Occupied(mut entry) => entry.get_mut().push(routing_entry),
2019-12-04 08:32:35 +00:00
hash_map::Entry::Vacant(entry) => {
entry.insert(vec![routing_entry]);
}
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 routing table
2019-01-01 23:35:14 +00:00
#[allow(unknown_lints, clippy::needless_range_loop)]
2015-11-25 18:23:25 +00:00
fn lookup(&mut self, addr: &Address) -> Option<SocketAddr> {
2015-11-26 21:16:51 +00:00
let len = addr.len as usize;
let mut found = None;
let mut found_len: isize = -1;
2016-06-26 17:18:38 +00:00
// Iterate over the prefix length from longest prefix group to shortest (empty) prefix
// group
let mut group_bytes = addr.data;
for i in len..16 {
group_bytes[i] = 0;
}
2019-01-01 23:35:14 +00:00
for i in (0..=len).rev() {
if i < len {
group_bytes[i] = 0;
}
if let Some(group) = self.0.get(&group_bytes) {
2016-06-26 17:18:38 +00:00
// If the group is not empty, check every entry
2015-11-21 15:50:50 +00:00
for entry in group {
2016-06-26 17:18:38 +00:00
// Calculate the match length of the address and the prefix
2015-11-21 15:50:50 +00:00
let mut match_len = 0;
2015-11-26 09:45:25 +00:00
for j in 0..addr.len as usize {
2019-01-09 16:45:12 +00:00
let b = addr.data[j] ^ entry.bytes.data[j];
2015-11-21 15:50:50 +00:00
if b == 0 {
match_len += 8;
} else {
match_len += b.leading_zeros();
2019-12-04 08:32:35 +00:00
break
2015-11-21 15:50:50 +00:00
}
}
2016-06-26 17:18:38 +00:00
// If the full prefix matches and the match is longer than the longest prefix
// found so far, remember the peer
if match_len as u8 >= entry.prefix_len && entry.prefix_len as isize > found_len {
2015-11-26 21:16:51 +00:00
found = Some(entry.address);
found_len = entry.prefix_len as isize;
2015-11-21 15:50:50 +00:00
}
}
}
}
2016-06-26 17:18:38 +00:00
// Return the longest match found (if any).
2015-11-26 21:16:51 +00:00
found
2015-11-21 15:50:50 +00:00
}
2015-11-22 18:00:56 +00:00
2016-06-26 17:18:38 +00:00
/// This method does not do anything.
2015-11-22 18:00:56 +00:00
fn housekeep(&mut self) {
2019-12-04 08:32:35 +00:00
// nothing to do
2015-11-22 18:00:56 +00:00
}
2015-11-22 21:00:34 +00:00
2019-01-09 16:45:12 +00:00
/// Write out the table
fn write_out<W: Write>(&self, out: &mut W) -> Result<(), io::Error> {
2019-03-01 22:12:19 +00:00
writeln!(out, "Routing table:")?;
2019-01-09 16:45:12 +00:00
for entries in self.0.values() {
for entry in entries {
2019-03-01 22:12:19 +00:00
writeln!(out, " - {}/{} => {}", entry.bytes, entry.prefix_len, entry.address)?;
2019-01-09 16:45:12 +00:00
}
}
Ok(())
}
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, _addr: &Address) -> bool {
// Do nothing, removing single address from prefix-based routing tables does not make sense
false
}
2016-06-26 17:18:38 +00:00
/// Removed all addresses associated with a certain peer
fn remove_all(&mut self, addr: &SocketAddr) {
2017-05-04 05:11:23 +00:00
for entry in &mut self.0.values_mut() {
entry.retain(|entr| &entr.address != addr);
}
2015-11-22 21:00:34 +00:00
}
2015-11-22 18:00:56 +00:00
}
2019-02-19 17:42:50 +00:00
#[cfg(test)] use std::net::ToSocketAddrs;
2019-12-04 08:32:35 +00:00
#[cfg(test)] use std::str::FromStr;
2019-02-19 17:42:50 +00:00
#[test]
fn decode_ipv4_packet() {
2019-12-04 08:32:35 +00:00
let data = [0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 168, 1, 1, 192, 168, 1, 2];
2019-02-19 17:42:50 +00:00
let (src, dst) = Packet::parse(&data).unwrap();
2019-12-04 08:32:35 +00:00
assert_eq!(src, Address { data: [192, 168, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], len: 4 });
assert_eq!(dst, Address { data: [192, 168, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], len: 4 });
2019-02-19 17:42:50 +00:00
}
#[test]
fn decode_ipv6_packet() {
2019-12-04 08:32:35 +00:00
let data = [
0x60, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 6, 5,
4, 3, 2, 1
];
2019-02-19 17:42:50 +00:00
let (src, dst) = Packet::parse(&data).unwrap();
2019-12-04 08:32:35 +00:00
assert_eq!(src, Address { data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6], len: 16 });
assert_eq!(dst, Address { data: [0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1], len: 16 });
2019-02-19 17:42:50 +00:00
}
#[test]
fn decode_invalid_packet() {
2019-12-04 08:32:35 +00:00
assert!(Packet::parse(&[0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 168, 1, 1, 192, 168, 1, 2]).is_ok());
assert!(Packet::parse(&[
0x60, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 6, 5,
4, 3, 2, 1
])
.is_ok());
2019-02-19 17:42:50 +00:00
// no data
assert!(Packet::parse(&[]).is_err());
// wrong version
assert!(Packet::parse(&[0x20]).is_err());
// truncated ipv4
2019-12-04 08:32:35 +00:00
assert!(Packet::parse(&[0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 168, 1, 1, 192, 168, 1]).is_err());
2019-02-19 17:42:50 +00:00
// truncated ipv6
2019-12-04 08:32:35 +00:00
assert!(Packet::parse(&[
0x60, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 6, 5,
4, 3, 2
])
.is_err());
2019-02-19 17:42:50 +00:00
}
#[test]
fn routing_table_ipv4() {
let mut table = RoutingTable::new();
let peer1 = "1.2.3.4:1".to_socket_addrs().unwrap().next().unwrap();
let peer2 = "1.2.3.4:2".to_socket_addrs().unwrap().next().unwrap();
let peer3 = "1.2.3.4:3".to_socket_addrs().unwrap().next().unwrap();
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.clone());
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.clone());
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.clone());
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.clone());
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.clone());
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.clone());
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.clone());
assert_eq!(table.lookup(&Address::from_str("192.168.2.1").unwrap()), Some(peer3));
}
#[test]
fn routing_table_ipv6() {
let mut table = RoutingTable::new();
let peer1 = "::1:1".to_socket_addrs().unwrap().next().unwrap();
let peer2 = "::1:2".to_socket_addrs().unwrap().next().unwrap();
let peer3 = "::1:3".to_socket_addrs().unwrap().next().unwrap();
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.clone());
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.clone());
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.clone());
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.clone());
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.clone());
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.clone());
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.clone());
assert_eq!(table.lookup(&Address::from_str("dead:beef:dead:beef:dead:beef:dead:be01").unwrap()), Some(peer3));
}