Protocole:TCP

From aldeid
Jump to navigation Jump to search

Le protocole TCP

Définition et fonctions

TCP signifie « Transport Control Protocol » soit, en français, Protocole de Contrôle de Transmission. Ses fonctions sont les suivantes :

  • Remettre en ordre les datagrammes en provenance du protocole IP ;
  • Vérifier le flot de données afin d'éviter une saturation du réseau ;
  • Formater les données en segments de longueur variable afin de les confier au protocole IP ;
  • Multiplexer les données, c'est-à-dire de faire circuler simultanément des informations provenant de sources (applications par exemple) distinctes sur une même ligne ;
  • Initialiser et mettre fin à une communication.

Tout comme UDP et ICMP, les messages TCP sont encapsulés dans des datagrammes IP :

En-tête IP
En-tête TCP Données

En-tête TCP

L’en-tête TCP a la forme suivante :
Image:tcp-001.png

Champ (abréviation) Description
Port source (sport=) Le champ Port source, codé sur 16 bits, correspond au port relatif à l'application en cours sur la machine source.
Port destination (dport=) Le champ Port destination est codé sur 16 bits et correspond au port relatif à l'application en cours sur la machine de destination.
Numéro de séquence (seq=) Le champ Numéro de séquence est codé sur 32 bits et correspond au numéro du paquet. Cette valeur est incrémentée lors d’un échange entre client et serveur.
Numéro d'accusé de réception (ack=) Le champ Numéro d’accusé réception est codé sur 32 bits et définit un acquittement pour les paquets reçus. Cette valeur signale le prochain numéro de paquet attendu.
Par exemple, si il vaut 1500, cela signifie que tous les datagrammes <1500 ont été reçus
Longueur en-tête TCP (dataofs=) Le champ Offset est codé sur 4 bits et définit le nombre de mots de 32 bits dans l'entête TCP. Ce champ indique donc où les données commencent.
Réservé (reserved=) Le champ Réservé est codé sur 6 bits et il servira pour des besoins futurs. Ce champ doit être marqué à 0.
Drapeaux (flags=) Les drapeaux prennent pour valeur 0 ou 1 et sont codés sur 1 bit chacun.
  • CWR (Congestion Window Reduced) = RFC 3168
  • ECE  = ECN Echo RFC 3168
  • URG : indique que le champ Pointeur de donnée urgente est utilisé.
  • ACK : indique que le numéro de séquence pour les acquittements est valide.
  • PSH : indique au récepteur de délivrer les données à l'application et de ne pas attendre le remplissage des tampons.
  • RST : demande la réinitialisation de la connexion.
  • SYN : indique la synchronisation des numéros de séquence.
  • FIN : indique la fin de la transmission.
Taille de fenêtre (window=) Le champ Fenêtre "Window" est codé sur 16 bits et correspond au nombre d'octets à partir de la position marquée dans l'accusé de réception que le récepteur est capable de recevoir. Le destinataire ne doit donc pas envoyer les paquets après Numéro de séquence + Window.
Total de contrôle (chksum=) Le champ Checksum est codé sur 16 bits et représente la validité du paquet de la couche 4 TCP.

Le Checksum est constitué en calculant le complément à 1 sur 16 bits de la somme des compléments à 1 des octets de l’en-tête et des données pris deux par deux (mots de 16 bits). Si le message entier contient un nombre impair d’octets, un 0 est ajouté à la fin du message pour terminer le calcul du Checksum. Cet octet supplémentaire n’est pas transmis. Lors du calcul du Checksum, les positions des bits attribués à celui-ci sont marquées à 0. Le Checksum couvre de plus, une pseudo en-tête de 96 bits préfixée à l’en-tête TCP. Cette pseudo en-tête comporte les adresses Internet sources et destinataires, le type de protocole et la longueur du message TCP (incluant la data). Ceci protège TCP contre les erreurs de routage.

Pointeur d’urgence

(urgptr=)

Le champ Pointeur de donnée urgente est codé sur 16 bits et communique la position d'une donnée urgente en donnant son décalage par rapport au numéro de séquence. Le pointeur doit pointer sur l'octet suivant la donnée urgente. Ce champ n'est interprété que lorsque le Flag URG est marqué à 1. Dès que cet octet est reçu, la pile TCP doit envoyer les données à l'application.
Options (options=) Options diverses :
  • 0 : End of Options List
  • 1 : No Operation (NOP)
  • 2 : Maximum segment size
  • 3 : Window Scale
  • 4 : Selective ACK ok
  • 8 : Timestamp

Pour une liste plus complète des options, référez-vous à l'adresse suivante : http://www.iana.org/assignments/tcp-parameters/

