Choisir la configuration réseau au démarrage

Lorsque l'on dispose d'un portable que l'on promène par monts et par vaux, il peut être bien pratique de choisir son environnement réseau au démarrage de la machine. On n'a alors plus besoin d'activer/désactiver certaines interfaces réseau ni de les configurer une fois l'initialisation de la machine terminée. Ce document propose une méthode simple permettant d'atteindre cet objectif, basée sur le choix d'un réseau dans me menu de démarrage, une configuration du fichier /etc/network/interfaces et un script de «mapping».

Utilisation d'un paramètre au lancement du noyau

Depuis longtemps déjà, il est possible de spécifier des arguments à transmettre au noyau au démarrage de celui-ci. Parmi les plus connus citons root=/dev/XXXX pour spécifier la partition racine du système, ou vga=XYZ pour déterminer le mode graphique lors de la phase de démarrage.

Sur le système en fonctionnement, l'ensemble des paramètres transmis au noyau en fonctionnement est consigné dans le fichier /proc/cmdline. Nous allons utiliser ce moyen pour préciser quel est l'environnement réseau que nous souhaitons activer. On ajoutera par exemple une directive du type :

  net=home-wifi
ou
  net=work-wired

à la liste des paramètres déjà présents.

Configuration des réseaux logiques

Au démarrage de la machine, le contenu du fichier /etc/network/interfaces détermine quelles sont les interfaces physiques qui vont être activées, et de quelle manière (automatique, manuelle avec spécification de l'adresse IP…). À chaque choix de réseau logique accessible dans le menu de démarrage nous allons faire correspondre une configuration particulière d'interface physique grâce à ce fichier /etc/network/interfaces.

Récupération du paramètre lors de la configuration des interfaces réseau

Il ne nous reste plus qu'à récupérer, grâce à un script qui sera exécuté à l'intérieur de /etc/network/interfaces, la valeur de paramètre définissant le réseau logique choisi. Sachant que l'ensemble des paramètres passés au noyau est disponible dans le fichier /proc/cmdline ; le script en question se contentera d'aller extraire la valeur de la chaîne de caractères qui suit la directive net= et de remonter cette information aux instructions suivantes dans /etc/network/interfaces.

Modification du menu de démarrage

FIXME ce qui suit n'est plus d'actualité sur les version récentes d'Ubuntu qui utilisent grub-pc. Le menu de démarrage est décrit dans le fichier /boot/grub/menu.lst (le fonctionnement détaillé de grub est spécifié dans ce tutoriel). Chacune des entrées est représentée par un bloc dont la première ligne commence par le mot-clé title et dont la dernière comporte le mot-clé boot. En règle générale, on choisit toujours la même entrée (ou l'entrée par défaut) pour démarrer la machine. Sur mon système p. ex. le bloc correspondant est :

title           Ubuntu, kernel 2.6.12-10-386
root            (hd0,4)
kernel          /boot/vmlinuz-2.6.12-10-386 root=/dev/sda5 ro vga=771 quiet splash
initrd          /boot/initrd.img-2.6.12-10-386
savedefault
boot

Afin de pouvoir choisir son réseau au démarrage, on va dupliquer ce bloc autant de fois qu'il y a de configurations réseau souhaitées. Dans mon cas, il y en a quatre : un mode «non-connecté» où aucune interface ne doit être activée que j'appellerai Standalone, un deuxième mode adapté à mon réseau domestique sans fil (Home Wifi) où seule l'interface WiFi doit être configurée, un troisième mode (Work WiFi) où je suis connecté au réseau d'entreprise par une borne WiFi, et enfin un dernier mode (Work Wired) utilisant un bon vieux câble Ethernet au cas où la borne WiFi de mon entreprise serait défaillante ;-).

Seules les lignes title et kernel doivent être modifiées :

  • title pour adapter le label qui sera proposé au démarrage,
  • kernel pour ajouter le paramètre noyau spécifique au réseau.

En remplacement du bloc précédent, mon /boot/grub/menu.lst contiendra donc les quatre blocs ci-dessous :

