13 Commits

Author SHA1 Message Date
Datong Sun
494abf37c5 docs(readme) add IPv6 support info 2021-10-30 09:21:23 -07:00
Datong Sun
cab87bd75b chore(cargo) bump Phantun to v0.2.2 2021-10-30 09:15:23 -07:00
Datong Sun
042f5af49f feat(phantun) add support for connecting to/from IPv6 based UDP endpoint 2021-10-31 00:09:02 +08:00
Datong Sun
f667f56747 chore(actions) always use the latest stable toolchain 2021-10-21 03:47:57 -07:00
Datong Sun
49665b906f chore(cargo) use Rust edition 2021 2021-10-21 03:41:42 -07:00
Datong Sun
e9cde27923 ci(dependabot) add Dependabot checks 2021-10-20 02:07:05 -07:00
Datong Sun
cf588db042 ci(release) add musl libc targets 2021-10-19 01:13:56 -07:00
Datong Sun
0e27822995 docs(readme) update WireGuard MTU calculation to take into account for
padding truncation
2021-10-16 10:55:01 -07:00
Datong Sun
eeca1d0108 docs(readme) bump latest release version to v0.2.1 2021-10-12 07:26:49 -07:00
Datong Sun
35541df7e2 chore(phantun) bump version to v0.2.1, bump fake-tcp dependency to v0.1.2 2021-10-09 09:33:16 -07:00
Datong Sun
3219cb9f38 chore(fake-tcp) bump version to 0.1.2 2021-10-09 09:31:55 -07:00
Datong Sun
41e86521b7 fix(fake-tcp) more robust checking for receiving end closing, avoids
panicking tasks from causing server to stop completely
2021-10-10 00:29:28 +08:00
Datong Sun
427fb7c19a fix(fake-tcp) use 64 as TTL value, fixes #11 2021-10-09 23:57:47 +08:00
10 changed files with 70 additions and 28 deletions

12
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "cargo"
directory: "/"
schedule:
interval: "daily"

View File

@@ -16,12 +16,19 @@ jobs:
matrix:
target:
- x86_64-unknown-linux-gnu
- x86_64-unknown-linux-musl
- i686-unknown-linux-gnu
- i686-unknown-linux-musl
- armv7-unknown-linux-gnueabihf
- armv7-unknown-linux-musleabihf
- arm-unknown-linux-gnueabihf
- arm-unknown-linux-musleabihf
- aarch64-unknown-linux-gnu
- aarch64-unknown-linux-musl
- mips-unknown-linux-gnu
- mips-unknown-linux-musl
- mipsel-unknown-linux-gnu
- mipsel-unknown-linux-musl
steps:
- uses: actions/checkout@v2

View File

@@ -12,6 +12,9 @@ jobs:
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Run lint
run: cargo clippy --verbose
- name: Build

View File

