mirror of https://github.com/dswd/vpncloud.git
Some documentation and code cleanup
This commit is contained in:
parent
ab7c033383
commit
72b8eccfa9
|
@ -9,7 +9,7 @@ use std::net::{UdpSocket, ToSocketAddrs, Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
|
|
||||||
use super::cloud::GenericCloud;
|
use super::cloud::GenericCloud;
|
||||||
use super::device::Device;
|
use super::device::{Device, Type};
|
||||||
use super::udpmessage::{Options, Message, encode, decode};
|
use super::udpmessage::{Options, Message, encode, decode};
|
||||||
use super::crypto::{Crypto, CryptoMethod};
|
use super::crypto::{Crypto, CryptoMethod};
|
||||||
use super::ethernet::{Frame, SwitchTable};
|
use super::ethernet::{Frame, SwitchTable};
|
||||||
|
@ -155,7 +155,7 @@ fn epoll_wait(b: &mut Bencher) {
|
||||||
#[bench]
|
#[bench]
|
||||||
fn handle_interface_data(b: &mut Bencher) {
|
fn handle_interface_data(b: &mut Bencher) {
|
||||||
let mut node = GenericCloud::<Frame>::new(
|
let mut node = GenericCloud::<Frame>::new(
|
||||||
Device::dummy("vpncloud0", "/dev/null").unwrap(), 0, None,
|
Device::dummy("vpncloud0", "/dev/null", Type::Tap).unwrap(), 0, None,
|
||||||
Box::new(SwitchTable::new(300)), 1800, true, true, vec![], Crypto::None
|
Box::new(SwitchTable::new(300)), 1800, true, true, vec![], Crypto::None
|
||||||
);
|
);
|
||||||
let mut data = [0; 1500];
|
let mut data = [0; 1500];
|
||||||
|
@ -169,7 +169,7 @@ fn handle_interface_data(b: &mut Bencher) {
|
||||||
#[bench]
|
#[bench]
|
||||||
fn handle_net_message(b: &mut Bencher) {
|
fn handle_net_message(b: &mut Bencher) {
|
||||||
let mut node = GenericCloud::<Frame>::new(
|
let mut node = GenericCloud::<Frame>::new(
|
||||||
Device::dummy("vpncloud0", "/dev/null").unwrap(), 0, None,
|
Device::dummy("vpncloud0", "/dev/null", Type::Tap).unwrap(), 0, None,
|
||||||
Box::new(SwitchTable::new(300)), 1800, true, true, vec![], Crypto::None
|
Box::new(SwitchTable::new(300)), 1800, true, true, vec![], Crypto::None
|
||||||
);
|
);
|
||||||
let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 1));
|
let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 1));
|
||||||
|
|
170
src/cloud.rs
170
src/cloud.rs
|
@ -11,6 +11,7 @@ use std::os::unix::io::AsRawFd;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::hash::BuildHasherDefault;
|
use std::hash::BuildHasherDefault;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
use std::cmp::{min, max};
|
||||||
|
|
||||||
use fnv::FnvHasher;
|
use fnv::FnvHasher;
|
||||||
use epoll;
|
use epoll;
|
||||||
|
@ -23,7 +24,7 @@ use super::types::{Table, Protocol, Range, Error, NetworkId, NodeId};
|
||||||
use super::device::Device;
|
use super::device::Device;
|
||||||
use super::udpmessage::{encode, decode, Options, Message};
|
use super::udpmessage::{encode, decode, Options, Message};
|
||||||
use super::crypto::Crypto;
|
use super::crypto::Crypto;
|
||||||
use super::util::{now, Time, Duration};
|
use super::util::{now, Time, Duration, resolve};
|
||||||
|
|
||||||
type Hash = BuildHasherDefault<FnvHasher>;
|
type Hash = BuildHasherDefault<FnvHasher>;
|
||||||
|
|
||||||
|
@ -72,8 +73,7 @@ impl PeerList {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_connected<Addr: ToSocketAddrs+fmt::Display>(&self, addr: Addr) -> Result<bool, Error> {
|
fn is_connected<Addr: ToSocketAddrs+fmt::Display>(&self, addr: Addr) -> Result<bool, Error> {
|
||||||
let addrs = try!(addr.to_socket_addrs().map_err(|_| Error::SocketError("Error looking up name")));
|
for addr in try!(resolve(addr)) {
|
||||||
for addr in addrs {
|
|
||||||
if self.contains_addr(&addr) {
|
if self.contains_addr(&addr) {
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
@ -219,9 +219,16 @@ impl<P: Protocol> GenericCloud<P> {
|
||||||
self.device.ifname()
|
self.device.ifname()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sends the message to all peers
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// Returns an `Error::SocketError` when the underlying system call fails or only part of the
|
||||||
|
/// message could be sent (can this even happen?).
|
||||||
|
/// Some messages could have been sent.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn broadcast_msg(&mut self, msg: &mut Message) -> Result<(), Error> {
|
fn broadcast_msg(&mut self, msg: &mut Message) -> Result<(), Error> {
|
||||||
debug!("Broadcasting {:?}", msg);
|
debug!("Broadcasting {:?}", msg);
|
||||||
|
// Encrypt and encode once and send several times
|
||||||
let msg_data = encode(&self.options, msg, &mut self.buffer_out, &mut self.crypto);
|
let msg_data = encode(&self.options, msg, &mut self.buffer_out, &mut self.crypto);
|
||||||
for addr in self.peers.as_vec() {
|
for addr in self.peers.as_vec() {
|
||||||
let socket = match addr {
|
let socket = match addr {
|
||||||
|
@ -240,9 +247,15 @@ impl<P: Protocol> GenericCloud<P> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sends a message to one peer
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// Returns an `Error::SocketError` when the underlying system call fails or only part of the
|
||||||
|
/// message could be sent (can this even happen?).
|
||||||
#[inline]
|
#[inline]
|
||||||
fn send_msg(&mut self, addr: SocketAddr, msg: &mut Message) -> Result<(), Error> {
|
fn send_msg(&mut self, addr: SocketAddr, msg: &mut Message) -> Result<(), Error> {
|
||||||
debug!("Sending {:?} to {}", msg, addr);
|
debug!("Sending {:?} to {}", msg, addr);
|
||||||
|
// Encrypt and encode
|
||||||
let msg_data = encode(&self.options, msg, &mut self.buffer_out, &mut self.crypto);
|
let msg_data = encode(&self.options, msg, &mut self.buffer_out, &mut self.crypto);
|
||||||
let socket = match addr {
|
let socket = match addr {
|
||||||
SocketAddr::V4(_) => &self.socket4,
|
SocketAddr::V4(_) => &self.socket4,
|
||||||
|
@ -258,16 +271,28 @@ impl<P: Protocol> GenericCloud<P> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the self-perceived addresses (IPv4 and IPv6) of this node
|
||||||
|
///
|
||||||
|
/// Note that those addresses could be private addresses that are not reachable by other nodes,
|
||||||
|
/// or only some other nodes inside the same network.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// Returns an IOError if the underlying system call fails
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn address(&self) -> IoResult<(SocketAddr, SocketAddr)> {
|
pub fn address(&self) -> IoResult<(SocketAddr, SocketAddr)> {
|
||||||
Ok((try!(self.socket4.local_addr()), try!(self.socket6.local_addr())))
|
Ok((try!(self.socket4.local_addr()), try!(self.socket6.local_addr())))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the number of peers
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn peer_count(&self) -> usize {
|
pub fn peer_count(&self) -> usize {
|
||||||
self.peers.len()
|
self.peers.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds a peer to the reconnect list
|
||||||
|
///
|
||||||
|
/// This method adds a peer to the list of nodes to reconnect to. A periodic task will try to
|
||||||
|
/// connect to the peer if it is not already connected.
|
||||||
pub fn add_reconnect_peer(&mut self, add: String) {
|
pub fn add_reconnect_peer(&mut self, add: String) {
|
||||||
self.reconnect_peers.push(ReconnectEntry {
|
self.reconnect_peers.push(ReconnectEntry {
|
||||||
address: add,
|
address: add,
|
||||||
|
@ -277,9 +302,13 @@ impl<P: Protocol> GenericCloud<P> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns whether the address is blacklisted
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// Returns an `Error::SocketError` if the given address is a name that failed to resolve to
|
||||||
|
/// actual addresses.
|
||||||
fn is_blacklisted<Addr: ToSocketAddrs+fmt::Display>(&self, addr: Addr) -> Result<bool, Error> {
|
fn is_blacklisted<Addr: ToSocketAddrs+fmt::Display>(&self, addr: Addr) -> Result<bool, Error> {
|
||||||
let addrs = try!(addr.to_socket_addrs().map_err(|_| Error::SocketError("Error looking up name")));
|
for addr in try!(resolve(addr)) {
|
||||||
for addr in addrs {
|
|
||||||
if self.blacklist_peers.contains(&addr) {
|
if self.blacklist_peers.contains(&addr) {
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
@ -287,6 +316,14 @@ impl<P: Protocol> GenericCloud<P> {
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Connects to a node given by its address
|
||||||
|
///
|
||||||
|
/// This method connects to node by sending a `Message::Init` to it. If `addr` is a name that
|
||||||
|
/// resolves to multiple addresses, one message is sent to each of them.
|
||||||
|
/// If the node is already a connected peer or the address is blacklisted, no message is sent.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// This method returns `Error::NameError` if the address is a name that fails to resolve.
|
||||||
pub fn connect<Addr: ToSocketAddrs+fmt::Display+Clone>(&mut self, addr: Addr) -> Result<(), Error> {
|
pub fn connect<Addr: ToSocketAddrs+fmt::Display+Clone>(&mut self, addr: Addr) -> Result<(), Error> {
|
||||||
if try!(self.peers.is_connected(addr.clone())) || try!(self.is_blacklisted(addr.clone())) {
|
if try!(self.peers.is_connected(addr.clone())) || try!(self.is_blacklisted(addr.clone())) {
|
||||||
return Ok(())
|
return Ok(())
|
||||||
|
@ -294,39 +331,48 @@ impl<P: Protocol> GenericCloud<P> {
|
||||||
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);
|
// Send a message to each resolved address
|
||||||
if let Ok(addrs) = addr.to_socket_addrs() {
|
for a in try!(resolve(addr)) {
|
||||||
let mut addrs = addrs.collect::<Vec<_>>();
|
// Ignore error this time
|
||||||
addrs.dedup();
|
let mut msg = Message::Init(0, node_id, subnets.clone());
|
||||||
for a in addrs {
|
|
||||||
//Ignore error this time
|
|
||||||
self.send_msg(a, &mut msg).ok();
|
self.send_msg(a, &mut msg).ok();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Run all periodic housekeeping tasks
|
||||||
|
///
|
||||||
|
/// This method executes several tasks:
|
||||||
|
/// - Remove peers that have timed out
|
||||||
|
/// - Remove switch table entries that have timed out
|
||||||
|
/// - Periodically send the peers list to all peers
|
||||||
|
/// - Periodically reconnect to peers in the reconnect list
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// This method returns errors if sending a message fails or resolving an address fails.
|
||||||
fn housekeep(&mut self) -> Result<(), Error> {
|
fn housekeep(&mut self) -> Result<(), Error> {
|
||||||
self.peers.timeout();
|
self.peers.timeout();
|
||||||
self.table.housekeep();
|
self.table.housekeep();
|
||||||
|
// Periodically send peer list to peers
|
||||||
let now = now();
|
let now = now();
|
||||||
if self.next_peerlist <= now {
|
if self.next_peerlist <= now {
|
||||||
debug!("Send peer list to all peers");
|
debug!("Send peer list to all peers");
|
||||||
let mut peer_num = self.peers.len();
|
let mut peer_num = self.peers.len();
|
||||||
|
// If the number of peers is high, send only a fraction of the full peer list to
|
||||||
|
// reduce the management traffic. The number of peers to send is the square root of the
|
||||||
|
// total number of peers.
|
||||||
if peer_num > 10 {
|
if peer_num > 10 {
|
||||||
peer_num = (peer_num as f32).sqrt().ceil() as usize;
|
peer_num = max(10, min(255, (peer_num as f32).sqrt().ceil() as usize));
|
||||||
if peer_num < 10 {
|
|
||||||
peer_num = 10;
|
|
||||||
}
|
|
||||||
if peer_num > 255 {
|
|
||||||
peer_num = 255
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// Select that many peers...
|
||||||
let peers = self.peers.subset(peer_num);
|
let peers = self.peers.subset(peer_num);
|
||||||
|
// ...and send them to all peers
|
||||||
let mut msg = Message::Peers(peers);
|
let mut msg = Message::Peers(peers);
|
||||||
try!(self.broadcast_msg(&mut msg));
|
try!(self.broadcast_msg(&mut msg));
|
||||||
|
// Reschedule for next update
|
||||||
self.next_peerlist = now + self.update_freq as Time;
|
self.next_peerlist = now + self.update_freq as Time;
|
||||||
}
|
}
|
||||||
|
// Connect to those reconnect_peers that are due
|
||||||
for entry in self.reconnect_peers.clone() {
|
for entry in self.reconnect_peers.clone() {
|
||||||
if entry.next > now {
|
if entry.next > now {
|
||||||
continue
|
continue
|
||||||
|
@ -334,54 +380,114 @@ impl<P: Protocol> GenericCloud<P> {
|
||||||
try!(self.connect(&entry.address as &str));
|
try!(self.connect(&entry.address as &str));
|
||||||
}
|
}
|
||||||
for entry in &mut self.reconnect_peers {
|
for entry in &mut self.reconnect_peers {
|
||||||
|
// Schedule for next second if node is connected
|
||||||
if try!(self.peers.is_connected(&entry.address as &str)) {
|
if try!(self.peers.is_connected(&entry.address as &str)) {
|
||||||
entry.tries = 0;
|
entry.tries = 0;
|
||||||
entry.timeout = 1;
|
entry.timeout = 1;
|
||||||
entry.next = now + 1;
|
entry.next = now + 1;
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
// Ignore if next attempt is already in the future
|
||||||
if entry.next > now {
|
if entry.next > now {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
// Exponential backoff: every 10 tries, the interval doubles
|
||||||
entry.tries += 1;
|
entry.tries += 1;
|
||||||
if entry.tries > 10 {
|
if entry.tries > 10 {
|
||||||
entry.tries = 0;
|
entry.tries = 0;
|
||||||
entry.timeout *= 2;
|
entry.timeout *= 2;
|
||||||
}
|
}
|
||||||
|
// Maximum interval is one hour
|
||||||
if entry.timeout > 3600 {
|
if entry.timeout > 3600 {
|
||||||
entry.timeout = 3600;
|
entry.timeout = 3600;
|
||||||
}
|
}
|
||||||
|
// Schedule next connection attempt
|
||||||
entry.next = now + entry.timeout as Time;
|
entry.next = now + entry.timeout as Time;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handles payload data coming in from the local network device
|
||||||
|
///
|
||||||
|
/// This method takes payload data received from the local device and parses it to obtain the
|
||||||
|
/// destination address. Then it checks the lookup table to get the peer for that destination
|
||||||
|
/// address. If a peer is found, the message is sent to it, otherwise the message is either
|
||||||
|
/// broadcast to all peers or dropped (depending on mode).
|
||||||
|
///
|
||||||
|
/// The parameter `payload` contains the payload data starting at position `start` and ending
|
||||||
|
/// at `end`. It is important that the buffer has enough space before the payload data to
|
||||||
|
/// prepend a header of max 64 bytes and enough space after the payload data to append a mac of
|
||||||
|
/// max 64 bytes.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// This method fails
|
||||||
|
/// - with `Error::ParseError` if the payload data failed to parse
|
||||||
|
/// - with `Error::SocketError` if sending a message fails
|
||||||
pub fn handle_interface_data(&mut self, payload: &mut [u8], start: usize, end: usize) -> Result<(), Error> {
|
pub fn handle_interface_data(&mut self, payload: &mut [u8], start: usize, end: usize) -> Result<(), Error> {
|
||||||
let (src, dst) = try!(P::parse(&payload[start..end]));
|
let (src, dst) = try!(P::parse(&payload[start..end]));
|
||||||
debug!("Read data from interface: src: {}, dst: {}, {} bytes", src, dst, end-start);
|
debug!("Read data from interface: src: {}, dst: {}, {} bytes", src, dst, end-start);
|
||||||
match self.table.lookup(&dst) {
|
match self.table.lookup(&dst) {
|
||||||
Some(addr) => {
|
Some(addr) => { // Peer found for destination
|
||||||
debug!("Found destination for {} => {}", dst, addr);
|
debug!("Found destination for {} => {}", dst, addr);
|
||||||
try!(self.send_msg(addr, &mut Message::Data(payload, start, end)));
|
try!(self.send_msg(addr, &mut Message::Data(payload, start, end)));
|
||||||
if !self.peers.contains_addr(&addr) {
|
if !self.peers.contains_addr(&addr) {
|
||||||
|
// If the peer is not actually conected, remove the entry in the table and try
|
||||||
|
// to reconnect.
|
||||||
warn!("Destination for {} not found in peers: {}", dst, addr);
|
warn!("Destination for {} not found in peers: {}", dst, addr);
|
||||||
self.table.remove(&dst);
|
self.table.remove(&dst);
|
||||||
try!(self.connect(&addr));
|
try!(self.connect(&addr));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
if !self.broadcast {
|
if self.broadcast {
|
||||||
debug!("No destination for {} found, dropping", dst);
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
debug!("No destination for {} found, broadcasting", dst);
|
debug!("No destination for {} found, broadcasting", dst);
|
||||||
let mut msg = Message::Data(payload, start, end);
|
let mut msg = Message::Data(payload, start, end);
|
||||||
try!(self.broadcast_msg(&mut msg));
|
try!(self.broadcast_msg(&mut msg));
|
||||||
|
} else {
|
||||||
|
debug!("No destination for {} found, dropping", dst);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handles a message received from the network
|
||||||
|
///
|
||||||
|
/// This method handles messages from the network, i.e. from peers. `peer` contains the sender
|
||||||
|
/// of the message. `options` contains the options from the message and `msg` contains the
|
||||||
|
/// message.
|
||||||
|
///
|
||||||
|
/// If the `network_id` in the messages options differs from the `network_id` of this node,
|
||||||
|
/// the message is simply ignored.
|
||||||
|
///
|
||||||
|
/// Then this method will check the message type and will handle each message type differently.
|
||||||
|
///
|
||||||
|
/// # `Message::Data` messages
|
||||||
|
/// This message type contains payload data and therefore this path is optimized for speed.
|
||||||
|
///
|
||||||
|
/// The payload of data messages is written to the local network device and if the node is in
|
||||||
|
/// a learning mode it will associate the sender peer with the source address.
|
||||||
|
///
|
||||||
|
/// # `Message::Peers` messages
|
||||||
|
/// If this message is received, the local node will use all the node addresses in the message
|
||||||
|
/// as well as the senders address to connect to.
|
||||||
|
///
|
||||||
|
/// # `Message::Init` messages
|
||||||
|
/// This message is used in the peer connection handshake.
|
||||||
|
///
|
||||||
|
/// To make sure, the node does not connect to itself, it will compare the remote `node_id` to
|
||||||
|
/// the local one. If the id is the same, it will ignore the message and blacklist the address
|
||||||
|
/// so that it won't be used in the future.
|
||||||
|
///
|
||||||
|
/// If the message is coming from a different node, the nodes address is added to the peer list
|
||||||
|
/// and its claimed addresses are associated with it.
|
||||||
|
///
|
||||||
|
/// If the `stage` of the message is 1, a `Message::Init` message with `stage=1` is sent in
|
||||||
|
/// reply, together with a peer list.
|
||||||
|
///
|
||||||
|
/// # `Message::Close` message
|
||||||
|
/// If this message is received, the sender is removed from the peer list and its claimed
|
||||||
|
/// addresses are removed from the table.
|
||||||
pub fn handle_net_message(&mut self, peer: SocketAddr, options: Options, msg: Message) -> Result<(), Error> {
|
pub fn handle_net_message(&mut self, peer: SocketAddr, options: Options, msg: Message) -> Result<(), Error> {
|
||||||
if self.options.network_id != options.network_id {
|
if self.options.network_id != options.network_id {
|
||||||
info!("Ignoring message from {} with wrong token {:?}", peer, options.network_id);
|
info!("Ignoring message from {} with wrong token {:?}", peer, options.network_id);
|
||||||
|
@ -399,16 +505,18 @@ impl<P: Protocol> GenericCloud<P> {
|
||||||
return Err(Error::TunTapDevError("Failed to write to device"));
|
return Err(Error::TunTapDevError("Failed to write to device"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// not adding peer to increase performance
|
|
||||||
if self.learning {
|
if self.learning {
|
||||||
//learn single address
|
// Learn single address
|
||||||
self.table.learn(src, None, peer);
|
self.table.learn(src, None, peer);
|
||||||
}
|
}
|
||||||
|
// Not adding peer in this case to increase performance
|
||||||
},
|
},
|
||||||
Message::Peers(peers) => {
|
Message::Peers(peers) => {
|
||||||
|
// Connect to sender if not connected
|
||||||
if !self.peers.contains_addr(&peer) {
|
if !self.peers.contains_addr(&peer) {
|
||||||
try!(self.connect(&peer));
|
try!(self.connect(&peer));
|
||||||
}
|
}
|
||||||
|
// Connect to all peers in the message
|
||||||
for p in &peers {
|
for p in &peers {
|
||||||
if ! self.peers.contains_addr(p) && ! self.blacklist_peers.contains(p) {
|
if ! self.peers.contains_addr(p) && ! self.blacklist_peers.contains(p) {
|
||||||
try!(self.connect(p));
|
try!(self.connect(p));
|
||||||
|
@ -416,10 +524,12 @@ impl<P: Protocol> GenericCloud<P> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Message::Init(stage, node_id, ranges) => {
|
Message::Init(stage, node_id, ranges) => {
|
||||||
|
// Avoid connecting to self
|
||||||
if node_id == self.node_id {
|
if node_id == self.node_id {
|
||||||
self.blacklist_peers.push(peer);
|
self.blacklist_peers.push(peer);
|
||||||
return Ok(())
|
return Ok(())
|
||||||
}
|
}
|
||||||
|
// Add sender as peer or as alternative address to existing peer
|
||||||
if self.peers.contains_node(&node_id) {
|
if self.peers.contains_node(&node_id) {
|
||||||
self.peers.add_alt_addr(node_id, peer);
|
self.peers.add_alt_addr(node_id, peer);
|
||||||
} else {
|
} else {
|
||||||
|
@ -428,6 +538,7 @@ impl<P: Protocol> GenericCloud<P> {
|
||||||
self.table.learn(range.base, Some(range.prefix_len), peer);
|
self.table.learn(range.base, Some(range.prefix_len), peer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Reply with stage=1 if stage is 0
|
||||||
if stage == 0 {
|
if stage == 0 {
|
||||||
let peers = self.peers.as_vec();
|
let peers = self.peers.as_vec();
|
||||||
let own_addrs = self.addresses.clone();
|
let own_addrs = self.addresses.clone();
|
||||||
|
@ -444,6 +555,13 @@ impl<P: Protocol> GenericCloud<P> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The main method of the node
|
||||||
|
///
|
||||||
|
/// This method will use epoll to wait in the sockets and the device at the same time.
|
||||||
|
/// It will read from the sockets, decode and decrypt the message and then call the
|
||||||
|
/// `handle_net_message` method. It will also read from the device and call
|
||||||
|
/// `handle_interface_data` for each packet read.
|
||||||
|
/// Also, this method will call `housekeep` every second.
|
||||||
#[allow(unknown_lints)]
|
#[allow(unknown_lints)]
|
||||||
#[allow(cyclomatic_complexity)]
|
#[allow(cyclomatic_complexity)]
|
||||||
pub fn run(&mut self) {
|
pub fn run(&mut self) {
|
||||||
|
|
|
@ -64,6 +64,7 @@ type Hash = BuildHasherDefault<FnvHasher>;
|
||||||
/// This table contains a mapping of prefixes associated with peer addresses.
|
/// 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
|
/// To speed up lookup, prefixes are grouped into full bytes and map to a list of prefixes with
|
||||||
/// more fine grained prefixes.
|
/// more fine grained prefixes.
|
||||||
|
#[derive(Default)]
|
||||||
pub struct RoutingTable(HashMap<Vec<u8>, Vec<RoutingEntry>, Hash>);
|
pub struct RoutingTable(HashMap<Vec<u8>, Vec<RoutingEntry>, Hash>);
|
||||||
|
|
||||||
impl RoutingTable {
|
impl RoutingTable {
|
||||||
|
|
16
src/main.rs
16
src/main.rs
|
@ -18,14 +18,14 @@ extern crate fnv;
|
||||||
extern crate net2;
|
extern crate net2;
|
||||||
#[cfg(feature = "bench")] extern crate test;
|
#[cfg(feature = "bench")] extern crate test;
|
||||||
|
|
||||||
#[macro_use] mod util;
|
#[macro_use] pub mod util;
|
||||||
mod types;
|
pub mod types;
|
||||||
mod crypto;
|
pub mod crypto;
|
||||||
mod udpmessage;
|
pub mod udpmessage;
|
||||||
mod ethernet;
|
pub mod ethernet;
|
||||||
mod ip;
|
pub mod ip;
|
||||||
mod cloud;
|
pub mod cloud;
|
||||||
mod device;
|
pub mod device;
|
||||||
#[cfg(test)] mod tests;
|
#[cfg(test)] mod tests;
|
||||||
#[cfg(feature = "bench")] mod benches;
|
#[cfg(feature = "bench")] mod benches;
|
||||||
|
|
||||||
|
|
|
@ -224,6 +224,7 @@ pub enum Error {
|
||||||
ParseError(&'static str),
|
ParseError(&'static str),
|
||||||
WrongNetwork(Option<NetworkId>),
|
WrongNetwork(Option<NetworkId>),
|
||||||
SocketError(&'static str),
|
SocketError(&'static str),
|
||||||
|
NameError(String),
|
||||||
TunTapDevError(&'static str),
|
TunTapDevError(&'static str),
|
||||||
CryptoError(&'static str)
|
CryptoError(&'static str)
|
||||||
}
|
}
|
||||||
|
@ -234,6 +235,7 @@ impl fmt::Display for Error {
|
||||||
Error::SocketError(ref msg) => write!(formatter, "{}", msg),
|
Error::SocketError(ref msg) => write!(formatter, "{}", msg),
|
||||||
Error::TunTapDevError(ref msg) => write!(formatter, "{}", msg),
|
Error::TunTapDevError(ref msg) => write!(formatter, "{}", msg),
|
||||||
Error::CryptoError(ref msg) => write!(formatter, "{}", msg),
|
Error::CryptoError(ref msg) => write!(formatter, "{}", msg),
|
||||||
|
Error::NameError(ref name) => write!(formatter, "failed to resolve name '{}'", name),
|
||||||
Error::WrongNetwork(Some(net)) => write!(formatter, "wrong network id: {}", net),
|
Error::WrongNetwork(Some(net)) => write!(formatter, "wrong network id: {}", net),
|
||||||
Error::WrongNetwork(None) => write!(formatter, "wrong network id: none"),
|
Error::WrongNetwork(None) => write!(formatter, "wrong network id: none"),
|
||||||
}
|
}
|
||||||
|
|
14
src/util.rs
14
src/util.rs
|
@ -2,6 +2,11 @@
|
||||||
// Copyright (C) 2015-2016 Dennis Schwerdel
|
// Copyright (C) 2015-2016 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::net::{SocketAddr, ToSocketAddrs};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use super::types::Error;
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
use libc;
|
use libc;
|
||||||
|
|
||||||
|
@ -102,3 +107,12 @@ macro_rules! try_fail {
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn resolve<Addr: ToSocketAddrs+fmt::Display>(addr: Addr) -> Result<Vec<SocketAddr>, Error> {
|
||||||
|
let addrs = try!(addr.to_socket_addrs().map_err(|_| Error::NameError(format!("{}", addr))));
|
||||||
|
// Remove duplicates in addrs (why are there duplicates???)
|
||||||
|
let mut addrs = addrs.collect::<Vec<_>>();
|
||||||
|
addrs.dedup();
|
||||||
|
Ok(addrs)
|
||||||
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ vpncloud(1) -- Peer-to-peer VPN
|
||||||
|
|
||||||
Switch table entry timeout in seconds. This parameter is only used in switch
|
Switch table entry timeout in seconds. This parameter is only used in switch
|
||||||
mode. Addresses that have not been seen for the given period of time will
|
mode. Addresses that have not been seen for the given period of time will
|
||||||
be forgot. [default: `300`]
|
be forgotten. [default: `300`]
|
||||||
|
|
||||||
* `--ifup <command>`:
|
* `--ifup <command>`:
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ in 3 different modes:
|
||||||
* **Switch mode**: In this mode, the VPN will dynamically learn addresses
|
* **Switch mode**: In this mode, the VPN will dynamically learn addresses
|
||||||
as they are used as source addresses and use them to forward data to its
|
as they are used as source addresses and use them to forward data to its
|
||||||
destination. Addresses that have not been seen for some time
|
destination. Addresses that have not been seen for some time
|
||||||
(option `dst_timeout`) will be forgot. Data for unknown addresses will be
|
(option `dst_timeout`) will be forgotten. Data for unknown addresses will be
|
||||||
broadcast to all peers. This mode is the default mode for TAP devices that
|
broadcast to all peers. This mode is the default mode for TAP devices that
|
||||||
process Ethernet frames but it can also be used with TUN devices and IP
|
process Ethernet frames but it can also be used with TUN devices and IP
|
||||||
packets.
|
packets.
|
||||||
|
|
Loading…
Reference in New Issue