Compare commits

...

57 Commits
v0.4.1 ... main

Author SHA1 Message Date
Datong Sun
869c79422f chore(cargo): add Cargo.lock. Closes #138
Some checks failed
Docker image build / build (push) Has been cancelled
Rust / build (push) Has been cancelled
2025-03-14 22:46:01 -07:00
Datong Sun
201da45ee8 style(fake-tcp): fix warnings 2025-03-14 22:45:24 -07:00
SH Weng
333c6dd059
fix(deps): support newer version of rand crate
Closes #186.
2025-03-15 15:38:13 +08:00
Datong Sun
62f0278c1a fix(phantun): fix tokio-tun incompatiable API change
Some checks failed
Docker image build / build (push) Has been cancelled
Rust / build (push) Has been cancelled
2025-01-02 21:52:56 +08:00
Meng Zhuo
f436325d23
docs(README): fix typo
Some checks failed
Rust / build (push) Has been cancelled
2024-12-29 19:01:26 +08:00
Datong Sun
028a32d197
docs(readme): latest release is now v0.7.0
Some checks failed
Docker image build / build (push) Has been cancelled
Rust / build (push) Has been cancelled
2024-11-22 01:31:25 +08:00
Datong Sun
e452e40edd chore(release): remove MIPS targets due to being downgraded to Tier 3
support by Rust
2024-11-21 09:27:19 -08:00
dependabot[bot]
253ce54554 chore(deps): bump docker/build-push-action from 5 to 6
Some checks are pending
Docker image build / build (push) Waiting to run
Rust / build (push) Waiting to run
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5 to 6.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v5...v6)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-20 23:12:10 +08:00
Datong Sun
34d2350d1c chore(cargo): bump fake-tcp version to 0.6.0 and phantun to
`0.7.0`
2024-11-20 23:06:36 +08:00
Datong Sun
6955a1eb4c chore(deps): bump dependencies to latest 2024-11-20 23:06:36 +08:00
Datong Sun
e86c5c5c50
fix(fake-tcp): when connect()-ing, attempt to get ephemeral port using algorithm similar to Linux (#162)
* fix(fake-tcp): when `connect()`-ing, attempt to get ephemeral port 5 times to reduce the chance
of panicking

Fixes #79
2024-11-20 22:57:11 +08:00
Datong Sun
60f24d2563 Revert "docs(readme): update README.md to include incoming interface (`-i t…"
Some checks failed
Rust / build (push) Has been cancelled
This reverts commit 8c7f4e98b39518e10bf5cbd69987e4ccf702015b.
2024-08-27 23:19:09 +08:00
Ricardo Pallas
8c7f4e98b3
docs(readme): update README.md to include incoming interface (-i tun0) in client NAT commands example (#163)
Some checks are pending
Rust / build (push) Waiting to run
2024-08-26 19:50:07 +08:00
Datong Sun
90b93370ce chore(docs): update license year to 2024 2024-04-19 09:15:33 -07:00
dependabot[bot]
792ee46ec4 chore(deps): bump softprops/action-gh-release from 1 to 2
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 1 to 2.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/v1...v2)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-26 23:41:37 +08:00
dependabot[bot]
f5cb4b1220 chore(deps): update nix requirement from 0.27 to 0.28
Updates the requirements on [nix](https://github.com/nix-rust/nix) to permit the latest version.
- [Changelog](https://github.com/nix-rust/nix/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nix-rust/nix/compare/v0.27.0...v0.28.0)

---
updated-dependencies:
- dependency-name: nix
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-26 23:41:27 +08:00
dependabot[bot]
8a0ec729e2 chore(deps): update tokio-tun requirement from 0.9 to 0.11
Updates the requirements on [tokio-tun](https://github.com/yaa110/tokio-tun) to permit the latest version.
- [Commits](https://github.com/yaa110/tokio-tun/compare/0.9.0...0.11.2)

---
updated-dependencies:
- dependency-name: tokio-tun
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-30 22:45:51 +08:00
Datong Sun
78dd7c13b1 style(phantun): fix Clippy warnings 2023-09-19 00:25:52 +08:00
dependabot[bot]
b58d58956b chore(deps): update nix requirement from 0.26 to 0.27
Updates the requirements on [nix](https://github.com/nix-rust/nix) to permit the latest version.
- [Changelog](https://github.com/nix-rust/nix/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nix-rust/nix/compare/v0.26.0...v0.27.0)

---
updated-dependencies:
- dependency-name: nix
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-19 00:15:35 +08:00
dependabot[bot]
310bb17516 chore(deps): update pnet requirement from 0.33 to 0.34
Updates the requirements on [pnet](https://github.com/libpnet/libpnet) to permit the latest version.
- [Release notes](https://github.com/libpnet/libpnet/releases)
- [Commits](https://github.com/libpnet/libpnet/compare/v0.33.0...v0.34.0)

---
updated-dependencies:
- dependency-name: pnet
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-19 00:07:50 +08:00
dependabot[bot]
632132b75a chore(deps): bump docker/setup-buildx-action from 2 to 3
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 2 to 3.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-12 22:09:47 +08:00
dependabot[bot]
48a0399f59 chore(deps): bump docker/setup-qemu-action from 2 to 3
Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 2 to 3.
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-12 22:09:34 +08:00
dependabot[bot]
590a048b5b chore(deps): bump docker/build-push-action from 4 to 5
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 4 to 5.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v4...v5)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-12 22:09:16 +08:00
dependabot[bot]
3fa8f86379 chore(deps): bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-12 22:08:56 +08:00
dependabot[bot]
805bf80cd8 chore(deps): update tokio-tun requirement from 0.7 to 0.9
Updates the requirements on [tokio-tun](https://github.com/yaa110/tokio-tun) to permit the latest version.
- [Commits](https://github.com/yaa110/tokio-tun/compare/0.7.0...0.9.0)

---
updated-dependencies:
- dependency-name: tokio-tun
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-27 23:38:42 +08:00
dependabot[bot]
aec3bcdeda chore(deps): update flume requirement from 0.10 to 0.11
Updates the requirements on [flume](https://github.com/zesterer/flume) to permit the latest version.
- [Changelog](https://github.com/zesterer/flume/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zesterer/flume/commits)

---
updated-dependencies:
- dependency-name: flume
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-27 12:58:08 +08:00
dependabot[bot]
9b1d3c0124 chore(deps): update pretty_env_logger requirement from 0.4 to 0.5
Updates the requirements on [pretty_env_logger](https://github.com/seanmonstar/pretty-env-logger) to permit the latest version.
- [Commits](https://github.com/seanmonstar/pretty-env-logger/compare/v0.4.0...v0.5.0)

---
updated-dependencies:
- dependency-name: pretty_env_logger
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-23 02:39:00 +08:00
dependabot[bot]
6c42f02b28 chore(deps): update socket2 requirement from 0.4 to 0.5
Updates the requirements on [socket2](https://github.com/rust-lang/socket2) to permit the latest version.
- [Release notes](https://github.com/rust-lang/socket2/releases)
- [Changelog](https://github.com/rust-lang/socket2/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/socket2/compare/v0.4.0...v0.5.1)

---
updated-dependencies:
- dependency-name: socket2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-21 00:35:39 +08:00
Datong Sun
ee0bce0a96
chore(docker): use Debian as base image (#108)
Alpine has worse performance and musl does not work well with Rust `libc` version `3`,
use Debian instead.
2023-03-21 00:30:39 +08:00
dependabot[bot]
1f11d618e0 chore(deps): bump docker/build-push-action from 3 to 4
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 3 to 4.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-14 18:56:42 +08:00
Sing Yu Chan
d7913c1407
chore(docker): add Docker image build. Thanks @pexcn for the contributions!
Co-authored-by: Datong Sun <dndx@idndx.com>
2023-02-13 23:29:59 +08:00
dependabot[bot]
ee7ee5d5f9 chore(deps): update pnet requirement from 0.31 to 0.33
Updates the requirements on [pnet](https://github.com/libpnet/libpnet) to permit the latest version.
- [Release notes](https://github.com/libpnet/libpnet/releases)
- [Commits](https://github.com/libpnet/libpnet/compare/v0.31.0...v0.33.0)

---
updated-dependencies:
- dependency-name: pnet
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-13 23:16:04 +08:00
Datong Sun
af3a9061a1
docs(README): fix build status link 2022-12-29 10:41:32 +08:00
dependabot[bot]
7c98012a67 chore(deps): update nix requirement from 0.25 to 0.26
Updates the requirements on [nix](https://github.com/nix-rust/nix) to permit the latest version.
- [Release notes](https://github.com/nix-rust/nix/releases)
- [Changelog](https://github.com/nix-rust/nix/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nix-rust/nix/compare/v0.25.0...v0.26.1)

---
updated-dependencies:
- dependency-name: nix
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-29 16:31:23 +08:00
Datong Sun
b674268863
docs(README): bumped latest release version to v0.6.0 2022-10-25 23:54:08 +08:00
Datong Sun
b40ca10cc1 chore(phantun): bump fake-tcp dependency to v0.5.0 2022-10-25 08:36:42 -07:00
Datong Sun
30f0a1118b chore(fake-tcp): bump to v0.5.0 2022-10-25 08:35:49 -07:00
Datong Sun
fd607bc72a Revert "chore(release) temporary disable the MIPS musl target until new versions"
This reverts commit 9ff691d063afb1cc7c475e0298c818dd3fe0a514.
2022-10-25 08:25:30 -07:00
Datong Sun
939e4aa94e chore(phantun): bump to v0.6.0 2022-10-25 08:22:55 -07:00
Datong Sun
7bcfada87b refactor(phantun): work with clap 4.0. 2022-10-25 23:21:58 +08:00
dependabot[bot]
fe18a49d40 chore(deps): update clap requirement from 3.0 to 4.0
Updates the requirements on [clap](https://github.com/clap-rs/clap) to permit the latest version.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v3.0.0...v4.0.2)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-25 23:21:58 +08:00
dependabot[bot]
b707c5bd12 chore(deps): update tokio-tun requirement from 0.6 to 0.7
Updates the requirements on [tokio-tun](https://github.com/yaa110/tokio-tun) to permit the latest version.
- [Release notes](https://github.com/yaa110/tokio-tun/releases)
- [Commits](https://github.com/yaa110/tokio-tun/compare/0.6.0...0.7.0)

---
updated-dependencies:
- dependency-name: tokio-tun
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-20 00:04:20 -07:00
Paolo Barbolini
6af7757456
perf(fake-tcp) let the memory allocator zero initialize the BytesMut memory instead of resizing immediately after allocation
Co-authored-by: Datong Sun <dndx@idndx.com>
2022-08-18 19:00:09 -07:00
dependabot[bot]
f374ac8081 chore(deps): update nix requirement from 0.24 to 0.25
Updates the requirements on [nix](https://github.com/nix-rust/nix) to permit the latest version.
- [Release notes](https://github.com/nix-rust/nix/releases)
- [Changelog](https://github.com/nix-rust/nix/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nix-rust/nix/compare/v0.24.0...v0.25.0)

---
updated-dependencies:
- dependency-name: nix
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-18 18:54:57 -07:00
dependabot[bot]
50346c1ba0 chore(deps): update tokio-tun requirement from 0.5 to 0.6
Updates the requirements on [tokio-tun](https://github.com/yaa110/tokio-tun) to permit the latest version.
- [Release notes](https://github.com/yaa110/tokio-tun/releases)
- [Commits](https://github.com/yaa110/tokio-tun/compare/0.5.1...0.6.0)

---
updated-dependencies:
- dependency-name: tokio-tun
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-18 18:54:47 -07:00
dependabot[bot]
f649c79656 chore(deps): update pnet requirement from 0.30 to 0.31
Updates the requirements on [pnet](https://github.com/libpnet/libpnet) to permit the latest version.
- [Release notes](https://github.com/libpnet/libpnet/releases)
- [Commits](https://github.com/libpnet/libpnet/compare/v0.30.0...v0.31.0)

---
updated-dependencies:
- dependency-name: pnet
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-25 02:57:39 +08:00
Datong Sun
c91bda7e6a
docs(readme) add blog post link about performance optimizations 2022-05-30 14:10:41 +08:00
Datong Sun
00a308a005 docs(readme) update latest release version to v0.5.0 2022-05-13 08:52:21 -07:00
Datong Sun
9ff691d063 chore(release) temporary disable the MIPS musl target until new versions
of `libc` is released with `libc::sock_txtime`
2022-05-13 08:38:11 -07:00
Datong Sun
b5e79653f0 chore(phantun) bump to v0.5.0 2022-05-13 08:34:31 -07:00
Datong Sun
f496a7919b feat(phantun) new option --handshake-packet that allows additional
packet to be sent to the other end after TCP connection establishment
2022-05-13 23:14:05 +08:00
dependabot[bot]
bf6b9bc2ff chore(deps): update pnet requirement from 0.29 to 0.30
Updates the requirements on [pnet](https://github.com/libpnet/libpnet) to permit the latest version.
- [Release notes](https://github.com/libpnet/libpnet/releases)
- [Commits](https://github.com/libpnet/libpnet/compare/v0.29.0...v0.29.0)

---
updated-dependencies:
- dependency-name: pnet
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-13 23:06:03 +08:00
dependabot[bot]
47b9037968 chore(deps): update nix requirement from 0.23 to 0.24
Updates the requirements on [nix](https://github.com/nix-rust/nix) to permit the latest version.
- [Release notes](https://github.com/nix-rust/nix/releases)
- [Changelog](https://github.com/nix-rust/nix/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nix-rust/nix/commits)

---
updated-dependencies:
- dependency-name: nix
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-21 20:07:52 +08:00
Datong Sun
c2341b6662 docs(README) bump the release to v0.4.2 and fixed default site-local address in doc 2022-04-16 09:58:07 -07:00
Datong Sun
a3eff42453 chore(phantun) release v0.4.2 2022-04-16 09:55:40 -07:00
Datong Sun
87a42a1e23 fix(phantun) do not use the deprecated fec0::/10 block for default ULA
address
2022-04-17 00:55:16 +08:00
Datong Sun
851750b13d docs(README) bump release version to v0.4.1 and add end-to-end IPv6 documentation 2022-04-16 19:45:31 +08:00
24 changed files with 1630 additions and 138 deletions

30
.github/workflows/docker.yml vendored Normal file
View File

@ -0,0 +1,30 @@
name: Docker image build
on:
push:
paths-ignore:
- '**.md'
jobs:
build:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: linux/amd64
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build Docker Image
uses: docker/build-push-action@v6
with:
context: .
file: docker/Dockerfile
tags: phantun
platforms: linux/amd64

View File

@ -25,13 +25,9 @@ jobs:
- 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@v3
- uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
@ -50,7 +46,7 @@ jobs:
zip phantun_${{ matrix.target }}.zip phantun_client phantun_server
- name: Upload Github Assets
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v2
with:
files: target/${{ matrix.target }}/release/*.zip
prerelease: ${{ contains(github.ref, '-') }}

View File

@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1
with:
toolchain: stable

1
.gitignore vendored
View File

@ -1,2 +1 @@
/target
Cargo.lock

1101
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,7 @@
[workspace]
resolver = "2"
members = [
"fake-tcp",
"phantun",

View File

@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work.
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2021-2022 Datong Sun (dndx@idndx.com)
Copyright 2021-2024 Datong Sun (dndx@idndx.com)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2021-2022 Datong Sun (dndx@idndx.com)
Copyright (c) 2021-2024 Datong Sun (dndx@idndx.com)
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated

View File

@ -2,7 +2,7 @@
A lightweight and fast UDP to TCP obfuscator.
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/dndx/phantun/Rust?style=flat-square)
![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/dndx/phantun/rust.yml)
![docs.rs](https://img.shields.io/docsrs/fake-tcp)
Table of Contents
@ -35,7 +35,7 @@ Table of Contents
# Latest release
[v0.3.2](https://github.com/dndx/phantun/releases/tag/v0.3.2)
[v0.7.0](https://github.com/dndx/phantun/releases/tag/v0.7.0)
# Overview
@ -72,30 +72,32 @@ It is also assumed that **Phantun Client** listens for incoming UDP packets at
`127.0.0.1:1234` (the `--local` option for client) and connects to Phantun Server at `10.0.0.1:4567`
(the `--remote` option for client).
Phantun creates TUN interface for both the Client and Server. For Client, Phantun assigns itself the IP address
`192.168.200.2` by default and for Server, it assigns `192.168.201.2` by default. Therefore, your Kernel must have
`net.ipv4.ip_forward` enabled and setup appropriate iptables rules for NAT between your physical
NIC address and Phantun's TUN interface address.
Phantun creates TUN interface for both the Client and Server. For **Client**, Phantun assigns itself the IP address
`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.
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.
Another way to help understand this network topology (please see the diagram above for an illustration of this topology):
Phantun Client is like a machine with private IP address (`192.168.200.2`) behind a router.
Phantun Client is like a machine with private IP address (`192.168.200.2`/`fcc8::2`) behind a router.
In order for it to reach the Internet, you will need to SNAT the private IP address before it's traffic
leaves the NIC.
Phantun Server is like a server with private IP address (`192.168.201.2`) behind a router.
Phantun Server is like a server with private IP address (`192.168.201.2`/`fcc9::2`) behind a router.
In order to access it from the Internet, you need to `DNAT` it's listening port on the router
and change the destination IP address to where the server is listening for incoming connections.
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.
As of Phantun v0.4.1, IPv6 is fully supported for both TCP and UDP sides.
To specify an IPv6 address, use the following format: `[::1]:1234` with
the command line options. Resolving AAAA record is also supported. Please run the program
with `-h` to see detailed options on how to control the IPv6 behavior.
[Back to TOC](#table-of-contents)
@ -103,6 +105,12 @@ the command line options.
Edit `/etc/sysctl.conf`, add `net.ipv4.ip_forward=1` and run `sudo sysctl -p /etc/sysctl.conf`.
<details>
<summary>IPv6 specific config</summary>
`net.ipv6.conf.all.forwarding=1` will need to be set as well.
</details>
[Back to TOC](#table-of-contents)
## 2. Add required firewall rules
@ -128,12 +136,16 @@ table inet nat {
}
```
Note: The above rule uses `inet` as the table family type, so it is compatible with
both IPv4 and IPv6 usage.
[Back to TOC](#table-of-contents)
#### Using iptables
```
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
```
[Back to TOC](#table-of-contents)
@ -150,10 +162,11 @@ actual TCP port number used by Phantun server
#### Using nftables
```
table ip nat {
table inet nat {
chain prerouting {
type nat hook prerouting priority dstnat; policy accept;
iif eth0 tcp dport 4567 dnat to 192.168.201.2
iif eth0 tcp dport 4567 dnat ip to 192.168.201.2
iif eth0 tcp dport 4567 dnat ip6 to fcc9::2
}
}
```
@ -164,6 +177,7 @@ table ip nat {
```
iptables -t nat -A PREROUTING -p tcp -i eth0 --dport 4567 -j DNAT --to-destination 192.168.201.2
ip6tables -t nat -A PREROUTING -p tcp -i eth0 --dport 4567 -j DNAT --to-destination fcc9::2
```
[Back to TOC](#table-of-contents)
@ -202,6 +216,10 @@ Or use host name with `--remote`:
RUST_LOG=info /usr/local/bin/phantun_server --local 4567 --remote example.com:1234
```
Note: Server by default assigns both IPv4 and IPv6 private address to the Tun interface.
If you do not wish to use IPv6, you can simply skip creating the IPv6 DNAT rule above and
the presence of IPv6 address on the Tun interface should have no side effect to the server.
[Back to TOC](#table-of-contents)
### Client
@ -219,12 +237,22 @@ Or use host name with `--remote`:
RUST_LOG=info /usr/local/bin/phantun_client --local 127.0.0.1:1234 --remote example.com:4567
```
<details>
<summary>IPv6 specific config</summary>
```
RUST_LOG=info /usr/local/bin/phantun_client --local 127.0.0.1:1234 --remote [fdxx::1234]:4567
```
Domain name with AAAA record is also supported.
</details>
[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
is the following:
is the following (using IPv4 below as an example):
**Standard UDP packet:** `20 byte IP header + 8 byte UDP header = 28 bytes`
@ -234,7 +262,7 @@ is the following:
Note that Phantun does not add any additional header other than IP and TCP headers in order to pass through
stateful packet inspection!
Phantun's additional overhead: `12 bytes`. I other words, when using Phantun, the usable payload for
Phantun's additional overhead: `12 bytes`. In other words, when using Phantun, the usable payload for
UDP packet is reduced by 12 bytes. This is the minimum overhead possible when doing such kind
of obfuscation.
@ -248,18 +276,23 @@ For people who use Phantun to tunnel [WireGuard®](https://www.wireguard.com) UD
out the correct MTU to use for your WireGuard interface.
```
WireGuard MTU = Interface MTU - IP header (20 bytes) - TCP header (20 bytes) - WireGuard overhead (32 bytes)
WireGuard MTU = Interface MTU - IPv4 header (20 bytes) - TCP header (20 bytes) - WireGuard overhead (32 bytes)
```
or
```
WireGuard MTU = Interface MTU - IPv6 header (40 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:
```
1500 - 20 - 20 - 32 = 1428 bytes
```
IPv4: `1500 - 20 - 20 - 32 = 1428 bytes`
IPv6: `1500 - 40 - 20 - 32 = 1408 bytes`
The resulted Phantun TCP data packet will be 1500 bytes which does not exceed the
interface MTU of 1500. Please note it is strongly recommended to use the same interface
MTU for both ends of a WireGuard tunnel, or unexected packet loss may occur and these issues are
MTU for both ends of a WireGuard tunnel, or unexpected packet loss may occur and these issues are
generally very hard to troubleshoot.
[Back to TOC](#table-of-contents)
@ -296,11 +329,12 @@ Test command: `iperf3 -c <IP> -p <PORT> -R -u -l 1400 -b 1000m -t 30 -P 5`
| Phantun (5 streams) | 5.00 Gbits/sec | 2.38 Gbits/sec | 95% (all cores utilized) |
| udp2raw (`cipher-mode=none` `auth-mode=none` `disable-anti-replay`) (5 streams) | 5.00 Gbits/sec | 770 Mbits/sec | 50% (2 cores at 100%) |
Writeup on some of the techniques used in Phantun to achieve this performance result: [Writing Highly Efficient UDP Server in Rust](https://idndx.com/writing-highly-efficient-udp-server-in-rust/).
[Back to TOC](#table-of-contents)
# Future plans
* IPv6 support for fake-tcp
* Load balancing a single UDP stream into multiple TCP streams
* Integration tests
* Auto insertion/removal of required firewall rules
@ -328,13 +362,13 @@ 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 | UDP only | ✅ |
| IPv6 | ✅ | ✅ |
[Back to TOC](#table-of-contents)
# License
Copyright 2021-2022 Datong Sun (dndx@idndx.com)
Copyright 2021-2024 Datong Sun (dndx@idndx.com)
Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
[https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license

2
docker/.dockerignore Normal file
View File

@ -0,0 +1,2 @@
README.md
docker-compose.yml

33
docker/Dockerfile Normal file
View File

@ -0,0 +1,33 @@
#
# Dockerfile for phantun
#
#
# Build stage
#
FROM rust:latest AS builder
COPY . /phantun
RUN cd phantun \
&& cargo build --release \
&& strip target/release/server target/release/client \
&& install target/release/server /usr/local/bin/phantun-server \
&& install target/release/client /usr/local/bin/phantun-client \
&& cd - \
&& rm -r phantun
#
# Runtime stage
#
FROM debian:latest
COPY --from=builder /usr/local/bin/phantun-server /usr/local/bin/
COPY --from=builder /usr/local/bin/phantun-client /usr/local/bin/
COPY docker/phantun.sh /usr/local/bin/
ENV USE_IPTABLES_NFT_BACKEND=0
ENV RUST_LOG=INFO
ENTRYPOINT ["phantun.sh"]
CMD ["phantun-server", "--help"]

11
docker/README.md Normal file
View File

@ -0,0 +1,11 @@
# phantun (docker)
## Build
```sh
docker build -t phantun -f docker/Dockerfile .
```
## Usage
It is recommended to use docker-compose, see [docker-compose.yml](docker-compose.yml) for details.

26
docker/docker-compose.yml Normal file
View File

@ -0,0 +1,26 @@
version: '3.9'
services:
phantun-server:
image: phantun
container_name: phantun-server
restart: unless-stopped
network_mode: host
privileged: true
environment:
USE_IPTABLES_NFT_BACKEND: 0
RUST_LOG: INFO
command: >
phantun-server --local 1985 --remote 127.0.0.1:1984 --ipv4-only
phantun-client:
image: phantun
container_name: phantun-client
restart: unless-stopped
network_mode: host
privileged: true
environment:
USE_IPTABLES_NFT_BACKEND: 0
RUST_LOG: INFO
command: >
phantun-client --local 127.0.0.1:1984 --remote 11.22.33.44:1985 --ipv4-only

209
docker/phantun.sh Executable file
View File

@ -0,0 +1,209 @@
#!/bin/sh
# alias settings must be global, and must be defined before the function being called with the alias
if [ "$USE_IPTABLES_NFT_BACKEND" = 1 ]; then
alias iptables=iptables-nft
alias iptables-save=iptables-nft-save
alias ip6tables=ip6tables-nft
alias ip6tables-save=ip6tables-nft-save
fi
info() {
local green='\e[0;32m'
local clear='\e[0m'
local time=$(date '+%Y-%m-%d %T')
printf "${green}[${time}] [INFO]: ${clear}%s\n" "$*"
}
warn() {
local yellow='\e[1;33m'
local clear='\e[0m'
local time=$(date '+%Y-%m-%d %T')
printf "${yellow}[${time}] [WARN]: ${clear}%s\n" "$*" >&2
}
error() {
local red='\e[0;31m'
local clear='\e[0m'
local time=$(date '+%Y-%m-%d %T')
printf "${red}[${time}] [ERROR]: ${clear}%s\n" "$*" >&2
}
_get_default_iface() {
ip -4 route show default | awk -F 'dev' '{print $2}' | awk '{print $1}'
}
_get_default6_iface() {
ip -6 route show default | awk -F 'dev' '{print $2}' | awk '{print $1}'
}
_get_addr_by_iface() {
ip -4 addr show dev "$1" | grep -w "inet" | awk '{print $2}' | awk -F '/' '{print $1}' | head -1
}
_get_addr6_by_iface() {
ip -6 addr show dev "$1" | grep -w "inet6" | awk '{print $2}' | awk -F '/' '{print $1}' | head -1
}
_check_rule_by_comment() {
iptables-save | grep -q "$1"
}
_check_rule6_by_comment() {
ip6tables-save | grep -q "$1"
}
_is_server_mode() {
[ "$1" = "phantun-server" ]
}
_is_ipv4_only() {
case "$@" in
*-4*|*--ipv4-only*)
return 0
;;
*\ -4*|*\ --ipv4-only*)
return 0
;;
esac
return 1
}
_get_tun_from_args() {
local tun=$(echo "$@" | awk -F '--tun' '{print $2}' | awk '{print $1}')
echo ${tun:=tun0}
}
_get_peer_from_args() {
local peer=$(echo "$@" | awk -F '--tun-peer' '{print $2}' | awk '{print $1}')
_is_server_mode "$1" && echo ${peer:=192.168.201.2} || echo ${peer:=192.168.200.2}
}
_get_peer6_from_args() {
local peer=$(echo "$@" | awk -F '--tun-peer6' '{print $2}' | awk '{print $1}')
_is_server_mode "$1" && echo ${peer:=fcc9::2} || echo ${peer:=fcc8::2}
}
_get_port_from_args() {
local value=$(echo "$@" | awk -F '-l|--local' '{print $2}' | awk '{print $1}')
_is_server_mode "$1" && echo $value || echo $value | awk -F ':' '{print $2}'
}
_iptables() {
iptables -w 10 "$@"
}
_ip6tables() {
ip6tables -w 10 "$@"
}
apply_sysctl() {
info "apply sysctl: $(sysctl -w net.ipv4.ip_forward=1)"
! _is_ipv4_only "$@" || return
info "apply sysctl: $(sysctl -w net.ipv6.conf.all.forwarding=1)"
}
apply_iptables() {
local interface=$(_get_default_iface)
local address=$(_get_addr_by_iface "${interface}")
local tun=$(_get_tun_from_args "$@")
local peer=$(_get_peer_from_args "$@")
local port=$(_get_port_from_args "$@")
local comment="phantun_${tun}_${port}"
if _check_rule_by_comment "${comment}"; then
warn "iptables rules already exist, maybe needs to check."
else
_iptables -A FORWARD -i $tun -j ACCEPT -m comment --comment "${comment}" || error "iptables filter rule add failed."
_iptables -A FORWARD -o $tun -j ACCEPT -m comment --comment "${comment}" || error "iptables filter rule add failed."
if _is_server_mode "$1"; then
info "iptables DNAT rule added: [${comment}]: ${interface} -> ${tun}, ${address} -> ${peer}"
_iptables -t nat -A PREROUTING -p tcp -i $interface --dport $port -j DNAT --to-destination $peer \
-m comment --comment "${comment}" || error "iptables DNAT rule add failed."
else
info "iptables SNAT rule added: [${comment}]: ${tun} -> ${interface}, ${peer} -> ${address}"
_iptables -t nat -A POSTROUTING -s $peer -o $interface -j SNAT --to-source $address \
-m comment --comment "${comment}" || error "iptables SNAT rule add failed."
fi
fi
}
apply_ip6tables() {
! _is_ipv4_only "$@" || return
local interface=$(_get_default6_iface)
local address=$(_get_addr6_by_iface "${interface}")
local tun=$(_get_tun_from_args "$@")
local peer=$(_get_peer6_from_args "$@")
local port=$(_get_port_from_args "$@")
local comment="phantun_${tun}_${port}"
if _check_rule6_by_comment "${comment}"; then
warn "ip6tables rules already exist, maybe needs to check."
else
_ip6tables -A FORWARD -i $tun -j ACCEPT -m comment --comment "${comment}" || error "ip6tables filter rule add failed."
_ip6tables -A FORWARD -o $tun -j ACCEPT -m comment --comment "${comment}" || error "ip6tables filter rule add failed."
if _is_server_mode "$1"; then
info "ip6tables DNAT rule added: [${comment}]: ${interface} -> ${tun}, ${address} -> ${peer}"
_ip6tables -t nat -A PREROUTING -p tcp -i $interface --dport $port -j DNAT --to-destination $peer \
-m comment --comment "${comment}" || error "ip6tables DNAT rule add failed."
else
info "ip6tables SNAT rule added: [${comment}]: ${tun} -> ${interface}, ${peer} -> ${address}"
_ip6tables -t nat -A POSTROUTING -s $peer -o $interface -j SNAT --to-source $address \
-m comment --comment "${comment}" || error "ip6tables SNAT rule add failed."
fi
fi
}
stop_process() {
kill $(pidof phantun-server phantun-client)
info "terminate phantun process."
}
revoke_iptables() {
local tun=$(_get_tun_from_args "$@")
local port=$(_get_port_from_args "$@")
local comment="phantun_${tun}_${port}"
iptables-save -t filter | grep "${comment}" | while read rule; do
_iptables -t filter ${rule/-A/-D} || error "iptables filter rule remove failed."
done
iptables-save -t nat | grep "${comment}" | while read rule; do
_iptables -t nat ${rule/-A/-D} || error "iptables nat rule remove failed."
done
info "iptables rule: [${comment}] removed."
}
revoke_ip6tables() {
! _is_ipv4_only "$@" || return
local tun=$(_get_tun_from_args "$@")
local port=$(_get_port_from_args "$@")
local comment="phantun_${tun}_${port}"
ip6tables-save -t filter | grep "${comment}" | while read rule; do
_ip6tables -t filter ${rule/-A/-D} || error "ip6tables filter rule remove failed."
done
ip6tables-save -t nat | grep "${comment}" | while read rule; do
_ip6tables -t nat ${rule/-A/-D} || error "ip6tables nat rule remove failed."
done
info "ip6tables rule: [${comment}] removed."
}
graceful_stop() {
warn "caught SIGTERM or SIGINT signal, graceful stopping..."
stop_process
revoke_iptables "$@"
revoke_ip6tables "$@"
}
start_phantun() {
trap 'graceful_stop "$@"' SIGTERM SIGINT
apply_sysctl "$@"
apply_iptables "$@"
apply_ip6tables "$@"
"$@" &
wait
}
start_phantun "$@"

View File

@ -1,6 +1,6 @@
[package]
name = "fake-tcp"
version = "0.4.0"
version = "0.6.0"
edition = "2021"
authors = ["Datong Sun <dndx@idndx.com>"]
license = "MIT OR Apache-2.0"
@ -16,10 +16,10 @@ benchmark = []
[dependencies]
bytes = "1"
pnet = "0.29"
tokio = { version = "1.14", features = ["full"] }
rand = { version = "0.8", features = ["small_rng"] }
log = "0.4"
internet-checksum = "0.2"
tokio-tun = "0.5"
flume = "0.10"
pnet = "0"
tokio = { version = "1", features = ["full"] }
rand = { version = "0", features = ["small_rng"] }
log = "0"
internet-checksum = "0"
tokio-tun = "0"
flume = "0"

View File

@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work.
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2021-2022 Datong Sun (dndx@idndx.com)
Copyright 2021-2024 Datong Sun (dndx@idndx.com)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2021-2022 Datong Sun (dndx@idndx.com)
Copyright (c) 2021-2024 Datong Sun (dndx@idndx.com)
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated

View File

@ -50,8 +50,10 @@ use rand::prelude::*;
use std::collections::{HashMap, HashSet};
use std::fmt;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::{Arc, RwLock};
use std::sync::{
atomic::{AtomicU32, Ordering},
Arc, RwLock,
};
use tokio::sync::broadcast;
use tokio::sync::mpsc;
use tokio::time;
@ -146,7 +148,7 @@ impl Socket {
)
}
fn build_tcp_packet(&self, flags: u16, payload: Option<&[u8]>) -> Bytes {
fn build_tcp_packet(&self, flags: u8, payload: Option<&[u8]>) -> Bytes {
let ack = self.ack.load(Ordering::Relaxed);
self.last_ack.store(ack, Ordering::Relaxed);
@ -400,32 +402,50 @@ impl Stack {
/// Connects to the remote end. `None` returned means
/// the connection attempt failed.
pub async fn connect(&mut self, addr: SocketAddr) -> Option<Socket> {
let mut rng = SmallRng::from_entropy();
let local_port: u16 = rng.gen_range(1024..65535);
let local_addr = SocketAddr::new(
if addr.is_ipv4() {
IpAddr::V4(self.local_ip)
} else {
IpAddr::V6(self.local_ip6.expect("IPv6 local address undefined"))
},
local_port,
);
let tuple = AddrTuple::new(local_addr, addr);
let (mut sock, incoming) = Socket::new(
self.shared.clone(),
self.shared.tun.choose(&mut rng).unwrap().clone(),
local_addr,
addr,
None,
State::Idle,
);
let mut rng = SmallRng::from_os_rng();
for local_port in rng.random_range(32768..=60999)..=60999 {
let local_addr = SocketAddr::new(
if addr.is_ipv4() {
IpAddr::V4(self.local_ip)
} else {
IpAddr::V6(self.local_ip6.expect("IPv6 local address undefined"))
},
local_port,
);
let tuple = AddrTuple::new(local_addr, addr);
let mut sock;
{
let mut tuples = self.shared.tuples.write().unwrap();
assert!(tuples.insert(tuple, incoming.clone()).is_none());
{
let mut tuples = self.shared.tuples.write().unwrap();
if tuples.contains_key(&tuple) {
trace!(
"Fake TCP connection to {}, local port number {} already in use, trying another one",
addr, local_port
);
continue;
}
let incoming;
(sock, incoming) = Socket::new(
self.shared.clone(),
self.shared.tun.choose(&mut rng).unwrap().clone(),
local_addr,
addr,
None,
State::Idle,
);
assert!(tuples.insert(tuple, incoming).is_none());
}
return sock.connect().await.map(|_| sock);
}
sock.connect().await.map(|_| sock)
error!(
"Fake TCP connection to {} failed, emphemeral port number exhausted",
addr
);
None
}
async fn reader_task(
@ -436,8 +456,7 @@ impl Stack {
let mut tuples: HashMap<AddrTuple, flume::Sender<Bytes>> = HashMap::new();
loop {
let mut buf = BytesMut::with_capacity(MAX_PACKET_LEN);
buf.resize(MAX_PACKET_LEN, 0);
let mut buf = BytesMut::zeroed(MAX_PACKET_LEN);
tokio::select! {
size = tun.recv(&mut buf) => {

View File

@ -15,7 +15,7 @@ pub enum IPPacket<'p> {
V6(ipv6::Ipv6Packet<'p>),
}
impl<'a> IPPacket<'a> {
impl IPPacket<'_> {
pub fn get_source(&self) -> IpAddr {
match self {
IPPacket::V4(p) => IpAddr::V4(p.get_source()),
@ -36,7 +36,7 @@ pub fn build_tcp_packet(
remote_addr: SocketAddr,
seq: u32,
ack: u32,
flags: u16,
flags: u8,
payload: Option<&[u8]>,
) -> Bytes {
let ip_header_len = match local_addr {
@ -47,8 +47,7 @@ pub fn build_tcp_packet(
let tcp_header_len = TCP_HEADER_LEN + if wscale { 4 } else { 0 }; // nop + wscale
let tcp_total_len = tcp_header_len + payload.map_or(0, |payload| payload.len());
let total_len = ip_header_len + tcp_total_len;
let mut buf = BytesMut::with_capacity(total_len);
buf.resize(total_len, 0);
let mut buf = BytesMut::zeroed(total_len);
let mut ip_buf = buf.split_to(ip_header_len);
let mut tcp_buf = buf.split_to(tcp_total_len);

View File

@ -1,6 +1,6 @@
[package]
name = "phantun"
version = "0.4.1"
version = "0.7.0"
edition = "2021"
authors = ["Datong Sun <dndx@idndx.com>"]
license = "MIT OR Apache-2.0"
@ -11,14 +11,14 @@ Transforms UDP stream into (fake) TCP streams that can go through
Layer 3 & Layer 4 (NAPT) firewalls/NATs.
"""
[dependencies]
clap = { version = "3.0", features = ["cargo"] }
socket2 = { version = "0.4", features = ["all"] }
fake-tcp = { path = "../fake-tcp", version = "0.4" }
tokio = { version = "1.14", features = ["full"] }
tokio-util = "0.7"
log = "0.4"
pretty_env_logger = "0.4"
tokio-tun = "0.5"
num_cpus = "1.13"
neli = "0.6"
nix = "0.23"
clap = { version = "4", features = ["cargo"] }
socket2 = { version = "0", features = ["all"] }
fake-tcp = { path = "../fake-tcp", version = "0" }
tokio = { version = "1", features = ["full"] }
tokio-util = "0"
log = "0"
pretty_env_logger = "0"
tokio-tun = "0"
num_cpus = "1"
neli = "0"
nix = { version = "0", features = ["net"] }

View File

@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work.
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2021-2022 Datong Sun (dndx@idndx.com)
Copyright 2021-2024 Datong Sun (dndx@idndx.com)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2021-2022 Datong Sun (dndx@idndx.com)
Copyright (c) 2021-2024 Datong Sun (dndx@idndx.com)
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated

View File

@ -1,9 +1,10 @@
use clap::{crate_version, Arg, Command};
use clap::{crate_version, Arg, ArgAction, Command};
use fake_tcp::packet::MAX_PACKET_LEN;
use fake_tcp::{Socket, Stack};
use log::{debug, error, info};
use phantun::utils::{assign_ipv6_address, new_udp_reuseport};
use std::collections::HashMap;
use std::fs;
use std::io;
use std::net::{Ipv4Addr, SocketAddr};
use std::sync::Arc;
@ -28,7 +29,6 @@ async fn main() -> io::Result<()> {
.required(true)
.value_name("IP:PORT")
.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(
Arg::new("remote")
@ -37,7 +37,6 @@ async fn main() -> io::Result<()> {
.required(true)
.value_name("IP or HOST NAME:PORT")
.help("Sets the address or host name and port where Phantun Client connects to Phantun Server, IPv6 address need to be specified as: \"[IPv6]:PORT\"")
.takes_value(true),
)
.arg(
Arg::new("tun")
@ -46,7 +45,6 @@ async fn main() -> io::Result<()> {
.value_name("tunX")
.help("Sets the Tun interface name, if absent, pick the next available name")
.default_value("")
.takes_value(true),
)
.arg(
Arg::new("tun_local")
@ -55,7 +53,6 @@ async fn main() -> io::Result<()> {
.value_name("IP")
.help("Sets the Tun interface IPv4 local address (O/S's end)")
.default_value("192.168.200.1")
.takes_value(true),
)
.arg(
Arg::new("tun_peer")
@ -66,7 +63,6 @@ async fn main() -> io::Result<()> {
You will need to setup SNAT/MASQUERADE rules on your Internet facing interface \
in order for Phantun Client to connect to Phantun Server")
.default_value("192.168.200.2")
.takes_value(true),
)
.arg(
Arg::new("ipv4_only")
@ -74,8 +70,8 @@ async fn main() -> io::Result<()> {
.short('4')
.required(false)
.help("Only use IPv4 address when connecting to remote")
.takes_value(false)
.conflicts_with_all(&["tun_local6", "tun_peer6"]),
.action(ArgAction::SetTrue)
.conflicts_with_all(["tun_local6", "tun_peer6"]),
)
.arg(
Arg::new("tun_local6")
@ -83,8 +79,7 @@ async fn main() -> io::Result<()> {
.required(false)
.value_name("IP")
.help("Sets the Tun interface IPv6 local address (O/S's end)")
.default_value("fec8::1")
.takes_value(true),
.default_value("fcc8::1")
)
.arg(
Arg::new("tun_peer6")
@ -94,20 +89,29 @@ async fn main() -> io::Result<()> {
.help("Sets the Tun interface IPv6 destination (peer) address (Phantun Client's end). \
You will need to setup SNAT/MASQUERADE rules on your Internet facing interface \
in order for Phantun Client to connect to Phantun Server")
.default_value("fec8::2")
.takes_value(true),
.default_value("fcc8::2")
)
.arg(
Arg::new("handshake_packet")
.long("handshake-packet")
.required(false)
.value_name("PATH")
.help("Specify a file, which, after TCP handshake, its content will be sent as the \
first data packet to the server.\n\
Note: ensure this file's size does not exceed the MTU of the outgoing interface. \
The content is always sent out in a single packet and will not be further segmented")
)
.get_matches();
let local_addr: SocketAddr = matches
.value_of("local")
.get_one::<String>("local")
.unwrap()
.parse()
.expect("bad local address");
let ipv4_only = matches.is_present("ipv4_only");
let ipv4_only = matches.get_flag("ipv4_only");
let remote_addr = tokio::net::lookup_host(matches.value_of("remote").unwrap())
let remote_addr = tokio::net::lookup_host(matches.get_one::<String>("remote").unwrap())
.await
.expect("bad remote address or host")
.find(|addr| !ipv4_only || addr.is_ipv4())
@ -115,42 +119,45 @@ async fn main() -> io::Result<()> {
info!("Remote address is: {}", remote_addr);
let tun_local: Ipv4Addr = matches
.value_of("tun_local")
.get_one::<String>("tun_local")
.unwrap()
.parse()
.expect("bad local address for Tun interface");
let tun_peer: Ipv4Addr = matches
.value_of("tun_peer")
.get_one::<String>("tun_peer")
.unwrap()
.parse()
.expect("bad peer address for Tun interface");
let (tun_local6, tun_peer6) = if ipv4_only {
let (tun_local6, tun_peer6) = if matches.get_flag("ipv4_only") {
(None, None)
} else {
(
matches
.value_of("tun_local6")
.get_one::<String>("tun_local6")
.map(|v| v.parse().expect("bad local address for Tun interface")),
matches
.value_of("tun_peer6")
.get_one::<String>("tun_peer6")
.map(|v| v.parse().expect("bad peer address for Tun interface")),
)
};
let tun_name = matches.value_of("tun").unwrap();
let tun_name = matches.get_one::<String>("tun").unwrap();
let handshake_packet: Option<Vec<u8>> = matches
.get_one::<String>("handshake_packet")
.map(fs::read)
.transpose()?;
let num_cpus = num_cpus::get();
info!("{} cores available", num_cpus);
let tun = TunBuilder::new()
.name(tun_name) // if name is empty, then it is set by kernel.
.tap(false) // false (default): TUN, true: TAP.
.packet_info(false) // false: IFF_NO_PI, default is true.
.up() // or set it up manually using `sudo ip link set <tun-name> up`.
.address(tun_local)
.destination(tun_peer)
.try_build_mq(num_cpus)
.queues(num_cpus)
.build()
.unwrap();
if remote_addr.is_ipv6() {
@ -186,9 +193,17 @@ async fn main() -> io::Result<()> {
}
let sock = Arc::new(sock.unwrap());
if let Some(ref p) = handshake_packet {
if sock.send(p).await.is_none() {
error!("Failed to send handshake packet to remote, closing connection.");
continue;
}
debug!("Sent handshake packet to: {}", sock);
}
// send first packet
let res = sock.send(&buf_r[..size]).await;
if res.is_none() {
if sock.send(&buf_r[..size]).await.is_none() {
continue;
}

View File

@ -1,8 +1,9 @@
use clap::{crate_version, Arg, Command};
use clap::{crate_version, Arg, ArgAction, Command};
use fake_tcp::packet::MAX_PACKET_LEN;
use fake_tcp::Stack;
use log::{debug, error, info};
use phantun::utils::{assign_ipv6_address, new_udp_reuseport};
use std::fs;
use std::io;
use std::net::Ipv4Addr;
use std::sync::Arc;
@ -28,7 +29,6 @@ async fn main() -> io::Result<()> {
.required(true)
.value_name("PORT")
.help("Sets the port where Phantun Server listens for incoming Phantun Client TCP connections")
.takes_value(true),
)
.arg(
Arg::new("remote")
@ -37,7 +37,6 @@ async fn main() -> io::Result<()> {
.required(true)
.value_name("IP or HOST NAME:PORT")
.help("Sets the address or host name and port where Phantun Server forwards UDP packets to, IPv6 address need to be specified as: \"[IPv6]:PORT\"")
.takes_value(true),
)
.arg(
Arg::new("tun")
@ -46,7 +45,6 @@ async fn main() -> io::Result<()> {
.value_name("tunX")
.help("Sets the Tun interface name, if absent, pick the next available name")
.default_value("")
.takes_value(true),
)
.arg(
Arg::new("tun_local")
@ -55,7 +53,6 @@ async fn main() -> io::Result<()> {
.value_name("IP")
.help("Sets the Tun interface local address (O/S's end)")
.default_value("192.168.201.1")
.takes_value(true),
)
.arg(
Arg::new("tun_peer")
@ -66,7 +63,6 @@ async fn main() -> io::Result<()> {
You will need to setup DNAT rules to this address in order for Phantun Server \
to accept TCP traffic from Phantun Client")
.default_value("192.168.201.2")
.takes_value(true),
)
.arg(
Arg::new("ipv4_only")
@ -74,8 +70,8 @@ async fn main() -> io::Result<()> {
.short('4')
.required(false)
.help("Do not assign IPv6 addresses to Tun interface")
.takes_value(false)
.conflicts_with_all(&["tun_local6", "tun_peer6"]),
.action(ArgAction::SetTrue)
.conflicts_with_all(["tun_local6", "tun_peer6"]),
)
.arg(
Arg::new("tun_local6")
@ -83,8 +79,7 @@ async fn main() -> io::Result<()> {
.required(false)
.value_name("IP")
.help("Sets the Tun interface IPv6 local address (O/S's end)")
.default_value("fec9::1")
.takes_value(true),
.default_value("fcc9::1")
)
.arg(
Arg::new("tun_peer6")
@ -94,61 +89,74 @@ async fn main() -> io::Result<()> {
.help("Sets the Tun interface IPv6 destination (peer) address (Phantun Client's end). \
You will need to setup SNAT/MASQUERADE rules on your Internet facing interface \
in order for Phantun Client to connect to Phantun Server")
.default_value("fec9::2")
.takes_value(true),
.default_value("fcc9::2")
)
.arg(
Arg::new("handshake_packet")
.long("handshake-packet")
.required(false)
.value_name("PATH")
.help("Specify a file, which, after TCP handshake, its content will be sent as the \
first data packet to the client.\n\
Note: ensure this file's size does not exceed the MTU of the outgoing interface. \
The content is always sent out in a single packet and will not be further segmented")
)
.get_matches();
let local_port: u16 = matches
.value_of("local")
.get_one::<String>("local")
.unwrap()
.parse()
.expect("bad local port");
let remote_addr = tokio::net::lookup_host(matches.value_of("remote").unwrap())
let remote_addr = tokio::net::lookup_host(matches.get_one::<String>("remote").unwrap())
.await
.expect("bad remote address or host")
.next()
.expect("unable to resolve remote host name");
info!("Remote address is: {}", remote_addr);
let tun_local: Ipv4Addr = matches
.value_of("tun_local")
.get_one::<String>("tun_local")
.unwrap()
.parse()
.expect("bad local address for Tun interface");
let tun_peer: Ipv4Addr = matches
.value_of("tun_peer")
.get_one::<String>("tun_peer")
.unwrap()
.parse()
.expect("bad peer address for Tun interface");
let (tun_local6, tun_peer6) = if matches.is_present("ipv4_only") {
let (tun_local6, tun_peer6) = if matches.get_flag("ipv4_only") {
(None, None)
} else {
(
matches
.value_of("tun_local6")
.get_one::<String>("tun_local6")
.map(|v| v.parse().expect("bad local address for Tun interface")),
matches
.value_of("tun_peer6")
.get_one::<String>("tun_peer6")
.map(|v| v.parse().expect("bad peer address for Tun interface")),
)
};
let tun_name = matches.value_of("tun").unwrap();
let tun_name = matches.get_one::<String>("tun").unwrap();
let handshake_packet: Option<Vec<u8>> = matches
.get_one::<String>("handshake_packet")
.map(fs::read)
.transpose()?;
let num_cpus = num_cpus::get();
info!("{} cores available", num_cpus);
let tun = TunBuilder::new()
.name(tun_name) // if name is empty, then it is set by kernel.
.tap(false) // false (default): TUN, true: TAP.
.packet_info(false) // false: IFF_NO_PI, default is true.
.up() // or set it up manually using `sudo ip link set <tun-name> up`.
.address(tun_local)
.destination(tun_peer)
.try_build_mq(num_cpus)
.queues(num_cpus)
.build()
.unwrap();
if let (Some(tun_local6), Some(tun_peer6)) = (tun_local6, tun_peer6) {
@ -169,6 +177,14 @@ async fn main() -> io::Result<()> {
loop {
let sock = Arc::new(stack.accept().await);
info!("New connection: {}", sock);
if let Some(ref p) = handshake_packet {
if sock.send(p).await.is_none() {
error!("Failed to send handshake packet to remote, closing connection.");
continue;
}
debug!("Sent handshake packet to: {}", sock);
}
let packet_received = Arc::new(Notify::new());
let quit = CancellationToken::new();