mirror of
				https://github.com/dndx/phantun.git
				synced 2025-10-31 18:06:00 +08:00 
			
		
		
		
	Compare commits
	
		
			24 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 7f7da10b1b | ||
|  | 9d74a6bfeb | ||
|  | 9bdfd76819 | ||
|  | d1c18c64f3 | ||
|  | b42ed82147 | ||
|  | 7c3864a3ed | ||
|  | 6a39e9e9d0 | ||
|  | cedee0c699 | ||
|  | d969f0cc5d | ||
|  | 19c9f2d9f2 | ||
|  | 1252affdad | ||
|  | 141c3477f9 | ||
|  | d8dd3e65d1 | ||
|  | 66de44e32f | ||
|  | 2a37a2fc92 | ||
|  | f5aac38969 | ||
|  | 118f20f74f | ||
|  | 6a424fd43c | ||
|  | 869c79422f | ||
|  | 201da45ee8 | ||
|  | 333c6dd059 | ||
|  | 62f0278c1a | ||
|  | f436325d23 | ||
|  | 028a32d197 | 
							
								
								
									
										15
									
								
								.github/ISSUE_TEMPLATE/bug_report.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								.github/ISSUE_TEMPLATE/bug_report.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| --- | ||||
| name: Bug report | ||||
| about: Create a report to help us improve | ||||
| title: '' | ||||
| labels: '' | ||||
| assignees: '' | ||||
|  | ||||
| --- | ||||
|  | ||||
| **Describe the bug** | ||||
| A clear and concise description of what the bug is. | ||||
|  | ||||
| **Operating system** | ||||
|  | ||||
| **`tcpdump` between the server and client on Phantun's port** | ||||
							
								
								
									
										2
									
								
								.github/workflows/docker.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/docker.yml
									
									
									
									
										vendored
									
									
								
							| @@ -11,7 +11,7 @@ jobs: | ||||
