Pour ceux qui s’interressent au WHOIS, voici une petite présentation faite il y a quelques semaines.

Le temps étant limité, je n’ai pas parlé de tout ce que j’avais en tête, mais le principal s’y trouve.

Me remonter par la page de contact (ou par les commentaires) au cas ou un truc faux se serait glissé dans la présentation à l’insu de mon plein gré.

Introduction

Il n’y a même pas la possibilité par défaut sur un Kindle de changer les images de veille. Rien que pour cette raison, on est tenté de rooter/jailbreaker son Kindle afin d’en reprendre un peu le controle. (My device, my rules).

Quand je me le suis procuré il y a quelques mois, il est arrivé en version 5.6 quelquechose et il n’est pas possible à l’heure où sont écrites ces lignes, de le rooter/jailbreaker de manière uniquement logicielle.

Dans des versions précédentes, il était possible de faire passer le JailBreak pour une mise à jour, mais ceci a été “corrigé” par Amazon.

La seule solution est pour l’instant d’ouvrir le Kindle, et d’accèder au port série. (Au moins il y en a un, c’est déjà çà).

IMG_20151107_220727.jpg-s_m

La technique dans les grandes lignes:

  • Ouvrir le Kindle et se connecter sur le port série
  • Booter sur la 2ème partition de debug/diag
  • Trouver le mot de passe de cette partition de debug/diag et se connecter en root dessus
  • Une fois root sur la partion de debug/diag, monter la partition “principale” pour éditer le fichier /etc/passwd pour en débloquer l’accès root.
  • Rebooter sur la 1ère partition et s’y connecter en root.
  • Lancer le script de JailBreak

Si j’ai bien compris, Amazon n’autorise que les applications qu’ils ont signés eux (avec leur clé privée) à s’installer. Le JailBreak consiste à ajouter une autre clé publique (dont la communauté connait la clé privée) rendant donc possible l’installation d’applications non authorisée par Amazon.

uggy-kindle-pubKey.png-s_m

Connaitre sa version de firmare

Menu/Paramètres/Menu/Infos sur l’appareil/Version du micrologiciel

Trouver son numéro de série/modèle

http://wiki.mobileread.com/wiki/Kindle_Serial_Numbers

Avoir un accès console avec niveaux logiques 1.8V

Le port série des Kindles (au moins mon PW2) communique avec des niveaux logiques 1.8V.

Il faut donc utiliser un port série qui utilise ces niveaux logiques et non les classiques 3.3V et 5V

J’ai utilisé un PL2303HXrevD (dans les 4€ sur Ebay)

PIN4 The power pin for the serial port signals.
The range can be from 1.8V~3.3V

(Attention, le PL2303HX (pas révision D) ne supporte pas le 1.8V d’après la datasheet)

Il suffit de décoller doucement la PIN4 du chip (par exemple avec une petit aiguille) afin de pouvoir la connecter ensuite à du 1.8V (ou 3V3 ou 5V pour d’autres usages)

IMG_20151108_190546.jpg-s_m

Trouver le mot de passe de la partition diag (2ème partition)

J’avais initialement utilisé le code suivant trouvé sur le forum http://www.mobileread.com/forums/

#!/usr/bin/env python  
import hashlib  
print("fiona%s"%hashlib.md5("XXXYOURSERIALXXX\n".encode('utf-8')).hexdigest()[7:11])

Mais dans mon cas, le mot de passe ainsi trouvé n’a ensuite PAS fonctionné.
Même problème avec le site https://www.sven.de/kindle/ qui utilise le même “algo”.

J’ai donc utilisé kindletool qui lui m’a donné un mot de passe différent qui a fonctionné sur mon Kindle.

$ ./kindletool info XXXYOURSERIALXXX  
Platform is Wario or newer  
Root PW fionaXXX  
Recovery PW fionaXXXX  

Démonter le Kindke pour accéder au port console

Je me suis basé sur cette vidéo

Si vous acheter le PL2303HXrevD à HongKong sur un site d’enchère (environ 4€), cà vaut peut être le coup d’acheter en même temps les “Metal spudger” (2€ les 2) mais sinon un couteau avec une lame fine peut faire l’affaire.

