mirror of
https://github.com/dndx/phantun.git
synced 2025-09-16 04:04:29 +08:00
Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
494abf37c5 | ||
|
cab87bd75b | ||
|
042f5af49f | ||
|
f667f56747 | ||
|
49665b906f | ||
|
e9cde27923 | ||
|
cf588db042 | ||
|
0e27822995 | ||
|
eeca1d0108 | ||
|
35541df7e2 | ||
|
3219cb9f38 | ||
|
41e86521b7 | ||
|
427fb7c19a |
12
.github/dependabot.yml
vendored
Normal file
12
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
version: 2
|
||||
updates:
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
|
||||
- package-ecosystem: "cargo"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
7
.github/workflows/release.yml
vendored
7
.github/workflows/release.yml
vendored
@@ -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
|
||||
|
3
.github/workflows/rust.yml
vendored
3
.github/workflows/rust.yml
vendored
@@ -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
|
||||
|
21
README.md
21
README.md
@@ -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)
|
||||
|
||||
|
@@ -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"
|
||||
|
@@ -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;
|
||||
|
@@ -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());
|
||||
|
@@ -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"
|
||||
|
@@ -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
|
||||
|
@@ -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 {
|
||||
|
Reference in New Issue
Block a user