Protocole:IP
Le protocole IP
Définition et fonctions
IP signifie « Internet Protocol » soit, en français Protocole Internet. Ce protocole a pour fonction :
- De découper l'information à transmettre en paquets ;
- D’adresser ces paquets ;
- De transporter ces paquets indépendamment les uns des autres ;
- Et de recomposer le message initial à l'arrivée.
En-tête IP
L’en-tête IP se présente comme suit :
Champ (abréviation) | Description |
---|---|
Version (version=) | Le champ version, codé sur 4 bits, représente le numéro de version du protocole IP. Il permet aux piles IP réceptionnant chaque trame, de vérifier le format et d'interpréter correctement la suite du paquet. C'est d'ailleurs pour cette raison qu'il est placé au début. Une version inconnue par un équipement conduit au rejet du paquet. Par exemple, les codes 04 et 06 sont assignés respectivement à IP v4 et IP v6. |
Longueur en-tête (ihl=) | IHL signifie "Internet Header Lengh". Ce champ, codé sur 4 bits, représente le nombre d'ensembles de 32 bits. Un en-tête sans option a une longueur de 5, soit 20 bytes (5*32/8).
Comme la longueur de l'en-tête est codée sur 4 bits, sa taille maximum est de 1111 en binaire (15 en décimal), soit 60 bytes (15*32bits). |
Type de service (tos=) | Le champ "Type Of Service", codé sur 8 bits, permet la gestion d'une qualité de service traitée directement en couche 3 du modèle OSI. Cependant, la plupart des équipements ne tiennent pas compte de ce champ et même certains le réinitialisent à 0. |
Longueur totale (len=) | Le champ Longueur totale, codé sur 16 bits, représente la longueur du paquet, incluant l'entête IP et les données associées. La longueur totale est exprimée en bytes, et accepte une taille maximum de 1111111111111111 en binaire, soit 65 535 bytes. La longueur des données correspond à la longueur totale diminuée de 4 fois la longueur de l'en-tête.
|
Identification (id=) | Le champ Identification, codé sur 16 bits, constitue l'identification utilisée pour reconstituer les différents fragments. Chaque fragment possède le même numéro d'identification, les entêtes IP des fragments sont identiques à l'exception des champs Longueur totale, Checksum et Position fragment.
Les détails des mécanismes de fragmentation et de réassemblage sont spécifiés dans la RFC815. |
Drapeaux (flags=) | Le champ Flags est codé sur 3 bits et indique l'état de la fragmentation. Voici le détail des différents bits constituant ce champ.
|
Position fragment (frag=) | Le champ Position fragment, codé sur 13 bits, indique la position du fragment par rapport à la première trame. Le premier fragment possède donc le champ Position fragment à 0. |
Durée de vie (ttl=) | Le champ TTL (Time To Live) est codé sur 8 bits et indique le nombre de routeurs par lesquels le paquet peut passer. A chaque passage sur un routeur, la valeur du TTL est diminuée de 1. Si le TTL arrive à 0, alors l'équipement qui possède le paquet, le détruira. |
Protocole (proto=) | Le champ Protocole, codé sur 8 bits, indique le protocole dont est issu le datagramme. |
Total de contrôle (chksum=) | Le champ somme de contrôle de l'en-tête (en anglais Header Checksum) est codé sur 16 bits et permet de contrôler l'intégrité des données de l'en-tête afin de s'assurer que celui-ci n'a pas été altéré. |
Adresse source (src=) | Le champ IP source est codé sur 32 bits et représente l'adresse IP source ou de réponse. Le mécanisme de traduction est expliqué ici. |
Adresse de destination (dst=) | Le champ IP destination est codé sur 32 bits et représente l'adresse IP destination. |
Options (éventuelles)
(options=) |
Le champ Options est codé entre 0 et 40 octets et n'est pas obligatoire. Lorsque des options sont présentes, le premier byte de ce champ correspond normalement à des informations relatives aux options. |
MTU et fragmentation
Le MTU (Maximum Transfer Unit) correspond à la taille maximale de paquet pouvant être transmise sans fragmentation. Si un paquet est transmis à un routeur dont le MTU est plus faible que la taille du paquet, ce dernier est alors fragmenté.
La recherche du MTU à partir d'un hôte A souhaitant transférer des données vers un hôte B consiste en la détermination du Path MTU (PMTU). Il s'agit du Path MTU discovery (PMTUd). Le PMTU peut être obtenu par la commande tracepath :
$ tracepath aldeid.com 1: 192.168.1.10 (192.168.1.10) 0.385ms pmtu 1500 1: aldeid.com (82.240.150.190) 17.943ms reached 1: aldeid.com (82.240.150.190) 28.171ms reached Resume: pmtu 1500 hops 1 back 64
Sur un poste client, le MTU sous Linux peut être consulté avec la commande ifconfig :
$ ifconfig eth0 Lien encap:Ethernet HWaddr 00:0C:29:18:08:64 inet adr:192.168.182.133 Bcast:192.168.182.255 Masque:255.255.255.0 adr inet6: fe80::20c:29ff:fe18:864/64 Scope:Lien UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:1227 errors:0 dropped:0 overruns:0 frame:0 TX packets:1258 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 lg file transmission:1000 RX bytes:110565 (107.9 KiB) TX bytes:667966 (652.3 KiB) Interruption:177 Adresse de base:0x1080
L’exemple ci-dessus illustre le mécanisme de fragmentation. Le MTU valant 1500, le paquet de 4136 bytes (en-tête IP sans option : 20 + en-tête TCP sans option : 20 + données : 4096) doit être fragmenté.
Le fragment offset représente, pour chaque paquet fragmenté, sa position dans le datagramme IP initial.
- premier fragment : 0
- deuxième fragment : 1480 (la position du deuxième fragment dans le datagramme IP initial correspond à la taille du premier fragment)
- troisième fragment = 2960 (la position du troisième fragment dans le datagramme IP initial correspond à la taille des premier et deuxième fragments).
Nous pouvons simuler cet exemple avec Scapy. Pour cela, nous placerons une sonde tcpdump sur le serveur, et forgerons des paquets sur le client, à l’aide de Scapy.
Sur le serveur (192.168.182.130), lançons une sonde tcpdump qui permettra de capturer les trames émises par le client (192.168.182.128).
# tcpdump –w test-frag.cap
Sur le client (192.168.182.128), nous allons envoyer un paquet contenant comme données une chaîne de 4096 caractères ‘a’, à destination du serveur (192.168.182.130), sur le port 22.
>>> a=IP(dst="192.168.182.130")/TCP(dport=22)/('a'*4096) >>> ls(a) version : BitField = 4 (4) ihl : BitField = None (None) tos : XByteField = 0 (0) len : ShortField = None (None) id : ShortField = 1 (1) flags : FlagsField = 0 (0) frag : BitField = 0 (0) ttl : ByteField = 64 (64) proto : ByteEnumField = 6 (0) chksum : XShortField = None (None) src : Emph = '192.168.182.128' (None) dst : Emph = '192.168.182.130' ('127.0.0.1') options : IPoptionsField = () -- sport : ShortEnumField = 20 (20) dport : ShortEnumField = 22 (80) seq : IntField = 0 (0) ack : IntField = 0 (0) dataofs : BitField = None (None) reserved : BitField = 0 (0) flags : FlagsField = 2 (2) window : ShortField = 8192 (8192) chksum : XShortField = None (None) urgptr : ShortField = 0 (0) options : TCPOptionsField = {} ({}) -- load : StrField = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa … Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa’ ()
Afin de fragmenter les paquets, nous faisons appel à la fonction fragment(). La fonction send() quant à elle, permet d’envoyer le contenu précédemment forgé :
>>> send(fragment(a, 1480))
Les résultats de la sonde tcdump peuvent maintenant être analysés :
# tcpdump -SnX –vv -r test-frag.cap 17:18:34.625768 IP (tos 0x0, ttl 64, id 1, offset 0, flags [+], proto: TCP (6), length: 1500) 192.168.182.128.20 > 192.168.182.130.22: S 0:1460(1460) win 8192 0x0000: 4500 05dc 0001 2000 4006 66c7 c0a8 b680 [email protected]..... 0x0010: c0a8 b682 0014 0016 0000 0000 0000 0000 ................ 0x0020: 5002 2000 8659 0000 6161 6161 6161 6161 P....Y..aaaaaaaa 0x0030: 6161 6161 6161 6161 6161 6161 6161 6161 aaaaaaaaaaaaaaaa 0x0040: 6161 6161 6161 6161 6161 6161 6161 6161 aaaaaaaaaaaaaaaa 0x0050: 6161 aa 17:18:34.646632 IP (tos 0x0, ttl 64, id 1, offset 1480, flags [+], proto: TCP (6), length: 1500) 192.168.182.128 > 192.168.182.130: tcp 0x0000: 4500 05dc 0001 20b9 4006 660e c0a8 b680 [email protected]..... 0x0010: c0a8 b682 6161 6161 6161 6161 6161 6161 ....aaaaaaaaaaaa 0x0020: 6161 6161 6161 6161 6161 6161 6161 6161 aaaaaaaaaaaaaaaa 0x0030: 6161 6161 6161 6161 6161 6161 6161 6161 aaaaaaaaaaaaaaaa 0x0040: 6161 6161 6161 6161 6161 6161 6161 6161 aaaaaaaaaaaaaaaa 0x0050: 6161 aa 17:18:34.668801 IP (tos 0x0, ttl 64, id 1, offset 2960, flags [none], proto: TCP (6), length: 1176) 192.168.182.128 > 192.168.182.130: tcp 0x0000: 4500 0498 0001 0172 4006 8699 c0a8 b680 E......r@....... 0x0010: c0a8 b682 6161 6161 6161 6161 6161 6161 ....aaaaaaaaaaaa 0x0020: 6161 6161 6161 6161 6161 6161 6161 6161 aaaaaaaaaaaaaaaa 0x0030: 6161 6161 6161 6161 6161 6161 6161 6161 aaaaaaaaaaaaaaaa 0x0040: 6161 6161 6161 6161 6161 6161 6161 6161 aaaaaaaaaaaaaaaa 0x0050: 6161 aa
Nous constatons la présence de 3 paquets (fragments), avec un découpage qui présente les caractéristiques suivantes :
Fragment 1 | Offset | 0 |
---|---|---|
Flags | [+] | |
Length | 1500 | |
Fragment 2 | Offset | 1480 |
Flags | [+] | |
Length | 1500 | |
Fragment 3 | Offset | 2960 |
Flags | [none] | |
Length | 1500 |
Tcpdump utilise la notation [+] pour signifier la présence d’autres fragments (More Fragment). Le dernier fragment est noté [none] afin de mettre en évidence l’absence de fragments supplémentaires.
Il est également à noter que le premier fragment encapsule l’en-tête TCP. C’est la raison pour laquelle la taille des données du premier fragment ne vaut pas 1500 mais 1480 (soit la taille du MTU [1500], diminuée de la taille de l’en-tête TCP sans options [20]). Ainsi, le « offset » désigne bien la position du paquet fragmenté dans le datagramme IP initial.