Protocole:IP

From aldeid
Jump to navigation Jump to search
You might also see: Adressage IP • Trames

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.
Note
Ce protocole est présenté en premier car il encapsule les protocoles TCP, UDP et ICMP, comme nous le verrons plus loin.

En-tête IP

L’en-tête IP se présente comme suit :
En-tête du protocole IP

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.


Longueur des données (en bytes) = Longueur totale (en bytes) - ( IHL * 4 )

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.
  • 1er bit Reservé : positionné à 1.
  • 2ème bit DF (Don't Fragment) : indique si la fragmentation est autorisée. Un datagramme devant être fragmenté et ayant le flag DF égal à 1 est détruit.
  • 3ème bit MF (More fragments) : indique s'il s'agit du dernier fragment (dans ce cas, il vaut 0).
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é.
Image:protocole-004.png
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

Image:protocole-005.png
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.