mirror of https://github.com/dswd/vpncloud.git
Pretty error messages instead of panics
This commit is contained in:
parent
83fb941599
commit
12b5b17c3b
|
@ -27,12 +27,11 @@ This is what currently works:
|
|||
|
||||
However there are some open issues:
|
||||
|
||||
* Encryption is not very mature. Do not use it for any relevant data.
|
||||
* The protocol, especially the encryption part, can change.
|
||||
* Encryption has not been thoroughly reviewed, use with care.
|
||||
* The protocol can still change.
|
||||
* Running on IPv6 is not supported.
|
||||
* The software is not very well tested.
|
||||
* The closing message is not sent to peers.
|
||||
* Usage of rust panics instead of pretty error messages.
|
||||
* The coverage score includes all unused methods from *libsodium*
|
||||
|
||||
Please feel free to help and contribute code.
|
||||
|
|
29
src/cloud.rs
29
src/cloud.rs
|
@ -13,7 +13,6 @@ use epoll;
|
|||
use super::types::{Table, Protocol, Range, Error, NetworkId};
|
||||
use super::device::Device;
|
||||
use super::udpmessage::{encode, decode, Options, Message};
|
||||
use super::{ethernet, ip};
|
||||
use super::crypto::Crypto;
|
||||
|
||||
struct PeerList {
|
||||
|
@ -108,7 +107,7 @@ impl<P: Protocol> GenericCloud<P> {
|
|||
crypto: Crypto) -> Self {
|
||||
let socket = match UdpSocket::bind(&listen as &str) {
|
||||
Ok(socket) => socket,
|
||||
_ => panic!("Failed to open socket")
|
||||
_ => fail!("Failed to open socket {}", listen)
|
||||
};
|
||||
let mut options = Options::default();
|
||||
options.network_id = network_id;
|
||||
|
@ -271,35 +270,33 @@ impl<P: Protocol> GenericCloud<P> {
|
|||
}
|
||||
|
||||
pub fn run(&mut self) {
|
||||
let epoll_handle = epoll::create1(0).expect("Failed to create epoll handle");
|
||||
let epoll_handle = try_fail!(epoll::create1(0), "Failed to create epoll handle: {}");
|
||||
let socket_fd = self.socket.as_raw_fd();
|
||||
let device_fd = self.device.as_raw_fd();
|
||||
let mut socket_event = epoll::EpollEvent{events: epoll::util::event_type::EPOLLIN, data: 0};
|
||||
let mut device_event = epoll::EpollEvent{events: epoll::util::event_type::EPOLLIN, data: 1};
|
||||
epoll::ctl(epoll_handle, epoll::util::ctl_op::ADD, socket_fd, &mut socket_event).expect("Failed to add socket to epoll handle");
|
||||
epoll::ctl(epoll_handle, epoll::util::ctl_op::ADD, device_fd, &mut device_event).expect("Failed to add device to epoll handle");
|
||||
try_fail!(epoll::ctl(epoll_handle, epoll::util::ctl_op::ADD, socket_fd, &mut socket_event), "Failed to add socket to epoll handle: {}");
|
||||
try_fail!(epoll::ctl(epoll_handle, epoll::util::ctl_op::ADD, device_fd, &mut device_event), "Failed to add device to epoll handle: {}");
|
||||
let mut events = [epoll::EpollEvent{events: 0, data: 0}; 2];
|
||||
let mut buffer = [0; 64*1024];
|
||||
loop {
|
||||
let count = epoll::wait(epoll_handle, &mut events, 1000).expect("Epoll wait failed");
|
||||
let count = try_fail!(epoll::wait(epoll_handle, &mut events, 1000), "Epoll wait failed: {}");
|
||||
// Process events
|
||||
for i in 0..count {
|
||||
match &events[i as usize].data {
|
||||
&0 => match self.socket.recv_from(&mut buffer) {
|
||||
Ok((size, src)) => {
|
||||
&0 => {
|
||||
let (size, src) = try_fail!(self.socket.recv_from(&mut buffer), "Failed to read from network socket: {}");
|
||||
match decode(&mut buffer[..size], &mut self.crypto).and_then(|(options, msg)| self.handle_net_message(src, options, msg)) {
|
||||
Ok(_) => (),
|
||||
Err(e) => error!("Error: {:?}", e)
|
||||
}
|
||||
},
|
||||
Err(_error) => panic!("Failed to read from network socket")
|
||||
},
|
||||
&1 => match self.device.read(&mut buffer) {
|
||||
Ok(size) => match self.handle_interface_data(&buffer[..size]) {
|
||||
&1 => {
|
||||
let size = try_fail!(self.device.read(&mut buffer), "Failed to read from tap device: {}");
|
||||
match self.handle_interface_data(&buffer[..size]) {
|
||||
Ok(_) => (),
|
||||
Err(e) => error!("Error: {:?}", e)
|
||||
},
|
||||
Err(_error) => panic!("Failed to read from tap device")
|
||||
}
|
||||
},
|
||||
_ => unreachable!()
|
||||
}
|
||||
|
@ -315,7 +312,3 @@ impl<P: Protocol> GenericCloud<P> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub type TapCloud = GenericCloud<ethernet::Frame>;
|
||||
pub type TunCloud = GenericCloud<ip::Packet>;
|
||||
|
|
|
@ -91,7 +91,7 @@ impl Table for RoutingTable {
|
|||
}
|
||||
|
||||
fn housekeep(&mut self) {
|
||||
//nothin to do
|
||||
//nothing to do
|
||||
}
|
||||
|
||||
fn remove_all(&mut self, _addr: SocketAddr) {
|
||||
|
|
73
src/main.rs
73
src/main.rs
|
@ -5,7 +5,7 @@ extern crate rustc_serialize;
|
|||
extern crate epoll;
|
||||
#[cfg(feature = "crypto")] extern crate libsodium_sys;
|
||||
|
||||
mod util;
|
||||
#[macro_use] mod util;
|
||||
mod types;
|
||||
mod crypto;
|
||||
mod udpmessage;
|
||||
|
@ -24,8 +24,8 @@ use std::process::Command;
|
|||
use device::Device;
|
||||
use ethernet::SwitchTable;
|
||||
use ip::RoutingTable;
|
||||
use types::{Error, Mode, Type, Range, Table};
|
||||
use cloud::{TapCloud, TunCloud};
|
||||
use types::{Error, Mode, Type, Range, Table, Protocol};
|
||||
use cloud::GenericCloud;
|
||||
use udpmessage::VERSION;
|
||||
use crypto::Crypto;
|
||||
|
||||
|
@ -80,32 +80,13 @@ fn run_script(script: String, ifname: &str) {
|
|||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Args = Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit());
|
||||
if args.flag_version {
|
||||
println!("VpnCloud v{} ({}, protocol version {})", env!("CARGO_PKG_VERSION"),
|
||||
if cfg!(feature = "crypto") { "with crypto support" } else { "without crypto support" },
|
||||
VERSION
|
||||
);
|
||||
return;
|
||||
}
|
||||
log::set_logger(|max_log_level| {
|
||||
assert!(!args.flag_verbose || !args.flag_quiet);
|
||||
if args.flag_verbose {
|
||||
max_log_level.set(log::LogLevelFilter::Debug);
|
||||
} else if args.flag_quiet {
|
||||
max_log_level.set(log::LogLevelFilter::Error);
|
||||
} else {
|
||||
max_log_level.set(log::LogLevelFilter::Info);
|
||||
}
|
||||
Box::new(SimpleLogger)
|
||||
}).unwrap();
|
||||
debug!("Args: {:?}", args);
|
||||
let device = Device::new(&args.flag_device, args.flag_type).expect("Failed to open virtual interface");
|
||||
fn run<T: Protocol> (args: Args) {
|
||||
let device = try_fail!(Device::new(&args.flag_device, args.flag_type),
|
||||
"Failed to open virtual {} interface {}: {}", args.flag_type, &args.flag_device);
|
||||
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"));
|
||||
ranges.push(try_fail!(Range::from_str(&s), "Invalid subnet format: {} ({})", s));
|
||||
}
|
||||
let dst_timeout = Duration::seconds(args.flag_dst_timeout as i64);
|
||||
let peer_timeout = Duration::seconds(args.flag_peer_timeout as i64);
|
||||
|
@ -127,32 +108,42 @@ fn main() {
|
|||
Some(key) => Crypto::from_shared_key(&key),
|
||||
None => Crypto::None
|
||||
};
|
||||
match args.flag_type {
|
||||
Type::Tap => {
|
||||
let mut cloud = TapCloud::new(device, args.flag_listen, network_id, table, peer_timeout, learning, broadcasting, ranges, crypto);
|
||||
let mut cloud = GenericCloud::<T>::new(device, args.flag_listen, network_id, table, peer_timeout, learning, broadcasting, ranges, crypto);
|
||||
if let Some(script) = args.flag_ifup {
|
||||
run_script(script, cloud.ifname());
|
||||
}
|
||||
for addr in &args.flag_connect {
|
||||
cloud.connect(&addr as &str, true).expect("Failed to send");
|
||||
try_fail!(cloud.connect(&addr as &str, true), "Failed to send message to {}: {}", &addr);
|
||||
}
|
||||
cloud.run();
|
||||
if let Some(script) = args.flag_ifdown {
|
||||
run_script(script, cloud.ifname());
|
||||
}
|
||||
},
|
||||
Type::Tun => {
|
||||
let mut cloud = TunCloud::new(device, args.flag_listen, network_id, table, peer_timeout, learning, broadcasting, ranges, crypto);
|
||||
if let Some(script) = args.flag_ifup {
|
||||
run_script(script, cloud.ifname());
|
||||
}
|
||||
for addr in &args.flag_connect {
|
||||
cloud.connect(&addr as &str, true).expect("Failed to send");
|
||||
|
||||
fn main() {
|
||||
let args: Args = Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit());
|
||||
if args.flag_version {
|
||||
println!("VpnCloud v{} ({}, protocol version {})", env!("CARGO_PKG_VERSION"),
|
||||
if cfg!(feature = "crypto") { "with crypto support" } else { "without crypto support" },
|
||||
VERSION
|
||||
);
|
||||
return;
|
||||
}
|
||||
if let Some(script) = args.flag_ifdown {
|
||||
run_script(script, cloud.ifname());
|
||||
log::set_logger(|max_log_level| {
|
||||
assert!(!args.flag_verbose || !args.flag_quiet);
|
||||
if args.flag_verbose {
|
||||
max_log_level.set(log::LogLevelFilter::Debug);
|
||||
} else if args.flag_quiet {
|
||||
max_log_level.set(log::LogLevelFilter::Error);
|
||||
} else {
|
||||
max_log_level.set(log::LogLevelFilter::Info);
|
||||
}
|
||||
cloud.run()
|
||||
Box::new(SimpleLogger)
|
||||
}).unwrap();
|
||||
debug!("Args: {:?}", args);
|
||||
match args.flag_type {
|
||||
Type::Tap => run::<ethernet::Frame>(args),
|
||||
Type::Tun => run::<ip::Packet>(args),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
32
src/types.rs
32
src/types.rs
|
@ -95,11 +95,30 @@ impl FromStr for Range {
|
|||
pub enum Type {
|
||||
Tun, Tap
|
||||
}
|
||||
impl fmt::Display for Type {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
match self {
|
||||
&Type::Tun => write!(formatter, "tun"),
|
||||
&Type::Tap => write!(formatter, "tap"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(RustcDecodable, Debug)]
|
||||
pub enum Mode {
|
||||
Normal, Hub, Switch, Router
|
||||
}
|
||||
impl fmt::Display for Mode {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
match self {
|
||||
&Mode::Normal => write!(formatter, "normal"),
|
||||
&Mode::Hub => write!(formatter, "hub"),
|
||||
&Mode::Switch => write!(formatter, "switch"),
|
||||
&Mode::Router => write!(formatter, "router"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Table {
|
||||
fn learn(&mut self, Address, Option<u8>, SocketAddr);
|
||||
|
@ -120,7 +139,18 @@ pub enum Error {
|
|||
TunTapDevError(&'static str),
|
||||
CryptoError(&'static str)
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
match self {
|
||||
&Error::ParseError(ref msg) => write!(formatter, "{}", msg),
|
||||
&Error::SocketError(ref msg) => write!(formatter, "{}", msg),
|
||||
&Error::TunTapDevError(ref msg) => write!(formatter, "{}", msg),
|
||||
&Error::CryptoError(ref msg) => write!(formatter, "{}", msg),
|
||||
&Error::WrongNetwork(Some(net)) => write!(formatter, "wrong network id: {}", net),
|
||||
&Error::WrongNetwork(None) => write!(formatter, "wrong network id: none"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn address_fmt() {
|
||||
|
|
28
src/util.rs
28
src/util.rs
|
@ -19,3 +19,31 @@ pub fn to_vec(data: &[u8]) -> Vec<u8> {
|
|||
}
|
||||
v
|
||||
}
|
||||
|
||||
macro_rules! fail {
|
||||
($format:expr) => ( {
|
||||
use std::process;
|
||||
error!($format);
|
||||
process::exit(-1);
|
||||
} );
|
||||
($format:expr, $( $arg:expr ),+) => ( {
|
||||
use std::process;
|
||||
error!($format, $( $arg ),+ );
|
||||
process::exit(-1);
|
||||
} );
|
||||
}
|
||||
|
||||
macro_rules! try_fail {
|
||||
($val:expr, $format:expr) => ( {
|
||||
match $val {
|
||||
Ok(val) => val,
|
||||
Err(err) => fail!($format, err)
|
||||
}
|
||||
} );
|
||||
($val:expr, $format:expr, $( $arg:expr ),+) => ( {
|
||||
match $val {
|
||||
Ok(val) => val,
|
||||
Err(err) => fail!($format, $( $arg ),+, err)
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue