This commit is contained in:
2026-08-16 02:50:24 -03:00
parent 6dac260155
commit 5621de243a
8 changed files with 628 additions and 353 deletions
+114 -157
View File
@@ -1,13 +1,21 @@
# DragonTCP Full Android VPN v1
# DragonTCP VPN v3
This build replaces the old HTTP-proxy-only Android design with a real layer-3
VPN packet tunnel.
DragonTCP v3 is a real Android layer-3 VPN over DragonTCP's adaptive XOR-framed
TCP transport. It captures IPv4 and IPv6 through Android `VpnService`, passes
the TUN file descriptor to the Go core, and transfers raw IP packets to a Linux
DragonTCP server listening on TCP/53.
It does **not** use the uploaded `jni.zip` and does not depend on HEV or any
other tun2socks binary. The Android `VpnService` TUN file descriptor is passed
directly to the DragonTCP Go core with Unix `SCM_RIGHTS`, and the Go core moves
raw IPv4/IPv6 packets through DragonTCP's adaptive, XOR-framed TCP/53
transport.
This release fixes two important problems from the previous packet-VPN build:
1. Android can emit IPv6 link-local/control packets such as `fe80::...` on the
VPN TUN. Those packets no longer terminate the DragonTCP session. The client
drops packets whose source is not the assigned DragonTCP VPN address, and the
server independently treats source-mismatch/control packets as non-fatal
drops.
2. The DragonTCP transport chunk ceiling is restored to **1 MiB (1,048,576
bytes)**. Raw IP packets remain limited to 65,535 bytes, but multiple TUN
packets are batched into transfer objects up to 1 MiB so chunk sizes above
the VPN MTU are actually useful.
## Architecture
@@ -18,59 +26,58 @@ Android apps
v
Android VpnService TUN (MTU 1280)
|
| raw IPv4/IPv6 packets
v
DragonTCP Go VPN core
DragonTCP Android Go core
|
| adaptive small records, XOR 0xAD, TCP/53
| packet batching (up to 1 MiB transfer objects)
| adaptive fragmentation 32 B .. 1 MiB
| XOR 0xAD framing
v
DragonTCP VPN server
TCP/53
|
v
DragonTCP Linux server
|
v
Linux TUN dragontcp0
|
| IP forwarding + NAT
| forwarding / NAT
v
Internet
```
Because complete IP packets are tunneled, this carries TCP, UDP, DNS, ICMP,
IPv4 and IPv6. Applications do not need HTTP or SOCKS proxy support.
Because the tunnel carries raw IP packets, it can carry TCP, UDP, DNS, ICMP,
IPv4 and IPv6. It does not depend on applications supporting an HTTP proxy.
## Included files
```text
bin/dragontcp-vpn-server-linux-amd64
bin/dragontcp-vpn-server-linux-arm64
bin/dragontcp-vpn-client-linux-amd64 # test/debug client
android/build/DragonTCP-VPN.apk
android/lib/arm64-v8a/libdragontcp_vpn.so
core/ complete Go source
android/src/ complete Android Java source
core/ # complete Go source
android/src/ # complete Android Java source
build_core.sh
build_all.sh
android/build_apk.sh
```
## Server requirements
## Server
The full VPN server needs root/CAP_NET_ADMIN because it creates a Linux TUN
interface and enables packet forwarding/NAT.
The server needs root or equivalent CAP_NET_ADMIN permissions because it
creates a Linux TUN and configures forwarding/NAT.
Install the normal Linux networking tools if they are not already present:
Install networking tools on Debian/Ubuntu if needed:
```bash
sudo apt-get update
sudo apt-get install -y iproute2 iptables
```
TCP port 53 must be free.
Check:
```bash
sudo ss -lntp | grep ':53'
```
## Start the server
Start:
```bash
sudo ./dragontcp-vpn-server-linux-amd64 \
@@ -78,130 +85,125 @@ sudo ./dragontcp-vpn-server-linux-amd64 \
--debug
```
The defaults are:
Defaults:
```text
listen 0.0.0.0:53/TCP
TUN dragontcp0
TUN MTU 1280
server IPv4 10.123.0.1/16
server IPv6 fd7a:4472:6167:6f6e::1/64
maximum fragment 65535 bytes
poll wait 100ms
auto NAT enabled
private targets blocked
listen TCP port 53
server chunk max 1048576 bytes (1 MiB)
transfer batch max 1048576 bytes (1 MiB)
batch delay 1ms
TUN MTU 1280
server IPv4 10.123.0.1/16
server IPv6 fd7a:4472:6167:6f6e::1/64
poll wait 100ms
queued packet limit 2048/client
queued byte limit 8 MiB/client
auto NAT enabled
```
The server automatically enables IPv4/IPv6 forwarding and installs
MASQUERADE/forward rules with `iptables`/`ip6tables` when available.
If you manage routing/NAT yourself:
```bash
sudo ./dragontcp-vpn-server-linux-amd64 \
--token 'YOUR_SECRET' \
--auto-nat=false
```
To allow clients to reach private/LAN destination addresses too:
```bash
--allow-private
```
## Debug server
Normal diagnostics:
Useful explicit command:
```bash
sudo ./dragontcp-vpn-server-linux-amd64 \
--token 'YOUR_SECRET' \
--chunk-max 1048576 \
--vpn-buffer-bytes 8388608 \
--batch-delay 1ms \
--debug \
--debug-stats-interval 5s
```
Very verbose per-IP-packet diagnostics:
Per-packet/batch diagnostics are very verbose:
```bash
--debug-packets
```
Do not leave `--debug-packets` enabled for high-throughput use.
## Android app
Install:
Install `android/build/DragonTCP-VPN.apk`.
```text
DragonTCP-VPN.apk
```
The UI is intentionally small:
The UI asks for:
```text
Server
TCP Port
TCP port
Token
Maximum fragment
Minimum fragment
Maximum transport fragment
Minimum transport fragment
Timeout
CONNECT
STOP
Live log
```
Defaults:
```text
Port 53
Max 1280
Max 1048576
Min 32
Timeout 2s
Pollers 1 (fixed)
MTU 1280 (fixed)
VPN MTU 1280
```
The starting DragonTCP record size is always the configured maximum. On a
transport failure the client automatically reduces it. With Max=1280 and
Min=32 the reduction path can converge approximately as:
The adaptive record starts at Max and shrinks after transport failures. The
1 MiB value is a DragonTCP transport ceiling, not the IP MTU.
### Why 1 MiB can now help even though the VPN MTU is 1280
The old packet-VPN sent one TUN packet per DragonTCP transfer object, so a
record size larger than the IP packet had no benefit. v3 batches adjacent TUN
packets for a short window:
```text
1280 -> 640 -> 320 -> 160 -> 80 -> 40 -> 32
1280-byte packet --+
1280-byte packet ---+
1280-byte packet ----+--> one DragonTCP transfer object --> adaptive fragments
... |
1280-byte packet ----+
```
After sustained successful full-size records it cautiously grows again.
A busy flow can therefore produce transfer objects much larger than 65,535
bytes. If the network accepts large DragonTCP records, fewer transactions are
needed. If it does not, the same transfer object is automatically fragmented
into smaller records and retried.
The app assigns itself a stable private DragonTCP VPN IPv4/IPv6 pair on first
run. The DragonTCP app UID itself is excluded from the VPN so the TCP/53
transport cannot recursively enter its own TUN interface.
## Android link-local source fix
## Why Max defaults to 1280
A log such as this from the previous build:
This version transports IP packets, not an HTTP byte stream. The Android VPN
MTU is 1280, so an individual IP packet normally cannot exceed 1280 bytes.
The UI still accepts larger DragonTCP record ceilings up to 65535, but there
is usually no throughput benefit unless the VPN MTU is raised too.
```text
VPN stopped: source fe80::... does not match session address
```
## Building everything from source
is no longer fatal.
The Android core now logs an occasional line such as:
```text
VPN DROP local packet (source fe80::... is not assigned VPN address) dropped=1
```
and continues running. The server also performs a non-fatal drop as a second
line of defense.
## Build from source
Requirements:
- Go 1.22+
- JDK 17+
- Android SDK platform and build-tools
- `zip`
- Android SDK platform/build-tools
- zip
No Android NDK is required in this build.
No Android NDK is required for this build.
Set the SDK path:
Set the SDK directory:
```bash
export ANDROID_SDK_ROOT="$HOME/Android/Sdk"
```
Build server, Android native core, and APK:
Build native components and APK:
```bash
./build_all.sh
@@ -216,76 +218,31 @@ android/lib/arm64-v8a/libdragontcp_vpn.so
android/build/DragonTCP-VPN.apk
```
Build only Go/native components:
Build only the Go/native components:
```bash
./build_core.sh
```
Build only APK after the core is present:
Build only the APK after the native core exists:
```bash
./android/build_apk.sh
cd android
./build_apk.sh
```
## Android TUN fd handoff
## Testing performed
The Android service creates the VPN using `VpnService.Builder.establish()`.
It then sends that TUN file descriptor to the Go child over a private Unix
socket using Android `LocalSocket.setFileDescriptorsForSend()`. The Go side
receives the descriptor with `SCM_RIGHTS` and directly reads/writes IP
packets.
The Go packages compile with `go test ./...`.
This avoids JNI and avoids passing an inherited descriptor through
`ProcessBuilder`.
A local mock-TUN test verified:
## Protocol packet mode
- an IPv6 `fe80::` source packet is dropped without terminating the client;
- a valid packet immediately afterward still passes;
- 120 IPv4 packets were combined into a **120,241-byte transfer object**,
proving that transfer objects larger than 65,535 bytes work;
- the echoed packets were returned byte-for-byte and in order;
- the same path also works with a fixed **32-byte DragonTCP fragment size**.
Packet mode still uses the DragonTCP request/response envelope:
```text
request : UP + request-id + length + XOR(payload)
response : OK + request-id + length + XOR(payload)
```
The VPN payload protocol is binary rather than text to reduce overhead on very
small records.
Commands include:
```text
VOPEN
VPUSH fragment
VPULL fragment
VCLOSE
```
A random 128-bit session ID is used after authenticated session creation.
Packets and fragments have sequence/offset fields so retries do not duplicate
bytes.
## Test mode
For protocol testing without root/TUN/NAT, the server has:
```bash
./dragontcp-vpn-server-linux-amd64 \
--host 127.0.0.1 \
--port 19053 \
--token test \
--mock-echo
```
This echoes complete IP packets back to the client instead of forwarding them
to the Internet.
During development the packet path was tested with IPv4 and IPv6 1280-byte
packets while the server forced a 32-byte maximum DragonTCP fragment. Both
were reassembled byte-for-byte correctly.
## Security
XOR 0xAD remains protocol obfuscation, not cryptographic encryption. HTTPS
and other TLS-based application protocols retain their own end-to-end
security, but the DragonTCP transport itself should not be considered
cryptographically confidential.
A physical Android phone is still required to validate device/vendor-specific
`VpnService` behavior and the real mobile-network TCP/53 path.