Compare commits

...

35 Commits
v0.6.0 ... 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
24 changed files with 1501 additions and 74 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 - arm-unknown-linux-musleabihf
- aarch64-unknown-linux-gnu - aarch64-unknown-linux-gnu
- aarch64-unknown-linux-musl - aarch64-unknown-linux-musl
- mips-unknown-linux-gnu
- mips-unknown-linux-musl
- mipsel-unknown-linux-gnu
- mipsel-unknown-linux-musl
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: stable
@ -50,7 +46,7 @@ jobs:
zip phantun_${{ matrix.target }}.zip phantun_client phantun_server zip phantun_${{ matrix.target }}.zip phantun_client phantun_server
- name: Upload Github Assets - name: Upload Github Assets
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v2
with: with:
files: target/${{ matrix.target }}/release/*.zip files: target/${{ matrix.target }}/release/*.zip
prerelease: ${{ contains(github.ref, '-') }} prerelease: ${{ contains(github.ref, '-') }}

View File

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

1
.gitignore vendored
View File

@ -1,2 +1 @@
/target /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] [workspace]
resolver = "2"
members = [ members = [
"fake-tcp", "fake-tcp",
"phantun", "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 same "printed page" as the copyright notice for easier
identification within third-party archives. 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"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
MIT License 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 Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated person obtaining a copy of this software and associated

View File

@ -2,7 +2,7 @@
A lightweight and fast UDP to TCP obfuscator. 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) ![docs.rs](https://img.shields.io/docsrs/fake-tcp)
Table of Contents Table of Contents
@ -35,7 +35,7 @@ Table of Contents
# Latest release # Latest release
[v0.5.0](https://github.com/dndx/phantun/releases/tag/v0.5.0) [v0.7.0](https://github.com/dndx/phantun/releases/tag/v0.7.0)
# Overview # Overview
@ -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 Note that Phantun does not add any additional header other than IP and TCP headers in order to pass through
stateful packet inspection! 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 UDP packet is reduced by 12 bytes. This is the minimum overhead possible when doing such kind
of obfuscation. of obfuscation.
@ -368,7 +368,7 @@ Here is a quick overview of comparison between those two to help you choose:
# License # 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 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 [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] [package]
name = "fake-tcp" name = "fake-tcp"
version = "0.5.0" version = "0.6.0"
edition = "2021" edition = "2021"
authors = ["Datong Sun <dndx@idndx.com>"] authors = ["Datong Sun <dndx@idndx.com>"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
@ -16,10 +16,10 @@ benchmark = []
[dependencies] [dependencies]
bytes = "1" bytes = "1"
pnet = "0.31" pnet = "0"
tokio = { version = "1.14", features = ["full"] } tokio = { version = "1", features = ["full"] }
rand = { version = "0.8", features = ["small_rng"] } rand = { version = "0", features = ["small_rng"] }
log = "0.4" log = "0"
internet-checksum = "0.2" internet-checksum = "0"
tokio-tun = "0.7" tokio-tun = "0"
flume = "0.10" 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 same "printed page" as the copyright notice for easier
identification within third-party archives. 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"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
MIT License 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 Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated 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::collections::{HashMap, HashSet};
use std::fmt; use std::fmt;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::{
use std::sync::{Arc, RwLock}; atomic::{AtomicU32, Ordering},
Arc, RwLock,
};
use tokio::sync::broadcast; use tokio::sync::broadcast;
use tokio::sync::mpsc; use tokio::sync::mpsc;
use tokio::time; 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); let ack = self.ack.load(Ordering::Relaxed);
self.last_ack.store(ack, Ordering::Relaxed); self.last_ack.store(ack, Ordering::Relaxed);
@ -400,32 +402,50 @@ impl Stack {
/// Connects to the remote end. `None` returned means /// Connects to the remote end. `None` returned means
/// the connection attempt failed. /// the connection attempt failed.
pub async fn connect(&mut self, addr: SocketAddr) -> Option<Socket> { pub async fn connect(&mut self, addr: SocketAddr) -> Option<Socket> {
let mut rng = SmallRng::from_entropy(); let mut rng = SmallRng::from_os_rng();
let local_port: u16 = rng.gen_range(1024..65535); for local_port in rng.random_range(32768..=60999)..=60999 {
let local_addr = SocketAddr::new( let local_addr = SocketAddr::new(
if addr.is_ipv4() { if addr.is_ipv4() {
IpAddr::V4(self.local_ip) IpAddr::V4(self.local_ip)
} else { } else {
IpAddr::V6(self.local_ip6.expect("IPv6 local address undefined")) IpAddr::V6(self.local_ip6.expect("IPv6 local address undefined"))
}, },
local_port, local_port,
); );
let tuple = AddrTuple::new(local_addr, addr); let tuple = AddrTuple::new(local_addr, addr);
let (mut sock, incoming) = Socket::new( let mut sock;
self.shared.clone(),
self.shared.tun.choose(&mut rng).unwrap().clone(),
local_addr,
addr,
None,
State::Idle,
);
{ {
let mut tuples = self.shared.tuples.write().unwrap(); let mut tuples = self.shared.tuples.write().unwrap();
assert!(tuples.insert(tuple, incoming.clone()).is_none()); 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( async fn reader_task(

View File

@ -15,7 +15,7 @@ pub enum IPPacket<'p> {
V6(ipv6::Ipv6Packet<'p>), V6(ipv6::Ipv6Packet<'p>),
} }
impl<'a> IPPacket<'a> { impl IPPacket<'_> {
pub fn get_source(&self) -> IpAddr { pub fn get_source(&self) -> IpAddr {
match self { match self {
IPPacket::V4(p) => IpAddr::V4(p.get_source()), IPPacket::V4(p) => IpAddr::V4(p.get_source()),
@ -36,7 +36,7 @@ pub fn build_tcp_packet(
remote_addr: SocketAddr, remote_addr: SocketAddr,
seq: u32, seq: u32,
ack: u32, ack: u32,
flags: u16, flags: u8,
payload: Option<&[u8]>, payload: Option<&[u8]>,
) -> Bytes { ) -> Bytes {
let ip_header_len = match local_addr { let ip_header_len = match local_addr {

View File

@ -1,6 +1,6 @@
[package] [package]
name = "phantun" name = "phantun"
version = "0.6.0" version = "0.7.0"
edition = "2021" edition = "2021"
authors = ["Datong Sun <dndx@idndx.com>"] authors = ["Datong Sun <dndx@idndx.com>"]
license = "MIT OR Apache-2.0" 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. Layer 3 & Layer 4 (NAPT) firewalls/NATs.
""" """
[dependencies] [dependencies]
clap = { version = "4.0", features = ["cargo"] } clap = { version = "4", features = ["cargo"] }
socket2 = { version = "0.4", features = ["all"] } socket2 = { version = "0", features = ["all"] }
fake-tcp = { path = "../fake-tcp", version = "0.5" } fake-tcp = { path = "../fake-tcp", version = "0" }
tokio = { version = "1.14", features = ["full"] } tokio = { version = "1", features = ["full"] }
tokio-util = "0.7" tokio-util = "0"
log = "0.4" log = "0"
pretty_env_logger = "0.4" pretty_env_logger = "0"
tokio-tun = "0.7" tokio-tun = "0"
num_cpus = "1.13" num_cpus = "1"
neli = "0.6" neli = "0"
nix = "0.25" 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 same "printed page" as the copyright notice for easier
identification within third-party archives. 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"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
MIT License 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 Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated person obtaining a copy of this software and associated

View File

@ -71,7 +71,7 @@ async fn main() -> io::Result<()> {
.required(false) .required(false)
.help("Only use IPv4 address when connecting to remote") .help("Only use IPv4 address when connecting to remote")
.action(ArgAction::SetTrue) .action(ArgAction::SetTrue)
.conflicts_with_all(&["tun_local6", "tun_peer6"]), .conflicts_with_all(["tun_local6", "tun_peer6"]),
) )
.arg( .arg(
Arg::new("tun_local6") Arg::new("tun_local6")
@ -153,12 +153,11 @@ async fn main() -> io::Result<()> {
let tun = TunBuilder::new() let tun = TunBuilder::new()
.name(tun_name) // if name is empty, then it is set by kernel. .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`. .up() // or set it up manually using `sudo ip link set <tun-name> up`.
.address(tun_local) .address(tun_local)
.destination(tun_peer) .destination(tun_peer)
.try_build_mq(num_cpus) .queues(num_cpus)
.build()
.unwrap(); .unwrap();
if remote_addr.is_ipv6() { if remote_addr.is_ipv6() {

View File

@ -71,7 +71,7 @@ async fn main() -> io::Result<()> {
.required(false) .required(false)
.help("Do not assign IPv6 addresses to Tun interface") .help("Do not assign IPv6 addresses to Tun interface")
.action(ArgAction::SetTrue) .action(ArgAction::SetTrue)
.conflicts_with_all(&["tun_local6", "tun_peer6"]), .conflicts_with_all(["tun_local6", "tun_peer6"]),
) )
.arg( .arg(
Arg::new("tun_local6") Arg::new("tun_local6")
@ -152,12 +152,11 @@ async fn main() -> io::Result<()> {
let tun = TunBuilder::new() let tun = TunBuilder::new()
.name(tun_name) // if name is empty, then it is set by kernel. .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`. .up() // or set it up manually using `sudo ip link set <tun-name> up`.
.address(tun_local) .address(tun_local)
.destination(tun_peer) .destination(tun_peer)
.try_build_mq(num_cpus) .queues(num_cpus)
.build()
.unwrap(); .unwrap();
if let (Some(tun_local6), Some(tun_peer6)) = (tun_local6, tun_peer6) { if let (Some(tun_local6), Some(tun_peer6)) = (tun_local6, tun_peer6) {