Reverse Ingeneering de protocole TCP/IP avec C#
Objectif :
Realiser le Reverse Ingeneering de protocole TCP/IP avec C#.
1) Introduction:
Dans ce document, nous allons aborder les techniques de base de la programmation réseau, réseau signifiant ici aussi bien réseau local que réseau Internet. Nous allons aussi apprendre à faire communiquer deux machines en utilisant le protocole TCP/IP, le protocole retenu par Internet.
Le langage C# offre une simplicité de programmation qui rend ce domaine un peu moins obscure qu'il ne peut l'être en langage C. Nous allons donc voir comment tirer parti des avantages de ce nouveau langage dans notre code.
2) Les sockets :
Faire communiquer deux ou plusieurs systèmes hétérogènes implique évidemment l'adoption de protocoles standardisés. Dans notre cas, nous supposerons qu'il s'agit du protocole TCP/IP adopté par Internet, bien que la classe Socket soit bien plus générale et puisse s'appliquer à d'autres protocoles (UPD, IP, IGMP, ICMP, etc ...).Les objets présentés dans ce chapitre sont issus du namespace System.Net.Sockets.
1. Connexion type client :
Commentaires :
- La classe Socket prends en paramètre de son constructeur 3 données:
- AddressFamily: renseigne sur le modèle d'adresse utilisé par la socket.
- SocketType: indique le type de socket à utiliser : Stream, Row, DGram, etc ...
- ProtocolType: spécifie les protocoles pris en charge par la socket.
- La méthode SetSocketOption permet de d'affecter une valeur à une option en précisant en premier argument le niveau auquel s'applique l'option, en second le nom de l'option et en troisième la valeur de cette option. Ici, c'est l'option de timeout en réception qui a été initialisée à 3 secondes (un appel de réception de données bloquant plus de 3 secondes génèrera une SocketException).
- Les méthodes Send et Receive sont explicit, elles servent respectivement à l'envoi et la réception de données sous forme de tableau de byte.
- Il existe des méthodes d'envoi de réception et de connexions dites asynchrones, elle seront détaillées au chapitre suivant dans la classe TcpClient.
2. Création d'un serveur :
Commentaires :
- L'établissement d'un serveur en écoute commence par la céation d'un objet de type Socket comme pour une connexion type client.
- La méthode Bind permet de lier le socket à une interface et à un port de l'ordinateursur lequel le programme est lancé.
- La méthode Accept renvoi un objet de type Socket correspondant à la connexion avec le client. Cet objet se traite comme précédemment expliquer dans le cas d'une connexion type client.
2. Connexion TCP/IP :
Pour simplifier la programmation de l'accès à des sites Internet, larchitecture .NET fournit les classes TcpClient et TcpListener. Ces classes sont plus simples que la classe Socket et elles conviennent généralement pour accéder à un site en utilisant le protocole TCP/IP. Elles n'offrent cependant qu'un accès restreint au paramétrage des liaisons. La mise en oeuvre des sockets par la classe Socket sera traitée au second chapitre.
1. La classe TcpClient :
a. Procédure de connexion :
Commentaires :
- La classe TcpClient permet d'effectuer une connexion TCP de façon relativement simple à un serveur. Le constructeur prend en premier argument une chaîne représentant soit une adresse IP (ref. exemple), soit un nom d'hôte (www.labo-dotnet.com).
- Une exception est générée si la connexion n'a pu aboutir.
b. Envoi et réception :
Commentaires :
- Le flux de données entrantes ou sortantes est représenté par un objet de la classe NetworkStream ; un tel objet est obtenu en appelant la méthode GetStream d'un objet TcpClient. La classe NetworkStream est dérivée de la classe Stream.
- Nous allons créer un StreamWriter puis un StreamReader à partir de cet objet NetworkStream afin de pouvoir réaliser des envoi et des réceptions de données plus aisément qu'avec les méthodes de base de NetworkStream héritées de Stream. Pour notre exemple cela va nous permettre l'écriture de chaîne et non de tableaux de bytes. L'appel à la méthode Flush va forcer lenvoi des données écrites dans le buffer de sortie (méthode Write) au serveur.
- La méthode Read de StreamReader renvoi un entier (int) contenant le nombre de char lus est inscrits dans le buffer (ici cbuffer).
c. Envoi et réception asynchrones :
Ces méthodes servent à effectuer les opérations qu'elles désignent en parallèle du code, elles sont mises en Thread.
Commentaires :
- Un appel asynchrone de lecture ou d'écriture permet de rendre la main à la méthode appelante immédiatement après cet appel.
- Les méthodes appelées de manière asynchrone sont des déléguées du type AsyncCallback. Cet appel asynchrone ce fait en grâce aux méthodes BeginRead et BeginWrite. En dernier paramètre de ces méthodes on trouve un objet qui est en faite une sorte de paramètre à passer à la méthode de rappel. Cet objet pourra être retrouvé dans la propriété AsyncState de l'interface IAsynResult seul paramètre obligatoire des méthodes de rappel.
- Si une exception est déclenchée lors de l'exécution d'une méthode asynchrone (qui soit dit en passant sexécute dans le ThreadPool), celle si est reportée et déclenchée lors de l'appel à EndWrite ou EndRead. Doù le bloc try-catch qui englobe ces appels.
- EndWrite et EndRead prennent en paramètre une instance de l'interface IAsyncResult qui identifie l'appel asynchrone qui à déclencher la méthode de rappel. En effet il est possible de lancer plusieurs appels asynchrones BeginWrite ou BeginRead les uns après les autres.
2. La classe TcpListener :
La classe TcpListener est semblable à TcpClient mais s'applique au côté serveur.
Commentaires :
- La méthode Parse de la classe IPAddress permet de créer un objet IPAddress à partir d'une chaîne-ip.
- Il existe 3 constructeurs pour la classe TcpListener :
- un dont le seul paramètre est le numéro de port sur lequel binder le serveur (l'adresse réseau par défaut sera utilisée)
- le deuxième celui qui est utilisé dans lexemple, prends en premier argument une IPAddress spécifiant l'interface réseau sur laquelle écouter, le second étant le numéro de port.
- un troisième constructeur existe, il ne prends quun argument IPEndPoint regroupement d'une IPAddress et d'un numéro de port.
- La méthode Pending de la classe TcpListener permet de savoir si il y a actuellement un client en attente dans la queue des demandes de connexions.
- La méthode AcceptTcpClient renvoi sous forme d'un objet de type TcpClient le client qui vient de se connecter.
- Enfin, les méthodes Start et Stop de TcpListener permettent respectivement de démarrer et de mettre fin à l'écoute.
4) Résolutions DNS :
1. Résolution de nom :
Commentaires :
- La méthode GetHostName de lobjet Dns renvoi un objet string contenant le nom de la machine local. Dans cet exemple on récupère toutes les adresses IP associées à la machine.
- La méthode GetHostByName renvoi un objet de type IPHostEntry qui contient les informations sur la résolution du nom passé en paramètre. Cette méthode peut engendrée une exception si la résolution a échoué.
- Le champ AdressList de IPHostEntry est un tableau des adresses IP (IPAddress) associées au nom d'hôte. Le champ 0 de ce tableau correspond l'adresse principale.
2. Résolution d'adresse :
Commentaires :
- Le champ HostName de IPHostEntry contient le nom de l'hôte si la résolution a réussi.
- Une exception peut être générée en cas d'échec.
Conclusion
Les programmes orientés réseau sont généralement introduit par ces deux lignes:
using System.Net;
using System.Net.Sockets;
Mots clé :
- AddressFamily : spécifie le modèle d'adresse pouvant être utilisé par une instance de la classe System.Net.Sockets.Socket.
- AsyncCallback : fait référence à la méthode de rappel à appeler lorsque l'opération asynchrone est terminée.
- Dns : Fournit des fonctionnalités de résolution de noms de domaines simples.
- GetHostByAddress : retourne une IPHostEntry à partir d'une adresse IP.
- GetHostByName : retourne une IPHostEntry à partir d'un nom d'hôte.
- GetHostName : obtient le nom d'hôte de l'ordinateur local.
- IAsyncResult : représente l'état d'une opération asynchrone.
- AsyncState :
- IPAddress : fournit une adresse IP.
- IPEndPoint : représente un point de terminaison du réseau comme une adresse IP et un numéro de port.
- IPHostEntry : fournit une classe conteneur pour les informations sur l'adresse de l'hôte Internet.
- AddressList : liste d'IPAddress de l'hôte.
- HostName : nom de l'hôte.
- ProtocolType : spécifie les protocoles pris en charge par la classe System.Net.Sockets.Socket.
- Socket : implémente l'interface de sockets Berkeley.
- Accept : retourne un objet Socket correspondant à une connexion entrante
- Bind : associe System.Net.Sockets.Socket à un point de terminaison local.
- Send : envoie des données à un System.Net.Sockets.Socket connecté.
- SetSocketOption : affecte la valeur spécifiée à l'option spécifiée.
- Receive : reçoit des données d'un System.Net.Sockets.Socket connecté.
- SocketType : spécifie le type de socket que représente une instance de la classe System.Net.Sockets.Socket.
- SocketException : exception levée lorsqu'une erreur de socket se produit.
- Stream : donne une vue générique d'une séquence d'octets.
- NetWorkStream : fournit le flux de données sous-jacent pour l'accès au réseau.
- StreamWriter : implémente System.IO.TextWriter pour écrire les caractères dans un flux selon un codage particulier.
- StreamReader : implémente System.IO.TextReader qui lit les caractères à partir d'un flux d'octets dans un codage particulier.
- Flush : vide le buffer de sortie, forcant ainsi l'envoi des données.
- Write : écrit une séquence d'octets à partir du flux actuel.
- Read : lit une séquence d'octets à partir du flux actuel.
- TcpClient : fournit des connexions client pour des services réseau TCP.
- BeginRead : démarre une lecture asynchrone d'un flux.
- BeginWrite : démarre une écriture asynchrone dans un flux.
- EndRead : gère la fin d'une lecture asynchrone.
- EndWrite : gère la fin d'une écriture asynchrone.
- GetStream : obtient un objet NetWorkStream associé à cette connexion.
- TcpListener : écoute des connexions de clients réseau TCP.
- AcceptTcpClient : renvoi un objet TcpClient construit à partir d'une connexion entrante.
- Pending : indique si un client est dans la file d'attente.
- Start : démarre l'écoute du serveur.
- Stop : termine l'écoute de ce serveur.
- Thread : crée et contrôle un thread.
- ThreadPool : fournit un pool de threads qui peuvent servir à publier des opérations, à gérer des E/S asynchrones, à attendre au nom d'autres threads et à gérer des minuteries.