diff --git a/src/cloud.rs b/src/cloud.rs index 3e62f08..d8ecb38 100644 --- a/src/cloud.rs +++ b/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 { +pub struct GenericCloud { peers: PeerList, addresses: Vec, learning: bool, broadcast: bool, reconnect_peers: Vec, - table: T, + table: Box, socket: UdpSocket, - device: I, + device: Device, network_id: Option, next_peerlist: SteadyTime, update_freq: Duration, buffer_out: [u8; 64*1024], next_housekeep: SteadyTime, - _dummy_m: PhantomData

, + _dummy_p: PhantomData

, } -impl GenericCloud { - pub fn new(device: I, listen: String, network_id: Option, table: T, +impl GenericCloud

{ + pub fn new(device: Device, listen: String, network_id: Option, table: Box

, peer_timeout: Duration, learning: bool, broadcast: bool, addresses: Vec) -> Self { let socket = match UdpSocket::bind(&listen as &str) { Ok(socket) => socket, @@ -123,7 +121,7 @@ impl GenericCloud { 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 GenericCloud { } -pub type TapCloud = GenericCloud; - -impl TapCloud { - pub fn new_tap_cloud(device: &str, listen: String, behavior: Behavior, network_id: Option, 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; - -impl TunCloud { - pub fn new_tun_cloud(device: &str, listen: String, behavior: Behavior, network_id: Option, range_strs: Vec, 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; +pub type TunCloud = GenericCloud; diff --git a/src/device.rs b/src/device.rs index 88030f2..a6d7389 100644 --- a/src/device.rs +++ b/src/device.rs @@ -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; -} - -#[allow(dead_code)] -struct TapSetup; - -impl DeviceSetup for TapSetup { - fn setup_device(fd: RawFd, ifname: &str) -> IoResult { - 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 { - 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 { +pub struct Device { fd: fs::File, - ifname: String, - _dummy_t: PhantomData + ifname: String } -impl Device { - pub fn new(ifname: &str) -> IoResult { +impl Device { + pub fn new(ifname: &str, type_: Type) -> IoResult { 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 Device { } } -impl AsRawFd for Device { +impl AsRawFd for Device { fn as_raw_fd(&self) -> RawFd { self.fd.as_raw_fd() } } -impl VirtualInterface for Device { +impl VirtualInterface for Device { fn read(&mut self, mut buffer: &mut [u8]) -> Result { self.fd.read(&mut buffer).map_err(|_| Error::TunTapDevError("Read error")) } @@ -87,6 +56,3 @@ impl VirtualInterface for Device { } } } - -pub type TapDevice = Device; -pub type TunDevice = Device; diff --git a/src/ethernet.rs b/src/ethernet.rs index 896fd9e..22b5472 100644 --- a/src/ethernet.rs +++ b/src/ethernet.rs @@ -51,24 +51,23 @@ impl Protocol for Frame { } -struct MacTableValue { +struct SwitchTableValue { address: SocketAddr, timeout: SteadyTime } - -pub struct MacTable { - table: HashMap, +pub struct SwitchTable { + table: HashMap, 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
= Vec::new(); @@ -84,7 +83,7 @@ impl Table for MacTable { } fn learn(&mut self, key: Address, _prefix_len: Option, 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); } diff --git a/src/ip.rs b/src/ip.rs index 0fcac50..7d4e59b 100644 --- a/src/ip.rs +++ b/src/ip.rs @@ -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")); diff --git a/src/main.rs b/src/main.rs index 4ca3362..6f2a70e 100644 --- a/src/main.rs +++ b/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 List of peers (addr:port) to connect to --network-id Optional token that identifies the network --peer-timeout Peer timeout in seconds [default: 1800] - --subnet ... The local subnets to use (only for tun) - --mac-timeout Mac table entry timeout in seconds (only for tap) [default: 300] + --subnet ... The local subnets to use + --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, flag_connect: Vec, 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); - match args.flag_type { - Type::Tap => tap_cloud(args), - Type::Tun => tun_cloud(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
) = 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 => { + 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() + } + }; } diff --git a/src/types.rs b/src/types.rs index d3539f8..5a2796b 100644 --- a/src/types.rs +++ b/src/types.rs @@ -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