Introducing gnirehtet
30 Mar 2017 (également disponible en français)I spent the last few weeks at Genymobile developing a tool providing reverse tethering for Android, so that devices may use the internet connection of the computer on which they are connected via USB, without requiring any root access (neither on the device nor on the computer). It works on GNU/Linux, Windows and Mac OS.
We decided to open source it under the name gnirehtet.
Yeah, that’s a weird name, until you realize that this is the output of this bash command:
How to use Gnirehtet
Basically, just download the latest release, extract it, and execute the following command on the computer:
./gnirehtet rt
Once activated, a “key” logo appears in your device status bar:
Check the README file of the project for more details.
How does gnirehtet work?
Gnirehtet is composed of two parts:
- an Android application (the client);
- a Java desktop application (the relay server).
Since then, I rewrote it in Rust.
The client registers itself as a VPN, in order to intercept the whole device
network traffic, as byte[]
of raw IPv4 packets, which it transmits to the
relay server over a TCP connection (established over adb).
The relay server parses the packets headers, open connections from the computer to the requested destinations, and relays the content in both directions following the UDP and TCP protocols. It creates and sends response packets back to the Android client, which writes them to the VPN interface.
In a sense, the relay server behaves like a NAT, in that it opens connections on behalf of private peers. However, it differs from standard NATs in the way it communicates with the clients (the private peers), by using a very specific (though simple) protocol over a TCP connection.
For more details, you can read the developers page.
Here are the solutions I have considered
Once the application is able to intercept the whole device network traffic, several alternative designs are possible.
TL;DR: I first considered creating a “TUN device” on the computer, but it did not suit our needs. Then I wanted to benefit from existing SOCKS servers, but some constraints prevented us to relay UDP traffic. So I implemented gnirehtet.
TUN device
During my investigations on how to implement reverse tethering, I first found
projects creating a TUN device on the computer (vpn-reverse-tether
and
SimpleRT
).
This design works very well, and has several advantages:
- it operates at network level, so there is no need for translation between level 3 and level 5 of the OSI model;
- all IP packets are tunneled, regardless of their transport protocol (so they are all supported, while gnirehtet “only” supports TCP and UDP).
However:
- it requires root access on the computer;
- it does not work on platforms other than Linux.
You could still consider using these “TUN device” applications, they may better suit your needs.
SOCKS
In order to avoid to develop a specific relay server, my first idea was to make
the client talk the SOCKS protocol (according to RFC 1928). That way, it
would be possible to use any existing SOCKS server, for instance the one
provided by ssh -D
.
You probably already used it to bypass annoying enterprise firewalls. For this purpose, just start the tunnel:
ssh my_serveur -ND1080
Then configure your browser to use the SOCKS proxy localhost:1080
. Also take
care to enable remote DNS resolution if you want to resolve domain names from
my_server
(in Firefox, enable network.proxy.socks_remote_dns
in
about:config
).
Unfortunately, the OpenSSH implementation does not support UDP, although the SOCKS5 protocol itself does. And we do need UDP, at least for DNS requests (and also NTP).
If you read carefully the two last paragraphs, you might want to ask yourself:
How may Firefox resolve domain names remotely through the OpenSSH SOCKS proxy if it does not even support UDP?
The answer lies in the section 4 of the RFC: the requested destination address may be an IPv4, an IPv6 or a domain name. However, using this feature implies that the client (e.g. Firefox) is aware of the proxy (since it must explicitly pass the domain name instead of resolving it locally), while our reverse tethering must be transparent.
But all is not lost. OK, OpenSSH does not support UDP, but this is just a
specific implementation, we could consider another one. Unfortunately, SOCKS5
requires to relay UDP over UDP, but the devices and the computer
communicate over adb (thanks to adb reverse
), which does not support UDP
port forwarding either.
Maybe we could at least relay DNS requests by forcing them to use TCP, like tsocks does:
tsocks will normally not be able to send DNS queries through a SOCKS server since SOCKS V4 works on TCP and DNS normally uses UDP. Version 1.5 and up do however provide a method to force DNS lookups to use TCP, which then makes them proxyable.
But then, SOCKS was no longer attractive to me for implementing reverse tethering.
Gnirehtet
Therefore, I developed both the client and the relay server manually.
This blog post and several open source projects (SimpleRT
,
vpn-reverse-tether
, LocalVPN
et ToyVpn
) helped me a lot to
understand how to implement this solution.
Conclusion
Gnirehtet allows Android devices to use the internet connection from a computer easily, without any root access. It helps when you can’t access the network using a WiFi access point.
I hope it will be useful to some of you.
This post was initially published on medium.
Discuss on reddit and Hacker News.