Le plus difficile est de ne pas laisser de trace pour passer le spudger sous la coque au tout début.
La suite du démontage est triviale.
Faire cependant attention à la bande de plastique blanche au niveau des LEDs car elle joue sur la répartition de la lumière sur la dalle.

Connecter le port série

uggy-serial-kindle.png-s_m

Les pins sont toutes petites, donc à souder avec précaution

IMG_20151107_220202.jpg-s_m

Pour les branchements, TX sur RX, RX sur TX, Gnd sur Gnd, le fil vert sur le bouton vert etc..

Les paramètres sont: 8N1 115200

J’ai utilisé screen

$ screen /dev/ttyUSB0 115200

Sortir de “veille” le kindle

Si tout se passe bien le port série devrait s’afficher comme ceci

uggy-kindle-Serial.png-s_m

Il dit “Welcome”, c’est qu’on a le droit de se connecter ;)

Boot de la partition diag

Rebooter le Kindle, tapez sur n’importe quelle touche au début du boot pour arreter la séquence (il y a un créneau que de quelques secondes), allez en mode diag en tapant bootm 0xE41000

uggy-kindle-bootm.png-s_m

Choisir “Exit, Reboot or Disable Diags” puis “Exit to login prompt” etc…

uggy-kindle-menu1.png-s_m

uggy-kindle-menu2.png-s_m

uggy-kindle-menu3.png-s_m

uggy-kindle-menu4.png-s_m

Se logguer

Utiliser le compte de la partition diag trouvé à l’une des étapes précédentes: root/fionaXXX

uggy-kindle-root-diag.png-s_m

Monter la partition principale (la 1ère partition) et éditer le fichier etc/passwd

uggy-kindle-passwd1.png-s_m

Modifier la ligne pour root

root:*: -> Indique un mot de passe chiffré dans /etc/shadow
root:: -> Indique qu’il n’y a pas de mot de passe

uggy-kindle-passwd2.png-s_m

uggy-kindle-passwd3.png-s_m

Pour l’instant on choisi d’enlever le mot de passe

Rebooter, tester l’accès root à la partition principale

uggy-kindle-root-main.png-s_m

Télécharger les fichiers de jailBreak

http://www.mobileread.com/forums/showthread.php?t=186645

Connecter l’USB, copier les fichiers à la racine sur le Kindle (USB classique) puis déconnecter l’USB

Executer le scipt de jaibreak avec l’acces root (partition principale, pas diag)

uggy-kindle-jb.png-s_m

Conclusion

Ce billet de couvre pas l’installation des outils que l’on peut alors utiliser.

Mais j’ai commencé par personnaliser l’écran de “veille”…

IMG_20151108_191509.jpg-s_s

Crédit: De nombreux posts et personnes de http://www.mobileread.com/forums/

Je suis tombé sur un petit problème DNS interressant…
Le voici dans l’ordre…

  • Je clic sur un lien et me voila envoyé vers un article du site http://www.leparisien.fr

    Patatra, marche pas.

  • Vérification DNS:

$ dig www.leparisien.fr  

; <<>> DiG 9.9.5-9+deb8u1-Debian <<>> www.leparisien.fr  
;; global options: +cmd  
;; Got answer:  
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 53534  
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1  

;; OPT PSEUDOSECTION:  
; EDNS: version: 0, flags:; udp: 4096  
;; QUESTION SECTION:  
;www.leparisien.fr. IN A  

;; Query time: 448 msec  
;; SERVER: 127.0.0.1#53(127.0.0.1)  
;; WHEN: Wed Jul 15 21:36:55 CEST 2015  
;; MSG SIZE rcvd: 46  

$

Marche pas, status: SERVFAIL

Interressant

$ dig cname www.leparisien.fr  
www.leparisien.fr. 86400 IN CNAME 2-01-275c-0002.cdx.cedexis.net.

Bon cette 1ère partie fonctionne.

  • Essayons de voir ce que donne 2-01-275c-0002.cdx.cedexis.net.
$ dig 2-01-275c-0002.cdx.cedexis.net.  

; <<>> DiG 9.9.5-9+deb8u1-Debian <<>> 2-01-275c-0002.cdx.cedexis.net.  
;; global options: +cmd  
;; Got answer:  
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 7708  
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1  

