mirror of https://github.com/dswd/vpncloud.git
More generic
This commit is contained in:
parent
a559a10155
commit
30fab51be6
68
src/cloud.rs
68
src/cloud.rs
|
@ -6,16 +6,14 @@ use std::io::Read;
|
|||
use std::fmt;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::marker::PhantomData;
|
||||
use std::str::FromStr;
|
||||
|
||||
use time::{Duration, SteadyTime, precise_time_ns};
|
||||
use epoll;
|
||||
|
||||
use super::types::{Table, Protocol, VirtualInterface, Range, Error, NetworkId, Behavior};
|
||||
use super::device::{TunDevice, TapDevice};
|
||||
use super::types::{Table, Protocol, VirtualInterface, Range, Error, NetworkId};
|
||||
use super::device::Device;
|
||||
use super::udpmessage::{encode, decode, Options, Message};
|
||||
use super::ethernet::{Frame, MacTable};
|
||||
use super::ip::{InternetProtocol, RoutingTable};
|
||||
use super::{ethernet, ip};
|
||||
|
||||
struct PeerList {
|
||||
timeout: Duration,
|
||||
|
@ -85,25 +83,25 @@ impl PeerList {
|
|||
}
|
||||
|
||||
|
||||
pub struct GenericCloud<T: Table, P: Protocol, I: VirtualInterface> {
|
||||
pub struct GenericCloud<P: Protocol> {
|
||||
peers: PeerList,
|
||||
addresses: Vec<Range>,
|
||||
learning: bool,
|
||||
broadcast: bool,
|
||||
reconnect_peers: Vec<SocketAddr>,
|
||||
table: T,
|
||||
table: Box<Table>,
|
||||
socket: UdpSocket,
|
||||
device: I,
|
||||
device: Device,
|
||||
network_id: Option<NetworkId>,
|
||||
next_peerlist: SteadyTime,
|
||||
update_freq: Duration,
|
||||
buffer_out: [u8; 64*1024],
|
||||
next_housekeep: SteadyTime,
|
||||
_dummy_m: PhantomData<P>,
|
||||
_dummy_p: PhantomData<P>,
|
||||
}
|
||||
|
||||
impl<T: Table, P: Protocol, I: VirtualInterface> GenericCloud<T, P, I> {
|
||||
pub fn new(device: I, listen: String, network_id: Option<NetworkId>, table: T,
|
||||
impl<P: Protocol> GenericCloud<P> {
|
||||
pub fn new(device: Device, listen: String, network_id: Option<NetworkId>, table: Box<Table>,
|
||||
peer_timeout: Duration, learning: bool, broadcast: bool, addresses: Vec<Range>) -> Self {
|
||||
let socket = match UdpSocket::bind(&listen as &str) {
|
||||
Ok(socket) => socket,
|
||||
|
@ -123,7 +121,7 @@ impl<T: Table, P: Protocol, I: VirtualInterface> GenericCloud<T, P, I> {
|
|||
update_freq: peer_timeout/2,
|
||||
buffer_out: [0; 64*1024],
|
||||
next_housekeep: SteadyTime::now(),
|
||||
_dummy_m: PhantomData,
|
||||
_dummy_p: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -311,47 +309,5 @@ impl<T: Table, P: Protocol, I: VirtualInterface> GenericCloud<T, P, I> {
|
|||
}
|
||||
|
||||
|
||||
pub type TapCloud = GenericCloud<MacTable, Frame, TapDevice>;
|
||||
|
||||
impl TapCloud {
|
||||
pub fn new_tap_cloud(device: &str, listen: String, behavior: Behavior, network_id: Option<NetworkId>, mac_timeout: Duration, peer_timeout: Duration) -> Self {
|
||||
let device = match TapDevice::new(device) {
|
||||
Ok(device) => device,
|
||||
_ => panic!("Failed to open tap device")
|
||||
};
|
||||
info!("Opened tap device {}", device.ifname());
|
||||
let table = MacTable::new(mac_timeout);
|
||||
let (learning, broadcasting) = match behavior {
|
||||
Behavior::Normal => (true, true),
|
||||
Behavior::Switch => (true, true),
|
||||
Behavior::Hub => (false, true),
|
||||
Behavior::Router => (false, false)
|
||||
};
|
||||
Self::new(device, listen, network_id, table, peer_timeout, learning, broadcasting, vec![])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub type TunCloud = GenericCloud<RoutingTable, InternetProtocol, TunDevice>;
|
||||
|
||||
impl TunCloud {
|
||||
pub fn new_tun_cloud(device: &str, listen: String, behavior: Behavior, network_id: Option<NetworkId>, range_strs: Vec<String>, peer_timeout: Duration) -> Self {
|
||||
let device = match TunDevice::new(device) {
|
||||
Ok(device) => device,
|
||||
_ => panic!("Failed to open tun device")
|
||||
};
|
||||
info!("Opened tun device {}", device.ifname());
|
||||
let table = RoutingTable::new();
|
||||
let mut ranges = Vec::with_capacity(range_strs.len());
|
||||
for s in range_strs {
|
||||
ranges.push(Range::from_str(&s).expect("Invalid subnet"));
|
||||
}
|
||||
let (learning, broadcasting) = match behavior {
|
||||
Behavior::Normal => (false, false),
|
||||
Behavior::Switch => (true, true),
|
||||
Behavior::Hub => (false, true),
|
||||
Behavior::Router => (false, false)
|
||||
};
|
||||
Self::new(device, listen, network_id, table, peer_timeout, learning, broadcasting, ranges)
|
||||
}
|
||||
}
|
||||
pub type TapCloud = GenericCloud<ethernet::Frame>;
|
||||
pub type TunCloud = GenericCloud<ip::Packet>;
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
use std::os::unix::io::{AsRawFd, RawFd};
|
||||
use std::io::{Result as IoResult, Error as IoError, Read, Write};
|
||||
use std::marker::PhantomData;
|
||||
use std::fs;
|
||||
|
||||
use super::types::{Error, VirtualInterface};
|
||||
use super::types::{Error, VirtualInterface, Type};
|
||||
|
||||
extern {
|
||||
fn setup_tap_device(fd: i32, ifname: *mut u8) -> i32;
|
||||
|
@ -11,56 +10,26 @@ extern {
|
|||
}
|
||||
|
||||
|
||||
trait DeviceSetup {
|
||||
fn setup_device(RawFd, &str) -> IoResult<String>;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct TapSetup;
|
||||
|
||||
impl DeviceSetup for TapSetup {
|
||||
fn setup_device(fd: RawFd, ifname: &str) -> IoResult<String> {
|
||||
let mut ifname_string = String::with_capacity(32);
|
||||
ifname_string.push_str(ifname);
|
||||
ifname_string.push('\0');
|
||||
let mut ifname_c = ifname_string.into_bytes();
|
||||
let res = unsafe { setup_tap_device(fd, ifname_c.as_mut_ptr()) };
|
||||
match res {
|
||||
0 => Ok(String::from_utf8(ifname_c).unwrap()),
|
||||
_ => Err(IoError::last_os_error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct TunSetup;
|
||||
|
||||
impl DeviceSetup for TunSetup {
|
||||
fn setup_device(fd: RawFd, ifname: &str) -> IoResult<String> {
|
||||
let mut ifname_string = String::with_capacity(32);
|
||||
ifname_string.push_str(ifname);
|
||||
ifname_string.push('\0');
|
||||
let mut ifname_c = ifname_string.into_bytes();
|
||||
let res = unsafe { setup_tun_device(fd, ifname_c.as_mut_ptr()) };
|
||||
match res {
|
||||
0 => Ok(String::from_utf8(ifname_c).unwrap()),
|
||||
_ => Err(IoError::last_os_error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct Device<T> {
|
||||
pub struct Device {
|
||||
fd: fs::File,
|
||||
ifname: String,
|
||||
_dummy_t: PhantomData<T>
|
||||
ifname: String
|
||||
}
|
||||
|
||||
impl<T: DeviceSetup> Device<T> {
|
||||
pub fn new(ifname: &str) -> IoResult<Self> {
|
||||
impl Device {
|
||||
pub fn new(ifname: &str, type_: Type) -> IoResult<Self> {
|
||||
let fd = try!(fs::OpenOptions::new().read(true).write(true).open("/dev/net/tun"));
|
||||
let ifname = try!(T::setup_device(fd.as_raw_fd(), ifname));
|
||||
Ok(Device{fd: fd, ifname: ifname, _dummy_t: PhantomData})
|
||||
let mut ifname_string = String::with_capacity(32);
|
||||
ifname_string.push_str(ifname);
|
||||
ifname_string.push('\0');
|
||||
let mut ifname_c = ifname_string.into_bytes();
|
||||
let res = match type_ {
|
||||
Type::Tun => unsafe { setup_tun_device(fd.as_raw_fd(), ifname_c.as_mut_ptr()) },
|
||||
Type::Tap => unsafe { setup_tap_device(fd.as_raw_fd(), ifname_c.as_mut_ptr()) }
|
||||
};
|
||||
match res {
|
||||
0 => Ok(Device{fd: fd, ifname: String::from_utf8(ifname_c).unwrap()}),
|
||||
_ => Err(IoError::last_os_error())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -69,13 +38,13 @@ impl<T: DeviceSetup> Device<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> AsRawFd for Device<T> {
|
||||
impl AsRawFd for Device {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.fd.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> VirtualInterface for Device<T> {
|
||||
impl VirtualInterface for Device {
|
||||
fn read(&mut self, mut buffer: &mut [u8]) -> Result<usize, Error> {
|
||||
self.fd.read(&mut buffer).map_err(|_| Error::TunTapDevError("Read error"))
|
||||
}
|
||||
|
@ -87,6 +56,3 @@ impl<T> VirtualInterface for Device<T> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type TapDevice = Device<TapSetup>;
|
||||
pub type TunDevice = Device<TunSetup>;
|
||||
|
|
|
@ -51,24 +51,23 @@ impl Protocol for Frame {
|
|||
}
|
||||
|
||||
|
||||
struct MacTableValue {
|
||||
struct SwitchTableValue {
|
||||
address: SocketAddr,
|
||||
timeout: SteadyTime
|
||||
}
|
||||
|
||||
|
||||
pub struct MacTable {
|
||||
table: HashMap<Address, MacTableValue>,
|
||||
pub struct SwitchTable {
|
||||
table: HashMap<Address, SwitchTableValue>,
|
||||
timeout: Duration
|
||||
}
|
||||
|
||||
impl MacTable {
|
||||
pub fn new(timeout: Duration) -> MacTable {
|
||||
MacTable{table: HashMap::new(), timeout: timeout}
|
||||
impl SwitchTable {
|
||||
pub fn new(timeout: Duration) -> Self {
|
||||
SwitchTable{table: HashMap::new(), timeout: timeout}
|
||||
}
|
||||
}
|
||||
|
||||
impl Table for MacTable {
|
||||
impl Table for SwitchTable {
|
||||
fn housekeep(&mut self) {
|
||||
let now = SteadyTime::now();
|
||||
let mut del: Vec<Address> = Vec::new();
|
||||
|
@ -84,7 +83,7 @@ impl Table for MacTable {
|
|||
}
|
||||
|
||||
fn learn(&mut self, key: Address, _prefix_len: Option<u8>, addr: SocketAddr) {
|
||||
let value = MacTableValue{address: addr, timeout: SteadyTime::now()+self.timeout};
|
||||
let value = SwitchTableValue{address: addr, timeout: SteadyTime::now()+self.timeout};
|
||||
if self.table.insert(key.clone(), value).is_none() {
|
||||
info!("Learned address {:?} => {}", key, addr);
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@ use super::types::{Protocol, Error, Table, Address};
|
|||
use super::util::to_vec;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct InternetProtocol;
|
||||
pub struct Packet;
|
||||
|
||||
impl Protocol for InternetProtocol {
|
||||
impl Protocol for Packet {
|
||||
fn parse(data: &[u8]) -> Result<(Address, Address), Error> {
|
||||
if data.len() < 1 {
|
||||
return Err(Error::ParseError("Empty header"));
|
||||
|
|
96
src/main.rs
96
src/main.rs
|
@ -16,13 +16,16 @@ use time::Duration;
|
|||
use docopt::Docopt;
|
||||
|
||||
use std::hash::{Hash, SipHasher, Hasher};
|
||||
use std::str::FromStr;
|
||||
|
||||
use types::{Error, Behavior};
|
||||
use device::Device;
|
||||
use ethernet::SwitchTable;
|
||||
use ip::RoutingTable;
|
||||
use types::{Error, Behavior, Type, Range, Table};
|
||||
use cloud::{TapCloud, TunCloud};
|
||||
|
||||
|
||||
//TODO: hub behavior
|
||||
//TODO: L2 routing/L3 switching
|
||||
//TODO: L2 routing
|
||||
//TODO: Implement IPv6
|
||||
//TODO: Encryption
|
||||
//TODO: Call close
|
||||
|
@ -54,18 +57,13 @@ Options:
|
|||
-c <connect>, --connect <connect> List of peers (addr:port) to connect to
|
||||
--network-id <network_id> Optional token that identifies the network
|
||||
--peer-timeout <peer_timeout> Peer timeout in seconds [default: 1800]
|
||||
--subnet <subnet>... The local subnets to use (only for tun)
|
||||
--mac-timeout <mac_timeout> Mac table entry timeout in seconds (only for tap) [default: 300]
|
||||
--subnet <subnet>... The local subnets to use
|
||||
--dst-timeout <dst_timeout> Switch table entry timeout in seconds [default: 300]
|
||||
-v, --verbose Log verbosely
|
||||
-q, --quiet Only print error messages
|
||||
-h, --help Display the help
|
||||
";
|
||||
|
||||
#[derive(RustcDecodable, Debug)]
|
||||
enum Type {
|
||||
Tun, Tap
|
||||
}
|
||||
|
||||
#[derive(RustcDecodable, Debug)]
|
||||
struct Args {
|
||||
flag_type: Type,
|
||||
|
@ -76,49 +74,11 @@ struct Args {
|
|||
flag_network_id: Option<String>,
|
||||
flag_connect: Vec<String>,
|
||||
flag_peer_timeout: usize,
|
||||
flag_mac_timeout: usize,
|
||||
flag_dst_timeout: usize,
|
||||
flag_verbose: bool,
|
||||
flag_quiet: bool
|
||||
}
|
||||
|
||||
fn tap_cloud(args: Args) {
|
||||
let mut tapcloud = TapCloud::new_tap_cloud(
|
||||
&args.flag_device,
|
||||
args.flag_listen,
|
||||
args.flag_behavior,
|
||||
args.flag_network_id.map(|name| {
|
||||
let mut s = SipHasher::new();
|
||||
name.hash(&mut s);
|
||||
s.finish()
|
||||
}),
|
||||
Duration::seconds(args.flag_mac_timeout as i64),
|
||||
Duration::seconds(args.flag_peer_timeout as i64)
|
||||
);
|
||||
for addr in args.flag_connect {
|
||||
tapcloud.connect(&addr as &str, true).expect("Failed to send");
|
||||
}
|
||||
tapcloud.run()
|
||||
}
|
||||
|
||||
fn tun_cloud(args: Args) {
|
||||
let mut tuncloud = TunCloud::new_tun_cloud(
|
||||
&args.flag_device,
|
||||
args.flag_listen,
|
||||
args.flag_behavior,
|
||||
args.flag_network_id.map(|name| {
|
||||
let mut s = SipHasher::new();
|
||||
name.hash(&mut s);
|
||||
s.finish()
|
||||
}),
|
||||
args.flag_subnet,
|
||||
Duration::seconds(args.flag_peer_timeout as i64)
|
||||
);
|
||||
for addr in args.flag_connect {
|
||||
tuncloud.connect(&addr as &str, true).expect("Failed to send");
|
||||
}
|
||||
tuncloud.run()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Args = Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit());
|
||||
log::set_logger(|max_log_level| {
|
||||
|
@ -133,8 +93,42 @@ fn main() {
|
|||
Box::new(SimpleLogger)
|
||||
}).unwrap();
|
||||
debug!("Args: {:?}", args);
|
||||
let device = Device::new(&args.flag_device, args.flag_type).expect("Failed to open virtual interface");
|
||||
info!("Opened device {}", device.ifname());
|
||||
let mut ranges = Vec::with_capacity(args.flag_subnet.len());
|
||||
for s in args.flag_subnet {
|
||||
ranges.push(Range::from_str(&s).expect("Invalid subnet"));
|
||||
}
|
||||
let dst_timeout = Duration::seconds(args.flag_dst_timeout as i64);
|
||||
let peer_timeout = Duration::seconds(args.flag_peer_timeout as i64);
|
||||
let (learning, broadcasting, table): (bool, bool, Box<Table>) = match args.flag_behavior {
|
||||
Behavior::Normal => match args.flag_type {
|
||||
Type::Tap => (true, true, Box::new(SwitchTable::new(dst_timeout))),
|
||||
Type::Tun => (false, false, Box::new(RoutingTable::new()))
|
||||
},
|
||||
Behavior::Router => (false, false, Box::new(RoutingTable::new())),
|
||||
Behavior::Switch => (true, true, Box::new(SwitchTable::new(dst_timeout))),
|
||||
Behavior::Hub => (false, true, Box::new(SwitchTable::new(dst_timeout)))
|
||||
};
|
||||
let network_id = args.flag_network_id.map(|name| {
|
||||
let mut s = SipHasher::new();
|
||||
name.hash(&mut s);
|
||||
s.finish()
|
||||
});
|
||||
match args.flag_type {
|
||||
Type::Tap => tap_cloud(args),
|
||||
Type::Tun => tun_cloud(args)
|
||||
Type::Tap => {
|
||||
let mut cloud = TapCloud::new(device, args.flag_listen, network_id, table, peer_timeout, learning, broadcasting, ranges);
|
||||
for addr in args.flag_connect {
|
||||
cloud.connect(&addr as &str, true).expect("Failed to send");
|
||||
}
|
||||
cloud.run()
|
||||
},
|
||||
Type::Tun => {
|
||||
let mut cloud = TunCloud::new(device, args.flag_listen, network_id, table, peer_timeout, learning, broadcasting, ranges);
|
||||
for addr in args.flag_connect {
|
||||
cloud.connect(&addr as &str, true).expect("Failed to send");
|
||||
}
|
||||
cloud.run()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -80,6 +80,11 @@ impl FromStr for Range {
|
|||
}
|
||||
|
||||
|
||||
#[derive(RustcDecodable, Debug, Clone, Copy)]
|
||||
pub enum Type {
|
||||
Tun, Tap
|
||||
}
|
||||
|
||||
#[derive(RustcDecodable, Debug)]
|
||||
pub enum Behavior {
|
||||
Normal, Hub, Switch, Router
|
||||
|
|
Loading…
Reference in New Issue