Comme expliqué dans la section sur les gestionnaires de mise en file d'attente basés sur des classes, les filtres sont nécessaires pour classifier les paquets dans n'importe laquelle des sous-files d'attente. Ces filtres sont appelés à l'intérieur des gestionnaires de mise en file d'attente basés sur des classes.
Voici une liste incomplète des classificateurs disponibles :
fw
-
Base la décision sur la façon dont le pare-feu a marqué les paquets. Ceci peut être un passage facile si vous ne voulez pas apprendre la syntaxe tc liée aux filtres. Voir le chapitre sur les gestionnaires de mise en file d'attente pour plus de détails.
u32
-
Base la décision sur les champs à l'intérieur du paquet (c'est-à-dire l'adresse IP source, etc.)
route
-
Base la décision sur la route que va emprunter le paquet.
rsvp
,rsvp6
-
Route les paquets en se basant sur RSVP. Seulement utile sur les réseaux que vous contrôlez. Internet ne respecte pas RSVP.
tcindex
-
Utilisé par le gestionnaire de file d'attente
DSMARK
. Voir la section DSMARK.
Notez qu'il y a généralement plusieurs manières de classifier un paquet. Cela dépend du système de classification que vous souhaitez utiliser.
Les classificateurs acceptent en général quelques arguments communs. Ils sont listés ici pour des raisons pratiques :
protocol
-
Le protocole que ce classificateur acceptera. Généralement, on n'acceptera que le trafic IP. Exigé.
parent
-
Le descripteur auquel ce classificateur est attaché. Ce descripteur doit être une classe déjà existante. Exigé.
prio
-
La priorité de ce classificateur. Les plus petits nombres seront testés en premier.
handle
-
Cette référence a plusieurs significations suivant les différents filtres.
Toutes les sections suivantes supposeront que vous essayez de
mettre en forme le trafic allant vers HostA
. Ces sections supposeront que la classe
racine a été configurée sur 1:
et que
la classe vers laquelle vous voulez envoyer le trafic sélectionné
est 1:1
.
Le filtre u32
est le filtre le plus
avancé dans l'implémentation courante. Il est entièrement basé sur
des tables de hachage, ce qui le rend robuste quand il y a beaucoup
de règles de filtrage.
Dans sa forme la plus simple, le filtre u32
est une liste d'enregistrements, chacun
consistant en deux champs : un sélecteur et une action. Les
sélecteurs, décrits ci-dessous, sont comparés avec le paquet IP
traité jusqu'à la première correspondance, et l'action associée est
réalisée. Le type d'action le plus simple serait de diriger le
paquet vers une classe CBQ
définie.
La ligne de commande du programme tc filter, utilisée pour configurer le filtre, consiste en trois parties : la spécification du filtre, un sélecteur et une action. La spécification du filtre peut être définie comme :
tc filter add dev IF [ protocol PROTO ] [ (preference|priority) PRIO ] [ parent CBQ ]
Le champ protocol
décrit le
protocole sur lequel le filtre sera appliqué. Nous ne discuterons
que du cas du protocole ip
. Le champ
preference
(priority
peut être utilisé comme alternative) fixe
la priorité du filtre que l'on définit. C'est important dans la
mesure où vous pouvez avoir plusieurs filtres (listes de règles)
avec des priorités différentes. Chaque liste sera scrutée dans
l'ordre d'ajout des règles. Alors, la liste avec la priorité la
plus faible (celle qui a le numéro de préférence le plus élevé)
sera traitée. Le champ parent
définit
le sommet de l'arbre CBQ (par
ex. 1:0
) auquel le filtre doit être
attaché.
Les options décrites s'appliquent à tous les filtres, pas
seulement à u32
.
Le sélecteur U32 contient la définition d'un modèle, qui sera comparé au paquet traité. Plus précisément, il définit quels bits doivent correspondre dans l'en-tête du paquet, et rien de plus, mais cette méthode simple est très puissante. Jetons un oeil sur l'exemple suivant, directement tiré d'un filtre assez complexe réellement existant :
# tc filter parent 1: protocol ip pref 10 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:3 \ match 00100000/00ff0000 at 0
Pour l'instant, laissons de côté la première ligne ; tous ces
paramètres décrivent les tables de hachage du filtre.
Focalisons-nous sur la ligne de sélection contenant le mot-clé
match
. Ce sélecteur fera correspondre
les en-têtes IP dont le second octet sera 0x10
(0010
). Comme
nous pouvons le deviner, le nombre 00ff
est le masque de correspondance, disant au
filtre quels bits il doit regarder. Ici, c'est 0xff
, donc l'octet correspondra si c'est
exactement 0x10. Le mot-clé at
signifie
que la correspondance doit démarrer au décalage spécifié (en
octets) - dans notre cas, c'est au début du paquet. Traduisons tout
cela en langage humain : le paquet correspondra si son champ Type
de Service (TOS) a le bit
« faible
délai » positionné. Analysons une autre règle
:
# tc filter parent 1: protocol ip pref 10 u32 fh 800::803 order 2051 key ht 800 bkt 0 flowid 1:3 \ match 00000016/0000ffff at nexthdr+0
L'option nexthdr
désigne l'en-tête
suivant encapsulé dans le paquet IP, c'est à dire celui du
protocole de la couche supérieure. La correspondance commencera
également au début du prochain en-tête. Elle devrait avoir lieu
dans le deuxième mot de 32 bits de l'en-tête. Dans les protocoles
TCP et UDP, ce champ contient le port de destination du paquet. Le
nombre est donné dans le format big-endian, c'est-à-dire les bits
les plus significatifs en premier. Il faut donc lire 0x0016 comme
22 en décimal, qui correspond au service SSH dans le cas de TCP.
Comme vous le devinez, cette correspondance est ambiguë sans un
contexte, et nous en discuterons plus loin.
Ayant compris tout cela, nous trouverons le sélecteur suivant
très facile à lire : match c0a80100/ffffff00
at 16
. Ce que nous avons ici, c'est une correspondance de
trois octets au 17ème octet, en comptant à partir du début de
l'en-tête IP. Cela correspond aux paquets qui ont une adresse de
destination quelconque dans le réseau 192.168.1/24
. Après avoir analysé les exemples,
nous pouvons résumer ce que nous avons appris.
Les sélecteurs généraux définissent le modèle, le masque et le décalage qui seront comparés au contenu du paquet. En utilisant les sélecteurs généraux, vous pouvez rechercher des correspondances sur n'importe quel bit de l'en-tête IP (ou des couches supérieures). Ils sont quand même plus difficiles à écrire et à lire que les sélecteurs spécifiques décrits ci-dessus. La syntaxe générale des sélecteurs est :
match [ u32 | u16 | u8 ] PATTERN MASK [ at OFFSET | nexthdr+OFFSET]
Un des mots-clés u32
, u16
ou u8
doit
spécifier la longueur du modèle en bits. PATTERN
et MASK
se
rapporteront à la longueur définie par ce mot-clé. Le paramètre
OFFSET
est le décalage, en octets, pour
le démarrage de la recherche de correspondance. Si le mot-clef
nexthdr+
est présent, le décalage sera
relatif à l'en-tête de la couche réseau supérieure.
Quelques exemples :
# tc filter add dev ppp14 parent 1:0 prio 10 u32 \ match u8 64 0xff at 8 \ flowid 1:4
Un paquet correspondra à cette règle si sa « durée de vie » (TTL) est de 64. TTL est le champ démarrant juste après le 8ème octet de l'en-tête IP.
Correspond à tous les paquets TCP ayant le bit ACK activé :
# tc filter add dev ppp14 parent 1:0 prio 10 u32 \ match ip protocol 6 0xff \ match u8 0x10 0xff at nexthdr+13 \ flowid 1:3
Utilisez ceci pour déterminer la présence du bit ACK sur les paquets d'une longueur inférieure à 64 octets :
## Vérifie la présence d'un ACK, ## protocol IP 6, ## longueur de l'en-tête IP 0x5(mots de 32 bits), ## longueur total IP 0x34 (ACK + 12 octets d'options TCP) ## TCP ack actif (bit 5, offset 33) # tc filter add dev ppp14 parent 1:0 protocol ip prio 10 u32 \ match ip protocol 6 0xff \ match u8 0x05 0x0f at 0 \ match u16 0x0000 0xffc0 at 2 \ match u8 0x10 0xff at 33 \ flowid 1:3
Seuls les paquets TCP sans charge utile et avec le bit
ACK positionné vérifieront cette
règle. Ici, nous pouvons voir un exemple d'utilisation de deux
sélecteurs, le résultat final étant un ET logique de leur résultat.
Si nous jetons un coup d'oeil sur un schéma de l'en-tête TCP, nous
pouvons voir que le bit ACK est
le second bit (0x10
) du 14ème octet de
l'en-tête TCP (at nexthdr+13
). Comme
second sélecteur, si nous voulons nous compliquer la vie, nous
pouvons écrire match u8 0x06 0xff at 9
à la place du sélecteur spécifique protocol
tcp
, puisque 6 est le numéro du protocole TCP, spécifié au
10ème octet de l'en-tête IP. D'un autre côté, dans cet exemple,
nous ne pourrons pas utiliser de sélecteur spécifique pour la
première correspondance, simplement parce qu'il n'y a pas de
sélecteur spécifique pour désigner les bits TCP ACK.
Le filtre ci dessous est une version modifiée du filtre présenté au-dessus. La différence est qu'il ne vérifie pas la longueur de l'en-tête ip. Pourquoi ? Car le filtre au-dessus ne marche que sur les systèmes 32 bits.
tc filter add dev ppp14 parent 1:0 protocol ip prio 10 u32 \ match ip protocol 6 0xff \ match u8 0x10 0xff at nexthdr+13 \ match u16 0x0000 0xffc0 at 2 \ flowid 1:3
La table suivante contient la liste de tous les sélecteurs spécifiques que les auteurs de cette section ont trouvés dans le code source du programme tc. Ils rendent simplement la vie plus facile en accroissant la lisibilité de la configuration du filtre.
FIXME: emplacement de la table - la table est dans un fichier séparé "selector.html"
FIXME: C'est encore en Polonais :-(
FIXME: doit être "sgmlisé"
Quelques exemples :
# tc filter add dev ppp0 parent 1:0 prio 10 u32 \ match ip tos 0x10 0xff \ flowid 1:4
FIXME: tcp dport match ne fonctionne pas comme décrit ci-dessous :
La règle ci-dessus correspondra à des paquets qui ont le champ
TOS égal à 0x10
. Le champ TOS commence
au deuxième octet du paquet et occupe 1 octet, ce qui nous permet
d'écrire un sélecteur général équivalent : match u8 0x10 0xff at 1
. Cela nous donne une
indication sur l'implémentation du filtre u32
. Les règles spécifiques sont toujours traduites
en règles générales, et c'est sous cette forme qu'elles sont
stockées en mémoire par le noyau. Cela amène à une autre conclusion
: les sélecteurs tcp
et udp
sont exactement les mêmes et c'est la raison
pour laquelle vous ne pouvez pas utiliser un simple sélecteur
match tcp dport 53 0xffff
pour
désigner un paquet TCP envoyé sur un port donné. Ce sélecteur
désigne aussi les paquets UDP envoyés sur ce port. Vous devez
également spécifier le protocole avec la règle suivante :
# tc filter add dev ppp0 parent 1:0 prio 10 u32 \ match tcp dport 53 0xffff \ match ip protocol 0x6 0xff \ flowid 1:2