;; OPT PSEUDOSECTION:  
; EDNS: version: 0, flags:; udp: 4096  
;; QUESTION SECTION:  
;2-01-275c-0002.cdx.cedexis.net. IN A  

;; Query time: 25 msec  
;; SERVER: 127.0.0.1#53(127.0.0.1)  
;; WHEN: Wed Jul 15 21:39:41 CEST 2015  
;; MSG SIZE rcvd: 59  

Donc c’est lui qui ne résoud pas chez moi… status: SERVFAIL…

  • Voyons voir les DNS de cdx.cedexis.net. ou plutôt ceux de cedexis.net.
$ dig ns cedexis.net. +short  
flipa.cedexis.net.  
flipd.cedexis.net.  
flipg.cedexis.net.  
$
  • Testons les en direct
 $ dig 2-01-275c-0002.cdx.cedexis.net. @flipa.cedexis.net. +short  
 cdn2.lequipe.fr.  
 $ dig 2-01-275c-0002.cdx.cedexis.net. @flipd.cedexis.net. +short  
 cdn2.lequipe.fr.  
 $ dig 2-01-275c-0002.cdx.cedexis.net. @flipg.cedexis.net. +short  
 cdn2.lequipe.fr.  
 $

Arf çà répond.
Alors que cela ne répond toujours pas avec mon serveur local:

$ dig 2-01-275c-0002.cdx.cedexis.net.  

; <<>> DiG 9.9.5-9+deb8u1-Debian <<>> 2-01-275c-0002.cdx.cedexis.net.  
;; global options: +cmd  
;; Got answer:  
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 31061  
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1  

;; OPT PSEUDOSECTION:  
; EDNS: version: 0, flags:; udp: 4096  
;; QUESTION SECTION:  
;2-01-275c-0002.cdx.cedexis.net. IN A  

;; Query time: 44 msec  
;; SERVER: 127.0.0.1#53(127.0.0.1)  
;; WHEN: Wed Jul 15 21:44:22 CEST 2015  
;; MSG SIZE rcvd: 59  
  • Comme vous l’avez remarqué, j’interroge mon serveur récursif local.

Quand la demande passe par lui, cela ne fonctionne pas, sinon cela semble fonctionner.

$ dig 2-01-275c-0002.cdx.cedexis.net. @8.8.8.8 +short  
cdn2.lequipe.fr.  
62.210.149.48  
$   
  • Mon serveur DNS local est Unbound, et il semble qu’un truc le dérange (uniquement avec ces serveurs DNS cedexis.net !)…

  • Activation des logs verbeux par la ligne

verbosity: 3
  • Et on regarde les logs:
1436989983] unbound[12494:1] info: reply from <cedexis.net.> 209.107.211.4#53   
1436989983] unbound[12494:1] info: Capsforid fallback: getting different replies, failed   
1436989983] unbound[12494:1] debug: return error response SERVFAIL   

Capsforid… Interressant

use-caps-for-id: Use 0x20-encoded random bits in the query to foil spoof
attempts. This perturbs the lowercase and uppercase of query
names sent to authority servers and checks if the reply still
has the correct casing. Disabled by default. This feature is
an experimental implementation of draft dns-0x20.

Donc en gros, avec ce paramètre à “yes”, unbound envoit le nom à résoudre avec des minuscule/majuscule aléatoires, puis vérifie que la réponse à la question, qui contient la question, à bien les minuscules/majuscules aux bons endroits.

Et ce paramètre est à yes dans ma conf Unbound.

  • Avant d’aller voir le draft dns-0x20, on lance wireshark

dns-wireshark-1

dns-wireshark-2

On voit clairement ce qui se passe, la réponse contient la question en minuscule, donc pas exactement comme elle a été posée.

  • Vérifions avec un autre domaine.. Au hasard bortzmeyer.org
$ dig www.bortzmeyer.org +short  
204.62.14.153  
$

Mon unbound résoud parfaitement.

On voit bien que la réponse, contient bien cette fois exactement la question, avec les minuscules/majuscules aux bons endroits.

dns-wireshark-3

  • Vérifions en mettant à no le use-caps-for-id (ce qui, il est vrai, est la valeur par défaut)

Bingo, çà fonctionne cette fois

$ dig 2-01-275c-0002.cdx.cedexis.net. +short  
cdn2.lequipe.fr.  
62.210.149.48  
$

