Gnirehtet

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 :

rev <<< tethering

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 :

key

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.

archi

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.

Vus : 637
Publié par ®om : 83