#+TITLE : Prise de notes CM 4I001 ARES
Olivier Fourmaux ([email protected]) 4I001
Suppose la complétion du cours 3I014 (Introductions aux réseaux). Tanenbaum (cours de licence)
Mais cours conçu pour être autosuffisant.
On se concentrera sur TCP/IP, les mécanismes dynamiques anti-congestion.
On part des applications, pour se rapprocher des protocoles et des technologies de bas niveau.
TD et TME sont sur 4 heures contigües. Dans une salle qui a une architecture qui permet la séparation client serveur (14-15:503).
10 semaines (2 semaines par partie) 10 * 2 CM 10 * 4 TD/TME (Lab)
Les cours et les labs sont sur la même semaine (inhabituel : une semaine de décalage en général)
Examens répartis (pas de règle du max, moyenne)
1 antisèche manuscrite (recto-verso) autorisée. 3-4 questions.
Rattrapage non-autorisé si note supérieure à 10.
Examen a lieu le vendredi 8 novembre. Tout sur applicatif et transport
Documents et supports de cours sont sur la page perso.
Les traces de trafic sont pré-enregistrées et consultables sur le site (en cas de panne, c’est normalement à nous à l’enregistrer). Les traces sont faisables depuis la maison (droits d’administrateur sur le paquet de logging et de traçage).
Annales d’examen
Les mécanismes de base ont assez peu changé. (TCP/IP est stable depuis les années 90).
Ce sont le réseau et les applications qui changent.
Réseau transit : Réseau sans machine terminale
Bonne intégration entre UNIX et IP (développé par les mêmes personnes)
Ces services diffèrent en certaines caractéristiques (ordonnancement, fiabilité, contrôle de flux ou congestion). On n’a pas de caractéristique de qualité de service, de débit ou de contrainte de temps dans la définition de ces services.
Groupes de travail IETF réguliers. Les standards sont des standards de fait plutôt que de droit.
Ce sont les protocoles qui sont contrôlés, pas les machines connectées.
Les applications font abstraction de la topologie du réseau.
Modèle client-serveur Modèle p2p
On peut distinguer différents types de délais :
- Traitement dans le noeud (incompressible)
- File d’attente (nul si pas de congestion)
- Délai de transmission (dépend de la taille du paquet)
- Propagation (Le paquet ne peut pas aller plus vite que la vitesse de la lumière)
à l’origine, Internet était conçu pour le transfert de fichiers.
Dans la couche applicative, on raisonne de bout en bout : on fait abstraction du réseau (des couches inférieures).
Plusieurs architectures possibles :
- N Clients - 1 serveur : fonctionne sur des requêtes simples, ou pour un petit nombre de clients
- N Clients - M serveurs : Des séries de serveur (plus complexe, plus résilient)
- N Clients-serveurs : P2P
La couche applicative de TCP/IP correspond aux couches Applications, Présentation et Session du modèle OSI.
Protocoles TELNET, RLOGIN (unix old-school), SSH (unix new-school).
Application de type client serveur.
On a surtout besoin d’interactivité (il ne faudrait pas attendre le prompt trop longtemps).
Notion de Network Virtual Terminal : il faut savoir séparer les commandes (contrôle) des données (caractères du terminal) (contrôle dans la bande).
Aujourd’hui, on utilise Secure Shell (ssh), qui contrairement à telnet ou rlogin, garantit la confidentialité et l’intégrité des données transférées.
Il n’est pas question ici des systèmes de fichiers distants (NFS, SSHFS, SMB), mais des transferts de fichiers explicites.
Signalisation out-of-bands : deux connexions, de contrôle (en général 21) et une de données (en général 20).
Accès interactif (ce qui est une contrainte plus qu’un avantage).
Une connexion par fichier : créé automatiquement une séparation entre les fichiers.
FTP est un vieux protocole, dispose de pleins d’options historiques. Dans les faits, on s’en sert aujourd’hui sur des fichiers non-structurés, codés en ASCII ou en binaire (attention aux conversion DOS/UNIX dans ce cas !), la transmission est faite en flux (TCP)
Les commandes effectives qui passent sur le réseau et les commandes utilisateurs ne sont pas les mêmes : A dire vrai, on peut penser plusieurs implémentations d’un client FTP, qui ont plein de commandes utilisateur différentes des autres implémentations, mais qui sont toujours exprimables en commandes effectives du protocole FTP.
Dans le cas d’un autre protocole, TFTP (Trivial File Transfer Protocol), qui fonctionne sous UDP, vu que la fiabilité des données ne peut pas être garantie au niveau de la couche trnasport (UDP), elle doit être implémentée au niveau de l’application. Dans le cas de TFTP, les paquets sont numérotés : si les numéros ne correspondent pas, la connexion est interrompue.
Les utilisateurs chargent la liste des fichiers à partager. Les adresses des fichiers (ou des bouts de fichiers) sont renvoyés aux clients.
Mais le serveur est centralisé (SPOF)
Recherche par inondation : je demande à N pairs s’ils ont le fichier. S’ils n’ont pas le fichier, ils le demandent à N pairs chacun.
On créé un réseau virtuel. Résilient au départ des pairs (ils peuvent être remplacés par leurs voisins) : dynamique.
Scale très mal.
Découpage d’un fichier en blocs (chunk) Le fichier torrent qui contient des méta-données Tracker supervise la distribution (quoi se trouve où)
Résistance au flash-crowd. Plus résilient avec un plus grand nombre d’utilisateurs.
Problème des free-riders, plusieurs manières de solutionner.
Mesure de la rareté des chunks par le tracker : on pourra optimiser les transmissions en fonction de la rareté, on veut disséminer le fichier dans son ensemble très vite.
Pas de système de recherche implémenté dans le protocole, les fichiers graine qui contiennent l’adresse des trackers doivent être obtenu autrement (par internet).
Pas dans une application client-serveur classique, le trafic peut passer par des relais.
- Mail User Agent : mu4e, thunderbird, etc…
Les chercheurs ont adoré la messagerie, très pratique dans les années 80 et 90 : courrier très long, téléphone très cher.
- Mail Transfer agent (serveur de mail)
- SMTP : au début fonctionne seulement pour des messages encodés en ASCII NVT.
Le protocole est très simple : en fait, les trucs du genre le sujet, les flags, etc… sont directement dans le message, qui est structuré d’une manière particulière.
Echappement, combinaison de caractères
?Charset?encode?encoded-text? L’échappement se fait avec ‘=’.
?iso-8859-2?Q?Igen,=20k=F6sz=F6n=F6m?
köszönöm (mercè ! en hongrois)
Trois octets de texte codée sur 4 caractères ASCII
réencodé en binaire, devient du gibberish, pour être désencodé à l’autre bout.
MIME
Ce qu’il a été besoin de mettre en place pour que les autres applications fonctionnent.
Le but de MIME est de typer et structurer des envois, pour pouvoir envoyer autre chose que du texte.
Les types MIME (cat /etc/mime.types)
Indique ce que l’objet est.
MIME fonctionne par sous en-tête, qui donne les limites des blocs, et ce que chaque bloc est.
From: Olivier Fourmaux <[email protected]> Date: Wed, 20 Feb 2002 01:21:01 +0100 To: Toto <[email protected]> Subject: Document no 3.02 Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="/9DWx/yDrRhgMJTb" Content-Disposition: inline Content-Transfer-Encoding: 8bit User-Agent: Mutt/1.2.5i --/9DWx/yDrRhgMJTb Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline Content-Transfer-Encoding: 8bit Voici le document secret que vous m’avez demandé... --/9DWx/yDrRhgMJTb Content-Type: application/pdf Content-Disposition: attachment; filename="sujet-exam-RES.pdf" Content-Transfer-Encoding: base64 JVBERi0xLjIKJcfsj6IKNSAwIG9iago8PC9MZW5ndGggNiAwIFIvRmlsdGVyIC9GbGF0ZURl Y29kZT4+CnN0cmVhbQp4nO1dy7YdtRGd3684Mx6L07T63ZkBdghgXvYlJFlMHNsYm+sHhkCS...
Vu qu’on ne peut pas toujours être connecté au serveur de mail, soit par NFS (comme on faisait dans le temps jadis), soit par un terminal vers le mainframe.
POP = Post Office Protocol
Trois phases :
- Autorisation
- Transaction
- Mise à jour
Problème de POP : supprime ou ne supprime pas les messages du serveur, donc ne synchronise pas entre les éventuels clients.
Internet Mail Access Protocol : permet la synchronisation, mais alors beaucoup plus coûteux : on doit vérifier les états entre les différents clients, résoudre les conflits.
Pas de sécurité à l’origine. Comment garantir l’intégrité et l’authenticité des messages ?
Pas du ressort du protocole : c’est au niveau applicatif qu’on peut se démerder pour encrypter.
Développé au CERN (diffère de l’internet, qui est juste un regroupement de réseaux).
Permet d’afficher des images, ce qui a fait son succès immédiat. (change de Gopher, où on ne pouvait afficher que du texte)
HyperText Transfer Protocol
[inclure image]
L’hypertexte est une manière de lire de l’information non-séquentiellement, mais permet d’inclure tout type de données. HyperText Markup Language : Balises sont des liens vers des ressources à récupérer et mettre dans la page. C’est au navigateur de se démerder pour reformer tout ça.
Les adresses sont données sous la forme URL : Protocole://Domaine/Arborescence
De fait, mon navigateur ne gère pas que http, il peut gérer probablement ftp aussi : c’est un client générique
HTTP définit des échanges : requêtes d’objet, réponses
Protocole sans état : très robuste : on peut recommencer où on veut.
[Inclure échange]
Authentification
On est sans état : le serveur peut demander à ce qu’un certain ensemble de paramètres ou d’informations soient stockés en local (puisque rien n’est stocké sur le serveur). Notion de cookie. Spécifique au navigateur, par contre. Le navigateur peut n’en tenir aucun compte.
Le serveur enregistre les correspondances entre paramètres stockés et infomation
On peut imaginer une proximité de contenu entre les utilisateurs : on pourrait imaginer un cache et un serveur unique qui garderait les informations requêtées pour les distribuer : notion de proxy, ou de serveur mandataire.
Bénéfice supplémentaire : permet de filtrer et de fliquer.
Réplication des contenus des grands sites : permet de diminuer la latence du chargement.
Le web moderne se charge de plein de choses inutiles et coûteuses. (Modern Web sucks) Les trucs qui ne servent à rien sont bien entendus chargés en premier, ce serait trop facile sinon, on pourrait couper la communication ensuite.
On a eu besoin d’inventer des optimisations (HTTP 2). Parmi celles-ci, on a les flux multiplexés (plusieurs GET dans une même connexion TCP), la compression binaire des en-têtes, etc…
Real-Time Transport Protocol (basé sur le protocole de transport UDP)
En vrai, il n’y a pas de temps réel dans l’internet. Associe des horloges au contenu transmis : ne garantit rien de l’ordre du temps réel.
RTCP est un protocole associé à RTP (encapsulé dans un RTP existant) Standardisé, mais dans une application (pas de port standart).
[Format message RTP]
La source choisit son horloge.
Pour la voix, on va avoir tendance à envoyer les paquets dans l’ordre, et avoir une fréquence d’horloge à peu près égale à l’échantillonnage de l’audio (fréquence des données).
Multicanal (genre stéréo) : Les canaux se suivent dans un même message RTP (le nombre de canaux ne peut pas augmenter n’importe comment)
Pour la vidéo, ça se fait de faire de l’interpolation, de ne pas envoyer les données dans l’ordre. 90kHz : multiple entier pour les fréquences usuelles de restitution des images.
Principalement hors-bande, plusieurs protocoles, spécifiques à la vidéo, à la téléphonie, etc…
Après la fin de flash, on a de plus en plus de plateformes.
Les contenus demandés par les clients sont aussi variés : il faut d’adapter aux spécificités du client et aux accès réseau.
- Il faut encoder à plein de niveaux de qualité, et découper la vidéo
- Encapsulation dans du HTTP : peut passer partout, mais surcharge d’en-tête ()
Streaming HTTP dynamique :
C’est au client de savoir ce qu’il veut (bonne qualité, écran, internet, etc…)
On va pouvoir utiliser la notion de cache : les vidéos sont découpées. CDN : Réseau de distribution, de duplication des données.
Le fichier mezzanine est le fichier de qualité production : il est encodé en différentes qualités, puis chacune des qualités est segmentée en segments de 10 secondes : un fichier de master playlist est créé.
Le principe de récupération est le suivant : On fait un HTTP GET pour récupérer la master playlist, puis on demande les morceaux les uns à la suite des autres, selon le niveau de qualité qu’on souhaite.
Le client récupère le fichier manifest (ici le fichier ISMC en haut à droite de l’image), et fait des HTTP GET sur les différents fragments.
Là encore, on récupère le fichier manifest, puis on fait des HTTP GET sur les différents fragments.
Côté client :
On télécharge le MPD, et on choisit de manière dynamique (ou manuelle) en fonction de l’accès au réseau, de la vitesse de récupération constatée.
DASH n’est pas un protocole, ni un encodeur. Rien de standardisé sinon les données après mise en forme, et l’annonce de ces données (le fichier manifest) : sur le dessin, seul le rectangle MPD et les rectangles “Per-bitrate media segment file” sont spécifiés.
Les clients sont libres : tout le monde sait comment écrire un client, puisque tout le monde a accès à la manière dont les données sont stockées et annoncées.
MPD (manifest) est un gros fichier xml, dont la structure ressemble à ça :
Tout ça c’est du XML. Un client va consister en un parser et un générateur de requête HTTP, très très simple.
On peut éventuellement envisager, si on veut vraiment bien faire les choses, un client DASH capable d’adapter les requêtes HTTP qu’il fait selon les performances de la vidéo, le support matériel, etc… de manière dynamique au cours de la vidéo :
On peut bien entendu accéder directement à une machine connectée au réseau internet si on connaît son adresse dans le protocole internet.
Eventuellement, on voudrait pouvoir donner des noms aux machines.
Problème qui devient de plus en plus compliqué avec la multiplication des machines connectées : autant au tout début, on pouvait se contenter d’avoir un fichier texte sur sa machine qui lie les adresses IP aux noms (on en a d’ailleurs encore un dans les machines UNIX modernes, le fichier /etc/hosts), autant on n’a plus la place et la bande passante pour stocker et mettre à jour en temps réel ce fichier.
Initialement, il y avait sur un serveur spécifique un fichier de ce genre /etc/hosts, que les clients venaient requérir pour mettre à jour leur annuaire perso. Sa gestions était centralisée par un NIC (Network Information Center).
On a depuis, à la suite de l’explosion des machines connectées, on a distribué la base de données selon un espace de nommage hiérarchique :
nom.nom.nom.nom (le dernier nom est le plus important, et dispose d’un ensemble de sous-noms, etc…) Le nommage, et la hiérarchie du nommage n’est pas nécessairement déterminée par la topologie physique.
Cette base de données distribuée est contrôlée par l’ICANN (Internet Corporation for Assigned Names and Numbers), qui délègue le contrôle à de nombreux délégués. La hiérarchie de la délégation suit de près la hiérarchie du nommage.
Cet ensemble de serveurs de noms dédiés constituent le DNS, le Domain Name System. Ces serveurs gèrent les requêtes DNS de tout le monde.
Les requêtes arrivent sur la couche transport TCP ou UDP, sur le port 53.
On peut accéder aux serveurs DNS via des utilitaires UNIX directement dans le système : gethostbyname(3) gethostbyaddr(3)
Ces API en C de bas niveau sont accessibles via des commandes shell comme getent(1) ou host(1).
Comme on l’a dit, le nommage est hiérarchique, suit à peu près la logique du système de fichier UNIX.
Le label d’un noeud fait 63 caractères maximum, (parmi les caractères alphanumériques, et -), et est insensible à la casse.
Le nom de domaine est constitué de la liste des labels en parcourant l’arbre vers la racine :
nom1.nom2.nom3
Dans cet exemple, la racine est nom3.
La taille totale du nom de domaine est de 255 caractères, sans compter les ‘.’ qui séparent les labels.
Un nom de domaine est soit absolu (Fully Qualified Domain Name), c’est-à-dire que sa racine est dans les domaines de premier niveau (soit générique, style .com ou .gov, soit générique, genre .fr ou .su), auquel cas son nom est géré par le système DNS, soit il est relatif à un domaine plus haut, auquel cas il est géré localement par l’hôte.
Par “domaine de premier niveau”, on entend la même chose que l’anglais “Top level domain” (TLD), qui se distinguent entre ccTLD (country code top level domain) et gTLD (generic top level domain).
Historiquement, l’ICANN est assez conservatrice dans l’attribution des noms de domaine de premier niveau (longtemps réservé aux états souverains et aux tld historiques). En 2012, environ 2000 nouveaux TLD ont été autorisés.
La résolution DNS est donc, à la question “pc24.cs.keio.ac.jp”, la réponse 198.237.57.24.
La résolution inverse est aussi possible.
Elle se fait via un sous-arbre un peu spécifique, le sous-arbre arpa, qui dispose lui-même des sous-arbres ip6 (pour les adresses IPv6), in-addr (pour les adresses IPv4). Si on veut obtenir le nom de domaine 198.237.57.24, on va en fait query le pseudo-nom de domaine 24.57.237.198.in-addr.arpa (en effet, la convention selon laquelle on lit l’arbre vers la racine reste valable).
ICANN se contente de gérer la racine, les TLD sont délégués à des domain name registries, probablement administré par les états souverains dans le cas des ccTLD, et une corporation random pour les gTLD.
On a en fait des zones (qui sont en fait les sous-arbres de l’arbre DNS total) administrées séparément.
Un serveur de nom est associé à chaque zone.
Zone et domaine ne sont pas la même chose : la zone est définie principalement par le serveur de nom. Un serveur de nom va gérer tous les noms de la zone.
Le domaine est beaucoup plus lâche : c’est simplement l’ensemble des machines dont l’adresse termine par le FQDN du domaine, indépendemment du ou des serveurs de nom qui administrent les noms.
On distingue deux types de serveurs de noms :
- Les serveurs de référence d’une zone, qui se distinguent en un serveur de référence primaire, qui dispose des informations de référence, qui connaît les descendants auxquels il a délégué, et dont l’initialisation est locale (il ne prend ses informations nulle part ailleurs qu’en lui-même), et en serveur de référence secondaires, qui servent de redondance au premier, et qui s’initialisent et se mettent à jour à partir du primaire.
- Les serveurs locaux (principalement mis en place par les fournisseurs d’accès), qui cachent une partie des correspondances, en prenant leurs informations auprès des serveurs de référence.
La résolution et top-down et itérative. On ne demande à chaque fois que la référence du DNS de la sous-zone, jusqu’à résoudre complètement le nom.
Fonctionnement du DNS itératif
- Ma machine locale cherche à résoudre pc24.cs.keio.ac.jp
- Je demande à mon serveur DNS local pc24.cs.keio.ac.jp ?
- Mon serveur DNS local demande au serveur DNS racine pc24.cs.keio.ac.jp ?
- Le serveur racine répond jp. correspond à la plage d’adresse (avec le serveur DNS en premier) addr1, addr2, …
- Mon serveur DNS local demande donc pc24.cs.keio.ac.jp au serveur DNS de jp.
- Le serveur DNS de jp. me répond que ac.jp. correspond à la plage d’adresses … (avec le serveur
DNS correspondant en premier)
etc…
Dès qu’un serveur peut fournir la résolution complète à mon serveur DNS local, il l’envoie, à mon serveur qui me la rend.
En fait, mon serveur DNS local est un peu mon mandataire : c’est lui qui pose les questions pour moi. Et les mêmes bénéfices que le mandataire HTTP sont là. Si on est plein à lui poser la même question, il va cacher la réponse et la fournir sans avoir besoin de reposer la question à chaque fois.
Fonctionnement du DNS récursif
- Ma machine locale cherche à résoudre pc24.cs.keio.ac.jp
- Je demande à mon serveur DNS local pc24.cs.keio.ac.jp ?
- Mon serveur DNS local forward ma demande à un autre serveur DNS, jusqu’à qu’on arrive à un serveur DNS qui connaisse un serveur de nom qui puisse le renseigner. Ensuite, on repasse sur un système itératif jusqu’à résolution complète.
- La réponse est repassé dans l’autre sens, jusqu’à parvenir à ma machine locale.
Les racines sont consultées systématiquement.
Pour que les charges soient supportables pour les serveurs DNS racine, les informations qui en sont tirées sont cachées par les autres serveurs DNS.
On ne s’intéressera pas à la structure d’un message DNS, Olivier Fourmaux fournissant gentiment la structure des messages de la couche transport et de la couche application en annexes des sujets d’examen.
Il n’y a pas de sécurité dans le protocole de base.
Il est donc possible de d’intercepter, modifier des messages DNS, de créer des faux messages, de détruire des message qui ont trait à une adresse particulière (déni d’existence).
Une extension du système DNS, plus tardive, DNSSEC, permet d’authentifier l’origine des données, de vérifier l’intégrité des données, mais ne garantit pas la confidentialité, et ne protège pas du déni de service distribué.
Gestion des gros réseaux.
Besoins :
- Surveillances du réseau, pour la détection de panne, mesure de performance.
- Intervention à distance
Contraintes :
- Hétérogénéité des machines (imprimantes, routeurs, etc…)
Agent spécifique à chaque équipement. Par contre, le protocole de communication entre ces agents.
On se sert d’un protocole SNMP (associés éventuellement à des clients GUI)
Ce protocole permet juste de lire ou écrire des variables : la richesse est dans la MIB (Management Information Base), (plus haut) on y met les informations et les actions qu’on veut. Le fabricant du matériel met ce qu’il veut, en suivant les contraintes du standard.
Ce qu’on fait en LAB. Récupérer des statistiques et même du trafic directement.
La capture du trafic passe par SNMP.
Le MIB d’un nouvel appareil (imprimante, switch) n’est pas forcément publié : ça dépend du bon vouloir du fabricant. Vu qu’on peut lire le trafic en clair, on peut tenter de reverse engineer le MIB. Nagios (administrateur open-source) doit avoir reçu des contributions de cette manière-là.
La couche transport se trouve, dans le modèle TCP/IP (on ignorera le modèle OSI), entre la couche applicative, plus haut, et la couche internet, plus bas.
La couche transport permet de faire communiquer deux ou plusieurs entités en faisant abstraction des éléments de réseau traversés.
La couche transport donne une association virtuelle entre processus : point de vue UNIX. La socket UNIX se contente de créer un outil de communication entre deux processus, indépendemment de la localisation de ces processus (c’est aussi le cas des autres IPC, dans une moindre mesure)
Les communications se font de bout en bout : on ne s’occupe pas des éventuels relais traversés. La couche transport est implémentée dans les machines d’extrémité, directement au niveau du système (alors que les protocoles applicatifs étaient dans les faits définis dans l’espace utilisateur) : le client et le serveur ont une pile TCP et une pile UDP, le routeur pas nécessairement.
UDP est une connexion sans état : tout ce qu’on sait, c’est l’adresse du destinataire. Transmissions non ordonnées, non fiables (service best effort, simple léger)
Par rapport à ce minimum syndical, TCP ajoute la fiabilité et ordonnancement, et le contrôle de congestion. Ce mode est orienté flux de données (plutôt que message).
On a aussi d’autres protocoles de transport beaucoup moins utilisés : un mode fiable orienté message (qui emprunte à TCP la fiabilité mais à UDP le mode message non connecté) : SCTP et QUIC
Et aussi un protocole qui prend à TCP le contrôle de congestion, mais qui reste sur un mode de transmission non connecté, non fiable, non ordonné : DCCP
Quel que soit le protocole qu’on considère, ne sont jamais disponibles :
- Des garanties temporelles (délais non-déterministes, gigue imprédictible)
- Des garanties de débit
En conséquence de ça, aucune garantie de temps réel sur les protocoles de transport.
Les deux grands modèles sont fondamentalement le mode message non-connecté et le mode connecté.
Au niveau système et applicatif, on dispose d’un certain nombre de primitives :
- LISTEN (écoute pour établissement de connexion, côté serveur)
- CONNECT (établissement de connexion par le client)
- SEND (envoi de paquet en mode connecté ou non, par n’importe qui)
- RECEIVE (réception de paquet en mode connecté ou non, par n’importe qui)
- DISCONNECT (rupture de connexion établie)
De la même manière qu’on a un automate d’état des processus UNIX, on peut avoir un automate d’état des connexions.
L’établissement de connexion passe par un système de réponse attendue.
En gros, la demande de connexion a une valeur bien précise dans son champ SYN (on prend la terminologie spécifique à TCP à dessein). La réponse doit avoir dans son champ ACK la même valeur, et cette réponse demande à son tour via son propre champ SYN une valeur.
Cette méthode est robuste en la persistance de vieux duplicats dans le sens où les réponses à ceux-ci peuvent être identifiés et rejetés facilement. En revanche, ça peut amener une rupture de la connexion. Donc robustesse en terme d’authentification, mais fragilité en terme de persistance.
Au niveau applicatif, les données sont transmises de processus à processus via des sockets.
Les sockets sont réputés imperméables : on met un truc dans un socket, il doit ressortir tel quel de l’autre côté, et nulle part ailleurs.
Mais de fait, si on a plusieurs sockets qui vont tous de la machine A à la machine B, il serait bête de ne pas profiter de la même connexion.
Notion de multiplexage, qui consiste à bien regrouper ces données. Au niveau de l’émetteur, on doit collecter les données auprès des sockets, les identifier par un en-tête. Au niveau du récepteur, on sépare les blocs et on les fournit au socket correspondant.
En mode non connecté, on associe le socket à un numéro de port. Quand un hôte reçoit le datagramme, il se contente de vérifier le numéro de port, et il envoie le datagramme au socket correspondant.
En mode connecté, le socket est identifié par l’adresse et le port de la source, l’adresse et le port de destination. Lors de la réception d’un segment, on peut identifier le socket auquel l’envoyer en regardant le quadruplet. De cette manière, un serveur qui accepte des connexions en mode connecté peut avoir un très grand nombre de connexions.
Le protocole UDP (User Datagram Protocol) est le protocole internet le plus minimaliste. Il consiste seulement à coller une adresse IP et un port à un paquet de données, et à le balancer sur le réseau (on exagère à peine).
Les datagrammes peuvent parfaitement être perdus, dupliqués ou être reçus de manière désordonnée.
Pas d’échange préalable à l’envoi des paquets. L’envoi ne dépend pas de l’état des extrémités.
Chaque datagramme vit sa vie, il est géré indépendemment des autres.
La structure est la suivante :
- Le port source sur deux octets (2^16 valeurs possibles, soient 65536)
- Le port destination sur deux octets (pareil)
- La taille en octets du datagramme, ce qui donne une taille maximale de 65536 octets
- Une somme de contrôle sur deux octets, donc
asseztrès très sensible aux collisions.
Puis ensuite le message, soient les données de la couche applicative.
Les ports sources inférieurs à 1024 sont en général les ports réservés à l’administrateur, et c’est sur ces ports là que les protocoles applicatifs usuels (qui ont un RFC) sont habituellement utilisés (rien n’empêche qu’ils soient utilisés ailleurs).
Les ports au-dessus de 1024 compris sont accessibles aux utilisateurs, mais sont en général bloqués par les pare-feu.
Les avantages de ce protocole extrêmement minimaliste :
- Protocole sans état
- Pas besoin d’établir une connexion
- Entête réduit, bonne efficacité
Convient particulièrement aux situations avec des ressources limitées aux extrémités, tant en terme de pile TCP/IP (plus complexe à coder, mais de nos jours implémenté dans tous les systèmes UNIX) que de capacité de traitement.
Si on a besoin de nouvelles fonctionnalités, il faut les implémenter dans la couche application.
Les applications qui utilisent UDP sont, parmi les applications classiques :
- La résolution de noms (DNS)
- L’administration réseau (SNMP)
- L’horloge (NTP)
- Les serveurs de fichiers distants (NFS)
Dans ces cas-là, la fiabilisation des échanges, quand elle est nécessaire, peut se faire par redondance temporelle ou explicitement dans la couche application.
En général, les applications qui ont tendance à utiliser UDP sont les applications qui ont de forte contraintes de débit et/ou de latence, tout en étant tolérants aux pertes, celles-ci pouvant être résorbées au niveau applicatif. Donc typiquement, les jeux vidéo en ligne, le streaming audio et vidéo, la voix par internet, etc…
Le but de cette partie est de donner les conditions de possibilité d’un protocole de transport fiable (PTF dans la suite et dans le support) dans des environnement matériels supposés non-fiables.
C’est ce qu’Olivier Fourmaux entend quand il écrit :
Les caractéristiques du canal non fiable déterminent la complexité du protocole de transfert fiable.
Il faut s’assurer, dans la couche transport, d’un certain nombre de choses si on veut pouvoir garantir à la couche applicative la fiabilité des transmissions dans un canal non fiable.
Construisons ensemble les caractéristiques du PTF.
Avant toute chose, il est question de transfert de données dans un seul sens dans un premier temps (les informations de contrôle peuvent aller dans les deux directions).
En quoi est-ce que la canal sous-jacent peut-il se révéler non-fiable ?
Certains bits peuvent être modifiés pendant le transport : on va donc devoir ajouter un contrôle d’erreur.
Il faut que l’envoyeur puisse récupérer les erreurs que le récepteur a levé : système d’acquittement positif (ACK) ou négatif (NAK).
Peu performant en soi : protocole stop and wait, l’émetteur attend la réponse du récepteur avant de continuer à transmettre.
Si les ACK ou NAK sont incorrects, l’émetteur perd les informations sur l’état du récepteur, les données sont peut être inutilement dupliquées.
L’émetteur est censé retransmettre le paquet courant si le ACK/NAK est incorrect. Les paquets sont assortis d’un numéro de séquence pour reconnaître les duplicats et les corrections. Le récepteur est donc capable de supprimer les duplicats.
On peut se permettre de n’avoir que deux numéros de séquence possibles, vu qu’on part du principe qu’on doit juste distinguer un paquet du précédent et du suivant.
Peut-on éliminer les NAK ? Si on remplace les NAK par le ACK du dernier paquet valide reçu, le récepteur peut inclure le numéro de séquence correspondant au ACK et donner à l’émetteur les mêmes informations que s’il avait envoyé NAK : si l’émetteur reçoit deux ACK avec le même numéro de séquence, il sait que le dernier paquet qu’il a envoyé est arrivé vérolé.
On se place maintenant dans le cas théorique où on peut non seulement voir un certain nombre de bits du paquet modifiés, mais aussi des paquets purement et simplement perdus en route.
L’absence d’un paquet ne déclenche pas de ACK, donc on est bloqué.
Il faut introduire une notion de temporisation : on doit d’abord estimer un temps raisonnable de retour du ACK.
On déclenche un chronomètre au départ d’un paquet. Si le ACK arrive avant le temps raisonnable, on est content, on arrête le chrono et on le reset. Si non, on retransmet.
Dans le cas où le ACK finit vraiment par arriver, mais après le temps raisonnable, on a une duplication, qui est gérée et détruite grâce au numéro de séquence.
On a maintenant ce que Olivier Fourmaux appelle PTF 3.0, qui gère les erreurs et les pertes.
Mais ça n’est pas très efficace.
On prend un gros débit : 1 Gb/s On part du principe que le délai de bout-en-bout est de 40ms, donc 80ms de délai d’aller-retour.
Les paquets font 1000 octets.
Le temps de la transmission se mesure en divisant la taille du paquet (en bits !) par le débit du lien. On tombe sur 8 ms.
Si on définit l’efficacité de l’émetteur comme la fraction du temps qu’il passe effectivement à transmettre, on peut la calculer comme suit :
Débit du lien / (Débit du lien + durée d’aller-retour), soit dans notre cas 1/10000.
Le débit du transport, dans notre cas, est donné par la taille du paquet divisé par la durée d’aller-retour, soit 100 Kb/s
Sur un paquet de 1000 octets, les performances du protocole de transport sont de 100 Kb/s pour un lien supportant 1 Gb/s.
Bien entendu, ces performances dépendent de la taille du paquet. Plus celui-ci est gros, moins le coût de l’aller-retour est cher.
Ces mauvaises performances viennent du caractère stop and wait du protocole : on ne peut envoyer un paquet que toutes les RTT temps.
La solution naturelle pour accélérer le traitement d’une suite de données, c’est de ne pas attendre qu’une donnée ait fini d’être traitée pour commencer le traitement de la suivante. Principe du pipeline.
Dans notre cas, le pipeline consistera en l’autorisation de l’envoi de plusieurs paquets avant la réception des ACK. Donc on va avoir plusieurs paquets en attente d’acquittement.
Ce qui implique immédiatement que la notation sur un bit simple du numéro de séquence ne tient plus. Implique aussi la mise en place, au niveau des machines d’extrémité, de tampons.
On va voir deux types de protocole en pipeline (en fait un seul, mais avec deux variantes).
Go-back-N : Les entêtes des paquets disposent de k bits de numéro de séquence. Dans la première variante, les acquittements envoyés à la réception sont cumulatifs : ACK prendra la forme ACK(n), et ACK(n) signifiera un acquittement de tous les paquets jusqu’au paquet portant le numéro de séquence n.
Vu qu’on a potentiellement à un instant bien précis un nombre supérieur à 1 de paquets non acquittés, il faut quand même définir un nombre maximal de paquets non acquittés à la fois permis. (Sinon, l’émetteur peut se contenter de bombarder comme un bienheureux)
On a donc un nouveau concept de fenêtre :
Du côté du récepteur, on envoie seulement des ACK avec le numéro de séquence le plus élevé des paquets valides ordonnés.
Un ACK dupliqué signifie la mauvaise réception de paquet après le numéro de séquence du ACK.
Du côté du récepteur, on peut se contenter de n’enregistrer que le numéro de séquence attendu du prochain paquet : les paquets déséquencés sont éliminés, ce qui élimine le besoin d’entretenir un tampon.
Le problème de cette approche est qu’en cas d’erreur (et a fortiori de perte) sur un des paquets de la séquence, les paquets suivants doivent in fine être éliminés (et donc retransmis) quand bien même ils ont été quant à eux reçus tout à fait correctement.
On gâche potentiellement énormément de trafic avec une simple erreur.
Pour cette raison, il existe une deuxième variante de ce Go-back-N avec retransmissions sélectives. Le récepteur acquitte individuellement, et non plus cumulativement tous les paquets reçus correctement.
De cette manière, on peut se permettre de n’avoir à retransmettre que le strict minimum, c’est-à-dire les paquets non acquittés.
La fenêtre d’émission reste limitée à N numéros de séquence consécutifs (on est bien toujours dans le cas du go-back-N).
Du côté de l’émetteur, on peut maintenant marquer individuellement la bonne réception des paquets dans l’intervalle [plus petit paquet non acquitté, plus petit paquet non acquitté + taille de la fenêtre].
Si le paquet à acquitter est le plus petit non encore acquitté, on peut décaler la fenêtre vers la droite.
Cette variante suppose en revanche un tampon du côté du récepteur :
- on acquittera explicitement pour tous les paquets reçus dans l’intervalle [base - N ; base + N], avec N la taille de la fenêtre, et base le paquet de plus petit numéro de séquence correctement reçu.
- Si, en particulier, le paquet est dans [base + 1 ; base + N], s’il est déséquencé (c.à.d qu’il n’est pas base + 1) on le met dans le tampon après avoir ACKé. S’il est séquencé, on décale la fenêtre jusqu’au plus petit paquet non reçu.
- Si le paquet est dans [base - N ; base], on ACK simplement sans rien faire.
Si le paquet n’est pas dans l’intervalle, on ne fait rien.
TCP est en fait l’exemple historique dominant du PTF qui respecte les caractéristiques qu’on a donné.
Certains champs intéressants de la structure de l’en-tête :
le champ qui donne le numéro de la séquence est écrit sur 32 bits et il numérote exactement le premier octet des data : il est en fait associé à chaque octet et non pas à un segment.
On a donc une numérotation implicite de tous les octets de données (les octets d’entête ne comptent pas).
Vu que ce numéro de séquence est écrit sur 32 bits, on boucle obligatoirement au bout de 2^32 octets (4 Gio).
Ce numéro de séquence permet très facilement de détecter les pertes et ordonnancer les segments.
Aussi écrit sur 32 bits.
Indique le numéro du prochain octet de données attendu (donc le numéro de séquence du paquet “réponse”, s’il y en a un).
Vu qu’il est cumulatif, il donne toujours le premier octet non reçu, même si d’autres avec des numéros de séquence supérieurs ont bien été reçus et sont dans le tampon de réception.
Un segment peut très bien à la fois porter des données et un acquittement de données précedemment reçu : principe du piggybacking.
Taille en octets de la fenêtre de réception
Ecrits sur 16 bits, donc peut annoncer jusqu’à 64 Kio.
Important pour le contrôle de flux : donne le nombre d’octets disponibles dans le tampon du récepteur, donc dimensionne la taille de la fenêtre d’anticipation de l’émetteur (combien de paquets il peut envoyer d’un coup).
Delayed ack (ack tous les deux paquets, ou au bout de 500ms)
Analyse de l’en-tête TCP.
RTO = retransmission timeout RTT = Round Trip Time
Taille de fenêtre ?
Supports de cours :