Research prototype for route-authorized service access through cooperative proxies.
ObfusRoute explores a simple idea: a protected service should not accept a request only because it reaches the server. It should accept it because the request followed a server-authorized route through a set of cooperative proxies.
The project implements an application-level protocol in C over TCP. A client first establishes a session with the server, requests a route, receives the first proxy and an opaque RouteToken, and then sends an application message through the proxy chain. Each proxy processes only its own route layer, learns only the next hop, and forwards the packet. The server validates the terminal route token before accepting the final message.
ObfusRoute is not a Tor implementation and does not try to provide Tor-equivalent anonymity. It is a smaller academic prototype focused on service access control and service-location obfuscation.
- Motivation
- How it works
- Architecture
- Protocol overview
- Security design
- Repository structure
- Requirements
- Build
- Run a local example
- Command-line reference
- Current capabilities
- Security and limitations
- Comparison with Tor
- Academic context
- License
Many network services are reachable through direct and easy-to-identify endpoints. Authentication can restrict who is allowed to use them, but the service location and access path may still be exposed.
ObfusRoute investigates an additional condition for access: the route itself. The server generates a valid path through cooperative proxies and later checks that the final request arrives with route material that could only have been processed along that path.
The goal is to study whether route traversal can act as an access-control signal while also reducing direct service exposure in a controlled prototype.
At a high level, ObfusRoute separates route generation, route traversal, and final validation.
flowchart LR
C[Client]
S[(Server)]
P1[Proxy 1]
P2[Proxy 2]
PN[Proxy N]
C -->|bootstrap, key exchange, route request| S
P1 -->|bootstrap and key exchange| S
P2 -->|bootstrap and key exchange| S
PN -->|bootstrap and key exchange| S
S -->|first hop and RouteToken| C
C -->|routed message| P1
P1 -->|processes its route layer| P2
P2 -->|processes its route layer| PN
PN -->|terminal route token| S
S -->|validates route and session| PN
PN -->|response relay| P2
P2 -->|response relay| P1
P1 -->|response relay| C
The client does not receive the full route. It receives the first hop and a fixed-size RouteToken. Each proxy unwraps the part encrypted for it, obtains the next hop, replaces the route token with the remaining inner token, and forwards the packet.
The server validates the terminal token using server-side state stored for the route and session. If the route is invalid, stale, malformed, or cannot be completed, the request is rejected or an OBF_MESSAGE_ERR is returned through the relay path when possible.
ObfusRoute defines three principal roles.
| Role | Responsibility |
|---|---|
| Client | Establishes a session, requests a route, and sends application payloads through the first proxy returned by the server. |
| Proxy | Registers with the server, receives route key material, processes one route-token layer, and forwards each routed message to the next hop. |
| Server | Tracks sessions and proxies, generates routes, builds route tokens, validates terminal route material, and returns the final response. |
The prototype uses one server, one client, and at least three active proxies for route generation. The minimum route length is 3 hops and the maximum route length is 16 hops.
The protocol is binary and implemented specifically for this project. Packets contain a fixed header, a mutable route-token field, and an optional payload.
| Field | Purpose |
|---|---|
version |
Protocol version, currently 0x01. |
type |
Message type such as bootstrap, key exchange, route request, or routed message. |
flags |
Control flags used by specific message families. |
SessionID |
16-byte session identifier used to associate packets with client or proxy sessions. |
RouteToken |
640-byte fixed-size route field, mutable at each proxy hop. |
payload_len |
Payload length. |
payload |
Message payload, optionally encrypted/authenticated depending on the phase. |
Main message types implemented by the protocol:
| Type | Direction | Purpose |
|---|---|---|
OBF_BOOTSTRAP_REQ / OBF_BOOTSTRAP_RES |
Client or proxy to server | Create or resume a session. |
OBF_KEYEXCHANGE_REQ / OBF_KEYEXCHANGE_RES |
Server and peer | Establish shared key material. |
OBF_ROUTE_REQ / OBF_ROUTE_RES |
Client and server | Request and receive an authorized route. |
OBF_MESSAGE_REQ / OBF_MESSAGE_RES |
Client, proxies, server | Carry the routed application message and response. |
OBF_MESSAGE_ERR |
Proxy or server back to client | Report route traversal errors when a return path exists. |
OBF_KEEP_ALIVE_REQ / OBF_KEEP_ALIVE_RES |
Peer and server | Refresh session state. |
sequenceDiagram
participant C as Client
participant P as Proxies
participant S as Server
P->>S: BOOTSTRAP_REQ + advertised IPv4 endpoint
S-->>P: BOOTSTRAP_RES + KEYEXCHANGE_REQ
P-->>S: KEYEXCHANGE_RES
C->>S: BOOTSTRAP_REQ
S-->>C: BOOTSTRAP_RES + KEYEXCHANGE_REQ
C-->>S: KEYEXCHANGE_RES
C->>S: ROUTE_REQ
S-->>C: ROUTE_RES with first hop and RouteToken
C->>P: OBF_MESSAGE_REQ through authorized route
P->>S: Final forwarded message with terminal token
S-->>P: OBF_MESSAGE_RES after terminal validation
P-->>C: Response relayed back through proxies
ObfusRoute uses modern cryptographic primitives, but it should be read as a prototype design rather than a production security system.
| Component | Use in ObfusRoute |
|---|---|
| X25519 | Establishes a shared secret between the server and each initialized client or proxy. |
| HKDF-SHA256 | Derives symmetric key material from the negotiated shared secret. |
| ChaCha20-Poly1305 | Provides authenticated encryption for protected payloads and route-token layers. |
| SQLite | Persists sessions, proxy tags, routes, route hops, and expiration metadata. |
Route enforcement is centered on the RouteToken. The server constructs it from the inside out. The innermost terminal token is encrypted for the server and binds the route to a SessionID and RouteID. Each outer proxy layer contains the next hop and the remaining inner token, encrypted with key material associated with that proxy.
The RouteToken has a fixed external size of 640 bytes. After each proxy unwraps its layer, the remaining token is padded back to the same size with random bytes. This avoids directly exposing the number of remaining hops through the token length.
| Path | Description |
|---|---|
src/client |
Client CLI, session handling, route requests, and relay-message logic. |
src/proxy |
Proxy bootstrap, forwarding, route-layer processing, and relay response handling. |
src/server |
Server state, session persistence, route generation, route validation, and SQLite storage. |
src/common |
Shared packet format, crypto, protocol helpers, buffers, logging, networking, and captures. |
test/unit |
Unit-test source files for crypto, protocol, and persistence components. |
docs |
Technical article, selected resources, and manual testing notes. |
Makefile |
Main local build file. |
compose.yaml |
Container-based local topology used for manual testing workflows. |
The verified local build path uses a Linux environment with:
| Dependency | Purpose |
|---|---|
gcc |
C compiler used by the default Makefile. |
make |
Build orchestration. |
libsqlite3-dev / SQLite development headers |
Links the server persistence layer against SQLite. |
POSIX sockets and poll(2) |
TCP networking and event handling. |
Linux getrandom(2) |
Randomness source used by the cryptographic code. |
On Debian or Ubuntu:
sudo apt update
sudo apt install build-essential libsqlite3-dev makeOn Arch Linux:
sudo pacman -S base-devel sqliteClone and build the project:
git clone https://github.com/RandallMan07/ObfusRoute.git
cd ObfusRoute
makeThe build produces four binaries in .bin/:
| Binary | Purpose |
|---|---|
.bin/obf-server |
Run the server role directly. |
.bin/obf-proxy |
Run a proxy role directly. |
.bin/obf-client |
Run the client role directly. |
.bin/obfusroute |
Dispatch to server, proxy, or client subcommands when the role binaries are on PATH. |
Install to ~/.local/bin:
make installInstall to a different prefix:
make install PREFIX=/usr/localClean build output:
make clean
make fcleanThe following example starts one server, three proxies, and one client on localhost. Three proxies are required because the route length minimum is 3 hops.
Build first:
make
mkdir -p /tmp/obfusroute-demoTerminal 1 - Server:
./.bin/obf-server -v -p 8648 -r 3 -d /tmp/obfusroute-demo/server.db --advertise-ip 127.0.0.1Terminal 2 - Proxy 1:
./.bin/obf-proxy -v -p 9001 --session-path /tmp/obfusroute-demo/proxy1.session --advertise-ip 127.0.0.1 127.0.0.1 8648Terminal 3 - Proxy 2:
./.bin/obf-proxy -v -p 9002 --session-path /tmp/obfusroute-demo/proxy2.session --advertise-ip 127.0.0.1 127.0.0.1 8648Terminal 4 - Proxy 3:
./.bin/obf-proxy -v -p 9003 --session-path /tmp/obfusroute-demo/proxy3.session --advertise-ip 127.0.0.1 127.0.0.1 8648Terminal 5 - Client:
./.bin/obf-client -v --session-path /tmp/obfusroute-demo/client.session 127.0.0.1 8648When the client waits for input, type a message and press Enter:
hello-obfusroute
Expected client output:
OBFUSROUTE_OK: request reached destination
That response means the client obtained a route, sent the message through the selected proxies, and the server accepted the final routed packet.
Common options supported by the role binaries:
| Option | Description |
|---|---|
-v, --verbose |
Increase log verbosity. Can be repeated. |
-c, --capture [path] |
Capture ObfusRoute packets to a file. |
| `--capture-format parsed | raw` |
-h, --help |
Show help. |
Server options:
| Option | Description |
|---|---|
-p, --port <port> |
Bind port. Default: 8648. |
-b, --backlog <num> |
Listen backlog. Default: 128. |
-e, --expiry <sec> |
Session expiry time. Default: 3600. |
-r, `--route-hops <n |
random>` |
-d, --database-path <path> |
SQLite database path. Default: obfusroute.db. |
-i, --poll-interval <sec> |
Server poll timeout interval. Default: 20. |
--advertise-ip <ipv4> |
IPv4 address published to peers. Default: auto-discover. |
--advertise-port <port> |
Port published to peers. Default: bind port. |
Proxy options:
| Option | Description |
|---|---|
-p, --port <port> |
Proxy listen port. Default: 8648. |
-b, --backlog <num> |
Listen backlog. Default: 128. |
-s, --session <hex> |
Session ID to try during bootstrap. |
--session-path <path> |
File used to persist the proxy session. Default: proxy.session. |
--advertise-ip <ipv4> |
IPv4 address published to the server. Default: auto-discover. |
--advertise-port <port> |
Port published to the server. Default: bind port. |
<server_ip> [server_port] |
Server endpoint used for bootstrap and key exchange. |
Client options:
| Option | Description |
|---|---|
-s, --session <hex> |
Session ID to try during bootstrap. |
--session-path <path> |
File used to persist the client session. Default: client.session. |
<server_ip> [server_port] |
Server endpoint used for bootstrap, key exchange, and route requests. |
- Application-level protocol implemented primarily in C over TCP.
- IPv4 endpoint parsing and advertisement.
- Separate
client,proxy, andserverroles. - Session creation, resumption, expiration, and persistence.
- SQLite-backed server state for sessions, proxy tags, routes, and route hops.
- Cooperative proxy routes with fixed or random route length selection.
- Configurable route length from 3 to 16 proxy hops.
- Route tokens processed hop by hop, with fixed-size random padding.
- One-use routed messages with response propagation back through the relay path.
- Parsed or raw packet capture output for debugging and manual inspection.
ObfusRoute is a research prototype. It is useful for studying protocol design, route-based access control, applied cryptography, and network-service obfuscation, but it is not production-ready.
Known limitations:
- IPv4-only operation in the current CLI and route encoding.
- No formal security proof and no independent security audit.
- Key exchange does not currently provide a complete authenticated identity model, so the design is susceptible to Man-in-the-Middle attacks during setup if deployed without additional authentication.
- The server is a central authority for sessions, route generation, route persistence, and terminal validation.
- The prototype validates the route and returns a static confirmation response; it does not yet tunnel a real application protocol such as HTTP.
SessionIDvalues are visible in packet headers, which can expose correlation metadata to observers with visibility across multiple links.- Route traversal depends on proxy availability; a missing intermediate hop prevents completion of the route.
- Testing has been focused on local and controlled environments, not large distributed deployments.
- The project does not claim Tor-equivalent anonymity, censorship resistance, traffic-analysis resistance, or production hardening.
ObfusRoute and Tor both use intermediate nodes, but they solve different problems and have different threat models.
| Dimension | ObfusRoute | Tor |
|---|---|---|
| Primary objective | Route-based access control and service-location obfuscation. | General-purpose anonymity for client traffic. |
| Network scale | Small cooperative proxy set controlled for the experiment. | Large public volunteer network. |
| Route creation | Server generates and authorizes routes for client sessions. | Client builds circuits through Tor relays. |
| Access-control model | Server validates that a request arrived through a valid route token. | Destination services generally do not validate Tor circuit membership. |
| Anonymity objective | No claim of strong anonymity. | Designed to hide client origin from destinations and observers under Tor's threat model. |
| Deployment model | Application-level prototype with custom client, proxy, and server roles. | Mature ecosystem with relays, directory authorities, clients, onion services, and tooling. |
| Intended use | Academic exploration of protected service access through cooperative routes. | Privacy-preserving Internet access and onion-service hosting. |
| Project maturity | Research prototype. | Production-grade open-source anonymity network. |
The distinction matters: ObfusRoute is not a replacement for Tor. It uses route processing as part of service authorization, whereas Tor focuses on anonymity and unlinkability at Internet scale.
ObfusRoute originated as a Computer Engineering final degree project at the Universitat Autònoma de Barcelona.
This public repository is a curated version of the implementation and selected technical material. It is published as a portfolio and open-source reference project; it should not be interpreted as official endorsement by the university.
Additional documentation:
| Document | Description |
|---|---|
docs/informe-final-v03.pdf |
English technical article/report generated from the LaTeX source. |
docs/informe-final-v03.tex |
LaTeX source for the technical article/report. |
docs/manual-testing.md |
Manual testing notes and capture workflow. |
Possible future work supported by the current design:
- Transport real application protocols over the routed channel.
- Add authenticated peer identity to strengthen the key-exchange phase.
- Improve metadata protection by reducing globally visible identifiers.
- Support persistent relays instead of one-use relay connections.
- Add dynamic proxy discovery and more advanced route selection.
- Evaluate latency, memory use, and cryptographic overhead across larger topologies.
- Expand beyond IPv4 where the packet and route-token formats permit it.
Issues and pull requests are welcome for documentation improvements, build fixes, portability work, protocol experiments, and test coverage.
Before proposing security-sensitive changes, please keep the prototype scope in mind and avoid presenting experimental changes as production guarantees.
ObfusRoute is licensed under the GNU Affero General Public License v3.0. See LICENSE for the complete terms.
SPDX-License-Identifier: AGPL-3.0-only
Copyright © 2026 Adrià Martín