Remplissage Le champ remplissage permet de compléter le champ options avec des 0 afin qu’il ait une longueur multiple de 32 bits

Etablissement d'une connexion

L’établissement d’une connexion se décompose en plusieurs étapes :

  1. Le client utilise son numéro de séquence initial dans le champ "Numéro de séquence" du segment SYN (x par exemple) ;
  2. Le serveur utilise son numéro de séquence initial dans le champ "Numéro de séquence" du segment SYN/ACK (y par exemple) et incrémente le numéro de séquence du client de 1 (x+1) dans le champ "Numéro d'acquittement" du segment ;
  3. Le client confirme en envoyant un ACK avec un numéro de séquence augmenté de 1 (x+1) et un numéro d'acquittement correspondant au numéro de séquence du serveur plus un (y+1).

Ce principe d'incrémentation est illustré dans l'exemple qui suit, correspondant à une connexion à un serveur SSH dans un extrait de capture tcpdump :

# tcpdump -S -vv -n -r test.cap

09:21:11.949516 IP (tos 0x0, ttl  64, id 751, offset 0, flags [DF], proto: TCP (6), length:
52) 192.168.182.1.1282 > 192.168.182.128.22: S, cksum 0xa4f4 (correct), 613135018:613135018
(0) win 65535 <mss 1460,nop,wscale 3,nop,nop,sackOK>

09:21:11.949620 IP (tos 0x0, ttl  64, id 0, offset 0, flags [DF], proto: TCP (6), length: 
52) 192.168.182.128.22 > 192.168.182.1.1282: S, cksum 0xe812 (correct), 1304647741:13046477
41(0) ack 613135019 win 5840 <mss 1460,nop,nop,sackOK,nop,wscale 3>

09:21:11.949843 IP (tos 0x0, ttl  64, id 752, offset 0, flags [DF], proto: TCP (6), length:
40) 192.168.182.1.1282 > 192.168.182.128.22: ., cksum 0x44c0 (correct), 613135019:613135019
(0) ack 1304647742 win 64240

La réponse du serveur à une demande de connexion diffère selon que le port est ouvert ou fermé :

Test d'un port ouvert Test d'un port fermé
Image:tcp-003.gif Image:tcp-004.gif
Dans le cas d’un port ouvert sur le serveur, l’émission d’un paquet SYN fait croire au serveur que le client souhaite établir une connexion. Le serveur entame alors la seconde étape de la poignée de main TCP (TCP 3-way handshake) en envoyant un paquet SYN/ACK. La connexion est alors avortée (émission d’un paquet RST au lieu du paquet ACK attendu normalement). C’est la technique de la connexion à moitié ouverte Dans le cas d’un port fermé, l’émission d’un paquet SYN vers le serveur provoque l’émission par le serveur d’un paquet RST (connexion non établie)
Voici ce que Scapy renvoie dans les deux cas (port ouvert pour le port 80/TCP et fermé pour le 81/TCP, respectivement dans les deux colonnes) :
>>> ans,unans=sr(IP(dst="192.168.182.133")/TCP(dport=80,flags="S"))
Begin emission:
.*Finished to send 1 packets.

Received 2 packets, got 1 answers, remaining 0 packets
>>> ans.summary()
IP / TCP 192.168.182.132:ftp_data > 192.168.182.133:www S ==> IP / TCP 192.168.1
82.133:www > 192.168.182.132:ftp_data SA / Padding

SA = SYN/ACK (port ouvert)

>>> ans,unans=sr(IP(dst="192.168.182.133")/TCP(dport=81,flags="S"))
Begin emission:
.Finished to send 1 packets.
*
Received 2 packets, got 1 answers, remaining 0 packets
>>> ans.summary()
IP / TCP 192.168.182.132:ftp_data > 192.168.182.133:81 S ==> IP / TCP 192.168.18
2.133:81 > 192.168.182.132:ftp_data RA / Padding

RA = RESET/ACK (port fermé)

Echange de données

La phase de transfert consiste en un échange de paquets (fragmentés ou non) dont les flags PUSH et/ou ACK sont utilisés.

L'extrait de capture tcpdump ci-dessous illustre une phase d'échange de données :

P1 (Demande du client - navigateur)

09:09:49.865015 IP (tos 0x0, ttl 64, id 600, offset 0, flags [DF], proto: TCP (
6), length: 429) 192.168.182.1.1213 > 192.168.182.128.80: P 3041339763:30413401
52(389) ack 1113674227 win 64240
0x0000: 4500 01ad 0258 4000 4006 4920 c0a8 b601 E....X@[email protected].....
0x0010: c0a8 b680 04bd 0050 b547 2973 4261 51f3 .......P.G)sBaQ.
0x0020: 5018 faf0 74e9 0000 4745 5420 2f20 4854 P...t...GET./.HT
0x0030: 5450 2f31 2e31 0d0a 486f 7374 3a20 3139 TP/1.1..Host:.19
0x0040: 322e 3136 382e 3138 322e 3132 380d 0a55 2.168.182.128..U
0x0050: 7365 se

