mirror of https://github.com/dswd/vpncloud.git
Specs
This commit is contained in:
parent
b66e86bddf
commit
90bf0f1c40
|
@ -0,0 +1,104 @@
|
||||||
|
ethcloud(1) -- Layer 2 VPN over UDP
|
||||||
|
===================================
|
||||||
|
|
||||||
|
## SYNOPSIS
|
||||||
|
|
||||||
|
```
|
||||||
|
Usage:
|
||||||
|
ethcloud [options]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-d <device>, --device <device> Name of the tap device [default: ethcloud%d]
|
||||||
|
-l <listen>, --listen <listen> Address to listen on [default: 0.0.0.0:3210]
|
||||||
|
-t <token>, --token <token> Token that identifies the network [default: 0]
|
||||||
|
-c <connect>, --connect <connect> List of peers (addr:port) to connect to
|
||||||
|
--peer-timeout <peer_timeout> Peer timeout in seconds [default: 1800]
|
||||||
|
--mac-timeout <mac_timeout> Mac table entry timeout in seconds [default: 300]
|
||||||
|
-v, --verbose Log verbosely
|
||||||
|
-q, --quiet Only print error messages
|
||||||
|
```
|
||||||
|
|
||||||
|
## DESCRIPTION
|
||||||
|
|
||||||
|
**Ethcloud** is a simple layer 2 VPN over UDP. It creates an ethernet based
|
||||||
|
network interface on the host and forwards all received frames via UDP to the
|
||||||
|
destination.
|
||||||
|
The forwarding is based on traditional switch behavior with MAC address
|
||||||
|
learning. Whenever a frame is received, the sender UDP address and MAC address
|
||||||
|
are associated and used for replies. Frames for unknown addresses will be
|
||||||
|
broadcast to all peers.
|
||||||
|
All connected ethcloud programs will form a peer-to-peer network and
|
||||||
|
cross-connect automatically until the network is fully connected.
|
||||||
|
|
||||||
|
The token is used to distinguish different networks and discard foreign packets.
|
||||||
|
It should be unique.
|
||||||
|
|
||||||
|
Ethcloud does not implement any loop-avoidance. Since data received on the UDP
|
||||||
|
socket will only be sent to the local network interface and vice versa, ethcloud
|
||||||
|
cannot produce loops on its own.
|
||||||
|
|
||||||
|
IEEE 802.1q frames (VLAN tagged) are detected and forwarded based on separate
|
||||||
|
MAC tables. All frames without a tag will be treated as having tag `0`.
|
||||||
|
|
||||||
|
The peer-to-peer protocol will cause nodes to exchange information about their
|
||||||
|
peers. For nodes behind a firewall or a NAT, this can function as hole-punching.
|
||||||
|
|
||||||
|
|
||||||
|
## NETWORK PROTOCOL
|
||||||
|
|
||||||
|
The protocol of `ethcloud` is kept as simple as possible to allow other
|
||||||
|
implementations and to maximize the performance.
|
||||||
|
|
||||||
|
The first 8 bytes of each packet are the token that is used to distinguish
|
||||||
|
different networks and sort out stray packets that do not belong.
|
||||||
|
|
||||||
|
After that, the 9th byte is a switch that determines the structure of the rest
|
||||||
|
of the packet:
|
||||||
|
|
||||||
|
* **Frame packet** (value `0`):
|
||||||
|
This packet contains an actual ethernet frame which starts right after the
|
||||||
|
switch byte and ends at the end of the packet. It contains the main
|
||||||
|
ethernet frame data starting with the destination MAC and ending with the
|
||||||
|
payload. It does not contain the preamble, SFD, padding, and CRC fields.
|
||||||
|
|
||||||
|
* **Peer list** (value `1`):
|
||||||
|
This packet contains the peer list of the sender. The first byte after the
|
||||||
|
switch byte contains the number of IPv4 addresses that follow.
|
||||||
|
After that, the specified number of addresses follow, where each address
|
||||||
|
is encoded in 6 bytes. The first 4 bytes are the IPv4 address and the later
|
||||||
|
2 bytes are port number (both in network byte order).
|
||||||
|
After those addresses, the next byte contains the number of IPv6 addresses
|
||||||
|
that follow. After that, the specified number of addresses follow, where
|
||||||
|
each address is encoded in 18 bytes. The first 16 bytes are the IPv6 address
|
||||||
|
and the later 2 bytes are port number (both in network byte order).
|
||||||
|
|
||||||
|
* **Get peer list** (value `2`):
|
||||||
|
This packet requests that the receiver sends its peer list to the sender.
|
||||||
|
It does not contain any further data.
|
||||||
|
|
||||||
|
* **Close** (value `3`):
|
||||||
|
This packet requests that the receiver removes the sender from its peer list
|
||||||
|
and stops sending data to it. It does not contain any further data.
|
||||||
|
|
||||||
|
Nodes are expected to request the peer list from the initial nodes they are
|
||||||
|
connecting to. After that, they should periodically send their peer list to all
|
||||||
|
of their peers to spread this information and to avoid peer timeouts.
|
||||||
|
To avoid the cubic growth of management traffic, nodes should select a subset of
|
||||||
|
peers and send them a subset of their peer information. A reasonable number
|
||||||
|
would be the square root of the number of peers. The subsets can be selected
|
||||||
|
using round robin (making sure all peers eventually receive all information)
|
||||||
|
or randomly.
|
||||||
|
|
||||||
|
Nodes should remove peers from their peer list after a certain period of
|
||||||
|
inactivity or when receiving a `Close` message. Before shutting down, nodes
|
||||||
|
should send the `Close` message to all of their peers in order to avoid
|
||||||
|
receiving further data until the timeout is reached.
|
||||||
|
|
||||||
|
Nodes should only add nodes to their peer list after receiving a message from
|
||||||
|
them instead of adding them right from the peer list of another peer. This
|
||||||
|
is necessary to avoid the case of a large network keeping dead nodes alive
|
||||||
|
|
||||||
|
|
||||||
|
## COPYRIGHT
|
||||||
|
|
||||||
|
Copyright (C) 2015 Dennis Schwerdel
|
|
@ -319,7 +319,7 @@ impl EthCloud {
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(e) => error!("Error: {:?}", e)
|
Err(e) => error!("Error: {:?}", e)
|
||||||
}
|
}
|
||||||
thread::sleep(StdDuration::new(1, 0));
|
thread::sleep(StdDuration::new(10, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ use ethcloud::{Error, Token, EthCloud};
|
||||||
//TODO: Implement IPv6
|
//TODO: Implement IPv6
|
||||||
//TODO: Encryption
|
//TODO: Encryption
|
||||||
//TODO: Call close
|
//TODO: Call close
|
||||||
|
//TODO: Reconnect to peers given on command line
|
||||||
|
|
||||||
|
|
||||||
struct SimpleLogger;
|
struct SimpleLogger;
|
||||||
|
@ -46,8 +47,8 @@ Options:
|
||||||
-l <listen>, --listen <listen> Address to listen on [default: 0.0.0.0:3210]
|
-l <listen>, --listen <listen> Address to listen on [default: 0.0.0.0:3210]
|
||||||
-t <token>, --token <token> Token that identifies the network [default: 0]
|
-t <token>, --token <token> Token that identifies the network [default: 0]
|
||||||
-c <connect>, --connect <connect> List of peers (addr:port) to connect to
|
-c <connect>, --connect <connect> List of peers (addr:port) to connect to
|
||||||
--peer-timeout <peer_timeout> Peer timeout in seconds [default: 300]
|
--peer-timeout <peer_timeout> Peer timeout in seconds [default: 1800]
|
||||||
--mac-timeout <mac_timeout> Mac table entry timeout in seconds [default: 60]
|
--mac-timeout <mac_timeout> Mac table entry timeout in seconds [default: 300]
|
||||||
-v, --verbose Log verbosely
|
-v, --verbose Log verbosely
|
||||||
-q, --quiet Only print error messages
|
-q, --quiet Only print error messages
|
||||||
";
|
";
|
||||||
|
|
|
@ -118,6 +118,8 @@ pub fn encode(token: Token, msg: &Message, buf: &mut [u8]) -> usize {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
buf[count_pos] = count;
|
buf[count_pos] = count;
|
||||||
|
buf[pos] = 0;
|
||||||
|
pos += 1;
|
||||||
},
|
},
|
||||||
&Message::GetPeers => {
|
&Message::GetPeers => {
|
||||||
buf[pos] = 2;
|
buf[pos] = 2;
|
||||||
|
@ -156,8 +158,8 @@ fn encode_message_peers() {
|
||||||
let msg = Message::Peers(vec![SocketAddr::from_str("1.2.3.4:123").unwrap(), SocketAddr::from_str("5.6.7.8:12345").unwrap()]);
|
let msg = Message::Peers(vec![SocketAddr::from_str("1.2.3.4:123").unwrap(), SocketAddr::from_str("5.6.7.8:12345").unwrap()]);
|
||||||
let mut buf = [0; 1024];
|
let mut buf = [0; 1024];
|
||||||
let size = encode(token, &msg, &mut buf[..]);
|
let size = encode(token, &msg, &mut buf[..]);
|
||||||
assert_eq!(size, 22);
|
assert_eq!(size, 23);
|
||||||
assert_eq!(&buf[..size], &[0,0,0,0,0,0,0,134,1,2,1,2,3,4,0,123,5,6,7,8,48,57]);
|
assert_eq!(&buf[..size], &[0,0,0,0,0,0,0,134,1,2,1,2,3,4,0,123,5,6,7,8,48,57,0]);
|
||||||
let (token2, msg2) = decode(&buf[..size]).unwrap();
|
let (token2, msg2) = decode(&buf[..size]).unwrap();
|
||||||
assert_eq!(token, token2);
|
assert_eq!(token, token2);
|
||||||
assert_eq!(msg, msg2);
|
assert_eq!(msg, msg2);
|
||||||
|
|
Loading…
Reference in New Issue