@@ -31,7 +31,7 @@ Table of Contents
# Latest release
[v0.1.1](https://github.com/dndx/phantun/releases/tag/v0.1.1)
[v0.2.1](https://github.com/dndx/phantun/releases/tag/v0.2.1)
# Overview
@@ -84,6 +84,10 @@ and change the destination IP address to where the server is listening for incom
In those cases, the machine/iptables running Phantun acts as the "router" that allows Phantun
to communicate with outside using it's private IP addresses.
As of Phantun v0.2.2, IPv6 support for UDP endpoints has been added, however Fake TCP IPv6 support
has not been finished yet. To specify an IPv6 address, use the following format: `[::1]:1234` with
the command line options.
[Back to TOC](#table-of-contents)
## 1. Enable Kernel IP forwarding
@@ -218,18 +222,13 @@ of obfuscation.
For people who use Phantun to tunnel [WireGuard®](https://www.wireguard.com) UDP packets, here are some guidelines on figuring
out the correct MTU to use for your WireGuard interface.
WireGuard MTU = `MAX_OF_16`(Interface MTU - IP header (20 bytes) - TCP header (20 bytes) - WireGuard overhead (32 bytes))
Where:
`MAX_OF_16` takes an input integer and calculates the maximum multiple of 16 not exceeding the input. This
is needed because WireGuard will always pad it's payloads to multiple of 16 bytes.
WireGuard MTU = Interface MTU - IP header (20 bytes) - TCP header (20 bytes) - WireGuard overhead (32 bytes)
For example, for a Ethernet interface with 1500 bytes MTU, the WireGuard interface MTU should be set as:
`MAX_OF_16`(1500 - 20 - 20 - 32) = 1424 bytes
1500 - 20 - 20 - 32 = 1428 bytes
The resulted Phantun TCP data packet will be 1424 + 20 + 20 + 32 = 1496 bytes which does not exceed the
The resulted Phantun TCP data packet will be 1500 bytes which does not exceed the
interface MTU of 1500.
[Back to TOC](#table-of-contents)
@@ -255,7 +254,7 @@ for tunneling TCP/UDP traffic between two test instances and MTU has been tuned
# Future plans
* IPv6 support
* IPv6 support for fake-tcp
* Load balancing a single UDP stream into multiple TCP streams
* Integration tests
* Auto insertion/removal of required firewall rules
@@ -283,7 +282,7 @@ Here is a quick overview of comparison between those two to help you choose:
| Tunneling MTU overhead | 12 bytes | 44 bytes |
| Seprate TCP connections for each UDP connection | Client/Server | Server only |
| Anti-replay, encryption | ❌ | ✅ |
| IPv6 | Planned | ✅ |
| IPv6 | UDP only | ✅ |
[Back to TOC](#table-of-contents)

View File

@@ -1,7 +1,7 @@
[package]
name = "fake-tcp"
version = "0.1.1"
edition = "2018"
version = "0.1.2"
edition = "2021"
authors = ["Datong Sun <dndx@idndx.com>"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/dndx/phantun"

View File

@@ -385,9 +385,15 @@ impl Stack {
let tuple = AddrTuple::new(local_addr, remote_addr);
if let Some(c) = tuples.get(&tuple) {
c.send(buf).await.unwrap();
if c.send(buf).await.is_err() {
trace!("Cache hit, but receiver already closed, dropping packet");
}
continue;
// If not Ok, receiver has been closed and just fall through to the slow
// path below
} else {
trace!("Cache miss, checking the shared tuples table for connection");
let sender;

View File

@@ -32,7 +32,7 @@ pub fn build_tcp_packet(
v4.set_version(4);
v4.set_header_length(IPV4_HEADER_LEN as u8 / 4);
v4.set_next_level_protocol(ip::IpNextHeaderProtocols::Tcp);
v4.set_ttl(32);
v4.set_ttl(64);
v4.set_source(*local_addr.ip());
v4.set_destination(*remote_addr.ip());
v4.set_total_length(total_len.try_into().unwrap());

View File

@@ -1,7 +1,7 @@
[package]
name = "phantun"
version = "0.2.0"
edition = "2018"
version = "0.2.2"
edition = "2021"
authors = ["Datong Sun <dndx@idndx.com>"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/dndx/phantun"
@@ -13,7 +13,7 @@ Layer 3 & Layer 4 (NAPT) firewalls/NATs.
[dependencies]
clap = "2.33.3"
socket2 = { version = "0.4.2", features = ["all"] }
fake-tcp = "0.1.1"
fake-tcp = "0.1.2"
tokio = { version = "1.12.0", features = ["full"] }
log = "0.4"
pretty_env_logger = "0.4.0"

View File

@@ -16,8 +16,17 @@ use tokio_tun::TunBuilder;
const UDP_TTL: Duration = Duration::from_secs(180);
fn new_udp_reuseport(addr: SocketAddrV4) -> UdpSocket {
let udp_sock = socket2::Socket::new(socket2::Domain::IPV4, socket2::Type::DGRAM, None).unwrap();
fn new_udp_reuseport(addr: SocketAddr) -> UdpSocket {
let udp_sock = socket2::Socket::new(
if addr.is_ipv4() {
socket2::Domain::IPV4
} else {
socket2::Domain::IPV6
},
socket2::Type::DGRAM,
None,
)
.unwrap();
udp_sock.set_reuse_port(true).unwrap();
// from tokio-rs/mio/blob/master/src/sys/unix/net.rs
udp_sock.set_cloexec(true).unwrap();
@@ -40,7 +49,7 @@ async fn main() {
.long("local")
.required(true)
.value_name("IP:PORT")
.help("Sets the IP and port where Phantun Client listens for incoming UDP datagrams")
.help("Sets the IP and port where Phantun Client listens for incoming UDP datagrams, IPv6 address need to be specified as: \"[IPv6]:PORT\"")
.takes_value(true),
)
.arg(
@@ -83,7 +92,7 @@ async fn main() {
)
.get_matches();
let local_addr: SocketAddrV4 = matches
let local_addr: SocketAddr = matches
.value_of("local")
.unwrap()
.parse()
@@ -117,7 +126,7 @@ async fn main() {
info!("Created TUN device {}", tun[0].name());
let udp_sock = Arc::new(new_udp_reuseport(local_addr));
let connections = Arc::new(RwLock::new(HashMap::<SocketAddrV4, Arc<Socket>>::new()));
let connections = Arc::new(RwLock::new(HashMap::<SocketAddr, Arc<Socket>>::new()));
let mut stack = Stack::new(tun);
@@ -126,7 +135,7 @@ async fn main() {
loop {
tokio::select! {
Ok((size, SocketAddr::V4(addr))) = udp_sock.recv_from(&mut buf_r) => {
Ok((size, addr)) = udp_sock.recv_from(&mut buf_r) => {
// seen UDP packet to listening socket, this means:
// 1. It is a new UDP connection, or
// 2. It is some extra packets not filtered by more specific

View File

@@ -4,7 +4,7 @@ use clap::{crate_version, App, Arg};
use fake_tcp::packet::MAX_PACKET_LEN;
use fake_tcp::Stack;
use log::{error, info};
use std::net::{Ipv4Addr, SocketAddrV4};
use std::net::{Ipv4Addr, SocketAddr};
use tokio::net::UdpSocket;
use tokio::time::{self, Duration};
use tokio_tun::TunBuilder;
@@ -32,7 +32,7 @@ async fn main() {
.long("remote")
.required(true)
.value_name("IP:PORT")
.help("Sets the address and port where Phantun Server forwards UDP packets to")
.help("Sets the address and port where Phantun Server forwards UDP packets to, IPv6 address need to be specified as: \"[IPv6]:PORT\"")
.takes_value(true),
)
.arg(
@@ -71,7 +71,7 @@ async fn main() {
.unwrap()
.parse()
.expect("bad local port");
let remote_addr: SocketAddrV4 = matches
let remote_addr: SocketAddr = matches
.value_of("remote")
.unwrap()
.parse()
@@ -113,7 +113,13 @@ async fn main() {
info!("New connection: {}", sock);
tokio::spawn(async move {
let udp_sock = UdpSocket::bind("0.0.0.0:0").await.unwrap();
let udp_sock = UdpSocket::bind(if remote_addr.is_ipv4() {
"0.0.0.0:0"
} else {
"[::]:0"
})
.await
.unwrap();
udp_sock.connect(remote_addr).await.unwrap();
loop {