Unbound considère maintenant comme valide la réponse des serveurs de cedexis.net
Victoire, je peux lire mon article sur www.leparisien.fr

  • C’est quoi cedexis.net, ils auraient leur propre serveur DNS maison ?

“We’re dedicated to building a faster web for everyone in the world. Cedexis optimizes web performance across data centers, content delivery networks (CDNs) and clouds…”

Ah oui, çà colle, ils seraient bien capable d’avoir leur implémentation DNS maison.

Déjà on peut noter que c’est rédigé par Paul Vixie de l’ISC, c’est du sérieux.

Je vais vous résumer en gros:

Le protocole DNS est tel, qu’il y a parfois moyen de réussir à forger des réponses et donc de poluer les caches DNS.
Il est donc ensuite possible de rediriger les users vers des faux site web.. bref pas cool.. mais rien de nouveau pour l’instant.
Mais tout moyen permettant d’améliorer la sécurité, en rendant plus difficile de forger des fausses réponses, sans tout casser au protocole existant, est donc la bienvenue.
Ce draft expose un moyen d’y parvenir.

Comme vous l’avez compris (pour les 3 personnes qui sont arrivées jusqu’ici, chapeau bas), il s’agit de mettre des majuscules/minuscules aléatoires dans la question envoyée au serveur DNS, puis considérer comme invalides, les réponses qui ne reprendaient pas la question en respectant la casse.

Pour forger une fausse réponse DNS et donc polluer le cache, il faudrait donc non seulement trouver le bon ID (Kaminsky, Paradoxe des anniversaires etc..) mais donc en plus avoir les bonnes majuscules/minuscules aux bons endroits. (Pas con le Paul Vixie ! )

Mais pour que l’idée soit exploitable, il faut donc voir ce que dit la RFC 1035 et voir comment réagissent les principales implémentations de serveurs DNS authoritatives.

Pour ce qui est de la RFC1035 on peut lire en 7.3

that the question section corresponds to the information currently desired

Mmmm…Ce n’est pas super précis … Est-ce que cela inclu le respect de la casse… ?

Voyons voir les différentes implémentations:

On peut lire en 6.1

Several popular authoritative DNS implementations including ISC BIND (versions 4, 8, and 9), Nominum ANS, Akamai AKADNS, Neustar UltraDNS, Verisign Atlas, NLNetLabs NSD, PowerDNS, and DJBDNS were tested. All copied the question name exactly, bit for bit, from the request into the response.

Et en 6.2

Operational testing has revealed a small set of rare and/or private label authoritative DNS implementations who modify the 0x20 bits in question names while copying the question section from the request to the response. Usually this modification is to set the 0x20 bit, thus converting a domain name to be all-lower-case (0x61..0x7A, e.g., a-z).

  • Conclusion:

Toutes les implémentations de serveur DNS authoritative majeures répondent en respectant la casse de la question.
Si les serveurs récursifs pouvaient implémenter cette vérification, ceci pourrrait améliorer la sécurité du DNS.
Et c’est d’ailleurs la 1ère fois que j’ai ce problème avec un serveur DNS, je vais donc garder mon paramêtre, et tant pis pour le site web du Parisien ;)

Les serveurs DNS de cedexis.net ne semblent pas tourner sous une “popular authoritative DNS implementations” :) Je les ai contacté pour les informer…. si çà les interresse…

EDIT 31 Août 2015:

Antoine de Cedexis est tombé sur le billet et a remonté l’information aux bonnes personnes chez eux.
Je contaste que les modifications nécessaires (indiquées dans la roadmap dans son commentaire ci-dessous) semblent avoir été implémentées en production sur leurs serveurs DNS, et les résolutions ce font donc désormais correctement en respectant le draft dns-0x20.
Merci Antoine

L’idée est de pouvoir indiquer avec un ESP8266 à mes jeunes enfants qu’il a beau faire jour dehors en ce mois de Juin, ce n’est pas l’heure de venir réveiller leurs pauvres parents en manque de sommeil.

Je ne suis pas le premier à avoir eu la même idée de père fatigué, puisqu’en cherchant un peu je suis tombé sur l’excellent blog de Dani Eichhorn.