P2 (Réponse du serveur Apache)

09:09:49.865250 IP (tos 0x0, ttl 64, id 56701, offset 0, flags [DF], proto: TCP (
6), length: 40) 192.168.182.128.80 > 192.168.182.1.1213: ., cksum 0x4500 (correct
), 1113674227:1113674227(0) ack 3041340152 win 864
0x0000: 4500 0028 dd7d 4000 4006 6f7f c0a8 b680 E..(.}@[email protected].....
0x0010: c0a8 b601 0050 04bd 4261 51f3 b547 2af8 .....P..BaQ..G*.
0x0020: 5010 0360 4500 0000 P..`E...

Dans la trame ci-dessus, aucune donnée n'est transmise (champ data vide). La taille du paquet est donc réduite à la taille de l'en-tête TCP standard, soit 40 bytes (20 bytes pour l'en-tête IP sans option et 20 bytes pour l'en-tête TCP sans option et sans donnée). Le prochain numéro de séquence attendu est donc égal au numéro de séquence du paquet. La différence (0) entre les deux numéros de séquence est nulle.

P3

09:09:50.003599 IP (tos 0x0, ttl 64, id 56702, offset 0, flags [DF], proto: TCP (
6), length: 1500) 192.168.182.128.80 > 192.168.182.1.1213: . 1113674227:111367568
7(1460) ack 3041340152 win 864
0x0000: 4500 05dc dd7e 4000 4006 69ca c0a8 b680 E....~@[email protected].....
0x0010: c0a8 b601 0050 04bd 4261 51f3 b547 2af8 .....P..BaQ..G*.
0x0020: 5010 0360 721e 0000 4854 5450 2f31 2e31 P..`r...HTTP/1.1
0x0030: 2032 3030 204f 4b0d 0a44 6174 653a 2057 .200.OK..Date:.W
0x0040: 6564 2c20 3036 2041 7567 2032 3030 3820 ed,.06.Aug.2008.
0x0050: 3037 07

Dans la trame ci-dessus, nous pouvons remarquer que le numéro de séquence du paquet est équivalent à celui du paquet précédent, conformément au "prochain numéro de séquence attendu". En revanche, la taille du champ "données" est de 1460 bytes. Le prochain numéro de séquence attendu est incrémentée de 1460.

P4

09:09:50.003890 IP (tos 0x0, ttl 64, id 56703, offset 0, flags [DF], proto: TCP (
6), length: 1500) 192.168.182.128.80 > 192.168.182.1.1213: . 1113675687:111367714
7(1460) ack 3041340152 win 864
0x0000: 4500 05dc dd7f 4000 4006 69c9 c0a8 b680 E.....@[email protected].....
0x0010: c0a8 b601 0050 04bd 4261 57a7 b547 2af8 .....P..BaW..G*.
0x0020: 5010 0360 372a 0000 223e 3c2f 7464 3e3c P..`7*.."></td><
0x0030: 7464 3e3c 6120 6872 6566 3d22 6361 7074 td><a.href="capt
0x0040: 7572 654c 696e 7578 4465 6269 616e 4574 ureLinuxDebianEt
0x0050: 6368 ch

P5 (Acquittement du client)

09:09:50.004051 IP (tos 0x0, ttl 64, id 601, offset 0, flags [DF], proto: TCP (6
), length: 40) 192.168.182.1.1213 > 192.168.182.128.80: ., cksum 0x4207 (correct
), 3041340152:3041340152(0) ack 1113677147 win 64240
0x0000: 4500 0028 0259 4000 4006 4aa4 c0a8 b601 E..(.Y@[email protected].....
0x0010: c0a8 b680 04bd 0050 b547 2af8 4261 5d5b .......P.G*.Ba][
0x0020: 5010 faf0 4207 0000 0000 0000 0000 P...B.........

P6

09:09:50.004249 IP (tos 0x0, ttl 64, id 56704, offset 0, flags [DF], proto: TCP (
6), length: 1151) 192.168.182.128.80 > 192.168.182.1.1213: P 1113677147:111367825
8(1111) ack 3041340152 win 864
0x0000: 4500 047f dd80 4000 4006 6b25 c0a8 b680 E.....@[email protected]%....
0x0010: c0a8 b601 0050 04bd 4261 5d5b b547 2af8 .....P..Ba][.G*.
0x0020: 5018 0360 e3d4 0000 756c 2d32 3030 3820 P..`....ul-2008.
0x0030: 3137 3a34 3620 203c 2f74 643e 3c74 6420 17:46..</td><td.
0x0040: 616c 6967 6e3d 2272 6967 6874 223e 3739 align="right">79
0x0050: 304b 0K