title           Ubuntu, kernel 2.6.12-10-386 Standalone
root            (hd0,4)
kernel          /boot/vmlinuz-2.6.12-10-386 root=/dev/sda5 ro vga=771 quiet splash
initrd          /boot/initrd.img-2.6.12-10-386
savedefault
boot
title           Ubuntu, kernel 2.6.12-10-386 Home WiFi
root            (hd0,4)
kernel          /boot/vmlinuz-2.6.12-10-386 root=/dev/sda5 ro vga=771 quiet splash net=home-wifi
initrd          /boot/initrd.img-2.6.12-10-386
savedefault
boot
title           Ubuntu, kernel 2.6.12-10-386 Work WiFi
root            (hd0,4)
kernel          /boot/vmlinuz-2.6.12-10-386 root=/dev/sda5 ro vga=771 quiet splash net=work-wifi
initrd          /boot/initrd.img-2.6.12-10-386
savedefault
boot
title           Ubuntu, kernel 2.6.12-10-386 Work Wired
root            (hd0,4)
kernel          /boot/vmlinuz-2.6.12-10-386 root=/dev/sda5 ro vga=771 quiet splash net=work-wired
initrd          /boot/initrd.img-2.6.12-10-386
savedefault
boot

Configuration de ''/etc/network/interfaces''

Le fichier /etc/network/interfaces décrit l'ensemble des opérations à effectuer pour activer les différentes interfaces réseau physiques dont dispose la machine. Sa structure et son mode de fonctionnement pouvant être assez élaborés, je me contenterai ici d'aller à l'essentiel.

En premier lieu, on va demander à ce que toutes nos interfaces physiques subissent les opérations de configuration, quitte à que certaines restent inactives au bout du compte. Ceci s'obtient à l'aide d'un ligne de type :

auto lo eth0 wlan0