Son billet explique qu’il fait une connection HTTP à intervalle régulier, afin de récupérer l’heure sur Internet, puis allume une LED ou une autre suivant qu’il est l’heure de se lever ou non.

Cependant, j’avais imaginé une autre façon de procéder, donc je suis resté sur ma première idée qui a “l’inconvénient” d’utiliser mon Rasp à tout faire sur le réseau local, mais l’avantage de pouvoir changer l’heure de “réveil” sans avoir à modifier le script sur l’ESP8266. Et puis c’est plus sympa d’essayer de faire à sa sauce.

L’idée est la suivante:

  • L’ESP8266 faire tourner les serviettes un petit serveur HTTP.
  • S’il recoit une requête “jour”, il allume la LED verte
  • S’il recoit une requête “nuit”, il allume la LED rouge “laisse tes parents dormir, ils ne se couchent pas à 20h30 eux ! “.
  • Le Rasp sur le réseau local exécute le script toutes les minutes, regarde l’heure, et en fonction, envoi la requête HTTP “jour” ou “nuit” à l’ESP 8266.
  • Il y a en réalité 2 scripts dans la cron du Rasp, un qui s’exécute les jours de la semaine, et un autre le WE. L’heure de l’allumage “jour” est donc reglé plus tardivement le WE.
  • Une page web pourrait éventuellement être créée à l’avenir sur le Rasp pour que Madame Yop puisse elle même changer l’heure avec un navigateur… sans aller modifier le Rasp en SSH… (WAF) Mais avant cela, faudrait d’abord voir si les 2 loustics vont bien vouloir suivre les indications des LEDs…

Tests sur Breadboard:

esp-led-verte

esp-led-rouge

On soude un peu et on range tout çà:

esp-led-boitier1

esp-led-boitier2

Schéma

esp-led-schema

Scripts

init.lua
wifi.setmode(wifi.STATION) wifi.sta.config("SSID","Password") wifi.sta.connect() wifi.sta.setip({ip="192.168.1.247",netmask="255.255.255.0",gateway="192.168.1.1"}) print("ESP8266 mode is: " .. wifi.getmode()) print("The module MAC address is: " .. wifi.ap.getmac()) print("Config done, IP is "..wifi.sta.getip()) dofile("jour-nuit.lua")@@

J’ai récupéré le code suivant sur un github, mais je ne retouve pas lequel…

jour-nuit.lua
-- Relay pin as output gpio.mode(5, gpio.OUTPUT) gpio.mode(6, gpio.OUTPUT) -- Include url_parser module local parser = require "url_parser" -- Create server srv=net.createServer(net.TCP) srv:listen(80,function(conn) conn:on("receive",function(conn,payload) -- Parse request parsed_request = parser.parse(payload) if parsed_request == 'jour' then gpio.write(6, gpio.LOW) gpio.write(5, gpio.HIGH) end if parsed_request == 'nuit' then gpio.write(5, gpio.LOW) gpio.write(6, gpio.HIGH) end -- Display main page conn:send("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n") conn:send('<head>') conn:send('<meta name="viewport" content="width=device-width, initial-scale=1">') conn:send('<script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>') conn:send('<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">') conn:send('</head>') conn:send('<div class="container">') conn:send("<h1>Control Sommeil</h1>") conn:send('<div class="row">') conn:send('<div class="col-md-2"><input class="btn btn-block btn-lg btn-primary" type="button" value="Jour" onclick="jour()"></div>') conn:send('<div class="col-md-2"><input class="btn btn-block btn-lg btn-danger" type="button" value="Nuit" onclick="nuit()"></div>') conn:send('</div></div>') conn:send('<script>function jour() {$.get("/jour");}</script>') conn:send('<script>function nuit() {$.get("/nuit");}</script>') end) conn:on("sent",function(conn) conn:close() end) end)@@
url_parser.lua
-- Module declaration local parser = {} function parser.parse(request) -- Find start local e = string.find(request, "/") local request_handle = string.sub(request, e + 1) -- Cut end e = string.find(request_handle, "HTTP") request_handle = string.sub(request_handle, 0, (e-2)) return request_handle end return parser
jour-nuit.sh sur le Rasp
!/bin/bash # Control de la LED pour jour/nuit enfants LEVER="0720" COUCHER="2030" IP="192.168.1.247" CUR_TIME=date +%H%M if [ $CUR_TIME -ge $LEVER -a $CUR_TIME -le $COUCHER ] then echo "Jour" curl http://$IP/jour > /dev/null 2>&1 else echo "Nuit" curl http://$IP/nuit > /dev/null 2>&1 fi
Le résultat final

