Compare commits

...

54 Commits
v0.4.2 ... 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
24 changed files with 1581 additions and 121 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.4.1](https://github.com/dndx/phantun/releases/tag/v0.4.1)
[v0.7.0](https://github.com/dndx/phantun/releases/tag/v0.7.0)
# Overview
@ -73,8 +73,8 @@ It is also assumed that **Phantun Client** listens for incoming UDP packets at
(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` and `fec8::2` by default.
For **Server**, it assigns `192.168.201.2` and `fec9::2` by default. Therefore, your Kernel must have
`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.
@ -83,11 +83,11 @@ 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`/`fec8::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`/`fec9::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.
@ -166,7 +166,7 @@ table inet nat {
chain prerouting {
type nat hook prerouting priority dstnat; policy accept;
iif eth0 tcp dport 4567 dnat ip to 192.168.201.2
iif eth0 tcp dport 4567 dnat ip6 to fec9::2
iif eth0 tcp dport 4567 dnat ip6 to fcc9::2
}
}
```
@ -177,7 +177,7 @@ table inet 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 fec9::2
ip6tables -t nat -A PREROUTING -p tcp -i eth0 --dport 4567 -j DNAT --to-destination fcc9::2
```
[Back to TOC](#table-of-contents)
@ -262,7 +262,7 @@ is the following (using IPv4 below as an example):
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.
@ -329,6 +329,8 @@ 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
@ -366,7 +368,7 @@ Here is a quick overview of comparison between those two to help you choose:
# 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.2"
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")
@ -84,7 +80,6 @@ async fn main() -> io::Result<()> {
.value_name("IP")
.help("Sets the Tun interface IPv6 local address (O/S's end)")
.default_value("fcc8::1")
.takes_value(true),
)
.arg(
Arg::new("tun_peer6")
@ -95,19 +90,28 @@ 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("fcc8::2")
.takes_value(true),
)
.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")
@ -84,7 +80,6 @@ async fn main() -> io::Result<()> {
.value_name("IP")
.help("Sets the Tun interface IPv6 local address (O/S's end)")
.default_value("fcc9::1")
.takes_value(true),
)
.arg(
Arg::new("tun_peer6")
@ -95,60 +90,73 @@ 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("fcc9::2")
.takes_value(true),
)
.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();