A resource access microsystem: a client for existing VTun servers (vtund -s) that works without a TUN/TAP device and without a system VPN. The tunnel is terminated inside the application by a userspace TCP/IP stack (lwIP); applications reach remote devices through a local SOCKS5 proxy or port forwards on 127.0.0.1.
Warning
An experimental tool, not a security product. The tunnel has no encryption and no privacy protection: all traffic, including video, passwords and the web interfaces of the devices behind it, travels in clear text, and the VTun handshake can reveal the session password to anyone who captures it. Anyone on the path (public Wi-Fi, mobile and provider networks, the Internet) can read, alter or take over the session. Use it for experiments and only over networks you trust, or inside a secure channel of your own (TLS/stunnel, an operator VPN); do not expose cameras or other devices through it on open networks. Details: docs/security.md.
- No VPN: no root, no
/dev/net/tun, no AndroidVpnService(no VPN icon) - VTun: 3.0.x servers, TCP transport,
type etherandtype tunsessions, XOR challenge response, keepalive, automatic reconnection with exponential back-off - Network: address and routes via DHCP through the tunnel (option 121, RFC 3442), IPv4, outbound connections only
- UDP relay: RTP pushed by cameras to the tunnel address reaches a local player (
--udp-relay) - Local proxy: SOCKS5
CONNECTwith optional username/password, static TCP port forwards (e.g. RTSP over TCP for video players) - Targets: embedded Linux (IP cameras, routers; ARM and MIPS, including big-endian, uClibc/musl), Android, and later an embeddable communication module
- Library first: C99 + POSIX, single-threaded, no own main loop — easy to embed
Static binaries (no dependencies) are on the releases page: latest is rebuilt from every push to main (stable file names, used below). The release title shows the VTesse version; the change history is in CHANGELOG.md.
| Platform | ARCH |
|---|---|
| OpenIPC cameras: HiSilicon, Goke, SigmaStar, other 32-bit ARM; Raspberry Pi with a 32-bit OS | arm32 |
| OpenIPC cameras: Ingenic (T31 and others); MIPS little-endian routers (MediaTek MT7621, MT7628) | mipsel |
| MIPS big-endian routers (Qualcomm Atheros ath79 and others) | mips |
| 64-bit ARM: Raspberry Pi with a 64-bit OS, Rockchip, other ARM64 boards | arm64 |
| PCs and servers | x86_64 |
Two binaries per platform: vtesse-ARCH (lwIP and TAP backends: SOCKS5 / port forwards without root, or a kernel interface with --tap) and vtesse-tap-ARCH (TAP only, about half the size). The TAP backend needs root and the tun driver (/dev/net/tun), and the hook scripts vtesse-hook.sh and vtesse-udhcpc.script.
The releases also carry the VTun server for PCs and servers, vtund-3.0.2-x86_64: the original VTun 3.0.2 with our patches (a refused login is logged with the device ID and the reason), see server/README.md. For cameras and routers vtund is built in the OpenIPC environment when needed.
All installations below read /etc/vtesse.conf (the session name is the device ID: 12 characters 0-9A-F, also used as the MAC):
cat > /etc/vtesse.conf <<EOF
host=vtun.example.org
port=5555
session=02AB34CD56EF
password=secret
EOF
chmod 600 /etc/vtesse.confOn a camera or router the ID can come from the device's own MAC instead: replace session=… with id_from=eth0 (see Device ID).
# as root; ARCH = arm32 or mipsel, see the table
ARCH=arm32
URL=https://github.com/OpenIPC/vtesse/releases/download/latest
# directories, then each file straight to its place, executable on success
mkdir -p /usr/bin /usr/share/vtesse /etc/init.d
curl -fsSL -o /usr/bin/vtesse $URL/vtesse-tap-$ARCH && chmod 755 /usr/bin/vtesse
curl -fsSL -o /usr/share/vtesse/vtesse-hook.sh $URL/vtesse-hook.sh && chmod 755 /usr/share/vtesse/vtesse-hook.sh
curl -fsSL -o /usr/share/vtesse/vtesse-udhcpc.script $URL/vtesse-udhcpc.script && chmod 755 /usr/share/vtesse/vtesse-udhcpc.script
curl -fsSL -o /etc/init.d/S99vtesse $URL/S99vtesse && chmod 755 /etc/init.d/S99vtesse
vtesse --version
# run in the foreground (Ctrl+C to stop)
vtesse --config /etc/vtesse.conf --tap --ifname vtesse0 --hook /usr/share/vtesse/vtesse-hook.shStart at boot (S99vtesse is already installed; settings can be overridden in /etc/default/vtesse):
/etc/init.d/S99vtesse start
/etc/init.d/S99vtesse statusopkg update && opkg install curl kmod-tun # kmod-tun is needed for --tap only; apk add curl kmod-tun on OpenWrt 25+
# ARCH = mipsel (MT7621, MT7628), mips (ath79), arm64 or arm32, see the table
ARCH=mipsel
URL=https://github.com/OpenIPC/vtesse/releases/download/latest
mkdir -p /usr/bin /usr/share/vtesse /etc/init.d
curl -fsSL -o /usr/bin/vtesse $URL/vtesse-tap-$ARCH && chmod 755 /usr/bin/vtesse
curl -fsSL -o /usr/share/vtesse/vtesse-hook.sh $URL/vtesse-hook.sh && chmod 755 /usr/share/vtesse/vtesse-hook.sh
curl -fsSL -o /usr/share/vtesse/vtesse-udhcpc.script $URL/vtesse-udhcpc.script && chmod 755 /usr/share/vtesse/vtesse-udhcpc.script
curl -fsSL -o /etc/init.d/vtesse $URL/vtesse.init && chmod 755 /etc/init.d/vtesse
/etc/init.d/vtesse enable && /etc/init.d/vtesse startKeenetic router (research, #32)
Not supported yet. KeeneticOS (NDMS) is closed firmware: SSH gives only the NDMS command line, no Linux shell. Own software runs only through the OPKG component, which installs Entware into /opt on a storage volume (opkg disk <volume> <installer URL>), so the router needs a USB drive or an internal storage: partition.
Tried on a Netcraze Explorer NC-1621 (Keenetic rebrand, NDMS 5.2 beta, MIPS, 128 MB RAM, small_flash): the opkg component is available and installs (components install opkg, components commit, firmware rebuilt and the router restarts), but the model has no USB and no storage: volume, and Entware on the RAM disk temp: is refused (unsuitable disk type). Next: a Keenetic with a USB port (MT7621 or arm64) and an .ipk package with vtesse-mipsel/vtesse-arm64, an Entware init script and NDMS hooks for the TAP backend.
ARCH=x86_64 # x86_64; arm64 / arm32 on a Raspberry Pi with a 64-bit / 32-bit OS
mkdir -p ~/.local/bin
curl -fsSL -o ~/.local/bin/vtesse https://github.com/OpenIPC/vtesse/releases/download/latest/vtesse-$ARCH && chmod 755 ~/.local/bin/vtesse
# no root needed: SOCKS5 on 127.0.0.1:1080 and a forward to a camera's RTSP
~/.local/bin/vtesse --config /etc/vtesse.conf --socks 1080 --forward 8554:10.78.0.10:554Android 5.0 and later, including Android TV boxes: vtesse-android.apk. No VPN permission and no VPN icon — a service with a regular notification runs the tunnel and offers SOCKS5 and port forwards on 127.0.0.1; a player such as OpenIPC Decoder or VLC opens e.g. rtsp://127.0.0.1:1551/... (camera 1 of server 1). Up to three servers with up to 8 cameras each on fixed ports. The device ID is generated on first start (long press copies it) and must be added as a session on the server. Up to three server profiles, switched with one press. See android/README.md.
make
mkdir -p ~/.config/vtesse
cat > ~/.config/vtesse/vtesse.conf <<EOF
host=vtun.example.org
port=5555
session=02AB34CD56EF
password=secret
EOF
chmod 600 ~/.config/vtesse/vtesse.conf
build/vtesse-cli --config ~/.config/vtesse/vtesse.conf --socks 1080 --forward 8554:10.78.0.10:554
curl --socks5 127.0.0.1:1080 http://10.78.0.10/
ffplay -rtsp_transport tcp rtsp://127.0.0.1:8554/streamThe session name is the device ID (12 characters 0-9A-F, also used as the MAC); credentials are read only from the configuration file.
| Document | Contents |
|---|---|
| Usage | building, vtesse-cli options, configuration file, device ID, DHCP and routes, local proxy, error messages, probe tool |
| VTun protocol | handshake, challenge response, session flags, framing, keepalive, server behaviour that affects clients, UDP |
| Architecture | layers, tunnel_ops_t, VTun client, lwIP stack, proxy and flow control, repository layout |
| Embedding | using the libraries in another application, loop integration, example |
| Security | VTun authentication weaknesses, clear-text data, local proxy exposure |
| VTun server | patched vtund builds, release binaries, patch list |
| Testing | unit tests, sanitizers, big-endian MIPS, Docker test bench and acceptance tests |
Stages and tasks are tracked as GitHub issues:
| Stage | Status | Issues |
|---|---|---|
| 0. Test bench (VTun 3.0.2 in Docker, bridge, DHCP with option 121) | ✅ Done | #1 ✅ |
1. CLI prototype on Linux: TCP + type ether + DHCP over lwIP |
✅ Done | #2 ✅ #3 ✅ #4 ✅ #5 ✅ #6 ✅ #7 ✅ #8 ✅ |
| 2. Local proxy: SOCKS5 and port forwarding | ✅ Done | #10 ✅ #11 ✅ |
| 3. Embedded Linux: ARM/MIPS cross builds, footprint, CI | ✅ Done | #12 ✅ #20 ✅ |
| 3. TAP/TUN backend (kernel interface instead of lwIP, Linux targets) | ✅ Done | #19 ✅ |
| 4. Android app (no VpnService) | ✅ Done | #13 ✅ |
| 5. Optional: UDP transport, TLS wrapper, Blowfish auth | ⏸ Deferred | #14 #15 #16 |
| 6. Reuse of the upper layers for camex | ⏸ Deferred | #17 |
| Cross-cutting: tests, license | ✅ Done | #9 ✅ #18 ✅ |
✅ — closed issue. ⏸ — deferred.
The Prosperity Public License 3.0.0: free for noncommercial use, with a 30-day trial for commercial use. See LICENSE.md for the full terms. Third-party code keeps its own license (lwIP: BSD-3-Clause).
- Questions and bug reports: GitHub Issues
- Documentation: docs/
