This is what it cost me.
How the Idea Actually Started
I remember the first time I typed proxychains curl https://check.torproject.org and watched it work.
My traffic, invisibly rerouted. A server in another country, convinced it was talking to someone else entirely. No VPN app. No browser extension. Just a command.
I stared at the output for a while.
Then one thought crept in, the kind that doesn't leave:
The application didn't do anything. It had no idea.
How do you intercept a program's network calls without touching its source code? How does traffic get rerouted before the application even notices? I wasn't satisfied reading about it. I wanted to build it from scratch — raw bytes, no training wheels.
So the question formed:
What if I wrote something that hijacked a program's network calls and silently pushed them through Tor, without the program ever realizing what happened?
At the time, it stayed just that — a question.
From Thought to Project
The answer arrived when I stumbled across two words: LD_PRELOAD.
Linux lets you inject a shared library into any process at startup. If that library defines a function with the same name as a system call — say, connect() — the program will call your version instead of the real one. The program doesn't know. The OS doesn't warn it. It just happens.
That was the moment of validation.
Not from a person. From a mechanism in the OS that had existed for decades, quietly waiting for someone curious enough to misuse it.
That's when the question stopped being a question and became RouteX.
What RouteX Actually Does
At a high level, RouteX:
- Injects a shared library (
tord.so) into a target process usingLD_PRELOAD - Intercepts every call the program makes to
connect() - Silently connects to the local Tor daemon instead
- Negotiates a raw SOCKS5 handshake with Tor on the program's behalf
- Resolves DNS remotely inside the Tor network to prevent leaks
- Fuses the proxy socket back to the application's original file descriptor via
dup2
The application proceeds as normal.
It has no idea.
Simple.
Right?
The Lowest Point
The lowest point wasn't understanding the concept.
It was watching the application crash — silently, with no useful error — because I'd handed it a broken socket.
The dup2 call is the step where the proxy socket gets fused with the application's original file descriptor. If that goes wrong, the application doesn't get a helpful message. It just fails. Sometimes it hangs. Sometimes it segfaults. The silence is worse than the crash.
I remember staring at a terminal that had done nothing for 30 seconds, thinking:
Did it work? Did it fail? Is Tor even running? Did I corrupt the handshake?
DNS leaks were another low point. I thought I'd fixed the routing and was done. Then I realized my implementation was resolving hostnames locally before sending them to Tor — which meant every domain I was "anonymously" visiting was still visible to my ISP. The proxy worked. The privacy didn't.
Some nights the SOCKS5 handshake would return a byte I couldn't find documented anywhere. I was writing raw bytes to a socket, reading raw bytes back, trying to figure out which part of the RFC I'd misread.
That's the part nobody romanticizes about low-level networking. You are talking to the protocol directly. There is no helpful error message. There is only a byte you didn't expect.
What I Learned (The Honest Part)
Building RouteX taught me things no networking course ever could:
- LD_PRELOAD is power and danger in equal measure. You can modify a program's behavior without touching its source — but one mistake and it crashes with no trace of why.
- Protocols don't forgive. SOCKS5 expects specific bytes in a specific order. Send the wrong thing and the connection fails silently. There's no "invalid request" — only silence.
- DNS leaks are invisible until they aren't. A proxy can work perfectly and still betray you at the DNS layer. Privacy isn't a feature you get for free — it's something you have to actively build.
dup2is one of the most powerful and underexplained syscalls in Unix. Fusing file descriptors is the trick that makes the entire illusion hold together.
Most importantly:
The gap between "I know how this works conceptually" and "I have written the bytes myself" is enormous. Nothing closes it except doing the thing.
What I'm Actually Proud Of
Here's the part I don't downplay.
This was built entirely from first principles.
- No library to handle the SOCKS5 handshake for me
- No tutorial that walks through LD_PRELOAD injection step by step
- No existing project I could fork and modify
I had to read the SOCKS5 RFC. I had to understand how dynamic linkers resolve symbols at runtime. I had to figure out why dup2 was the right call — not dup — and what that distinction actually meant for a live socket.
Is it polished? No.
Did it break in ways I didn't expect? Constantly.
Does it work? Also yes.
If you're building something low-level and it feels like you're talking to the machine in a language you only half-know — that's not a sign you're in over your head. That's exactly what learning this stuff actually feels like.
Project Link
You can check out the project here:
👉 GitHub: RouteX
Happy hacking.