mirror of https://github.com/dswd/vpncloud.git
TunCloud
This commit is contained in:
parent
87571feef6
commit
1666845835
18
src/cloud.rs
18
src/cloud.rs
|
@ -10,8 +10,10 @@ use std::marker::PhantomData;
|
||||||
use time::{Duration, SteadyTime, precise_time_ns};
|
use time::{Duration, SteadyTime, precise_time_ns};
|
||||||
use epoll;
|
use epoll;
|
||||||
|
|
||||||
|
use super::device::{TunDevice, TapDevice};
|
||||||
use super::udpmessage::{encode, decode, Options, Message};
|
use super::udpmessage::{encode, decode, Options, Message};
|
||||||
use super::ethernet::{Frame, EthAddr, TapDevice, MacTable};
|
use super::ethernet::{Frame, EthAddr, MacTable};
|
||||||
|
use super::ip::{InternetProtocol, IpAddress, RoutingTable};
|
||||||
|
|
||||||
|
|
||||||
pub type NetworkId = u64;
|
pub type NetworkId = u64;
|
||||||
|
@ -324,3 +326,17 @@ impl TapCloud {
|
||||||
Self::new(device, listen, network_id, table, peer_timeout)
|
Self::new(device, listen, network_id, table, peer_timeout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub type TunCloud = GenericCloud<IpAddress, RoutingTable, InternetProtocol, TunDevice>;
|
||||||
|
|
||||||
|
impl TunCloud {
|
||||||
|
pub fn new_tun_cloud(device: &str, listen: String, network_id: Option<NetworkId>, table: RoutingTable, 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());
|
||||||
|
Self::new(device, listen, network_id, table, peer_timeout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
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::cloud::{Error, VirtualInterface};
|
||||||
|
|
||||||
|
extern {
|
||||||
|
fn setup_tap_device(fd: i32, ifname: *mut u8) -> i32;
|
||||||
|
fn setup_tun_device(fd: i32, ifname: *mut u8) -> i32;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
trait DeviceSetup {
|
||||||
|
fn setup_device(RawFd, &str) -> IoResult<String>;
|
||||||
|
}
|
||||||
|
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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> {
|
||||||
|
fd: fs::File,
|
||||||
|
ifname: String,
|
||||||
|
_dummy_t: PhantomData<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: DeviceSetup> Device<T> {
|
||||||
|
pub fn new(ifname: &str) -> 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})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn ifname(&self) -> &str {
|
||||||
|
&self.ifname
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> AsRawFd for Device<T> {
|
||||||
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
|
self.fd.as_raw_fd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> VirtualInterface for Device<T> {
|
||||||
|
fn read(&mut self, mut buffer: &mut [u8]) -> Result<usize, Error> {
|
||||||
|
self.fd.read(&mut buffer).map_err(|_| Error::TunTapDevError("Read error"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, data: &[u8]) -> Result<(), Error> {
|
||||||
|
match self.fd.write_all(&data) {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(_) => Err(Error::TunTapDevError("Write error"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type TapDevice = Device<TapSetup>;
|
||||||
|
pub type TunDevice = Device<TunSetup>;
|
|
@ -1,18 +1,14 @@
|
||||||
use std::{mem, ptr, fmt, fs};
|
use std::{mem, fmt, fs};
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
use std::io::{Result as IoResult, Error as IoError, Read, Write};
|
use std::io::{Result as IoResult, Error as IoError, Read, Write};
|
||||||
|
|
||||||
use super::cloud::{Error, Table, Protocol, VirtualInterface};
|
use super::cloud::{Error, Table, Protocol, VirtualInterface};
|
||||||
use super::util::{as_bytes, as_obj};
|
use super::util::as_obj;
|
||||||
|
|
||||||
use time::{Duration, SteadyTime};
|
use time::{Duration, SteadyTime};
|
||||||
|
|
||||||
extern {
|
|
||||||
fn setup_tap_device(fd: i32, ifname: *mut u8) -> i32;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Mac(pub [u8; 6]);
|
pub struct Mac(pub [u8; 6]);
|
||||||
|
@ -61,51 +57,6 @@ impl Protocol for Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub struct TapDevice {
|
|
||||||
fd: fs::File,
|
|
||||||
ifname: String
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TapDevice {
|
|
||||||
pub fn new(ifname: &str) -> IoResult<Self> {
|
|
||||||
let fd = try!(fs::OpenOptions::new().read(true).write(true).open("/dev/net/tun"));
|
|
||||||
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.as_raw_fd(), ifname_c.as_mut_ptr()) };
|
|
||||||
match res {
|
|
||||||
0 => Ok(TapDevice{fd: fd, ifname: String::from_utf8(ifname_c).unwrap()}),
|
|
||||||
_ => Err(IoError::last_os_error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn ifname(&self) -> &str {
|
|
||||||
&self.ifname
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRawFd for TapDevice {
|
|
||||||
fn as_raw_fd(&self) -> RawFd {
|
|
||||||
self.fd.as_raw_fd()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VirtualInterface for TapDevice {
|
|
||||||
fn read(&mut self, mut buffer: &mut [u8]) -> Result<usize, Error> {
|
|
||||||
self.fd.read(&mut buffer).map_err(|_| Error::TunTapDevError("Read error"))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(&mut self, data: &[u8]) -> Result<(), Error> {
|
|
||||||
match self.fd.write_all(&data) {
|
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(_) => Err(Error::TunTapDevError("Write error"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct MacTableValue {
|
struct MacTableValue {
|
||||||
address: SocketAddr,
|
address: SocketAddr,
|
||||||
timeout: SteadyTime
|
timeout: SteadyTime
|
||||||
|
|
74
src/ip.rs
74
src/ip.rs
|
@ -1,7 +1,8 @@
|
||||||
use std::net::{SocketAddr, Ipv4Addr, Ipv6Addr};
|
use std::net::{SocketAddr, Ipv4Addr, Ipv6Addr};
|
||||||
use std::collections::{hash_map, HashMap};
|
use std::collections::{hash_map, HashMap};
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
use super::cloud::{Protocol, Error};
|
use super::cloud::{Protocol, Error, Table};
|
||||||
use super::util::{as_obj, as_bytes};
|
use super::util::{as_obj, as_bytes};
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,7 +18,43 @@ impl Protocol for InternetProtocol {
|
||||||
type Address = IpAddress;
|
type Address = IpAddress;
|
||||||
|
|
||||||
fn parse(data: &[u8]) -> Result<(IpAddress, IpAddress), Error> {
|
fn parse(data: &[u8]) -> Result<(IpAddress, IpAddress), Error> {
|
||||||
unimplemented!()
|
if data.len() < 1 {
|
||||||
|
return Err(Error::ParseError("Empty header"));
|
||||||
|
}
|
||||||
|
let version = data[0] >> 4;
|
||||||
|
match version {
|
||||||
|
4 => {
|
||||||
|
if data.len() < 20 {
|
||||||
|
return Err(Error::ParseError("Truncated header"));
|
||||||
|
}
|
||||||
|
let src_data = unsafe { as_obj::<[u8; 4]>(&data[12..]) };
|
||||||
|
let src = Ipv4Addr::new(src_data[0], src_data[1], src_data[2], src_data[3]);
|
||||||
|
let dst_data = unsafe { as_obj::<[u8; 4]>(&data[16..]) };
|
||||||
|
let dst = Ipv4Addr::new(dst_data[0], dst_data[1], dst_data[2], dst_data[3]);
|
||||||
|
Ok((IpAddress::V4(src), IpAddress::V4(dst)))
|
||||||
|
},
|
||||||
|
6 => {
|
||||||
|
if data.len() < 40 {
|
||||||
|
return Err(Error::ParseError("Truncated header"));
|
||||||
|
}
|
||||||
|
let src_data = unsafe { as_obj::<[u16; 8]>(&data[8..]) };
|
||||||
|
let src = Ipv6Addr::new(
|
||||||
|
u16::from_be(src_data[0]), u16::from_be(src_data[1]),
|
||||||
|
u16::from_be(src_data[2]), u16::from_be(src_data[3]),
|
||||||
|
u16::from_be(src_data[4]), u16::from_be(src_data[5]),
|
||||||
|
u16::from_be(src_data[6]), u16::from_be(src_data[7]),
|
||||||
|
);
|
||||||
|
let dst_data = unsafe { as_obj::<[u16; 8]>(&data[24..]) };
|
||||||
|
let dst = Ipv6Addr::new(
|
||||||
|
u16::from_be(dst_data[0]), u16::from_be(dst_data[1]),
|
||||||
|
u16::from_be(dst_data[2]), u16::from_be(dst_data[3]),
|
||||||
|
u16::from_be(dst_data[4]), u16::from_be(dst_data[5]),
|
||||||
|
u16::from_be(dst_data[6]), u16::from_be(dst_data[7]),
|
||||||
|
);
|
||||||
|
Ok((IpAddress::V6(src), IpAddress::V6(dst)))
|
||||||
|
},
|
||||||
|
_ => Err(Error::ParseError("Invalid version"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +83,7 @@ impl RoutingTable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lookup(&self, bytes: Vec<u8>) -> Option<SocketAddr> {
|
pub fn lookup_bytes(&self, bytes: &[u8]) -> Option<SocketAddr> {
|
||||||
let mut len = bytes.len()/2 * 2;
|
let mut len = bytes.len()/2 * 2;
|
||||||
for i in 0..len/2 {
|
for i in 0..len/2 {
|
||||||
if let Some(group) = self.0.get(&bytes[0..len-2*i]) {
|
if let Some(group) = self.0.get(&bytes[0..len-2*i]) {
|
||||||
|
@ -73,3 +110,34 @@ impl RoutingTable {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Table for RoutingTable {
|
||||||
|
type Address = IpAddress;
|
||||||
|
|
||||||
|
fn learn(&mut self, _src: Self::Address, _addr: SocketAddr) {
|
||||||
|
//nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lookup(&self, dst: &Self::Address) -> Option<SocketAddr> {
|
||||||
|
match dst {
|
||||||
|
&IpAddress::V4(addr) => {
|
||||||
|
let mut bytes = [0u8; 4];
|
||||||
|
let ip = addr.octets();
|
||||||
|
unsafe { ptr::copy_nonoverlapping(ip.as_ptr(), bytes.as_mut_ptr(), ip.len()) };
|
||||||
|
self.lookup_bytes(&bytes[..])
|
||||||
|
},
|
||||||
|
&IpAddress::V6(addr) => {
|
||||||
|
let mut segments = addr.segments();
|
||||||
|
for i in 0..8 {
|
||||||
|
segments[i] = segments[i].to_be();
|
||||||
|
}
|
||||||
|
let bytes = unsafe { as_bytes(&segments) };
|
||||||
|
self.lookup_bytes(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn housekeep(&mut self) {
|
||||||
|
//nothin to do
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ mod udpmessage;
|
||||||
mod ethernet;
|
mod ethernet;
|
||||||
mod ip;
|
mod ip;
|
||||||
mod cloud;
|
mod cloud;
|
||||||
|
mod device;
|
||||||
|
|
||||||
use time::Duration;
|
use time::Duration;
|
||||||
use docopt::Docopt;
|
use docopt::Docopt;
|
||||||
|
|
Loading…
Reference in New Issue