2. PLAN
Introduction à Linux
Le noyau GNU/Linux
Programmation système
La pile réseau
Filtrage & QoS
Développement réseau en userspace
Captures et simulation
Linux embarqué
3. 1. Introduction à Linux
–Qu’est ce que Linux ?
–Linux historique
–Linux versions
–Linux statistiques
–Le projet GNU
–Les licences
4. Qu’est-ce que Linux ?
Linux est le noyau du système d’exploitation GNU/Linux
GNU/Linux est le mariage du noyau Linux et des programmes et utilitaires systèmes
du projet GNU (toolchain, librairies, shells, etc)
–Logiciel libre (Open Source)
Plusieurs organisations (à but lucratif ou non) distribuent le noyau Linux, les
utilitaires GNU, plus d’autres logiciels comme le gestionnaire de bureau Gnome ou
KDE, sous la forme d’un CD ou DVD facile à installer
–On parle alors de distributions Linux
–Exemples :
•Red-Hat
•Slackware
•Fedora
•Ubuntu
•Debian
4
6. Linux – Historique
1991 : Le noyau Linux est écrit à partir de zéro en 6 mois
par Linus Torvalds à l'université d'Helsinki
1991 : Linus distribue son noyau sur Internet.
1992 : Linux est distribué sous la licence GPL
1993 : Plus de 100 développeurs travaillent sur le noyau
1994 : Sortie de Linux 1.0
1994 : Les sociétés Red Hat et Suse publient les versions 1.0
de leur distribution
1996 : Sortie de Linux 2.0
1999 : Sortie de Linux 2.2
2001 : IBM investit 1 milliard de dollars dans Linux
2002 : Sortie de Linux 2.4
2004 : Sortie de Linux 2.6
2011 : Sortie de Linux 3.0
6
7. Linux – Historique (suite)
Premier post
effectué par Linus
Torvald sur Usenet :
Path:
gmdzi!unido!fauern!ira.uka.d
7
8. Linux – Historique (suite)
Nombre de développeurs travaillant sur le noyau :
–1992 : 100
–2010 : > 1000
Nombre de lignes de code dans le noyau :
–1995 : 250 000
–2010 : 14 millions
Top 500 super computers tournant sous Linux :
–1998 : 1
–2011 : 413
2011 : 80% des serveurs HTTP tournent sous Linux
8
19. Projet GNU
GNU est un projet de système d'exploitation composé
exclusivement de logiciels libres
GNU a été initié en 1983 par Richard Stallman à la suite
de son désaccord avec les licences de Berkeley
En 1985, Stallman fonde la Free Software Foundation (FSF)
Le système d'exploitation GNU reprend les concepts
d'Unix, mais son implémentation est indépendante et originale
Le projet GNU avait prévu le développement d’un noyau (Hurd)
L'arrivée du noyau Linux rendit disponibles les logiciels du projet GNU sur
x86 (Torvalds a mis Linux sous licence GPL en 1992 )
L'ensemble des distributions Linux portent l'empreinte du projet GNU (ne
serait-ce que dans leurs licences), d'où l'appellation distribution GNU/Linux
défendue par R. Stallman
19
20. Licences – Logiciels libres
Un logiciel libre est un logiciel qui peut être utilisé, copié, étudié, modifié et
redistribué sans restriction majeure autre que la mise à disposition du code source
Libertés fondamentales selon la FSF :
–Liberté d'exécuter le programme pour tous les usages
–Liberté d’étudier le fonctionnement du programme et de l’adapter (accès au
code source requis)
–La liberté de redistribuer des copies.
–Liberté d’améliorer le programme et de publier les améliorations pour en faire
profiter toute la communauté (accès au code source requis)
Copyleft :
–Opposition à la notion de Copyright
–Conservation du status libre pour un logiciel dérivé
–Garantie de le code libre le restera dans toutes ses modifications
–Impossibilité de distribution d'un logiciel propriétaire incorporant du code sous
licence avec Copyleft
20
21. Licences – General Public License (suite)
La GPL fixe les conditions légales de distribution des logiciels libres du projet GNU
Licence avec Copyleft
La licence GPL requiert que les modifications et les travaux dérivés soient aussi
placés sous licence GPL :
–Ne s’applique qu’aux logiciels distribués (donc pas utilisés en interne, en cours
de développement, en phase de test, etc.)
–Intégrer du code d’un programme GPL dans un autre implique de placer ce
programme sous GPL
–Tout programme utilisant du code GPL (lié statiquement ou dynamiquement)
est considéré comme une extension de ce code et est donc placé sous GPL
GCC a une clause spéciale : il est permis de compiler un programme sans qu’il soit
placé sous GPL
http://www.gnu.org/licenses/gpl-faq.html
21
22. Licences – Lesser General Public License (LGPL)
Licence avec Copyleft
Version limitée, ou amoindrie, de la licence GPL pour permettre à certains
logiciels libres de pénétrer certains domaines n’autorisant pas le choix d’une
publication entièrement libre
La licence LGPL permet d’intégrer une partie de code non modifiée d’un
programme sous LGPL sans contrainte
–Si le code est modifié, alors le programme l’intégrant doit être
redistribué sous LGPL.
Il est autorisé de lier, statiquement ou dynamiquement, un programme avec
une librairie LGPL, sans contrainte de licence ou de distribution de code
source
La LGPL autorise à lier un programme sous cette licence à du code non
LGPL, sans pour autant révoquer la licence
22
23. Licences – Autres licences OSS
MIT ou X11 (Massachusetts Institute of Technology)
–Licence sans Copyleft
–Autorisation donnée à toute personne recevant un logiciel sous licence
MIT/X11 le droit illimité de l'utiliser, le copier, le modifier, le fusionner, le
publier, le distribuer, le vendre et de changer sa licence
–Seule obligation de mettre le nom des auteurs avec la notice de
Copyright
BSD (Berkeley Software Distribution)
–Licence sans Copyleft
–Conditions aujourd'hui identiques à la licence MIT/X11
–Avant 1999, elle contenait une clause publicitaire maintenant disparue.
Il existe une multitude d’autres licences OSS
Toutes les licences OSS ne sont pas compatibles avec la GPL
23
24. Licences – Noyau Linux
Le noyau Linux est exclusivement sous licence GPL version 2
Les modules propriétaires sont tolérés (mais non recommandés) tant qu'ils
ne sont pas considérés comme dérivés de code GPL
Les pilotes propriétaires ne peuvent pas être liés statiquement au noyau
24
25. Linux – Architecture
Le noyau Linux est monolithique (un binaire statique)
–Les pilotes peuvent être compilés comme modules, et chargés ou
déchargés tandis que le système tourne
Les pilotes de périphériques tournent en espace noyau
Le noyau est multithreadé
Le noyau supporte SMP
La plupart des interfaces graphiques sont en espace utilisateur
Scalabilité : tourne sur des super ordinateurs aussi bien que sur des petits
appareils
Conformité aux standards et interopérabilité (POSIX)
Support réseau avec une pile très complète
Sécurité : discretionary access control, extended FS attributes, etc.
Stabilité et fiabilité
25
26. Linux – Architecture (suite)
Il est développé principalement en langage C (pas de langage objet tel que
le C++) avec une légère couche en assembleur
Minimum : processeurs 32 bits, avec ou sans MMU (Memory Management
Unit)
Architectures supportées :
–32 bits : alpha, arm, cris, h8300, i386, m68k, m68knommu, mips, parisc,
ppc, s390, sh, sparc, v850
–64 bits : ia64, mips64, ppc64, sh64, sparc64, x86_64
–http://en.wikipedia.org/wiki/List_of_Linux_supported_architectures
26
27. Famille de Linux
Plusieurs systèmes de paquets:
–APK (ANDROID) initié par Google
–DEB (DEBIAN) initié par Debian
–LZM (SLAX)
–RPM (RedHat) Package Manager initié par RedHat
–PUP ou PET (PUPPY)
–…
Conversion possible entre formats (alien)
Une distribution possède une base de donnée locale
Elle est aussi liée à un serveur de paquets (ou repository)
http://en.wikipedia.org/wiki/Linux_package_formats
28. Dépendance de paquets
Serveur de paquets
Station de travail linux
Noms des packages
déjà installés &
installable + versions
Noms des packages
disponible + versions
Sync des bases
de données
téléchargement
& installation
(avec résolution
des dépendances)
Système de fichiers linux
dans lequel s’installe
les packages
Packages
téléchargeable
Packages
téléchargeablePackages
téléchargeable
X86
X86-64
ARM
30. Démarrage d’un système linux
Bootloader
1
Bootloader
2
Initialise le
matériel
et sécurise
la carte
(EX :
INTEL CEFDK,
BROADCOM CFE,
etc … )
Prépare le
les paramètres
a donner au
Noyau linux
(Ex: uboot,
Redboot,
Grub, lilo, QI, …).
Noyau Linux Root Filesystem
Une fois chargé
en RAM, le
noyau
s’initialise en
commençant
par interpréter
les paramètres.
Si le noyau est
compressé, il se
décompresse
avant.
Paramètres
Le noyau passe
a l’espace
utilisateur en
exécutant par
Le processus
/sbin/init, le père
de tous les autres
process.
31. Echange noyau / utilisateur
NOYAU GNU/LINUX
/dev/… /proc et /sys Descripteur de fichiers
Il existe plusieurs moyen d’échange avec l’espace utilisateur.
ESPACE UTILISATEUR
PILE
RESEAU
SOCKET BSD
32. 2. Le noyau GNU/Linux
–Architecture
–Paramétrage d’un noyau
–Noyau statique vs modules dynamiques
–Détail des paramètres réseau
–Génération d’un noyau
–Les drivers réseau
–Compilation d’un module dynamique
–Chargement & déchargement de modules
–
35. Les deux mondes
Linux est constitué de deux monde, l’un est privilégié où tout est permis
(espace noyau), l’autre moins avec certaines restrictions (espace utilisateur).
Les deux mondes cohabitent autour de la syscall interface (SCI) utilisée utilisée pour
Véhiculer des informations entre les deux. Coté utilisateur, la frontière est délimité par
Une librairie (GNU libc) faisant abstraction avec la SCI. Tout programme y est linké
avec.
36. Sources du noyau linux
Noyau linux
PILE RESEAU
FILESYSTEM
MEMORY
CORE
DRIVERS
RESEAU
. . .
e1000
AppleTalk
. . .
37. Organisation des sources du noyau
Code de la pile réseau :
Racine des sources du noyau linux (après décompression) :
Codes des drivers réseaux :
38. Etapes pour la génération d’un noyau
Téléchargement des sources de kernel.org
Vérification de la signature de l’archive
Extraction des sources
Configuration du noyau
make menuconfig
make xconfig
make gconfig
Compilation
Make -j 5
Installation
make install modules_install
La configuration consiste à sélectionner ce qui sera en
statique dans le noyau (chargé en une fois) et ce qui
sera chargé séparément en modules dynamique.
L’étape de configuration est sauvegardé dans un
fichier .config ;
3 possibilités pour toutes les options du noyau :
y : en statique dans le noyau
m : en module dynamique
N : pas inclu
Il y a aussi une gestion des dépendances.
(ex: la pile réseau permet d’activer un driver réseau)
55. Builder & installer un noyau linux
Compilation du noyau & des modules dynamiques :
make –j 5
Génère une partie statique : vmlinux, vmlinuz ou bzImage
Génère des modules dynamiques *.ko
Installation de la partie statique :
sudo make install
Installation des modules dynamiques :
sudo make modules_install
56. Découpage modulaire du noyau
kernel
Le noyau peut être diviser en une partie statique (vmlinux)
et des modules dynamique
57. Chargement d’un module dynamique
Un module dynamique est un kernel object au
format ELF
Chargement :
–insmod ./mondriver.ko
–modprobe mondriver
Déchargement :
–rmmod mondriver
–modprobe –r mondriver
Autre :
–lsmod
–modinfo ./mondriver.ko
58. Programmation système
–Apercu de l'API posix et la system call interface (SCI)
–Programmation mutlti-threadé et process
–Gestion des priorités des tâches
59. L’API Posix de la libC
L’API POSIX de la libC regroupe un ensemble de fonctions autour :
–Gestion des process (chargement, exécution, création, fin …) ;
–Gestion des fichiers (c’éation, suppression, ouverture, fermeture, … ) ;
–Gestion des devices (ioctl, … )
–Gestions des infos lié au matériel (get/set de la date et de l’heure, … ) ;
–De la communication inter-process via des IPC (message queue, sockets, …).
http://syscalls.kernelgrok.com/
60. Processus – Priorité d’un processus
La fonction nice() permet de changer la priorité d’un processus
#include <unistd.h>
int nice(int nice);
–nice : valeur à ajouter à la valeur de nice courante du processus
–→ retourne la nouvelle valeur de nice (glibc ≥ 2.2.4) (avec errno)
Si la valeur de nice augmente, la priorité diminue, et vice-versa
–Les valeurs possibles vont de -20 à 19
La priorité par défaut est une valeur de nice de 0
Seul l’utilisateur avec UID 0 (root) peut changer nice avec une valeur négative
Un processus hérite de la valeur de nice de son parent après fork() ou exec()
60
61. Processus – Politiques d’ordonnancement
Le noyau Linux supporte plusieurs politiques d’ordonnancement
FIFO :
–Pas de quantum de temps
•Un processus occupe le CPU jusqu'à ce qu'il bloque ou est préempté
–Préemption par processus plus prioritaire
•Le processus préempté est de nouveau exécuté dès que le
processus plus prioritaire est bloqué
–Queue de processus en attente, par priorité
Round-Robin :
–Comme FIFO, mai un processus s'exécute pendant un quantum de
temps
–Préemption par processus plus prioritaire
–Queue de processus en attente, par priorité
61
62. Processus - Politiques d’ordonnancement (suite)
Other : l’ordonnancement Unix (Posix) traditionnel
–Quantum de temps
–Priorité de base (statique, valeur de nice) + priorité dynamique
•La priorité est incrémentée en interne lorsqu'un processus est prêt mais se
voit refuser le CPU
–Principe d’extinction des priorités
Batch : comme Other, mais permet de défavoriser un processus (Linux >= 2.6.16)
Idle : comme Batch, mais avec une valeur interne de nice > 19 (nice() n'a aucun
effet) (Linux >= 2.6.23)
Priorité des processus gérés par les quatre politiques :
–1. Processus associé à une FIFO
–2. Processus associé à un tourniquet
–3. Processus associé à la politique Other, Batch ou Idle
62
63. Processus – sched_get_priority_*()
Les fonctions sched_get_priority_max() et
sched_get_priority_min() permettent de connaitre l’échelle des priorités
pour une politique donnée
#include <sched.h>
int sched_get_priority_max(int policy);
int sched_get_priority_min(int policy);
–policy : SCHED_FIFO, SCHED_RR, SCHED_OTHER, SCHED_BATCH ou
SCHED_IDLE
–→ retourne la priorité minimale ou maximale pour la politique spécifiée, ou -1
si erreur (avec errno)
Couramment, les politiques FIFO et RR ont une échelle de priorité de 1 à 99.
Les politiques OTHER, BATCH et IDLE n’ont qu’un seul niveau de priorité : 0 (priorités
relatives gérées par nice() sauf pour IDLE)
63
64. Processus – sched_setscheduler()
La fonction sched_setscheduler() permet de sélectionner la politique et le niveau de
priorité d'un processus
#include <sched.h>
int sched_setscheduler(pid_t pid, int policy, struct sched_param
*param);
–pid : processus (si 0, processus courant)
–policy : SCHED_FIFO, SCHED_RR, SCHED_OTHER, SCHED_BATCH ou
SCHED_IDLE
–*param :
struct sched_param {
int sched_priority; // Priorité de 1 à 99 pour FIFO et RR
}
–→ retourne 0 ou -1 si erreur (avec errno)
Seul un processus d'UID effectif 0 (root) peut élever une politique ou une priorité
La politique et la priorité sont héritées après fork()
64
65. Processus – sched_getscheduler()
La fonction sched_getscheduler() permet de connaitre la politique
d'ordonnancement d'un processus
#include <sched.h>
int sched_getscheduler(pid_t pid);
–pid : processus (si 0, processus courant)
–→ retourne SCHED_FIFO, SCHED_RR, SCHED_OTHER,
SCHED_BATCH ou SCHED_IDLE
65
66. Processus – sched_setparam()
Les fonctions sched_setparam() et sched_getparam() permettent de
changer ou connaitre la priorité d'un processus
#include <sched.h>
int sched_setparam(pid_t pid, const struct sched_param
*param);
int sched_getparam(pid_t pid, struct sched_param *param);
–pid : processus (si 0, processus courant)
–*param :
struct sched_param {
int sched_priority;
}
–→ retourne 0 ou -1 si erreur (avec errno)
Seul un processus d'UID effectif 0 (root) peut élever une priorité
66
67. Processus – sched_rr_get_interval()
La fonction sched_rr_get_interval() permet de connaitre le quantum de temps
Round-Robin alloué à un processus
#include <sched.h>
int sched_rr_get_interval(pid_t pid, struct timespec *tp);
–pid : PID du processus (si 0, processus appelant)
–*tp : pointeur sur structure timespec :
struct timespec {
time_t tv_sec; // Secondes
long tv_nsec; // Nanosecondes
};
–→ retourne 0 ou -1 si erreur (avec errno)
La valeur par défaut du quantum est de 0.1 secondes
Linux permet de changer le quantum en changeant la valeur de nice (non portable, et le
quantum alloué varie selon la version du noyau)
67
68. Processus – sched_yield()
La fonction sched_yield() permet à un processus de volontairement se
suspendre
#include <sched.h>
int sched_yield(void);
–→ retourne 0 ou -1 si erreur (avec errno)
Le processus est placé à la fin de la queue de son niveau de priorité
–Si le processus est le seul dans sa queue, il est de nouveau exécuté
68
69. Processus – sched_setaffinity()
La fonction sched_setaffinity() permet de définir sur quels CPUs un
processus est "confiné"
#include <sched.h>
int sched_setaffinity(pid_t pid, size_t setsize, cpu_set_t
*mask);
int sched_getaffinity(pid_t pid, size_t setsize, cpu_set_t
*mask);
–pid : PID du processus (si 0, processus appelant)
–setsize : nombre de structures *mask
–*mask : structure opaque manipulable par des macros (voir man 3
CPU_SET)
–→ retournent 0 ou -1 si erreur (avec errno)
Les CPUs sont numérotés de 0 à CPU_SETSIZE (couramment 1024)
Le masque est hérité après fork()
69
70. Threads – Ordonnancement et priorité
Comme pour les processus, une politique d’ordonnancement et une priorité
particulières peuvent être spécifiées pour un thread
Par défaut, un thread hérite de la politique d’ordonnancement et de la
priorité de son ancêtre (processus ou autre thread)
–L’héritage peut-être désactivé dans un attribut du thread
–Si l’attribut d’héritage n’est pas désactivé, les attributs spécifiant la
politique et de la priorité sont sans effet
Le thread doit être privilégié (root) pour pouvoir augmenter la politique et
la priorité
70
71. Threads – pthread_attr_setinheritsched()
La fonction pthread_attr_setinheritsched() permet de spécifier
si la politique d’ordonnancement et la priorité sont héritées ou spécifié dans
les attributs du thread
int pthread_attr_setinheritsched(pthread_attr_t
*attr, int
inheritsched);
–*attr : attributs du thread
–inherited :
•PTHREAD_INHERIT_SCHED : politique et priorité sont hérité du
thread créateur
•PTHREAD_EXPLICIT_SCHED : honore les attributs de politique
et priorité à la création du thread
–→ retourne 0 ou un numéro d’erreur
71
72. Threads – pthread_attr_setsched*()
Les fonction pthread_attr_setsched*() permettent de spécifier la politique
d’ordonnancement et la priorité d’un thread
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int
policy);
–*attr : attributs du thread
–policy : SCHED_FIFO, SCHED_RR ou SCHED_OTHER
–→ retourne 0 ou un numéro d’erreur
int pthread_setschedparam(pthread_attr_t *attr, struct
sched_param *param);
–*attr : attributs du thread
–*param : structure ayant un membre :
•int sched_priority : priorité pour SCHED_FIFO ou SCHED_RR
–→ retourne 0 ou un numéro d’erreur
72
73. Threads – pthread_attr_setsched*() – Exemple
/* Toutes les conditions d’erreurs ne sont pas vérifiées dans cet exemple */
#include <pthread.h>
#include <sched.h>
pthread_attr_t attr;
sched_param param;
pthread_t thread_id;
pthread_attr_init(&attr);
param.sched_priority = 20;
pthread_attr_setschedparam(&attr, ¶m);
pthread_attr_setschedpolicy(&attr, SCHED_RR);
pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
pthread_create (&thread_id, &attr, func, NULL);
pthread_attr_destroy(&attr);
/* ... */
73
74. Threads – pthread_setschedparam()
La fonction pthread_setschedparam() permet de changer la
politique d’ordonnancement et la priorité d’un thread pendant son exécution
int pthread_setschedparam(pthread_t thread, int
policy, struct
sched_param *param);
–thread : identificateur du thread
–policy : SCHED_FIFO, SCHED_RR ou SCHED_OTHER
–*param : structure ayant un membre :
•int sched_priority : priorité pour SCHED_FIFO ou
SCHED_RR
–→ retourne 0 ou un numéro d’erreur
74
76. Threads – pthread_mutexattr_*prioceiling()
L’attribut prioceiling d’un mutex permet de spécifier une priorité
minimum appliquée aux threads verrouillant ce mutex
int
pthread_mutexattr_setprioceiling(pthread_mutexattr_t
*attr, int
prioceiling);
–*attr : attributs du mutex
–prioceiling : priorité minimum (même valeurs que pour
SCHED_FIFO)
–→ retourne 0 ou numéro d’erreur
En pratique, la priorité spécifiée est au moins égale à la priorité la plus
haute utilisée dans les threads
76
77. Threads – pthread_mutexattr_*protocol()
L’attribut protocol d’un mutex permet de spécifier comment un thread le
verrouillant verra sa priorité augmenter ou non
int
pthread_mutexattr_setprotocol(pthread_mutexattr_t
*attr, int
protocol);
–*attr : attributs du mutex
–protocol :
•PTHREAD_PRIO_NONE : pas de changement de priorité
•PTHREAD_PRIO_INHERIT : thread verrouillant hérite de la plus
haute priorité des threads en attente
•PTHREAD_PRIO_PROTECT : thread verrouillant s'exécute à la
priorité minimum prioceiling du mutex, même sans autre
thread bloqué
–→ retourne 0 ou un numéro d’erreur
77
78. 4. La pile réseau
–Architecture de la pile
–Les drivers réseau
–Les buffer de socket du noyau (SK BUFF)
–Circulation des paquets
–Configuration via /proc et /sys
–Configuration des interfaces
–Outils interagissant avec la pile réseau
–Estimations du coût des recopies
–Latence en UDP et TCP
79. Historique
Le développement de la couche réseau dans le noyau Linux a été
orchestré par plusieurs programmeurs indépendants.
Le but est d'implémenter un système qui soit au moins aussi
performant que les autres tout en restant dans le domaine du
logiciel libre.
C'est avant tout le protocole TCP/IP qui a été
développé avec des primitives de base par
Ross Biro. Orest Zborowski produisit la
première interface socket BSD pour le noyau
GNU Linux.
Le code fut ensuite repris par Alan Cox de
Red Hat.
80. Protocoles gérés
Linux gère une multitude de protocoles réseau :
OSI 2 : couche liaison (Driver réseaux) : 1.Ethernet
2.ARP / RARP
3.Tokenring
4.ATM
OSI 3 : couche réseau :
OSI 4 : couche transport :
1.TCP
2.UDP
3.Netbios
1.IP
2.ICMP
3.IGMP
4.ATM
La pile réseau de GNU Linux peut être considéré comme la plus complète et disponible à ce jour.
UNIX Unix domain sockets
INET TCP/IP
AX25 Amateur radio
IPX Novell IPX
APPLETALK Appletalk
X25 X.25
Etc…
(define in include/linux/socket.h)
82. Support du réseau dans le Kernel
Modèle Internet de la pile réseau. Architecture de la pile réseau.
La pile réseau couvre le protocole TCP/IP
de la couche liaison (drivers) jusqu'à la
couche transport (sockets BSD).
D'un point de vue de Linux, la pile est localisée
dans le noyau avec une API (les sockets BSD)
pouvant être appelée depuis l'espace utilisateur.
Couche matérielle
Couche de liaison
Couche réseau
Couche transport
Couche applicative
Application utilisateur
Driver réseau
Protocoles réseaux
Interface de diagnostique des devices
Interface de diagnostique des protocoles
Appels système
Carte réseau
Application
User
space
Kernel
space
83. Les drivers réseaux : introduction
Un driver réseau est la troisième catégorie
de drivers Linux après les drivers de blocs
et de caractères.
Le fonctionnement d'une interface réseau au
sein du système est assez similaire à un driver
de blocs. Un driver de blocs est utilisé par le
noyau pour transmettre ou recevoir des blocs
de données. D'un point de vue similaire, un
driver réseau s'enregistre auprès du noyau de
Façon à pouvoir échanger des paquets de
données avec l'extérieur.
Il y a cependant une différence avec un
driver de blocs qui consiste à ne pas avoir
de point d'entrée dans le répertoire dédié
aux devices /dev. Il n'est donc pas possible
de mettre en application la règle qui veut
que sous Unix / GNU Linux tout soit considéré
comme un fichier.
La différence la plus importante entre ces
deux types de drivers est que le driver de blocs
n'est utilisé que lorsque le driver y fait appel
tandis qu'un drivers réseau reçoit les paquets
réseau de façon asynchrone depuis l'extérieur.
Ainsi, alors qu'un driver de blocs demande
84. Les drivers réseaux : découpage modulaire
http://docs.huihoo.com/linux/kernel/a1/index.html
L'architecture réseau permet au noyau
Linux de se connecter à d'autres système
via le réseau.
Il existe un certain nombre important de
matériel ainsi qu'un nombre important de
protocole supportés .
Chaque objet réseau est représenté via une
socket. Les sockets sont associées aux process
dans le même sens que les i-nodes d'un
système de fichiers peuvent être associées.
Une socket peut être partagée par plusieurs
processus.
L'architecture réseau utilise le scheduler de
process du noyau Linux schedule() pour
suspendre ou reprendre un process en état
d'attente de données (géré par un système de
gestion du contrôle et du flow de données).
De plus, la couche VFS apporte un système de
fichiers logique (comme pour le cas de NFS ;
il existe des possibilités en mode user via libfuse)
85. Interaction entre une carte réseau et le noyau :
Toutes les cartes peuvent interagir avec le noyau de deux façon différentes :
–Polling : Le noyau vérifie le status du device à intervalle régulier de façon à
vérifier s'il y a quelque chose à faire ;
–Interruptions : La carte envoie un signal au noyau sous la forme d'une
interruption pour lui indiquer qu'il y a quelque chose à faire.
–
1.Matériel : elle accepte les paquets entrant en provenance des
interfaces réseaux et les positionne directement en file d'entrée.
2.
2.Software (NET_RX_SOFTIRQ) : elle exécute le handle de paquets
de réception. Elle est responsable de la gestion des protocoles. Les
paquets entrant sont gérés par cette interruption et placés dans une
file d'attente. Les paquets à forwarder sont placés dans la file de
sortie de l'interface de sortie.
Les drivers réseaux : liens
86. Chargement d'un driver
réseau dynamiquement
dans le kernel
Kmod est le chargeur de module
dans le noyau GNU Linux. Le
chargement initialise le nom du
module (argv[0]) à charger. Si au
lieu d'utiliser insmod, modprobe
est utilisé, kmod ira regarder la
configuration /etc/modprobe.conf
Chargement d’un driver réseau
87. Les drivers réseaux : enregistrement
Machine à états pour l'enregistrement d'un device réseau.
88. Les drivers réseaux : exemple
d'implémentation (old)
#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
MODULE_AUTHOR("Donald Becker
<becker@cesdis.gsfc.nasa.gov>");
MODULE_DESCRIPTION("3Com 3c590/3c900 series
Vortex/Boomerang driver");
MODULE_PARM(debug, "i");
...
#endif
...
#ifdef MODULE
int init_module(void)
{
...
}
#else
int tc59x_probe(struct device *dev)
{
...
}
#endif /* not MODULE */
...
static int vortex_scan(struct device *dev, struct pci_id_info pci_tbl[])
{
...
#if defined(CONFIG_PCI) || (defined(MODULE) && !defined(NO_PCI))
...
#ifdef MODULE
if (compaq_ioaddr) {
vortex_probe1(0, 0, dev, compaq_ioaddr, compaq_irq,
compaq_device_id, cards_found++);
dev = 0;
}
#endif
return cards_found ? 0 : -ENODEV;
}
...
#ifdef MODULE
void cleanup_module(void)
{
... ... ...
}
#endif
Example de code issue du code source du drivers réseau (drivers/net/3c59x.c) destiné au
Noyau 2.2.14. Il y a un nombre important de #ifdef MODULE et de #if defined (MODULE).
Cela est assez représentatif de l'ancienne façon de programmer qui définissait le fonctionnement
d'un module dynamique en fonction de la façon dont il était compilé tel un module statique au sein
De l'image d'un noyau.
89. Les drivers réseaux : exemple d'implémentation
(new)
static char version[] _ _devinitdata = DRV_NAME " ... ";
static struct vortex_chip_info {
...
}
vortex_info_tbl[] _ _devinitdata = {
{"3c590 Vortex 10Mbps",
... ... ...
}
static int _ _init vortex_init (void)
{
...
}
static void _ _exit vortex_cleanup (void)
{
...
}
module_init(vortex_init);
module_exit(vortex_cleanup);
Dans cette nouvelle version, les directives de
pré-processing ne sont plus nécessaires ce
qui enlève tous les #ifdef et #endif.
Cela le rend plus facile à lire pour les
développeurs de drivers via l'utilisation d'un
ensemble de macros (_ _init, _ _exit, et
_ _devinitdata ).
90. Les drivers réseaux : exemple d'implémentation
(macros 1/2)
Liste des sections de mémoire pouvant
être initialisées par des macros dans les
drivers réseau.
La plupart de ces macros sont définies dans
le header include/linux/init.h
91. Les drivers réseaux : exemple
d'implémentation (macros 2/2)
Macro Description
_ _init Routine d'initialisation lors de la séquence de boot.
_ _exit Appelée lorsque le composant kernel est déchargé du noyau.
core_initcall,
postcore_initcall,
arch_initcall,
subsys_initcall,
fs_initcall,
device_initcall,
late_initcall
Ensemble de routine pour modifier l'ordre de priorité dans les routines de virtualisation
exécutées lors de la séquence de BOOT.
_ _initcall Macro obsolète.
_ _exitcall Anciennement appelée par la routine de sortie du drivers lors de son déchargement.
_initdata Initialise une structure à la séquence de BOOT.
_exitdata A utiliser par les structures de données marquées par le tag __exitcall.
92. Check if a queue is empty : int skb_queue_empty (struct sk_buff_head * list);
Reference buffer : struct sk_buff * skb_get (struct sk_buff * skb);
Free an sk_buff : void kfree_skb (struct sk_buff * skb);
Is the buffer a clone : int skb_cloned (struct sk_buff * skb);
Is the buffer shared : int skb_shared (struct sk_buff * skb);
Make a copy of a shared buffer : struct sk_buff * skb_unshare (struct sk_buff * skb, int pri);
struct sk_buff * skb_peek (struct sk_buff_head * list_);
Get queue length: __u32 skb_queue_len (struct sk_buff_head * list_);
Queue a buffer at the list head : void __skb_queue_head (struct sk_buff_head * list, struct sk_buff * newsk)
void skb_queue_head (struct sk_buff_head * list, struct sk_buff * news
Queue a buffer at the list tail : void __skb_queue_tail (struct sk_buff_head * list, struct sk_buff * newsk);
void skb_queue_tail (struct sk_buff_head * list, struct sk_buff * newsk);
Remove from the head of the queue : struct sk_buff * __skb_dequeue (struct sk_buff_head * list);
struct sk_buff * skb_dequeue (struct sk_buff_head * list);
Primitives réseau du kernel 1/6
93. Insert a buffer : void skb_insert (struct sk_buff * old, struct sk_buff * newsk);
Append a buffer : void skb_append (struct sk_buff * old, struct sk_buff * newsk);
Remove a buffer from a list : void skb_unlink (struct sk_buff * skb);
Remove from the tail of the queue : struct sk_buff * __skb_dequeue_tail (struct sk_buff_head * list);
Remove from the head of the queue : struct sk_buff * skb_dequeue_tail (struct sk_buff_head * list);
Add data to a buffer : unsigned char * skb_put (struct sk_buff * skb, unsigned int len);
Add data to the start of a buffer : unsigned char * skb_push (struct sk_buff * skb, unsigned int len);
Remove data from the start of a buffer : unsigned char * skb_pull (struct sk_buff * skb, unsigned int len);
Bytes at buffer head : int skb_headroom (const struct sk_buff * skb);
Bytes at buffer end : int skb_tailroom (const struct sk_buff * skb);
Adjust headroom : void skb_reserve (struct sk_buff * skb, unsigned int len);
Primitives réseau du kernel 2/6
94. Orphan a buffer : void skb_orphan (struct sk_buff * skb);
Empty a list : void skb_queue_purge (struct sk_buff_head * list);
void __skb_queue_purge (struct sk_buff_head * list);
Allocate an skbuff for sending : struct sk_buff * dev_alloc_skb (unsigned int length);
Copy a buffer if need be : struct sk_buff * skb_cow (struct sk_buff * skb, unsigned int headroom);
Private function : void skb_over_panic (struct sk_buff * skb, int sz, void * here);
void skb_under_panic (struct sk_buff * skb, int sz, void * here);
void __kfree_skb (struct sk_buff * skb);
Allocate a network buffer : struct sk_buff * alloc_skb (unsigned int size, int gfp_mask);
Duplicate an sk_buff : struct sk_buff * skb_clone (struct sk_buff * skb, int gfp_mask);
Copy an sk_buff : struct sk_buff * skb_copy (const struct sk_buff * skb, int gfp_mask);
Copy and expand sk_buff : struct sk_buff * skb_copy_expand (const struct sk_buff * skb,
int newheadroom, int newtailroom, int gfp_mask);
Test if a device exists : int dev_get (const char * name);
Primitives réseau du kernel 3/6
95. Run a filter on a socket : int sk_run_filter (struct sk_buff * skb, struct sock_filter * filter, int flen);
Register ethernet device : struct net_device * init_etherdev (struct net_device * dev, int sizeof_priv );
Add packet handler : void dev_add_pack (struct packet_type * pt);
Remove packet handler : void dev_remove_pack (struct packet_type * pt);
Find a device by its name : struct net_device * __dev_get_by_name (const char * name);
struct net_device * dev_get_by_name (const char * name);
Find a device by its ifindex : struct net_device * __dev_get_by_index (int ifindex);
struct net_device * dev_get_by_index (int ifindex);
Allocate a name for a device : int dev_alloc_name (struct net_device * dev, const char * name);
Allocate a network device and name : struct net_device * dev_alloc (const char * name, int * err);
Device changes state : void netdev_state_change (struct net_device * dev);
Load a network module : void dev_load (const char * name);
Prepare an interface for use : int dev_open (struct net_device * dev);
Primitives réseau du kernel 4/6
96. Shutdown an interface : int dev_close (struct net_device * dev);
Register a network notifier block : int register_netdevice_notifier (struct notifier_block * nb);
Unregister a network notifier block : int unregister_netdevice_notifier (struct notifier_block * nb);
Transmit a buffer : int dev_queue_xmit (struct sk_buff * skb);
Post buffer to the network code : void netif_rx (struct sk_buff * skb);
void net_call_rx_atomic (void (*fn) (void));
Register a SIOCGIF handler : int register_gifconf (unsigned int family, gifconf_func_t * gifconf);
Set up master/slave pair : int netdev_set_master (struct net_device * slave, struct net_device *master);
Update promiscuity count on a device : void dev_set_promiscuity (struct net_device * dev, int inc);
Update allmulti count on a device : void dev_set_allmulti (struct net_device * dev, int inc);
Network device ioctl : int dev_ioctl (unsigned int cmd, void * arg);
Allocate an ifindex : int dev_new_index ( void);
Primitives réseau du kernel 5/6
97. Register a network device : int register_netdevice (struct net_device * dev);
Complete unregistration : int netdev_finish_unregister (struct net_device * dev);
Remove device from the kernel : int unregister_netdevice (struct net_device * dev);
Primitives réseau du kernel 6/6
98. Les buffers sk 1/4
Un paquet issu ou à destination du réseau n’est qu’une suite d’octets, un buffer, à émettre/recevoir.
Il est associé dans le noyau Linux à une structure de contrôle de type sk_buff appelée
sk_buffers (socket buffer). A cette structure est attaché un bloc mémoire contenant le buffer
reçu ou à émettre.
Lorsqu’un paquet doit être émis ou est reçu par la carte réseau, un sk_buff est créé. Cette structure
de contrôle se compose notamment de :
1.structures représentant les couches Ethernet, réseau et transport
2.pointeurs pour la gestion du sk_buffer dans la liste des sk_buffers
3.informations sur les périphériques (devices) d’entrée/sortie
4.informations sur le type de paquet (broadcast, multicast, …)
5.du buffer contenant le paquet à proprement parlé
Des pointeurs *head, *data, *tail, et *end servent à la gestion du bloc mémoire associé au
sk_buffer. head et end pointent respectivement sur le début et la fin du bloc mémoire. data
pointe sur un en-tête du paquet en fonction de l’endroit où le paquet se situe dans la pile de
protocoles.
Par exemple un paquet capturé à l’aide d’un hook netfilter aura son pointeur data positionné sur le
premier
octet de l’en-tête IP. tail pointe sur le premier octet de bourrage du bloc mémoire (le bloc mémoire
pouvant
99. Description d'un bloc mémoire associé à un sk_buffer, l'un vide et l'autre initialisé avec un bloc
mémoire initialisé avec un paquet :
Les buffers sk 2/4
Il est possible de déplacer ces pointeurs pour, par exemple, positionner le pointeur data sur un en-tête
différent. Il faut cependant garder à l’esprit qu’en mode noyau aucun contrôle n’est effectué sur les accès
mémoire et qu’un plantage du noyau peut donc se produire du fait d’une manipulation hasardeuse de
pointeur.
Les fonctions pour manipuler les sk_buffers sont définies dans le fichier header linux/skbuff.h.
100. Les buffers sk 3/4
La structure du buffer_sk est géré via une liste doublement chaînée.
101. struct sk_buff_head
{
/* These two members must be first. */
struct sk_buff * next;
struct sk_buff * prev;
_ _u32 qlen;
spinlock_t lock;
};
Les buffers sk 4/4
Structure
de
données
Init.
102. Architecture de la pile réseau
La pile TCP/IP est directement implémentée dans le noyau.
Les trames émises et reçues peuvent être amenées à traverser l’ensemble des couches
(matérielles et logicielles) :
Emission
Réception
Représentation des trames dans le Kernel Space les paquets sont manipulés par le noyau dans
des structures de type sk_buffer.
Le parcours d’une trame reçue ou à émettre, le traitement dans la pile IP peut être découpé en
phases.
103. Circulation des paquets 1/2
Le traitement IP comporte 4 grandes phases :
La réception de trame : point d’entrée
dans la couche IP pour les trames reçues sur
les interfaces réseau.
Le routage : choix de la route à suivre par
le paquet (réémission sur une autre interface/
réseau ou destination locale)
Le forwarding : contrôle du TTL et du
MTU avant de passer à la phase de
réémission.
L’émission : les paquets à émettre ou à
réémettre passent par cette étape. Juste
avant de quitter la couche IP l’en-tête
Ethernet est complété.
104. Circulation des
paquets 2/2
Couche transport
OSI #4
Couche réseau
OSI #3
Couche liaison
OSI #2
Couche physique
OSI #1
Cheminement des paquets
dans les différentes couches
de la stack réseau du kernel
GNU Linux
Une carte réseau utilise 2 listes
permettant de gérer les paquets
entrants (rx_ring) et les paquets
sortants (tx_ring) de la ou des
interfaces réseaux.
On peut ainsi distinguer la
procédure d’émission de la
procédure de réception.
Pour les noyaux 2.2 et inférieurs,
le traitement des trames est
différent (ex : on ne retrouve
pas les files tx et rx).
105. 1: Physical
Layer
2: Data
Link
4: Transport
3: Network
7: Application
6: Presentation
5: Session
Interface Layer (Ethernet, etc.)
Protocol Layer (TCP / IP)
Socket layer
Process
TCP / IP vs. OSI model
Estimation du coût (temps et consommation mémoire)
des recopie de paquets dans la pile réseau 1/5
Le but étant de faire une
estimation des recopies
mémoire d'un paquet
réseau de la carte réseau
à la socket BSD
106. Application
1: sosend (……………... )
Couche des sockets BSD
2: tcp_output ( ……. )
Couche transport (TCP / UDP)
3: ip_output ( ……. )
Couche liaison (Ethernet Device Driver)
Queue de sortie
5: recvfrom(……….)
Queue d'entrée
3: ip_input ( ……... )
4: tcp_input ( ……... )
Couche protocole (IP)
4: ethernet_output ( ……. ) 2: ethernet_input ( …….. )
Carte réseau
Résumé
des
couches
Estimation du coût (temps et consommation mémoire)
des recopies de paquets dans la pile réseau 2/5
107. send (int socket, const char *buf, int length, int flags)
Userspace
Kernelspace sendto (int socket, const char *data_buffer, int length, int flags, struct sockaddr *destination, int destination _length)
sendit (struct proc *p, int socket, struct msghdr *mp, int flags, int *return_size)
sosend (struct socket *s, struct mbuf *addr, struct uio *uio, struct mbuf *top, struct mbuf *control, int flags )
uipc_syscalls.c
uipc_socket.c
tcp_userreq (struct socket *s, int request, struct mbuf *m, struct mbuf * nam, struct mbuf * control ) tcp_userreq.c
tcp_output (struct tcpcb *tp) tcp_output.cTCP Layer
Estimation du coût (temps et consommation mémoire)
des recopies de paquets dans la pile réseau 3/5
108. Estimation du coût (temps et consommation mémoire) des
recopies de paquets dans la pile réseau 4/5
Réception d'un paquet
109. Algorigramme de la fonction tcp recvmsg
Estimation du coût (temps et consommation
mémoire) des recopies de paquets dans la pile
réseau 5/5
117. Latence 1/2
L'étude de la latence des couches de la pile réseau TCP/IP sur l'envoi d'un paquet de 1024 octets
en UDP et en TCP toutes les secondes montre les résultats suivant :
Globalement le temps de recopie pour 1024 octets est de 1 µs, l'appel à la primitive système de la socket BSD est
D'environ 2 µs et le temps de checksum en UDP est aussi de 2 µs.
L'utilisation du DMA pour le transfert des données entre le device et la mémoire est un réel atout d'un point de vue des
Performances.
Le temps d'émission par le driver réseau d'un paquet réseau est en dessous des 2 µs mais il monte à environ 4 µs en
réception du fait de la complexité inhérente du driver dans son mode réception. De plus, ce dernier mode possède une
recopie mémoire non négligeable.
UDP:
Le temps d'émission pour 1024 octets en UDP quand le checksum est requis est de 18.9 µs alors qu'en réception cela
Demande 35 µs. La capacité maximum d'envoie en UDP est donc de 433 Mbits/s alors qu'en réception le taux est de
234 Mbits/s.
TCP:
Avec le protocole TCP, l'envoie d'un paquet de 1024 octets met 22.5 µs et 36 µs en réception. La vitesse maximum en
Émission est de 364Mbits/s alors qu'en réception elle est de 228Mbits/s.
Lorsque le destinataire/expéditaire est local (localhost) la capacité maximale est d'environ 150 Mbit/s.
Le temps global nécessaire dans le noyau GNU Linux pour les recopies mémoires, les checksums et les appels systèmes
sont de 22% pour la partie émission en TCP et 16.7% pour la partie réception avec le même protocole. Idem pour UDP.
119. Routage 1/5 : routage statique vs dynamique
Routage statique vs routage dynamique
Le paramétrage statique d'une interface se fait de différente façon selon les familles de
linux. Sous GNU Debian/Ubuntu il y a le fichier /etc/network/interfaces qui contient le
paramétrage des interfaces réseau alors que sous Redhat/Fedora/suze c'est le fichier
/etc/sysconfig/network-scripts/ifcfg-eth0
Statique (paramétrage manuel) :
$ ifconfig eth0 192.168.1.1 netmask 255.255.255.0 broadcast
192.168.1.255 up
Par convention l'adresse réseau est celle la plus basse : 192.168.1.0. L'adresse de
broadcast celle la plus haute : 192.168.1.255. Pour finir, la gateway est : 192.168.1.1. Au
dela de cette convention, les adresses peuvent être choisis séparément.
Pour un paquet réseau destiné à être émis sur le réseau, le routage statique consiste à
utiliser l'adresse réseau (Ex: 192.168.1.X) pour savoir sur quelle interface envoyer le
paquet. Lorsqu'aucune interface ne possède d'adresse en adéquation avec celle des
interfaces, la table de routage envoie sur celle désigné pour être associée à la route par
défault (plus précisément à la passerelle). Pour spécifier une route manuellement il suffit
d'utiliser la commande suivante :
$ route add default gw 192.168.1.1 eth0
Il ne s'agit pas ici de routage interne ou externe utilisé sur les WAN comme RIP ou
OSPF mais d'un routage local sur un LAN.
Définition d'une adresse virtuelle ou alias :
$ ifconfig eth0:0 192.168.10.12 netmask 255.255.255.0 broadcast
192.168.10.255
$ route add -host 192.168.10.12 dev eth0
$ route add -host 192.168.10.14 dev eth0
120. Routage 2/5
http://www.subnetmask.info/ http://www.subnet-calculator.com/
Déclaration en statique d'une interface
Debian/Ubuntu (/etc/network/interfaces) :
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
address 208.88.34.106
netmask 255.255.255.248
broadcast 208.88.34.111
network 208.88.34.104
gateway 208.88.34.110
RedHad/Fedora/Suse/Mandriva
(/etc/sysconfig/network) :
DEVICE=eth0
BOOTPROTO=static
BROADCAST=XXX.XXX.XXX.255
IPADDR=XXX.XXX.XXX.XXX NETMASK=255.255.255.0
NETWORK=XXX.XXX.XXX.0 ONBOOT=yes
Déclaration dynamique (DHCP) d'une interface
Debian/Ubuntu (/etc/network/interfaces) :
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp
RedHad/Fedora/Suse/Mandriva
(/etc/sysconfig/network) :
DEVICE=eth0
ONBOOT=yes
BOOTPROTO=dhcp
lo: Loopback interface (network within your system
without slowing down for the real ethernet based
network)
ethx: Ethernet interface card
wlanx : wireless card
Dynamique : c'est un moyen supplémentaire (par rapport au routage statique) pour résoudre un
nom de machine.
121. Fichier /etc/resolv.conf : fichier de résolution des noms d'hôtes (hostname)
Search nom-de_domaine.com : nom du nom de domaine (souvent celui du fournisseur d'accès à
l'Internet).
nameserver IPADDRESS : adresse IP du serveur DNS primaire, secondaire
Cela configure la résolution avec le DNS (Domain Name Server) et les adresses IP. Si la configuration
cliente utilise le protocole DHCP avec une interface réseau il sera possible de récupérer une
configuration réseau complète : $ dhclient eth0
Fichier /etc/hosts : fichier de résolution adresse IP / Nom d'hôte
IPADDRESS HOSTNAME : associe une adresse IP à un nom d'hôte.
Ex : 127.0.0.1 localhost
Ce système est utilisé pour les systèmes n'utilisant ni DNS, ni NIS ou bien lorsqu'il est nécessaire de
forcer l'association d'une adresse IP à un nom d'hôte.
Fichier: /etc/nsswitch.conf : fichier de configuration vers le système base de données de noms via le
protocole DNS, NIS, NIS+
Le système résoud premièrement les noms d'hôte par le fichier d'association /etc/hosts,
ensuite essaye une résolution DNS (/etc/resolv.conf) et enfin recherche le serveur NIS/NIS+.
Anciennement, il y avait une recherche dans les fichiers suivants /etc/nsswitch.conf,
/etc/svc.conf, /etc/netsvc.conf …. suivant la distribution.
Définition du hostname d'une machine :
$ hostname : permet de connaître le nom du host courant.
Pour le modifier : /etc/hostname (sous Debian/Ubuntu)
Ou sous toutes les distrib : sysctl -w kernel.hostname="superserver"
Routage 3/5 : résolution de noms
122. Routage 4/5 : chemin de recherche
Pour bien comprendre la fonction de recherche de
route décrite plus tard, il faut commencer par
comprendre comment les routes sont définies
dans le noyau
Vérification de l'activation du routage :
sudo sysctl -a | grep forward
Activation du routage :
echo "1" > /proc/sys/net/ipv4/ip_forward
Inhibition du routage :
echo "0" > /proc/sys/net/ipv4/ip_forward
L'activation du routage (prise en compte
dynamique, c'est-à-dire sans avoir à rebooter
permet à la pile réseau de se comporter
comme un "routeur" de paquets IP
123. Routage 5/5
Le rôle de la couche IP est de décider comment orienter les paquets vers leur destination finale. Pour rendre cela possib
chaque interface sur le réseau est associée à un contexte réseau obtenu soit statiquement, soit dynamiquement. Une
adresse IP est constituée de quatre nombres séparés par des points, comme `167.216.245.249'. Chaque nombre étant
compris entre zéro et 255.
Consultation de la table de routage :
$ ip route ls
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.3
192.168.1.0/24 dev eth2 proto kernel scope link src 192.168.1.4
10.194.61.0/24 dev eth1 proto kernel scope link src 10.194.61.86
default via 10.194.61.1 dev eth1
default via 192.168.1.1 dev eth2
default via 192.168.1.1 dev eth0
http://mirabellug.org/wikini/upload/Documentations_routage.pdf
$ /sbin/route –n
Table de routage IP du noyau
Destination Passerelle Genmask Indic Metric Ref Use Iface
192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth2
10.194.61.0 0.0.0.0 255.255.255.0 U 0 0 0 eth1
0.0.0.0 10.194.61.1 0.0.0.0 UG 0 0 0 eth1
0.0.0.0 192.168.1.1 0.0.0.0 UG 0 0 0 eth2
0.0.0.0 192.168.1.1 0.0.0.0 UG 0 0 0 eth0
124. Administration réseau
ifconfig : permet de configurer les interfaces réseau résidentes dans le noyau
Ex: sudo ifconfig eth0:1 192.168.5.96 netmask 255.255.255.0
/sbin/ifconfig eth0 down
ifconfig eth0 inet6 add 2001:6ff:10:1::1000/64
route : permet la gestion de la table de routage
Ex : route add default gw 192.168.0.1 netmask 0.0.0.0
route -A inet6 add default gw 2001:6ff:10:1::ffff
ip (ou iproute2) : permet un gestion précise du réseau
Ex : ip addr add 192.168.0.2/24 dev eth0 brodcast 192.168.0.255
ip addr ls
ip link set dev eth0 up
ip -6 addr add 2001:6ff:10:1::1000/64 dev eth0
ip -6 route add default via 2001:6ff:10:1::ffff
iwconfig : permet la gestion des interfaces sans fil.
ipsysctl : permet la gestion du procfs /proc/sys/net
TCP tuning guide : http://www-didc.lbl.gov/TCP-tuning/TCP-tuning.html
125. Administration réseau
nameif : assigne un nom à une interface réseau
netstat : donne des statistiques sur la pile réseau
lsof : donne les ressources enregistrés par le noyau (inclus les
sockets BSD)
arp : permet de connaître son voisinage dans le LAN ;
ping : permet l’envoie de requêtes ICMP ping/pong ;
traceroute : outil permettant de connaître le routage emprunter
jusqu’à un serveur ;
126. /PROC
$ ls /proc/sys/net/ipv4
conf/ ip_autoconfig tcp_abc tcp_low_latency
Etc …
$ ls /proc/sys/net/ipv4/route
error_burst gc_elasticity gc_min_interval_ms x_delay min_delay
redirect_load
Etc …
http://linuxgazette.net/issue77/lechnyr.html
$ echo "0" > /proc/sys/net/ipv4/conf/all/accept_redirects
Listing des paramètres disponible dans le RAMFS du KERNEL :
Affichage et modifications des paramètres :
$ cat /proc/sys/net/ipv4/ip_forward
1
PROCFS est un RAMFS géré par le
noyau. C'est un lien entre le monde user
et le monde kernel.
http://mirrors.deepspace6.net/Linux+IPv6-HOWTO-fr/proc-net.html
127. Le protocole IPv4 permet d'utiliser un peu plus de quatre milliards d'adresses différentes pour
connecter les ordinateurs et les autres appareils reliés au réseau. Du temps des débuts d'Internet,
quand les ordinateurs étaient rares, cela paraissait plus que suffisant. Il était pratiquement
inimaginable qu'il y aurait un jour suffisamment de machines sur un unique réseau pour que l'on
commence à manquer d'adresses disponibles.
Une grande partie des quatre milliards d'adresses IP théoriquement disponibles ne sont pas
utilisables, soit parce qu'elles sont destinées à des usages particuliers (par exemple, le multicast), soit
parce qu'elles appartiennent déjà à des sous-réseaux importants. En effet, d'immenses plages de 16,8
millions d'adresses, les réseaux dits de classe A, ont été attribuées aux premières grandes
organisations connectées à Internet, qui les ont conservées jusqu'à aujourd'hui sans parvenir à les
épuiser. Les Nord-Américains, et dans une moindre mesure les Européens, se sont partagé les plus
grandes plages d'adresses, relativement peu nombreuses, tandis que les régions connectées plus
tardivement, comme l'Amérique du Sud et surtout l'Asie, sont restées sur la touche.
En conséquence, il y a aujourd'hui, principalement en Asie, une pénurie d'adresses que l'on doit
compenser par des mécanismes comme la Traduction d'adresse et de port réseau (NAPT) et
l'attribution dynamique d'adresses, et en assouplissant le découpage en classes des adresses (CIDR).
Au vu de l'importance et de la croissance d'Internet, cette situation pose de plus en plus de
problèmes. Il est de plus prévisible que la demande d'adresses Internet va augmenter dans les années
à venir, même dans les régions du monde épargnées jusqu'ici, suite à des innovations comme les
téléphones mobiles (et bientôt, sans doute, les automobiles et divers appareils) connectés à Internet.
C'est principalement en raison de cette pénurie, mais également pour résoudre quelques-uns des
problèmes révélés par l'utilisation à vaste échelle d'IPv4, qu'a commencé en 1995 la transition vers
IPv6. Parmi les nouveautés essentielles, on peut citer :
–l'augmentation de 232 (soit environ 10^10) à 2128 (soit environ 10^38) du nombre d'adresses
disponibles ;
–des mécanismes de configuration et de renumérotation automatique ;
–IPsec, QoS et le multicast implémentés nativement ;
–la simplification des en-têtes de paquets, qui facilite notamment le routage.
IPv6 1/3 : rappels
128. Une adresse IPv6 est longue de 16 octets, soit 128 bits, contre 4 octets (32 bits) pour IPv4. On
dispose ainsi d'environ 3,4 × 1038 adresses, soit 340 282 366 920 938 463 463 374 607 431 768
211 456, soit encore, pour reprendre l'image usuelle, plus de 667 132 000 milliards (6,67 x
10^17) d'adresses par millimètre carré de surface terrestre.
On abandonne la notation décimale pointée employée pour les adresses IPv4 (par exemple
172.31.128.1) au profit d'une écriture hexadécimale, où les 8 groupes de 16 bits sont séparés par
un signe deux-points :
1fff:0000:0a88:85a3:0000:0000:ac1f:8001
La notation canonique complète ci-dessus comprend exactement 39 caractères.
Les 64 premiers bits de l'adresse IPv6 (préfixe) servent généralement à l'adresse de sous-réseau,
tandis que les 64 bits suivants identifient l'hôte à l'intérieur du sous-réseau : ce découpage joue
un rôle un peu similaire aux masques de sous-réseau d'IPv4.
Différentes sortes d'adresses IPv6 jouent des rôles particuliers. Ces propriétés sont indiquées par
le début de l'adresse, appelé préfixe.
L'Internet IPv6 est défini comme étant le sous-réseau 2000::/3 (les adresses commençant par un
2 ou un 3). Seules ces adresses peuvent être routées. Toutes les autres adresses ne peuvent être
utilisées que localement sur un même réseau physique (de niveau 2), ou par un accord privé de
routage mutuel. Parmi les adresses de 2000::/3, on distingue :
–Les adresses 6to4 (2002::/16) permettant d'acheminer le trafic IPv6 via un ou plusieurs
réseaux IPv4.
–Les adresses du 6bone (3ffe::/16) pour l'expérimentation des interconnexions de réseaux
IPv6. (Le 6bone n'est plus opérationnel depuis le 6/6/2006)
IPv6 2/3 : rappels
129. IPv6 : 3/3
Test du support d'IPv6 : test -f /proc/net/if_inet6 && echo "Support IPv6 available."
Test si IPv6 est activé : lsmod |grep -w 'ipv6' && echo "IPv6 enabled"
Résumé : http://www.bieringer.de/linux/IPv6/status/IPv6+Linux-status-
distributions.html
Guide : http://deepspace6.net/sections/docs.html
IPv6 théorie et pratique : http://livre.point6.net/index.php/Accueil
La souche IPv6 a été intégrée officiellement au noyau depuis les versions 2.2, mais
ces noyaux étaient incomplets et non conformes aux RFC. Les noyaux 2.4 sont plus
corrects, mais eux aussi présentent quelques lacunes. Les noyaux 2.6 sont donc
préférables ; ils intègrent un partie des développements du projet japonais USAGI, en
particulier la sécurité (IPsec). Il faut aussi un noyau compilé avec l'option IPv6 (dans le
noyau ou en module). Ce type de noyau est en général disponible dans toutes les
distributions (au moins comme paquetage optionnel).
Les applications, quand à elles, doivent utiliser une librairie C supportant IPv6. La GNU
Libc 2 intègre correctement le support IPv6 à partir de la version 2.2 de la Glibc. Aussi,
il est important d'utiliser une distribution Linux qui réponde à ces critères.
Aujourd'hui la pile réseau est complètement opérationnelle avec IPv6.
130. 5. Filtrage & QOS
–Architecture de netfilter
–Implémentation d’un hook (drivers)
–Utilisation d’iptable /ip6table
–Utilisation d’un bridge (ebtable)
–Utilisation de tc d’iproute2
131. L'équipe de Netfilter et son leader actuel
Patrick McHardy :
Team Leader du projet
Netfilter .
The core Team du projet Netfilter.
132. Netfilter 1/2
L'intégration de netfilter, le firewall de Linux, se fait au travers de hook [1], de la façon suivante.
Les différents passages de fonctions s'effectuent via l'appel de NF_HOOK, une constante préprocesseur,
avec les paramètres suivants :
protocole du HOOK, exemple : PF_INET pour IPv4 ;
chaîne, exemple : NF_IP_PRE_ROUTING, NF_IP_LOCAL_IN, etc ;
pointeur vers une structure struct sk_buff, qui contient en fait des données relative au paquet ;
interface d'entrée ;
interface de sortie (peut être NULL) ;
la fonction à appeler si le paquet n'est pas supprimé.
Ainsi, si CONFIG_NETFILTER, n'est pas définie, la constante NF_HOOK est définie à :
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
se résumant à un simple appel de la fonction okfn, avec le paramètre skb.
[1] on peut traduire hook par crochet ou accroche, ou bien encore intercepteur
http://www.netfilter.org/documentation/HOWTO/netfilter-hacking-HOWTO-3.html
134. Netfilter 2/2
Un hook peut se définir comme un
point d’accès dans une chaîne de
traitement (par exemple : saisie au
clavier, parcours de la pile TCP/IP…).
Netfilter est un ensemble de hooks
à l’intérieur du noyau Linux permettant
aux modules noyau d’enregistrer des
fonctions de callback dans la pile IP.
Les trames ainsi capturées peuvent
être analysées, jetées ou modifiées.
Le firewall « natif » de linux iptables
n’est qu’un module « sur-couche » de
netfilter permettant de définir un
système de règles de filtrage et
masquerading (translation d’adresse)
de trames IP à partir des hooks.
135. Netfilter, étude de cas
Ecriture d'un driver gérant un hook netfilter :
// Fonction standard de chargement d'un driver sous GNU linux :
int init_module()
{
nfho_tunnel_in.hook = hook_func_tunnel_in;
nfho_tunnel_in.hooknum = NF_IP_PRE_ROUTING;
nfho_tunnel_in.pf = PF_INET;
nfho_tunnel_in.priority = NF_IP_PRI_FIRST;
nf_register_hook(&nfho_tunnel_in);
printk("ntNF_HOOK: Module instalenn");
return 0;
}
// Fonction standard de déchargement d'un driver
// sous GNU Linux :
void cleanup_module()
{
printk("nt NF_HOOK: I'll be back ....nn");
nf_unregister_hook(&nfho_tunnel_in);
}
136. Netfilter, etude de cas
#define __KERNEL__
#define MODULE
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
static struct nf_hook_ops netfilter_ops_in; /* NF_IP_PRE_ROUTING */
static struct nf_hook_ops netfilter_ops_out; / * NF_IP_POST_ROUTING */
/* Function prototype in <linux/netfilter> */
unsigned int main_hook(unsigned int hooknum,
struct sk_buff **skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff*))
{
return NF_DROP; /* Drop ALL Packets */
}
139. Netfilter, etude de cas
int init_module()
{
nfho.hook = hook_func;
nfho.hooknum = NF_IP_PRE_ROUTING;
nfho.pf = PF_INET;
nfho.priority = NF_IP_PRI_FIRST;
nf_register_hook(&nfho);
return 0;
}
void cleanup_module()
{
nf_unregister_hook(&nfho);
}
140. unsigned int hook_func_tunnel_in (unsigned int hooknum,
struct sk_buff **skb,
const struct net_device *in,
const struct net_
device *out,
int (*okfn)(struct sk_buff *))
{
struct sk_buff* sb= *skb;
struct iphdr* ip;
struct net_device *dev= NULL;
struct Qdisc *q;
int len;
len = sb->len;
ip = sb->nh.iph;
if((strcmp("eth0", in->name)==0) && (ip->daddr == ip1) )
{
affic_skb(sb,0);
sb->data -= 14;
sb->len = len+ 14;
memcpy(sb->data, hd_mac2, 14);
dev = dev_get_by_name("eth1");
spin_lock_bh (&(dev->queue_lock));
q = dev->qdisc;
q->enqueue(sb,q);
qdisc_run(dev);
spin_unlock_bh(&(dev->queue_lock));
affic_skb(sb,1);
return( NF_STOLEN );
}
Netfilter, étude de cas
(SUITE)
if((strcmp("eth1", in->name)==0) &&(ip->daddr
== ip0))
{
affic_skb(sb,0);
sb->data -= 14;
sb->len = len+14 ;
memcpy(sb->data,hd_mac1,
14);
dev =
dev_get_by_name("eth0");
spin_lock_bh (&(dev-
>queue_lock));
q = dev->qdisc;
q->enqueue(sb,q);
qdisc_run(dev);
spin_unlock_bh(&(dev-
>queue_lock));
return NF_STOLEN;
}
return( NF_ACCEPT );
}
Exemple d'implémentation de la fonction de hook utilisée dans le driver réseau.
http://www.linuxjournal.com/article/7184
141. Projet Open STB / Orange Labs
- R&D – Présentation pile
réseau sous GNU Linux
Spécificité du protocole ARP
A l ‘émission, seuls les paquets de type ETH_P_ALL
peuvent être capturés.
Il est important de noter que, comme pour le chemin
suivi par les trames dans le noyau, les fonctions
utilisées dans le packet handling peuvent changer
selon la version du noyau utilisé.
Pour récupérer les trames ARP, il suffit d’enregistrer
une structure packet_type dans une des listes
ptype (ptype_base ou ptype_all) avec la fonction de
callback dev_add_pack() (définie dans
linux/netdevice.h).
Comme pour les netfilter hooks, il faut supprimer ce
hook (packet handling) lorsque le module est retiré
du noyau. Ceci se fait grâce à la fonction
dev_remove_pack() (linux/netdevice.h).
En enregistrant une fonction pour ETH_P_ALL notre
packet type se retrouvera dans la liste ptype_all.
On va ainsi récupérer toutes les trames arrivant
(ou à destination) du driver de la carte réseau.
Lorsque l’on récupère un sk_buffer avec ce type de hook, c’est en fait une copie du sk_buffer capturé sur
Position des hooks de type « packet handling » dans la chaîne
de traitement des trames reçues ou à émettre.
142. Netfilter
Permet de filtrer et de manipuler les paquets réseau qui
passent dans le système
Fonctions de pare-feu :
–Contrôle des machines qui peuvent se connecter
–Sur quels ports
–Depuis l’extérieur vers l’intérieur, ou vice-versa
Fonctions de traduction d’adresses :
–Partage d’une connexion Internet (masquerading)
–Masquer des machines du réseau local
–Rediriger des connexions
Fonctions d’historisation du trafic réseau
Commande qui permet de configurer Netfilter : iptables
142
143. Netfilter
Intercepte les paquets réseau à différents endroits du
système
–Réception
–Avant de les transmettre aux processus
–Avant des les envoyer à la carte réseau
–Etc.
Les paquets interceptés passent à travers des tables
qui contiennent des chaînes qui vont déterminer ce
que le système doit faire avec le paquet
En modifiant ces chaines on va pouvoir bloquer
certains paquets et en laisser passer d'autres
143
144. Netfilter – Tables et chaînes
Une chaîne est un ensemble de règles qui indiquent ce qu'il
faut faire des paquets qui la traversent
Lorsqu'un paquet arrive dans une chaîne
–Netfilter regarde la 1ère règle de la chaîne
–Regarde si les critères de la règle correspondent au paquet
–Si le paquet correspond, la cible est exécutée (jeter le
paquet, le laisser passer, etc.)
–Sinon, Netfilter prend la règle suivante
–Ainsi de suite jusqu'à la dernière règle
Si aucune règle n'a interrompu le parcours de la chaîne, la
politique par défaut est appliquée
144
146. Netfilter – Tables et chaînes
Il est possible d'avoir de multiples tables
Chaque table peut contenir de multiples chaines
Chaque chaine peut contenir de multiples règles
Table Chaine Règle
146
147. Netfilter – Tables et chaînes
La table FILTER est la table par défaut
Cette table a trois chaines par défaut :
–INPUT
•Filtre les paquets à destination du système
–OUTPUT
•Filtre les paquets émis par les processus du système
–FORWARD
•Filtre les paquets que le système doit transmettre
147
148. Netfilter – Tables et chaînes
La table NAT a par défaut les chaines :
–PREROUTING
•Modifie les paquets avant routage
–POSTROUTING
•Modifie les paquets après routage
–OUTPUT
•Pour les paquets localement générés
148
149. Netfilter – Tables et chaînes
La table MANGLE permet d'altérer les paquets
(ex. TOS)
–PREROUTING
–OUTPUT
–FORWARD
–INPUT
–POSTROUTING
La table RAW sert pour les exemptions (pas de
filtrage)
–PREROUTING
–OUTPUT
149
151. Netfilter – Tables et chaînes
151
Arrivée d'un paquet dans la machine :Table Chaîne
1 Arrivée du paquet sur l'interface réseau
2 raw PREROUTING Permet de modifier le paquet
3 mangle PREROUTING Permet de modifier le paquet
4 nat PREROUTING Permet de faire du DNAT
5 Décision de routage
6 mangle INPUT Permet de modifier le paquet avant envoi à processus
7 filter INPUT Filtrage du paquet à destination de la machine locale
8 Un processus reçoit le paquet
152. Netfilter – Tables et chaînes
152
Envoi d'un paquet depuis la machine :Table Chaîne
1 Processus envoie le paquet
2 Décision de routage
3 raw OUTPUT Permet le traçage/marquage des connexions
4 Traçage des connexions, changements d'état
5 mangle OUTPUT Permet de modifier le paquet
6 nat OUTPUT Permet de faire du NAT
7 Décision de routage
8 filter OUTPUT Filtrage du paquet à destination du réseau
9 mangle POSTROUTING Permet de modifier le paquet
153. Netfilter – Tables et chaînes
153
Paquet redirigé :Table Chaîne
1 Processus envoie le paquet
2 raw PREROUTING Permet de modifier le paquet
3 mangle PREROUTING Permet de modifier le paquet
4 nat PREROUTING Permet de faire du DNAT
5 Décision de routage
6 mangle FORWARD Permet de modifier le paquet avant routage final
7 filter FORWARD Filtrage du paquet redirigé
8 mangle POSTROUTING Permet de modifier le paquet
9 nat POSTROUTING Permet de faire du SNAT
154. Netfilter – Règles
Une règle est une combinaison de critères et
une cible
Lorsque tous les critères correspondent au
paquet, le paquet est envoyé vers la cible.
Les critères disponibles et les actions possibles
dépendent de la chaîne manipulée
Il est possible de spécifier un saut vers une
chaîne différente de la même table
–Chaîne spécifique utilisateur
154
155. Netfilter – Cibles
Cibles de la table mangle :
–TOS
•Permet de définir ou modifier le champ Type Of Service
–TTL
•Permet de modifier le champ Time To Live
–MARK
•Permet d'associer une valeur de marquage au paquet
–Permet d'appliquer un routage différent
–Gestion de bande passante / priorité
–SECMARK et CONNSECMARK
•Marquage dans une contexte de sécurité (ex. SELinux)
155
156. Netfilter – Cibles
Cibles de la table nat :
–DNAT
•Change l'adresse de destination
–SNAT
•Change l'adresse source
–MASQUERADE
•Comme SNAT mais avec adresse IP dynamique
–REDIRECT
•Redirige les paquets vers la machine (ex. proxy
transparent)
156
158. Netfilter – Cibles
Cibles de la table filter :
–ACCEPT
•Laisse passer le paquet
–DROP
•Jette le paquet, n'en prévient pas l'émetteur
–DROP
•Jette le paquet, en prévient pas l'émetteur
–QUEUE
•Passe le paquet vers l'espace utilisateur
–RETURN
•N'exécute pas les prochaines règles de la chaine
158
159. Netfilter – conntrack
Netfilter est un pare-feu à états
–Traçage des connexions
–Réalisé avec une structure appelée conntrack
–Prend en charge les protocoles TCP, UDP et ICMP
–Défragmentation intégrée des paquets
Les paquets générés localement sont tracés dans la chaîne
OUTPUT
Le traçage de connexion est pris en charge dans la chaîne
PREROUTING
La liste des connexions tracées est lisible dans
/proc/net/ip_conntrack
159
160. Netfilter – conntrack
Etats pour les flux de paquets :
–NEW
•Premier paquet de la connexion
–ESTABLISHED
•Résulte de l'observation de trafic dans les deux sens
–RELATED
•Connexion liée a une connexion ESTABLISHED
•Nécessite d'analyser les contenus des paquets (ALGs)
–INVALID
•Paquet non identifié ou sans état
–UNTRACKED
•Paquet marqué dans la table raw avec la cible NOTRACK
160
164. Netfilter – Configuration noyau
164
Il existe un large éventail d'options,
configurables dans le noyau
Ces options peuvent être compilées
statiquement ou en tant que modules
171. iptables
La forme générale de la commande est :
iptables [-t <table>] <commande> <options>
Chaque paramètre peut souvent être spécifié
sous une forme longue (ex. --append) ou une
forme courte (ex. -A)
Les paramètres indiqués entre crochets sont
facultatifs (ex. [-t <table>])
Ce qui se trouve entre inférieur et supérieur
doit être remplacé par une valeur (ex. <table>)
171
172. iptables – Commandes principales
--list|-L [<chaîne>]
–Affiche les règles contenues dans les ou la chaîne
–Si -v est placé avant, le nombre de paquets ayant traversé chaque
règle sera affiché
–Ajouter -n pour éviter la résolution de noms
--append|-A <chaîne> <critères> -j <cible>
–Ajoute une règle à la fin de la chaîne
–Si tous les critères correspondent au paquet, il est envoyé à la
cible
--insert|-I <chaîne> <critères> -j <cible>
–Comme --append mais ajoute la règle au début de la chaîne
172
173. iptables – Commandes principales
--delete|-D <chaîne> <critères> -j <cible>
–Supprime la règle correspondante de la chaîne
--flush|-F [<chaîne>]
–Efface toutes les règles de la chaîne
–Si aucune chaîne n'est indiquée, toutes les chaînes de la
table seront vidées
--policy|-P <chaîne> <cible>
–Détermine la cible lorsque qu'aucune règle n'a interrompu
le parcours et que le paquet arrive en fin de chaîne
–Cibles autorisées : DROP et ACCEPT
173
174. iptables – Commandes principales
--protocol|-p [!] <protocole>
–Protocoles possibles : tcp, udp, icmp, all ou une valeur
numérique (/etc/protocol)
–Si un ! se trouve avant le protocole, un paquet
correspondra seulement s'il n'est pas du protocole spécifié
--source|-s [!] <adresse>[/<masque>]
--destination|-d [!] <adresse>[/<masque>]
–Si un masque est précisé, seules les parties actives du
masque sont comparées
–Le masque par défaut est /32
–Un ! ne fera correspondre le paquet que s'il n'a pas cette
adresse source
174
175. iptables – Commandes principales
-dport [!] <port>
-sport [!] <port>
– Il est obligatoire de préciser le protocole (-p tcp ou -p
udp)
-i <interface>
–L'interface réseau d'où provient le paquet
–N'est utilisable que dans la chaîne INPUT
-o <interface>
–L'interface réseau de laquelle va partir le paquet
–N'est utilisable que dans les chaînes OUTPUT et FORWARD
175
176. iptables – Cibles
-j ACCEPT
–Autorise le paquet à passer et interrompt son
parcours de la chaîne
-j DROP
–Jette le paquet sans prévenir l'émetteur, le
parcours de la chaîne est interrompu
-j REJECT
–Comme DROP mais prévient l'émetteur que le
paquet est rejeté
176
177. iptables – Cibles
LOG
–Enregistre dans le journal du noyau
–La règle suivante sera évaluée
–Options :
--log-level <niveau>
--log-prefix <préfixe>
--log-tcp-sequence
--log-tcp-options
--log-ip-options
--log-uid
177
178. iptables – Cibles
DNAT --to-destination [ip[-ip]][:port[-port]]
SNAT --to-source [ip[-ip]][:port[-port]]
–Spécifie une nouvelle adresse IP source ou
destination, ou un ensemble d'adresses
–En option : un ensemble de ports (si -p tcp ou -p
udp)
MASQUERADE
–Utilisée si l'adresse IP est dynamique (DHCP)
–Options :
--to-ports <port[-port]>
–si -p tcp ou -p udp), surcharge le mécanisme
automatique SNAT
--random
178
179. iptables – Cibles
-j REDIRECT --to-ports <port[-port]>
–Redirige un paquet vers un ou des ports
spécifiques de la machine
–Exemple :
# iptables -t nat -A PREROUTING -p tcp
--dport 80 -j REDIRECT --to-ports 8080
179
180. iptables – Cibles
AUDIT [--type <accept|drop|reject>]
–Utilisée pour compter les paquets acceptés, jetés
ou rejetés
–Voir man 8 auditd
–Exemple :
# iptables -A INPUT -j AUDIT --type drop
# iptables –A INPUT –j DROP
CLASSIFY --set-class <major:minor>
–Permet de mettre le paquet dans une classe CBQ
–Voir man 8 tc
180
181. iptables – Chaînes
--new-chain|-N <chaîne>
–Créé une nouvelle chaîne dans la table spécifiée
--delete-chain|-X <chaîne>
–Efface une chaîne dans la table spécifiée
--rename-chain|-E <chaîne>
–Renomme une chaîne dans la table spécifiée
181
182. iptables – TCP
-p tcp [!] --tcp-flags <mask> <comp>
–Match lorsque les flags TCP sont spécifiés dans le
paquet
•<mask> est la liste des flags à examiner
•<comp> est la liste des flags qui doivent être spécifiés
–Les flags sont :
•SYN, ACK, FIN, RST, URG, PSH, ALL, NONE
Exemple :
-p tcp --tcp-flags SYN,ACK,FIN,RST SYN
–Match les paquets avec SYN mais sans les ACK, FIN
et RST
182
183. iptables – TCP
-p tcp [!] --syn
–Equivalent à --tcp-flags SYN,RST,ACK,FIN SYN
-p tcp [!] --tcp-option <number>
–Match si les options sont spécifiées dans le paquet
–Liste des options :
•www.iana.org/assignments/tcp-parameters/tcp-parameters.xml
-p tcp [!] –mss <value>[:value]
–Maximum segment size
–Utilisable seulement sur les paquets SYN ou SYN/ACK
183
184. iptables – ICMP
-p icmp [!] --icmp-type <type[/code]|typename>
–Permet de spécifier les type ICMP, par valeur
numérique ou par nom
–Liste des noms :
# iptables -p icmp –help
Exemple pour ping :
-A INPUT -p icmp --icmp-type 0 -j ACCEPT
-A INPUT -p icmp --icmp-type 8 -j ACCEPT
-A OUTPUT -p icmp --icmp-type 0 -j ACCEPT
184
185. iptables – Correspondances
Une correspondance spécifique doit être
chargée par l'option -m ou –match
-m |--match addrtype [!]
<--src-type|--dst-type>
<type>
–Type d'adresse des paquets :
•LOCAL , UNICAST, BROADCAST, ANYCAST, MULTICAST,
UNREACHABLE
-m |--match iprange [!]
<--src-range|--dst-range> <from>[-
to]
–Plage d'adresses IP
185
186. iptables – Correspondances
-m|--match limit ...
–Limite un taux :
--limit <rate>[/second|/minute|/hour|/day]
--limit-burst number
-m|--match mac [!] --mac-source <adresse>
–Match les paquets avec adresse MAC spécifiée
-m|--match multiport [!] ...
–Permet de spécifier plusieurs port pour une même
règle :
[!] --sports <port>[,port|,port:port] ...
[!] --dports <port>[,port|,port:port] ...
186
187. iptables – Correspondances
-m|--match owner ...
–Permet de sélectionner des paquets à partir de
l'identité du processus qui les a crées :
[!] --uid-owner <username>|<uid[-uid]>
[!] --gid-owner <groupname>|<gid[-gid]>
[!] --socket-exists
-m |--match pkttype [!] --pkt-type
<unicast|broadcast|multicast>
–Match le type de paquet
187
188. iptables – Correspondances
-m |--match state [!] --state <state>[,state]...
–Correspondance au traçage des paquets dans
netfilter (conntrack)
–Indique dans quel état doit être la connexion pour
que les paquets correspondent
–Etats possibles :
•INVALID, NEW, ESTABLISHED, RELATED, UNTRACKED
Il existe beaucoup d'autres correspondances,
moins usuelles
–Voir man 8 iptables
188
189. iptables – /proc
Paramètres du noyau affectant Netfilter :
/proc/sys/net/ipv4/ip_dynaddr
•Support d'adresses dynamiques
/proc/sys/net/ipv4/ip_forward
•Autorisation des redirections/forwarding
/proc/sys/net/ipv4/conf/default/rp_filter
/proc/sys/net/ipv4/conf/all/rp_filter
•Valide qu'un paquet arrive par la bonne interface
/proc/sys/net/ipv4/tcp_syncookies
•Active la protection contre les tempêtes SYN
189
190. iptables – /proc
/proc/sys/net/ipv4/
icmp_ignore_bogus_error_responses
•Ignore les message ICMP falsifiés
/proc/sys/net/ipv4/conf/all/accept_redirects
/proc/sys/net/ipv4/conf/all/send_redirects
•Mettre à 0 pour désactiver les ICMP-Redirect
/proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
•Ignore les pings broadcastés
/proc/sys/net/ipv4/conf/all/log_martians
•Log les paquets venant d'adresses impossibles
190
191. iptables – Exemple
# Tout réinitialiser
iptables –F
iptables –X
# Politiques par défaut
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP
# Tout accepter sur l'interface loopback
iptables -A INPUT ! -i lo -s 127.0.0.1/8 -j DROP
iptables -A INPUT ! -i lo -d 127.0.0.1/8 -j DROP
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT ! -o lo -s 127.0.0.1/8 -j DROP
iptables -A OUTPUT ! -o lo -d 127.0.0.1/8 -j DROP
iptables -A OUTPUT –o lo -j ACCEPT
191
192. iptables – Exemple
# Chaîne pour jeter des paquets et en notifier le journal
iptables -N LOGNDROP
iptables -A LOGNDROP -p tcp -m limit --limit 1/s
-j LOG --log-prefix "[TCP drop] " --log-level=info
iptables -A LOGNDROP -p udp -m limit --limit 1/s
-j LOG --log-prefix "[UDP drop] " --log-level=info
iptables -A LOGNDROP -p icmp -m limit --limit 1/s
-j LOG --log-prefix "[ICMP drop] " --log-level=info
iptables -A LOGNDROP -f -m limit --limit 1/s
-j LOG --log-prefix "[FRAG drop] " --log-level=info
iptables -A LOGNDROP -j DROP
192
193. iptables – Exemple
# Chaîne pour vérifier les flags TCP
iptables -N TCPFLAGS
iptables -A TCPFLAGS -p tcp
--tcp-flags ALL FIN,URG,PSH -j LOGNDROP
iptables -A TCPFLAGS -p tcp
--tcp-flags ALL NONE -j LOGNDROP
iptables -A TCPFLAGS -p tcp
--tcp-flags ALL ALL -j LOGNDROP
iptables -A TCPFLAGS -p tcp
--tcp-flags ALL SYN,RST,ACK,FIN,URG -j LOGNDROP
iptables -A TCPFLAGS -p tcp
--tcp-flags SYN,FIN SYN,FIN -j LOGNDROP
iptables -A TCPFLAGS -p tcp
--tcp-flags SYN,RST SYN,RST -j LOGNDROP
193
194. iptables – Exemple
iptables -A TCPFLAGS -p tcp
--tcp-flags FIN,RST FIN,RST -j LOGNDROP
iptables -A TCPFLAGS -p tcp
--tcp-flags ACK,FIN FIN -j LOGNDROP
iptables -A TCPFLAGS -p tcp
--tcp-flags ACK,PSH PSH -j LOGNDROP
iptables -A TCPFLAGS -p tcp
--tcp-flags ACK,URG URG -j LOGNDROP
iptables -A TCPFLAGS –j DROP
194
195. iptables – Exemple
# Chaîne input
iptables -A INPUT -p all
-m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp -j TCPFLAGS
# SSH
iptables -A INPUT -p tcp --dport 22
--syn -m state --state NEW -j ACCEPT
# ICMP
iptables -A INPUT -p icmp --icmp-type 0 -j ACCEPT
iptables -A INPUT -p icmp --icmp-type 8
-m limit --limit 1/s -j ACCEPT
iptables -A INPUT -p all -j DROP
195
196. iptables – Exemple
# Chaîne output
iptables -A BADPACKETS -p all -m state --state INVALID -j DROP
iptables -A BADPACKETS -f -j DROP
iptables -A ICMPOUT -p icmp --icmp-type 0 -j ACCEPT
iptables -A ICMPOUT -p icmp -j DROP
iptables -A ICMPOUT -p all -j ACCEPT
196
197. iptables – Exemple NAT
# NAT
iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
iptables -A INPUT -i ppp0
-m state --state NEW,INVALID -j DROP
iptables -A FORWARD -i ppp0
-m state --state NEW,INVALID -j DROP
iptables -A FORWARD -o ppp0 -j ACCEPT
echo 1 > /proc/sys/net/ipv4/ip_forward
197
198. iptables – Exemple FTP
# FTP actif
iptables -A OUTPUT -o eth0 -p tcp
-m multiport --sport 20,21
-m state --state ! INVALID -j ACCEPT
iptables -A INPUT -i eth0 -p tcp
-m multiport --dport 20,21
-m state --state RELATED,ESTABLISHED -j ACCEPT
# FTP passif (requiert ip_conntrack et ip_conntrack_ftp)
iptables -A OUTPUT -o eth0 -p tcp
--sport 1024:
-m state --state ! INVALID -j ACCEPT
iptables -A INPUT -i eth0 -p tcp
--dport 1024:
-m state --state RELATED,ESTABLISHED -j ACCEPT
198
199. iptables – Exemple Port Forwarding
# PF vers eth2, machine 192.168.1.50 port 80
iptables -P FORWARD DROP
iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80
-j DNAT --to 192.168.1.50:80
iptables –A FORWARD -i eth0 -o eth2 -p tcp
-m state --state NEW --dport 80 -j ACCEPT
iptables -A POSTROUTING -t nat -o eth2 -j MASQUERADE
199
200. Bridge
Permet de bridger une interface réseau physique vers deux interface réseau
virtuelles
Permet le filtrage Ethernet
ebtable s’utilise similairement à iptable.
N2cessite le support « bridge » dans le noyau
+ les outils bridge-utils
202. EBTABLE
bloquant comme un routeur Ipv4 :
ebtables -P FORWARD DROP
ebtables -A FORWARD -p Ipv4 -j ACCEPT
ebtables -A FORWARD -p ARP -j ACCEPT
...idem pour tables INPUT et OUTPUT
– Anti-spoofing :
ebtables -A FORWARD -p Ipv4 –ip-src 172.16.2.5
-s ! 00:11:22:33:44:55 -j DROP
– NATing :
ebtables -t nat -A PREROUTING -d 00:11:22:33:44:55 -i eth0
-j dnat –to-destination 00:66:77:88:99:AA
203. NETEM
Networking -->
Networking Options -->
QoS and/or fair queuing -->
Network emulator
Le noyau linux nécessite que la config noyau suivante :
http://www.linuxfoundation.org/collaborate/workgroups/networking/netem
204. TC / NETwork EMulator
NETEM est un ordonnanceur de paquet réseau. Il peut servir à simuler le comportement d’une connexion.
Commande Netm pour générer les pertes sur les paquets émis par l'interface Eth0 :
- Premier lancement avec 1% de paquet perdu : sudo tc qdisc add dev eth0 root netem loss 1%
- Modification des pertes à 0,3% : sudo tc qdisc change dev eth0 root netem loss 0.3%
Arrêt des pertes de paquets : sudo tc qdisc change dev eth0 root netem loss 0%
Commande Netm pour générer les pertes sur les paquets émis par l'interface Eth1 :
- Premier lancement avec 1% de paquet perdu : sudo tc qdisc add dev eth1 root netem loss 1%
- Modification des pertes à 0,3% : sudo tc qdisc change dev eth1 root netem loss 0.3%
- Arrêt des pertes de paquets : sudo tc qdisc change dev eth1 root netem loss 0%
Commande NetEm pour rajouter du délai sur les paquets émis par l'interface Eth0 :
- Premier lancement avec 100ms de latence : sudo tc qdisc add dev eth0 root netem delay 100ms
- Modification de la latence à 10ms : sudo tc qdisc change dev eth0 root netem delay 10ms
- Suppression de la latence supplémentaire : sudo tc qdisc change dev eth0 root netem delay 0ms
Pour aller plus loin avec NetEm :
- http://www.linuxfoundation.org/en/Net:Netem
- http://devresources.linux-foundation.org/shemminger/netem/example.html
205. NETEM
Pour appliquer un simple delai de 100ms :
# tc qdisc add dev eth0 root netem delay 100ms
Si on veut un jitter 10ms autour de 100ms, on peut changer la régle :
# tc qdisc change dev eth0 root netem delay 100ms 10ms
Si on veut une corrélation on peut rajouter un pourcenage à la de la commande :
# tc qdisc change dev eth0 root netem delay 100ms 10ms 25%
On peut appliquer une distribution (loi normale, distribution de pareto) sur le delai :
# tc qdisc change dev eth0 root netem delay 100ms 10ms distribution normal
Quand on utilise les paramètres pas défaut, si on applique un jitter trop important on
a un réordonnancement de packet.
Pour eviter ceci on utilse la fifo d'entrée pure et non pas la fifo de la discipline de
queue. Pour ceci on change les commandes :
# tc qdisc add dev eth0 root handle 1: netem delay 10ms 100ms
# tc qdisc add dev eth0 parent 1:1 pfifo limit 1000
206. 6. Développement réseau en userspace
–API des sockets BSD
–Architecture client/serveur
–Paramétrage des sockets
–Netlink
–MPTCP
207. Les sockets BSD
L'utilisation des primitives réseau
ne se fait pas directement mais
via une API disponible
en userspace
http://www-adele.imag.fr/users/Didier.Donsez/cours/socketunix.pdf
208. Les sockets BSD
Vue synthétique des couches montrant la
localisation de l'API des sockets BSD
http://docs.huihoo.com/linux/kernel/a2/index.html
209. Sockets – Introduction
Les sockets sont une interface système utilisée pour la communication entre
processus, notamment à travers un réseau
Cette API permet à un processus de spécifier un port et un protocole et d’y
accéder pour émettre ou recevoir des données
Couvre les protocoles AppleTalk, AX.25, IPX, NetRom, TCP/IP, IPC local,
Netlink…
Certaines fonctionnalités ne sont accessibles ne sont accessibles qu’aux
processus avec un UID effectif de 0 (root) :
–Les ports privilégiés (en dessous de 1024)
–Les API permettant d'accéder à certains protocoles bas-niveau (ex.
ICMP)
209
210. Sockets – Fichiers et commandes
Le fichier /etc/host.conf indique quels services (et leur ordre
d’utilisation) seront utilisés pour la résolution de noms (DNS)
Le fichier /etc/resolv.conf défini les domaines et adresses IP de
serveurs DNS
Le fichier /etc/hosts contient une table statique d’adresses IP et de
noms symboliques
Le fichier /etc/services contient une liste des ports et services TCP et
UDP communs
Le fichier /etc/protocols contient une table de protocoles et leur
numéros tels que définis par l’IANA
Commandes utiles : ifconfig, ip, netstat, arp, rarp, route
210
211. Sockets – /proc/net
L’interface /proc/net permet d’obtenir des statistiques réseau
/proc/net/dev
–Contient des informations sur les interfaces réseau (nombre de
paquets, erreurs, collisions, etc)
/proc/net/tcp, /proc/net/udp, /proc/net/unix,
/proc/net/raw
–Contiennent des informations pour chaque socket ouverte (adresses
locale et distante, état, taille des queues, timers, UID, etc)
/proc/net/arp, /proc/net/rarp, /proc/net/route
–Contiennent les tables ARP et de routage
/proc/net/snmp
–Contient des statistiques protocoles (MIB-2 RFC)
La plupart des adresses IP sont représentées en 4 octets hexadécimaux
little-endian (ex : 0100007F:0017 -> 127.0.0.1:23)
211
212. Sockets – /proc/sys/net
L’interface /proc/sys/net permet d’ajuster certains paramètres réseau
–/proc/sys/net/core/(r|w)mem_(default|max)
–/proc/sys/net/ipv4/tcp_timestamps
–/proc/sys/net/ipv4/tcp_window_scaling
–/proc/sys/net/ipv4/tcp_sack
–/proc/sys/net/ipv4/tcp_rmem
–/proc/sys/net/ipv4/tcp_wmem
–/proc/sys/net/ipv4/tcp_fin_timeout
–/proc/sys/net/ipv4/tcp_keepalive_intvl
–/proc/sys/net/ipv4/tcp_keepalive_probes
–/proc/sys/net/ipv4/tcp_tw_recycle
–/proc/sys/net/ipv4/tcp_tw_reuse
Voir Documentation/networking/ip-sysctl.txt dans les sources du
noyau
212
213. Sockets – Domaines
Domaine Unix
–Une socket peut être utilisé pour la communication entre processus
d’une même machine
Domaine Internet Protocol
•Une socket peut être utilisé pour la communication entre processus
de machines différentes
•La socket est alors définie par
–Le protocole
–L’adresse IP de la machine A
–Le port associé sur la machine A
–L’adresse IP de la machine B
–Le port associé sur la machine B
Autres domaines : Netlink, AppleTalk, Packet, etc
213
214. Sockets – Types
Type datagramme
–Sockets en mode non connecté
–Dans le domaine Internet, le protocole est UDP
–Datagrammes de taille bornée
Type flux (ou stream)
–Socket en mode connecté
–Dans le domaine Internet, le protocole est TCP
Type raw
–Fournit un accès bas-niveau direct avec la couche IP ou ICMP
–L’UID effectif du processus doit être 0 (root)
214
215. Sockets – hton*() et ntoh*()
Les protocoles fondés sur IP figent l’ordre des octets dans le réseau en big-
endian (network byte-order)
Sur une machine little-endian, il faut convertir l’ordre des données envoyées
et reçues
Il est de bonne pratique de systématiquement convertir les données
quelque soit l’endianness de la machine (portabilité)
Des fonctions de conversion sont déclarées dans <netinet/in.h>
unsigned long int htonl(unsigned long int val);
unsigned short int htons(unsigned short int val);
unsigned long int ntohl(unsigned long int val);
unsigned short int ntohs(unsigned short int val);
215
216. Sockets – Structure sockaddr
La structure sockaddr sert à définir une adresse réseau
La plupart des fonctions sur les sockets l’utilisent
struct sockaddr {
unsigned short int sa_family;
char sa_data[14];
};
–sa_familly : AF_UNIX, AF_INET, AF_INET6, AF_IPX, …
–sa_data : données propres au protocole
Cette structure est générique (coquille vide)
Chaque protocole utilise en fait sa propre structure (sockaddr_un,
sockaddr_ipx, sockaddr_in6, etc.) qui est castée :
–(struct sockaddr *) &sockaddr_un
216
217. Sockets – Structure sockaddr_in
Les structures adresses du domaine Internet IPv4 sont
sockaddr_in {
sa_family_t sin_family; // toujours AF_INET
in_port_t sin_port; // port
struct in_addr sin_addr; // adresse IPv4
};
struct in_addr {
uint32_t s_addr; // adresse IPv4
};
L’adresse et le port doivent être sous la forme réseau (big-endian)
L’adresse INADDR_ANY (0.0.0.0) associe une socket avec toutes les interfaces
La valeur 0 dans sin_port laisse le système choisir le port source
217