Upload
thierry-gayet
View
170
Download
0
Embed Size (px)
Citation preview
Réseau & embarqué
PLAN
Introduction à LinuxLe noyau GNU/LinuxProgrammation systèmeLa pile réseauFiltrage & QoSDéveloppement réseau en userspaceCaptures et simulationLinux embarqué
1. Introduction à Linux
–Qu’est ce que Linux ?–Linux historique–Linux versions–Linux statistiques–Le projet GNU–Les licences
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
Unix – Historique
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 GPL1993 : Plus de 100 développeurs travaillent sur le noyau1994 : Sortie de Linux 1.01994 : Les sociétés Red Hat et Suse publient les versions 1.0
de leur distribution1996 : Sortie de Linux 2.01999 : Sortie de Linux 2.22001 : IBM investit 1 milliard de dollars dans Linux2002 : Sortie de Linux 2.42004 : Sortie de Linux 2.62011 : Sortie de Linux 3.0
6
Linux – Historique (suite)
Premier post effectué par Linus Torvald sur Usenet :
Path:
gmdzi!unido!fauern!ira.uka.d
e!sol.ctr.columbia.edu!zapho7
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
Linux – Historique – Versions
Linux – Statistiques (suite)
10
Linux – Statistiques (suite)
11
Linux – Statistiques (suite)
12
Linux – Statistiques (suite)
13
Linux – Statistiques (suite)
14
Linux – Statistiques (suite)
Linux – Statistiques (suite) – 2.6.35
Linux – Reviewers – 2.6.35
Linux – Marché embarqué
18
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 suitede 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 originaleLe 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
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
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
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
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
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
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 noyauLe noyau est multithreadéLe noyau supporte SMPLa plupart des interfaces graphiques sont en espace utilisateurScalabilité : tourne sur des super ordinateurs aussi bien que sur des petits
appareilsConformité aux standards et interopérabilité (POSIX)Support réseau avec une pile très complèteSécurité : discretionary access control, extended FS attributes, etc.Stabilité et fiabilité
25
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
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 localeElle est aussi liée à un serveur de paquets (ou repository)
http://en.wikipedia.org/wiki/Linux_package_formats
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’installeles packages
Packagestéléchargeable
PackagestéléchargeablePackages
téléchargeable
X86X86-64
ARM
Démarrage d’un système linux
Démarrage d’un système linux
Bootloader1
Bootloader2
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.
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
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–
Linux tel un oignon
Architecture du noyau
Le noyau est divisé en un ensemble de blocs séparés :
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.
Sources du noyau linux
Noyau linux
PILE RESEAU
FILESYSTEM
MEMORY
CORE
DRIVERSRESEAU
. . .
e1000
AppleTalk
. . .
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 :
Etapes pour la génération d’un noyau
Téléchargement des sources de kernel.orgVérification de la signature de l’archiveExtraction des sourcesConfiguration du noyau
make menuconfigmake xconfigmake gconfig
CompilationMake -j 5
Installationmake install modules_install
La configuration consiste à sélectionner ce qui sera enstatique dans le noyau (chargé en une fois) et ce quisera chargé séparément en modules dynamique.L’étape de configuration est sauvegardé dans unfichier .config ;3 possibilités pour toutes les options du noyau :y : en statique dans le noyaum : en module dynamiqueN : pas inclu Il y a aussi une gestion des dépendances.(ex: la pile réseau permet d’activer un driver réseau)
Paramétrer un noyau
make menuconfig Donne un fichier de
paramétrage .config
Paramétrer un noyau
Paramétrer un noyau
Paramétrer un noyau
Paramétrer un noyau
Paramétrer un noyau
Paramétrer un noyau
Paramétrer un noyau
Paramétrer un noyau
Paramétrer un noyau
Paramétrer un noyau
Paramétrer un noyau
Paramétrer un noyau
Paramétrer un noyau
Paramétrer un noyau
Interface de configuration graphique
make gconfig
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
Découpage modulaire du noyau
kernel
Le noyau peut être diviser en une partie statique (vmlinux)
et des modules dynamique
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
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
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/
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
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
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
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 -1si 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
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
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
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
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; // Secondeslong tv_nsec; // Nanosecondes
};–→ retourne 0 ou -1 si erreur (avec errno)
La valeur par défaut du quantum est de 0.1 secondesLinux permet de changer le quantum en changeant la valeur de nice (non portable, et le
quantum alloué varie selon la version du noyau)
67
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
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
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
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
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
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
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
Threads – Inversion de priorité
75
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
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
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
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.
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)
Protocoles gérés
Disponibilité des fonctionnalités dans la pile réseau en
fonction des versions du noyau Linux 2.2, 2.4 et 2.6
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
ApplicationUser
space
Kernel
space
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
avant d'envoyer quelque chose au noyau,
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)
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
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
Les drivers réseaux : enregistrement
Machine à états pour l'enregistrement d'un device réseau.
Les drivers réseaux : exemple d'implémentation (old)
#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115MODULE_AUTHOR("Donald Becker <[email protected]>");MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver");MODULE_PARM(debug, "i");...#endif...#ifdef MODULEint init_module(void){...}#elseint 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 MODULEif (compaq_ioaddr) {vortex_probe1(0, 0, dev, compaq_ioaddr, compaq_irq,compaq_device_id, cards_found++);dev = 0;}#endifreturn cards_found ? 0 : -ENODEV;}...#ifdef MODULEvoid 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.
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 ).
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
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.
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 * newsk);
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
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
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
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
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
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
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
être plus grand que le paquet à stocker).
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êtedifférent. Il faut cependant garder à l’esprit qu’en mode noyau aucun contrôle n’est effectué sur les accèsmé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.
Les buffers sk 3/4
La structure du buffer_sk est géré via une liste doublement chaînée.
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.
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.
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é.
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 listespermettant de gérer les paquetsentrants (rx_ring) et les paquetssortants (tx_ring) de la ou desinterfaces réseaux.
On peut ainsi distinguer la procédure d’émission de laprocédure de réception.
Pour les noyaux 2.2 et inférieurs, le traitement des trames est différent (ex : on ne retrouvepas les files tx et rx).
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
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
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
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
Algorigramme de la fonction tcp recvmsg
Estimation du coût (temps et consommation mémoire) des recopies de paquets dans la pileréseau 5/5
Les QDISK
#
# QoS and/or fair queueing
#
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_CBQ=m
CONFIG_NET_SCH_HTB=m
CONFIG_NET_SCH_CSZ=m
CONFIG_NET_SCH_PRIO=m
CONFIG_NET_SCH_RED=m
CONFIG_NET_SCH_SFQ=m
CONFIG_NET_SCH_TEQL=m
CONFIG_NET_SCH_TBF=m
CONFIG_NET_SCH_GRED=m
CONFIG_NET_SCH_DSMARK=m
CONFIG_NET_SCH_INGRESS=m
CONFIG_NET_QOS=y
CONFIG_NET_ESTIMATOR=y
CONFIG_NET_CLS=y
CONFIG_NET_CLS_TCINDEX=m
CONFIG_NET_CLS_ROUTE4=m
CONFIG_NET_CLS_ROUTE=y
CONFIG_NET_CLS_FW=m
CONFIG_NET_CLS_U32=m
CONFIG_NET_CLS_RSVP=m
CONFIG_NET_CLS_RSVP6=m
CONFIG_NET_CLS_POLICE=y
Les dépendances noyau :
Les QDISK - TC
[root@leander]# tc
Usage: tc [ OPTIONS ] OBJECT { COMMAND | help }
where OBJECT := { qdisc | class | filter }
OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] }
http://tldp.org/HOWTO/Traffic-Control-HOWTO/software.html
TC, l’outil de contrôle des classifieur en userspace :
QDISK (pfifo and bfifo)
cat bfifo.tcc
/*
* make a FIFO on eth0 with 10kbyte queue size
*
*/
dev eth0 {
egress {
fifo (limit 10kB );
}
}
[root@leander]# tcc < bfifo.tcc
# ================================ Device eth0
================================
tc qdisc add dev eth0 handle 1:0 root dsmark indices 1 default_index 0
tc qdisc add dev eth0 handle 2:0 parent 1:0 bfifo limit 10240
[root@leander]# cat pfifo.tcc
/*
* make a FIFO on eth0 with 30 packet queue size
*
*/
dev eth0 {
egress {
fifo (limit 30p );
}
}
[root@leander]# tcc < pfifo.tcc
# ================================ Device eth0
================================
tc qdisc add dev eth0 handle 1:0 root dsmark indices 1 default_index 0
tc qdisc add dev eth0 handle 2:0 parent 1:0 pfifo limit 30
QDISK (pfifo_fast)
QDISC (SFQ)
cat sfq.tcc
/*
* make an SFQ on eth0 with a 10 second perturbation
*
*/
dev eth0 {
egress {
sfq( perturb 10s );
}
}
[root@leander]# tcc < sfq.tcc
# ================================ Device eth0
================================
tc qdisc add dev eth0 handle 1:0 root dsmark indices 1 default_index 0
tc qdisc add dev eth0 handle 2:0 parent 1:0 sfq perturb 10
QDISK (ESFQ, Extended Stochastic Fair Queuing)
Usage: ... esfq [ perturb SECS ] [ quantum BYTES ] [ depth FLOWS ]
[ divisor HASHBITS ] [ limit PKTS ] [ hash HASHTYPE]
Where:
HASHTYPE := { classic | src | dst }
QDISK (TBF, Token Bucket Filter)
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.
Latence 2/2
Résumé du benchmark précédent :
Emission
Réception
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 upPar 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
Routage 2/5
http://www.subnetmask.info/ http://www.subnet-calculator.com/
Déclaration en statique d'une interfaceDebian/Ubuntu (/etc/network/interfaces) : auto loiface lo inet loopbackauto eth0iface eth0 inet staticaddress 208.88.34.106netmask 255.255.255.248broadcast 208.88.34.111network 208.88.34.104gateway 208.88.34.110
RedHad/Fedora/Suse/Mandriva (/etc/sysconfig/network) :DEVICE=eth0BOOTPROTO=staticBROADCAST=XXX.XXX.XXX.255IPADDR=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.
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ôteIPADDRESS 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
Routage 4/5 : chemin de recherche
Pour bien comprendre la fonction de recherche deroute 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
Routage 5/5Le rôle de la couche IP est de décider comment orienter les paquets vers leur destination finale. Pour rendre cela possible,chaque interface sur le réseau est associée à un contexte réseau obtenu soit statiquement, soit dynamiquement. Uneadresse IP est constituée de quatre nombres séparés par des points, comme `167.216.245.249'. Chaque nombre étantcompris 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
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 lsip 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
Administration réseau
nameif : assigne un nom à une interface réseaunetstat : donne des statistiques sur la pile réseaulsof : 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 ;
/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
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
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
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.htmlGuide : http://deepspace6.net/sections/docs.htmlIPv6 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.
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
L'équipe de Netfilter et son leader actuel
Patrick McHardy :
Team Leader du projet
Netfilter .
The core Team du projet Netfilter.
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
Netfilter
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.
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("\n\tNF_HOOK: Module instale\n\n");
return 0;
}
// Fonction standard de déchargement d'un driver
// sous GNU Linux :
void cleanup_module()
{
printk("\n\t NF_HOOK: I'll be back ....\n\n");
nf_unregister_hook(&nfho_tunnel_in);
}
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 */
}
Netfilter, etude de cas
int init_module()
{
// Premier hook
netfilter_ops_in.hook = main_hook;
netfilter_ops_in.pf = PF_INET;
netfilter_ops_in.hooknum = NF_IP_PRE_ROUTING;
netfilter_ops_in.priority = NF_IP_PRI_FIRST;
// Second hook
netfilter_ops_out.hook = main_hook;
netfilter_ops_out.pf = PF_INET;
netfilter_ops_out.hooknum = NF_IP_POST_ROUTING;
netfilter_ops_out.priority = NF_IP_PRI_FIRST;
nf_register_hook(&netfilter_ops_in); /* register NF_IP_PRE_ROUTING hook */
nf_register_hook(&netfilter_ops_out); /* register NF_IP_POST_ROUTING hook */
return 0;
}
void cleanup()
{
nf_unregister_hook(&netfilter_ops_in); /* unregister NF_IP_PRE_ROUTING hook */
nf_unregister_hook(&netfilter_ops_out); /* unregister NF_IP_POST_ROUTING hook */
}
Netfilter, etude de cas#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/skbuff.h>
#include <linux/udp.h>
#include <linux/ip.h>
static struct nf_hook_ops nfho; //net filter hook option struct
struct sk_buff *sock_buff;
struct udphdr *udp_header; //udp header struct (not used)
struct iphdr *ip_header; //ip header struct
unsigned int hook_func(unsigned int hooknum, struct sk_buff **skb, const struct net_device *in, const struct net_device *out, int
(*okfn)(struct sk_buff *))
{
sock_buff = *skb;
ip_header = (struct iphdr *)skb_network_header(sock_buff); //grab network header using accessor
if(!sock_buff) { return NF_ACCEPT;}
// Vérifie s’il s’agit d’un paquet UDP :
if (ip_header->protocol==17)
{
udp_header = (struct udphdr *)skb_transport_header(sock_buff); //grab transport header
printk(KERN_INFO "got udp packet \n"); //log we’ve got udp packet to /var/log/messages
return NF_DROP;
}
return NF_ACCEPT;
}
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);
}
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
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
laquelle on va travailler. La copie doit être détruite en fin de fonction avec la fonction kfree_skb().
Position des hooks de type « packet handling » dans la chaîne
de traitement des trames reçues ou à émettre.
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éseauCommande qui permet de configurer Netfilter : iptables
142
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
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
Netfilter – Tables et chaînes
145
Netfilter – Tables et chaînes
Il est possible d'avoir de multiples tablesChaque table peut contenir de multiples chainesChaque chaine peut contenir de multiples règles Table Chaine Règle
146
Netfilter – Tables et chaînes
La table FILTER est la table par défautCette 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
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
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
Netfilter – Tables et chaînes
manglePREROUTING
réseau
natPREROUTING
routagemangleINPUTfilter
INPUT
processus
routage
mangleOUTPUT
natOUTPUT
filterOUTPUT
routage
manglePOSTROUTING
natPOSTROUTING
réseau
mangleFORWARD
filterFORWARD
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
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
10 nat POSTROUTING Permet de faire du SNAT
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
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
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
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
Netfilter – Cibles
Cibles de la table raw :–NOTRACK
•Pas de traçage
157
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
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
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
Netfilter – conntrack
Etats internes pour tracer les connexions TCP :–NONE
–ESTABLISHED 5 jours–SYN_SENT2 minutes–SYN_RECV60 secondes–FIN_WAIT2 minutes–TIME_WAIT 2 minutes–CLOSE 10 secondes–CLOSE_WAIT 12 heures–LAST_ACK30 secondes–LISTEN 2 minutes
Délais ajustables : /proc/sys/net/ipv4/netfilter/ip_ct_tcp_*
161
Netfilter – conntrack
Connexion TCP
162
Client
SYN
Pare-feu
SYN_SENT
Serveur
SYN/ACK
SYN_RECV
ACK
ESTABLISHED
Netfilter – conntrack
Client
FIN/ACK
Pare-feu
FIN_WAIT
Serveur
ACK
CLOSE_WAIT
(closed)
FIN/ACK
FIN_WAIT
ACK
CLOSED
(closed)
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
Netfilter – Configuration noyau
165
Netfilter – Configuration noyau
166
Netfilter – Configuration noyau
167
Netfilter – Configuration noyau
168
Netfilter – Configuration noyau
169
Netfilter – Configuration noyau
170
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
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
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
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
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
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
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
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
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
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
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
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, FINet RST
182
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
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
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
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
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
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
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
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
iptables – Exemple
# Tout réinitialiseriptables –Fiptables –X
# Politiques par défautiptables -P INPUT DROPiptables -P FORWARD DROPiptables -P OUTPUT DROP
# Tout accepter sur l'interface loopbackiptables -A INPUT ! -i lo -s 127.0.0.1/8 -j DROPiptables -A INPUT ! -i lo -d 127.0.0.1/8 -j DROPiptables -A INPUT -i lo -j ACCEPTiptables -A OUTPUT ! -o lo -s 127.0.0.1/8 -j DROPiptables -A OUTPUT ! -o lo -d 127.0.0.1/8 -j DROPiptables -A OUTPUT –o lo -j ACCEPT
191
iptables – Exemple
# Chaîne pour jeter des paquets et en notifier le journaliptables -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
iptables – Exemple
# Chaîne pour vérifier les flags TCPiptables -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
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
iptables – Exemple
# Chaîne inputiptables -A INPUT -p all
-m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp -j TCPFLAGS
# SSHiptables -A INPUT -p tcp --dport 22
--syn -m state --state NEW -j ACCEPT
# ICMPiptables -A INPUT -p icmp --icmp-type 0 -j ACCEPTiptables -A INPUT -p icmp --icmp-type 8
-m limit --limit 1/s -j ACCEPT
iptables -A INPUT -p all -j DROP
195
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
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
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
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
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
Netfilter & iptable/ebtable
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
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
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
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
6. Développement réseau en userspace
–API des sockets BSD–Architecture client/serveur–Paramétrage des sockets–Netlink–MPTCP
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
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
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
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
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
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
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
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
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
Sockets – Structure sockaddr
La structure sockaddr sert à définir une adresse réseauLa 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
Sockets – Structure sockaddr_in
Les structures adresses du domaine Internet IPv4 sont
sockaddr_in {sa_family_t sin_family; // toujours AF_INETin_port_t sin_port; // portstruct 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 interfacesLa valeur 0 dans sin_port laisse le système choisir le port source
217
Sockets – Structure sockaddr_in6
Les structures adresse du domaine Internet IPv6 sont :
sockaddr_in6 {sa_family_t sin6_family; // toujours AF_INET6in_port_t sin6_port; // portuint32_t sin6_flowinfo; // information de fluxstruct in6_addr sin6_addr; // adresse IPv6uint32_t sin6_scope_id; // scope ID};
struct in6_addr {unsigned char s6_addr[16]; // adresse IPv6};
L’adresse et le port doivent être sous la forme réseau (big-endian)
L’adresse in6addr_any associe une socket avec toutes les interfaces
218
Sockets – inet_*()
Les adresses IPv4 sont habituellement écrites sous la forme du chaine de caractères x.x.x.x (dotted quad)
Des fonctions permettent de passer de cette forme à la forme réseau (big-endian) et vice-versa
Il faut inclure les headers <sys/socket.h>, <netinet/in.h> et <arpa/inet.h>int inet_aton(const char *cp, struct in_addr *inp);char *inet_ntoa(struct in_addr in);in_addr_t inet_addr(const char *cp);int inet_pton(int af, const char *src, void *dst);
NOTE : En cas d’erreur (adresse IP malformée), la fonction inet_addr()retourne INADDR_NONE, qui a pour valeur -1, qui est une valeur d’adresse IP légale (255.255.255.255)
219
Sockets – inet_pton()
La fonction inet_pton() sert à convertir une adresse IPv4 ou IPv6 sous forme de chaine de caractères en une structure adresse#include <arpa/inet.h>int inet_pton(int af, const char *src, void *dst);
–af : AF_INET ou AF_INET6–*src : adresse IP :
•IPv4 : "xxx.xxx.xxx.xxx"•IPv6 : "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx"
–*dst : structure adresse :•IPv4 : struct in_addr•IPv6 : struct in6_addr
–→ retourne 1 si conversion réussie, 0 si *src ne représente pas une adresse valide, -1 si af ne contient pas une famille valide
220
Sockets – inet_ntop()
La fonction inet_ntop() sert à convertir une adresse IPv4 ou IPv6 d’une structure adresse en une chaine de caractères#include <arpa/inet.h>char *inet_ntop(int af, const void *restrict src,
char *restrict dst, socklen_t size);
–af : AF_INET ou AF_INET6–*src : structure adresse :
•IPv4 : struct in_addr•IPv6 : struct in6_addr
–*dst : buffer qui contiendra l’adresse IP–size : taille du buffer dst (INET_ADDRSTRLEN ou INET6_ADDRSTRLEN)–→ retourne un pointeur sur le buffer si conversion réussie, NULL sinon (avec errno)
221
Sockets – gethostbyname()
La fonction gethostbyname() permet de faire une résolution de nom DNS vers une adresse IPv4 ou IPv6#include <netdb.h>struct hostent *gethostbyname(const char *name);
–*name : nom de domaine ou adresse IP–→ retourne un pointeur sur hostent ou NULL si erreur (avec h_errno)
struct hostent {char *h_name; // nom DNS officielchar **h_aliases; // liste d’aliasint h_addrtype; // AF_INET ou AF_INET6int h_length; // longueur d’une adresse en octetschar **h_addr_list; // liste chainée d'adresses IP};
Note : cette fonction n’est pas réentrante
222
Sockets – gethostbyaddr()
La fonction gethostbyaddr() permet de faire une résolution inverse d’une adresse IP vers un nom de domaine#include <netdb.h>struct hostent *gethostbyaddr(const void *addr, int len, int type);
–*addr : pointeur sur une structure adresse (sin_addr pour AF_INET)–len : longueur de la structure addr (4 pour IPv4, 16 pour IPv6)–type : AF_INET ou AF_INET6–→ retourne un pointeur sur hostent ou NULL si erreur (avec h_errno)
Note : cette fonction n’est pas réentrante
223
Sockets – getaddrinfo()
La fonction getaddrinfo() est l’équivalent réentrant (donc thread-safe) de gethostbyname() et fonctionne pour IPv4 et IPv6#include <netdb.h>int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);
–*node : nom de domaine (ex. "www.exemple.com") ou adresse IP–*service : nom du service (ex. "http") ou port–*hints : structure pré-remplie (voir ci-après) ou NULL–*res : liste chainée (voir ci-après)–→ retourne 0 ou un code d’erreur
La liste chainée *res doit être libérée avec :–freeaddrinfo(struct addrinfo *res);
Voir getnameinfo() pour la fonction inverse
224
Sockets – Structure addrinfo
addrinfo est une structure utilisée par la fonction getaddrinfo()
struct addrinfo {int ai_flags; // AI_PASSIVE, AI_CANONNAME, etcint ai_family; // AF_INET, AF_INET6, AF_UNSPECint ai_socktype; // SOCK_STREAM, SOCK_DGRAMint ai_protocol; // 0size_t ai_addrlen; // taille de ai_addrstruct sockaddr *ai_addr; // sockaddr_in or _in6char *ai_canonname; // canonical hostnamestruct addrinfo *ai_next; // linked list, next node};
AF_UNSPEC permet de s’affranchir de la version IP
225
Sockets – getaddrinfo() – Exemple
#include <sys/types.h> #include <sys/socket.h>#include <netdb.h>
int status;struct addrinfo *servinfo;
if ((status = getaddrinfo("site.com", NULL, NULL, &servinfo)) != 0) {fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));retourn -1;
}
/* le domaine site.com est résolu, servinfo pointe sur une liste chainée d’une ou plusieurs struct addrinfos */
/* ... */
freeaddrinfo(servinfo);
226
Sockets – socket()
La fonction socket() permet de créer une socket nécessaire pour la communications entre processus (locaux ou distants)
#include <sys/socket.h>int socket(int domain, int type, int protocol);
–domain : domaine de la socket (AF_UNIX, AF_INET, AF_INET6, …)–type : type de socket
•SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, SOCK_PACKET–protocol : numéro du protocole utilisé, ou 0 pour le protocole par défaut–→ retourne un descripteur ou -1 si erreur (avec errno)
Le descripteur est utilisable par les fonctions telles que read() et write()
La fonction close() permet de fermer le descripteur d’une socket
227
Sockets – Streams
Socket du type SOCK_STREAM
Protocole TCP dans le domaine AF_INET–Transport fiable, vérification qu’un message envoyé est bien reçu–Contrôle de flux–Contrôle de congestion–Checksum
L’établissement de la connexion entre machines se fait en plusieurs étapes
La dissymétrie entre le serveur et le client est clairement marquée–Le serveur doit être en attente de connexion–Lorsque le serveur reçoit une connexion, une socket "de service" est créée–Le client prend l’initiative d’une connexion
228
Sockets – Streams : Client / Serveur
229
Sockets – Streams – bind()
La fonction bind() permet d’attacher une sockets à une adresseDoit être utilisée avant de pouvoir accepter des connexions
#include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr,
socklen_t addr_len);
–sockfd : descripteur de socket–*addr : pointeur sur une structure d’adresse–addr_len : taille en octets de la structure addr–→ retourne 0 ou -1 si erreur (avec errno)
Peut être utilisée avec d'autres protocoles que TCP
La structure addr employée dépend de la famille d’adresse utilisée (ex : sockaddr_in pour une adresse IPv4)
230
Sockets – Streams – listen()
La fonction listen() permet de créer une file d’attente pour les demandes de connexion
#include <sys/socket.h>int listen(int sockfd, int backlog);
–sockfd : descripteur de la socket–backlog : longueur de la file d’attente–→ retourne 0 ou -1 si erreur (avec errno)
La file est limitée à la valeur de /proc/sys/net/core/somaxconn(128 par défaut)
Lorsque la file d’attente est pleine, les connections suivantes sont refusées
231
Sockets – Streams – listen()
La fonction accept() permet a un serveur d’accepter une connexion en attente dans la file crée par listen()
#include <sys/socket.h>int accept(int sockfd, struct sockaddr *addr, socklen_t addr_len);
–sockfd : descripteur–*addr : adresse du client se connectant–addr_len : taille en octets de la structure addr–→ retourne un descripteur sur une nouvelle socket ou -1 si erreur (avec errno)
Le descripteur original continue d’être utilisé pour les connexions suivantes
S’il n’y a pas de connexion pendante, par défaut la fonction bloque
232
Sockets – Streams – connect()
En mode SOCK_STREAM, la fonction connect() permet a un client de se connecter à un serveur
#include <sys/socket.h>int connect(int sockfd, const struct sockaddr *addr,
socklen_t addr_len);
–sockfd : descripteur–*addr : adresse du serveur–addr_len : taille en octets de la structure addr–→ retourne 0 ou -1 si erreur (avec errno)
La fonction connect() bloque jusqu’à ce que le serveur accepte la connexion (ou timeout dépendant du protocole) (sauf si la socket est en mode non bloquant)
En mode SOCK_STREAM, il n'est pas possible de réutiliser connect() sur la même socket pour se connecter à un autre serveur
233
Sockets – Streams – Exemple client
/* Toutes les conditions d’erreurs ne sont pas vérifiées dans cet exemple */
void tcp_client(void){int sockfd;struct sockaddr_in address;char ch = 'A';
sockfd = socket(AF_INET, SOCK_STREAM, 0);
address.sin_family = AF_INET;address.sin_addr.s_addr = inet_addr("127.0.0.1");address.sin_port = htons(9734);connect(sockfd, (struct sockaddr *)&address, sizeof(address));write(sockfd, &ch, 1);read(sockfd, &ch, 1);printf("char from server = %c\n", ch);close(sockfd);}
234
Sockets – Streams – Exemple serveur
/* Toutes les conditions d’erreurs ne sont pas vérifiées dans cet exemple */
void tcp_server(void){
int server_sockfd, client_sockfd, client_len;struct sockaddr_in server_address;struct sockaddr_in client_address;char ch;
server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
server_address.sin_family = AF_INET;server_address.sin_addr.s_addr = htonl(INADDR_ANY);server_address.sin_port = htons(9734);bind(server_sockfd, (struct sockaddr *)&server_address,
sizeof(server_address));listen(server_sockfd, 5);client_len = sizeof(client_address);
235
Sockets – Streams – Exemple serveur (suite)
while(1)
{client_sockfd = accept(server_sockfd, (struct sockaddr *)
&client_address, &client_len);read(client_sockfd, &ch, 1);ch++;write(client_sockfd, &ch, 1);close(client_sockfd);
}
236
Sockets – Streams – close()
La fonction close() est utilisée pour fermer un descripteur de socket–Effectif seulement lorsque tous les processus partageant la socket ont appelé close()
En TCP, par défaut, close() retourne immédiatement–Normalement, génère l'envoi d'un segment FIN–Il se peut que certaines données n'aient pas encore été transmises ou reçues
•Si des données sont encore dans le buffer de réception, envoi d'un RST–Timeout TCP
Durant les timeouts TCP, la socket continue d'exister dans le système–Par défaut, un nouveau bind() sur le même port échouera
Lorsqu'un hôte distant termine son coté de la connexion, read() retourne 0
237
Sockets – Streams – shutdown()
La fonction shutdown() permet de fermer une socket en mode connecté, en réception et/ou émission
#include <sys/socket.h> int shutdown(int sockfd, int how);
–sockfd : descripteur–how :
•SHUT_RD : ferme en réception–Des données déjà dans le buffer de réception sont ignorées
•SHUT_WR : ferme en émission–Des données déjà dans le buffer d'émission sont envoyées
•SHUT_RDWR : ferme en réception et en émission–→ retourne 0 ou -1 si erreur (avec errno)
shutdown() initie la fin d'une connexion (FIN) quelque soit le nombre de références sur la socket
238
Sockets – Streams – shutdown() – Exemple
sock = socket(AF_INET, SOCK_STREAM, 0);
/* ... */
write(sock, buffer, 1000000);
shutdown(sock, SHUT_WR);
while(1) {res = read(sock, buffer, 4000);if (res < 0) {
perror("reading");return -1;
}if (!res)
break;}close(sock);
239
Sockets – Sockets type datagramme
Socket du type SOCK_DGRAM
Protocole UDP dans le domaine AF_INET–Aucune vérification qu’un message envoyé est bien reçu–Les messages peuvent être reçu dans un ordre différent de l’ordre d’envoi–Aucun contrôle de flux–Aucun contrôle de congestion–Checksum à la fin du message
Deux modes de fonctionnement :–Socket non connectée :
•Chaque message est envoyé ou reçu potentiellement à ou depuis un hôte différent
–Socket connectée :•La socket est connecté avec à une adresse et un port, l’envoi ou la réception de messages se fait avec le même hôte
240
Sockets – Datagrammes – sendto() et recvfrom()
Les fonctions sendto() et recvfrom() permettent d’envoyer ou recevoir un message par une socket, non nécessairement en mode connectée
Les adresses de destination et provenance sont donc spécifiées
#include <sys/socket.h>ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen);ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
–sockfd : descripteur de socket–*buf : buffer–len : taille en octets de buf–flags : options (voir page sur send() et recv())–*addr : adresse du destinataire ou de l’émetteur–addr_len : taille en octets de addr–→ retournent le nombre d’octets lus ou écrits ou -1 si erreur (avec errno)
241
Sockets – Datagrammes – connect()
La fonction connect() peut être utilisé sur une socket SOCK_DGRAM
Cela n’implique pas une connexion protocolaire comme avec SOCK_STREAM
Tous les paquets envoyés le seront vers l’adresse spécifiée
Seuls les paquets venant de l’adresse spécifiée seront reçus
Il est donc ensuite possible d’utiliser read() et write() au lieu de recvfrom() et sendto()
Il est possible d’utiliser plusieurs fois connect() sur la même socket pour changer d’association
Une association peut être rompue en utilisant AF_UNSPEC
242
Sockets – Datagrammes – send() et recv()
Les fonctions send() et recv() permettent d’envoyer et recevoir des données à travers une socket en mode connecté
#include <sys/socket.h>int send(int sockfd, const void *msg, int len, int flags);int recv(int sockfd, void *msg, int len, int flags);
–sockfd : descripteur–*msg : buffer de données à envoyer ou reçues–len : taille du buffer–flags : 0 ou OU binaire entre :
•MSG_DONTROUTE : pas de routage à travers un gateway•MSG_DONTWAIT : opération non bloquante•MSG_OOB : message out-of-band (flag TCP URG)
–→ retourne le nombre d’octets envoyés ou lus ou -1 si erreur (avec errno)
243
Sockets – Principales options des sockets
SOL_SOCKET Description
SO_REUSADDR Permet de réutiliser une socket immédiatement
SO_KEEPALIVE Envoie des messages keep-alive (streams)
SO_LINGER Délai entre messages non envoyés et retour de close()
SO_BROADCAST Permet l’envoie ou reçoit des datagrammes broadcast
SO_SNDBUF Taille du buffer d’émission
SO_RCVBUF Taille du buffer de réception
SO_TYPE Permet de lire le type de socket
SO_DONTROUTE N’envoie pas de données à travers un gateway
TCP_NODELAY Désactive l’algorithme de Nagle
244
Sockets – setsockopt()
Les fonctions setsockopt() et getsockopt() permettent de spécifier ou relire les options d’une socket
#include <sys/socket.h>int setsockopt(int sockfd, int level, int optname, void *optval, socklen_t optlen);int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
–sockfd : descripteur–level : niveau de protocole (SOL_SOCKET, SOL_TCP, IPPROTO_TCP, …)–optname : nom de l’option–*optval : valeur de l’option–optlen : longueur de la valeur en octets–→ retourne 0 ou -1 si erreur (avec errno)
245
Sockets – SO_REUSADDR
Par défaut, refaire un bind() sur un même port lorsqu'une socket TCP est dans l'état TIME_WAIT échoue
–bind() retourne EADDRINUSE
L'option SO_REUSADDR permet de pouvoir réutiliser une socket TCP–Permet de relancer un serveur immédiatement
Exemple :
int sd = socket(AF_INET, SOCK_DGRAM, 0);if (sd < 0) return -1;
int yes = 1;setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof yes);
bind(sd,(struct sockaddr *)(&addr),sizeof(struct sockaddr));
/* ... */
246
Sockets – SO_LINGER
L'option SO_LINGER configure le comportement de close() si le buffer d'émission n'est pas vide
Avec SO_LINGER et son timeout activé, close() est bloquant jusqu'à ce que les données aient été envoyées, ou jusqu'à ce que le timeout expire
Avec SO_LINGERmais avec un timeout nul, close() retourne immédiatement et un RST est envoyé à l'hôte distant
L'argument passé à setsocktopt() est une structure :
struct linger {int l_onoff; // linger activé ou nonint l_linger; // délai en secondes
};
247
Sockets – Multicast
La fonction setsockopt() permet de joindre ou quitter un groupe multicast
setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,struct ip_mreq *mreq, sizeof
(ip_mreq));setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
struct ip_mreq *mreq, sizeof (ip_mreq));
struct ip_mreq {struct in_addr imr_multiaddr; // Adresse IP multicaststruct in_addr imr_interface; // Adresse IP locale
};
En multicast, il est nécessaire d’autoriser l’utilisation répétée d’une adresse IP :
char one = 1;setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(char));
248
Sockets – Multiplexage
Le multiplexage permet à un serveur de traiter plusieurs connexions clientes simultanément
Plusieurs implémentations possibles :–Utiliser un processus par client (fork() après accept())–Utiliser une réserve de processus (plusieurs fork() avant accept())–Utiliser un thread par client (pthread_create() après accept())–Utiliser une réserve de thread (pthread_create() avant accept())–Utiliser une réserve de sockets (select() ou poll())
249
Sockets – Multiplexage – Exemple forking
/* Toutes les conditions d’erreurs ne sont pas vérifiées dans cet exemple */
/* socket(), bind() et listen() ont été appelées à ce point */
while(1){
new_sock = accept(server_sock, NULL, NULL);if ((pid = fork()) == 0){
/* processus fils */close(server_sock);nread = read(new_sock, buffer, 25, 0);/* ... */close(new_sock);exit(EXIT_SUCCESS);
} else {/* processus parent */close(new_sock);
}}
250
Sockets – Multiplexage – Exemple pre-forking
/* Toutes les conditions d’erreurs ne sont pas vérifiées dans cet exemple */
/* socket(), bind() et listen() ont été appelées à ce point */
for (x = o; x < MAX_CHILDREN; ++x){if ((pid = fork()) == 0){/* process fils */while(1){new_sock = accept(server_sock, NULL, NULL);nread = read(new_sock, buffer, 25, 0);/* ... */close(new_sock);}}}
251
Sockets – Multiplexage – Exemple threaded
/* Toutes les conditions d’erreurs ne sont pas vérifiées dans cet exemple */
/* socket(), bind() et listen() ont été appelées à ce point */
while(1){
new_sock = accept(server_sock, NULL, NULL);pthread_create(&thread_id, NULL, &thread_proc, (void *) new_sock);pthread_detach(thread_id);
}
void thread_proc(void *arg){
int sock = (int) arg;int nread = read(sock, buffer, 25, 0);/* ... */close(sock);
}
252
Sockets – select()
La fonction select() permet de surveiller (attente d’un événement) plusieurs descripteurs (donc sockets) à la fois
La fonction distingue trois ensembles de descripteurs à surveiller en lecture, écriture et exceptions
En retour, la fonction ne garde dans chaque ensemble que les descripteurs ayant eu un événement
Les ensembles de descripteurs sont placés dans une variable de type fd_set
Des macros permettent de manipuler les variables de type fd_set :–FD_SET(int fd, fd_set *set); // Ajoute fd à l'ensemble–FD_CLR(int fd, fd_set *set); // Enlève fd de l'ensemble–FD_ISSET(int fd, fd_set *set);// Vrai si fd est dans l'ensemble–FD_ZERO(fd_set *set); // Efface l'ensemble
Un ensemble ne peut contenir plus de FD_SETSIZE descripteurs
253
Sockets – select() (suite)
#include <sys/select.h>int select(int n, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval timeout);
–n : valeur du descripteur le plus élevé des trois ensembles + 1–*readfds, *writefds, *exceptfds : ensembles de descripteurs à surveiller–timeout : délai d’attente ou NULL pour infini–→ retourne le nombre de descripteurs modifiés, 0 si timeout ou -1 si erreur (avec errno)
La fonction select() peut être utilisée avec tout type de descripteur
L’établissement d’une nouvelle connexion sur une socket est signalé dans l’ensemble de lecture
Un descripteur sur fichier régulier est toujours prêt en lecture si pas à la fin du fichier, et est toujours prêt en écriture
254
Sockets – select() – Exemple 1
#include <stdio.h>#include <sys/select.h>
int main(void){fd_set readfds;struct timeval tv;tv.tv_sec = 2;tv.tv_usec = 500000;FD_ZERO(&readfds);FD_SET(STDIN_FILENO, &readfds);
if (select(STDIN_FILENO + 1, &readfds, NULL, NULL, &tv) > 0) {if (FD_ISSET(STDIN_FILENO, &readfds))printf("Une touche a été appuyée\n");}else printf("Timeout.\n");
return 0;}
255
Sockets – select() – Exemple 2
/* socket(), bind() et listen() ont été appelées à ce point */
fd_set readset;FD_ZERO(&readfds);FD_SET(sockfd, &readfds);result = select(sockfd + 1, &readfds, NULL, NULL, NULL);if (result > 0) {if (FD_ISSET(sockfd, &readfds)) {result = read(sockfd, buffer, buffer_len);if (result == 0) {close(socket_fd); // hôte distant à fermé la connexion} else {/* ... */}}}else if (result < 0) {printf("Erreur sur select(): %s\", strerror(errno));}
256
Sockets – select() – Exemple 3
fd_set read_set, test_set;FD_ZERO(&read_set);FD_SET(sockfd, &read_set)max_sockfd = sockfd;while(1) {test_set = read_set;if (1 <= select(max_sockfd + 1, &test_set, NULL, NULL, NULL)) {for (var x = 0; x < max_sockfd; x++) {if (FD_ISSET(x, &test_set)) {if (x == sockfd) {int new_sock = accept(sockfd, NULL, NULL);FD_SET(new_sock, &read_set);max_sockdf = max(max_sockdf, new_sock)} else {nread = read(x, buffer, 25, 0)/* ... */close(x);FD_CLR(x, $read_set);}}}}}
257
Sockets – poll()
La fonction poll() s’apparente à select()
#include <poll.h>int poll(struct pollfd *fds, nfds_t nfds, int timeout);
–*fds : tableau de structure (voir ci-après):struct pollfd {int fd; // descripteur de fichiershort events;// événements à surveillershort revents; // événements retournés};
–nfds : nombre de structures dans fds–timeout : délai d’attente ou NULL pour infini–→ retourne le nombre de structures avec événements, 0 si timeout ou -1 si erreur (avec errno)
258
Sockets – poll() (suite)
Les événements sont définis avec un OU binaire :
–POLLIN : données reçues en attente–POLLPRI : données urgentes reçues (par exemple TCP OOB)–POLLOUT : écrire ne bloquerait pas–POLLHUP : déconnection de la connexion–POLLERR : condition d’erreur–POLLNVAL : descripteur invalide
En définissant _GNU_SOURCE :–POLLRDHUP : l’hôte distant a fermé sa socket (SOCK_STREAM)
259
Sockets – poll() – Exemple
struct pollfd fds[2];int ret, i;
fds[0].fd = open("/dev/dev0", O_WRONLY);fds[1].fd = open("/dev/dev1", O_WRONLY);/* ... Vérification de la validité des descripteurs ... */
fds[0].events = POLLOUT | POLLERR;fds[1].events = POLLOUT | POLLERR;
if ((ret = poll(fds, 2, timeout_msecs)) > 0) {for (i = 0; i < 2; ++i) {if (fds[i].revents & POLLERR) {/* ... gestion de l'erreur ... */}if (fds[i].revents & POLLOUT) {/* ... écriture sur le device ... */}}}
260
Sockets – Mode non bloquant
Les sockets peuvent être configurées en mode non bloquant
Les fonctions (accept(), connect(), read(), write(), etc) qui normalement bloquent retournent immédiatement
–Si l’opération n’est pas possible, elles retournent -1 et errno est égal à EAGAIN (or EWOULDBLOCK)
La fonction fcntl() est utilisée pour configurer un descripteur en mode non bloquant :
#include <fcntl.h>
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);/* ... */int flags = fcntl(sockfd, F_GETFL, 0);fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
261
Sockets – Domaine Unix
Les sockets du domaine Unix sont similaires dans le principe à un tube nommé
S'utilisent en SOCK_STREAM ou SOCK_DGRAM
L’adresse utilisée pour bind() ou connect() est un nom de fichier–Les sockets créées dans le système de fichiers ne peuvent être utilisées qu’avec l’API des sockets–Le fichier socket ne doit pas exister avant la création d’une nouvelle socket (le supprimer avec unlink())
La structure adresse du domaine Unix est :
struct sockaddr_un {sa_family_t sun_family; // Domaine : AF_UNIX ou AF_LOCALchar sun_path[104]; // Nom de fichier};
262
Sockets – Domaine Unix – Exemple serveur
/* Toutes les conditions d’erreurs ne sont pas vérifiées dans cet exemple */
#define SOCKET_FILE "/tmp/mysocket"
void server(void){
int server_sockfd, client_sockfd, client_len;struct sockaddr_un server_address;struct sockaddr_un client_address;char ch;
unlink(SOCKET_FILE);
server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
server_address.sun_family = AF_UNIX;strcpy(server_address.sun_path, SOCKET_FILE);bind(server_sockfd, (struct sockaddr *)&server_address,
sizeof(server_address));
263
Sockets – Domaine Unix – Exemple serveur (suite)
listen(server_sockfd, 5);
client_len = sizeof(client_address);
while(1){
client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address, &client_len);
read(client_sockfd, &ch, 1);ch++;write(client_sockfd, &ch, 1);close(client_sockfd);
}}
264
Sockets – Domaine Unix – Exemple client
/* Toutes les conditions d’erreurs ne sont pas vérifiées dans cet exemple */
#define SOCKET_FILE "/tmp/mysocket"
void client(void) {int sockfd;struct sockaddr_un address;char ch = 'A';
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
address.sun_family = AF_UNIX;strcpy(address.sun_path, SOCKET_FILE);connect(sockfd, (struct sockaddr *)&address, sizeof(address));write(sockfd, &ch, 1);read(sockfd, &ch, 1);printf("char from server = %c\n", ch);
close(sockfd);}
265
Sockets – socketpair()
La fonction socketpair() permet de créer une paire de sockets Unix connectées entre-elles, full-duplex
L’utilisation est similaire à pipe()
#include <sys/socket.h>int socketpair(int dom, int type, int protocol, int sv[2]);
–dom : domaine, toujours AF_UNIX ou AF_LOCAL–type : SOCK_STREAM ou SOCK_DGRAM–protocol : 0–sv : tableau de 2 descripteur–→ retourne 0 ou -1 si erreur (avec errno)
266
Sockets – socketpair() – Exemple
/* Toutes les conditions d’erreurs ne sont pas vérifiées dans cet exemple */
int sockets[2];socketpair(AF_UNIX, SOCK_STREAM, 0, sockets);
child = fork();if (child) {
/* processus parent. */close(sockets[0]);read(sockets[1], buf, 1024, 0); // danger de débordementprintf("-->%s\n", buf);write(sockets[1], DATA2, sizeof(DATA2));close(sockets[1]);
} else {/* processus fils */close(sockets[1]);write(sockets[0], DATA1, sizeof(DATA1));read(sockets[0], buf, 1024, 0); // danger de débordementprintf("-->%s\n", buf);close(sockets[0]);
}
267
ioctl
Netlink
Kernel-Space Netlink
RTNelink
268
ioctl
ioctl est un moyen de communication qui est, entre autres, utilisé pour paramétrer les options des sockets
L'interface ioctl est considérée obsolète, mais beaucoup de code l'utilise toujours (ex. ifconfig)
ioctl opère sur un descripteur de fichier, donc aussi une socket :
int ioctl(int descriptor, int ioctl_op, ...);
La liste des opérations est disponible avec man ioctl_list
269
ioctl – Structure ifreq
L'accès aux informations et à la configuration des interfaces réseau se fait avec un structure ifreq(net/if.h)
struct ifreq {
char ifr_name[IFNAMSIZ];
union {
struct sockaddr ifr_addr;
struct sockaddr ifr_dstaddr;
struct sockaddr ifr_broadaddr;
struct sockaddr ifr_netmask;
struct sockaddr ifr_hwaddr;
short ifr_flags;
int ifr_ifindex;
int ifr_metric;
int ifr_mtu;
struct ifmap ifr_map;
char ifr_slave[IFNAMSIZ];
char ifr_newname[IFNAMSIZ];
char *ifr_data;
};
};
270
ioctl – Structure ifreq – Opérations
SIOCGIFNAME
–En utilisant ifr_ifindex, renvoie le nom de l'interface dans ifr_name
SIOCGIFINDEX
–Retrouve le numéro d'interface et le place dans ifr_ifindex
SIOCGIFMETRIC, SIOCSIFMETRIC–Lire ou écrire le MTU du périphérique avec ifr_mtu
SIOCGIFHWADDR, SIOCSIFHWADDR–Lire ou écrire l'adresse matérielle du périphérique en utilisant ifr_hwaddr
271
ioctl – Structure ifreq – Attributs
SIOCADDMULTI, SIOCDELMULTI
–Ajouter ou supprimer une adresse des filtres multicast du niveau 2 du périphérique en utilisant ifr_hwaddr
SIOCGIFTXQLEN, SIOCSIFTXQLEN–Lire ou écrire la taille de la file d'émission du périphérique avec ifr_qlen
SIOCSIFNAME
–Changer le nom de l'interface indiquée dans ifr_name pour ifr_newname
SIOCGIFFLAGS, SIOCSIFFLAGS–Lire ou écrire les attributs actifs du périphérique
272
ioctl – Structure ifreq – Opérations
ifr_flags contient un masque de bits :–IFF_UP : Interface fonctionne–IFF_RUNNING : Ressources allouées–IFF_BROADCAST : Adresse de broadcast valide–IFF_LOOPBACK : Interface de type loopback–IFF_POINTOPOINT : Interface de type point-à-point–IFF_NOARP : Pas de protocole Arp–IFF_PROMISC : Interface en mode promiscuous–IFF_ALLMULTI : Accepte tous les paquets multicast–IFF_MULTICAST : Support multicast
273
ioctl – Structure ifreq – Exemple
/* Récupère l'adresse MAC de l'interface eth0 */
#include <sys/ioctl.h>#include <net/if.h>
void get_eth0_mac(unsigned char* mac_addr){
struct ifreq ifr;int sockfd;
sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
memset(&ifr, 0, sizeof(struct ifreq));memcpy(ifr.ifr_name, "eth0", IFNAMSIZ);
ioctl(sock_fd, SIOCGIFHWADDR, &ifr);memcpy(mac_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
close(sock_fd);}
274
ioctl – Structure ifconf
L'opération SIOCGIFCONF renvoie la liste des adresses IPv4
L'accès à la liste se fait à travers une structure ifconf qui contient un pointeur sur une table de structures ifreq :
struct ifconf {
int ifc_len;
union {
char* ifc_buf;
struct ifreq* ifc_req;
};
};
Pour chaque ifreq :–ifr_name contient le nom de l'interface–ifr_addr contient l'adresse MAC
275
ioctl – Structure ifconf
/* Récupère la liste des interfaces */
Void print_ifaces(void){
struct ifconf config;struct ifreq ifreq[128];int sock_fd, nb, ii;
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
memset(&config, 0, sizeof(struct ifconf));config.ifc_buf = (char*) ifreq;config.ifc_len = 128 * sizeof(struct ifreq);
ioctl(devices, SIOCGIFCONF, (char *) &config);
nb = config.ifc_len / (sizeof(struct ifreq));for (ii = 0; ii < nb; ii++) {
printf("Interface : %s\n", ifreq[ii].ifr_name);}close(sock_fd);
}
276
Netlink
Netlink est un mécanisme de transfert d'informations entre le noyau et les processus de l'espace utilisateur, ou entre les processus d'une même machine
Netlink est conçu et utilisé pour transférer des informations relatives à la pile réseau
Netlink est le successeur de l'interface ioctl
Interface basée sur les sockets standards pour les processus utilisateur
API interne pour les modules du noyau
277
Netlink – nlmsghdr
Une socket Netlink fonctionne un peu comme une socket raw
Contrairement aux protocoles comme TCP, où les entêtes sont auto-générées, l'entête des messages Netlink doit être préparée par le programme
L'entête du message Netlink est définie dans cette structure :
struct nlmsghdr
{
__u32 nlmsg_len; /* Longueur y compris en-tête */
__u16 nlmsg_type; /* Contenu message */
__u16 nlmsg_flags; /* Attributs supplémentaires */
__u32 nlmsg_seq; /* Numéro de séquence */
__u32 nlmsg_pid; /* PID du créateur socket */
};
278
Pour créer un socket Netlink :int socket(PF_NETLINK, int type, int protocol);
type :–SOCK_RAW et SOCK_DGRAM sont des valeurs possibles pour le type de la socket
protocol :–sélectionne le module du noyau ou le groupe Netlink avec qui communiquer
Netlink – socket()
279
Netlink – Protocoles
NETLINK_ROUTE
–Reçoit les modifications de routage et peut être utilisé pour mettre à jour les tables de routage IPv4
NETLINK_ROUTE6
–Reçoit et envoie les mise à jour de la table de routage IPv6
NETLINK_FIREWALL
–Reçoit les paquets envoyés par le code du firewall
NETLINK_IP6_FW
–Pour recevoir les paquets rejetés par le firewall IPv6
280
Netlink – Protocoles
NETLINK_ARPD
–Pour gérer la table Arp dans l'espace utilisateur
NETLINK_NFLOG
–Interface entre Netfilter et iptables
NETLINK_AUDIT
–Fournit une interface sur le sous-système
NETLINK_USERSOCK
–Réservé pour les protocoles dans l'espace utilisateur
281
Netlink – bind()
Comme pour une socket IP, bind() associe une adresse locale avec
une socket
La structure d'adresse Netlink est :
struct sockaddr_nl
{
sa_family_t nl_family; /* AF_NETLINK */
unsigned short nl_pad; /* zero */
__u32 nl_pid; /* process pid */
__u32 nl_groups; /* mcast groups mask */
}
282
Netlink – bind()
Le champ nl_pid sert d'adresse locale–L'application doit donc choisir un entier unique :
Si pour un même processus, une seule socket pour un protocole Netlink particulier est utilisée :
–nl_pid = getpid();
Si pour un même processus, plusieurs sockets pour un protocole Netlink particulier sont utilisées :
–nl_pid = pthread_self() << 16 |
getpid();
283
Netlink – bind()
Il est possible de définir jusqu'à 32 groupes multicast pour chaque famille Netlink
–1<<i avec 0 <= i <=31
Utilisé lorsqu'un groupe de processus et le noyau s'entendent sur une fonctionnalité commune
Pour recevoir des messages multicast :–nl_groups = bitmask des groupes visés
Si pas de groupes multicast :–nl_groups = 0;
284
Netlink – sendmsg()
Pour envoyer un message Netlink au noyau ou à un autre processus, une structure sockaddr_nl doit être utilisée comme adresse de destination, et fournie à une structure msghdr
Message est à destination du noyau :–nl_pid = nl_groups = 0;
Message unicast à destination d'un autre processus :–nl_pid = nl_pid du processus visé–nl_groups = 0;
Message multicast :–nl_groups = bitmask des groupes visés
285
Netlink – sendmsg()
L'entête des messages Netlink doit être fournie par le programme :
struct nlmsghdr
{
__u32 nlmsg_len; /* Length of message */
__u16 nlmsg_type; /* Message type*/
__u16 nlmsg_flags; /* Additional flags */
__u32 nlmsg_seq; /* Sequence number */
__u32 nlmsg_pid; /* Sending process PID */
};
286
Netlink – sendmsg()
–nlmsg_len : longueur totale du message incluant le header
–nlmsg_type : permet d'indiquer un message à ignorer, un message d'erreur, ou un message multi-parties
–nlmsg_flags : attributs supplémentaires pour messages de requête, messages multi-parties, demandes d'acquittements, etc.
–nlmsg_seq et nlmsg_pid : pas de signification particulière, libre à l'application de les utiliser
287
Netlink – sendmsg()
Pour les messages multi-parties :–Tous les entêtes ont l'attribut NLM_F_MULTI actif, sauf le dernier en-tête qui a le type NLMSG_DONE
Le flux d'octets du message ne doit être accédé qu'à travers les macros standards NLMSG_*
–Similaires aux macros CMSG_*
Finalement le message en lui-même est attaché à la structure msghdr et envoyé avec sendmsg()
288
Netlink – sendmsg() – Exemple
/* Toutes les conditions d'erreur ne sont pas vérifiées */
#include <sys/socket.h>#include <linux/netlink.h>
struct sockaddr_nl src_addr, dest_addr;struct nlmsghdr *nlh = NULL;struct iovec iov;int sock_fd;
sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USERSOCK);
memset(&src_addr, 0, sizeof(src_addr));src_addr.nl_family = AF_NETLINK;src_addr.nl_pid = getpid();src_addr.nl_groups = 0;bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));
289
Netlink – sendmsg() – Exemple
memset(&dest_addr, 0, sizeof(dest_addr));dest_addr.nl_family = AF_NETLINK;dest_addr.nl_pid = 0;dest_addr.nl_groups = 0;
nlh = (struct nlmsghdr*) malloc(NLMSG_SPACE(1024));nlh->nlmsg_len = NLMSG_SPACE(1024);nlh->nlmsg_pid = getpid();nlh->nlmsg_flags = 0;strcpy(NLMSG_DATA(nlh), "Hello world");
iov.iov_base = (void *)nlh;iov.iov_len = nlh->nlmsg_len;msg.msg_name = (void *)&dest_addr;msg.msg_namelen = sizeof(dest_addr);msg.msg_iov = &iov;msg.msg_iovlen = 1;
sendmsg(fd, &msg, 0);
290
Netlink – recvmsg()
Une application désirant recevoir un message Netlink doit allouer un buffer suffisamment large
La réception se fait à travers une structure msghdr pointant sur une structure sockaddr_nl
Après réception, le membre nlh pointe sur l'entête du message
La macro NLMSG_DATA retourne un pointeur sur les données
291
Netlink – recvmsg() – Exemple
struct sockaddr_nl nladdr;struct msghdr msg;struct iovec iov;char data[1024];
iov.iov_base = (void*) nlh;iov.iov_len = MAX_NL_MSG_LEN;
msg.msg_name = (void*) &nladdr;msg.msg_namelen = sizeof(nladdr);msg.msg_iov = &iov;msg.msg_iovlen = 1;recvmsg(fd, &msg, 0);
strncpy(data, NLMSG_DATA(nlh), 1023);data[1023] = '\0';
292
Kernel-Space Netlink
293
Netlink – Noyau
L'API Netlink du noyau peut être utilisée par des modules pour communiquer avec des programmes d'espace utilisateur
L'API Netlink du noyau est dans net/netlink/af_netlink.c
Il est possible d'ajouter son propre protocole Netlink dans include/linux/netlink.h
#define NETLINK_ROUTE 0
/* … */
#define NETLINK_GENERIC 16
#define NETLINK_EUROGICIEL 17
294
Netlink – netlink_kernel_create
Pour créer une socket Netlink dans le noyau :
struct sock*
netlink_kernel_create(int unit,
void (*input)(struct
sock *sk, int len));
–unit : protocol Netlink–input : pointeur sur fonction appelée quand un message arrive
295
Netlink – netlink_kernel_create
Exemple de callback :
void input (struct sock *sk, int len)
{
struct sk_buff *skb;
struct nlmsghdr *nlh = NULL;
u8 *payload = NULL;
while ((skb = skb_dequeue(&sk->receive_queue))
!= NULL) {
nlh = (struct nlmsghdr *)skb->data;
payload = NLMSG_DATA(nlh);
}
}
296
Netlink – netlink_kernel_create
La fonction callback est exécutée suite à l'appel à sendmsg() en espace utilisateur
–sendmsg() est bloquante jusqu'au retour de la fonction callback
Si la fonction callback devait prendre beaucoup de temps, il faudrait déferrer son travail
Par exemple :–Un thread noyau qui lit sur la socket retournée :
skb = skb_recv_datagram(nl_sk);
–La fonction callback débloque ce thread à réception :wake_up_interruptible(sk->sleep);
297
Netlink – netlink_unicast
Pour envoyer une message unicast :
int netlink_unicast(struct sock *ssk,
struct sk_buff *skb, u32 pid, int
nonblock);
–ssk : socket retournée par netlink_kernel_create()–skb : adresses source et destination :
NETLINK_CB(skb).groups = 0;
NETLINK_CB(skb).pid = 0;
NETLINK_CB(skb).dst_groups = 0;
NETLINK_CB(skb).dst_pid = dst_pid;
–pid : PID du processus visé–nonblock : API bloquante ou non
298
Netlink – netlink_broadcast
Pour envoyer une message multicast :
int netlink_broadcast(struct sock *ssk, struct
sk_buff *skb, u32 pid, u32 group, int allocation);
–A la différence de la version unicast, on précisera les groupes :NETLINK_CB(skb).groups = dst_group;
NETLINK_CB(skb).dst_groups = dst_groups;
NETLINK_CB(skb).dst_pid = 0;
group = dst_groups;
–allocation : GFP_ATOMIC ou GFP_KERNEL
299
Netlink – netlink_broadcast
Pour envoyer une message multicast :
int netlink_broadcast(struct sock *ssk, struct
sk_buff *skb, u32 pid, u32 group, int allocation);
–A la différence de la version unicast, on précisera les groupes :NETLINK_CB(skb).dst_groups = dst_groups;
NETLINK_CB(skb).dst_pid = 0;
group = dst_groups
–allocation : GFP_ATOMIC ou GFP_KERNEL
300
Netlink – Noyau
struct sock *nl_sk = NULL;
void nl_data_ready (struct sock *sk, int len){wake_up_interruptible(sk->sleep);
}
void netlink_test(){struct sk_buff *skb = NULL;struct nlmsghdr *nlh = NULL;int err;u32 pid;
nl_sk = netlink_kernel_create(NETLINK_TEST, nl_data_ready);
skb = skb_recv_datagram(nl_sk, 0, 0, &err);
301
Netlink – Noyau
nlh = (struct nlmsghdr *)skb->data;printk("message reçcu : %s\n", NLMSG_DATA(nlh));
pid = nlh->nlmsg_pid;NETLINK_CB(skb).groups = 0;NETLINK_CB(skb).pid = 0;NETLINK_CB(skb).dst_pid = pid;NETLINK_CB(skb).dst_groups = 0;netlink_unicast(nl_sk, skb, pid, MSG_DONTWAIT);
sock_release(nl_sk->socket);}
302
RTNetlink
303
RTNetlink
RTNetlink permet de lire et modifier :–Les tables de routage–Les adresses IP–Les paramètres de liaison–La configuration du voisinage–Les files, les classes de trafic et les classes de paquets
Basé sur les sockets Netlink
304
RTNetlink – Attributs
Certains messages Netlink ont des attributs supplémentaires après l'en-tête initial :
struct rtattr {
unsigned short rta_len; /* Longueur option */
unsigned short rta_type; /* Type d'option */
/* Les données suivent... */
};
Ces attributs ne doivent être manipulés qu'en utilisant les macros RTA_*
305
RTNetlink – Messages – Link
RTNetlink est constitué de trois types de messages :
RTM_NEWLINK, RTM_DELLINK, RTM_GETLINK–Crée, supprime, ou renvoie des informations d'une interface réseau–Une structure ifinfomsg suivie d'une série de rtattr
struct ifinfomsg {
unsigned char ifi_family; /* AF_UNSPEC */
unsigned short ifi_type; /* Type périphérique */
int ifi_index; /* Index interface */
unsigned int ifi_flags; /* Attributs périph. */
unsigned int ifi_change; /* Masque modificat. */
};
306
RTNetlink – Messages – Link
–ifi_flags : contient les attributs du périphérique (comme pour la structure ifreq)–ifi_change : réservé et doit toujours valoir 0xFFFFFFFF
–rta_type :•IFLA_ADDRESS : adresse MAC•IFLA_BROADCAST : adresse broadcast MAC•IFLA_IFNAME : nom du périphérique•IFLA_MTU : MTU du périphérique•IFLA_LINK : type de liaison•IFLA_QDISC : Mécanismes files•IFLA_STATS : struct net_device_stats
307
RTNetlink – Messages – Addr
RTM_NEWADDR, RTM_DELADDR, RTM_GETADDR
–Ajoute, supprime ou renvoie des informations sur une adresse IP associée à une interface–Une structure ifaddrmsg, suivie éventuellement par une structure rtaddr
struct ifaddrmsg {
unsigned char ifa_family; /* Type adresse */
unsigned char ifa_prefixlen;/* Longueur masque */
unsigned char ifa_flags; /* Attributs adresse */
unsigned char ifa_scope; /* Portée adresse */
int ifa_index; /* Index interface */
};
308
RTNetlink – Messages – Addr
–ifa_family : AF_INET ou AF_INET6–ifa_prefixlen : longueur du masque d'adresse–ifa_scope : portée de l'adresse–ifa_index : index de l'interface associée à l'adresse–ifa_flags : IFA_F_PERMANENT, IFA_F_SECONDARY
–rta_type :•IFA_ADDRESS : Adresse de l'interface•IFA_LABEL : Nom de l'interface•IFA_BROADCAST : Adresse broadcast•IFA_ANYCAST : Adresse anycast
309
RTNetlink – Messages – Route
RTM_NEWROUTE, RTM_DELROUTE, RTM_GETROUTE –Crée, supprime ou renvoie des informations à propos d'une route–Une structure rtmsg suivie d'une séquence éventuelle de structures rtattr
struct rtmsg {
unsigned char rtm_family; /* Famille d'adresse */
unsigned char rtm_dst_len; /* Longueur source */
unsigned char rtm_src_len; /* Longueur dest. */
unsigned char rtm_tos; /* Filtre TOS */
unsigned char rtm_table; /* ID table routage */
unsigned char rtm_protocol;/* Cf page suivante */
unsigned char rtm_scope; /* Cf page suivante */
unsigned char rtm_type; /* Cf page suivante */
unsigned int rtm_flags;
};
310
RTNetlink – Messages – Route
–Pour RTM_GETROUTE : mettre rtm_dst_len et rtm_src_len à 0 signifie obtenir toutes les entrées pour la table de routage indiquée–Pour les autres champs, sauf rtm_table et rtm_protocol, 0 est le symbole générique signifiant "toutes valeurs"–rtm_type :
•RTN_UNICAST, RTN_LOCAL, RTN_ANYCAST, RTN_MULTICAST, RTN_BLACKHOLE, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_THROW, RTN_NAT
–rtm_protocol :•RTPROT_KERNEL, RTPROT_BOOT, RTPROT_STATIC
–rtm_scope :•RT_SCOPE_UNIVERSE, RT_SCOPE_SITE, RT_SCOPE_LINK, RT_SCOPE_HOST, RT_SCOPE_NOWHERE
RTNetlink – Messages – Route
–rtm_flags :•RTM_F_NOTIFY, RTM_F_CLONED
–rtm_table :•RT_TABLE_UNSPEC, RT_TABLE_DEFAULT, RT_TABLE_MAIN, RT_TABLE_LOCAL
–rta_type :•RTA_DST, RTA_SRC : adresses destination et source•RTA_IIF, RTA_OIF : interfaces d'entrée et de sortie•RTA_GATEWAY : adresse de passerelle•RTA_PRIORITY : priorité de la route•RTA_METRICS : métrique de la route
312
RTNetlink – Messages – Neighbor
RTM_NEWNEIGH, RTM_DELNEIGH, RTM_GETNEIGH
–Ajoute, supprime ou renvoie des informations sur les voisinage d'un élément de table (ex : entrée ARP)–Contient une structure ndmsg
struct ndmsg {
unsigned char ndm_family;
int ndm_ifindex; /* Index interface */
__u16 ndm_state; /* États */
__u8 ndm_flags; /* Attributs */
__u8 ndm_type;
};
313
RTNetlink – Messages – Neighbor
struct nda_cacheinfo
{
__u32 ndm_confirmed;
__u32 ndm_used;
__u32 ndm_updated;
__u32 ndm_refcnt;
};
–ndm_state : champ de bits :•NUD_INCOMPLETE : entrée non résolue•NUD_REACHABLE : entrée confirmée correcte•NUD_STALE : entrée expirée•NUD_DELAY : entrée en attente de time•NUD_PROBE : entrée en cours de vérification
314
RTNetlink – Messages – Neighbor
–ndm_state : (suite)•NUD_FAILED : entrée invalide•NUD_NOARP : périphérique sans cache de destination•NUD_PERMANENT : entrée permanente
–ndm_flags :•NTF_PROXY : entrée proxy Arp•NTF_ROUTER : routeur IPv6
–rta_type :•NDA_DST : adresse niveau réseau•NDA_LLADDR : adresse niveau liaison
315
RTNetlink – Exemple
/* Récupère la liste des interfaces réseau */
#include <linux/netlink.h>#include <linux/rtnetlink.h>
typedef struct nl_req_s nl_req_t;struct nl_req_s {
struct nlmsghdr hdr;struct rtgenmsg gen;
};
int main(int argc, char **argv){
int fd;struct sockaddr_nl local;struct sockaddr_nl kernel;struct msghdr rtnl_msg;struct iovec io;nl_req_t req;char reply[8192];pid_t pid = getpid();int end = 0;
fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
316
RTNetlink – Exemple
memset(&local, 0, sizeof(local));local.nl_family = AF_NETLINK;local.nl_pid = pid;local.nl_groups = 0;bind(fd, (struct sockaddr *) &local, sizeof(local));
memset(&rtnl_msg, 0, sizeof(rtnl_msg));memset(&kernel, 0, sizeof(kernel));memset(&req, 0, sizeof(req));
kernel.nl_family = AF_NETLINK;
req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));req.hdr.nlmsg_type = RTM_GETLINK;req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;req.hdr.nlmsg_seq = 1;req.hdr.nlmsg_pid = pid;req.gen.rtgen_family = AF_PACKET;
io.iov_base = &req;io.iov_len = req.hdr.nlmsg_len;rtnl_msg.msg_iov = &io;rtnl_msg.msg_iovlen = 1;rtnl_msg.msg_name = &kernel;rtnl_msg.msg_namelen = sizeof(kernel);
317
RTNetlink – Exemple
while (!end) {
int len;struct nlmsghdr *msg_ptr;struct msghdr rtnl_reply;struct iovec io_reply;
memset(&io_reply, 0, sizeof(io_reply));memset(&rtnl_reply, 0, sizeof(rtnl_reply));
io.iov_base = reply;io.iov_len = IFLIST_REPLY_BUFFER;
rtnl_reply.msg_iov = &io;rtnl_reply.msg_iovlen = 1;rtnl_reply.msg_name = &kernel;rtnl_reply.msg_namelen = sizeof(kernel);
len = recvmsg(fd, &rtnl_reply, 0);
318
RTNetlink – Exemple
if (len) {
for (msg_ptr = (struct nlmsghdr *) reply; NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len))
{switch(msg_ptr->nlmsg_type){case 3: /* NLMSG_DONE */
end++;break;
case 16: /* RTM_NEWLINK */rtnl_print_link(msg_ptr);break;
default:}
}}
}
close(fd);}
319
RTNetlink – Exemple
void rtnl_print_link(struct nlmsghdr *h){
struct ifinfomsg *iface;struct rtattr *attribute;int len;
iface = NLMSG_DATA(h);len = h->nlmsg_len - NLMSG_LENGTH(sizeof(*iface));
for (attribute = IFLA_RTA(iface); RTA_OK(attribute, len); attribute = RTA_NEXT(attribute, len)) {
switch(attribute->rta_type) {case IFLA_IFNAME:
printf("Interface %d : %s\n", iface->ifi_index, (char *) RTA_DATA(attribute));break;
default:break;
}}
}
320
Environ 10000 lines of code in the Linux Kernel ;Travaux initiés par Sébastien Barré ;Désormais 3 threads actifs sont suivis coté développement
noyau par :Christoph PaaschFabien DuchêneGregory Detal
Disponible gratuitement : http://mptcp.info.ucl.ac.be
MPTCP (MultiPath TCP)
Entête MPTCP
Source Port Destination Port
Sequence Number
Acknowledgment Number
Receive WindowHeader
LengthReserved Code bits
Checksum
Options
Urgent Pointer
Data
Bit 0 Bit 15 Bit 16 Bit 31
20
Bytes
0 - 40
Bytes
Subflow
Subflow
Subflow Subflow
Data sequence number Data ACK
Création d’une session MPTCP
Création d’une socket TCP
Création d’une socket MPTCP
Création d’une méta-socket par le noyau
Création de nouveau subflow
Association des différents MPTCP subflow par le noyau
7. Captures & simulations
–Captures réseau (tcpdump, wireshark, …)–Outils de monitoring (iptraf, iperf, …)–Utilisation de la librairie libpcap–Présentation de NS2/3
Outils
Il existes pléthore d’outils :–Tcpprobe– iperf–netperf–netPIPE–gensink–Ttcp–curl-loader–Nttcp–n-u-t-t-c-p–ISIC–tcpdump / wireshark–…
http://www.ubuntugeek.com/bandwidth-monitoring-tools-for-linux.html
TCPDUMP
tcpdump est un analyseur de paquets en ligne de commande. Il permet d'obtenir le détail du
trafic visible depuis une interface réseau. L'outil distribué par les distributions GNU/Linux,
FreeBSD, NetBSD, OpenBSD et Mac OS X dépend de la bibliothèque logicielle libpcap. Leur
portage sous Windows est connu sous les appellations WinPCAP/WinDUMP.
tcpdump et libpcap sont développés en 1987 au laboratoire national Lawrence Berkeley aux
États-Unis par Van Jacobson, Steven McCanne et Craig Leres, le créateur d'arpwatch. Vers la
fin des années 1990, tcpdump est distribué dans de nombreux systèmes ce qui ne favorisait
guère l'application de correctifs. Michael Richardson (mcr) et Bill Fenner créent un site officiel
en 1999 pour répondre à ce manque de coordination et deviennent alors les mainteneurs du
projet.
La bibliothèque logicielle libpcap est à l'origine développée pour l'outil tcpdump mais peut être
utilisée par tous les analyseurs de paquets. Elle fournit en effet une interface de programmation
pour de tels programmes leur permettant de capturer et d'analyser n'importe quel paquet
(réseau) à partir d'un périphérique réseau (en). La librairie est également distribuée
séparément pour compiler ou programmer soi-même de tels outils.
TCPDump
tcpdump [ -AdDefIKlLnNOpqRStuUvxX ] [ -B buffer_size ] [ -c count ]
[ -C file_size ] [ -G rotate_seconds ] [ -F file ]
[ -i interface ] [ -m module ] [ -M secret ]
[ -r file ] [ -s snaplen ] [ -T type ] [ -w file ]
[ -W filecount ]
[ -E spi@ipaddr algo:secret,... ]
[ -y datalinktype ] [ -z postrotate-command ] [ -Z user ]
[ expression ]
TCPDUMP
Cette commande va capturer les paquets et sauvegarder le tout dans le fichier
capture.dump:
# tcpdump -v -r capture.dump
Si vous souhaitez maintenant afficher le contenu de ce fichier avec l'option -r, il faut
taper la commande:
reading from file capture.dump, link-type EN10MB (Ethernet)
13:28:09.495897 IP (tos 0x0, ttl 64, id 47730, offset 0, flags [DF], proto: TCP (6),
length: 52) 192.168.29.246.49084 > ftp.fu-berl
in.de.60772: ., cksum 0x13d0 (correct), ack 1339443207 win 2003
13:28:09.503376 IP (tos 0x0, ttl 64, id 47731, offset 0, flags [DF], proto: TCP (6),
length: 52) 192.168.29.246.49084 > ftp.fu-berl
in.de.60772: ., cksum 0x0e1d (correct), ack 1449 win 2003
13:28:09.506374 IP (tos 0x0, ttl 64, id 47732, offset 0, flags [DF], proto: TCP (6),
length: 52) 192.168.29.246.49084 > ftp.fu-berl
in.de.60772: ., cksum 0x0872 (correct), ack 2897 win 2003
TCPDUMP
Quelques exemples (consulter le man tcpdump pour une liste exhaustive):
# tcpdump host www.google.fr
Affiche seulement les paquets qui ont pour adresse source ou destination www.google.fr:
# tcpdump dst www.google.fr
Affiche seulement les paquets qui ont pour adresse destination www.google.fr
# tcpdump port http
Affiche seulement les paquets HTTP (web):
# tcpdump proto gre
Affiche seulement les paquets GRE (utilisés lors de tunnel ipsec). Il est bien sur possible de
mixer plusieurs filtres:
# tcpdump dst 192.168.29.10 and port domain
Affiche tous les paquets DNS (domain) à destination de l'adresse 192.168.29.10
TCPDUMP
# tcpdump –v
...
11:34:23.480144 IP (tos 0x0, ttl 64, id 10784, offset 0, flags [DF], proto: UDP (17), length: 67) 192.168.29.246.32794 >
192.168.29.1.domain: 8576+ A? ftp.redhat.ikoula.com. (39)
...
On peut alors voir les informations supplémentaires suivantes:
(tos 0x0, ttl 64, id 10784, offset 0, flags [DF], proto: UDP (17), length: 67)
Associés au champs IP, elle fournie des informations sur le protocole (flags, protocole UDP, taille du paquet...).
8576+ A? ftp.redhat.ikoula.com. (39)
Donne un apercu du champ data (dans notre exemple, on peut voir que c'est une requête DNS qui demande l'adresse
IP du serveur ftp.redhat.ikoula.com)
Si vous voulez encore plus d'informations, vous pouvez utiliser les options -vv et même –vvv. Si vous souhaité avoir
un dump du contenu du de chaque paquet, vous pouvez utiliser l'option -A, par exemple:
# tcpdump -v –A
11:46:00.607145 IP (tos 0x0, ttl 64, id 33771, offset 0, flags [DF], proto: TCP (6), length: 765) 192.168.29.157.49659 >
mu-in-f104.google.com.http: P 1543672215:1543672940(725) ack 1290089933 win 65535
E.....@.@.}......U.h...P...L.5.P...9...GET / HTTP/1.1
Host: www.google.fr
User-
WIRESHARK
Wireshark est un analyseur de paquets libre utilisé dans le dépannage et l'analyse de
réseaux informatiques, le développement de protocoles, l'éducation et la rétro-ingénierie. Son
appellation d'origine (Ethereal) est modifiée en mai 2006 pour des questions relatives au droit
des marques.
Wireshark utilise la bibliothèques logicielles GTK+ pour l'implémentation de son interface
utilisateur et pcap pour la capture des paquets; il fonctionne sur de nombreux environnements
compatibles UNIX comme GNU/Linux, FreeBSD, NetBSD, OpenBSD ou Mac OSX, mais
également sur Microsoft Windows.
Wireshark reconnaît 759 protocoles.
À la fin des années 1990, Gerald Combs est diplômé de l'Université du Missouri-Kansas City
et travaille au sein d'un petit fournisseur d'accès à Internet. L'analyseur de protocole utilisé en
interne est un logiciel propriétaire commercialisé près de 1500 $2 et ne fonctionne pas sur la
plateforme de production de la société (GNU/Linux et Solaris). Gerald Combs débute alors les
développements d'Ethereal et réalise sa première version en 19983.
En mai 2006, Combs intègre la société CACE Technologies. Il clone alors le dépôt SVN du
projet Ethereal sur son propre dépôt de code source Wireshark en toute légalité puisqu'il
détient les droits d'auteur sur la majeure partie du code source d'Ethereal, le reste étant
également distribué selon les termes de la licence publique générale GNU. Il n'est toutefois pas
propriétaire de la marque Ethereal et change donc le nom de son projet en Wireshark.
WIRESHARK
http://www.thegeekstuff.com/2010/08/tcpdump-command-examples/
WIRESHARK
Mesure de la bande passante :
WIRESHARK
Statistics > Summary
IPERF
iperf -s
------------------------------------------------------------
Server listening on TCP port 5001
TCP window size: 60.0 KByte (default)
------------------------------------------------------------
[ 4] local <IP Addr node2> port 5001 connected with <IP Addr node1> port 2357
[ ID] Interval Transfer Bandwidth
[ 4] 0.0-10.1 sec 6.5 MBytes 5.2 Mbits/sec
Iperf est un logiciel informatique permettant la mesure de différentes variables
d'une connexion réseau IP. Iperf est développé par le National Laboratory for
Applied Network Research (NLANR, États-Unis d'Amérique). Basé sur une
architecture client/serveur et disponible sur différents systèmes d'exploitation (Unix,
Windows, MacOS X,...).
Iperf doit être lancé sur deux machines se trouvant de part et d'autre du réseau à
tester. La première machine lance Iperf en "mode serveur" (avec l'option -s), la
seconde en "mode client" (option -c). Par défaut le test réseau se fait en utilisant le
protocole TCP (mais il est également possible d'utiliser le mode UDP avec l'option -
u).
IPERF
IPTRAF
Ip traffic monitor : vous allez pouvoir voir toutes les connections entrantes et
sortantes, les ports et protocoles, ainsi que les IP des connexions….un peu
brouillon, mais cela permet de voir precisement pour une IP le volume de data qui
transite
General interface statistics : c’est le menu du volume brut qui transite
Detailled interface statistics : vous devez indiquer quelle interface vous désirez
voir, et vous aurez des statistiques détaillées de son utilisation (entrée et sortie,
TCP et UDP, IP et non IP, icmp, broadcast….), c’est très intéressant.
Statistical breakdowns : information par paquet ou par protocole transitant par
une interface, assez intéressant à étudier.
Lan station monitor : les adresses macs et le volume de donnée transitant par
elles….inutile donc indispensable
Mesure TCP
Lorsque l’on expérimente autour de bande passante variable il peut être
nécessaire de changer la taille maximum de la fenêtre TCP disponible. La couche
TCP est paramétrable (Documentation/networking/ip-sysctl.txt). Lorsqu’un le
minimum est atteint, tcp_rmem[2] est incrémenté pour le reçeveur et
tcp_wmem[2] pour l’émetteur et ce deux fois.
Il peut être aussi nécessaire de de désactiver les métrique lié aux routes :
sysctl -w net.ipv4.tcp_no_metrics_save=1
Normalement Linux doit se souvenir du dernier démarrage lent (ssthresh). Cela
modifiera le résultat du prochain test et causera une erreur
Mesure TCP
A basic test would be:
Start iperf server on the receiver : iperf -s
Insert tcp_probe module (as root) on sending machine and filter for iperf port. You can change the mode to allow non-root user
access: modprobe tcp_probe port=5001
chmod 444 /proc/net/tcpprobe
Capture tcp probe output (on sender) and place in background
cat /proc/net/tcpprobe >/tmp/tcpprobe.out & TCPCAP=$!
Run iperf test on sender for 15 minutes : iperf -i 10 -t 300 -c receiver
Kill capture process
kill $TCPCAP
The tcp probe capture file will contain one line for each packet sent.
0.073678 10.8.0.54:38644 192.168.1.42:5001 24 0xb6b19bb 0xb6b19bb 2 2147483647 5792
^ ^ ^ ^ ^ ^ ^ ^ ^
| | | | | | | | +- [9] Send window
| | | | | | | +------------ [8] Slow start threshold
| | | | | | +-------------- [7] Congestion window
| | | | | +------------------------ [6] Unacknowledged sequence #
| | | | +---------------------------------- [5] Next send sequence #
| | | +------------------------------------- [4] Bytes in packet
| | +------------------------------------------------------- [3] Receiver address:port
| +----------------------------------------------------------------------- [2] Sender address:port
+-------------------------------------------------------------------------------- [1] Time seconds
* The value of slow start threshold here is (-1) which means it hasn't been determined yet
Mesure TCP
This text file can be easily filtered and modified with standard tools such as awk and perl. A common usage is to make a plot
of congestion window and slow start threshold over time using gnuplot.
$ gnuplot -persist <<"EOF"
set data style linespoints
show timestamp
set xlabel "time (seconds)"
set ylabel "Segments (cwnd, ssthresh)"
plot "/tmp/tcpprobe.out" using 1:7 title "snd_cwnd", \
"/tmp/tcpprobe.out" using 1:($8>=2147483647 ? 0 : $8) title "snd_ssthresh"
EOF
The result should look something like this:
pcap
pcap (« packet capture ») est une interface de programmation permettant de capturer un
trafic réseau. Elle est implémentée sous les systèmes GNU/Linux, FreeBSD, NetBSD,
OpenBSD et Mac OS X au sein de la librairie libpcap. WinPcap est le portage sous Windows
de libpcap.
Les outils de supervision réseau peuvent utiliser pcap et/ou WinPcap afin de capturer les
paquets transitant sur le réseau. Les versions récentes permettent également de transmettre
des paquets sur la couche de liaison.
libpcap et WinPcap permettent aussi de sauvegarder les paquets capturés dans un fichier, et
la lecture de fichiers provenant de captures précédentes. Des applications peuvent être
développées utilisant libpcap ou WinPcap pour pouvoir capturer du trafic réseau, le lire,
l’enregistrer et l’analyser.
libpcap et Winpcap fournissent l’outil de filtrage et de capture de paquets qu'utilisent de
nombreux logiciels libres ou commerciaux d’analyse de trafic, allant des analyseurs de
protocoles, moniteurs réseaux aux systèmes de détection d’intrusion, générateurs de trafic et
testeurs de réseau.
libpcap a été initialement écrit par les développeurs de tcpdump au laboratoire national
Lawrence Berkeley. Le code de capture bas niveau, de lecture et d'écriture de fichiers de
tcpdump a été extrait et transformé en bibliothèque. libpcap est toujours développé sur le site
tcpdump.org.
PCAP
#include <pcap.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
pcap_t *handle; /* Session handle */
char *dev; /* The device to sniff on */
char errbuf[PCAP_ERRBUF_SIZE]; /* Error string */
struct bpf_program fp; /* The compiled filter */
char filter_exp[] = "port 23"; /* The filter expression */
bpf_u_int32 mask; /* Our netmask */
bpf_u_int32 net; /* Our IP */
struct pcap_pkthdr header; /* The header that pcap gives us */
const u_char *packet; /* The actual packet */
/* Define the device */
dev = pcap_lookupdev(errbuf);
if (dev == NULL) {
fprintf(stderr, "Couldn't find default device: %s\n", errbuf);
return(2);
}
/* Find the properties for the device */
if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
fprintf(stderr, "Couldn't get netmask for device %s: %s\n", dev, errbuf);
net = 0;
mask = 0;
}
PCAP
/* Open the session in promiscuous mode */
handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
if (handle == NULL) {
fprintf(stderr, "Couldn't open device %s: %s\n", somedev, errbuf);
return(2);
}
/* Compile and apply the filter */
if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
return(2);
}
if (pcap_setfilter(handle, &fp) == -1) {
fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));
return(2);
}
/* Grab a packet */
packet = pcap_next(handle, &header);
/* Print its length */
printf("Jacked a packet with length of [%d]\n", header.len);
/* And close the session */
pcap_close(handle);
return(0);
}
PCAP
#include <stdio.h>
#include <stdlib.h>
#include <pcap.h> /* GIMME a libpcap plz! */
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc, char **argv)
{
char *dev; /* name of the device to use */
char *net; /* dot notation of the network address */
char *mask;/* dot notation of the network mask */
int ret; /* return code */
char errbuf[PCAP_ERRBUF_SIZE];
bpf_u_int32 netp; /* ip */
bpf_u_int32 maskp;/* subnet mask */
struct in_addr addr;
/* ask pcap to find a valid device for use to sniff on */
dev = pcap_lookupdev(errbuf);
/* error checking */
if(dev == NULL)
{
printf("%s\n",errbuf);
exit(1);
}
/* print out device name */
printf("DEV: %s\n",dev);
PCAP/* ask pcap for the network address and mask of the device */
ret = pcap_lookupnet(dev,&netp,&maskp,errbuf);
if(ret == -1)
{
printf("%s\n",errbuf);
exit(1);
}
/* get the network address in a human readable form */
addr.s_addr = netp;
net = inet_ntoa(addr);
if(net == NULL)/* thanks Scott :-P */
{
perror("inet_ntoa");
exit(1);
}
printf("NET: %s\n",net);
/* do the same as above for the device's mask */
addr.s_addr = maskp;
mask = inet_ntoa(addr);
if(mask == NULL)
{
perror("inet_ntoa");
exit(1);
}
printf("MASK: %s\n",mask);
8. Embarqué
–Système de fichiers d’un desktop–Description et utilisation d’une chaîne de cross-compilation–Description des binutils–Exemple de compilation d’un package basé sur autotools–Adaptation d’un Makefile pour la cross-compilation
Architecture d’un linux
Un ROOTFS contient habituellement :
•Des binutils : ar, ldd, strip, …
•Une chaine de compilation native: gcc, system, libraries (libc, libm, libpthread, …),
headers, …
•Un debugger : gdb
Seulement une architecture est disponible à un instant t (x86, x86-64, …).
http://www.pathname.com/fhs/
Cross-compilation
SDK (stagingdir) :
Rootfs intermédiaire / il y en a
un par architecture
Toolchain :
• gcc
• headers
• host tools
• …
Rootfs local
Gestion de version
Installation
intermédiaire
Utilisé pour la compilation
(headers), et l’édition de liens
(librairies) Real rootfs for
the
Embedded target Target
embarqué
FirmwaresFlashage
Boot
TFTP /
NFS
Installation finale
(dans le rootfs)
Les binutils
Les GNU Binutils Sont une collection d’outils utiles pour le développement :
* ld - the GNU linker.* as - the GNU assembler.* addr2line - Converts addresses into filenames and line numbers.* ar - A utility for creating, modifying and extracting from archives.* gprof - Displays profiling information.* nm - Lists symbols from object files.* objcopy - Copys and translates object files.* objdump - Displays information from object files.* ranlib - Generates an index to the contents of an archive.* readelf - Displays information from any ELF format object file.* size - Lists the section sizes of an object or archive file.* strings - Lists printable strings from files.* strip - Discards symbols.
Pour de lacross-compilation l’usage d’un prefixe est requis devant le nom des binaires (sh4-linux-ar, sh4-linux-nm, sh4-linux-strip, .... )
Librairie statique
Creating a static library is an easy task thank to the ar tool from the binutils :
$ ar –rv mystaticlibrary.a file1.o file2.o file3.o
or
$ ar –rv mystaticlibrary.a *.o
The previous command merge the three objects (test1.o, test2.o et test3.o) in one archive.
A static library is:
•a tank for ELF objects
•similar to an archive such as zip or tar
•have a .a extension
A static library is not linked but is an archive make by the ar binutil. Thus, This is possible
extract it the buildin objects.
Extracting the content of a static library use the same tool: $ ar x
mystaticlibrary.a
Some tools such as Midnight commanger (mc) can browse into.
For more information: man ar
Libraries statiques
Il est aussi possible de lister le contenu des fichiers objets inclus dans la librairie :
$ ar –t mystaticlibrary
cominter.o
com_util.o
filointer.o
miscell.o
paral.o
pilot.o
simul_api.o
spyinter.o
userint.o
La commande suivante permet de lister la liste des symboles par objets :
$ nm mystaticlibrary.a
ad_server.o:
00000099 T affichage_etat_client
00000004 C bDebugAd
00000004 C bDebugSu
U bTrace
00000390 T close_socket
cominter.o:
00000004 d bComInit
00000000 d bNoInitWarn
00000010 b bTrComInter
U : undefined (implémentation externe)
T : implémenté à l’intérieur « Pour un objet
cela liste les fonctions et pour une librairie
les fonctions par objet . »
Librairie dynamique
La création d’une librairie dynamique necessite de rassenbler les objets en un
objet ELF.$ gcc -Wall -fPIC -c test1.c –o test1.o
$ gcc -Wall -fPIC -c test2.c -0 test2.o
$ gcc -shared -Wl,-soname,libtest.so.1 -o libtest.so.1.0 test1.o
test2.o
$ ranlib libtest.so.1.0
Liste des paramètres à passer à l’éditeur de liens :
Pour plus d’information : man ld
Compiler options Definitions
-Wall include all warnings. See man page for warnings specified.
-fPIC Compiler directive to output position independent code, a characteristic required by shared libraries. Also see -fpic.
-shared Produce a shared object which can then be linked with other objects to form an executable.
-W1 Pass options to linker. In this example the options to be passed on to the linker are: ”-soname libctest.so.1”. The name passed with the ”-o” option is passed to gcc.
-o Output of operation. In this case the name of the shared object to be output will be libctest.so.1.0
Cross-compilation via des autotools
La compilation d’un package autotools se fait de la façon suivante :./configure --prefix=/usr makesudo make install Le compilateur natif gcc sera utilisé.
La cross-compilation est assez similaire au paramètre --host prêt:./configure --prefix=/usr --host=arm-linuxmakesudo make install Le cross-compilateur arm-linux-gcc sera utilisé.
Cross-compilation à base d’un Makefile
La compilation d’un package autotools se fait de la façon suivante :all: mybinarymybinary: objet1.o objet2.o
gcc $< -o [email protected]:objet1.c
gcc -c $< -o [email protected]:objet2.o
gcc -c $< -o $@
La cross-compilation est assez similaire au paramètre --host prêt:all: mybinarymybinary: objet1.o objet2.o
arm-linux-gcc $< -o [email protected]:objet1.c
arm-linux-gcc -c $< -o [email protected]:objet2.o
arm-linux-gcc -c $< -o $@
XPREFIX=arm-linux-
CC=$(XPREFIX)gcc
all: mybinary
mybinary: objet1.o objet2.o
$(CC) $< -o $@
objet1.o:objet1.c
$(CC) -c $< -o $@
objet2.o:objet2.o
$(CC) -c $< -o $@
REFERENCES
Livres / Linux
Livres / Réseau
Livres / Réseau
Livres / Réseau
Livres / Réseau
Livres / Noyau & drivers
Livres / Embarqué
LiensGNU Linux DDK : http://www.kroah.com/log/2006/05/24/#ddkLinux Device Drivers, Third Edition - Network Drivers : http://lwn.net/images/pdf/LDD3/ch17.pdfIpsysctl tutorial : http://ipsysctl-tutorial.frozentux.net/ipsysctl-tutorial.htmlLinux IP Networking : http://www.cs.unh.edu/cnrg/gherrin/linux-net.htmlUNIX IP Stack Tuning Guide : http://www.cymru.com/Documents/ip-stack-tuning.htmlPerformance Analysis of the TCP/IP Stack of Linux Kernel :http://user.informatik.uni-goettingen.de/~kperf/gaug-ifi-tb-2005-03.pdfLinux IP Masquerade mini HOWTO : http://www.ibiblio.org/pub/Linux/docs/HOWTO/translations/fr/pdf/IP-Masquerade-HOWTO.pdfPont + pare-feu + DSL Mini-HOWTO :http://www.ibiblio.org/pub/Linux/docs/HOWTO/translations/fr/pdf/Bridge+Firewall+DSL.pdfMini How-To sur la configuration de l’aliasing IP sous Linux : http://www.ibiblio.org/pub/Linux/docs/HOWTO/translations/fr/pdf/IP-Alias.pdfLinux Network Administrators Guide : http://tldp.org/LDP/nag2/nag2.pdfThe Linux Networking Overview HOWTO : http://www.ibiblio.org/pub/Linux/docs/HOWTO/other-formats/pdf/Networking-Overview-HOWTO.pdfTCP/IP Stack Hardening : http://www.cromwell-intl.com/security/security-stack-hardening.htmlVoyage au centre de la pile TCP/IP de Linux : http://asyd.net/docs/kernel/tcpip-stack.html
A Measurement Study of the Linux TCP/IP Stack Performance and
Scalability on SMP systems : http://www.cse.iitb.ac.in/~varsha/allpapers/mypapers/comswarepaper.pdf
Berkeley sockets : http://en.wikipedia.org/wiki/Berkeley_sockets
Linux TCP/IP Stack : http://www.cs.odu.edu/~csi/tcpipstack.ppt
IP & Ethernet Interfaces : http://www.beyondlogic.org/etherip/ip.htm
Implementation of TCP/IP in Linux : http://netweb.usc.edu/~rsinha/docs/tcp-ip.ppt
Conception du sous-système réseau de linux : http://lacl.univ-paris12.fr/cegielski/reseau.html
Liens
Serial Line IP Implementation for Linux Kernel TCP/IP Stack : http://www.cse.iitb.ac.in/~bestin/pdfs/slip.pdf
HOWTO du routage avancé et du contrôle de trafic sous Linux :
http://www.ibiblio.org/pub/Linux/docs/HOWTO/translations/fr/pdf/lartc.pdf
Linux NAT HOWTO : http://www.linux-france.org/prj/inetdoc/guides/NAT-HOWTO/
Linux Packet Filtering HOWTO : http://www.linux-france.org/prj/inetdoc/guides/packet-filtering-HOWTO/
Linux inetdoc : http://www.linux-france.org/prj/
Linux IPv6 HOWTO : http://cvs.tldp.org/go.to/LDP/LDP/users/Peter-Bieringer/Linux+IPv6-HOWTO.fr.pdf
Nisnet (network emulator) : http://www-x.antd.nist.gov/nistnet/
TCPStackPerformance : http://www.gelato.unsw.edu.au/IA64wiki/TCPStackPerformance
Anatomy of the Linux networking stack :
http://www.ibm.com/developerworks/linux/library/l-linux-networking-stack/
Guide pratique du multicast sur les réseaux TCP/IP :
http://www.ibiblio.org/pub/Linux/docs/HOWTO/translations/fr/pdf/Multicast-HOWTO.pdf
Historique de la stack IP :
http://www.linuxfranch-county.org/docs/guideLLLinux/implementation_reseau_5-2.pdf
Fonctions réseau du noyau Linux : http://www.linux-france.org/prj/inetdoc/telechargement/interco.noyau.pdf
Understanding Linux Network Internals :
http://book.chinaunix.net/special/ebook/oreilly/Understanding_Linux_Network_Internals/
Algorithmic Complexity Attacks and the Linux Networking Code :
http://www.enyo.de/fw/security/notes/linux-dst-cache-dos.html
Linux Network Stack Walkthrough :
http://gicl.cs.drexel.edu/people/sevy/network/Linux_network_stack_walkthrough.html
Data Link Layer : http://lion.cs.uiuc.edu/courses/cs498hou_spring05/lectures/lecture8.pdf
skb - Linux network buffers : http://ftp.gnumonks.org/pub/doc/skb-doc.html
Paris240-244
Avenue Pierre-Brossolette
92240 MalakoffTel: +33 1 49 65 63 00
Nantes2, rue du Tyrol
104 rue Leinster – Bât.CLe Parc du Vieux Moulin
44240 La Chapelle sur Erdre
Tel: +33 2 72 64 40 17
Toulouse417 L’Occitane
BP 4750631675 Labège Cedex
Tel: +33 5 61 00 79 79
Sophia-AntipolisBâtiment Frégate
2400 route des Crêtes06560 Sophia-
AntipolisTel: +33 4 92 91 36 36
BristolEurogiciel at Voith Unit 23 Ape
Court, WoodlandsAlmondsbury Bristol BS32KJ
UNITED KINGDOMTel: +441 454 275 610
RennesCentre Affaires Alizés
La Rigourdière35510 Cesson SévignéTel: +33 2 28 23 21 00
BordeauxDomaine Millenium6 avenue Henri Le
Chatelier33700 Mérignac
Tel: +33 5 57 92 38 38
MarseilleImm. Optimum, Bât C165 avenue du Marin
Blanc13400 Aubagne
Tel: +33 4 42 72 19 19
MunichNymphenburger Str.4
80335 MünchenGERMANY
Tel: +49 89 208 0270
TunisPôle Technologique Gazala
BP432088 Ariana
TUNISIETel: +216 71 857 778
Principales références
Implantations
www.eurogiciel.fr – [email protected]
ACTIA - Aerolia - Afpa - Airbus - Air France-KLM - Air Liquide - Alstom - Amadeus - Ansaldo - ArcelorMittal - Areva - Banque Populaire - BouyguesTelecom - Caisse d’Epargne - CEA - Cegedim Activ - Cegelec - CLS - CNES - Continental - Cultura - Dassault Aviation - DCNS - DGA - EADS - EDF - ELTA -Envivio - Euler Hermes – Eurocopter - France Télévisions - GDF Suez - Latécoère - Hermès – Honeywell - INTEL - Intercontrole - IRSN - Labinal - LaPoste - Lafarge - Lectra - Leroy-Somer - Liebherr - MMA - Ministère de l’Agriculture – Ministère de l’Ecologie, du Développement durable, desTransports et du Logement - Ministère de l’Education Nationale - Monaco Telecom - Nagravision - Nexter Orange - Panasonic - Pierre Fabre - PSA –RATP - Recaéro - RIETER - Rockwell Collins - Rolls Royce - Safran - Saft - Sanofi - Siemens - Technicolor - SmarDTV - SNCF - Société Générale - Thales -Tisséo - TOTAL - Viaccess - ZODIAC
Ch
arte
Gra
ph
iqu
e EU
RO
GIC
IEL
Ingé
nie
rie
VF-
v2_0