|  | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v4 | ||||
|         uses: actions/checkout@v5 | ||||
|  | ||||
|       - name: Setup QEMU | ||||
|         uses: docker/setup-qemu-action@v3 | ||||
|   | ||||
							
								
								
									
										40
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										40
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							| @@ -27,7 +27,7 @@ jobs: | ||||
|           - aarch64-unknown-linux-musl | ||||
|  | ||||
|     steps: | ||||
|       - uses: actions/checkout@v4 | ||||
|       - uses: actions/checkout@v5 | ||||
|       - uses: actions-rs/toolchain@v1 | ||||
|         with: | ||||
|           toolchain: stable | ||||
| @@ -50,3 +50,41 @@ jobs: | ||||
|         with: | ||||
|           files: target/${{ matrix.target }}/release/*.zip | ||||
|           prerelease: ${{ contains(github.ref, '-') }} | ||||
|           update_existing: true | ||||
|  | ||||
|   build-mips-nightly: | ||||
|     runs-on: ubuntu-latest | ||||
|     env: | ||||
|       RUST_BACKTRACE: full | ||||
|     strategy: | ||||
|       matrix: | ||||
|         target: | ||||
|           - mips-unknown-linux-musl | ||||
|           - mips64-unknown-linux-muslabi64 | ||||
|           - mipsel-unknown-linux-musl | ||||
|  | ||||
|     steps: | ||||
|       - uses: actions/checkout@v5 | ||||
|       - uses: actions-rs/toolchain@v1 | ||||
|         with: | ||||
|           toolchain: nightly | ||||
|           override: true | ||||
|           components: rust-src | ||||
|       - uses: actions-rs/cargo@v1 | ||||
|         with: | ||||
|           use-cross: true | ||||
|           command: build | ||||
|           args: --release --target ${{ matrix.target }} -Z build-std | ||||
|       - name: Rename artifacts and compress | ||||
|         run: | | ||||
|           cd target/${{ matrix.target }}/release | ||||
|           mv client phantun_client | ||||
|           mv server phantun_server | ||||
|           zip phantun_${{ matrix.target }}_nightly.zip phantun_client phantun_server | ||||
|  | ||||
|       - name: Upload Github Assets | ||||
|         uses: softprops/action-gh-release@v2 | ||||
|         with: | ||||
|           files: target/${{ matrix.target }}/release/*.zip | ||||
|           prerelease: ${{ contains(github.ref, '-') }} | ||||
|           update_existing: true | ||||
|   | ||||
							
								
								
									
										2
									
								
								.github/workflows/rust.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/rust.yml
									
									
									
									
										vendored
									
									
								
							| @@ -11,7 +11,7 @@ jobs: | ||||
|     runs-on: ubuntu-latest | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v4 | ||||
|     - uses: actions/checkout@v5 | ||||
|     - uses: actions-rs/toolchain@v1 | ||||
|       with: | ||||
|         toolchain: stable | ||||
|   | ||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,2 +1 @@ | ||||
| /target | ||||
| Cargo.lock | ||||
|   | ||||
							
								
								
									
										1301
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										1301
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,8 +1,11 @@ | ||||
| [workspace] | ||||
|  | ||||
| resolver = "2" | ||||
| resolver = "3" | ||||
|  | ||||
| members = [ | ||||
|     "fake-tcp", | ||||
|     "phantun", | ||||
| ] | ||||
|  | ||||
| [workspace.dependencies] | ||||
| tokio = { version = "1", features = ["full"] } | ||||
| log = "0" | ||||
|   | ||||
							
								
								
									
										36
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								README.md
									
									
									
									
									
								
							| @@ -5,8 +5,7 @@ A lightweight and fast UDP to TCP obfuscator. | ||||
|  | ||||
|  | ||||
|  | ||||
| Table of Contents | ||||
| ================= | ||||
| # Table of Contents | ||||
|  | ||||
| * [Phantun](#phantun) | ||||
| * [Latest release](#latest-release) | ||||
| @@ -35,7 +34,14 @@ Table of Contents | ||||
|  | ||||
| # Latest release | ||||
|  | ||||
| [v0.6.0](https://github.com/dndx/phantun/releases/tag/v0.6.0) | ||||
| [v0.8.1](https://github.com/dndx/phantun/releases/tag/v0.8.1) | ||||
|  | ||||
| <details> | ||||
|   <summary>MIPS architecture support for Phantun</summary> | ||||
|  | ||||
|   [Rust only provides Tier 3 supports for MIPS based platforms](https://github.com/rust-lang/compiler-team/issues/648) | ||||
| since 2023. Phantun's MIPS build are therefore built using nightly Rust toolchain and provided on a best effort basis only. | ||||
| </details> | ||||
|  | ||||
| # Overview | ||||
|  | ||||
| @@ -262,7 +268,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. | ||||
|  | ||||
| @@ -276,22 +282,30 @@ 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 - IPv4 header (20 bytes) - TCP header (20 bytes) - WireGuard overhead (32 bytes) | ||||
| WireGuard MTU = Link 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) | ||||
| WireGuard MTU = Link 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: | ||||
| For example, for a network link with 1500 bytes MTU, the WireGuard interface MTU should be set as: | ||||
|  | ||||
| IPv4: `1500 - 20 - 20 - 32 = 1428 bytes` | ||||
| IPv6: `1500 - 40 - 20 - 32 = 1408 bytes` | ||||
| **IPv4:** `1500 (link MTU) - 20 - 20 - 32 = 1428 bytes` | ||||
|  | ||||
| **IPv6:** `1500 (link MTU) - 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 | ||||
| interface MTU of 1500. | ||||
|  | ||||
| Please note **Phantun can not function correctly if | ||||
| the packet size exceeds that of the link MTU**, as Phantun do not perform any IP-fragmentation | ||||
| and reassymbly. For the same reason, Phantun always sets the `DF` (Don't Fragment) bit | ||||
| in the IP header to prevent intermidiate devices performing any fragmentation on the packet. | ||||
|  | ||||
| It is also *strongly recommended* to use the same interface | ||||
| MTU for both ends of a WireGuard tunnel, or unexpected packet loss may occur and these issues are | ||||
| generally very hard to troubleshoot. | ||||
|  | ||||
| @@ -368,7 +382,7 @@ Here is a quick overview of comparison between those two to help you choose: | ||||
|  | ||||
| # License | ||||
|  | ||||
| Copyright 2021-2024 Datong Sun (dndx@idndx.com) | ||||
| Copyright 2021-2025 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 | ||||
|   | ||||
							
								
								
									
										5
									
								
								debian/cargo-checksum.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								debian/cargo-checksum.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| [source.crates-io] | ||||
| replace-with = "vendored-sources" | ||||
|  | ||||
| [source.vendored-sources] | ||||
| directory = "vendor" | ||||
							
								
								
									
										25
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| phantun (0.7.0) UNRELEASED; urgency=medium | ||||
|  | ||||
|   [ Datong Sun ] | ||||
|   * fix(fake-tcp): when `connect()`-ing, attempt to get ephemeral port using algorithm similar to Linux (#162) | ||||
|   * chore(deps): bump dependencies to latest | ||||
|   * chore(cargo): bump `fake-tcp` version to `0.6.0` and `phantun` to `0.7.0` | ||||
|  | ||||
|   [ dependabot[bot] ] | ||||
|   * chore(deps): bump docker/build-push-action from 5 to 6 | ||||
|   * chore(release): remove MIPS targets due to being downgraded to Tier 3 support by Rust | ||||
|   * docs(readme): latest release is now `v0.7.0` | ||||
|  | ||||
|   [ Randy Li ] | ||||
|   * phantun: change default tun address to link local | ||||
|   * phantun: add client and server xor support | ||||
|   * rpm: add selinux and rpm spec | ||||
|   * deb: add debian files | ||||
|  | ||||
|  -- Randy Li <ayaka@soulik.info>  Wed, 11 Dec 2024 15:30:45 +0000 | ||||
|  | ||||
| phantun (0.6.1-1) UNRELEASED; urgency=medium | ||||
|  | ||||
|   * Initial release. (Closes: #nnnn)  <nnnn is the bug number of your ITP> | ||||
|  | ||||
|  -- Randy Li <ayaka@soulik.info>  Wed, 06 Nov 2024 18:58:00 +0000 | ||||
							
								
								
									
										1
									
								
								debian/compat
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								debian/compat
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| 10 | ||||
							
								
								
									
										19
									
								
								debian/control
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								debian/control
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| Source: phantun | ||||
| Section: net | ||||
| Priority: optional | ||||
| Maintainer: Randy Li <ayaka@soulik.info> | ||||
| Build-Depends: debhelper (>= 9), cargo, rustc | ||||
| Standards-Version: 4.5.0 | ||||
| Homepage: <insert homepage here> | ||||
|  | ||||
| Package: phantun-client | ||||
| Architecture: any | ||||
| Depends: ${shlibs:Depends}, ${misc:Depends} | ||||
| Description: Phantun client | ||||
|  Phantun client binary. | ||||
|  | ||||
| Package: phantun-server | ||||
| Architecture: any | ||||
| Depends: ${shlibs:Depends}, ${misc:Depends} | ||||
| Description: Phantun server | ||||
|  Phantun server binary. | ||||
							
								
								
									
										24
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ | ||||
| Upstream-Name: phantun | ||||
| Source: https://github.com/hizukiayaka/phantun | ||||
|  | ||||
| Files: * | ||||
| Copyright: 2023, Randy Li <ayaka@soulik.info> | ||||
| License: MIT | ||||
|  Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  of this software and associated documentation files (the "Software"), to deal | ||||
|  in the Software without restriction, including without limitation the rights | ||||
|  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  copies of the Software, and to permit persons to whom the Software is | ||||
|  furnished to do so, subject to the following conditions: | ||||
|  . | ||||
|  The above copyright notice and this permission notice shall be included in all | ||||
|  copies or substantial portions of the Software. | ||||
|  . | ||||
|  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  SOFTWARE. | ||||
							
								
								
									
										6
									
								
								debian/phantun-client-wrapper
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								debian/phantun-client-wrapper
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| #!/bin/bash | ||||
| PID_FILE=$1 | ||||
| shift 1 | ||||
| mkdir -p /var/run/phantun | ||||
| /usr/libexec/phantun/phantun-client "$@" & | ||||
| echo $! > /var/run/phantun/${PID_FILE} | ||||
							
								
								
									
										2
									
								
								debian/phantun-client.install
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								debian/phantun-client.install
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| usr/libexec/phantun/phantun-client | ||||
| usr/bin/phantun-client | ||||
							
								
								
									
										6
									
								
								debian/phantun-server-wrapper
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								debian/phantun-server-wrapper
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| #!/bin/bash | ||||
| PID_FILE=$1 | ||||
| shift 1 | ||||
| mkdir -p /var/run/phantun | ||||
| /usr/libexec/phantun/phantun-server "$@" & | ||||
| echo $! > /var/run/phantun/${PID_FILE} | ||||
							
								
								
									
										2
									
								
								debian/phantun-server.install
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								debian/phantun-server.install
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| usr/libexec/phantun/phantun-server | ||||
| usr/bin/phantun-server | ||||
							
								
								
									
										35
									
								
								debian/rules
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										35
									
								
								debian/rules
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| #!/usr/bin/make -f | ||||
|  | ||||
| %: | ||||
| 	dh $@ --buildsystem=cargo | ||||
|  | ||||
| override_dh_auto_install: | ||||
| 	# Define DESTDIR | ||||
| 	DESTDIR=$(CURDIR)/debian/phantun | ||||
|  | ||||
| 	# Install client binary | ||||
| 	install -D -m 0755 target/release/client debian/tmp/usr/libexec/phantun/phantun-client | ||||
|  | ||||
| 	# Install server binary | ||||
| 	install -D -m 0755 target/release/server debian/tmp/usr/libexec/phantun/phantun-server | ||||
|      | ||||
| 	# Create wrapper scripts | ||||
| 	install -D -m 0755 debian/phantun-client-wrapper  debian/tmp/usr/bin/phantun-client | ||||
|  | ||||
| 	install -D -m 0755 debian/phantun-server-wrapper debian/tmp/usr/bin/phantun-server | ||||
|  | ||||
| 	chmod +x debian/tmp/usr/bin/phantun-client | ||||
| 	chmod +x debian/tmp/usr/bin/phantun-server | ||||
|  | ||||
| override_dh_auto_configure: | ||||
| 	cp ./debian/cargo-checksum.json ./.cargo-checksum.json | ||||
|  | ||||
| override_dh_auto_build: | ||||
| 	cargo build --release | ||||
|  | ||||
| override_dh_install: | ||||
| 	dh_install | ||||
|  | ||||
| override_dh_auto_test: | ||||
| 	# Disable the auto test step | ||||
| 	true | ||||
| @@ -25,6 +25,10 @@ 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/ | ||||
| RUN apt-get update && apt-get install -y \ | ||||
|     iproute2 \ | ||||
|     iptables \ | ||||
|     procps | ||||
|  | ||||
| ENV USE_IPTABLES_NFT_BACKEND=0 | ||||
| ENV RUST_LOG=INFO | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| #!/bin/sh | ||||
| #!/bin/bash | ||||
|  | ||||
| # alias settings must be global, and must be defined before the function being called with the alias | ||||
| if [ "$USE_IPTABLES_NFT_BACKEND" = 1 ]; then | ||||
| @@ -70,17 +70,17 @@ _is_ipv4_only() { | ||||
| } | ||||
|  | ||||
| _get_tun_from_args() { | ||||
|   local tun=$(echo "$@" | awk -F '--tun' '{print $2}' | awk '{print $1}') | ||||
|   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}') | ||||
|   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}') | ||||
|   local peer=$(echo "$@" | awk -F '--tun-peer6 ' '{print $2}' | awk '{print $1}') | ||||
|   _is_server_mode "$1" && echo ${peer:=fcc9::2} || echo ${peer:=fcc8::2} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| [package] | ||||
| name = "fake-tcp" | ||||
| version = "0.6.0" | ||||
| edition = "2021" | ||||
| version = "0.7.1" | ||||
| edition = "2024" | ||||
| authors = ["Datong Sun <dndx@idndx.com>"] | ||||
| license = "MIT OR Apache-2.0" | ||||
| repository = "https://github.com/dndx/phantun" | ||||
| @@ -17,9 +17,9 @@ benchmark = [] | ||||
| [dependencies] | ||||
| bytes = "1" | ||||
| pnet = "0" | ||||
| tokio = { version = "1", features = ["full"] } | ||||
| rand = { version = "0", features = ["small_rng"] } | ||||
| log = "0" | ||||
| internet-checksum = "0" | ||||
| tokio-tun = "0" | ||||
| flume = "0" | ||||
| tokio = { workspace = true } | ||||
| log = { workspace = true } | ||||
|   | ||||
| @@ -5,7 +5,7 @@ packet oriented tunneling with minimum overhead. | ||||
|  | ||||
| ## License | ||||
|  | ||||
| Copyright 2021 Datong Sun <dndx@idndx.com> | ||||
| Copyright 2021-2025 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 | ||||
|   | ||||
| @@ -402,8 +402,8 @@ 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(); | ||||
|         for local_port in rng.gen_range(32768..=60999)..=60999 { | ||||
|         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) | ||||
|   | ||||
| @@ -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()), | ||||
| @@ -127,7 +127,7 @@ pub fn build_tcp_packet( | ||||
|     ip_buf.freeze() | ||||
| } | ||||
|  | ||||
| pub fn parse_ip_packet(buf: &Bytes) -> Option<(IPPacket, tcp::TcpPacket)> { | ||||
| pub fn parse_ip_packet(buf: &Bytes) -> Option<(IPPacket<'_>, tcp::TcpPacket<'_>)> { | ||||
|     if buf[0] >> 4 == 4 { | ||||
|         let v4 = ipv4::Ipv4Packet::new(buf).unwrap(); | ||||
|         if v4.get_next_level_protocol() != ip::IpNextHeaderProtocols::Tcp { | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| [package] | ||||
| name = "phantun" | ||||
| version = "0.7.0" | ||||
| edition = "2021" | ||||
| version = "0.8.1" | ||||
| edition = "2024" | ||||
| authors = ["Datong Sun <dndx@idndx.com>"] | ||||
| license = "MIT OR Apache-2.0" | ||||
| repository = "https://github.com/dndx/phantun" | ||||
| @@ -14,11 +14,11 @@ Layer 3 & Layer 4 (NAPT) firewalls/NATs. | ||||
| 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"] } | ||||
| nix = { version = "0", features = ["net", "uio", "socket"] } | ||||
| tokio = { workspace = true } | ||||
| log = { workspace = true } | ||||
|   | ||||
| @@ -4,7 +4,7 @@ Client/Server crate, see [Phantun Project README.md](https://github.com/dndx/pha | ||||
|  | ||||
| ## License | ||||
|  | ||||
| Copyright 2021 Datong Sun <dndx@idndx.com> | ||||
| Copyright 2021-2025 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,11 +2,11 @@ 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 phantun::utils::{assign_ipv6_address, new_udp_reuseport, udp_recv_pktinfo}; | ||||
| use std::collections::HashMap; | ||||
| use std::fs; | ||||
| use std::io; | ||||
| use std::net::{Ipv4Addr, SocketAddr}; | ||||
| use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; | ||||
| use std::sync::Arc; | ||||
| use tokio::sync::{Notify, RwLock}; | ||||
| use tokio::time; | ||||
| @@ -156,7 +156,8 @@ async fn main() -> io::Result<()> { | ||||
|         .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() { | ||||
| @@ -174,17 +175,17 @@ async fn main() -> io::Result<()> { | ||||
|         let mut buf_r = [0u8; MAX_PACKET_LEN]; | ||||
|  | ||||
|         loop { | ||||
|             let (size, addr) = udp_sock.recv_from(&mut buf_r).await?; | ||||
|             let (size, udp_remote_addr, udp_local_addr) = udp_recv_pktinfo(&udp_sock, &mut buf_r).await?; | ||||
|             // seen UDP packet to listening socket, this means: | ||||
|             // 1. It is a new UDP connection, or | ||||
|             // 2. It is some extra packets not filtered by more specific | ||||
|             //    connected UDP socket yet | ||||
|             if let Some(sock) = connections.read().await.get(&addr) { | ||||
|             if let Some(sock) = connections.read().await.get(&udp_remote_addr) { | ||||
|                 sock.send(&buf_r[..size]).await; | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             info!("New UDP client from {}", addr); | ||||
|             info!("New UDP client from {}", udp_remote_addr); | ||||
|             let sock = stack.connect(remote_addr).await; | ||||
|             if sock.is_none() { | ||||
|                 error!("Unable to connect to remote {}", remote_addr); | ||||
| @@ -209,7 +210,7 @@ async fn main() -> io::Result<()> { | ||||
|             assert!(connections | ||||
|                 .write() | ||||
|                 .await | ||||
|                 .insert(addr, sock.clone()) | ||||
|                 .insert(udp_remote_addr, sock.clone()) | ||||
|                 .is_none()); | ||||
|             debug!("inserted fake TCP socket into connection table"); | ||||
|  | ||||
| @@ -227,8 +228,34 @@ async fn main() -> io::Result<()> { | ||||
|                 tokio::spawn(async move { | ||||
|                     let mut buf_udp = [0u8; MAX_PACKET_LEN]; | ||||
|                     let mut buf_tcp = [0u8; MAX_PACKET_LEN]; | ||||
|                     let udp_sock = new_udp_reuseport(local_addr); | ||||
|                     udp_sock.connect(addr).await.unwrap(); | ||||
|                     // Always reply from the same address that the peer used to communicate with | ||||
|                     // us. This avoids a frequent problem with IPv6 privacy extensions when we | ||||
|                     // erroneously bind to wrong short-lived temporary address even if the peer | ||||
|                     // explicitly used a persistent address to communicate to us. | ||||
|                     // | ||||
|                     // To do so, first bind to (<incoming packet dst_ip>, <local addr port>), and then | ||||
|                     // connect to (<incoming packet src_ip>, <incoming packet src_port>). | ||||
|                     let bind_addr = match (udp_remote_addr, udp_local_addr) { | ||||
|                         (SocketAddr::V4(_), IpAddr::V4(udp_local_ipv4)) => { | ||||
|                             SocketAddr::V4(SocketAddrV4::new( | ||||
|                                 udp_local_ipv4, | ||||
|                                 local_addr.port(), | ||||
|                             )) | ||||
|                         } | ||||
|                         (SocketAddr::V6(udp_remote_addr), IpAddr::V6(udp_local_ipv6)) => { | ||||
|                             SocketAddr::V6(SocketAddrV6::new( | ||||
|                                 udp_local_ipv6, | ||||
|                                 local_addr.port(), | ||||
|                                 udp_remote_addr.flowinfo(), | ||||
|                                 udp_remote_addr.scope_id(), | ||||
|                             )) | ||||
|                         } | ||||
|                         (_, _) => { | ||||
|                             panic!("unexpected family combination for udp_remote_addr={udp_remote_addr} and udp_local_addr={udp_local_addr}"); | ||||
|                         } | ||||
|                     }; | ||||
|                     let udp_sock = new_udp_reuseport(bind_addr); | ||||
|                     udp_sock.connect(udp_remote_addr).await.unwrap(); | ||||
|  | ||||
|                     loop { | ||||
|                         tokio::select! { | ||||
| @@ -244,13 +271,12 @@ async fn main() -> io::Result<()> { | ||||
|                             res = sock.recv(&mut buf_tcp) => { | ||||
|                                 match res { | ||||
|                                     Some(size) => { | ||||
|                                         if size > 0 { | ||||
|                                             if let Err(e) = udp_sock.send(&buf_tcp[..size]).await { | ||||
|                                                 error!("Unable to send UDP packet to {}: {}, closing connection", e, addr); | ||||
|                                         if size > 0 | ||||
|                                             && let Err(e) = udp_sock.send(&buf_tcp[..size]).await { | ||||
|                                                 error!("Unable to send UDP packet to {}: {}, closing connection", e, remote_addr); | ||||
|                                                 quit.cancel(); | ||||
|                                                 return; | ||||
|                                             } | ||||
|                                         } | ||||
|                                     }, | ||||
|                                     None => { | ||||
|                                         debug!("removed fake TCP socket from connections table"); | ||||
| @@ -279,14 +305,14 @@ async fn main() -> io::Result<()> { | ||||
|                     tokio::select! { | ||||
|                         _ = read_timeout => { | ||||
|                             info!("No traffic seen in the last {:?}, closing connection", UDP_TTL); | ||||
|                             connections.write().await.remove(&addr); | ||||
|                             connections.write().await.remove(&udp_remote_addr); | ||||
|                             debug!("removed fake TCP socket from connections table"); | ||||
|  | ||||
|                             quit.cancel(); | ||||
|                             return; | ||||
|                         }, | ||||
|                         _ = quit.cancelled() => { | ||||
|                             connections.write().await.remove(&addr); | ||||
|                             connections.write().await.remove(&udp_remote_addr); | ||||
|                             debug!("removed fake TCP socket from connections table"); | ||||
|                             return; | ||||
|                         }, | ||||
|   | ||||
| @@ -155,7 +155,8 @@ async fn main() -> io::Result<()> { | ||||
|         .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) { | ||||
| @@ -218,13 +219,12 @@ async fn main() -> io::Result<()> { | ||||
|                             res = sock.recv(&mut buf_tcp) => { | ||||
|                                 match res { | ||||
|                                     Some(size) => { | ||||
|                                         if size > 0 { | ||||
|                                             if let Err(e) = udp_sock.send(&buf_tcp[..size]).await { | ||||
|                                         if size > 0 | ||||
|                                             && let Err(e) = udp_sock.send(&buf_tcp[..size]).await { | ||||
|                                                 error!("Unable to send UDP packet to {}: {}, closing connection", e, remote_addr); | ||||
|                                                 quit.cancel(); | ||||
|                                                 return; | ||||
|                                             } | ||||
|                                         } | ||||
|                                     }, | ||||
|                                     None => { | ||||
|                                         quit.cancel(); | ||||
|   | ||||
| @@ -1,15 +1,21 @@ | ||||
| use neli::{ | ||||
|     consts::{ | ||||
|         nl::{NlmF, NlmFFlags}, | ||||
|         rtnl::{Ifa, IfaFFlags, RtAddrFamily, Rtm}, | ||||
|         nl::NlmF, | ||||
|         rtnl::{Ifa, IfaF, RtAddrFamily, RtScope, Rtm}, | ||||
|         socket::NlFamily, | ||||
|     }, | ||||
|     nl::{NlPayload, Nlmsghdr}, | ||||
|     rtnl::{Ifaddrmsg, Rtattr}, | ||||
|     socket::NlSocketHandle, | ||||
|     nl::{NlPayload, NlmsghdrBuilder}, | ||||
|     rtnl::{IfaddrmsgBuilder, RtattrBuilder}, | ||||
|     socket::synchronous::NlSocketHandle, | ||||
|     types::RtBuffer, | ||||
|     utils::Groups, | ||||
| }; | ||||
| use std::net::{Ipv6Addr, SocketAddr}; | ||||
| use nix::sys::socket::{ | ||||
|     CmsgIterator, ControlMessageOwned, MsgFlags, SockaddrLike, SockaddrStorage, cmsg_space, | ||||
| }; | ||||
| use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; | ||||
| use std::os::unix::io::AsRawFd; | ||||
| use tokio::io::Interest; | ||||
| use tokio::net::UdpSocket; | ||||
|  | ||||
| pub fn new_udp_reuseport(local_addr: SocketAddr) -> UdpSocket { | ||||
| @@ -27,34 +33,123 @@ pub fn new_udp_reuseport(local_addr: SocketAddr) -> UdpSocket { | ||||
|     // from tokio-rs/mio/blob/master/src/sys/unix/net.rs | ||||
|     udp_sock.set_cloexec(true).unwrap(); | ||||
|     udp_sock.set_nonblocking(true).unwrap(); | ||||
|  | ||||
|     // enable IP_PKTINFO/IPV6_PKTINFO delivery so we know the destination address of incoming | ||||
|     // packets | ||||
|     if local_addr.is_ipv4() { | ||||
|         nix::sys::socket::setsockopt(&udp_sock, nix::sys::socket::sockopt::Ipv4PacketInfo, &true) | ||||
|             .unwrap(); | ||||
|     } else { | ||||
|         nix::sys::socket::setsockopt( | ||||
|             &udp_sock, | ||||
|             nix::sys::socket::sockopt::Ipv6RecvPacketInfo, | ||||
|             &true, | ||||
|         ) | ||||
|         .unwrap(); | ||||
|     } | ||||
|  | ||||
|     udp_sock.bind(&socket2::SockAddr::from(local_addr)).unwrap(); | ||||
|     let udp_sock: std::net::UdpSocket = udp_sock.into(); | ||||
|     udp_sock.try_into().unwrap() | ||||
| } | ||||
|  | ||||
| /// Similiar to `UdpSocket::recv_from()`, but returns a 3rd value `IPAddr` | ||||
| /// which corresponds to where the UDP datagram was destined to, this is useful | ||||
| /// for disambigous when socket can receive on multiple IP address | ||||
| /// or interfaces. | ||||
| pub async fn udp_recv_pktinfo( | ||||
|     sock: &UdpSocket, | ||||
|     buf: &mut [u8], | ||||
| ) -> std::io::Result<(usize, SocketAddr, IpAddr)> { | ||||
|     sock.async_io(Interest::READABLE, || { | ||||
|         const CONTROL_MESSAGE_BUFFER_SIZE: usize = max_usize( | ||||
|             cmsg_space::<nix::libc::in_pktinfo>(), | ||||
|             cmsg_space::<nix::libc::in6_pktinfo>(), | ||||
|         ); | ||||
|         let mut control_message_buffer = [0u8; CONTROL_MESSAGE_BUFFER_SIZE]; | ||||
|         let iov = &mut [std::io::IoSliceMut::new(buf)]; | ||||
|         let res = nix::sys::socket::recvmsg::<SockaddrStorage>( | ||||
|             sock.as_raw_fd(), | ||||
|             iov, | ||||
|             Some(&mut control_message_buffer), | ||||
|             MsgFlags::empty(), | ||||
|         )?; | ||||
|  | ||||
|         let src_addr = res.address.expect("missing source address"); | ||||
|         let src_addr: SocketAddr = { | ||||
|             if let Some(inaddr) = src_addr.as_sockaddr_in() { | ||||
|                 SocketAddrV4::new(inaddr.ip(), inaddr.port()).into() | ||||
|             } else if let Some(in6addr) = src_addr.as_sockaddr_in6() { | ||||
|                 SocketAddrV6::new( | ||||
|                     in6addr.ip(), | ||||
|                     in6addr.port(), | ||||
|                     in6addr.flowinfo(), | ||||
|                     in6addr.scope_id(), | ||||
|                 ) | ||||
|                 .into() | ||||
|             } else { | ||||
|                 panic!("unexpected source address family {:#?}", src_addr.family()); | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         let dst_addr = dst_addr_from_cmsgs(res.cmsgs()?).expect("didn't receive pktinfo"); | ||||
|  | ||||
|         Ok((res.bytes, src_addr, dst_addr)) | ||||
|     }) | ||||
|     .await | ||||
| } | ||||
|  | ||||
| fn dst_addr_from_cmsgs(cmsgs: CmsgIterator) -> Option<IpAddr> { | ||||
|     for cmsg in cmsgs { | ||||
|         if let ControlMessageOwned::Ipv4PacketInfo(pktinfo) = cmsg { | ||||
|             return Some(Ipv4Addr::from(pktinfo.ipi_addr.s_addr.to_ne_bytes()).into()); | ||||
|         } | ||||
|         if let ControlMessageOwned::Ipv6PacketInfo(pktinfo) = cmsg { | ||||
|             return Some(Ipv6Addr::from(pktinfo.ipi6_addr.s6_addr).into()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     None | ||||
| } | ||||
|  | ||||
| pub fn assign_ipv6_address(device_name: &str, local: Ipv6Addr, peer: Ipv6Addr) { | ||||
|     let index = nix::net::if_::if_nametoindex(device_name).unwrap(); | ||||
|  | ||||
|     let mut rtnl = NlSocketHandle::connect(NlFamily::Route, None, &[]).unwrap(); | ||||
|     let rtnl = NlSocketHandle::connect(NlFamily::Route, None, Groups::empty()).unwrap(); | ||||
|     let mut rtattrs = RtBuffer::new(); | ||||
|     rtattrs.push(Rtattr::new(None, Ifa::Local, &local.octets()[..]).unwrap()); | ||||
|     rtattrs.push(Rtattr::new(None, Ifa::Address, &peer.octets()[..]).unwrap()); | ||||
|  | ||||
|     let ifaddrmsg = Ifaddrmsg { | ||||
|         ifa_family: RtAddrFamily::Inet6, | ||||
|         ifa_prefixlen: 128, | ||||
|         ifa_flags: IfaFFlags::empty(), | ||||
|         ifa_scope: 0, | ||||
|         ifa_index: index as i32, | ||||
|         rtattrs, | ||||
|     }; | ||||
|     let nl_header = Nlmsghdr::new( | ||||
|         None, | ||||
|         Rtm::Newaddr, | ||||
|         NlmFFlags::new(&[NlmF::Request]), | ||||
|         None, | ||||
|         None, | ||||
|         NlPayload::Payload(ifaddrmsg), | ||||
|     rtattrs.push( | ||||
|         RtattrBuilder::default() | ||||
|             .rta_type(Ifa::Local) | ||||
|             .rta_payload(&local.octets()[..]) | ||||
|             .build() | ||||
|             .unwrap(), | ||||
|     ); | ||||
|     rtnl.send(nl_header).unwrap(); | ||||
|     rtattrs.push( | ||||
|         RtattrBuilder::default() | ||||
|             .rta_type(Ifa::Address) | ||||
|             .rta_payload(&peer.octets()[..]) | ||||
|             .build() | ||||
|             .unwrap(), | ||||
|     ); | ||||
|  | ||||
|     let ifaddrmsg = IfaddrmsgBuilder::default() | ||||
|         .ifa_family(RtAddrFamily::Inet6) | ||||
|         .ifa_prefixlen(128) | ||||
|         .ifa_flags(IfaF::empty()) | ||||
|         .ifa_scope(RtScope::Universe) | ||||
|         .ifa_index(index) | ||||
|         .rtattrs(rtattrs) | ||||
|         .build() | ||||
|         .unwrap(); | ||||
|     let nl_header = NlmsghdrBuilder::default() | ||||
|         .nl_type(Rtm::Newaddr) | ||||
|         .nl_flags(NlmF::REQUEST) | ||||
|         .nl_payload(NlPayload::Payload(ifaddrmsg)) | ||||
|         .build() | ||||
|         .unwrap(); | ||||
|     rtnl.send(&nl_header).unwrap(); | ||||
| } | ||||
|  | ||||
| const fn max_usize(a: usize, b: usize) -> usize { | ||||
|     if a > b { a } else { b } | ||||
| } | ||||
|   | ||||
							
								
								
									
										128
									
								
								rpm/phantun.spec
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								rpm/phantun.spec
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,128 @@ | ||||
| Name:         	phantun  | ||||
| Version:        0.7.0 | ||||
| Release:        2%{?dist} | ||||
| Summary:        A lightweight and fast UDP to TCP obfuscator | ||||
|  | ||||
| License:        Apache-2.0 | ||||
| URL:            https://github.com/dndx/phantun/tree/main | ||||
| Source0:        %{name}-%{version}.tar.gz | ||||
|  | ||||
| BuildRequires:  rust | ||||
| BuildRequires:  cargo | ||||
| BuildRequires:  selinux-policy-devel | ||||
|  | ||||
| %description | ||||
| Your project with client and server components. | ||||
|  | ||||
| %package client | ||||
| Summary:        Client component of phantun | ||||
| Requires: (%{name}-selinux if selinux-policy-%{selinuxtype}) | ||||
|  | ||||
| %description client | ||||
| 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. | ||||
|  | ||||
| %package server | ||||
| Summary:        Server component of phantun | ||||
| Requires: (%{name}-selinux if selinux-policy-%{selinuxtype}) | ||||
|  | ||||
| %description server | ||||
| 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. | ||||
|  | ||||
| %package selinux | ||||
| Summary:        SELinux module for phantun | ||||
| %{?selinux_requires} | ||||
| %global modulename phantun | ||||
| %global selinuxtype targeted | ||||
|  | ||||
| %description selinux | ||||
| This package provides the SELinux policy module to ensure phantun | ||||
| runs properly under an environment with SELinux enabled. | ||||
|  | ||||
| %global debug_package %{nil} | ||||
|  | ||||
| %prep | ||||
| %setup -q | ||||
|  | ||||
| %build | ||||
| cargo build --release | ||||
| make -C selinux | ||||
|  | ||||
| %install | ||||
| # Install binaries | ||||
| install -D -m 0755 target/release/client %{buildroot}/usr/libexec/phantun/phantun-client | ||||
| install -D -m 0755 target/release/server %{buildroot}/usr/libexec/phantun/phantun-server | ||||
|  | ||||
| mkdir -p %{buildroot}/usr/bin | ||||
| # Create wrapper scripts | ||||
| echo '#!/bin/bash | ||||
| PID_FILE=$1 | ||||
| shift 1 | ||||
| mkdir -p /var/run/phantun | ||||
| /usr/libexec/phantun/phantun-client "$@" & | ||||
| echo $! > /var/run/phantun/${PID_FILE}' > %{buildroot}/usr/bin/phantun-client | ||||
|  | ||||
| echo '#!/bin/bash | ||||
| PID_FILE=$1 | ||||
| shift 1 | ||||
| mkdir -p /var/run/phantun | ||||
| /usr/libexec/phantun/phantun-server "$@" & | ||||
| echo $! > /var/run/phantun/${PID_FILE}' > %{buildroot}/usr/bin/phantun-server | ||||
|  | ||||
| # Make wrapper scripts executable | ||||
| chmod +x %{buildroot}/usr/bin/phantun-client | ||||
| chmod +x %{buildroot}/usr/bin/phantun-server | ||||
|  | ||||
| # SELinux | ||||
| install -d %{buildroot}%{_datadir}/selinux/packages/%{selinuxtype} | ||||
| install -m 0644 selinux/%{modulename}.pp.bz2 %{buildroot}%{_datadir}/selinux/packages/%{selinuxtype} | ||||
|  | ||||
| %pre selinux | ||||
| %selinux_relabel_pre -s %{selinuxtype} | ||||
|  | ||||
| %post selinux | ||||
| %selinux_modules_install -s %{selinuxtype} %{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}.pp.bz2 | ||||
|  | ||||
| %postun selinux | ||||
| if [ $1 -eq 0 ]; then | ||||
|     %selinux_modules_uninstall -s %{selinuxtype} %{modulename} | ||||
| fi | ||||
|  | ||||
| %posttrans selinux | ||||
| %selinux_relabel_post -s %{selinuxtype} | ||||
|  | ||||
| %files client | ||||
| /usr/libexec/phantun/phantun-client | ||||
| /usr/bin/phantun-client | ||||
|  | ||||
| %files server | ||||
| /usr/libexec/phantun/phantun-server | ||||
| /usr/bin/phantun-server | ||||
|  | ||||
| %files selinux | ||||
| %{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}.pp.bz2 | ||||
|  | ||||
| %changelog | ||||
| * Wed Dec 11 2024 Randy Li <ayaka@soulik.info> - 0.7.0-2 | ||||
| - chore(deps): update tokio-tun requirement from 0.9 to 0.11 | ||||
| - chore(deps): update nix requirement from 0.27 to 0.28 | ||||
| - chore(deps): bump softprops/action-gh-release from 1 to 2 | ||||
| - chore(docs): update license year to 2024 | ||||
| - docs(readme): update `README.md` to include incoming interface (`-i tun0`) in client NAT commands example (#163) | ||||
| - Revert "docs(readme): update `README.md` to include incoming interface (`-i t…" | ||||
| - fix(fake-tcp): when `connect()`-ing, attempt to get ephemeral port using algorithm similar to Linux (#162) | ||||
| - chore(deps): bump dependencies to latest | ||||
| - chore(cargo): bump `fake-tcp` version to `0.6.0` and `phantun` to `0.7.0` | ||||
| - chore(deps): bump docker/build-push-action from 5 to 6 | ||||
| - chore(release): remove MIPS targets due to being downgraded to Tier 3 support by Rust | ||||
| - docs(readme): latest release is now `v0.7.0` | ||||
|  | ||||
| * Sat Oct 14 2023 Randy Li <ayaka@soulik.info> - 0.6.1-1 | ||||
| - Initial package | ||||
|  | ||||
							
								
								
									
										26
									
								
								selinux/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								selinux/Makefile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| TARGET?=phantun | ||||
| MODULES?=${TARGET:=.pp.bz2} | ||||
| SHAREDIR?=/usr/share | ||||
|  | ||||
| all: ${TARGET:=.pp.bz2} | ||||
|  | ||||
| %.pp.bz2: %.pp | ||||
| 	@echo Compressing $^ -\> $@ | ||||
| 	bzip2 -9 $^ | ||||
|  | ||||
| %.pp: %.te | ||||
| 	make -f ${SHAREDIR}/selinux/devel/Makefile $@ | ||||
|  | ||||
| clean: | ||||
| 	rm -f *~  *.tc *.pp *.pp.bz2 | ||||
| 	rm -rf tmp *.tar.gz | ||||
|  | ||||
| man: install-policy | ||||
| 	sepolicy manpage --path . --domain ${TARGET}_t | ||||
|  | ||||
| install-policy: all | ||||
| 	semodule -i ${TARGET}.pp.bz2 | ||||
|  | ||||
| install: man | ||||
| 	install -D -m 644 ${TARGET}.pp.bz2 ${DESTDIR}${SHAREDIR}/selinux/packages/${TARGET}.pp.bz2 | ||||
| 	install -D -m 644 ${TARGET}_selinux.8 ${DESTDIR}${SHAREDIR}/man/man8/ | ||||
							
								
								
									
										5
									
								
								selinux/phantun.fc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								selinux/phantun.fc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| /usr/libexec/phantun/phantun-client -- gen_context(system_u:object_r:phantun_client_exec_t,s0) | ||||
| /usr/libexec/phantun/phantun-server -- gen_context(system_u:object_r:phantun_server_exec_t,s0) | ||||
| /usr/bin/phantun-client -- gen_context(system_u:object_r:wireguard_exec_t,s0) | ||||
| /usr/bin/phantun-server -- gen_context(system_u:object_r:wireguard_exec_t,s0) | ||||
| /var/run/phantun(/.*)? gen_context(system_u:object_r:phantun_var_run_t,s0) | ||||
							
								
								
									
										60
									
								
								selinux/phantun.te
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								selinux/phantun.te
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| policy_module(phantun, 1.0) | ||||
|  | ||||
| gen_require(` | ||||
|     type wireguard_t; | ||||
|     type wireguard_exec_t; | ||||
|     class capability net_admin; | ||||
|     class tun_socket { append bind connect create getattr getopt ioctl lock read relabelfrom relabelto setattr setopt shutdown write }; | ||||
|     class tcp_socket { name_bind listen accept connect }; | ||||
|     class udp_socket { name_bind }; | ||||
|     class file { getattr open read write create unlink execute }; | ||||
|     class process { transition }; | ||||
| ') | ||||
|  | ||||
|  | ||||
| # Define custom types | ||||
| type phantun_server_exec_t; | ||||
| type phantun_client_exec_t; | ||||
| type phantun_server_port_t; | ||||
| type phantun_client_port_t; | ||||
| type phantun_var_run_t; | ||||
|  | ||||
| # Allow the wrapper scripts to execute the phantun client and server binaries | ||||
| allow wireguard_exec_t phantun_client_exec_t:file { getattr open read execute }; | ||||
| allow wireguard_exec_t phantun_server_exec_t:file { getattr open read execute }; | ||||
|  | ||||
| # Allow the wrapper scripts to write to the PID file | ||||
| allow wireguard_exec_t phantun_var_run_t:file { getattr open read write create unlink }; | ||||
| allow wireguard_t self:process transition; | ||||
|  | ||||
| #################################### | ||||
| # Server | ||||
| # | ||||
|  | ||||
| # Allow wireguard_t to execute the server binary | ||||
| allow wireguard_t phantun_server_exec_t:file { getattr open read execute }; | ||||
|  | ||||
| # Allow the server to create and manage tun devices | ||||
| allow phantun_server_exec_t self:tun_socket { append bind connect create getattr getopt ioctl lock read relabelfrom relabelto setattr setopt shutdown write }; | ||||
|  | ||||
| # Allow the server to bind to the custom TCP port and listen for incoming connections | ||||
| allow phantun_server_exec_t phantun_server_port_t:tcp_socket { name_bind listen accept }; | ||||
|  | ||||
| # Allow the server to use net_admin capability | ||||
| allow phantun_server_exec_t self:capability net_admin; | ||||
|  | ||||
| #################################### | ||||
| # Client | ||||
| # | ||||
|  | ||||
| # Allow wireguard_t to execute the client binary | ||||
| allow wireguard_t phantun_client_exec_t:file { getattr open read execute }; | ||||
|  | ||||
| # Allow the client to create and manage tun devices | ||||
| allow phantun_client_exec_t self:tun_socket { append bind connect create getattr getopt ioctl lock read relabelfrom relabelto setattr setopt shutdown write }; | ||||
|  | ||||
| # Allow the client to bind to the custom UDP port | ||||
| #allow phantun_client_exec_t phantun_client_port_t:udp_socket { name_bind }; | ||||
|  | ||||
| # Allow the client to use net_admin capability | ||||
| allow phantun_client_exec_t self:capability net_admin; | ||||
		Reference in New Issue
	
	Block a user