IMA4 2016/2017 ECP1
Sommaire
- 1 Présentation du projet
- 2 Travail effectué
- 2.1 Lundi 5 juin
- 2.2 mardi 6 juin
- 2.3 mercredi 7 juin
- 2.4 jeudi 8 juin
- 2.5 vendredi 9 juin
- 2.6 lundi 12 juin
- 2.7 mardi 13 juin
- 2.8 mercredi 14 juin
- 2.9 Vendredi 16 juin
- 2.10 lundi 19 juin
- 2.11 mardi 20 juin
- 2.12 Mercredi 21, jeudi 22juin
- 2.13 lundi 26, mardi 27 juin
- 2.14 jeudi 29 juin
- 2.15 vendredi 30 juin
- 2.16 samedi 1 juillet
- 2.17 Lundi 3 juillet
- 3 =mardi 4 juillet
- 4 Documents
- 5 rendu projet final
- 5.1 Récapitulatif
- 5.2 Enlever la demande des adresses Ethernet du formulaire
- 5.3 implémenter la gestion des écho-requêtes et réponses d’écho
- 5.4 implémenter la creation et gestion des paquets ICMP de type 5
- 5.5 créer un serveur Websocket
- 5.6 créer une interface virtuelle
- 5.7 faire communiquer les différents modules
- 5.8 Le schema
- 6 Sources
Présentation du projet
Contexte
L'élève effectue son stage au Vietnam sans aucun matériel informatique personnel. Il lui est proposé une EC purement logicielle pouvant être développée sur n'importe quel système d'exploitation. Une machine virtuelle Linux est cependant nécessaire pour une partie du projet.
Objectif
L'objectif est de compléter un simulateur réseau écrit en JavaScript et tournant dans un navigateur. Ce simulateur se trouve à l'adresse http://rex.plil.fr/reseau.
Description du projet
Il est demandé d'ajouter la gestion des paquets ICMPv4 au simulateur. Cet ajout doit se faire proprement avec gestion des paquets ARP et mise en file d'attente des paquets IPv4 en attente de résolution d'adresses IPv4 en adresses Ethernet. Les paquets ICMPv4 à gérer sont les paquets de demande (ICMP de type 8) et de réponse d'écho (ICMP de type 0) ainsi que les paquet de redirection de route (ICMP de type 5). Les machines et les éléments du réseau pourront ainsi être testées par la commande ping
mais aussi générer une erreur ICMP lorsqu'un paquet ne peut pas être routé pour diverses raisons.
En parallèle, pour tester la gestion des ICMPv4, il est demandé que le simulateur puisse gérer des éléments "externes". Le comportement de ces éléments ne sera pas pris en charge par le simulateur mais par un système d'exploitation externe. Le simulateur se contentera d'envoyer les paquets destinés aux éléments externes à une interface Ethernet virtuelle d'une machine Linux. A l'inverse, les paquets générés par l'interface virtuelle seront injectés dans le simulateur. La communication entre le simulateur et les interfaces virtuelles doit s'effectuer par des serveurs WebSocket. Vous utiliserez la bibliothèque WebSocket 2.x de Linux.
Cahier des charges
Un schéma d'ensemble précis du système est demandé. Ce schéma doit à la fois représenter l'architecture de communication entre le simulateur et les interface Ethernet virtuelles mais aussi l'architecture interne des modules du simulateur.
Modifier le programme de façon à enlever la demande d'adresse Ethernet. Les stations trouveront les adresses grâce au protocole ARP.
Planning prévisionnel
Travail effectué
Lundi 5 juin
J'ai tout d'abord commencé à me familiariser avec le logiciel de simulation et tenté de comprendre comment celui-ci fonctionnait. j'ai ensuite ouvert les pages HTML et JAVASCRIPT pour comprendre comment elles étaient organisées. Après avoir relus les notions de bases en java script, ainsi que mes cours de réseau j'ai tenté de comprendre pourquoi une des simulations fournies ne fonctionnait pas. En effet sur le schéma le plus complexe, deux stations ne sont pas capables de recevoir les paquets. Le problème venait d'une mauvaise configuration des masques. Les paquets ARP semblent fonctionner pourtant il m'est demandé de veiller à leur bon fonctionnement dans le cahier des charges.
mardi 6 juin
Après discussion avec Monsieur Redon, j'ai eu la confirmation qu'une coquille au niveau de l'adressage des stations était présente. Deux stations se trouvaient hors du réseau sur la table de routage du routeur. J'ai donc changé leurs adresses et cela refonctionne:
- nouvelle adresse de la station 4: 192.168.1.200
- nouvelle adresse de la station 3: 192.168.2.200
mercredi 7 juin
J'ai commencé à modifier le formulaire IP. L'adresse Ethernet source est maintenant déterminée automatiquement grâce à l'adresse IPV4. En effet grâce à l'adresse IPV4, on peut aller chercher, dans les div, directement l'adresse MAC associée. On retrouvera, dans la fonction de création de paquet, le code suivant qui permet de récupérer l'adresse MAC.
for(i=0;i<elements.length;i++){ if (elements[i].find("[class=ip4port]").text() == ip4source_value){ var ethsource_value = elements[i].find("[class=ethport]").text(); var ethsource_color = elements[i].find("[class=ethport]").css('background-color'); } }
Pour pouvoir trouver l'adresse MAC du destinataire, nous faisons appel au protocole ARP afin de simuler avec exactitude le fonctionnement d'un réseau. j'ai donc, pour éviter la redondance de code, relu les fonctions ARP utilisées pour le routeur. Je vais donc en utiliser plusieurs pour pouvoir mettre en place ce protocole au niveau des stations. Je pourrai, après avoir mis cela en place, m'attaquer à la construction du protocole de couche 3 de détection d'erreur: le protocole ICMP.
jeudi 8 juin
Je travaille aujourd’hui sur la recuperation de l’adresse Ethernet via protocole ARP. En utilisant des fonctions existantes, dont une que j'ai légèrement modifiée, j'arrive à faire circuler les paquets ARP dans le même réseau. Ainsi deux machines dans un même réseau peuvent communiquer avec seulement leur adresse IP comme adresse de départ. Cette partie de code permet de retrouver les éléments sources nécessaire à l'envoi d'un paquet IPV4. Toutefois nous pouvons constater qu'il nous manque l'adresse Ethernet destination. Je récupère dans cette partie le cache ARP en prévention pour la partie suivante.
//recherche de l'adresse ethernet,port,cache arp source grâce à l'adresse ip donnée for(i=0;i<elements.length;i++){ if (elements[i].find("[class=ip4port]").text() == ip4source_value){ var ethsource_value = elements[i].find("[class=ethport]").text(); var ethsource_color = elements[i].find("[class=ethport]").css('background-color'); var port = elements[i].find("[class=port]"); var arp=elements[i].children('.cachearp');
Dans la partie de code suivante je cherche dans le cache ARP l'adresse MAC, si l'adresse n'est pas dans le cache, je crée un paquet ARP à envoyer grâce à une fonction déjà existante que j'ai un peu adapté. J'ai donc crée "station_route_ip4" qui est fortement inspirée de "router_route_ipv4".
//requête ARP pour retrouver l'adresse Mac destinataire var entry=cachearp_find_address(arp,ARPtarget_value); if(entry===undefined){ station_route_ip4_retry(form,port,ARPtarget_value);//fonction qui route un paquet arp} else {suite du code pour creation IPV4}
vendredi 9 juin
Le problème rencontré est le suivant: Si je possède l'adresse IP d'une machine d'un autre réseau, alors le routeur, ne reconnaissant pas son adresse IP lors de la demande ARP, ne renvoie pas son adresse MAC. Je suis donc en train de mettre au point une consultation de la table de routage de la station source. Ainsi la station émettrice enverra un paquet ARP avec l'adresse IP du routeur correspondant si elle constate que la machine réceptrice ne se trouve pas dans son réseau.
//on regarde si l'adresse IP est dans le réseau var ip=ip4addr_to_array(ip4target_value); elements[i].find('.route').each(function(i,obj){ var masque = ip4addr_to_array($(obj).children('.route_masque').text()); var reseau = array_to_ip4addr(array_and(ip,masque)); if(reseau == $(obj).children('.route_adresse').text() && reseau != '0.0.0.0') {ARPtarget_value=ip4target_value;bool=true;} if(bool==false) {ARPtarget_value='192.168.1.1';}
Dans le code ci-dessus, je cherche dans la table de routage si la station destinataire se trouve dans le réseau. Si elle se trouve dans un autre réseau,l'adresse destinataire du cache ARP sera celle de la bonne passerelle. Ces modifications ont toutes été faites dans la fonction create_ip4_packet_from_form(form).
Je peux maintenant commencer la partie ICMPV4.
Je me suis donc renseigne sur les paquet ICMP que je devrai gérer:
- Le paquet de type 8 est un echo request.
- Le paquet de type 0 est un echo reply.
Le ping est en réalité une combinaison de ces deux paquet ICMP.
- le paquet de type 5, ICMP redirect, indique qu'il y a un chemin plus court vers la destination.
lundi 12 juin
Avant de commencer à ajouter la gestion de paquets ICMP dans mon simulateur, j'ai d’abord décidé de créer le serveur, et de faire en sorte de gérer les paquets Ethernet entrant et sortant sur mon interface.
Le serveur Websocket, de base, fait avec la librairie Websocket linux est disponible dans la partie Document. Il porte le nom serveur.txt (ce n'est pas la version finale). Ce serveur contient les fonctions de bases pour pouvoir communiquer avec notre client simulateur. Je devrai le modifier légèrement pour qu'il puisse réceptionner des trames écrites dans le terminal afin de les transmettre directement au simulateur qui enverra le paquet de l'adresse source à l'adresse destination.
Maintenant que mon serveur tourne, je rajoute le code nécessaire dans le client, c'est à dire sur la page réseau.js. dans le main().
Toutefois je rencontre un problème: Quand je crée une connexion dans le main et que j'utilise cette connexion hors du main pour envoyer un message cela ne fonctionne pas. Je soupçonne que lors de la fin du main(), la connexion se ferme.
J'ai donc lancé cette fonction, non dans la fonction principale, mais dans la fonction "router_enqueue_packet(queue,packet,laddr,paddr)". En effet c'est cette fonction qui est exécutée à la fin du voyage d'un paquet pour le stocker en mémoire sur la station correspondante. A présent la station stocke dans sa mémoire et restitue le paquet, sous forme d'une trame d'octets, au serveur qui l'imprime dans le terminal. Il reste à l'envoyer par l'interface virtuelle.
mardi 13 juin
j'ai essayé de comprendre comment envoyer un paquet internet depuis le serveur. Mais je n'arrive toujours pas à initialiser une connexion depuis le serveur. De plus pour lire les entrées clavier, j’ai voulu utiliser la fonction read. Mais cette fonction est bloquante. Le serveur n'est donc plus à l’écoute des messages arrivant du simulateur.
mercredi 14 juin
J'ai réussi à concevoir mon interface Ethernet virtuelle. Comme vous pouvez le voir je n'ai pas encore rajouté l'option O_NONBLOCK car il me reste des soucis dont je vais parler plus bas.
int creationInterfaceVirtuelle(char *nom) { struct ifreq interface; int fd,erreur; /* Ouverture du peripherique principal */ if((fd=open(TAP_PRINCIPAL,O_RDWR))<0) { printf("error open"); return fd; } /* Preparation de la structure */ memset(&interface,0,sizeof(interface)); interface.ifr_flags=IFF_TUN|IFF_NO_PI; if(nom!=NULL) strncpy(interface.ifr_name,nom,IFNAMSIZ); /* Creation de l'interface */ if((erreur=ioctl(fd,TUNSETIFF,(void *)&interface))<0){ close(fd); return erreur; } /* Recuperation du nom de l'interface */ strcpy(nom,interface.ifr_name); /*retour du descripteur*/ return fd; }
Il m'a fallu rajouter dans le main les infos importantes pour lancer mon interface
char *a_name = malloc(IFNAMSIZ); strcpy(a_name,"tun77"); fd=creationInterfaceVirtuelle(a_name);
Maintenant que l'interface est fonctionnelle je peux utiliser un read() pour recevoir des trames émises par PING sur un autre terminal.
while (1) { //lws_service(context, 50); nread = read(fd,buffer,sizeof(buffer)); if(nread < 0) { perror("Reading from interface"); close(fd); return -1; } printf("Read %d bytes from device %s\n", nread, a_name); for(int i=0;i<84;i++){printf("%x ",buffer[i]);} printf(" \n"); }
Comme vous pouvez le voir, lws_service(...) est en commentaire. Je rappelle que cette fonction est celle permettant à mon serveur de communiquer avec le simulateur. En effet le problème rencontré est que si je décommente cette ligne, je ne recevrai pas tous les messages du simulateur, car la fonction read est bloquante. Mais si je rajoute O_NONBLOCK j'ai une erreur à la lecture du read. Je n'ai pas encore trouvé de solution. Avant de pouvoir utiliser PING, j'ai du procéder à quelques commandes pour lier mon descripteur de fichier et une adresse IP. Les voici:
openvpn --mktun --dev tun77 ip link set tun77 up ip addr add 10.0.0.1/24 dev tun77
Je dois faire ces commandes à chaque fois que j'allume le PC.
j'ai de plus, un dernier problème. Les trames reçues, qui doivent être des trames ICMP, que je demande d'afficher en hexadécimale ne sont pas celles attendues... En effet j'ai des chiffres complètement incohérents et je ne sais pas comment retrouver une trame, avec le protocole ICMP, cohérente.
Vendredi 16 juin
Après discussion avec mon professeur, Mr Redon, il s'est avéré que mes trames reçues étaient bonnes. Je suis donc en train de d'essayer de les envoyer vers mon simulateur. Toutefois je rencontre un problème: Il m'a été conseillé d'utiliser régulièrement la fonction callback_on_Writable pour pouvoir déclencher un événement de ce genre:
case LWS_CALLBACK_SERVER_WRITEABLE: { //envoie du paquet ICMP reçu par le PING unsigned char *buf = (unsigned char*) malloc(LWS_SEND_BUFFER_PRE_PADDING + len + LWS_SEND_BUFFER_POST_PADDING); int i; ......................................... ........................................ } break; }
Mais je ne vois pas où appeler cette fonction. Elle nécessite une instance (wsi), je ne peux donc pas l'appeler dans le main... Une fois ce problème résolu je n'aurai plus qu'à traiter l'envoi de ces trames dans le simulateur et mon projet sera terminé.
lundi 19 juin
Je bloque sur le même sujet. Je récupère de l’interface virtuelle des octets que je stocke dans un tableau de caractère. Même si je sais que un octet et un char font la même taille, je ne comprends pas comment on peut les stocker alors que ce n’est pas le bon type. De plus je veux envoyer cette chaîne de caractère au simulateur mais cette chaîne contient des bytes qui ne sont pas lisible à part avec un printf(%x). j'ai cherché comment transformer les bytes en caractère mais je n’ai pas réussi. Recevant des chaînes de caractère du simulateur, je n’arrive pas non plus à les envoyer à l’interface car elles ne sont pas du bon type (error :EINVAL).
mardi 20 juin
En utilisant la fonction sprintf() j'ai réussi à récupérer les bytes de l'interface et à les stocker sous forme de tableau de caractère. voici le code ci-dessous
if(read(fd,buffer,84)>=0) { printf("Read bytes from device %s\n", a_name); for(int i=0;i<84;i++) { sprintf(&trame[(LWS_SEND_BUFFER_PRE_PADDING)+i*3],"%x",buffer[i]); sprintf(&trame[(LWS_SEND_BUFFER_PRE_PADDING)+(i*3)+2]," "); } printf(" \n"); for(int i=0;i<252;i++) { printf("%c",trame[i]); } printf(" \n"); }
La deuxième boucle for ne sert juste qu'à afficher la trame pour vérifier le contenu.
LWS_SEND_BUFFER_PRE_PADDING est une partie qu'il faut que je laisse libre pour l'envoi par le socket. Etant donné que pour représenter un nombre hexadécimal il nous faut deux caractère et que je sépare chaque groupe d'un espace, je place donc la valeur du buffer puis j'avance de trois cases dans la chaîne. Le deuxième sprintf() ne sert juste qu'à mettre des espaces dans les bonnes cases de mon tableau.
J'avais un problème au niveau de ma chaîne récupérée car je réceptionnais des valeurs de ce type "ffffffxx". J'ai compris que j'avais un dépassement dans la mémoire car la valeur était négative. J'ai juste eu à préciser que le type de ma chaîne était "unsigned char".
Après ceci je procède à l'envoi de ma trame grâce à la partie du code suivante.
case LWS_CALLBACK_SERVER_WRITEABLE: { //envoi du paquet ICMP reçu par le PING lws_write(wsi,&trame[LWS_SEND_BUFFER_PRE_PADDING],252,LWS_WRITE_TEXT); printf("test ok \n"); break; }
J'envoie donc mon code en laissant bien de la place au début de ma trame pour que l'envoi réussisse. Pour l'instant le simulateur n'affiche qu'une alerte de réception de la trame. Il faut donc que je gère l'envoi de cette trame comme un paquet ICMP à travers le simulateur.
Mercredi 21, jeudi 22juin
Étant donné que je passe ma soutenance de stage mercredi prochain, j'ai mis mon projet de coté pour pouvoir finir mon rapport et avancer le plus loin possible sur le travail demandé.
lundi 26, mardi 27 juin
Après avoir réussi à recevoir une trame venant de mon PING sur le simulateur, j'ai donc commencé à la traiter. Je crée donc une fonction ICMP_create_request(Nouveau nom: serveur_create_packet). Dans cette fonction, je récupère les deux strings des adresses IP source et IP destination que je transforme en forme décimale (exemple: 192.1.23.215).
function icmp_create_request(trame){ var ip4src=""; var ip4tgt=""; var bool=false, ARPtarget_value; for(i=36;i<=47;i++){ ip4src+=trame[i]; ip4tgt+=trame[i+12] } var ip4srcaddr= array_to_ip4addr(bytes_to_array(ip4src)); var ip4tgtaddr= array_to_ip4addr(bytes_to_array(ip4tgt));
Comme avec le formulaire, je viens récupérer l'adresse Ethernet source, la couleur de l'adresse, le cache ARP et la couleur de l’adresse IP source aussi.
//recupere l'adresse ethernet/couleur/arp/port de la source for(i=0;i<elements.length;i++){ if (elements[i].find("[class=ip4port]").text() == ip4srcaddr){ var ethsource_value = elements[i].find("[class=ethport]").text(); var ethsource_color = elements[i].find("[class=ethport]").css('background-color'); var ip4srccolor = elements[i].find("[class=ip4port]").css('background-color'); var port = elements[i].find("[class=port]"); var arp=elements[i].children('.cachearp');
Comme avec le formulaire, je regarde si l'adresse IP est dans le réseau, pour savoir si la trame ARP doit garder comme IP de destination l'IP de la station ou prendre l'IP du routeur.
//on regarde si l'adresse IP est dans le réseau var ip=ip4addr_to_array(ip4tgtaddr); elements[i].find('.route').each(function(i,obj){ var masque = ip4addr_to_array($(obj).children('.route_masque').text()); var reseau = array_to_ip4addr(array_and(ip,masque)); if(reseau == $(obj).children('.route_adresse').text() && reseau != '0.0.0.0') {ARPtarget_value=ip4tgtaddr;bool=true;} }); if(bool==false){ARPtarget_value='192.168.1.1';} //adresse par Default que l'on peut aller chercher dans la table de routage } if (elements[i].find("[class=ip4port]").text() == ip4tgtaddr){ var ip4tgtcolor = elements[i].find("[class=ip4port]").css('background-color'); } }
On cherche dans le cache arp pour voir si nous disposons de l'adresse ethernet, sinon on envoie une demande arp.
var entry=cachearp_find_address(arp,ARPtarget_value); if(entry===undefined){ arp_create_request(port,ARPtarget_value); setTimeout(function(){ icmp_create_request(trame);},IP4_RETRY_DELAY); }
Si on possède l'adresse Ethernet on envoie notre trame ICMP encapsulée dans un paquet IPV4.
else { var ethtarget_value=entry['ethernet']; var ethtarget_color=find_address_color('ethport',ethtarget_value); packet=create_ip4_packet(ethsource_value,ethsource_color,ethtarget_value,ethtarget_color, ip4srcaddr,ip4srccolor,ip4tgtaddr,ip4tgtcolor,"64","1",trame,false); send_packet_from_source(packet); } }
J'ai de plus commencé à traiter ces paquets. Lorsqu'ils arrivent en fin de course, je reconnais le paquet ICMP et j'envoie un paquet ICMP de réponse d’écho (type 0).
jeudi 29 juin
Aujourd'hui j'ai avancé sur les paquets ICMP dans le simulateur. j'ai pu mettre en place des nouvelles fonctions:
La fonction permettant de savoir si on a affaire à un paquet ICMP.
function packet_is_icmp(packet){ var content=packet.children("input[name='contenu']").val(); var bytes=bytes_to_hexa(content); alert(bytes[34]+bytes[35]); return (bytes[34]+bytes[35]=='0800'); }
La fonction qui permet de renvoyer un paquet ICMP transformé en réponse. Je travaille sur cette dernière car elle n'est pas encore au point.
function icmp_return_answer(packet){ var temp=[]; var content=packet.children("input[name='contenu']").val(); var bytes=bytes_to_hexa(content); for(i=0;i<4;i++){ temp[i]=bytes[i+26]; bytes[i+26]=bytes[i+30]; bytes[i+30]=temp[i]; } for(i=0;i<6;i++){ temp[i]=bytes[i]; bytes[i]=bytes[i+6]; bytes[i+6]=temp[i]; } for(i=0;i<4;i++){ temp[i]=bytes[i+46]; bytes[i+46]=bytes[i+50]; bytes[i+50]=temp[i]; } bytes[54]="00"; alert(bytes); content=hexa_to_bytes(bytes); packet.children("input[name='contenu']").val(content); //on renvoie la paquet send_packet_from_source(packet); }
J'ai de plus rencontré plusieurs erreurs. Je ne supprimais pas l'entête IPV4 sur mes paquets ICMP entre le serveur et le simulateur, donc j'avais deux entêtes empilées. Je n'arrive toujours pas à envoyer une trame du serveur vers le simulateur, si je n'ai pas au préalable envoyé un message du simulateur au serveur.
L’idée principale reste de réussir à faire naviguer une question réponse, en aller retour, de mon interface jusque mon simulateur.
vendredi 30 juin
J'ai réussi à récupérer un paquet ICMP de type 0 (un paquet de réponse à un écho) sur mon serveur. Je le stocke dans un tableau. Il me reste donc à l'envoyer sur mon interface virtuelle. J'ai une erreur sur le write() qui me permet d'envoyer ce paquet ICMP à l'interface. En effet l'erreur est de type EINVAL. Je sais que ça doit être ma trame le problème. Je n'arrive cependant pas à comprendre pourquoi elle serait invalide. Je cherche encore. En parallèle j'essaye de comprendre comment fonctionne le lws_on_writable. Je l'appelle dans l'initialisation mais je dois donc attendre un premier message du client. Mon serveur ne commence donc à envoyer les PING reçus, au simulateur, seulement après réception d'un premier message.
Je bloque aussi sur un problème de fermeture de serveur coté client. En effet quand je tape la commande "ws.close()" qui ferme le connexion "ws" que j'ai lancé auparavant, mon programme plante.
samedi 1 juillet
Ne trouvant pas pourquoi ma trame ne passe pas dans la fonction write(), j'ai réglé les autres problèmes: Mon serveur arrive à communiquer avec le simulateur dès que nous chargeons la page du simulateur. Il gère, tout seul, les paquets ICMP entrants et sortants. La fonction qui m'a permis d'automatiser cela et le suivante. J’appelle cette fonction récursive dans le main de reseau.js. Elle récupère un message envoyé du serveur, le compare à celui qu'elle a reçu précédemment. Si c’est le même la fonction ne fais rien, si il est différent, elle crée une requête ICMP. Après la requête, elle se rappelle elle même.
function received_ICMP(){ //connexion au serveur Websocket var ws= new WebSocket('ws://localhost:9500','my'); ws.onmessage = function(evt) { var received_msg = evt.data; var trame = bytes_to_hexa(received_msg); if(temp!=trame[5]){ icmp_create_request(received_msg); } temp=trame[5]; //alert(temp); received_ICMP(); ws.close(); }; ws.onerror = function () {alert("non connecte au serveur");}; ws.onclose= function (){//alert("message envoye et connection ferme");}; }
}
Le petit problème et que le nombre de ping en continue est trop nombreux pour le simulateur qui crash. j'envoie donc une dizaine de ping à chaque fois, pas plus. J'ai aussi réussi à fermé mes connexions grâce à ws.close(). Il s'est avéré que je tapais cette commande au mauvais endroit.
Lundi 3 juillet
J'ai change la fonction enqueue_packet de façon à ce qu'elle laisse passer tout les paquets vers le serveur. Le serveur reçoit donc les requêtes ICMP et ARP ainsi que leurs réponses. Il reçoit de plus les paquets de donné classiques envoyés depuis le formulaire. Je cherche à mettre en place le code ICMP 5 mais je travaille sur le simulateur n'ayant qu'un routeur. Je ne sais donc pas comment tester cette partie.
J'ai travaillé sur le message ICMP5. Le routeur remarque que la route qu'a choisie l'ordinateur émetteur n'est pas optimale car le prochain routeur à passer pour atteindre le destinataire se trouve sur le même réseau que celui de l'ordinateur émetteur. Le routeur envoie l'adresse du prochain routeur à ajouter dans la table de routage de l'ordinateur émetteur de façon que le prochain envoi vers le même destinataire ne passe pas inutilement par lui.
J'ai donc implémenté une fonction dans "router_route_ip4_packet". Cette fonction "redirection(ipdest,srcip4,self)" envoie un paquet icmp 5 si elle constate que l'adresse ip source et ip destination sont dans le mème réseau et que le message ne devait pas passer par lui.
function redirection(ipdest,ipsource,self,port){ var masque = ip4addr_to_array("255.255.255.0"); var reseau_src = array_and(ipsource,masque); var reseau_tgt = array_and(ipdest,masque); if(reseau_src == reseau_tgt){ var ethsrcaddr=port.children('.ethport').html(); var ethsrccolor=find_address_color('ethport',ethsrcaddr); var ethtgtaddr=//a recuperer; var ethtgtcolor=//a recuperer; var icmp= "05 00 ff ff " icmp+=ethaddr_to_hexa(ethsrcaddr)+' '+ip4addr_to_hexa(ip4srcaddr)+' '; icmp+="00 00 00 00 00 ";
packet=create_eth_packet(ethsrcaddr,ethsrccolor,ethtgtaddr,ethtgtcolor,icmp,false); send_packet(packet,port); }
}
Cette fonction n'est pas encore fini car je n'ai pas encore récupéré toutes les informations pour envoyer le paquet Ethernet à la source.
De plus je ne savais pas comment faire pour définir quelle station transférerai les messages envoyés par le serveur web. Dans le code "serveur_create_packet" j'ai arbitrairement entré l'adresse d'une des quatre stations. Je ne sais pas comment faire autrement.
J'ai corrigé la fonction received_ICMP qui s’appelle maintenant Received_paquet.
=mardi 4 juillet
Apres discussion avec le professeur, j'ai compris comment recevoir des trames ARP directement de l'interface virtuelle. J'ai eu plusieurs problèmes car mon interface était de type TUN mais pour recevoir les paquets ARP il fallait qu'elle soit de type TAP. Maintenant je reçois bien des paquets ARP que je peux visualiser grâce a la commande tcpdump. Hors quand je les affiches j'ai ce type de trame:
ff ff ff ff ff ff 16 46 1f 64 d4 ae 88 d6 60 c1 b8 c0 16 34 10 f1 16 46 1f 64 d4 ae a0 01 11 41 10 f0 f0 60 d0 a0 a0 31 e1 32 00 00 80 00 00 00 00 00 f0 60 d0 fb 14 e9 14 e9 70 35 ce 5f 70 60 70 40 60 62 60 60 60 60 60 c0 f5 5f 69 70 70 73 74 5f 74 63
je n'arrive pas a retrouver les différentes adresses et valeurs composants la trame. J'essaye de voir comment régler ce contre temps.
En mettant mon buffer en type char et pas unsigned char j’obtiens cette trame, qui me parait plus logique:
//ethernet ff ff ff ff ff ff broadcast 16 46 1f 64 ff ff adresse source f8 a6 type de protol //ARP 00 01 Ethernet (10Mb) 08 00 IP 06 ethernet 04 ipv4 00 01 request requete 16 46 1f 64 ff ff adresse mac source a0 a1 01 01 adresse ip source 00 00 00 00 00 00 mac destination a0 01 01 02 adresse ip destination //bourrage 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
j'ai des problèmes sur ma traduction de ma trame de bytes vers string car on voie bien que mon type de protocole devrait être "08 06" et qu'il est de f8 a6 On voit aussi pour les adresse ip que je récupère "a0...." alors que je devrais récupérer "0a...." car je ping a l'adresse "10.1.1.2".
En redémarrant le serveur je me suis aperçu que l'erreur disparaissait toute seule... je ne sais pas a quoi elle était due.
J'ai un problème avec les paquets ARP réponses devant sortir du simulateur. Je n'arrive pas a les récupérer sur mon serveur. J'ai trouve la raison. Il s’avère que l'adresse Ethernet du système est différente de celle de ma machine simulée. donc la station simulée pense que le paquet n'est pas pour elle. De plus, laissant passer tout les paquets je reçois un multitude de paquets ARP qui font crasher mon simulateur.
Après discussion avec le professeur j'ai du modifier l'adresse Ethernet de système faisant le ping. Voici le résultat.
link/ether 00:11:11:11:11:01 brd ff:ff:ff:ff:ff:ff inet 192.168.1.100/24 scope global tap0 valid_lft forever preferred_lft forever
Documents
rendu projet final
C'est ici que vous trouverai le rendu mon projet en pièce jointe. Je vais de plus essayer de détailler les différentes fonctions que j'ai modifiee ou creer et d'indiquer ou elles se trouvent pour que vous puissiez vous retrouver dans les différentes pages de code. J'ai partager mon boulot en plusieurs partie sur les quelles je travaillais en parallèle. Ces parties sont listées ci dessous.
Récapitulatif
- Enlever la demande des adresse Ethernet du formulaire
- implémenter la gestion des écho-requêtes et réponses d’écho(ICMP 8 et 0)
- implémenter la creation et gestion des paquets ICMP de type 5
- créer un serveur Websocket
- créer une interface virtuelle
- faire communiquer les différents modules
- fournir un schéma de l'architecture du projet
Enlever la demande des adresses Ethernet du formulaire
J'ai enlevé les demandes d'adresses Ethernet dans la page formip4.html. Je récupère l'adresse destination grâce au protocole ARP et l'adresse source dans les div. Toutes les modifications faites pour récupérer les adresses se trouve dans la fonction create_ip4_packet_from_form. Dans cette fonction, je cherche aussi si l'adresse IP destination est dans le réseau. Cela me permet de savoir a qui envoyer le paquet ARP(si l'adresse IP n'est pas dans le réseau j'envoie le paquet ARP au routeur). Vous aviez coder une fonction du même type pour chercher le réseau mais je n'ai pas réussi a la comprendre. j'ai donc code la mienne. je ne pense pas qu'elle soit mieux mais je me suis dis que c’était mieux que rien
implémenter la gestion des écho-requêtes et réponses d’écho
A la réception des paquets j'ai tout d’abord cree une fonction serveur_create_paquet qui faisais le meme travail de creation de paquet que celle utilise avec le formulaire. sauf qu'elle puisait les information necessaire dans la trame recue et non le formulaire.
Je n'utilise plus cette fonction car le professeur m'a conseille de récupérer directement les trames du serveur de les encapsuler et de les envoyer directement tel quelle sur le simulateur. C’est donc le système lui même qui lors du ping, envoyait les paquets ARP a transmettre dans le simulateur, etc. vous la trouverez quand même dans mon code en commentaire car elle fonctionnait et je ne voulais pas supprimer du travail accompli. la fonction maintenant utilisee est received_paquet() dont je parlerai dans la communication entre module. Les paquets envoye sur le reseau devait etre analyse et permettre l'envoi d'une reponse. Vous trouverai donc, dans la fonction router_behaviour, la fonction packet_is_request_icmp qui determine si un paquet recu par une machine et bien un paquet icmp et aui le cas echant renvoie vers la fonction icmp_return_answer. Cette fonction utilise le paquet icmp d’écho et crée a partir de la, un paquet ICMP de réponse a l'attention de la machine ayant lance la requête.