Streamer une caméra TecTecTec XPro2 sur PC
Sommaire
Présentation
L'objectif principal du projet est de pouvoir streamer le flux vidéo de la caméra sur un ordinateur. La caméra ne peut actuellement que streamer vers un smartphone via une application dédiée.
Comment Faire ?
Prérequis
Matériel nécessaire
- 1 Caméra TecTecTec XPro2
- 1 Ordinateur avec carte réseau supportant le mode monitor et un OS Linux de préférence
Logiciel nécessaire
- airmon-ng pour utiliser le mode monitor de la carte wifi
- Wireshark pour analyser le traffic réseau de la caméra
- ffplay ou VLC pour lire le flux vidéo
Analyse du réseau
Activation du mode monitor
Le mode monitor permet à un récepteur Wifi d'écouter la totalité du traffic réseau à sa portée sans se limiter au réseau auquel il appartient. Ce mode d'écoute n'est pas compatible avec toutes les cartes réseau. Une liste de cartes compatibles est disponible à cette adresse :
Il est possible d'activer le mode monitor de deux manières :
Avec iwconfig
ifconfig wlan0 down iwconfig wlan0 mode monitor ifconfig wlan0 up
Avec la suite aircrack
airmon-ng check kill airmon-ng start wlan0
Il est ensuite possible de monitorer les échanges Wifi grace à la commande
airodump-ng <iface>
Prévention du channel hopping
Un réseau Wifi opère sur des canaux (une bande de fréquences) afin de limiter les interférences avec d'autres équipements. Pour le Wifi 2.4GHz il existe 14 canaux et chaque point d'accès fonctionne sur un canal pré-déterminé. Une carte réseau en mode monitor ne peut écouter le traffic que sur un seul canal à la fois. Elle vas donc faire du channel-hopping (c'est à dire qu'elle va changer de canal ou bout d'un très petit intervalle de temps) afin de pouvoir écouter le traffic sur l'ensemble des canaux. Cela a cependant le gros désavantage de rater une partie des paquets émis. Il est heureusement possible de spécifier un canal précis à monitorer. Les autres canaux seront alors ignoré et nous pourrons enregistrer l'intégralité du traffic qui nous intéresse. Grace à airodump-ng il est possible de voir sur quel canal (channel) Wifi la caméra TecTecTec est active (ici le canal 6) Une fois le canal identifié il faut redémarrer la carte réseau en mode monitor sur le canal utilisé par la caméra
airmon-ng stop wlan0mon airmon-ng check kill airmon-ng start wlan0 6
Capture du traffic avec Wireshark
En lançant Wireshark sur l'interface passée précédement nous pouvons désormais capturer l'ensemble du traffic sur le canal étudié. Il reste cependant un problème majeur : L'intégralité du traffic est crypté, généralement en WPA2. Il nous est cependant possible, en streamant le flux vidéo de la caméra sur un smartphone et étudiant la forme des paquets reçus de déterminer quels sont les BSSID de la caméra et du smartphone pour filter le traffic et ne garder que celui entre les deux appareils.
Décryptage WPA
Pour décrypter le traffic entre les deux appareils nous avons besoin de deux choses : La clé WPA2 et le dialogue de connexion entre les deux appareils (4-way handshake). Pour récupérer le 4-way Handshake il faut procéder de la façon suivante :
- Déconnecter le smartphone du Wifi
- Aller dans les préférences Wifi et "Oublier" le point d'accès correspondant à la caméra
- Lancer la capture de traffic avec Wireshark
- Connecter le smartphone au wifi de la caméra
- Effectuer la capture
Une fois la capture terminée il est possible de vérifier que le 4-way handshake a bien été capturé en filtrant les paquets de type EAPOL (filtre eapol dans Wireshark) et en vérifiant ques les 4 paquets sont bien capturés ("1 of 4", "2 of 4", "3 of 4" et "4 of 4" ).
Pour décrypter le traffic il faut alors se rendre sous Wireshark dans Edit->Preferences->Protocols->IEEE 802.11 Cliquer sur edit keys et ajouter une entrée de type wpa-pwd en entrant dans le champ key lePassword:SSID_du_reseau Valider et cocher les cases "Assume packets have FCS" et "Ignore the protection bit YES - with IV" Retourner ensuite au résultat de la capture, normalement les paquets devraient être décryptés et vous devriez maintenant voir les adresses IP de la caméra et du téléphone.
Exploitation des données capturées
Une fois le trafic décrypté, il faut analyser les différentes trames reçus pour tenter de comprendre le protocole entre le téléphone et la caméra. Tout d'abord, il est simple de constater que les échanges se font dans un premier temps avec le protocole TCP sur le port 6666. On applique ensuite le filtre suivant sur Wireshark afin d'afficher uniquement les trames utiles. L'option "follow TCP stream" est également très pratique.
En parcourant les différentes trames, on remarque un format de paquet commun à toute les trames. Il est facilement reconnaissable car il débute par le magic number 0xABCD.
Sur la caméra, un daemon écoute le port TCP 6666. Le client se connecte au point d'accès puis envoie une demande de connexion contenant un login et un mot de passe. Celui-ci n'est pas chiffré. La caméra accepte ensuite la connexion en renvoyant de nouveau un paquet contenant le login/mot de passe, admin/12345.
Pour démarrer le streaming vidéo, le client envoie le paquet suivant : 0xABCD 0008 0000 01FF 0000. Le flux vidéo est alors envoyé sur le port UDP 6669 au client. De plus, la caméra vérifie régulièrement que le client est toujours présent en envoyant des paquets "Alive Request". En l'absence de réponse, la caméra finit par s'éteindre, considérant le client comme déconnecté. Les commandes associées sont les suivantes : 0x0000 1112 (Alive Request) et 0x0000 1113 (Alive Response).
A partir de maintenant, le format des paquets diffère selon ce modèle :
Il existe 2 types de message UDP. Le type n°1 est celui contenant le flux vidéo au format brute H.264. Le numéro de séquence est incrémenté à chaque paquet. Après un certain nombre de paquets vidéo envoyés au client, la caméra envoie un paquet plus petit de type 2. Celui-ci indique le temps écoulé en milliseconde pour le groupe de paquet précédemment transmis.
De nombreuses autres commandes existent, mais celles présentées ici sont suffisantes pour établir un streaming vidéo minimal.
Streamer sur un PC avec ffplay
Le stream vidéo en diffusé en H264 raw et directement encapsulé dans les trames UDP sans utilisation de protocole particulier. Pour lire le stream il nous suffit donc de simplement supprimer les entêtes UDP et de les lires directement avec ffplay.
En plus de celà nous devons également communiquer avec la caméra sur le port 6666 afin d'envoyer les commandes de login et de démarrage de stream ainsi que répondre à ses keep_alive pour ne pas interrompre le stream. Nous avons ainsi réalisé le programme suivant en nodeJS afin de réaliser ces opérations.
var net = require ("net");
var dgram = require("dgram");
var videoRcv = dgram.createSocket('udp4');
var videoSnd = dgram.createSocket('udp4');
var client = net.Socket();
var elapsed = 0;
var iSeq = 0;
//On se met sur le port 6669 utilisé par la caméra
videoRcv.bind(6669);
var videoBuffer = Buffer.alloc(0);
var rtp = Buffer.alloc(12);
videoRcv.on('listening', function(){
console.log("En attente du stream sur le port 6669");
});
videoRcv.on('message', function(msg, info){
//Récupération du type de payload
var type = msg.readUInt16BE(6);
if(type == 1) {//Type 1 => donnée videoBuffer
videoBuffer = Buffer.concat([videoBuffer, msg.slice(8)]);
} else if (type == 2){
//Décommenter pour streamer sur VLC (Expérimental)
//Et ajouter à VLC un fichier .SDP contenant les lignes suivantes
//m=video 4242 RTP/AVP 99
//a=rtpmap:99 H264/90000
/*
rtp.writeUInt16BE(0x8063, 0);
rtp.writeUInt16BE(iSeq, 2);
//elapsed * 90 à cause du h264
//Le h264 demande un sample rate de 90Hz
rtp.writeUInt32BE(elapsed * 90, 4);
rtp.writeUInt32BE(0, 8);
videoSnd.send(Buffer.concat([rtp, videoBuffer]), 4242, "127.0.0.1");
*/
//Envoie le stream vidéo sur le port 6969 en localhost.
//Peut être lu par ffplay directement
videoSnd.send(videoBuffer, 6969, "127.0.0.1");
elapsed = msg.readUInt32LE(20);
videoBuffer = Buffer.alloc(0);
iSeq++;
} else {
console.log("Type inconnu...");
}
});
client.connect(6666, '192.168.100.1', function() {
console.log("Connexion à la TecTecTec");
//Création du packet de connexion à la caméra
//0x0110 -> demande de login
var packet = Buffer.from([0xab, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
packet.writeUInt16BE(0x0110, 6);
var loginData = Buffer.alloc(128);
//Les identifiants sont passé dans le packet
loginData.write("admin", 0, 5, "ascii");
loginData.write("12345", 64, 5, "ascii");
//On ajoute les données au paquet et on l'envoie
packet = Buffer.concat([packet, loginData]);
//On change l'octet indiquant la taille du paquet pour mettre la nouvelle
packet.writeUInt16BE(packet.length - 8, 2);
sendToClient(client,packet);
});
client.on('data', function(data){
//Commande envoyée par la caméra
var commande = data.readUInt16BE(6);
if(commande == 0x0111){ //Login accepté
console.log("Connexion acceptée");
sendCommand(client, 0xA034); //On demande la version de la caméra
} else if (commande == 0x0112){ //ping?
client.write(Buffer.from([0xab, 0xcd, 0x00, 0x00, 0x00, 0x01, 0x13])); //Demande de continuer le stream
} else if (commande == 0xA035){ //Renvoie la version de la caméra
sendCommand(client, 0x01FF, Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])); //Demande le début du stream
}
});
client.on('close', function() {
console.log("Connexion perdue");
});
function sendCommand(client, commande, payload) {
var p = Buffer.from([0xab, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
packet.writeUInt16BE(commande, 6);
if(payload != null) {
p = Buffer.concat([p, payload]);
}
p.writeUInt16BE(p.length - 8, 2);
sendToClient(client, p);
}
function sendToClient(client, data) {
client.write(data);
}
Une fois ce programme lancé il est possible de lire le stream vidéo avec la commande suivante :
ffplay udp://127.0.0.1:6969
Extension : Streamer via internet
Une extension envisagée du projet est de pouvoir connecter la caméra à un réseau internet pour pouvoir ensuite visualiser le stream vidéo depuis n'importe quel PC. Pour cela il nous faut accéder au software de la caméra. Celle ci fonctionnant sous Android il est nous est possible de nous y connecter en utilisant ADB
Connecter la caméra à un PC
Utiliser un cable micro-USB - USB (Le même que pour la plupart des téléphones Android) pour brancher la caméra sur le PC
Windows
- Télécharger et installer Android Minimal ADB and FastBoot ([1])
- Installer Android SDK
- Connecter la caméra en USB au PC
- Ouvrir Minimal ADB and FastBoot
- Entrer adb devices pour lister les appareils disponibles
- Si la liste est vide
- Ouvrir le gestionnaire de périphérique
- La caméra doit apparaitre dans la catégorie "Android Devices" sous le nom Android. Faire un clic droit et sélectionner Mettre à jour le pilote..."
- Sélectionner "Rechercher un pilote sur mon ordinateur"
- Sélectionner "Choisir parmi une liste de pilotes de périphériques sur mon ordinateur"
- Sélectionner "Afficher tous les périphériques"
- Cliquer sur "Disque fourni..."
- Cliquer sur "Parcourir" et aller dans [emplacement du sdk]\extras\google\usb_driver et sélectionner android_winusb.inf
- Sélectionner 'Android ADB Interface' dans la liste.
- Procéder à l'installation
Linux
Sous la plupart des distribution Linux le gestionnaire de packages permet d'installer très rapidement ADB Par exemple :
Debian, Ubuntu ...
apt-get install adb
Fedora, SUSE ...
yum install android-tools
Si cela n'est pas disponible pour votre distribution vous pouvez suivre ce [tutoriel]
Accéder au shell de la caméra
Une fois la caméra connecté au PC et ADB correctement installé il suffit, dans un terminal de commande d'entre la commande
adb shell
Nous sommes alors dans le système d'exploitation de la TecTecTec.Première surprise nous somme connectés en root, ce qui vas nous faciliter la tâche.
Connecter la caméra à un réseau wifi
Une deuxième surprise nous attends en explorant les fichiers de la caméra, wpa_supplicant est installé alors qu'il est inutile au bon fonctionnement de la caméra. Ce outil nous permettra de connecter la caméra à un réseau wifi en ajoutant un fichier de configuration wpa_supplicant.conf
update_config=1 ctrl_interface=DIR=/data/system/wpa_supplicant GROUP=wifi eapol_version=1 ap_scan=1 fast_reauth=1 network={ ssid="SSID du réseau" psk="la passphrase du réseau" key_mgmt=WPA-PSK priority=241 }
La commande ci dessous permet de se connecter au réseau préconfiguré.
wpa_supplicant -i wlan0 -c <fichier de configuration>
Si une fois la caméra connectée au wifi celle-ci n'as toujours pas d'IP la commande suivante devrait lui en attribuer une.
dhcpcd wlan0
Nous avons utilisé une carte Udoo afin de créer un Hotspot wifi pour y connecter la caméra. Une fois celle-ci joignable sur le réseau il nous a été possible de streamer sur un PC connecté à ce réseau. Afin de diffuser sur Internet il aurait fallut utiliser la deuxième interface réseau de la carte Udoo pour se connecter à l'internet et ensuite permettre à la caméra d'être joignable depuis cette deuxième interface.