Corrigé bac NSI 2025 Métropole jour 1 — Exercice 3 : Réseau CaféNet : adressage IPv4, routage RIP et OSPF, table de routage en ABR
Sujet officiel du baccalauréat, spécialité numérique et sciences informatiques, session 2025. Corrigé rédigé par Ibrahim Alame.
Travailler ce sujet sur Adloun Sujet officiel (PDF) Corrigé complet (PDF)
Énoncé
Cet exercice porte sur l'architecture matérielle (réseau), les arbres binaires de recherche et la programmation Python.
L'entreprise CaféNet possède plusieurs cafés répartis dans différentes villes. Le réseau de la chaîne de cafés est représenté en Figure 1.
Sur le schéma sont représentés 4 routeurs, le réseau du siège social, le réseau du café 1, le réseau du café 2. Dans les réseaux du café 1 et du café 2, des bornes de commandes sont connectées à des switchs (ce sont des boitiers de connexion qui n'ont pas eux-mêmes d'adresse IP). Les 4 routeurs représentés sont composés d'au moins 3 interfaces réseau capable de relier des réseaux ensemble. Chaque interface possède donc une adresse IPV4 sur le réseau auquel elle est reliée.
Les masques des sous-réseaux sont tous 255.255.255.0. Avec ce masque, les trois premiers octets des adresses IP codent l'adresse réseau. Le dernier octet, c'est-à-dire les 8 derniers bits, code l'adresse des machines à l'intérieur de chaque sous-réseau.
Partie A
Le gérant veut faire installer une troisième borne de commande dans le café 1.
1. Indiquer les deux seules adresses IP valides pour cette nouvelle borne, parmi les quatre adresses IP proposées.
| (a) `192.168.20.2` | (c) `192.168.20.261` |
|---|---|
| (b) `192.168.20.157` | (d) `192.168.24.10` |
L'adresse de diffusion, appelée aussi adresse de broadcast, est la dernière adresse disponible à l'intérieur d'un réseau local.
2. Déterminer l'adresse de diffusion du réseau du café 1.
3. Déterminer combien de machines informatiques il est encore possible de connecter au réseau du café 1 après l'installation de la troisième borne de commande.
Le réseau local du café 1 n'a pas besoin de plus de 8 adresses IP différentes. Ce décompte d'adresses IP inclut les adresses IP réservées (à savoir l'adresse de diffusion et l'adresse du réseau). Il est rappelé que la longueur du masque de sous-réseau est actuellement de 24 bits (c'est-à-dire 3 octets).
4. Expliquer quelle est la longueur maximale du masque de sous-réseau que l'on pourrait choisir pour le réseau local du café 1.
Partie B
RIP (Routing Information Protocol) est un protocole de routage utilisé dans les réseaux IP. Il est conçu pour réduire le nombre de sauts entre deux réseaux. Un « saut » correspond au transfert des données d'un routeur à un autre. Le protocole RIP utilise le nombre de sauts comme critère principal pour évaluer le coût d'un chemin. Autrement dit, il considère que le chemin le plus optimal est celui qui traverse le moins de routeurs.
La table de routage du routeur 2 de la Figure 1 est représentée ci-dessous :
Routeur 2
| Réseau destination | Interface de sortie | Prochain routeur | Nombre de sauts |
|---|---|---|---|
| 192.168.20.0 | 192.168.20.1 | aucun | 0 |
| 172.16.3.0 | 172.16.3.1 | aucun | 0 |
| 172.16.4.0 | 172.16.4.1 | aucun | 0 |
| 192.168.10.0 | 172.16.3.1 | 172.16.3.2 | 2 |
| 172.16.0.0 | 172.16.4.1 | 172.16.4.2 | 1 |
| 172.16.2.0 | 172.16.4.1 | 172.16.4.2 | 1 |
| 192.168.30.0 | … | … | … |
| 172.16.1.0 | … | … | … |
5. Recopier et compléter les deux dernières lignes de la table de routage du routeur 2.
La table de routage du routeur 2 contient un réseau de destination pour lequel deux routes différentes sont possibles. La ligne correspondante dans la table de routage aurait donc pu être remplie différemment tout en respectant le protocole RIP.
6. Identifier, dans la table de routage du routeur 2, le réseau de destination que l'on peut atteindre d'une autre façon et indiquer comment cette ligne de la table de routage pourrait être modifiée.
Une adresse IP qui n'est pas référencée dans la table de routage doit être routée par défaut vers Internet.
7. Recopier et compléter la ligne à ajouter à la table de routage du routeur 2.
| Réseau destination | Interface de sortie | Prochain routeur |
|---|---|---|
| autre | … | … |
Partie C
OSPF est également un protocole d'échanges de données entre les routeurs qui prend en compte le coût des routes. Le coût est lié au débit des liaisons entre les routeurs par la formule suivante :
8. Recopier et compléter la dernière colonne du tableau ci-dessous :
Tableau des coûts
| Type de connexion | Débit en | coût |
|---|---|---|
| Ethernet | 100 | |
| Fast Ethernet | … | |
| Fibre optique | … |
Le schéma ci-dessous met en évidence les types de connexion qui relient les routeurs.
9. Déterminer la route dont le coût est minimal pour aller du routeur 1 jusqu'au routeur 4 et calculer son coût au sens du protocole OSPF.
Partie D
Le but de cette partie est de classer les adresses IP des différents réseaux afin de faciliter leur recherche.
La fonction ip_bin prend en argument une chaîne de caractères décrivant une adresse IP en notation décimale, et renvoie une chaîne de caractères, de longueur 35 (32 bits et les 3 points), décrivant l'adresse IP en notation binaire. Exemple :
>>> ip_bin('192.168.10.1')
'11000000.10101000.00001010.00000001'
10. Donner la chaîne de caractères renvoyée par ip_bin('192.168.20.12').
La fonction precede prend en paramètres deux adresses IP en notation binaire, sous forme de chaînes de caractères identiques à celles renvoyées par la fonction ip_bin. La fonction precede renvoie un booléen qui vaut True si la première adresse IP en paramètre précède la seconde adresse IP. Exemple :
>>> a = '11000000.10101000.00001010.00000001'
>>> b = '11000000.10101000.00001111.00000001'
>>> precede(a, b)
True
L'algorithme compare bit à bit les deux chaînes binaires, en lisant les chaînes de caractères dans le sens usuel (de gauche à droite). Dans l'exemple ci-dessus, tous les caractères sont identiques jusqu'au sixième caractère du troisième octet. Comme le bit de l'adresse a est inférieur à celui de l'adresse b, on en déduit que l'adresse IP a précède l'adresse IP b.
Si la première adresse IP ne précède pas la seconde, la fonction doit renvoyer False. L'algorithme de comparaison est traduit dans le langage Python sous la forme suivante :
def precede(ip_1, ip_2):
for i in range(35):
if ip_1[i] < ip_2[i]:
return ...
elif ip_1[i] > ip_2[i]:
return ...
return ...
11. Expliquer dans quel cas la fonction precede exécutera la dernière instruction return de la ligne 7.
12. Recopier et compléter les lignes 4, 6 et 7 du code de la fonction precede.
Les tables de routage de chaque routeur sont implémentées sous la forme d'arbre binaire de recherche avec la classe Abr.
class Abr:
def __init__(self, adresse_ip,
interface, passerelle,
cout):
self.adresse_ip = adresse_ip
self.interface = interface
self.passerelle = passerelle
self.cout = cout
if adresse_ip != '':
self.gauche = Abr('','','',0)
self.droite = Abr('','','',0)
def est_vide(self):
return ...
Dans cette représentation :
adresse_ipdésigne l'adresse IP de la destination ;interfacedésigne l'interface réseau ;passerelledésigne l'adresse IP du prochain routeur ;coutdésigne le nombre de sauts pour atteindre la destination ;- par convention, l'arbre binaire vide est une instance de
Abrpour laquelleadresse_ipest une chaîne de caractères vide ; - un arbre binaire de recherche non vide possède nécessairement un sous-arbre gauche et un sous-arbre droit, éventuellement vides, qui sont tous les deux des arbres binaires de recherche. Ces sous-arbres sont désignés par
gaucheetdroitedans la classeAbr; - si elle n'est pas vide, l'adresse IP du sous-arbre gauche précède l'adresse IP de l'instance parent ;
- si le sous-arbre droit n'est pas vide, alors l'adresse IP de l'instance parent précède l'adresse IP du sous-arbre droit.
13. Citer un attribut et citer une méthode de la classe Abr.
14. Recopier et compléter la ligne 14 du code de la classe Abr.
15. Justifier, en mobilisant des connaissances de cours, l'intérêt qu'il peut y avoir à représenter la table de routage par un arbre binaire de recherche.
La section de code qui définit modifie est incluse dans la classe Abr.
def modifie(self, adresse_ip,
interface, passerelle,
cout):
if self.est_vide():
self.adresse_ip = adresse_ip
self.interface = interface
self.passerelle = passerelle
self.cout = cout
self.gauche = Abr('','','',0)
self.droite = Abr('','','',0)
else:
self.adresse_ip = adresse_ip
self.interface = interface
self.passerelle = passerelle
self.cout = cout
Les lignes 20 à 23 sont exactement les mêmes que les lignes 27 à 30.
16. Réécrire le code de la fonction modifie en évitant cette répétition.
La classe Abr est complétée afin de permettre l'ajout de nouvelles lignes à la table de routage, tout en conservant les propriétés que doit posséder un arbre binaire de recherche.
def rechercher(self, adresse_ip):
if self.est_vide() or adresse_ip==self.adresse_ip:
return self
elif precede(...):
return self.gauche.rechercher(adresse_ip)
else:
return self.droite.rechercher(adresse_ip)
def inserer(self, adresse_ip,
interface, passerelle,
cout):
destination = self.rechercher(adresse_ip)
destination.modifie(adresse_ip,
interface, passerelle,
cout)
On rappelle que la fonction precede prend en arguments des adresses IP écrites sous forme binaire.
17. Recopier et compléter la ligne 35 du code de la fonction rechercher.
Corrigé
Partie A
1. Le réseau du café 1 est le réseau 192.168.20.0 de masque 255.255.255.0 : les trois premiers octets 192.168.20 sont imposés à toute machine du réseau, et seul le dernier octet, codé sur 8 bits, distingue les machines.
- [–] (a)
192.168.20.2: valide. Elle appartient bien au réseau du café 1, son dernier octet est compris entre 1 et 254, et elle est encore libre (le routeur 2 occupe.1, les deux bornes existantes.10et.11). - [–] (b)
192.168.20.157: valide, pour les mêmes raisons. - [–] (c)
192.168.20.261: impossible. Un octet est codé sur 8 bits, donc compris entre 0 et : 261 ne s'écrit pas sur un octet. - [–] (d)
192.168.24.10: le troisième octet vaut 24 et non 20. Cette adresse appartient à un autre réseau ; la borne ne pourrait pas dialoguer avec les machines du café 1 sans passer par un routeur.
Les deux adresses valides sont donc (a) et (b).
2. L'adresse de diffusion est la dernière adresse du réseau local, c'est-à-dire celle dont tous les bits de la partie machine valent 1 : le dernier octet vaut . L'adresse de diffusion du café 1 est 192.168.20.255.
3. Le dernier octet offre combinaisons, mais deux sont réservées : 192.168.20.0 (adresse du réseau) et 192.168.20.255 (adresse de diffusion). Il reste adresses attribuables. Sont déjà attribuées : 192.168.20.1 (interface du routeur 2), 192.168.20.10 et 192.168.20.11 (les deux bornes), plus la nouvelle borne, soit 4 adresses. Les switchs, eux, n'ont pas d'adresse IP et ne comptent pas. On peut donc encore connecter machines.
4. Il faut que le réseau contienne au moins 8 adresses, adresse du réseau et adresse de diffusion comprises. Or : il faut au moins 3 bits pour la partie machine, donc au plus bits pour le masque. La longueur maximale du masque est 29 bits, soit 255.255.255.248 en notation décimale. Un masque de 30 bits ne laisserait que adresses, ce qui est insuffisant. En passant de 24 à 29 bits, on libère les autres adresses pour d'autres sous-réseaux.
Partie B
5. On raisonne à partir de la Figure 1, en comptant les transferts de routeur à routeur.
| Réseau destination | Interface de sortie | Prochain routeur | Nombre de sauts |
|---|---|---|---|
| 192.168.30.0 | 172.16.4.1 | 172.16.4.2 | 1 |
| 172.16.1.0 | 172.16.3.1 | 172.16.3.2 | 1 |
192.168.30.0 est le réseau du café 2, relié au routeur 3 : depuis le routeur 2, on sort par l'interface 172.16.4.1 vers le routeur 3 (172.16.4.2), soit 1 saut. L'autre chemin, par le routeur 1 puis le routeur 3, coûterait 2 sauts : RIP retient le plus court.
172.16.1.0 est le réseau qui relie le routeur 4 au routeur 1 : le routeur 1 y possède l'interface 172.16.1.2, il suffit donc de l'atteindre. On sort par 172.16.3.1 vers le routeur 1 (172.16.3.2), soit 1 saut ; en passant par le routeur 3 puis le routeur 4, il en faudrait 2.
6. La réponse attendue est le réseau 192.168.10.0 (le siège social, relié au routeur 4) : il est atteignable de deux façons de même coût : par le routeur 1 puis le routeur 4 (2 sauts, comme l'indique la table), ou par le routeur 3 puis le routeur 4 (2 sauts également). La ligne pourrait donc s'écrire :
| Réseau destination | Interface de sortie | Prochain routeur | Nombre de sauts |
|---|---|---|---|
| 192.168.10.0 | 172.16.4.1 | 172.16.4.2 | 2 |
Ce que le correcteur attend : le nombre de sauts, lui, ne change pas (les deux routes ont le même coût au sens de RIP) ; seuls l'interface de sortie et le prochain routeur changent. Honnêteté du corrigé : le réseau 172.16.0.0, qui relie les routeurs 1 et 3, est en réalité dans la même situation : il est à 1 saut par le routeur 3 (172.16.4.1 / 172.16.4.2, comme dans la table) comme par le routeur 1 (172.16.3.1 / 172.16.3.2) ; l'énoncé n'en attend qu'un, et 192.168.10.0 est celui dont les deux routes empruntent des chemins vraiment distincts. Une copie qui cite 172.16.0.0 en le justifiant ne dit rien de faux. Ce sont les deux cycles du graphe des routeurs qui créent cette ambiguïté ; RIP ne la tranche pas, le routeur conserve la première route apprise.
7. Internet est relié au routeur 1, dont l'interface porte l'adresse 203.0.113.1. Depuis le routeur 2, tout paquet dont la destination n'est pas dans la table doit donc partir vers le routeur 1 :
| Réseau destination | Interface de sortie | Prochain routeur |
|---|---|---|
| autre | 172.16.3.1 | 172.16.3.2 |
L'interface de sortie est celle du routeur 2 sur cette liaison, et le prochain routeur est l'adresse de l'interface du routeur 1 sur la même liaison. Cette ligne, la route par défaut, est examinée en dernier : elle ne sert que si aucune autre ne correspond.
Partie C
8. On applique :
| Type de connexion | Débit | coût |
|---|---|---|
| Ethernet | ||
| Fast Ethernet | ||
| Fibre optique |
Le coût de Fast Ethernet vaut 10, celui de la fibre optique vaut 1. Plus le débit est grand, plus le coût est petit : OSPF préfère les liaisons rapides.
9. La Figure 2 donne le type de chaque liaison, donc son coût : routeur 4 – routeur 3 en fibre (coût 1) ; routeur 4 – routeur 1 en Ethernet (100) ; routeur 1 – routeur 3 en Ethernet (100) ; routeur 1 – routeur 2 en Fast Ethernet (10) ; routeur 3 – routeur 2 en Fast Ethernet (10). On énumère les chemins du routeur 1 au routeur 4 :
| Chemin | Coût |
|---|---|
La route de coût minimal est routeur 1 routeur 2 routeur 3 routeur 4, de coût 21.
Ce que le correcteur attend : la route la plus courte en nombre de sauts (la liaison directe, 1 saut) n'est pas la moins coûteuse au sens d'OSPF. Traverser trois liaisons rapides coûte 21, quand une seule liaison Ethernet lente coûte 100. C'est toute la différence entre RIP, qui compte les routeurs traversés, et OSPF, qui tient compte du débit. La Figure 2 échange par ailleurs les étiquettes des deux cafés par rapport à la Figure 1 ; cela ne change rien au calcul, qui ne porte que sur les liaisons entre routeurs.
Partie D
10. On convertit chaque octet en binaire sur 8 bits : , , , .
>>> ip_bin('192.168.20.12')
'11000000.10101000.00010100.00001100'
La chaîne compte bien 35 caractères : 32 chiffres binaires et 3 points.
11. La boucle for examine les 35 caractères. Le premier caractère où les deux chaînes diffèrent déclenche immédiatement un return (ligne 4 si ip_1[i] est le plus petit, ligne 6 sinon) et la fonction s'arrête. La ligne 7 n'est donc atteinte que si la boucle est allée jusqu'au bout sans jamais trouver de différence : les deux chaînes sont identiques, c'est-à-dire que les deux paramètres désignent la même adresse IP. Les points occupent les mêmes positions dans les deux chaînes et ne peuvent jamais créer d'écart.
12. Une adresse ne se précède pas elle-même : le cas de la ligne 7 doit donc renvoyer False, comme le cas où la première adresse est la plus grande.
def precede(ip_1, ip_2):
for i in range(35):
if ip_1[i] < ip_2[i]:
return True
elif ip_1[i] > ip_2[i]:
return False
return False
Vérification sur l'exemple du sujet : avec a et b, les 23 premiers caractères coïncident ; au vingt-quatrième (le sixième bit du troisième octet) on a a[23] = '0' et b[23] = '1', donc '0' < '1' et la fonction renvoie True. Elle renvoie False pour precede(b, a) et pour precede(a, a). La comparaison < porte ici sur des caractères : elle compare leurs codes, et '0' < '1', ce qui donne bien l'ordre des bits.
13. Un attribut : adresse_ip (on accepte aussi interface, passerelle, cout, gauche, droite). Une méthode : est_vide (on accepte aussi __init__, modifie, rechercher, inserer). Un attribut est une donnée portée par chaque instance, accessible par self ; une méthode est une fonction définie dans la classe, dont le premier paramètre est self.
14. Par convention, l'arbre est vide lorsque son adresse IP est la chaîne vide :
def est_vide(self):
return self.adresse_ip == ''
On renvoie directement le booléen de la comparaison ; attention à l'opérateur de comparaison == et non à l'affectation =.
15. Une table de routage est consultée à chaque paquet transmis : la vitesse de recherche est décisive. Rangée dans une liste, la table impose une recherche séquentielle, donc comparaisons dans le pire des cas pour lignes : un coût linéaire. Dans un arbre binaire de recherche, chaque comparaison avec la racine élimine d'un coup tout un sous-arbre : on descend d'un niveau à chaque étape, et le nombre de comparaisons est majoré par la hauteur de l'arbre. Si l'arbre est équilibré, cette hauteur est de l'ordre de : le coût est logarithmique. Pour une table de 1 000 lignes, cela fait une dizaine de comparaisons au lieu d'un millier. De plus, le parcours infixe de l'arbre rend les adresses déjà triées, et l'insertion d'une nouvelle ligne ne demande aucun décalage. Réserve à signaler : l'avantage disparaît si l'arbre dégénère en peigne (adresses insérées déjà triées) : la recherche redevient linéaire.
16. Les quatre affectations sont communes aux deux cas : on les sort du test. Seule la création des deux sous-arbres vides est propre au cas où le nœud était vide. Il faut donc mémoriser la réponse de est_vide() avant de modifier adresse_ip :
def modifie(self, adresse_ip,
interface, passerelle,
cout):
etait_vide = self.est_vide()
self.adresse_ip = adresse_ip
self.interface = interface
self.passerelle = passerelle
self.cout = cout
if etait_vide:
self.gauche = Abr('','','',0)
self.droite = Abr('','','',0)
Ce que le correcteur attend : si l'on garde if self.est_vide(): après les affectations, le test est toujours faux, puisque self.adresse_ip vient de recevoir une adresse non vide : les sous-arbres ne sont jamais créés et l'insertion suivante échoue sur AttributeError: 'Abr' object has no attribute 'gauche'. C'est le piège de la question.
17. L'arbre est ordonné par la relation precede, qui attend des adresses binaires : il faut donc convertir les deux adresses avec ip_bin avant de les comparer. Si l'adresse cherchée précède celle du nœud, elle ne peut se trouver que dans le sous-arbre gauche :
def rechercher(self, adresse_ip):
if self.est_vide() or adresse_ip==self.adresse_ip:
return self
elif precede(ip_bin(adresse_ip), ip_bin(self.adresse_ip)):
return self.gauche.rechercher(adresse_ip)
else:
return self.droite.rechercher(adresse_ip)
Le cas d'arrêt de cette fonction récursive est double : ou bien l'adresse est trouvée, ou bien on aboutit à un arbre vide, qui est précisément l'emplacement où inserer viendra écrire la nouvelle ligne par un appel à modifie.
Vérification : en insérant dans un arbre vide les huit lignes de la table du routeur 2 (avec les deux lignes complétées à la question 5), le parcours infixe rend les adresses dans l'ordre croissant, 172.16.0.0, 172.16.1.0, 172.16.2.0, 172.16.3.0, 172.16.4.0, 192.168.10.0, 192.168.20.0, 192.168.30.0 : la propriété de l'arbre binaire de recherche est bien respectée. Un inserer portant sur une adresse déjà présente met la ligne à jour sans créer de doublon, puisque rechercher retourne le nœud existant.