P7

09:09:50.158959 IP (tos 0x0, ttl 64, id 604, offset 0, flags [DF], proto: TCP (6),
length: 40) 192.168.182.1.1213 > 192.168.182.128.80: ., cksum 0x3e3b (correct), 3
041340152:3041340152(0) ack 1113678258 win 64101
0x0000: 4500 0028 025c 4000 4006 4aa1 c0a8 b601 E..(.\@[email protected].....
0x0010: c0a8 b680 04bd 0050 b547 2af8 4261 61b2 .......P.G*.Baa.
0x0020: 5010 fa65 3e3b 0000 0000 0000 0000 P..e>;........

Tableau résumé des paquets

Paramètre P1 P2 P3 P4 P5 P6 P7
Description Demande
client
Acquittement
serveur
Envoi
de données
Envoi
de données
Acquit
-tement
Envoi
de données
Acquit
-tement
IPID 600 56701 56702 56703 601 56704 604
length 429 40 1500 1500 40 1151 40
dont data 389 - 1460 1460 - 1111 -
flags PA A A A A PA A
seq 3041339763 1113674227 1113674227 1113675687 3041340152 1113677147 3041340152
seq(prochain) 3041340152 1113674227 1113675687 1113677147 3041340152 1113678258 3041340152
ack 1113674227 3041340152 3041340152 3041340152 1113677147 3041340152 1113678258
window 64240 864 864 864 64240 864 64101

Nous pouvons constater que tant que le serveur n'a pas demandé l'acquittement au client, le numéro d'acquittement reste inchangé.

Par ailleurs, nous constatons que le volume des données par paquet ne peut excéder 1460 bytes (Taille d'un paquet de 1500 bytes, diminuée de son en-tête IP de 40 bytes). Lorsque cette taille est atteinte, le paquet est transmis, même s'il reste des données à transmettre. Ces dernières sont transmises dans les paquets suivants.

Fermeture d'une connexion

Une femeture de connexion est similaire à une ouverture de connexion, la seule différence résidant dans les flags transmis.

  1. Le client utilise son numéro de séquence initial dans le champ "Numéro de séquence" du segment FIN (x par exemple) ;
  2. Le serveur utilise son numéro de séquence initial dans le champ "Numéro de séquence" du segment FIN/ACK (y par exemple) et incrémente le numéro de séquence du client de 1 (x+1) dans le champ "Numéro d'acquittement" du segment ;
  3. Le client confirme en envoyant un ACK avec un numéro de séquence augmenté de 1 (x+1) et un numéro d'acquittement correspondant au numéro de séquence du serveur plus un (y+1).
Image:tcp-005.gif

Ce principe d'incrémentation est illustré dans l'exemple qui suit, correspondant à une fermeture de connexion SSH dans un extrait de capture tcpdump :

# tcpdump -S -vv -n -r test.cap
15:02:33.131298 IP (tos 0x0, ttl 64, id 12419, offset 0, flags [DF], proto: TCP (
6), length: 40) 192.168.1.10.3850 > 192.168.1.1.22: F, cksum 0xbfc2 (correct), 19
80283715:1980283715(0) ack 2557581716 win 64066
15:02:33.133672 IP (tos 0x10, ttl 64, id 39549, offset 0, flags [DF], proto: TCP 
(6), length: 40) 192.168.1.1.22 > 192.168.1.10.3850: F, cksum 0xb9bd (correct), 2
557581716:2557581716(0) ack 1980283716 win 71
15:02:33.133708 IP (tos 0x0, ttl 64, id 12420, offset 0, flags [DF], proto: TCP (
6), length: 40) 192.168.1.10.3850 > 192.168.1.1.22: ., cksum 0xbfc1 (correct), 19
80283716:1980283716(0) ack 2557581717 win 64066

Diagramme d'état TCP

Le protocole TCP permet d’assurer le transfert des données de manière fiable, par l’intermédiaire d’accusés réception. Ceci est représenté dans le diagramme d’état de la figure ci-dessous. On y retrouve la poignée de main TCP (3-way handshake : SYN, SYN/ACK, ACK).

Pour une description détaillée de chaque état, référez-vous à l'excellente documentation (en anglais) de la Kent State University : http://www.medianet.kent.edu/techreports/TR2005-07-22-tcp-EFSM.pdf.