mirror of https://github.com/dswd/vpncloud.git
Add listen option, switched to dual-stack
This commit is contained in:
parent
fba72882a6
commit
390f217a23
|
@ -2,6 +2,11 @@
|
|||
|
||||
This project follows [semantic versioning](http://semver.org).
|
||||
|
||||
### UNRELEASED
|
||||
|
||||
- [added] Added option to listen on specified IP
|
||||
- [changed] No longer using two sockets for ipv4 and ipv6
|
||||
|
||||
### v1.3.0 (2020-01-25)
|
||||
|
||||
- [added] Building for aarch64 aka arm64 (thanks to Ivan)
|
||||
|
|
|
@ -130,10 +130,9 @@ fn now(b: &mut Bencher) {
|
|||
|
||||
#[bench]
|
||||
fn epoll_wait(b: &mut Bencher) {
|
||||
let socketv4 = UdpSocket::bind("0.0.0.0:0").unwrap();
|
||||
let socketv6 = UdpSocket::bind("[::]:0").unwrap();
|
||||
let socket = UdpSocket::bind("[::]:0").unwrap();
|
||||
let device = TunTapDevice::dummy("dummy", "/dev/zero", Type::Dummy).unwrap();
|
||||
let mut waiter = WaitImpl::testing(&socketv4, &socketv6, &device, 1000).unwrap();
|
||||
let mut waiter = WaitImpl::testing(&socket, &device, 1000).unwrap();
|
||||
b.iter(|| assert!(waiter.next().is_some()));
|
||||
b.bytes = 1400;
|
||||
}
|
||||
|
|
67
src/cloud.rs
67
src/cloud.rs
|
@ -222,8 +222,7 @@ pub struct GenericCloud<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSou
|
|||
reconnect_peers: Vec<ReconnectEntry>,
|
||||
own_addresses: Vec<SocketAddr>,
|
||||
table: T,
|
||||
socket4: S,
|
||||
socket6: S,
|
||||
socket: S,
|
||||
device: D,
|
||||
crypto: Crypto,
|
||||
next_peerlist: Time,
|
||||
|
@ -248,13 +247,9 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
|
|||
port_forwarding: Option<PortForwarding>, stats_file: Option<File>
|
||||
) -> Self
|
||||
{
|
||||
let socket4 = match S::listen_v4("0.0.0.0", config.port) {
|
||||
let socket = match S::listen(config.listen) {
|
||||
Ok(socket) => socket,
|
||||
Err(err) => fail!("Failed to open ipv4 address 0.0.0.0:{}: {}", config.port, err)
|
||||
};
|
||||
let socket6 = match S::listen_v6("::", config.port) {
|
||||
Ok(socket) => socket,
|
||||
Err(err) => fail!("Failed to open ipv6 address ::{}: {}", config.port, err)
|
||||
Err(err) => fail!("Failed to open socket {}: {}", config.listen, err)
|
||||
};
|
||||
let now = TS::now();
|
||||
let update_freq = config.get_keepalive() as u16;
|
||||
|
@ -269,8 +264,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
|
|||
own_addresses: Vec::new(),
|
||||
peer_timeout_publish: config.peer_timeout as u16,
|
||||
table,
|
||||
socket4,
|
||||
socket6,
|
||||
socket,
|
||||
device,
|
||||
next_peerlist: now,
|
||||
update_freq,
|
||||
|
@ -309,11 +303,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
|
|||
let msg_data = encode(msg, &mut self.buffer_out, self.magic, &mut self.crypto);
|
||||
for addr in self.peers.peers.keys() {
|
||||
self.traffic.count_out_traffic(*addr, msg_data.len());
|
||||
let socket = match *addr {
|
||||
SocketAddr::V4(_) => &mut self.socket4,
|
||||
SocketAddr::V6(_) => &mut self.socket6
|
||||
};
|
||||
match socket.send(msg_data, *addr) {
|
||||
match self.socket.send(msg_data, *addr) {
|
||||
Ok(written) if written == msg_data.len() => Ok(()),
|
||||
Ok(_) => {
|
||||
Err(Error::Socket("Sent out truncated packet", io::Error::new(io::ErrorKind::Other, "truncated")))
|
||||
|
@ -335,11 +325,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
|
|||
// Encrypt and encode
|
||||
let msg_data = encode(msg, &mut self.buffer_out, self.magic, &mut self.crypto);
|
||||
self.traffic.count_out_traffic(addr, msg_data.len());
|
||||
let socket = match addr {
|
||||
SocketAddr::V4(_) => &mut self.socket4,
|
||||
SocketAddr::V6(_) => &mut self.socket6
|
||||
};
|
||||
match socket.send(msg_data, addr) {
|
||||
match self.socket.send(msg_data, addr) {
|
||||
Ok(written) if written == msg_data.len() => Ok(()),
|
||||
Ok(_) => Err(Error::Socket("Sent out truncated packet", io::Error::new(io::ErrorKind::Other, "truncated"))),
|
||||
Err(e) => Err(Error::Socket("IOError when sending", e))
|
||||
|
@ -354,8 +340,8 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
|
|||
/// # Errors
|
||||
/// Returns an IOError if the underlying system call fails
|
||||
#[allow(dead_code)]
|
||||
pub fn address(&self) -> io::Result<(SocketAddr, SocketAddr)> {
|
||||
Ok((self.socket4.address()?, self.socket6.address()?))
|
||||
pub fn address(&self) -> io::Result<SocketAddr> {
|
||||
Ok(self.socket.address()?)
|
||||
}
|
||||
|
||||
/// Returns the number of peers
|
||||
|
@ -747,10 +733,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
|
|||
fn initialize(&mut self) {
|
||||
match self.address() {
|
||||
Err(err) => error!("Failed to obtain local addresses: {}", err),
|
||||
Ok((v4, v6)) => {
|
||||
self.own_addresses.push(v4);
|
||||
self.own_addresses.push(v6);
|
||||
}
|
||||
Ok(addr) => self.own_addresses.push(addr)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -764,13 +747,8 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_socket_v4_event(&mut self, buffer: &mut [u8]) {
|
||||
let (size, src) = try_fail!(self.socket4.receive(buffer), "Failed to read from ipv4 network socket: {}");
|
||||
self.handle_socket_data(src, &mut buffer[..size])
|
||||
}
|
||||
|
||||
fn handle_socket_v6_event(&mut self, buffer: &mut [u8]) {
|
||||
let (size, src) = try_fail!(self.socket6.receive(buffer), "Failed to read from ipv6 network socket: {}");
|
||||
fn handle_socket_event(&mut self, buffer: &mut [u8]) {
|
||||
let (size, src) = try_fail!(self.socket.receive(buffer), "Failed to read from network socket: {}");
|
||||
self.handle_socket_data(src, &mut buffer[..size])
|
||||
}
|
||||
|
||||
|
@ -792,8 +770,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
|
|||
/// Also, this method will call `housekeep` every second.
|
||||
pub fn run(&mut self) {
|
||||
let ctrlc = CtrlC::new();
|
||||
let waiter =
|
||||
try_fail!(WaitImpl::new(&self.socket4, &self.socket6, &self.device, 1000), "Failed to setup poll: {}");
|
||||
let waiter = try_fail!(WaitImpl::new(&self.socket, &self.device, 1000), "Failed to setup poll: {}");
|
||||
let mut buffer = [0; 64 * 1024];
|
||||
let mut poll_error = false;
|
||||
for evt in waiter {
|
||||
|
@ -806,8 +783,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
|
|||
poll_error = true;
|
||||
}
|
||||
WaitResult::Timeout => {}
|
||||
WaitResult::SocketV4 => self.handle_socket_v4_event(&mut buffer),
|
||||
WaitResult::SocketV6 => self.handle_socket_v6_event(&mut buffer),
|
||||
WaitResult::Socket => self.handle_socket_event(&mut buffer),
|
||||
WaitResult::Device => self.handle_device_event(&mut buffer)
|
||||
}
|
||||
if self.next_housekeep < TS::now() {
|
||||
|
@ -842,26 +818,17 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
|
|||
|
||||
#[cfg(test)]
|
||||
impl<P: Protocol, T: Table> GenericCloud<MockDevice, P, T, MockSocket, MockTimeSource> {
|
||||
pub fn socket4(&mut self) -> &mut MockSocket {
|
||||
&mut self.socket4
|
||||
}
|
||||
|
||||
pub fn socket6(&mut self) -> &mut MockSocket {
|
||||
&mut self.socket6
|
||||
pub fn socket(&mut self) -> &mut MockSocket {
|
||||
&mut self.socket
|
||||
}
|
||||
|
||||
pub fn device(&mut self) -> &mut MockDevice {
|
||||
&mut self.device
|
||||
}
|
||||
|
||||
pub fn trigger_socket_v4_event(&mut self) {
|
||||
pub fn trigger_socket_event(&mut self) {
|
||||
let mut buffer = [0; 64 * 1024];
|
||||
self.handle_socket_v4_event(&mut buffer);
|
||||
}
|
||||
|
||||
pub fn trigger_socket_v6_event(&mut self) {
|
||||
let mut buffer = [0; 64 * 1024];
|
||||
self.handle_socket_v6_event(&mut buffer);
|
||||
self.handle_socket_event(&mut buffer);
|
||||
}
|
||||
|
||||
pub fn trigger_device_event(&mut self) {
|
||||
|
|
|
@ -12,13 +12,28 @@ use super::{
|
|||
};
|
||||
|
||||
use siphasher::sip::SipHasher24;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::{
|
||||
hash::{Hash, Hasher},
|
||||
net::{IpAddr, Ipv6Addr, SocketAddr}
|
||||
};
|
||||
|
||||
|
||||
const HASH_PREFIX: &str = "hash:";
|
||||
pub const DEFAULT_PEER_TIMEOUT: u16 = 600;
|
||||
|
||||
|
||||
fn parse_listen(addr: &str) -> SocketAddr {
|
||||
if addr.starts_with("*:") {
|
||||
let port = try_fail!(addr[2..].parse::<u16>(), "Invalid port: {}");
|
||||
SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), port)
|
||||
} else if addr.contains(':') {
|
||||
try_fail!(addr.parse::<SocketAddr>(), "Invalid address: {}: {}", addr)
|
||||
} else {
|
||||
let port = try_fail!(addr.parse::<u16>(), "Invalid port: {}");
|
||||
SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), port)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, PartialEq, Clone)]
|
||||
pub struct Config {
|
||||
pub device_type: Type,
|
||||
|
@ -29,7 +44,7 @@ pub struct Config {
|
|||
pub crypto: CryptoMethod,
|
||||
pub shared_key: Option<String>,
|
||||
pub magic: Option<String>,
|
||||
pub port: u16,
|
||||
pub listen: SocketAddr,
|
||||
pub peers: Vec<String>,
|
||||
pub peer_timeout: Duration,
|
||||
pub keepalive: Option<Duration>,
|
||||
|
@ -58,7 +73,7 @@ impl Default for Config {
|
|||
crypto: CryptoMethod::ChaCha20,
|
||||
shared_key: None,
|
||||
magic: None,
|
||||
port: 3210,
|
||||
listen: "[::]:3210".parse::<SocketAddr>().unwrap(),
|
||||
peers: vec![],
|
||||
peer_timeout: DEFAULT_PEER_TIMEOUT as Duration,
|
||||
keepalive: None,
|
||||
|
@ -79,6 +94,7 @@ impl Default for Config {
|
|||
}
|
||||
|
||||
impl Config {
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
pub fn merge_file(&mut self, file: ConfigFile) {
|
||||
if let Some(val) = file.device_type {
|
||||
self.device_type = val;
|
||||
|
@ -105,7 +121,11 @@ impl Config {
|
|||
self.magic = Some(val);
|
||||
}
|
||||
if let Some(val) = file.port {
|
||||
self.port = val;
|
||||
self.listen = parse_listen(&format!("{}", &val));
|
||||
warn!("The config option 'port' is deprecated, use 'listen' instead.");
|
||||
}
|
||||
if let Some(val) = file.listen {
|
||||
self.listen = parse_listen(&val);
|
||||
}
|
||||
if let Some(mut val) = file.peers {
|
||||
self.peers.append(&mut val);
|
||||
|
@ -181,7 +201,7 @@ impl Config {
|
|||
self.magic = Some(val);
|
||||
}
|
||||
if let Some(val) = args.flag_listen {
|
||||
self.port = val;
|
||||
self.listen = parse_listen(&val);
|
||||
}
|
||||
self.peers.append(&mut args.flag_connect);
|
||||
if let Some(val) = args.flag_peer_timeout {
|
||||
|
@ -265,6 +285,7 @@ pub struct ConfigFile {
|
|||
pub shared_key: Option<String>,
|
||||
pub magic: Option<String>,
|
||||
pub port: Option<u16>,
|
||||
pub listen: Option<String>,
|
||||
pub peers: Option<Vec<String>>,
|
||||
pub peer_timeout: Option<Duration>,
|
||||
pub keepalive: Option<Duration>,
|
||||
|
@ -322,6 +343,7 @@ stats_file: /var/log/vpncloud.stats
|
|||
shared_key: Some("mysecret".to_string()),
|
||||
magic: Some("0123ABCD".to_string()),
|
||||
port: Some(3210),
|
||||
listen: None,
|
||||
peers: Some(vec!["remote.machine.foo:3210".to_string(), "remote.machine.bar:3210".to_string()]),
|
||||
peer_timeout: Some(600),
|
||||
keepalive: Some(840),
|
||||
|
@ -352,6 +374,7 @@ fn config_merge() {
|
|||
shared_key: Some("mysecret".to_string()),
|
||||
magic: Some("0123ABCD".to_string()),
|
||||
port: Some(3210),
|
||||
listen: None,
|
||||
peers: Some(vec!["remote.machine.foo:3210".to_string(), "remote.machine.bar:3210".to_string()]),
|
||||
peer_timeout: Some(600),
|
||||
keepalive: Some(840),
|
||||
|
@ -376,7 +399,7 @@ fn config_merge() {
|
|||
magic: Some("0123ABCD".to_string()),
|
||||
crypto: CryptoMethod::AES256,
|
||||
shared_key: Some("mysecret".to_string()),
|
||||
port: 3210,
|
||||
listen: "[::]:3210".parse::<SocketAddr>().unwrap(),
|
||||
peers: vec!["remote.machine.foo:3210".to_string(), "remote.machine.bar:3210".to_string()],
|
||||
peer_timeout: 600,
|
||||
keepalive: Some(840),
|
||||
|
@ -402,7 +425,7 @@ fn config_merge() {
|
|||
flag_crypto: Some(CryptoMethod::ChaCha20),
|
||||
flag_shared_key: Some("anothersecret".to_string()),
|
||||
flag_magic: Some("hash:mynet".to_string()),
|
||||
flag_listen: Some(3211),
|
||||
flag_listen: Some("3211".to_string()),
|
||||
flag_peer_timeout: Some(1801),
|
||||
flag_keepalive: Some(850),
|
||||
flag_dst_timeout: Some(301),
|
||||
|
@ -429,7 +452,7 @@ fn config_merge() {
|
|||
magic: Some("hash:mynet".to_string()),
|
||||
crypto: CryptoMethod::ChaCha20,
|
||||
shared_key: Some("anothersecret".to_string()),
|
||||
port: 3211,
|
||||
listen: "[::]:3211".parse::<SocketAddr>().unwrap(),
|
||||
peers: vec![
|
||||
"remote.machine.foo:3210".to_string(),
|
||||
"remote.machine.bar:3210".to_string(),
|
||||
|
|
|
@ -72,7 +72,7 @@ pub struct Args {
|
|||
flag_crypto: Option<CryptoMethod>,
|
||||
flag_subnet: Vec<String>,
|
||||
flag_device: Option<String>,
|
||||
flag_listen: Option<u16>,
|
||||
flag_listen: Option<String>,
|
||||
flag_network_id: Option<String>,
|
||||
flag_magic: Option<String>,
|
||||
flag_connect: Vec<String>,
|
||||
|
@ -270,7 +270,7 @@ fn run<P: Protocol>(config: Config) {
|
|||
Some(ref key) => Crypto::from_shared_key(config.crypto, key),
|
||||
None => Crypto::None
|
||||
};
|
||||
let port_forwarding = if config.port_forwarding { PortForwarding::new(config.port) } else { None };
|
||||
let port_forwarding = if config.port_forwarding { PortForwarding::new(config.listen.port()) } else { None };
|
||||
let stats_file = match config.stats_file {
|
||||
None => None,
|
||||
Some(ref name) => {
|
||||
|
|
27
src/net.rs
27
src/net.rs
|
@ -1,34 +1,24 @@
|
|||
use std::{
|
||||
collections::{HashMap, VecDeque},
|
||||
io::{self, ErrorKind},
|
||||
net::{SocketAddr, SocketAddrV4, SocketAddrV6, UdpSocket},
|
||||
net::{SocketAddr, UdpSocket},
|
||||
os::unix::io::{AsRawFd, RawFd},
|
||||
sync::atomic::{AtomicBool, Ordering}
|
||||
};
|
||||
|
||||
use super::util::{MockTimeSource, Time, TimeSource};
|
||||
|
||||
use net2::UdpBuilder;
|
||||
|
||||
|
||||
pub trait Socket: AsRawFd + Sized {
|
||||
fn listen_v4(host: &str, port: u16) -> Result<Self, io::Error>;
|
||||
fn listen_v6(host: &str, port: u16) -> Result<Self, io::Error>;
|
||||
fn listen(addr: SocketAddr) -> Result<Self, io::Error>;
|
||||
fn receive(&mut self, buffer: &mut [u8]) -> Result<(usize, SocketAddr), io::Error>;
|
||||
fn send(&mut self, data: &[u8], addr: SocketAddr) -> Result<usize, io::Error>;
|
||||
fn address(&self) -> Result<SocketAddr, io::Error>;
|
||||
}
|
||||
|
||||
impl Socket for UdpSocket {
|
||||
fn listen_v4(host: &str, port: u16) -> Result<Self, io::Error> {
|
||||
UdpBuilder::new_v4().expect("Failed to obtain ipv4 socket builder").bind((host, port))
|
||||
}
|
||||
fn listen_v6(host: &str, port: u16) -> Result<Self, io::Error> {
|
||||
UdpBuilder::new_v6()
|
||||
.expect("Failed to obtain ipv4 socket builder")
|
||||
.only_v6(true)
|
||||
.expect("Failed to set only_v6")
|
||||
.bind((host, port))
|
||||
fn listen(addr: SocketAddr) -> Result<Self, io::Error> {
|
||||
UdpSocket::bind(addr)
|
||||
}
|
||||
fn receive(&mut self, buffer: &mut [u8]) -> Result<(usize, SocketAddr), io::Error> {
|
||||
self.recv_from(buffer)
|
||||
|
@ -99,13 +89,8 @@ impl AsRawFd for MockSocket {
|
|||
}
|
||||
|
||||
impl Socket for MockSocket {
|
||||
fn listen_v4(host: &str, port: u16) -> Result<Self, io::Error> {
|
||||
let ip = try_fail!(host.parse(), "Failed to parse IPv4 address: {}");
|
||||
Ok(Self::new(SocketAddr::V4(SocketAddrV4::new(ip, port))))
|
||||
}
|
||||
fn listen_v6(host: &str, port: u16) -> Result<Self, io::Error> {
|
||||
let ip = try_fail!(host.parse(), "Failed to parse IPv6 address: {}");
|
||||
Ok(Self::new(SocketAddr::V6(SocketAddrV6::new(ip, port, 0, 0))))
|
||||
fn listen(addr: SocketAddr) -> Result<Self, io::Error> {
|
||||
Ok(Self::new(addr))
|
||||
}
|
||||
fn receive(&mut self, buffer: &mut [u8]) -> Result<(usize, SocketAddr), io::Error> {
|
||||
if let Some((addr, data)) = self.inbound.pop_front() {
|
||||
|
|
|
@ -13,33 +13,30 @@ use crate::{device::Type, net::Socket};
|
|||
pub struct EpollWait {
|
||||
poll_fd: RawFd,
|
||||
event: libc::epoll_event,
|
||||
socketv4: RawFd,
|
||||
socketv6: RawFd,
|
||||
socket: RawFd,
|
||||
device: RawFd,
|
||||
timeout: u32
|
||||
}
|
||||
|
||||
impl EpollWait {
|
||||
pub fn new<S: Socket>(socketv4: &S, socketv6: &S, device: &dyn Device, timeout: u32) -> io::Result<Self> {
|
||||
Self::create(socketv4, socketv6, device, timeout, libc::EPOLLIN as u32)
|
||||
pub fn new<S: Socket>(socket: &S, device: &dyn Device, timeout: u32) -> io::Result<Self> {
|
||||
Self::create(socket, device, timeout, libc::EPOLLIN as u32)
|
||||
}
|
||||
|
||||
pub fn testing<S: Socket>(socketv4: &S, socketv6: &S, device: &dyn Device, timeout: u32) -> io::Result<Self> {
|
||||
Self::create(socketv4, socketv6, device, timeout, (libc::EPOLLIN | libc::EPOLLOUT) as u32)
|
||||
pub fn testing<S: Socket>(socket: &S, device: &dyn Device, timeout: u32) -> io::Result<Self> {
|
||||
Self::create(socket, device, timeout, (libc::EPOLLIN | libc::EPOLLOUT) as u32)
|
||||
}
|
||||
|
||||
fn create<S: Socket>(
|
||||
socketv4: &S, socketv6: &S, device: &dyn Device, timeout: u32, flags: u32
|
||||
) -> io::Result<Self> {
|
||||
fn create<S: Socket>(socket: &S, device: &dyn Device, timeout: u32, flags: u32) -> io::Result<Self> {
|
||||
let mut event = libc::epoll_event { u64: 0, events: 0 };
|
||||
let poll_fd = unsafe { libc::epoll_create(3) };
|
||||
if poll_fd == -1 {
|
||||
return Err(io::Error::last_os_error())
|
||||
}
|
||||
let raw_fds = if device.get_type() != Type::Dummy {
|
||||
vec![socketv4.as_raw_fd(), socketv6.as_raw_fd(), device.as_raw_fd()]
|
||||
vec![socket.as_raw_fd(), device.as_raw_fd()]
|
||||
} else {
|
||||
vec![socketv4.as_raw_fd(), socketv6.as_raw_fd()]
|
||||
vec![socket.as_raw_fd()]
|
||||
};
|
||||
for fd in raw_fds {
|
||||
event.u64 = fd as u64;
|
||||
|
@ -52,8 +49,7 @@ impl EpollWait {
|
|||
Ok(Self {
|
||||
poll_fd,
|
||||
event,
|
||||
socketv4: socketv4.as_raw_fd(),
|
||||
socketv6: socketv6.as_raw_fd(),
|
||||
socket: socket.as_raw_fd(),
|
||||
device: device.as_raw_fd(),
|
||||
timeout
|
||||
})
|
||||
|
@ -74,10 +70,8 @@ impl Iterator for EpollWait {
|
|||
-1 => WaitResult::Error(io::Error::last_os_error()),
|
||||
0 => WaitResult::Timeout,
|
||||
1 => {
|
||||
if self.event.u64 == self.socketv4 as u64 {
|
||||
WaitResult::SocketV4
|
||||
} else if self.event.u64 == self.socketv6 as u64 {
|
||||
WaitResult::SocketV6
|
||||
if self.event.u64 == self.socket as u64 {
|
||||
WaitResult::Socket
|
||||
} else if self.event.u64 == self.device as u64 {
|
||||
WaitResult::Device
|
||||
} else {
|
||||
|
|
|
@ -13,8 +13,7 @@ use std::io;
|
|||
|
||||
pub enum WaitResult {
|
||||
Timeout,
|
||||
SocketV4,
|
||||
SocketV6,
|
||||
Socket,
|
||||
Device,
|
||||
Error(io::Error)
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
macro_rules! assert_clean {
|
||||
($($node: expr),*) => {
|
||||
$(
|
||||
assert_eq!($node.socket4().pop_outbound().map(|(addr, mut msg)| (addr, $node.decode_message(&mut msg).unwrap().without_data())), None);
|
||||
assert_eq!($node.socket6().pop_outbound().map(|(addr, mut msg)| (addr, $node.decode_message(&mut msg).unwrap().without_data())), None);
|
||||
assert_eq!($node.socket().pop_outbound().map(|(addr, mut msg)| (addr, $node.decode_message(&mut msg).unwrap().without_data())), None);
|
||||
assert_eq!($node.device().pop_outbound(), None);
|
||||
)*
|
||||
};
|
||||
|
@ -10,13 +9,13 @@ macro_rules! assert_clean {
|
|||
|
||||
macro_rules! assert_message4 {
|
||||
($from: expr, $from_addr: expr, $to: expr, $to_addr: expr, $message: expr) => {
|
||||
let (addr, mut data) = msg4_get(&mut $from);
|
||||
let (addr, mut data) = msg_get(&mut $from);
|
||||
assert_eq!($to_addr, addr);
|
||||
{
|
||||
let message = $from.decode_message(&mut data).unwrap();
|
||||
assert_eq!($message, message.without_data());
|
||||
}
|
||||
msg4_put(&mut $to, $from_addr, data);
|
||||
msg_put(&mut $to, $from_addr, data);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -8,9 +8,9 @@ mod nat;
|
|||
mod payload;
|
||||
mod peers;
|
||||
|
||||
pub use std::net::SocketAddr;
|
||||
use std::{
|
||||
io::Write,
|
||||
net::{IpAddr, Ipv6Addr, SocketAddr},
|
||||
sync::{
|
||||
atomic::{AtomicUsize, Ordering},
|
||||
Once
|
||||
|
@ -73,13 +73,17 @@ thread_local! {
|
|||
static NEXT_PORT: AtomicUsize = AtomicUsize::new(1);
|
||||
}
|
||||
|
||||
fn next_sock_addr() -> SocketAddr {
|
||||
SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), NEXT_PORT.with(|p| p.fetch_add(1, Ordering::Relaxed)) as u16)
|
||||
}
|
||||
|
||||
fn create_tap_node(nat: bool) -> TapTestNode {
|
||||
create_tap_node_with_config(nat, Config::default())
|
||||
}
|
||||
|
||||
fn create_tap_node_with_config(nat: bool, mut config: Config) -> TapTestNode {
|
||||
MockSocket::set_nat(nat);
|
||||
config.port = NEXT_PORT.with(|p| p.fetch_add(1, Ordering::Relaxed)) as u16;
|
||||
config.listen = next_sock_addr();
|
||||
TestNode::new(&config, MockDevice::new(), SwitchTable::new(1800, 10), true, true, vec![], Crypto::None, None, None)
|
||||
}
|
||||
|
||||
|
@ -87,7 +91,7 @@ fn create_tap_node_with_config(nat: bool, mut config: Config) -> TapTestNode {
|
|||
fn create_tun_node(nat: bool, addresses: Vec<Range>) -> TunTestNode {
|
||||
MockSocket::set_nat(nat);
|
||||
TestNode::new(
|
||||
&Config { port: NEXT_PORT.with(|p| p.fetch_add(1, Ordering::Relaxed)) as u16, ..Config::default() },
|
||||
&Config { listen: next_sock_addr(), ..Config::default() },
|
||||
MockDevice::new(),
|
||||
RoutingTable::new(),
|
||||
false,
|
||||
|
@ -100,28 +104,15 @@ fn create_tun_node(nat: bool, addresses: Vec<Range>) -> TunTestNode {
|
|||
}
|
||||
|
||||
|
||||
fn msg4_get<P: Protocol, T: Table>(node: &mut TestNode<P, T>) -> (SocketAddr, Vec<u8>) {
|
||||
let msg = node.socket4().pop_outbound();
|
||||
fn msg_get<P: Protocol, T: Table>(node: &mut TestNode<P, T>) -> (SocketAddr, Vec<u8>) {
|
||||
let msg = node.socket().pop_outbound();
|
||||
assert!(msg.is_some());
|
||||
msg.unwrap()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn msg6_get<P: Protocol, T: Table>(node: &mut TestNode<P, T>) -> (SocketAddr, Vec<u8>) {
|
||||
let msg = node.socket6().pop_outbound();
|
||||
assert!(msg.is_some());
|
||||
msg.unwrap()
|
||||
}
|
||||
|
||||
fn msg4_put<P: Protocol, T: Table>(node: &mut TestNode<P, T>, from: SocketAddr, msg: Vec<u8>) {
|
||||
if node.socket4().put_inbound(from, msg) {
|
||||
node.trigger_socket_v4_event();
|
||||
}
|
||||
}
|
||||
|
||||
fn msg6_put<P: Protocol, T: Table>(node: &mut TestNode<P, T>, from: SocketAddr, msg: Vec<u8>) {
|
||||
if node.socket6().put_inbound(from, msg) {
|
||||
node.trigger_socket_v6_event();
|
||||
fn msg_put<P: Protocol, T: Table>(node: &mut TestNode<P, T>, from: SocketAddr, msg: Vec<u8>) {
|
||||
if node.socket().put_inbound(from, msg) {
|
||||
node.trigger_socket_event();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,7 +127,7 @@ fn simulate<P: Protocol, T: Table>(nodes: &mut [(&mut TestNode<P, T>, SocketAddr
|
|||
clean = true;
|
||||
let mut msgs = Vec::new();
|
||||
for (ref mut node, ref from_addr) in nodes.iter_mut() {
|
||||
while let Some((to_addr, msg)) = node.socket4().pop_outbound() {
|
||||
while let Some((to_addr, msg)) = node.socket().pop_outbound() {
|
||||
msgs.push((msg, *from_addr, to_addr));
|
||||
}
|
||||
}
|
||||
|
@ -144,22 +135,7 @@ fn simulate<P: Protocol, T: Table>(nodes: &mut [(&mut TestNode<P, T>, SocketAddr
|
|||
for (msg, from_addr, to_addr) in msgs {
|
||||
for (ref mut node, ref addr) in nodes.iter_mut() {
|
||||
if *addr == to_addr {
|
||||
msg4_put(node, from_addr, msg);
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut msgs = Vec::new();
|
||||
for (ref mut node, ref from_addr) in nodes.iter_mut() {
|
||||
while let Some((to_addr, msg)) = node.socket6().pop_outbound() {
|
||||
msgs.push((msg, *from_addr, to_addr));
|
||||
}
|
||||
}
|
||||
clean &= msgs.is_empty();
|
||||
for (msg, from_addr, to_addr) in msgs {
|
||||
for (ref mut node, ref addr) in nodes.iter_mut() {
|
||||
if *addr == to_addr {
|
||||
msg6_put(node, from_addr, msg);
|
||||
msg_put(node, from_addr, msg);
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ fn connect_via_beacons() {
|
|||
let beacon_path = "target/.vpncloud_test";
|
||||
let mut node1 =
|
||||
create_tap_node_with_config(false, Config { beacon_store: Some(beacon_path.to_string()), ..Config::default() });
|
||||
let node1_addr = node1.address().unwrap().0;
|
||||
let node1_addr = node1.address().unwrap();
|
||||
let mut node2 =
|
||||
create_tap_node_with_config(false, Config { beacon_load: Some(beacon_path.to_string()), ..Config::default() });
|
||||
let node2_addr = addr!("2.2.2.2:2222");
|
||||
|
@ -162,7 +162,7 @@ fn lost_init1() {
|
|||
assert_clean!(node1);
|
||||
|
||||
// Node 2 -> Node 1: Init 1 | Node 2 -> Node 1: Peers
|
||||
assert!(node2.socket4().pop_outbound().is_some());
|
||||
assert!(node2.socket().pop_outbound().is_some());
|
||||
assert!(!node1.peers().contains_node(&node2.node_id()));
|
||||
|
||||
simulate!(node1 => node1_addr, node2 => node2_addr);
|
||||
|
|
12
vpncloud.md
12
vpncloud.md
|
@ -38,9 +38,12 @@ vpncloud(1) -- Peer-to-peer VPN
|
|||
peers and ignore them otherwise. The **normal** mode is switch for tap
|
||||
devices and router for tun devices. [default: `normal`]
|
||||
|
||||
* `-l <port>`, `--listen <port>`:
|
||||
* `-l <addr>`, `--listen <addr>`:
|
||||
|
||||
The port number on which to listen for data. [default: `3210`]
|
||||
The address on which to listen for data. This can be simply a port number
|
||||
or a full address in form IP:PORT. If the IP is specified as '*' or only
|
||||
a port number is given, then the socket will listen on all IPs (v4 and v6),
|
||||
otherwise the socket will only listen on the given IP. [default: `3210`]
|
||||
|
||||
* `-c <addr>`, `--connect <addr>`:
|
||||
|
||||
|
@ -311,7 +314,8 @@ detailed descriptions of the options.
|
|||
* `crypto`: The encryption method to use. Same as `--crypto`
|
||||
* `shared_key`: The shared key to encrypt all traffic. Same as `--shared-key`
|
||||
* `magic`: Override the 4-byte magic header of each packet. Same as `--magic`
|
||||
* `port`: The port number on which to listen for data. Same as `--listen`
|
||||
* `port`: A port number to listen on. This option is DEPRECATED.
|
||||
* `listen`: The address on which to listen for data. Same as `--listen`
|
||||
* `peers`: A list of addresses to connect to. See `--connect`
|
||||
* `peer_timeout`: Peer timeout in seconds. Same as`--peer-timeout`
|
||||
* `beacon_store`: Path or command to store beacons. Same as `--beacon-store`
|
||||
|
@ -334,7 +338,7 @@ device_name: vpncloud%d
|
|||
ifup: ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up
|
||||
crypto: aes256
|
||||
shared_key: mysecret
|
||||
port: 3210
|
||||
listen: 3210
|
||||
peers:
|
||||
- remote.machine.foo:3210
|
||||
- remote.machine.bar:3210
|
||||
|
|
Loading…
Reference in New Issue