Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ env:
jobs:
build:

runs-on: ubuntu-latest
strategy:
matrix:
os: [ubuntu-latest, macos-latest]

runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v5
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

71 changes: 70 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,22 @@ A lightweight and fast UDP to TCP obfuscator.
* [Overview](#overview)
* [Usage](#usage)
* [1. Enable Kernel IP forwarding](#1-enable-kernel-ip-forwarding)
* [On Linux](#on-linux)
* [On macOS](#on-macos)
* [2. Add required firewall rules](#2-add-required-firewall-rules)
* [Client](#client)
* [Using nftables](#using-nftables)
* [Using iptables](#using-iptables)
* [Using pf (macOS)](#using-pf-macos)
* [Server](#server)
* [Using nftables](#using-nftables)
* [Using iptables](#using-iptables)
* [Using pf (macOS)](#using-pf-macos)
* [3. Run Phantun binaries as non-root (Optional)](#3-run-phantun-binaries-as-non-root-optional)
* [4. Start Phantun daemon](#4-start-phantun-daemon)
* [Server](#server)
* [Client](#client)
* [macOS](#macos)
* [MTU overhead](#mtu-overhead)
* [MTU calculation for WireGuard](#mtu-calculation-for-wireguard)
* [Version compatibility](#version-compatibility)
Expand Down Expand Up @@ -82,7 +87,9 @@ Phantun creates TUN interface for both the Client and Server. For **Client**, Ph
`192.168.200.2` and `fcc8::2` by default.
For **Server**, it assigns `192.168.201.2` and `fcc9::2` by default. Therefore, your Kernel must have
IPv4/IPv6 forwarding enabled and setup appropriate iptables/nftables rules for NAT between your physical
NIC address and Phantun's Tun interface address.
NIC address and Phantun's Tun interface address. On macOS the same applies, with `sysctl(8)`
and `pf(4)` in place of `sysctl.conf` and `iptables`: see
[step 1](#1-enable-kernel-ip-forwarding) and [step 2](#2-add-required-firewall-rules).

You may customize the name of Tun interface created by Phantun and the assigned addresses. Please
run the executable with `-h` options to see how to change them.
Expand All @@ -109,6 +116,8 @@ with `-h` to see detailed options on how to control the IPv6 behavior.

## 1. Enable Kernel IP forwarding

### On Linux

Edit `/etc/sysctl.conf`, add `net.ipv4.ip_forward=1` and run `sudo sysctl -p /etc/sysctl.conf`.

<details>
Expand All @@ -119,6 +128,22 @@ Edit `/etc/sysctl.conf`, add `net.ipv4.ip_forward=1` and run `sudo sysctl -p /et

[Back to TOC](#table-of-contents)

### On macOS

`sysctl(8)` applies the setting immediately, `/etc/sysctl.conf` at the next boot:

```
sudo sysctl -w net.inet.ip.forwarding=1
```

<details>
<summary>IPv6 specific config</summary>

`sudo sysctl -w net.inet6.ip6.forwarding=1` will need to be set as well.
</details>

[Back to TOC](#table-of-contents)

## 2. Add required firewall rules


Expand Down Expand Up @@ -156,6 +181,22 @@ ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

[Back to TOC](#table-of-contents)

#### Using pf (macOS)

With `pf(4)`, SNAT is written as `nat`. Add the rules below to `/etc/pf.conf`, changing `en0`
to whatever actual physical interface name is, and load them with `sudo pfctl -f /etc/pf.conf`.

`pf` requires translation rules to come before filtering ones, so insert them after the
`nat-anchor`/`rdr-anchor` lines instead of appending them at the end of the file, which fails
with `Rules must be in order`. `sudo pfctl -n -f /etc/pf.conf` checks the file without loading it.

```
nat on en0 inet from any to any -> (en0)
nat on en0 inet6 from any to any -> (en0)
```

[Back to TOC](#table-of-contents)

### Server

Server needs to DNAT the TCP listening port to Phantun's TUN interface address.
Expand Down Expand Up @@ -188,6 +229,19 @@ ip6tables -t nat -A PREROUTING -p tcp -i eth0 --dport 4567 -j DNAT --to-destinat

[Back to TOC](#table-of-contents)

#### Using pf (macOS)

With `pf(4)`, DNAT is written as `rdr`. Add the rules below to `/etc/pf.conf`, changing `en0`
to whatever actual physical interface name is, and load them with `sudo pfctl -f /etc/pf.conf`.
See the [Client](#using-pf-macos) rules above for where in the file they belong.

```
rdr on en0 inet proto tcp to port 4567 -> 192.168.201.2 port 4567
rdr on en0 inet6 proto tcp to port 4567 -> fcc9::2 port 4567
```

[Back to TOC](#table-of-contents)

## 3. Run Phantun binaries as non-root (Optional)

It is ill-advised to run network facing applications as root user. Phantun can be run fully
Expand Down Expand Up @@ -255,6 +309,21 @@ RUST_LOG=info /usr/local/bin/phantun_client --local 127.0.0.1:1234 --remote exam

[Back to TOC](#table-of-contents)

# macOS

Phantun supports macOS by using the `utun(4)` driver in place of Linux's TUN device. The usage
steps above apply, with the following differences:

* Creating a `utun` interface requires root and macOS has no equivalent of `cap_net_admin`, so
run the binaries with `sudo` and skip [step 3](#3-run-phantun-binaries-as-non-root-optional).
* The interface is called `utunN`, use `--tun utun4` to pin a specific unit. If that unit is
already taken, Phantun fails to start instead of picking another one.
* macOS refuses to connect a second `SO_REUSEPORT` socket to a peer that another one is
already connected to (`EADDRINUSE`), so a connection gets a single fastpath worker
instead of one per core.

[Back to TOC](#table-of-contents)

# MTU overhead

Phantun aims to keep tunneling overhead to the minimum. The overhead compared to a plain UDP packet
Expand Down
7 changes: 6 additions & 1 deletion fake-tcp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@ bytes = "1"
pnet = "0"
rand = { version = "0", features = ["small_rng"] }
internet-checksum = "0"
tokio-tun = "0"
flume = "0"
tokio = { workspace = true }
log = { workspace = true }

[target.'cfg(not(target_os = "macos"))'.dependencies]
tokio-tun = "0"

[target.'cfg(target_os = "macos")'.dependencies]
libc = "0.2"
7 changes: 4 additions & 3 deletions fake-tcp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#![cfg_attr(feature = "benchmark", feature(test))]

pub mod packet;
pub mod tun;

use bytes::{Bytes, BytesMut};
use log::{error, info, trace, warn};
Expand All @@ -57,7 +58,7 @@ use std::sync::{
use tokio::sync::broadcast;
use tokio::sync::mpsc;
use tokio::time;
use tokio_tun::Tun;
use tun::Tun;

const TIMEOUT: time::Duration = time::Duration::from_secs(1);
const RETRIES: usize = 6;
Expand Down Expand Up @@ -357,8 +358,8 @@ impl fmt::Display for Socket {

/// A userspace TCP state machine
impl Stack {
/// Create a new stack, `tun` is an array of [`Tun`](tokio_tun::Tun).
/// When more than one [`Tun`](tokio_tun::Tun) object is passed in, same amount
/// Create a new stack, `tun` is an array of [`Tun`](crate::tun::Tun).
/// When more than one [`Tun`](crate::tun::Tun) object is passed in, same amount
/// of reader will be spawned later. This allows user to utilize the performance
/// benefit of Multiqueue Tun support on machines with SMP.
pub fn new(tun: Vec<Tun>, local_ip: Ipv4Addr, local_ip6: Option<Ipv6Addr>) -> Stack {
Expand Down
Loading