Gnirehtet
30 Mar 2017 (also available in English)Durant ces dernières semaines chez Genymobile, j’ai développé un outil de reverse tethering pour Android, permettant aux téléphones (et aux tablettes) d’utiliser la connexion internet de l’ordinateur sur lequel ils sont branchés en USB, sans accès root (ni sur le téléphone, ni sur le PC). Il fonctionne sur GNU/Linux, Windows et Mac OS.
Nous avons décidé de le publier en open source, sous le nom de gnirehtet.
Oui, c’est un nom bizarre, jusqu’à ce qu’on réalise qu’il s’agit du résultat de la commande bash :
Utilisation
Il suffit de télécharger la dernière release, de l’extraire, et d’exécuter la commande suivante sur le PC :
./gnirehtet rt
Une fois activé, un logo en forme de clé apparaît dans la barre de statut du téléphone :
Lisez le fichier README pour plus de détails.
Fonctionnement
Le projet est composé de deux parties :
- une application Android (le client) ;
- une application Java pour le PC (le serveur relais).
Depuis, je l’ai réécrit en Rust.
Le client s’enregistre en tant que VPN, de manière à intercepter tout le trafic
réseau du téléphone, sous la forme de byte[]
de paquets IPv4 bruts, qu’il
transmet alors vers le serveur relais sur une connexion TCP (établie
par-dessus adb).
Le serveur relais analyse les en-têtes des paquets, ouvre des connexions à partir du PC vers les adresses de destinations demandées, et relaie le contenu dans les deux sens en suivant les protocoles UDP et TCP. Il crée et renvoie des paquets de réponse vers le client Android, qui les écrit sur l’interface VPN.
D’une certaine manière, le serveur relais se comporte comme un NAT, en cela qu’il ouvre des connexions pour le compte d’autres machines qui n’ont pas accès au réseau. Cependant, il diffère des NAT standards dans la manière dont il communique avec les clients, en utilisant un protocole spécifique (très simple) sur une connexion TCP.
Pour plus de détails, lisez la page développeurs.
Conception
Une fois que l’application est capable d’intercepter l’intégralité du traffic réseau du téléphone, différentes approches sont possibles. Voici celles que j’ai considérées.
TL;DR: J’ai d’abord étudié l’utilisation d’un “TUN device” sur le PC, mais ça ne répondait pas à nos besoins. J’ai ensuite voulu utiliser SOCKS pour bénéficier des serveurs existants, mais des contraintes nous empêchaient de relayer le trafic UDP. Alors j’ai implémenté gnirehtet.
TUN device
Lors de mes recherches pour savoir comment implémenter le reverse tethering,
j’ai d’abord trouvé des projets créant un TUN device sur l’ordinateur
(vpn-reverse-tether
and SimpleRT
).
Cette conception fonctionne très bien, et a plusieurs avantages :
- le traitement est effectué directement au niveau réseau, donc il n’y a pas besoin de traduction entre le niveau 3 et le niveau 5 du modèle OSI ;
- tous les paquets sont retransmis, indépendamment de leur protocole de transport (ils sont donc tous supportés, là où gnirehtet ne supporte “que” TCP et UDP).
Cependant :
- elle nécessite un accès root sur l’ordinateur ;
- elle ne fonctionne pas sur autre chose que Linux.
Il se peut néanmoins que ces applications répondent davantage à vos besoins.
SOCKS
Afin d’éviter d’avoir à développer un serveur relais spécifique, ma première
idée était d’écrire un client qui parlait le protocole SOCKS (suivant le RFC
1928). Ainsi, il serait possible d’utiliser n’importe quel serveur SOCKS
existant, par exemple celui fourni par ssh -D
.
Vous l’avez probablement déjà utilisé pour éviter le filtrage des pare-feux en entreprise. Pour cela, démarrez le tunnel :
ssh mon_serveur -ND1080
Puis configurez votre navigateur pour utiliser le proxy SOCKS localhost:1080
.
N’oubliez pas d’activer la résolution DNS distante pour résoudre les noms de
domaine à partir de mon_serveur
(dans Firefox, activez
network.proxy.socks_remote_dns
dans about:config
).
Malheureusement, l’implémentation d’OpenSSH ne supporte pas UDP, même si le protocole SOCKS5 lui-même le supporte. Et nous avons besoin d’UDP, au moins pour les requêtes DNS (ainsi que pour NTP).
Si vous avez lu attentivement les deux paragraphes précédents, vous devriez vous demander :
Comment Firefox peut-il résoudre les noms de domaine à distance alors que le proxy SOCKS d’OpenSSH ne supporte même pas UDP ?
La réponse se trouve dans la section 4 du RFC : l’adresse de destination demandée peut être une IPv4, une IPv6 ou un nom de domaine. Par contre, pour utiliser cette fonctionnalité, le client (par exemple Firefox) doit savoir qu’il passe par un proxy (puisqu’il doit explicitement passer le nom de domaine au lieu de le résoudre localement), alors que notre reverse tethering doit être transparent.
Mais tout n’est pas perdu. Certes, OpenSSH ne supporte pas UDP, mais ce n’est
qu’une implémentation spécifique, nous pourrions en utiliser une autre.
Malheureusement, SOCKS5 relaie UDP sur UDP, et les téléphones
et l’ordinateur communiquent sur adb (grâce à adb reverse
), qui ne supporte
pas non plus la redirection de ports UDP.
Peut-être que nous pourrions au moins relayer les requêtes DNS en les forçant à utiliser TCP, comme le fait tsocks :
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.
Mais finalement, SOCKS n’est plus une solution aussi attirante pour implémenter le reverse tethering.
Gnirehtet
Par conséquent, j’ai développé à la fois le client et le serveur relais manuellement.
Ce billet de blog et différents projets open source (SimpleRT
,
vpn-reverse-tether
, LocalVPN
et ToyVpn
) m’ont beaucoup aidé à comprendre
comment implémenter cette solution de reverse tethering.
Conclusion
Gnirehtet permet aux téléphones et tablettes Android d’utiliser facilement la connection internet d’un ordinateur par USB, sans accès root. C’est très utile quand vous ne pouvez pas accéder au réseau par un point d’accès WiFi.
J’espère qu’il pourra être utile à certains d’entre vous.
Discussions sur reddit et Hacker News.
Hello,
Chouette article, super projet. Bravo ! 👍