6.1 KiB
DragonTCP Full Android VPN v1
This build replaces the old HTTP-proxy-only Android design with a real layer-3 VPN packet tunnel.
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.
Architecture
Android apps
|
| IPv4 + IPv6 default routes
v
Android VpnService TUN (MTU 1280)
|
v
DragonTCP Go VPN core
|
| adaptive small records, XOR 0xAD, TCP/53
v
DragonTCP VPN server
|
v
Linux TUN dragontcp0
|
| IP 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.
Included files
bin/dragontcp-vpn-server-linux-amd64
bin/dragontcp-vpn-server-linux-arm64
android/build/DragonTCP-VPN.apk
android/lib/arm64-v8a/libdragontcp_vpn.so
core/ complete Go source
android/src/ complete Android Java source
build_core.sh
build_all.sh
android/build_apk.sh
Server requirements
The full VPN server needs root/CAP_NET_ADMIN because it creates a Linux TUN interface and enables packet forwarding/NAT.
Install the normal Linux networking tools if they are not already present:
sudo apt-get update
sudo apt-get install -y iproute2 iptables
TCP port 53 must be free.
Check:
sudo ss -lntp | grep ':53'
Start the server
sudo ./dragontcp-vpn-server-linux-amd64 \
--token 'YOUR_SECRET' \
--debug
The defaults are:
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
The server automatically enables IPv4/IPv6 forwarding and installs
MASQUERADE/forward rules with iptables/ip6tables when available.
If you manage routing/NAT yourself:
sudo ./dragontcp-vpn-server-linux-amd64 \
--token 'YOUR_SECRET' \
--auto-nat=false
To allow clients to reach private/LAN destination addresses too:
--allow-private
Debug server
Normal diagnostics:
sudo ./dragontcp-vpn-server-linux-amd64 \
--token 'YOUR_SECRET' \
--debug \
--debug-stats-interval 5s
Very verbose per-IP-packet diagnostics:
--debug-packets
Do not leave --debug-packets enabled for high-throughput use.
Android app
Install:
DragonTCP-VPN.apk
The UI is intentionally small:
Server
TCP Port
Token
Maximum fragment
Minimum fragment
Timeout
CONNECT
STOP
Live log
Defaults:
Port 53
Max 1280
Min 32
Timeout 2s
Pollers 1 (fixed)
MTU 1280 (fixed)
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:
1280 -> 640 -> 320 -> 160 -> 80 -> 40 -> 32
After sustained successful full-size records it cautiously grows again.
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.
Why Max defaults to 1280
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.
Building everything from source
Requirements:
- Go 1.22+
- JDK 17+
- Android SDK platform and build-tools
zip
No Android NDK is required in this build.
Set the SDK path:
export ANDROID_SDK_ROOT="$HOME/Android/Sdk"
Build server, Android native core, and APK:
./build_all.sh
Outputs:
bin/dragontcp-vpn-server-linux-amd64
bin/dragontcp-vpn-server-linux-arm64
android/lib/arm64-v8a/libdragontcp_vpn.so
android/build/DragonTCP-VPN.apk
Build only Go/native components:
./build_core.sh
Build only APK after the core is present:
./android/build_apk.sh
Android TUN fd handoff
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.
This avoids JNI and avoids passing an inherited descriptor through
ProcessBuilder.
Protocol packet mode
Packet mode still uses the DragonTCP request/response envelope:
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:
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:
./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.