…ou presque (manque les autocollants de Spiderman et de la Reine de Neige)

esp-led-end

Evolutions possibles futures

(ou pas) dépendra surtout si les bambins suivent les indications des LEDs:

  • Serveur web de configuration de l’heure
  • Ajout d’une sonde de température ds18b20
  • Utilisation du mode “veille” / utilisation sur batterie

Comme nous l’avons vu dans un le précédent billet, l’ESP8266 peut être flashé avec des firmwares alternatifs.

Modification des branchements

Pour je pense toutes les versions, il est nécessaire de mettre la GPIO0 à la masse au démarrage du module pour qu’il puisse rentre en mode “ready pour être flashé”.
(Penser à l’enlever après ! )

Logiciel pour flasher

Sous GnuLinux, j’ai utilisé esptool.

$ sudo apt-get install python-serial  
$ git clone https://github.com/themadinventor/esptool.git  
$ ./esptool/esptool.py --help  
usage: esptool [-h] [--port PORT] [--baud BAUD]

Exemple avec NodeMCU si votre port série est /dev/ttyUSB0

$ wget https://github.com/nodemcu/nodemcu-firmware/raw/master/pre_build/latest/nodemcu_latest.bin  
$ python esptool.py --port /dev/ttyUSB0 write_flash 0x000000 nodemcu_latest.bin  
Connecting...  
Erasing flash...  
Writing at 0x00062000... (100 %)  

Leaving...

Firmwares

Frankenstein

Frankenstein est un firmware qui permet de se passer des commandes AT pas très intuitives, et d’utiliser à la place des commande beaucoup plus simples.

Exemples de commandes qui elles se passent d’explication:

iwscan  
iwconnect ApName password  
ifconfig  
listen 8080  
send 192.168.0.101 8080 hello  
deepsleep 10000  
gpio out 0 1  

simple…

NodeMcu

NodeMcu ici ou ici est je pense, à la date de rédaction de ce billet, le firmware le plus utilisé.

Il utilise des scripts en Lua.

NodeMCU 0.9.5 build 20150214 powered by Lua 5.1.4  
lua: cannot open init.lua  

print("hello")  
 hello  

Exemple de code pour faire tourner un serveur HTTP:

-- a simple http server  
srv=net.createServer(net.TCP)  
srv:listen(80,function(conn)   
conn:on("receive",function(conn,payload)   
print(payload)   
conn:send("<h1> Hello, NodeMCU.</h1>")  
end)   
end)  

Le mieux est d’aller voir les autres exemples sur le site web ou sur GitHub pour se rendre compte.

Au démarrage, le fichier init.lua sera exécuté, s’il existe.
Il est donc possible par exemple de faire tourner un serveur HTTP connecté en Wifi qui permet de basculer les GPIOs.
Oui, oui, tout ceci pour 2€50 ! Sans avoir besoin d’un Arduino etc.. L’Internet des objets est là.

esp8266-cli

esp8266-cli permet de réaliser simplement des opérations sur le système de fichier accessible sous le firmware NodeMcu.

Il permet donc de copier facilement ses scripts, les supprimer etc.. en ligne de commande.

$ sudo npm install -g esp8266

J’ai eu l’erreur “/usr/bin/env: node: No such file or directory” qui a été corrigé par

$ ll /usr/bin/nodejs  
-rwxr-xr-x 1 root root 1.4M Oct 19 2013 /usr/bin/nodejs  
$ sudo ln -s /usr/bin/nodejs /usr/bin/node  

Exemples de copie de fichier vers l’ESP8266:

$ echo pouet > toto  
$ sudo esp port set /dev/ttyUSB0  
$ sudo esp file list  
$ sudo esp file write toto  
$ sudo esp file list  
6 bytes toto  
$ sudo esp file read toto  
pouet  

$ sudo esp file remove toto  
$ sudo esp file list  

ESPlorer

Dispo ici, écrit en Java, il est multi-plateformes

$ java -jar ESPlorer.jar

esp8266-esplorer