(lo est obligatoire, c'est la «boucle locale» ; eth0 et wlan0 sont les interfaces correspondant respectivement à ma carte Ethernet, et à ma carte WiFi).

Comme il faut obligatoirement initialiser la boucle locale, la ligne suivante s'écrit :

iface lo inet loopback

Ensuite, des directives de «mapping» vont faire correspondre à chaque interface physique le nom du réseau tel qu'il a été spécifié en tant que paramètre au démarrage du noyau.

En l'espèce, pour déterminer quelle configuration adopter pour le réseau sans fil, les lignes suivantes sont nécessaires :

mapping wlan0
  script /etc/network/get_net_kernel_param.sh
  map home-wifi wifihome
  map work-wifi wifiwork

Cette déclaration signifie que pour configurer wlan0 il faut appeller le script /etc/network/get_net_kernel_param.sh (auquel nous reviendrons dans la section suivante) qui recevra comme argument le nom de l'adresse physique, ici wlan0, et en entrée standard les autres lignes du bloc mapping desquelles sont enlevées les mots-clés map.

En clair, c'est comme si en ligne de commande, on faisait :

echo -e "home-wifi wifihome\nwork-wifi wifiwork" | /etc/network/get_kernel_param.sh wlan0

Ce script est alors censé afficher sur sa sortie standard un identifiant de configuration figurant dans /etc/network/interfaces. Dans notre cas, si l'on a choisi au démarrage l'entrée correspondant à Home WiFi (et donc le paramètre net=home-wifi, le script devra afficher :

wifihome

Si l'on a choisi l'entrée Work WiFi la sortie du script sera :

wifiwork

J'ajoute donc à /etc/network/interfaces les instructions de configuration effectives pour wifihome et pour wifiwork :

  iface wifihome inet static
       pre-up modprobe ndiswrapper
       address 192.168.0.2
       netmask 255.255.255.0
       gateway 192.168.0.1
       wireless-essid homesweethome
       wireless-key 1234ABCDEF
       post-up echo -e "nameserver 213.228.0.168\nameserver 212.27.63.113" > /etc/resolv.conf
  
  iface wifiwork inet dhcp
       pre-up modprobe ndiswrapper
       wireless-essid workessid
       wireless-key ABCDEF1234

La configuration de wifihome est purement statique. Outre sa propre adresse, j'y spécifie le masque de sous-réseau et la passerelle. Et en fin de configuration, à l'aide de la ligne comportant la commande post-up je crée le fichier /etc/resolv.conf avec les deux serveurs de nom de mon FAI pour avoir un DNS fonctionnel.

La configuration de wifiwork est, quant à elle, entièrement automatique (par dhcp)

Ces deux configurations nécessitent néanmoins que l'on charge préalablement le module ndiswrapper (bah oui, ma carte n'est pas supportée en natif :-(), d'o la ligne contenant la commande pre-up. Dans les deux cas, les identifiants des réseaux sans fil sont également inclus dans la configuration.

Ce qui vaut pour l'interface physique wlan0 est aisément transposable à eth0 dont la configuration se fait donc à l'aide des lignes ci-dessous :

  mapping eth0
       script /etc/network/get_kernel_param.sh
       map work-wired wiredwork
  
  iface wiredwork inet dhcp

Ouf ! Voilà pour le fichier /etc/network/interfaces. Ne reste plus que la dernière étape…

En fait, le comportement erratique de ce module lorsque mon portable fonctionne sur batterie a été l'une des motivations pour mettre au point cette méthode de configuration dynamique du réseau.

Installation du script de «mapping»

Voici script de mapping dont le fonctionnement est décrit dans la section précédente :

  #!/bin/bash
 
  # First argument of script is physical interface.
  IFACE="$1"
 
  # Fetch kernel net= argument given at boot time.
  BOOTNETNAME=$(sed 's/^.*net=\([a-z_A-Z0-9-]*\).*$/\1/' /proc/cmdline)
 
  # Resulting interface to bring up
  RESULTIFACENAME=""
 
  # Read map lines given on stdin.
  while read NETNAME IFACENAME ; do
        if [ "$RESULTIFACENAME" ] ; then
                continue
        fi
        if [ "$NETNAME" = "$BOOTNETNAME" ] ; then
                RESULTIFACENAME=$IFACENAME
        fi
  done
 
  # Output resulting interface name
  if [ "$RESULTIFACENAME" ] ; then
        echo $RESULTIFACENAME
        exit 0
  fi
 
  exit1

Même si les commentaires sont en anglais, sont déroulement ne devrait pas poser de problème de compréhension majeur :

  • le nom de l'interface passé en premier argument est récupéré dans la variable IFACE
  • le nom de la configuration réseau (paramètre noyau) est récupéré dans BOOTNETNAME
  • le nom de l'interface logique à configurer sera stocké dans RESULTIFACENAME
  • une boucle while traite toutes les lignes reçues en entrée et issues des lignes map de /etc/network/interfaces
    • ces lignes contiennent deux mots : le nom d'une configuration réseau (NETNAME) et le nom logique de l'interface correspondante à configurer (IFACENAME)
    • s'il y a correspondance entre le nom de la configuration et celle passée au noyau, on affecte l'interface logique à configurer avec la valeur de IFACENAME
  • enfin, un test final vérifie qu'il y a bien une configuration correspondant à celle demandée (RESULTIFACENAME n'est pas vide) et l'affiche
  • dans le cas contraire un code de retour non-nul est retourné signifiant qu'il ne faut pas configurer l'interface physique donnée en argument du script.

Ce scipt se trouve donc dans le fichier /etc/network/get_net_kernel_param.sh comme indiqué dans /etc/network/interfaces.

Nous sommes donc arrivés au bout de nos peines, et disposons d'un système dont nous pouvons personnaliser à souhait les différents environnements réseau.

Extensions

Pour ceux qui ne se seraient pas encore endormis, il peut être utile d'ajouter d'autres éléments à la configuration dynamique. Par exemple, ma propre configuration ajoute quelques lignes supplémentaire à chaque interface logique dans /etc/network/interfaces de façon à configurer correctement le serveur SMTP sortant. L'astuce est de déclarer ce serveur dans /etc/hosts comme mailhost et de configurer l'ensemble de ses clients de messagerie en indiquant mailhost comme serveur de messagerie sortant.

Voici un exemple de ce que j'ai ajouté au bloc qui configure wifihome :

post-up grep -v mailhost /etc/hosts >> /tmp/hosts
post-up mv /tmp/hosts/ /etc/hosts
post-up echo "212.27.48.4 smtp.free.fr mailhost" >> /etc/hosts

Les deux premières lignes nettoyent /etc/hosts pour en éliminer un éventuel mailhost résiduel, et la dernière y a joute l'adresse du serveur SMTP de mon FAI.

Problème ouvert : Proxy ?

Que faire pour basculer entre :

  • une connexion maison par wifi
  • une connexion travail derrière un PROXY ?

Contributeurs : verrader

  • dyn_network.txt
  • Dernière modification: Le 11/09/2022, 11:51
  • par moths-art