Add listen option, switched to dual-stack

This commit is contained in:
Dennis Schwerdel 2020-02-20 16:25:35 +01:00
parent fba72882a6
commit 390f217a23
12 changed files with 102 additions and 151 deletions

View File

@ -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)

View File

@ -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;
}

View File

@ -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) {

View File

@ -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(),

View File

@ -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) => {

View File

@ -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() {

View File

@ -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 {

View File

@ -13,8 +13,7 @@ use std::io;
pub enum WaitResult {
Timeout,
SocketV4,
SocketV6,
Socket,
Device,
Error(io::Error)
}

View File

@ -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);
};
}

View File

@ -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
}
}

View File

@ -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);

View File

@ -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