Protocole:TCP
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
L’en-tête TCP a la forme suivante :
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.
|
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 :
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 :
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é |
---|---|
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.
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.