Les adresses IPv4
Pourquoi
Dans la configuration de Signalements, Camille tombe sur trois lignes qui se ressemblent et ne disent pas du tout la même chose :
gunicorn --bind 127.0.0.1:8000 ...
gunicorn --bind 0.0.0.0:8000 ...
gunicorn --bind 172.16.20.11:8000 ...La première rend l'API injoignable depuis toute autre machine. La deuxième l'expose sur toutes les interfaces, y compris, sur une machine qui en a une, l'interface publique. La troisième ne l'expose que sur le réseau privé. Une erreur entre ces trois lignes, et l'on obtient soit un service mystérieusement injoignable, soit une API ouverte à Internet sans le savoir.
Ailleurs, un collègue propose de créer le réseau privé de la préproduction en 172.16.22.0/24 « pour ne pas gêner la production en 172.16.20.0/22 ». Il ne voit pas que la seconde plage contient déjà la première. Et dans un ticket, un client signale que son serveur a l'adresse 169.254.12.7 et « ne marche pas » : cette adresse dit, à elle seule, ce qui ne va pas.
Toutes ces situations se lisent en quelques secondes quand on sait lire une adresse IPv4. Cette leçon apprend à le faire, à la main et avec des outils.
Les concepts
Le paquet IPv4
La leçon 1 a placé IP au centre du sablier : c'est le seul protocole que tous les équipements d'Internet comprennent. Son en-tête, défini par la RFC 791 de septembre 1981, fait 20 octets sans options :
| Champ | Taille | Rôle |
|---|---|---|
| Version | 4 bits | 4 pour IPv4 |
| IHL | 4 bits | longueur de l'en-tête, en mots de 32 bits (5 sans options, soit 20 octets) |
| DSCP et ECN | 8 bits | à l'origine Type of Service ; aujourd'hui classe de service (DSCP) et signalement de congestion (ECN) |
| Longueur totale | 16 bits | taille du paquet, en-tête compris : 65 535 octets au plus |
| Identification, drapeaux, décalage | 32 bits | fragmentation d'un paquet trop grand (leçon 6) |
| TTL (Time to Live) | 8 bits | décrémenté par chaque routeur ; à zéro, le paquet est détruit (leçon 6) |
| Protocole | 8 bits | ce que transporte le paquet : 6 TCP, 17 UDP, 1 ICMP |
| Somme de contrôle de l'en-tête | 16 bits | vérifiée et recalculée à chaque routeur |
| Adresse source | 32 bits | qui envoie |
| Adresse destination | 32 bits | à qui |
Deux champs nous occupent dans cette leçon : les adresses, sur 32 bits chacune. Le TTL vaut 64 au départ sur Linux (/proc/sys/net/ipv4/ip_default_ttl) ; nous le retrouverons avec traceroute.
Une adresse, c'est un nombre de 32 bits
Une adresse IPv4 est un nombre entier entre 0 et 4 294 967 295 (2³² − 1). Pour le lire, on le découpe en quatre octets, chacun écrit en décimal de 0 à 255, séparés par des points : c'est la notation décimale pointée. L'adresse de sig-app-1, 172.16.20.11, est en réalité :
172 16 20 11
10101100 00010000 00010100 00001011La conversion d'un octet se fait avec les puissances de 2 : 172 = 128 + 32 + 8 + 4, donc les bits de poids 128, 32, 8 et 4 sont à 1 : 1010 1100. Avec un peu de pratique, les valeurs utiles se reconnaissent d'elles-mêmes : 128 = 1000 0000, 192 = 1100 0000, 224 = 1110 0000, 240 = 1111 0000, 248, 252, 254, 255 = 1111 1111.
Réseau et hôte : le préfixe
Une adresse IP ne désigne pas seulement une machine : elle dit aussi dans quel réseau elle se trouve. Les premiers bits de l'adresse identifient le réseau, les suivants identifient la machine (l'hôte) dans ce réseau. La frontière entre les deux s'appelle le préfixe, et on l'écrit après une barre oblique : 172.16.20.11/22 signifie « les 22 premiers bits désignent le réseau, les 10 derniers l'hôte ».
La même information s'écrit aussi sous la forme d'un masque de sous-réseau : un nombre de 32 bits dont les bits du réseau sont à 1 et ceux de l'hôte à 0. Pour /22 :
11111111 11111111 11111100 00000000 = 255.255.252.0Le masque et le préfixe sont deux écritures de la même chose. On rencontre encore beaucoup de masques dans les vieux fichiers de configuration et les interfaces graphiques ; les outils modernes (ip, les fournisseurs de cloud) parlent en préfixes.
À partir d'une adresse et de son préfixe, on calcule trois choses :
- L'adresse du réseau : l'adresse avec tous les bits d'hôte à 0. C'est un ET logique entre l'adresse et le masque.
- L'adresse de diffusion du réseau : tous les bits d'hôte à 1.
- Le nombre d'adresses utilisables pour des hôtes : 2 puissance (nombre de bits d'hôte), moins 2, puisque l'adresse du réseau et celle de diffusion sont réservées.
Pour 172.16.20.11/22 :
adresse 10101100.00010000.000101|00.00001011 172.16.20.11
masque 11111111.11111111.111111|00.00000000 255.255.252.0
réseau 10101100.00010000.000101|00.00000000 172.16.20.0
diffusion 10101100.00010000.000101|11.11111111 172.16.23.255Le réseau va donc de 172.16.20.0 à 172.16.23.255 : 2¹⁰ = 1 024 adresses, dont 1 022 utilisables. C'est le réseau privé pn-signalements du cours cloud. On remarque que la frontière tombe au milieu du troisième octet : c'est ce qui rend les préfixes qui ne sont pas des multiples de 8 un peu plus délicats à calculer de tête. Une astuce : pour /22, le troisième octet avance par pas de 2¹⁰⁻⁸ = 4 (20, 24, 28...), donc le réseau qui contient .20.x commence à .20.0 et finit à .23.255.
La fin des classes : CIDR
Pendant les douze premières années d'IPv4, il n'y avait pas de préfixe écrit : la taille du réseau se déduisait des premiers bits de l'adresse. La RFC 791 définissait trois classes :
| Classe | Premiers bits | Plage | Préfixe implicite | Hôtes par réseau |
|---|---|---|---|---|
| A | 0 | 0.0.0.0 à 127.255.255.255 | /8 | 16 777 214 |
| B | 10 | 128.0.0.0 à 191.255.255.255 | /16 | 65 534 |
| C | 110 | 192.0.0.0 à 223.255.255.255 | /24 | 254 |
L'idée était simple, et les routeurs pouvaient connaître la taille d'un réseau sans configuration. Elle s'est révélée désastreuse au début des années 1990. La RFC 4632 le résume : la classe C, avec 254 hôtes, est trop petite pour la plupart des organisations, et la classe B, avec 65 534, beaucoup trop grande. Tout le monde demandait des classes B, qui s'épuisaient, et la moitié de leurs adresses dormaient. Dans le même temps, chaque réseau de classe C attribué ajoutait une ligne aux tables de routage d'Internet, qui grossissaient plus vite que la mémoire des routeurs.
La réponse fut CIDR (Classless Inter-Domain Routing), en 1993 (RFC 1519, remplacée par la RFC 4632 en 2006) : le préfixe devient explicite et peut avoir n'importe quelle longueur. On attribue un /22 à qui a besoin de mille adresses, et un fournisseur d'accès peut annoncer à Internet un seul /16 pour tous ses clients, au lieu de 256 lignes de classe C. C'est l'agrégation des routes.
Les classes n'existent plus que dans le vocabulaire (« une classe C » pour dire « un /24 ») et dans quelques réflexes anciens. Une adresse en 10. n'est pas « forcément en /8 », une adresse en 192.168. n'est pas « forcément en /24 » : seul le préfixe configuré fait foi.
Les adresses spéciales
Toutes les adresses ne sont pas utilisables partout. L'IANA tient le registre des adresses à usage particulier, établi par la RFC 6890. Les plages à connaître :
| Plage | Nom | Usage |
|---|---|---|
0.0.0.0/8 | « cet hôte sur ce réseau » | 0.0.0.0 comme adresse source d'une machine qui n'a pas encore d'adresse (DHCP), et comme adresse d'écoute « toutes les adresses » |
10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 | privées (RFC 1918) | réseaux internes, jamais routées sur Internet (leçon 7) |
100.64.0.0/10 | espace partagé (RFC 6598) | réseaux internes des opérateurs qui font du NAT à grande échelle (leçon 7) |
127.0.0.0/8 | boucle locale (loopback) | la machine elle-même, toute la plage |
169.254.0.0/16 | lien local (RFC 3927) | adresses auto-attribuées sans serveur DHCP ; services de métadonnées des fournisseurs de cloud |
192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24 | documentation (RFC 5737) | exemples dans les livres et les cours, comme celui-ci |
198.18.0.0/15 | tests de performance | bancs d'essai d'équipements réseau |
224.0.0.0/4 | multidiffusion | un paquet pour un groupe d'abonnés (ex. 224.0.0.251 pour mDNS) |
240.0.0.0/4 | réservé | jamais attribué |
255.255.255.255/32 | diffusion limitée | tout le réseau local, sans passer un routeur |
Quelques remarques :
- La boucle locale est un
/8entier :127.0.0.2ou127.5.5.5désignent aussi la machine elle-même sous Linux. Seule127.0.0.1est configurée sur l'interfacelo, mais le noyau traite toute la plage comme locale (nous le vérifierons). - Les adresses de lien local en
169.254.ont deux visages. Sur un poste ou un serveur, une adresse de ce type attribuée automatiquement signifie presque toujours que le DHCP a échoué : la machine s'est donné une adresse au hasard pour pouvoir au moins parler à ses voisins immédiats. C'est le cas du ticket de l'introduction. Dans le cloud, en revanche, la plage sert volontairement aux services de métadonnées :169.254.169.254chez la plupart des fournisseurs,169.254.42.42chez Scaleway, comme l'a montré le cours Le cloud : les fondamentaux. Ces adresses ne sont jamais routées au-delà du lien, ce qui garantit que seule l'instance elle-même atteint son service de métadonnées. - Les plages de documentation existent pour que les exemples ne visent jamais une machine réelle. Ce cours les utilise systématiquement :
203.0.113.10est l'adresse du répartiteur de Signalements dans nos exemples, et n'appartient à personne.
L'épuisement des adresses
Quatre milliards d'adresses semblaient beaucoup en 1981. En retirant les plages spéciales, il en reste environ 3,7 milliards pour Internet, soit moins d'une par habitant de la planète, et bien moins d'une par appareil connecté. Le stock s'est épuisé par étapes :
- Le 3 février 2011, l'IANA a distribué ses cinq derniers blocs
/8libres, un à chacun des cinq registres régionaux (RIR) qui attribuent les adresses dans le monde. - Le 25 novembre 2019, le RIPE NCC, registre de l'Europe, du Moyen-Orient et d'une partie de l'Asie centrale, a fait sa dernière attribution d'un bloc
/22. Depuis, il ne distribue plus que des adresses récupérées, par blocs de/24, à de nouveaux membres inscrits sur une liste d'attente.
Les conséquences sont tangibles : une adresse IPv4 publique se paie (les fournisseurs de cloud la facturent à part, comme l'a montré la leçon 8 du cours cloud), elle s'achète et se revend sur un marché, et l'on économise les adresses par la traduction d'adresses (leçon 7). La solution de long terme est IPv6, avec ses adresses de 128 bits (leçon 8).
En pratique
Les sorties ont été produites sur le poste Ubuntu 24.04 de Camille, avec LC_ALL=C.UTF-8 ; les adresses de son réseau ont été remplacées par des adresses de l'exemple.
Lire ip addr
$ ip -4 addr show wlo1
2: wlo1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
altname wlp0s20f3
inet 192.168.1.23/24 brd 192.168.1.255 scope global dynamic noprefixroute wlo1
valid_lft 4854sec preferred_lft 4854sec
-4 limite l'affichage aux adresses IPv4. La ligne qui commence par inet se lit ainsi, d'après ip-address(8) :
192.168.1.23/24: l'adresse et son préfixe. Le poste est dans le réseau192.168.1.0/24, celui de la box.brd 192.168.1.255: l'adresse de diffusion du réseau, calculée à partir du préfixe.scope global: l'adresse est valable au-delà de la machine.scope hostdésigne une adresse utilisable seulement sur la machine (la boucle locale) ;scope link, une adresse valable sur le lien seulement (lien local).dynamic: l'adresse a été obtenue par DHCP et a une durée de vie ;valid_lft(valid lifetime) dit combien de secondes il reste avant l'expiration du bail, que le client DHCP renouvellera avant.noprefixroute: le noyau n'a pas ajouté lui-même la route vers le réseau192.168.1.0/24; c'est NetworkManager, le gestionnaire réseau du poste de travail, qui s'en charge avec sa propre priorité. Sur un serveur configuré par netplan et systemd-networkd, cette mention est en général absente.
L'interface de boucle locale, elle, a une adresse fixe :
$ ip -4 addr show lo
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
Une interface peut porter plusieurs adresses : il suffit d'en ajouter (sudo ip addr add 172.16.20.50/22 dev ens2, sur une machine de laboratoire). Chacune apparaît sur sa propre ligne inet. C'est ainsi qu'une machine porte une adresse de service en plus de sa propre adresse. Une adresse ajoutée par ip addr add disparaît au redémarrage : la configuration permanente passe par netplan sur Ubuntu Server, ou par le fournisseur de cloud via DHCP.
Calculer avec Python
Le module ipaddress de la bibliothèque standard de Python fait tous les calculs de cette leçon, sans rien installer :
$ python3 -c 'import ipaddress as i; n=i.ip_network("172.16.20.0/22"); print(n.netmask, n.network_address, n.broadcast_address, n.num_addresses)'
255.255.252.0 172.16.20.0 172.16.23.255 1024
$ python3 -c 'import ipaddress as i; a=i.ip_interface("172.16.20.11/22"); print(a.ip, a.network, a.netmask)'
172.16.20.11 172.16.20.0/22 255.255.252.0
ip_network désigne un réseau, ip_interface une adresse avec son préfixe, comme on la configure sur une interface. Si vous passez une adresse d'hôte à ip_network, Python refuse, et l'erreur est instructive :
$ python3 -c 'import ipaddress as i; i.ip_network("172.16.20.11/22")' 2>&1 | tail -1
ValueError: 172.16.20.11/22 has host bits set
$ python3 -c 'import ipaddress as i; print(i.ip_network("172.16.20.11/22", strict=False))'
172.16.20.0/22
Le message dit exactement ce qui ne va pas : un réseau s'écrit avec ses bits d'hôte à zéro. Pour voir les bits :
$ python3 -c 'import ipaddress as i; print(".".join(f"{o:08b}" for o in i.ip_address("172.16.20.11").packed)); print(".".join(f"{o:08b}" for o in i.ip_network("172.16.20.0/22").netmask.packed))'
10101100.00010000.00010100.00001011
11111111.11111111.11111100.00000000
Et pour tester l'appartenance d'une adresse à un réseau, la question du collègue de l'introduction :
$ python3 -c 'import ipaddress as i; print(i.ip_address("172.16.24.1") in i.ip_network("172.16.20.0/22"), i.ip_address("172.16.23.200") in i.ip_network("172.16.20.0/22"))'
False True
172.16.23.200 est dans le réseau de production, 172.16.24.1 n'y est pas. Le réseau 172.16.22.0/24 proposé pour la préproduction est donc inclus dans celui de la production : c'est un chevauchement, qui empêchera de relier un jour les deux réseaux. La méthode overlaps() le dit directement (exercice 3).
Note
Certaines distributions fournissent aussi la commande ipcalc (paquet ipcalc sur Debian et Ubuntu), qui affiche ces informations en couleur. Elle n'est pas installée par défaut ; le module Python, si.
Que veut dire « privé » ?
Le même module classe les adresses selon le registre de l'IANA :
$ python3 -c 'import ipaddress as i; print(i.ip_address("100.64.0.1").is_private, i.ip_address("100.64.0.1").is_global, i.ip_address("203.0.113.10").is_private)'
False False True
Deux surprises. Une adresse de documentation comme 203.0.113.10 est considérée comme « privée » : pour Python, is_private veut dire « non joignable globalement selon le registre », et pas « dans les plages de la RFC 1918 ». Et l'espace partagé 100.64.0.0/10 n'est ni privé ni global : la documentation de Python le traite explicitement comme une exception. Si vous écrivez un contrôle de sécurité (« refuser les adresses internes »), lisez la documentation de la fonction que vous utilisez : le mot « privé » n'a pas le même sens partout.
Écouter sur 127.0.0.1 ou sur 0.0.0.0
Revenons aux trois lignes de Gunicorn de l'introduction, et vérifions le comportement avec le petit serveur HTTP de Python, sur un port de test :
$ python3 -m http.server 8123 --bind 127.0.0.1 &
$ ss -ltn 'sport = :8123'
State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0 5 127.0.0.1:8123 0.0.0.0:*
$ curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8123/
200
$ curl -sS http://127.0.0.2:8123/
curl: (7) Failed to connect to 127.0.0.2 port 8123 after 0 ms: Couldn't connect to server
Le serveur écoute sur 127.0.0.1 seulement : même une autre adresse de la boucle locale, 127.0.0.2, est refusée. A fortiori, une autre machine ne peut pas le joindre. Arrêtez-le (kill %1) et relancez-le sur 0.0.0.0 :
$ python3 -m http.server 8123 --bind 0.0.0.0 &
$ ss -ltn 'sport = :8123'
State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0 5 0.0.0.0:8123 0.0.0.0:*
$ curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.2:8123/
200
0.0.0.0 comme adresse d'écoute signifie « toutes les adresses IPv4 de la machine », présentes et futures : la boucle locale, l'adresse du réseau privé, et l'adresse publique s'il y en a une. C'est une adresse joker, pas une adresse de destination. La bonne pratique sur un serveur est donc l'adresse la plus étroite qui rende le service : 127.0.0.1 si seul un proxy local doit le joindre, l'adresse privée si un répartiteur de charge passe par le réseau privé, et 0.0.0.0 seulement quand un pare-feu en amont contrôle effectivement l'exposition.
Arrêtez le serveur avant de passer à la suite (kill %1).
La boucle locale est un /8
Le noyau considère bien toute la plage 127.0.0.0/8 comme locale, ce que montre la table de routage local, que le noyau gère lui-même :
$ ip route get 127.5.5.5
local 127.5.5.5 dev lo src 127.0.0.1 uid 1000
cache <local>
$ ip route show table local | grep -E "^(local|broadcast) 127"
local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1
local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1
broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1
ip route get demande au noyau quelle route il emprunterait pour une adresse, sans rien envoyer ; nous nous en servirons beaucoup à la leçon 5.
Sous le capot
Un ET logique par paquet. Pour décider si une destination est sur son réseau local, une machine fait, pour chaque route, un ET bit à bit entre l'adresse de destination et le masque de la route, et compare le résultat à l'adresse du réseau. C'est une opération que les processeurs exécutent en un cycle, et que les routeurs matériels implémentent dans des mémoires spécialisées. CIDR a rendu la recherche un peu plus subtile, puisque plusieurs routes de longueurs différentes peuvent correspondre : on garde la plus longue, ce qui est l'objet de la leçon 5.
L'adresse appartient à la machine, pas à l'interface. Sous Linux, une adresse IP est configurée sur une interface, mais le noyau, par défaut, répond à une requête qui vise n'importe laquelle de ses adresses, quelle que soit l'interface par laquelle elle arrive (ce que la littérature appelle le modèle d'hôte « faible »). C'est un comportement à connaître : une machine avec une interface publique et une interface privée peut accepter, sur l'interface publique, un paquet destiné à son adresse privée, si un routeur le lui envoie. Les pare-feu et certains réglages du noyau (rp_filter, arp_ignore) servent à resserrer ce comportement.
Pourquoi 0.0.0.0 « écoute partout ». Lors de bind(2), l'adresse INADDR_ANY (qui vaut 0.0.0.0) dit au noyau de ne pas filtrer sur l'adresse de destination : toute connexion qui arrive sur le bon port, quelle que soit l'adresse locale visée, est remise à cette socket. Une socket liée à une adresse précise ne reçoit que les connexions qui visent cette adresse. C'est ce que décrit ip(7).
Pièges courants
Confondre adresse de réseau et adresse d'hôte. 172.16.20.0/22 est un réseau ; 172.16.20.11/22 est une adresse dans ce réseau. Beaucoup d'outils (Python, Terraform, les API des fournisseurs) refusent l'une à la place de l'autre, avec un message comme has host bits set.
Supposer le préfixe d'après la classe. Une adresse en 10. n'est pas en /8, une adresse en 192.168. n'est pas en /24 : seul le préfixe configuré compte. Un ancien script qui « devine » le masque produira une mauvaise adresse de diffusion et une mauvaise route.
Des plages qui se chevauchent. Les réseaux d'un même ensemble (production, préproduction, réseau de l'entreprise relié par VPN, réseaux des conteneurs Docker) doivent être disjoints, sinon on ne pourra jamais les relier. Docker, par exemple, prend par défaut des plages dans 172.17.0.0/16 et au-delà pour ses réseaux : une machine dont le réseau d'entreprise est en 172.18.0.0/16 aura des surprises. Tenez un registre des plages utilisées.
Exposer un service par 0.0.0.0 sans le savoir. Beaucoup de serveurs de développement, de bases de données et d'images de conteneurs écoutent par défaut sur toutes les adresses. Vérifiez toujours avec ss -ltn ce qui écoute réellement, et où.
Ignorer une adresse en 169.254.. Sur un serveur ou un poste, elle signale un échec DHCP ; ce n'est pas une adresse avec laquelle on peut travailler.
Utiliser des adresses publiques réelles dans des exemples ou des tests. Une adresse inventée « au hasard » appartient presque toujours à quelqu'un. Dans la documentation, les tests et les fichiers d'exemple, utilisez les plages de la RFC 5737.
Sécurité
- L'adresse d'écoute est la première ligne de défense. Un service lié à
127.0.0.1est inaccessible depuis le réseau, quel que soit l'état du pare-feu. Un service lié à0.0.0.0ne doit sa protection qu'au pare-feu et au groupe de sécurité : la moindre erreur de configuration l'expose. Des milliers de bases de données se retrouvent chaque année ouvertes sur Internet de cette façon. - Une adresse source ne prouve rien. N'importe qui peut écrire n'importe quelle adresse source dans un paquet. Les opérateurs bien tenus filtrent en sortie les adresses qui ne leur appartiennent pas (BCP 38), mais pas tous. Une liste blanche d'adresses IP est une mesure utile, jamais une authentification.
- Les adresses de métadonnées sont sensibles. Une application qui va chercher des URL fournies par l'utilisateur (aperçu de lien, import d'image) peut être détournée vers
169.254.169.254ou169.254.42.42pour lire les métadonnées de l'instance : c'est l'attaque SSRF vue dans le cours cloud. Une liste de refus doit couvrir la boucle locale, le lien local, les plages privées et partagées, et vérifier l'adresse après résolution DNS. - « Privé » n'est pas « sûr ». Les plages privées ne sont pas routées sur Internet, mais une machine compromise du même réseau privé, un VPN mal configuré ou une redirection de port les atteint. On authentifie et on chiffre aussi à l'intérieur.
En production
- Planifiez l'adressage avant de créer les réseaux. Une plage par environnement et par région, sans chevauchement avec le réseau de l'entreprise ni avec les plages par défaut des outils (Docker, Kubernetes). La leçon 4 donne la méthode. Changer de plage après coup oblige à tout reconstruire.
- Les adresses publiques sont rares et facturées. On les réserve aux points d'entrée (répartiteurs de charge, passerelles), comme dans l'architecture de Signalements du cours cloud, où les instances n'ont plus d'adresse publique.
- Fixez les adresses des services, pas des machines. Une machine remplacée change souvent d'adresse ; un nom DNS, une IP flexible ou une adresse de répartiteur restent stables. Les adresses IP en dur dans une configuration applicative sont une dette.
- Chez Lyneko, le réseau privé des applications et les plages des clusters Kubernetes sont choisis pour ne jamais chevaucher les réseaux des clients reliés par VPN : c'est la première question posée avant de créer un environnement.
Exercices
1. Convertir (niveau 100). Écrivez en binaire 192.168.1.23 et 255.255.255.192. Quel préfixe correspond à ce masque ?
Solution
192.168.1.23 = 11000000.10101000.00000001.00010111 (192 = 128 + 64, 168 = 128 + 32 + 8, 23 = 16 + 4 + 2 + 1). 255.255.255.192 = 11111111.11111111.11111111.11000000 : 26 bits à 1, donc /26. Vérification : python3 -c 'import ipaddress as i; print(i.ip_network("0.0.0.0/255.255.255.192").prefixlen)'.
2. Calculer un réseau (niveau 100). Pour l'adresse 10.42.37.200/20, donnez l'adresse du réseau, l'adresse de diffusion, la première et la dernière adresse d'hôte, et le nombre d'hôtes.
Solution
/20 : 12 bits d'hôte, la frontière est dans le troisième octet, qui avance par pas de 2⁴ = 16 (0, 16, 32, 48...). 37 est entre 32 et 47. Réseau : 10.42.32.0/20 ; diffusion : 10.42.47.255 ; premier hôte 10.42.32.1, dernier 10.42.47.254 ; 2¹² − 2 = 4 094 hôtes. Vérification avec ipaddress.ip_interface("10.42.37.200/20").network puis .broadcast_address et .num_addresses.
3. Le chevauchement (niveau 100). La production utilise 172.16.20.0/22. Parmi 172.16.22.0/24, 172.16.24.0/22 et 172.16.16.0/21, lesquels peuvent servir à la préproduction ? Vérifiez avec la méthode overlaps() de ipaddress.
Solution
172.16.22.0/24 est inclus dans 172.16.20.0/22 (qui va de .20.0 à .23.255) : refusé. 172.16.24.0/22 va de .24.0 à .27.255 : disjoint, accepté. 172.16.16.0/21 va de .16.0 à .23.255 : il contient la production, refusé. Vérification : python3 -c 'import ipaddress as i; p=i.ip_network("172.16.20.0/22"); [print(r, p.overlaps(i.ip_network(r))) for r in ["172.16.22.0/24","172.16.24.0/22","172.16.16.0/21"]]' affiche True, False, True.
4. Lire des adresses (niveau 100). Que vous apprend chacune de ces adresses vues sur un serveur ou dans un journal ? (a) 169.254.12.7/16 sur l'interface principale d'un serveur ; (b) une connexion entrante depuis 100.72.4.9 ; (c) Gunicorn lancé avec --bind 0.0.0.0:8000 sur une instance qui a une adresse publique ; (d) une requête d'une application vers 169.254.42.42.
Solution
(a) Adresse de lien local auto-attribuée : le serveur n'a pas obtenu de bail DHCP. On regarde le client DHCP, le lien, le serveur DHCP. (b) Une adresse de l'espace partagé 100.64.0.0/10 : la connexion vient de derrière le NAT d'un opérateur (CGNAT, leçon 7), ou d'un réseau interne qui utilise cette plage. (c) L'API écoute sur toutes les adresses, y compris l'adresse publique : seule la configuration du pare-feu ou du groupe de sécurité la protège ; mieux vaut lier Gunicorn à l'adresse privée ou à 127.0.0.1. (d) Le service de métadonnées de Scaleway : légitime pour cloud-init ou un agent, suspect s'il s'agit d'une application web qui suit des URL fournies par l'utilisateur (SSRF).
Récapitulatif
- L'en-tête IPv4 (RFC 791) fait 20 octets sans options : version, longueur, TTL, protocole, somme de contrôle, et surtout les adresses source et destination de 32 bits.
- Une adresse IPv4 est un nombre de 32 bits écrit en quatre octets décimaux ; le préfixe (
/22) ou le masque (255.255.252.0) sépare la partie réseau de la partie hôte. - Adresse du réseau : bits d'hôte à 0 ; diffusion : bits d'hôte à 1 ; hôtes : 2^(bits d'hôte) − 2.
- Les classes A, B, C ont été abandonnées en 1993 au profit de CIDR : préfixe explicite de longueur quelconque, et agrégation des routes.
- Plages à reconnaître : privées (
10/8,172.16/12,192.168/16), partagée (100.64/10), boucle locale (127/8), lien local (169.254/16, échec DHCP ou métadonnées), documentation (192.0.2/24,198.51.100/24,203.0.113/24). - Le stock IPv4 est épuisé (IANA en 2011, RIPE NCC en 2019) : les adresses publiques se paient et s'économisent.
- Écouter sur
127.0.0.1: la machine seule ; sur une adresse précise : cette interface ; sur0.0.0.0: toutes les adresses, publique comprise. Choisissez la plus étroite. ip addrmontre adresses, préfixes, portée et bail ; le module Pythonipaddressfait tous les calculs.
Pour aller plus loin
- Le registre IANA des adresses IPv4 à usage particulier, qui fait autorité sur les plages spéciales.
- La RFC 4632, section 3, pour l'histoire et la mécanique de CIDR et de l'agrégation.
- La documentation du module
ipaddressde Python, pour les calculs dans vos scripts. - La leçon suivante, qui découpe une plage en sous-réseaux et construit le plan d'adressage de Signalements.
Sources
- RFC 791, Internet Protocol (J. Postel, septembre 1981)
- RFC 4632, Classless Inter-domain Routing (CIDR) (août 2006)
- RFC 6890, Special-Purpose IP Address Registries (2013), et registre IANA correspondant
- RFC 1918, Address Allocation for Private Internets (1996)
- RFC 5737, IPv4 Address Blocks Reserved for Documentation (2010)
- ARIN, The IANA IPv4 Address Free Pool is now Depleted (3 février 2011)
- RIPE NCC, The RIPE NCC has run out of IPv4 Addresses (25 novembre 2019)
- Python, documentation du module ipaddress
- Linux man-pages : ip-address(8), ip(7)