Découper en sous-réseaux
Pourquoi
À la leçon 6 du cours Le cloud : les fondamentaux, l'équipe de Signalements a créé son réseau privé avec une commande qui précisait subnets.0=172.16.20.0/22, et une consigne : « tenez un registre des plages utilisées ». Cette leçon explique ce qu'il y a derrière ces deux lignes.
Choisir des adresses semble anodin : on prend 10.0.0.0/16, ou ce que le fournisseur propose par défaut, et tout fonctionne. Tout fonctionne, tant que ce réseau reste seul. Les ennuis commencent le jour où on le relie à un autre :
- un développeur se connecte au VPN de l'entreprise, et ne joint plus la base de données de préproduction, parce que sa box et le réseau distant utilisent tous deux
192.168.1.0/24; - une instance fait tourner Docker, et ne joint plus une partie du réseau privé, parce que Docker a créé un pont dont la plage recouvre celle du réseau voisin ;
- deux entreprises fusionnent, ou deux équipes relient leurs VPC, et découvrent qu'elles ont choisi les mêmes adresses ; il faut renuméroter des centaines de machines.
La RFC 1918, qui a réservé les plages privées en 1996, anticipait déjà ce dernier cas : quand deux organisations qui ont numéroté leurs réseaux privés sans se coordonner les réunissent, certaines adresses ne sont plus uniques. Renuméroter un réseau en service coûte cher et fait peur. Planifier coûte une heure.
Il y a une seconde raison de savoir découper : les règles de pare-feu, les tables de routage, les groupes de sécurité et les listes de contrôle d'accès s'écrivent en préfixes. Une règle « autoriser 172.16.20.0/26 » ne fait pas ce que vous croyez si vous ne savez pas, de tête ou presque, quelles adresses elle couvre.
Les concepts
Rappel : le préfixe découpe l'adresse en deux
La leçon 3 a posé la notation CIDR. Une adresse IPv4 compte 32 bits ; un préfixe /22 dit que les 22 premiers bits désignent le réseau et les 10 suivants l'hôte dans ce réseau. Voici 172.16.20.11/22 en binaire, avec son masque :
$ python3 -c "
import ipaddress
for a in ['172.16.20.11','255.255.252.0','172.16.20.0','172.16.23.255']:
print(f'{a:<15}', '.'.join(f'{int(o):08b}' for o in a.split('.')))
"
172.16.20.11 10101100.00010000.00010100.00001011
255.255.252.0 11111111.11111111.11111100.00000000
172.16.20.0 10101100.00010000.00010100.00000000
172.16.23.255 10101100.00010000.00010111.11111111
Lisez la deuxième ligne : 22 bits à 1, puis 10 bits à 0. L'adresse de réseau (172.16.20.0) garde les 22 bits de tête et met tous les bits d'hôte à 0 ; l'adresse de diffusion (172.16.23.255) les met tous à 1. Entre les deux, 2¹⁰ = 1 024 adresses, dont 1 022 utilisables par des machines dans un réseau classique.
Découper, c'est allonger le préfixe : prendre des bits à la partie hôte pour les donner à la partie réseau. Chaque bit emprunté double le nombre de sous-réseaux et divise leur taille par deux. Un /22 donne deux /23, quatre /24, seize /26.
Regrouper (on dit aussi agréger, ou supernetting), c'est l'inverse : raccourcir le préfixe pour qu'un seul préfixe couvre plusieurs sous-réseaux contigus. C'est ce qui permet à un routeur de n'avoir qu'une route vers 172.16.20.0/22 au lieu de quatre routes vers des /24. La RFC 4632, qui définit le CIDR, en fait le cœur de son plan : agréger les routes pour que les tables de routage d'Internet restent d'une taille raisonnable.
Le tableau à connaître
Tout découpage IPv4 se ramène aux puissances de deux. Ce tableau se reconstruit en une minute et mérite d'être su :
| Préfixe | Masque | Adresses | Utilisables (réseau classique) | Pas dans l'octet concerné |
|---|---|---|---|---|
/20 | 255.255.240.0 | 4 096 | 4 094 | 16 (3e octet) |
/21 | 255.255.248.0 | 2 048 | 2 046 | 8 (3e octet) |
/22 | 255.255.252.0 | 1 024 | 1 022 | 4 (3e octet) |
/23 | 255.255.254.0 | 512 | 510 | 2 (3e octet) |
/24 | 255.255.255.0 | 256 | 254 | 1 (3e octet) |
/25 | 255.255.255.128 | 128 | 126 | 128 (4e octet) |
/26 | 255.255.255.192 | 64 | 62 | 64 |
/27 | 255.255.255.224 | 32 | 30 | 32 |
/28 | 255.255.255.240 | 16 | 14 | 16 |
/29 | 255.255.255.248 | 8 | 6 | 8 |
/30 | 255.255.255.252 | 4 | 2 | 4 |
/31 | 255.255.255.254 | 2 | 2 (liaison point à point) | 2 |
/32 | 255.255.255.255 | 1 | 1 (une seule machine) | 1 |
La colonne « utilisables » retire deux adresses, celle du réseau et celle de diffusion. Ce n'est vrai que dans un réseau classique : les /31 et /32 sont des cas particuliers (plus bas), et les fournisseurs cloud retirent davantage d'adresses (section En production).
La méthode du nombre magique
Pour découper de tête, on n'a pas besoin d'écrire 32 bits. On cherche l'octet intéressant, celui où tombe la frontière du préfixe, et le nombre magique : 256 moins la valeur du masque dans cet octet. C'est le pas entre deux sous-réseaux.
Exemple : dans quel sous-réseau /26 se trouve 172.16.20.75 ?
/26: la frontière tombe dans le 4e octet (24 bits pour les trois premiers octets, plus 2).- Masque dans cet octet :
192(deux bits à 1 : 128 + 64). Nombre magique : 256 − 192 = 64. - Les sous-réseaux commencent à 0, 64, 128, 192.
75est entre 64 et 127. - Réponse : réseau
172.16.20.64/26, diffusion172.16.20.127, adresses utilisables de.65à.126.
Deuxième exemple, avec la frontière dans le 3e octet : dans quel /22 se trouve 172.16.21.200 ?
/22: 16 bits pour les deux premiers octets, plus 6 dans le 3e.- Masque dans le 3e octet :
252. Nombre magique : 256 − 252 = 4. - Les blocs commencent à 0, 4, 8, 12, 16, 20, 24...
21est entre 20 et 23. - Réponse :
172.16.20.0/22, de172.16.20.0à172.16.23.255.
La méthode binaire donne le même résultat, et reste la référence quand on hésite : un ET logique bit à bit entre l'adresse et le masque donne l'adresse de réseau.
Découper à tailles variables (VLSM)
Rien n'oblige à découper un bloc en morceaux égaux. Le VLSM (Variable Length Subnet Masking) consiste à donner à chaque usage la taille dont il a besoin : un /24 pour des applications qui grossiront, un /27 pour trois machines d'administration. Le CIDR l'a rendu possible en 1993 en abandonnant les classes d'adresses ; aujourd'hui, c'est la façon normale de travailler.
Une règle évite presque toutes les erreurs : allouer du plus grand au plus petit. Un /24 doit commencer sur une frontière de 256 adresses, un /26 sur une frontière de 64. Si l'on place d'abord les petits blocs au hasard, on fragmente l'espace et l'on ne trouve plus de place alignée pour le grand. En partant des grands, les petits se casent dans les restes.
Les plages privées et leurs voisines
La RFC 1918 réserve trois blocs pour les réseaux privés, que personne n'annonce sur Internet :
| Bloc | Étendue | Taille | Où on le rencontre souvent |
|---|---|---|---|
10.0.0.0/8 | 10.0.0.0 à 10.255.255.255 | 16,7 millions d'adresses | Grandes entreprises, VPN, Kubernetes (réseaux de pods) |
172.16.0.0/12 | 172.16.0.0 à 172.31.255.255 | 1 million d'adresses | Docker (172.17.0.0/16 par défaut), réseaux privés cloud |
192.168.0.0/16 | 192.168.0.0 à 192.168.255.255 | 65 536 adresses | Box et routeurs domestiques |
Le deuxième bloc piège souvent : 172.16.0.0/12 va jusqu'à 172.31.255.255, et non jusqu'à 172.16.255.255. Une adresse comme 172.20.5.1 est donc privée.
Deux autres plages comptent pour un plan d'adressage :
100.64.0.0/10, l'espace d'adresses partagé de la RFC 6598, réservé aux opérateurs qui font de la traduction d'adresses à grande échelle (le CGNAT, Carrier-Grade NAT, leçon 7). La RFC précise que cet espace est distinct de celui de la RFC 1918, parce qu'il est destiné aux réseaux des opérateurs. Ne l'utilisez pas pour vos réseaux internes : une box d'opérateur ou un VPN peut déjà s'en servir. Scaleway l'interdit d'ailleurs dans ses réseaux privés.192.0.2.0/24,198.51.100.0/24et203.0.113.0/24, réservées à la documentation par la RFC 5737. Ce cours les utilise pour ses exemples ; elles ne doivent jamais apparaître dans une configuration réelle.
Le chevauchement, ennemi silencieux
Deux réseaux se chevauchent quand au moins une adresse appartient aux deux. Tant qu'ils ne sont pas reliés, cela n'a aucune importance : c'est même tout l'intérêt des plages privées. Dès qu'une machine a une route vers les deux, elle ne peut plus choisir correctement, et c'est la route au préfixe le plus long qui l'emporte (leçon 5), ce qui rend l'un des deux réseaux en partie injoignable.
Le cas d'école du poste de développement :
- la box domestique distribue
192.168.1.0/24; - le VPN de l'entreprise pousse une route vers un site distant en
192.168.1.0/24; - résultat : les deux routes ont la même longueur, et selon leurs métriques, l'imprimante de la maison ou le serveur du bureau devient injoignable.
Le cas des conteneurs est plus sournois. Docker crée ses réseaux de pont dans des réserves d'adresses par défaut, dont 172.17.0.0/16 et les blocs suivants de 172.16.0.0/12, puis 192.168.0.0/16. La documentation de Docker indique qu'il essaie d'éviter les préfixes déjà utilisés sur l'hôte, mais qu'il peut être nécessaire de régler default-address-pools dans /etc/docker/daemon.json pour éviter des conflits de routage. Sur un poste qui a lancé quelques projets Docker Compose, ip route montre facilement une demi-douzaine de réseaux en 172.17.0.0/16, 172.18.0.0/16, 172.19.0.0/16, etc. Un VPC en 172.18.0.0/16, joint par un VPN depuis ce poste, serait en partie masqué.
C'est pour cela que la leçon du cours cloud choisissait 172.16.20.0/22 plutôt qu'un bloc proposé au hasard : la plage est dans 172.16.0.0/12, mais en dessous des réserves par défaut de Docker (qui commencent à 172.17.0.0), et loin des 192.168.x.0/24 des box.
En pratique
Python fournit, dans sa bibliothèque standard, le module ipaddress, qui fait tous ces calculs sans erreur. Les sorties ci-dessous ont été produites avec Python 3.12 sur Ubuntu 24.04. Écrivez les calculs à la main d'abord, puis vérifiez-les avec le module.
Lire un bloc
$ python3
>>> import ipaddress
>>> b = ipaddress.ip_network("172.16.20.0/22")
>>> print(b.num_addresses, b.netmask, b.hostmask, b.broadcast_address)
1024 255.255.252.0 0.0.3.255 172.16.23.255
>>> ipaddress.ip_address("172.16.21.200") in b
True
num_addresses: la taille totale du bloc, adresses de réseau et de diffusion comprises.netmaskethostmask: le masque, et son complément (les bits d'hôte). Le masque inverse0.0.3.255est celui qu'attendent certains équipements et certaines listes de contrôle d'accès.in: l'appartenance d'une adresse au bloc.
Le module refuse une adresse d'hôte là où il attend un réseau, ce qui attrape une erreur fréquente (la trace d'appel est abrégée) :
>>> ipaddress.ip_network("172.16.20.11/22")
Traceback (most recent call last):
...
ValueError: 172.16.20.11/22 has host bits set
>>> ipaddress.ip_network("172.16.20.11/22", strict=False)
IPv4Network('172.16.20.0/22')
>>> ipaddress.ip_interface("172.16.20.11/22").network
IPv4Network('172.16.20.0/22')
172.16.20.11/22 n'est pas un réseau : c'est l'adresse d'une interface (celle de sig-app-1) avec la longueur de préfixe de son réseau. C'est d'ailleurs ce qu'affiche ip -br addr sur l'instance. ip_interface représente ce couple ; .network en extrait le réseau.
Découper
>>> list(b.subnets(new_prefix=24))
[IPv4Network('172.16.20.0/24'), IPv4Network('172.16.21.0/24'), IPv4Network('172.16.22.0/24'), IPv4Network('172.16.23.0/24')]
>>> [str(s) for s in b.subnets(new_prefix=26)][:5]
['172.16.20.0/26', '172.16.20.64/26', '172.16.20.128/26', '172.16.20.192/26', '172.16.21.0/26']
Quatre /24, seize /26 (dont les cinq premiers sont montrés). Remarquez le pas : 64 dans le dernier octet, comme le prévoyait le nombre magique, puis le passage au /24 suivant.
Pour un sous-réseau donné, les adresses utiles :
>>> n = ipaddress.ip_network("172.16.20.64/26")
>>> print(n.network_address, n.broadcast_address, n.num_addresses - 2, n[1], n[-2])
172.16.20.64 172.16.20.127 62 172.16.20.65 172.16.20.126
n[1] est la première adresse utilisable, n[-2] la dernière (l'indice -1 serait la diffusion).
Regrouper
>>> ipaddress.ip_network("172.16.20.0/24").supernet(new_prefix=22)
IPv4Network('172.16.20.0/22')
>>> list(ipaddress.collapse_addresses([ipaddress.ip_network("172.16.20.0/24"),
... ipaddress.ip_network("172.16.21.0/24")]))
[IPv4Network('172.16.20.0/23')]
supernet(new_prefix=22)donne le bloc plus large qui contient ce réseau.collapse_addressesregroupe une liste de réseaux en le moins de préfixes possible : deux/24contigus et alignés deviennent un/23.
Le mot « aligné » compte. 172.16.21.0/24 et 172.16.22.0/24 sont contigus, mais ne forment pas un /23 : un /23 commence forcément sur un troisième octet pair. collapse_addresses les rendrait tels quels, en deux préfixes.
Détecter un chevauchement
>>> ipaddress.ip_network("172.17.0.0/16").overlaps(ipaddress.ip_network("172.16.0.0/12"))
True
>>> ipaddress.ip_network("172.16.20.0/22").overlaps(ipaddress.ip_network("172.17.0.0/16"))
False
Le réseau par défaut de Docker est bien une partie de la plage privée 172.16.0.0/12 ; il ne recouvre pas le réseau privé de Signalements. Ce test, appliqué à toutes les plages d'un registre, est la vérification à faire avant toute création de réseau.
Bâtir le plan d'adressage de Signalements
Jusqu'ici, Signalements vit dans un seul réseau privé de 1 024 adresses. Supposons que l'équipe veuille séparer ses usages, pour pouvoir filtrer entre eux : les applications (qui vont se multiplier), la préproduction, les bases de données et les machines d'administration. Elle estime ses besoins à un /24 pour les applications, un /24 pour la préproduction, un /26 (62 adresses) pour les bases et un /27 (30 adresses) pour l'administration, le tout dans 172.16.20.0/22.
Le petit programme suivant applique la règle du plus grand au plus petit : pour chaque besoin, il prend le plus petit bloc libre assez grand, en garde le premier morceau de la taille voulue, et remet le reste dans les blocs libres.
import ipaddress
bloc = ipaddress.ip_network("172.16.20.0/22")
besoins = {"applications": 24, "preproduction": 24, "bases": 26, "administration": 27}
libres = [bloc]
for nom, prefixe in sorted(besoins.items(), key=lambda b: b[1]):
# le plus petit bloc libre assez grand, puis on le découpe
libres.sort(key=lambda n: (-n.prefixlen, n.network_address))
parent = next(n for n in libres if n.prefixlen <= prefixe)
libres.remove(parent)
morceaux = list(parent.subnets(new_prefix=prefixe))
print(f"{nom:<15} {morceaux[0]}")
libres.extend(parent.address_exclude(morceaux[0]))
print("reste libre ", ", ".join(str(n) for n in sorted(libres)))$ python3 plan.py
applications 172.16.20.0/24
preproduction 172.16.21.0/24
bases 172.16.22.0/26
administration 172.16.22.64/27
reste libre 172.16.22.96/27, 172.16.22.128/25, 172.16.23.0/24
address_exclude renvoie ce qui reste d'un réseau une fois un sous-réseau retiré, sous forme de préfixes alignés. Le plan obtenu :
flowchart TB
B["172.16.20.0/22 : Signalements"]
B --> A["172.16.20.0/24<br/>applications"]
B --> P["172.16.21.0/24<br/>préproduction"]
B --> C["172.16.22.0/24"]
B --> R2["172.16.23.0/24<br/>réserve"]
C --> D["172.16.22.0/26<br/>bases"]
C --> E["172.16.22.64/27<br/>administration"]
C --> R1["172.16.22.96/27<br/>réserve"]
C --> R3["172.16.22.128/25<br/>réserve"]
Trois remarques sur ce plan :
- La réserve est délibérée. Un quart du bloc (
172.16.23.0/24) reste libre, plus deux morceaux dans le troisième/24. Le jour où les bases ont besoin de plus de place,172.16.22.0/26peut s'étendre... à condition que ses voisins soient libres. Ici, le/26suivant est occupé par l'administration ; une meilleure version placerait les petits blocs à la fin du/24et laisserait grandir les bases vers le haut. Les plans d'adressage des grandes organisations laissent souvent un bloc libre de même taille à côté de chaque bloc alloué, précisément pour pouvoir le doubler sans renuméroter. - La préproduction est-elle au bon endroit ? La mettre dans le même
/22que la production simplifie les routes, mais mélange les environnements dans un même espace. Beaucoup d'équipes préfèrent un bloc par environnement (172.16.20.0/22pour la production,172.16.24.0/22pour la préproduction), qui se lit d'un coup d'œil et se filtre avec une seule règle. C'est un choix à faire tôt. - Le plan va dans le registre. Une page, un fichier versionné, ou mieux un outil de gestion d'adresses (IPAM), qui liste chaque bloc, son usage, son propriétaire et sa date. C'est le registre dont parlait la leçon du cours cloud.
Le cas des liaisons point à point : /31 et /32
Une liaison entre deux routeurs n'a que deux extrémités. Un /30 (4 adresses) en gaspillait deux, réseau et diffusion. La RFC 3021 autorise le /31 sur les liaisons point à point : ses deux adresses doivent alors être interprétées comme des adresses d'hôtes, et la diffusion dirigée disparaît. Le module ipaddress connaît cette règle :
>>> list(ipaddress.ip_network("192.0.2.0/31").hosts())
[IPv4Address('192.0.2.0'), IPv4Address('192.0.2.1')]
Le /32 désigne une seule adresse. On le rencontre dans les règles de pare-feu (« autoriser 203.0.113.10/32 »), dans les listes d'adresses autorisées (le bastion de la leçon 6 du cours cloud), et dans certains réseaux cloud qui attribuent à chaque machine une adresse en /32 routée.
Sous le capot
Pourquoi les blocs doivent être alignés. Un routeur compare l'adresse de destination et le préfixe d'une route bit à bit, sur la longueur du préfixe. Un /24 « commençant » à 172.16.20.128 n'existerait pas : avec 24 bits de réseau, les 8 derniers bits sont ceux de l'hôte, et le réseau est forcément 172.16.20.0. C'est pourquoi ipaddress.ip_network("172.16.20.128/24") lève la même erreur has host bits set que plus haut. L'alignement n'est pas une convention, c'est une conséquence du fonctionnement du préfixe.
Comment le noyau sait si une destination est locale. Quand vous attribuez 172.16.20.11/22 à une interface, Linux crée automatiquement une route 172.16.20.0/22 dev ens2 proto kernel scope link : tout ce qui tombe dans ce préfixe est joignable directement, sans passer par un routeur, en demandant l'adresse matérielle par ARP (leçon 2). Une erreur de préfixe a donc des effets concrets. Avec /24 au lieu de /22, sig-app-1 croirait que 172.16.21.5 est ailleurs et l'enverrait à la passerelle ; avec /16, elle croirait que 172.16.99.1 est sur le même segment et l'appellerait par ARP sans jamais obtenir de réponse. La leçon 5 détaille cette décision.
Pourquoi le CIDR a remplacé les classes. Jusqu'en 1993, la taille d'un réseau dépendait de son premier octet : classe A (/8), B (/16) ou C (/24), rien entre les deux. Une organisation qui avait besoin de 2 000 adresses recevait un /16 (65 536 adresses) ou une poignée de /24, avec autant de routes. La RFC 4632 raconte le double problème que le CIDR résolvait : l'épuisement accéléré des adresses, et la croissance des tables de routage des routeurs du cœur d'Internet. On rencontre encore les mots « classe C » pour dire /24 : c'est un abus de langage, sans effet sur le fonctionnement.
Pièges courants
Se tromper d'étendue sur 172.16.0.0/12. Croire que 172.20.0.0/16 est une plage publique, ou au contraire que 172.32.0.0/16 est privée. La plage privée s'arrête à 172.31.255.255 ; 172.32.0.1 est une adresse publique.
Écrire une adresse d'hôte à la place d'un réseau. 10.0.0.5/24 dans une route ou une règle de pare-feu : selon l'outil, l'erreur est refusée (comme ipaddress), corrigée en silence (AWS normalise 100.68.0.18/18 en 100.68.0.0/18), ou acceptée avec un sens différent. Écrivez toujours l'adresse de réseau.
Allouer les petits blocs en premier. On place un /28 d'administration à 172.16.20.16, puis on cherche un /24 aligné : 172.16.20.0/24 n'est plus libre. Du plus grand au plus petit.
Oublier les plages des autres. Le réseau des box (192.168.0.0/24, 192.168.1.0/24), les réserves de Docker, les plages des VPN de vos clients, celle de 100.64.0.0/10 de certains opérateurs. Un réseau d'entreprise qui doit accueillir des postes nomades devrait éviter 192.168.0.0/16 en entier.
Dimensionner au plus juste. Un /28 pour « trois serveurs » se remplit dès qu'on ajoute un répartiteur de charge, une passerelle, deux interfaces de supervision, et les adresses que le fournisseur se réserve. Agrandir un sous-réseau sans renuméroter n'est possible que si l'espace voisin est libre.
Croire que .0 et .255 sont toujours inutilisables. Dans un /22, 172.16.21.0 et 172.16.20.255 sont des adresses d'hôte parfaitement valides : seules la première et la dernière adresse du bloc sont spéciales. Certains équipements anciens les refusent quand même ; ce n'est pas une règle d'IP.
Sécurité
Le découpage est la base du filtrage. Séparer les bases de données dans leur propre sous-réseau permet d'écrire une règle simple : « seul 172.16.20.0/24 peut joindre 172.16.22.0/26 sur le port 5432 ». Sans découpage, il faut énumérer des adresses, et la règle se périme à chaque nouvelle machine.
Un préfixe trop large ouvre plus qu'on ne croit. Une règle qui autorise 172.16.0.0/12 « pour le réseau privé » autorise aussi tous les réseaux Docker d'une machine, les autres VPC reliés, et les plages de VPN. Écrivez le préfixe le plus étroit qui couvre le besoin, et vérifiez-le avec overlaps ou subnet_of avant de l'appliquer.
Les plages privées ne sont pas un mécanisme de sécurité. Une adresse en 10.x n'est pas joignable directement depuis Internet parce qu'aucun opérateur ne la route, pas parce qu'elle serait protégée. Une machine compromise du même réseau, un VPN mal configuré ou une règle de redirection de port suffisent à l'atteindre. La RFC 1918 recommande d'ailleurs de filtrer les paquets à adresse privée aux frontières, dans les deux sens, pour éviter les fuites de trafic et de routes.
Ne publiez pas votre plan d'adressage. Il n'est pas secret au point de le chiffrer, mais il renseigne un attaquant sur l'organisation de votre réseau. Il a sa place dans un dépôt interne, pas dans un ticket public ou une documentation en ligne.
En production
Les fournisseurs cloud se réservent des adresses. Chez AWS, dans chaque sous-réseau, les quatre premières adresses et la dernière ne sont pas utilisables : l'adresse de réseau, le routeur du VPC (.1), le serveur DNS (.2), une adresse réservée pour un usage futur (.3), et la dernière, puisque le VPC ne gère pas la diffusion. Un /24 y offre donc 251 adresses, et un sous-réseau AWS doit mesurer entre /28 et /16. Chez Scaleway, la documentation de création d'un réseau privé indique que les deux premières et les deux dernières adresses du bloc ne sont pas disponibles, et que la taille va de /20 à /28 ; elle exclut aussi plusieurs plages, dont 100.64.0.0/10 et 169.254.0.0/16.
Note
Les leçons de ce cours donnent à la passerelle du réseau privé de Signalements l'adresse 172.16.20.1, par convention et pour la lisibilité des exemples. Chez Scaleway, cette adresse fait partie de celles que le bloc ne met pas à disposition, et l'adresse réelle d'une passerelle publique est attribuée par le gestionnaire d'adresses (IPAM). Sur une vraie infrastructure, lisez-la (ip route sur l'instance, ou l'API) plutôt que de la supposer.
Tenez un registre, et faites-le respecter. À l'échelle d'une organisation, le plan d'adressage devient un document de référence : quelles plages pour quels environnements, quels sites, quels clients. Les outils d'IPAM (NetBox est très répandu, et les fournisseurs cloud ont les leurs) gardent ce registre et refusent les allocations qui se chevauchent. Les outils d'infrastructure as code peuvent le lire au lieu de recopier des plages à la main.
Prévoyez l'interconnexion dès le départ. Les réseaux qui seront un jour reliés (VPC de production et de préproduction, cloud et réseau d'entreprise, clusters Kubernetes avec leurs réseaux de pods et de services) doivent recevoir des plages disjointes dès leur création. C'est presque gratuit au début et très cher ensuite.
Kubernetes consomme beaucoup d'adresses. Un cluster a au moins trois plages : celle des nœuds, celle des pods (souvent un /16 découpé en un /24 par nœud) et celle des services. Elles s'ajoutent au plan d'adressage, et doivent éviter les plages des VPN des personnes qui administrent le cluster. Le cours Kubernetes : réseau et exposition y revient.
Et IPv6 ? Avec 2⁶⁴ adresses dans chaque sous-réseau standard, la pénurie disparaît, mais pas le besoin d'un plan : on découpe des préfixes, on les agrège, on évite les chevauchements de la même façon. La leçon 8 en donne les règles.
Exercices
1. Le nombre magique (niveau 100). Pour chaque adresse, donnez le réseau, la première et la dernière adresse utilisables, et l'adresse de diffusion : (a) 172.16.20.200/27 ; (b) 10.8.13.7/20 ; (c) 192.168.1.130/25.
Solution
(a) /27 : 4e octet, masque 224, pas de 32. Les blocs commencent à 192 et 224 ; 200 est dans le bloc 192. Réseau 172.16.20.192, utilisables .193 à .222, diffusion .223.
(b) /20 : 3e octet, masque 240, pas de 16. Les blocs du 3e octet commencent à 0 et 16 ; 13 est dans le bloc 0. Réseau 10.8.0.0, utilisables 10.8.0.1 à 10.8.15.254, diffusion 10.8.15.255.
(c) /25 : 4e octet, masque 128, pas de 128. 130 est dans le bloc 128. Réseau 192.168.1.128, utilisables .129 à .254, diffusion .255.
Vérification : ipaddress.ip_interface("172.16.20.200/27").network, puis .broadcast_address.
2. Découper (niveau 100). Combien de sous-réseaux /27 contient 172.16.22.0/24 ? Donnez les trois premiers et le dernier.
Solution
27 − 24 = 3 bits empruntés, soit 2³ = 8 sous-réseaux de 32 adresses : 172.16.22.0/27, 172.16.22.32/27, 172.16.22.64/27... jusqu'à 172.16.22.224/27.
3. Regrouper (niveau 200). Peut-on résumer chacune de ces listes par un seul préfixe ? Si oui, lequel ? (a) 10.1.4.0/24, 10.1.5.0/24, 10.1.6.0/24, 10.1.7.0/24 ; (b) 10.1.5.0/24, 10.1.6.0/24 ; (c) 172.16.20.0/23, 172.16.22.0/24.
Solution
(a) Oui : 10.1.4.0/22. Quatre /24 contigus, et 4 est un multiple de 4 : le bloc est aligné.
(b) Non. Ils sont contigus, mais un /23 commence sur un 3e octet pair : 10.1.4.0/23 couvrirait 4 et 5, 10.1.6.0/23 couvrirait 6 et 7. Il faut deux préfixes ; un /22 (10.1.4.0/22) les couvrirait, mais il inclurait aussi 4 et 7, ce qui est faux si ces blocs appartiennent à quelqu'un d'autre.
(c) Non. Un /22 couvrirait 172.16.20.0 à 172.16.23.255, donc aussi 172.16.23.0/24. collapse_addresses rend deux préfixes.
4. Chevauchements (niveau 200). Une développeuse travaille depuis chez elle (box en 192.168.1.0/24), avec Docker (réseaux en 172.17.0.0/16 et 172.18.0.0/16), et se connecte au VPN de Lyneko, qui pousse des routes vers 10.20.0.0/16 et 172.16.0.0/12. Quel est le problème, et quelle correction proposez-vous côté VPN ?
Solution
172.16.0.0/12 chevauche les deux réseaux Docker. Pour une destination en 172.17.0.5, le poste a deux routes : 172.17.0.0/16 (Docker) et 172.16.0.0/12 (VPN). Le préfixe le plus long gagne : le trafic reste chez Docker, et toute machine distante dans 172.17.0.0/16 ou 172.18.0.0/16 est injoignable par le VPN. À l'inverse, des conteneurs créés plus tard pourraient recevoir des plages qui masquent des réseaux distants. Correction : le VPN ne doit pousser que les plages réellement utilisées (172.16.20.0/22, par exemple), pas toute la plage privée. On peut aussi régler default-address-pools de Docker sur le poste, mais la correction durable est côté VPN.
5. Un plan d'adressage (niveau 200). Lyneko héberge trois clients sur Scaleway et veut, pour chacun, un réseau de production et un réseau de préproduction de 500 machines au plus chacun, plus un réseau d'administration commun de 50 machines. Proposez un plan dans 172.16.0.0/16, qui laisse chaque réseau doubler de taille sans renuméroter. Tenez compte des tailles autorisées par Scaleway.
Solution
500 machines plus les quatre adresses indisponibles chez Scaleway : il faut un /23 (510 adresses utilisables dans un réseau classique, 508 chez Scaleway). Pour pouvoir le doubler, on réserve un /22 par réseau et on n'en utilise que la première moitié. Une proposition :
| Bloc réservé | Réseau créé | Usage |
|---|---|---|
172.16.0.0/22 | 172.16.0.0/23 | client A, production |
172.16.4.0/22 | 172.16.4.0/23 | client A, préproduction |
172.16.8.0/22 | 172.16.8.0/23 | client B, production |
172.16.12.0/22 | 172.16.12.0/23 | client B, préproduction |
172.16.16.0/22 | 172.16.16.0/23 | client C, production |
172.16.20.0/22 | 172.16.20.0/23 | client C, préproduction |
172.16.252.0/24 | 172.16.252.0/26 | administration commune |
Chaque /23 peut devenir un /22 sans toucher aux voisins. Le réseau d'administration est rangé loin, à la fin de la plage, et peut grandir jusqu'au /24. Le /22 est dans les tailles permises par Scaleway (de /20 à /28). Le reste de 172.16.0.0/16 reste libre pour d'autres clients. On peut discuter de l'emplacement de l'administration ; l'essentiel est que chaque choix soit écrit dans le registre.
6. Vérifier avec Python (niveau 200). Écrivez une fonction conflits(registre) qui reçoit une liste de préfixes et renvoie toutes les paires qui se chevauchent. Testez-la sur ["172.16.20.0/22", "172.16.22.0/24", "10.0.0.0/8", "10.20.0.0/16", "192.168.1.0/24"].
Solution
import ipaddress
from itertools import combinations
def conflits(registre):
reseaux = [ipaddress.ip_network(p) for p in registre]
return [(str(a), str(b)) for a, b in combinations(reseaux, 2) if a.overlaps(b)]
print(conflits(["172.16.20.0/22", "172.16.22.0/24", "10.0.0.0/8",
"10.20.0.0/16", "192.168.1.0/24"]))Deux conflits : 172.16.20.0/22 contient 172.16.22.0/24, et 10.0.0.0/8 contient 10.20.0.0/16. Le second est peut-être voulu (un sous-réseau d'un bloc d'organisation) : un vrai registre distingue les blocs parents des allocations, et ne signale que les chevauchements entre allocations.
Récapitulatif
- Découper, c'est allonger le préfixe : chaque bit emprunté double le nombre de sous-réseaux et divise leur taille par deux. Regrouper, c'est le raccourcir, à condition que les blocs soient contigus et alignés.
- Le nombre magique (256 moins le masque dans l'octet concerné) donne le pas entre sous-réseaux ; le binaire tranche en cas de doute.
- Le VLSM donne à chaque usage sa taille ; on alloue du plus grand au plus petit, et l'on garde de la marge à côté de chaque bloc.
- Plages privées de la RFC 1918 :
10.0.0.0/8,172.16.0.0/12(jusqu'à172.31.255.255),192.168.0.0/16.100.64.0.0/10est réservé aux opérateurs. - Les chevauchements (box, Docker, VPN, autres VPC) ne posent problème qu'au moment où l'on relie les réseaux, et c'est alors le préfixe le plus long qui gagne. Un registre des plages les évite.
- Les fournisseurs cloud se réservent des adresses dans chaque sous-réseau (cinq chez AWS, quatre chez Scaleway) et imposent des tailles minimales et maximales.
- Le module Python
ipaddress(subnets,supernet,collapse_addresses,address_exclude,overlaps) fait tous ces calculs sans erreur.
Pour aller plus loin
- La RFC 4632, qui explique pourquoi le CIDR a été adopté et comment l'agrégation garde Internet routable.
- La RFC 1918, courte, dont la section sur les avantages et les inconvénients des adresses privées reste d'actualité.
- La documentation du module
ipaddressde Python, qui couvre aussi IPv6 avec la même interface. - La leçon suivante, qui montre comment le noyau choisit, parmi tous ces préfixes, le chemin d'un paquet.
Sources
- RFC 4632, Classless Inter-domain Routing (CIDR): The Internet Address Assignment and Aggregation Plan
- RFC 1918, Address Allocation for Private Internets
- RFC 6598, IANA-Reserved IPv4 Prefix for Shared Address Space
- RFC 3021, Using 31-Bit Prefixes on IPv4 Point-to-Point Links
- RFC 5737, IPv4 Address Blocks Reserved for Documentation
- Python, documentation du module ipaddress
- AWS, Amazon VPC : Subnet CIDR blocks (adresses réservées)
- Scaleway, créer un réseau privé (taille du bloc et adresses indisponibles)
- Scaleway, plages réservées des réseaux privés
- Docker, documentation : Networking overview (default-address-pools)