Listening on ipv4 and ipv6

pull/9/head
Dennis Schwerdel 2016-05-02 08:35:11 +02:00
parent cd2259c09d
commit 2f2f7b725f
8 changed files with 122 additions and 53 deletions

View File

@ -4,7 +4,9 @@ This project follows [semantic versioning](http://semver.org).
### Unreleased
- [changed] Using SO_REUSEADDR to allow frequent rebinding
- [changed] Building and using local libsodium library automatically
- [changed] Updated dependencies
### v0.5.0 (2016-04-05)

91
Cargo.lock generated
View File

@ -3,23 +3,24 @@ name = "vpncloud"
version = "0.5.0"
dependencies = [
"aligned_alloc 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"docopt 0.6.78 (registry+https://github.com/rust-lang/crates.io-index)",
"docopt 0.6.80 (registry+https://github.com/rust-lang/crates.io-index)",
"epoll 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"signal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"signal 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "aho-corasick"
version = "0.5.1"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
@ -30,8 +31,8 @@ name = "aligned_alloc"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -45,12 +46,17 @@ name = "bitflags"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cfg-if"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "docopt"
version = "0.6.78"
version = "0.6.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"regex 0.1.62 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.1.69 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -61,7 +67,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"errno 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -69,8 +75,8 @@ name = "errno"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -81,12 +87,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "gcc"
version = "0.3.26"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "kernel32-sys"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -100,7 +106,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.9"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -113,13 +119,20 @@ name = "memchr"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mempool"
version = "0.3.0"
name = "net2"
version = "0.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nix"
@ -136,7 +149,7 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -149,18 +162,18 @@ name = "rand"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "0.1.62"
version = "0.1.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"mempool 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -176,7 +189,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "signal"
version = "0.1.3"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
@ -189,13 +202,30 @@ name = "strsim"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "thread-id"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "time"
version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -214,3 +244,12 @@ name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ws2_32-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

View File

@ -16,12 +16,13 @@ docopt = "0.6"
rustc-serialize = "0.3"
log = "0.3"
epoll = "0.3"
signal = "0.1"
signal = ">=0.1.4"
nix = "0.5"
libc = "0.2"
aligned_alloc = "0.1"
rand = "0.3"
fnv = "1"
net2 = "*"
[build-dependencies]
gcc = "0.3"

View File

@ -20,15 +20,13 @@ VpnCloud version: `VpnCloud v0.5.0, protocol version 1, libsodium 1.0.10 (AES256
The sender runs the following command:
```
$> ./vpncloud -t tap -l SENDER:3210 -c RECEIVER:3210 \
--ifup 'ifconfig $IFNAME 10.2.1.1/24 mtu 1400 up' &
$> ./vpncloud -t tap -l 3210 -c RECEIVER:3210 --ifup 'ifconfig $IFNAME 10.0.0.1/24 mtu 1400 up' &
```
and the receiver runs:
```
$> ./vpncloud -t tap -l RECEIVER:3210 -c SENDER:3210 \
--ifup 'ifconfig $IFNAME 10.2.1.2/24 mtu 1400 up' &
$> ./vpncloud -t tap -l 3210 -c SENDER:3210 --ifup 'ifconfig $IFNAME 10.0.0.2/24 mtu 1400 up' &
$> iperf -s &
$> top
```

View File

@ -2,8 +2,8 @@
// Copyright (C) 2015-2016 Dennis Schwerdel
// This software is licensed under GPL-3 or newer (see LICENSE.md)
use std::net::{SocketAddr, ToSocketAddrs};
use std::collections::HashMap;
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
use std::collections::{HashSet, HashMap};
use std::hash::Hasher;
use std::net::UdpSocket;
use std::io::Read;
@ -19,6 +19,7 @@ use nix::sys::signal::{SIGTERM, SIGQUIT, SIGINT};
use signal::trap::Trap;
use time::SteadyTime;
use rand::{random, sample, thread_rng};
use net2::UdpBuilder;
use super::types::{Table, Protocol, Range, Error, NetworkId, NodeId};
use super::device::Device;
@ -98,7 +99,8 @@ pub struct GenericCloud<P: Protocol> {
reconnect_peers: Vec<SocketAddr>,
blacklist_peers: Vec<SocketAddr>,
table: Box<Table>,
socket: UdpSocket,
socket4: UdpSocket,
socket6: UdpSocket,
device: Device,
options: Options,
crypto: Crypto,
@ -110,12 +112,19 @@ pub struct GenericCloud<P: Protocol> {
}
impl<P: Protocol> GenericCloud<P> {
pub fn new(device: Device, listen: &str, network_id: Option<NetworkId>, table: Box<Table>,
pub fn new(device: Device, listen: u16, network_id: Option<NetworkId>, table: Box<Table>,
peer_timeout: Duration, learning: bool, broadcast: bool, addresses: Vec<Range>,
crypto: Crypto) -> Self {
let socket = match UdpSocket::bind(listen) {
let socket4 = match UdpBuilder::new_v4().expect("Failed to obtain ipv4 socket builder")
.reuse_address(true).expect("Failed to set so_reuseaddr").bind(("0.0.0.0", listen)) {
Ok(socket) => socket,
_ => fail!("Failed to open socket {}", listen)
Err(err) => fail!("Failed to open ipv4 address 0.0.0.0:{}: {}", listen, err)
};
let socket6 = match UdpBuilder::new_v6().expect("Failed to obtain ipv6 socket builder")
.only_v6(true).expect("Failed to set only_v6")
.reuse_address(true).expect("Failed to set so_reuseaddr").bind(("::", listen)) {
Ok(socket) => socket,
Err(err) => fail!("Failed to open ipv6 address ::{}: {}", listen, err)
};
let mut options = Options::default();
options.network_id = network_id;
@ -128,7 +137,8 @@ impl<P: Protocol> GenericCloud<P> {
reconnect_peers: Vec::new(),
blacklist_peers: Vec::new(),
table: table,
socket: socket,
socket4: socket4,
socket6: socket6,
device: device,
options: options,
crypto: crypto,
@ -150,7 +160,11 @@ impl<P: Protocol> GenericCloud<P> {
debug!("Broadcasting {:?}", msg);
let msg_data = encode(&mut self.options, msg, &mut self.buffer_out, &mut self.crypto);
for addr in &self.peers.as_vec() {
try!(match self.socket.send_to(msg_data, addr) {
let socket = match addr {
&SocketAddr::V4(_) => &self.socket4,
&SocketAddr::V6(_) => &self.socket6
};
try!(match socket.send_to(msg_data, addr) {
Ok(written) if written == msg_data.len() => Ok(()),
Ok(_) => Err(Error::SocketError("Sent out truncated packet")),
Err(e) => {
@ -166,7 +180,11 @@ impl<P: Protocol> GenericCloud<P> {
fn send_msg(&mut self, addr: SocketAddr, msg: &mut Message) -> Result<(), Error> {
debug!("Sending {:?} to {}", msg, addr);
let msg_data = encode(&mut self.options, msg, &mut self.buffer_out, &mut self.crypto);
match self.socket.send_to(msg_data, addr) {
let socket = match &addr {
&SocketAddr::V4(_) => &self.socket4,
&SocketAddr::V6(_) => &self.socket6
};
match socket.send_to(msg_data, addr) {
Ok(written) if written == msg_data.len() => Ok(()),
Ok(_) => Err(Error::SocketError("Sent out truncated packet")),
Err(e) => {
@ -177,8 +195,8 @@ impl<P: Protocol> GenericCloud<P> {
}
#[allow(dead_code)]
pub fn address(&self) -> IoResult<SocketAddr> {
self.socket.local_addr()
pub fn address(&self) -> IoResult<(SocketAddr, SocketAddr)> {
Ok((try!(self.socket4.local_addr()), try!(self.socket6.local_addr())))
}
#[allow(dead_code)]
@ -325,11 +343,14 @@ impl<P: Protocol> GenericCloud<P> {
let dummy_time = SteadyTime::now();
let trap = Trap::trap(&[SIGINT, SIGTERM, SIGQUIT]);
let epoll_handle = try_fail!(epoll::create1(0), "Failed to create epoll handle: {}");
let socket_fd = self.socket.as_raw_fd();
let socket4_fd = self.socket4.as_raw_fd();
let socket6_fd = self.socket6.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};
try_fail!(epoll::ctl(epoll_handle, epoll::util::ctl_op::ADD, socket_fd, &mut socket_event), "Failed to add socket to epoll handle: {}");
let mut socket4_event = epoll::EpollEvent{events: epoll::util::event_type::EPOLLIN, data: 0};
let mut socket6_event = epoll::EpollEvent{events: epoll::util::event_type::EPOLLIN, data: 1};
let mut device_event = epoll::EpollEvent{events: epoll::util::event_type::EPOLLIN, data: 2};
try_fail!(epoll::ctl(epoll_handle, epoll::util::ctl_op::ADD, socket4_fd, &mut socket4_event), "Failed to add ipv4 socket to epoll handle: {}");
try_fail!(epoll::ctl(epoll_handle, epoll::util::ctl_op::ADD, socket6_fd, &mut socket6_event), "Failed to add ipv6 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];
@ -339,13 +360,20 @@ impl<P: Protocol> GenericCloud<P> {
for i in 0..count {
match &events[i].data {
&0 => {
let (size, src) = try_fail!(self.socket.recv_from(&mut buffer), "Failed to read from network socket: {}");
let (size, src) = try_fail!(self.socket4.recv_from(&mut buffer), "Failed to read from ipv4 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: {}, from: {}", e, src)
}
},
&1 => {
let (size, src) = try_fail!(self.socket6.recv_from(&mut buffer), "Failed to read from ipv6 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: {}, from: {}", e, src)
}
},
&2 => {
let start = 64;
let size = try_fail!(self.device.read(&mut buffer[start..]), "Failed to read from tap device: {}");
match self.handle_interface_data(&mut buffer, start, start+size) {

View File

@ -14,6 +14,7 @@ extern crate libc;
extern crate aligned_alloc;
extern crate rand;
extern crate fnv;
extern crate net2;
#[cfg(feature = "bench")] extern crate test;
#[macro_use] mod util;
@ -69,7 +70,7 @@ struct Args {
flag_crypto: CryptoMethod,
flag_subnet: Vec<String>,
flag_device: String,
flag_listen: String,
flag_listen: u16,
flag_network_id: Option<String>,
flag_connect: Vec<String>,
flag_peer_timeout: Duration,
@ -123,7 +124,7 @@ fn run<T: Protocol> (args: Args) {
Some(key) => Crypto::from_shared_key(args.flag_crypto, &key),
None => Crypto::None
};
let mut cloud = GenericCloud::<T>::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());
}

View File

@ -8,8 +8,8 @@ Options:
[default: vpncloud%d]
-m <mode>, --mode <mode> The mode of the VPN ("hub", "switch",
"router", or "normal"). [default: normal]
-l <addr>, --listen <addr> The address to listen for data.
[default: 0.0.0.0:3210]
-l <port>, --listen <port> The port number on which to listen for data.
[default: 3210]
-c <addr>, --connect <addr> Address of a peer to connect to.
--subnet <subnet> The local subnets to use.
--network-id <id> Optional token that identifies the network.

View File

@ -27,9 +27,9 @@ 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 <addr>`, `--listen <addr>`:
* `-l <port>`, `--listen <port>`:
The address to listen for data. [default: `0.0.0.0:3210`]
The port number on which to listen for data. [default: `3210`]
* `-c <addr>`, `--connect <addr>`: