Cet article présente quelques manipulations importantes pour utiliser un micro-ordinateur Raspberry Pi sans tête, c’est-à-dire sans y connecter de moniteur, de clavier ou de souris. En outre, j’explique comment accéder au Raspberry Pi depuis un réseau local lorsqu’il y accède lui-même par l’intercession du Partage Internet d’un ordinateur sous Mac OS X.
Raspberry Pi? Sans tête?
Le Raspberry Pi est un mignon micro-ordinateur basé sur la plate-forme ARM. Il n’a besoin d’énergie que ce que donne un port USB et roule un système d’exploitation chargé à partir d’une carte SD (typiquement une variante GNU/Linux). C’est une bébelle idéale pour expérimenter tant avec des idées de haut niveau, comme un serveur d’application web maison, qu’avec des trucs de bas niveau, comme attaquer des vulnérabilités de gestion de pile ou de tas.
Incidemment, je dois donner un workshop sur le sujet des exploits de pile et de tas sur la plate-forme ARM à l’Université du Nouveau-Brunswick la semaine prochaine. Je veux faire de ce workshop un tutoriel interactif, aussi désirai-je utiliser mon Raspberry Pi comme hôte des programmes ciblés par de tels exploits. Cependant, deux obstacles se dressaient devant ce dessein:
- Je n’ai pas de périphériques adéquats pour contrôler le Pi directement. Je veux donc l’utiliser à travers une connexion réseau, présumément par un accès SSH.
- Le Pi ne comporte pas d’antenne pour accéder à un réseau sans fil 802.11; son accès réseau est un unique port Ethernet. Bien qu’on puisse y adjoindre une interface 802.11 par un port USB, je désirais minimiser les accessoires. Je désire donc accéder au Pi par une connexion Ethernet directe avec mon portable (MacBook Pro). D’une part, le Pi gagne accès à l’Internet à l’aide du Partage Internet offert par Mac OS X. D’autre part, je veux que les pairs sur le même réseau local que moi puissent aussi accéder au Pi, via mon portable.
Le reste de l’article présente les approches simples que j’ai mises en oeuvre pour franchir ces obstacles.
Préparation du système d’exploitation du Raspberry Pi
J’ai suivi les étapes de ce tutoriel de Tristan Collins pour installer le système d’exploitation Raspbian, un port de Debian Linux au Raspberry Pi. En bref, une fois qu’on a téléchargé l’image disque de Raspbian, on doit la décompresser et la transmettre à la carte SD.
Pour ma part, j’ai d’abord eu quelques problèmes avec ma carte SD. Mes
tentatives d’utiliser la commande dd
indiquée ci-dessous ne réussissaient
pas: le message d’erreur suggérait que la carte était en lecture seule.
Je crois que des grains de poussière se sont déposés près du commutateur de
verrouillage de la carte.
En faisant bouger le petit levier gris et en soufflant dans la petite cavité où le commutateur glisse, je pense avoir été en mesure de libérer la poussière qui faisait croire au lecteur que la carte était verrouillée. Après ces manipulations, j’ai pu procéder à la transmission de l’image disque.
Les instructions qui suivent valent pour un ordinateur sous Mac OS X; sur
GNU/Linux, la commande dd
est disponible, mais le device correspondant à
la carte SD doit être identifié d’une autre manière.
Sur un Mac, on déterminer d’abord le device correspondant à la carte SD,
à l’aide de la commande diskutil
.
$ diskutil list
...
/dev/disk7
#: TYPE NAME SIZE IDENTIFIER
0: FDisk_partition_scheme *31.9 GB disk7
1: FAT32 NO NAME 31.9 TB disk7s1
Dans mon cas, la carte SD a pour device /dev/disk7
. Sachant cela, je
démonte les partitions que OS X avait cru bon monter lorsque j’ai inséré la
carte dans le lecteur.
$ diskutil unmountDisk disk7
Unmount of all volumes on disk7 was successful
Finalement, je décompresse et je transmets l’image Raspbian que j’ai
téléchargée. La dernière opération (commande dd
) s’exécute en quelque 25 minutes:
excellent moment pour aller préparer une bonne tasse de chaud.
$ cd Downloads
$ unzip 2014-09-09-wheezy-raspbian.zip
$ sudo dd bs=1m if=2014-09-09-wheezy-raspbian.img of=/dev/disk7
3125+0 records in
3125+0 records out
3276800000 bytes transferred in 1584.555457 secs (2067962 bytes/sec)
On insère ensuite la carte dans la fente appropriée du Raspberry Pi et on
branche le micro-ordinateur à un port USB. En principe, tout va bien: le
voyant rouge PWR
s’allume et le voyant ACT
clignote au rythme des
entrées/sorties à la carte SD. Si on ne voit pas ce clignotement, c’est
vraisemblablement à cause d’une panique de noyau, entraînant l’arrêt des
calculs. Vérifiez que votre carte SD fonctionne bien, et répétez les
instructions ci-haut au besoin.
Partage Internet
On branche maintenant le Pi au MacBook, qui lui partagera sa connexion Internet sans fil via son interface Ethernet. Il faut vraiment faire cette étape en premier, alors je le répète:
Branchez d’abord le Raspberry Pi et le MacBook Pro avec le câble Ethernet.
Si on démarre d’abord le Partage Internet et que les câbles ne sont pas branchés, il m’est arrivé que le serveur DHCP du MacBook Pro ne démarre pas, de sorte que le pauvre Pi, une fois branché, ne recevra jamais d’adresse IP, malgré ses incessantes supplications.
On démarre ensuite le Partage Internet, à partir de l’onglet Partage des Réglages du MacBook Pro:
Avant de cliquer sur la case démarrant le partage, on s’assure que la source du partage est la connexion sans fil et que l’interface Ethernet est choisie parmi les destinations du partage.
Découverte de l’adresse du Raspberry Pi
Le partage Internet implanté sur Mac OS X n’est pas conçu pour donner une
adresse à un appareil sans tête. Par conséquent, le serveur DHCP qu’il démarre
ne peut être ni configuré, ni interrogé. J’ai découvert deux méthodes pour
découvrir l’adresse du Pi branché au Mac. Dans les deux cas, il faut d’abord
établir quel numéro de réseau le Partage Internet retient. On y parvient en
examinant l’ensemble des interfaces réseau sur le Mac, via la commande
ifconfig
:
$ ifconfig
...
bridge100: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
options=3<RXCSUM,TXCSUM>
ether ca:2a:14:51:e5:64
inet 192.168.2.1 netmask 0xffffff00 broadcast 192.168.2.255
Configuration:
id 0:0:0:0:0:0 priority 0 hellotime 0 fwddelay 0
maxage 0 holdcnt 0 proto stp maxaddr 100 timeout 1200
root id 0:0:0:0:0:0 priority 0 ifcost 0 port 0
ipfilter disabled flags 0x2
member: en0 flags=3<LEARNING,DISCOVER>
ifmaxaddr 0 port 4 priority 0 path cost 0
media: autoselect
status: active
Le partage Internet a donc lieu via l’interface Ethernet sur le réseau
192.168.2/24. On sait d’ailleurs que la distribution Raspbian comporte un
usage nommé pi
, dont le mot de passe est raspberry
. Ainsi, la première
approche à laquelle j’ai pensé a été la force brute: essayer les adresses sur
le réseau 192.168.2/24 une après l’autre (en omettant 192.168.2.1, réservée au
MacBook Pro). Lorsqu’une tentative de connexion prend plus de quelques
secondes, je l’abandonne et j’essaie l’adresse suivante.
$ ssh pi@192.168.2.2
^C
$ ssh pi@192.168.2.3
^C
$ ssh pi@192.168.2.4
The authenticity of host '192.168.2.4 (192.168.2.4)' can't be established.
RSA key fingerprint is d0:d8:f4:d0:2e:1b:a9:3e:e2:97:6a:42:5e:a8:7b:b0.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.2.4' (RSA) to the list of known hosts.
pi@192.168.2.4's password:
Linux raspberrypi 3.12.28+ #709 PREEMPT Mon Sep 8 15:28:00 BST 2014 armv6l
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
NOTICE: the software on this Raspberry Pi has not been fully configured.
Please run 'sudo raspi-config'
pi@raspberrypi ~ $
Naturellement, cette
approche prendrait un temps fou si le serveur DHCP du MacBook Pro ne donnait
pas une adresse proche de 192.168.2.1 au Raspberry Pi. Une approche plus
élégante pour découvrir les hôtes sur un certain réseau est d’utiliser nmap
.
Cet outil n’est pas installé par défaut sur Mavericks: on le télécharge
d’ici. nmap
est un balayeur réseau:
il peut découvrir les hôtes appartenant à un réseau ou les ports ouverts sur
ces hôtes. Dans le cas présent, on cherche seulement les hôtes valides, donc
on peut éviter le coûteux balayage des ports:
$ nmap -sn 192.168.2.*
Starting Nmap 6.47 ( http://nmap.org ) at 2014-09-26 20:55 EDT
Nmap scan report for 192.168.2.1
Host is up (0.00081s latency).
Nmap scan report for 192.168.2.4
Host is up (0.0016s latency).
Nmap done: 256 IP addresses (2 hosts up) scanned in 19.59 seconds
Comme il ne peut y avoir que deux adresses sur ce réseau et qu’on sait que 192.168.2.1 correspond au MacBook Pro, on bien découvert le Raspberry Pi.
Accès au Raspberry Pi depuis le réseau local
Ceci résout le premier obstacle mentionné ci-haut. Cependant, réseauter le Raspberry Pi à travers le Mac par une adresse non routable le rend inaccessible depuis le reste du réseau local auquel le MacBook Pro participe (le réseau sans fil).
L’approche la plus simple que j’ai trouvée pour permettre cet accès implique d’utiliser le serveur SSH du MacBook Pro comme proxy SOCKS, via sa fonctionnalité de redirection de ports dynamique. Un serveur SOCKS articule une sorte de réseau virtuel privé au niveau application: un client de ce proxy peut initier des échanges IP qui émanent du serveur, lequel redirige les réponses à ces échanges au client. Ces transactions sur le protocole IP sont résolues par le serveur: ainsi, bien que l’adresse 192.168.2.4 soit généralement non routable, le MacBook Pro qui réalise le partage Internet sait comment la router. En passant par ce MacBook Pro comme proxy SOCKS, on permet donc l’accès au Raspberry Pi à tous les clients SOCKS.
Serveur
Pour réaliser cette approche, il faut démarrer le serveur SSH du MacBook Pro. Cela est implicite à l’activation des Sessions à distance, qu’on réalise depuis l’onglet Partage de l’application de Réglages. Cela fait, on démarre un serveur SOCKS qui sera accessible pour tout participant au réseau local:
$ ssh -D *:1080 -fN localhost
Le paramètre *:1080
qui suit l’option -D
indique que le serveur SOCKS est
accessible depuis toutes les interfaces réseau du Mac, sur le port 1080
(défaut pour les serveurs SOCKS). Les options -fN
font en sorte que la
connexion SSH ne démarre pas de shell ni de commande client, et démarre en
arrière-plan, libérant le terminal. On pourra interrompre le serveur SOCKS en
éliminant le client SSH par la commande kill
.
Client
De manière générale, seules les applications gérant explicitement la connexion
à un proxy SOCKS (comme un navigateur Internet) peuvent bénéficier de
l’accès prolongé par un tel serveur. Heureusement, j’ai
découvert
l’utilitaire GNU/Linux tsocks
, qui utilise de la magie noire de librairies
dynamiques pour emballer toutes les fonctions de programmation IP (socket
,
connect
, etc.) dans un tunnel SOCKS. Sur Ubuntu/Debian, on installe ce
programme à l’aide de apt-get
:
$ sudo apt-get install tsocks
On doit ensuite configurer les serveurs SOCKS que tsocks
peut utiliser pour
accéder à telle ou telle adresse. Les échanges IP impliquant seulement
certains intervalles d’adresses seront ainsi relayés au serveur SOCKS. Voici
le contenu de /etc/tsocks.conf
pour une machine virtuelle connectée au même
réseau local que le MacBook Pro (192.168.1/24), à partir de laquelle je veux
accéder au Raspberry Pi:
# Réseaux "locaux", accédés sans relai à un proxy SOCKS.
local = 192.168.1.0/255.255.255.0
# Accès à 192.168.2/24
path {
reaches = 192.168.2.0/255.255.255.0
server = 192.168.1.154 # Adresse du MacBook Pro.
server_port = 1080
server_type = 5
}
# Serveur par défaut.
server = 192.168.1.154
server_type = 5
server_port = 1080
Sur cette machine virtuelle, j’accède au Pi par la commande
$ tsocks ssh pi@192.168.2.4
pi@192.168.2.4's password:
Cette approche ajoute un peu de complexité au niveau des clients, mais l’alternative que je perçois est de mettre en oeuvre un réseau virtuel privé. Ce déploiement d’un proxy SOCKS est trop simple pour que je m’en passe.