Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
bsd:pf_poilu_fr [2007/01/08 17:42]
mat created
bsd:pf_poilu_fr [2010/01/12 13:29] (current)
Line 1: Line 1:
 +====== Optimisation de règles de firewall ======
  
 +
 +===== Buts =====
 +Dans l'​idéal,​ l'​utilisation d'un filtre de paquets ne devrait pas affecter le traffic réseau légitime. Les paquets violant la politique de filtrage devraient être bloqués, et les paquets conformes devraient traverser le filtre de paquets comme s'il n'​était pas là.
 +
 +En réalité, plusieurs facteurs limitent à quel point un filtre de paquet peut accomplir sa tâche sans faille. Les paquets doivent passer par le dispositif, ajoutant une certaine latence entre le moment un paquet est reçu et le temps où il est réexpédié. Quel que soit le dispositif, il peut seulement traiter une quantité finie de paquets par seconde. Quand les paquets arrivent à un taux plus élevé que ce que le dispositif peut les faire transiter, des paquets sont perdus.
 +
 +La plupart des protocoles, comme TCP, traitent bien la latence induite par les différents appareils. Vous pouvez espérer avoir de grandes vitesses de transfert en TCP même sur des liens ayant plusieurs centaines de milisecondes de latence. D'un autre côté, dans un jeu en réseau de type temps réel même quelques dizaines de millisecondes de latence sont habituellement perçues en tant que trop. La perte de paquet est généralement quelque chose de plus grave, les performances de TCP se dégraderont sérieusement lorsqu'​un nombre significatif de paquets sont perdus. ​
 +
 +Cet article explique comment identifier les cas où pf devient le facteur limitant dans le débit réseau et qu'est ce qui peut être fait pour améliorer les performances dans ces cas-là.
 +
 +
 +=====De l'​importance du nombre de paquets par seconde=====
 +
 +Une unité généralement utilisée pour mesurer la performance d'un réseau est son débit en octets par seconde. Mais cette unité est inadéquate pour mesurer les performances de pf. Le vrai facteur limitant n'est pas le débit mais le "​packet rate", le nombre de paquets par seconde que le dispositif peut traiter. Le même PC qui fait transiter un flux réseau à un débit de 100Mbps avec des paquets de 1500 octets sans problèmes peut être mis à genoux par un traffic de  10Mbps avec des paquets de 40 octets. Dans le premier cas, seul 8.000 paquets/​secondes transitaient,​ mais dans le deuxième cas, le dispositif faisait transiter 32 000 paquets/​secondes,​ ce qui multiplie approximativement par quatre la charge pour le PC.
 +
 +
 +Pour comprendre ceci, regardons comment les paquets traversent réellement le dispositif. Les paquets sont reçus du réseau par la carte réseau (NIC) et sont copiés dans un petit buffer présent sur la NIC. Quand ce buffer est plein, la NIC déclenche une interruption matérielle (IRQ), et déclenche la copie des paquets dans des "​network memory buffers (mbufs)"​ dans l'​espace de mémoire du noyau, copie effectuée par le driver réseau. Les paquets transitent alors dans la pile TCP/IP sous la forme de ces mbufs. Une fois qu'un paquet est transféré dans un mbuf, la plupart des opérations que la pile TCP/IP exécute sur le paquet ne dépendent pas de la taille de paquet, car ces opérations inspectent seulement les en-têtes du paquet et pas le corps du paquet (les données). C'est également vrai pour pf, qui reçoit les paquets un par un et prend la décision soit de les bloquer, soit de les laisser passer, en examinant les en-têtes. Si le paquet a besoin d'​être réexpédié,​ la pile TCP/IP le passera à un driver de carte réseau, qui extraira le paquet à partir du mbuf et le renverra sur le réseau. ​
 +
 +
 +La plupart de ces opérations ont un coût élevé par rapport au nombre de paquets, mais faible vis-à-vis de la taille du paquet. ** Bon, formulation à revoir ici...** Par conséquent,​ le traitement d'un grand paquet est seulement légèrement plus coûteux que le traitement d'un petit.
 +
 +Quelques limites sont basées sur le matériel et le logiciel en dehors de pf. Par exemple, les machines de type PC ne peuvent pas manipuler plus de 10.000 interruptions par seconde, qu'​importe la gamme du CPU, en raison des contraintes architecturales. Certaines cartes réseau produiront une interruption pour chaque paquet reçu. Par conséquent,​ la machine commencera à perdre des paquets quand le débit excèdera 10 000 paquets par seconde. D'​autres NICs, comme des cartes gigabit plus coûteuses, ont de plus grands buffers incorporés au matériel, ce qui leur permet d'​envoyer plusieurs paquets par interruption. Le choix du matériel peut donc imposer des limites qu'​aucune optimisation de pf ne peut surpasser.
 +
 +
 +=====Lorsque pf est le goulot d'​étranglement=====
 +
 +Le noyau passe les paquets à pf de manière séquentielle,​ l'un après l'​autre. Pendant que pf est appellé pour décider du destin d'un paquet, le passage des paquets par le noyau est brièvement suspendu. Pendant cette courte période, d'​autres paquets reçus du réseau par les NICs doivent être placés dans des buffers. Si les évaluations de pf prennent trop de temps, les paquets rempliront rapidement les buffers, et d'​autres paquets seront perdus. Le but d'​optimiser les jeux de règles de pf est de réduire la quantité de temps que pf dépense pour chaque paquet.
 +
 +Un exercice intéressant est de mettre intentionnellement la machine dans cet état surchargé en chargeant un jeu de règles très grand comme ceci :
 +
 +
 +  $ i=0; while [ $i -lt 100 ]; do \
 +      printf "block from any to %d.%d.%d.%d\n"​ \
 +        `jot -r -s " " 4 1 255`; \
 +      let i=i+1; \
 +    done | pfctl -vf -
 +
 +Vous obtiendrez des règles comme suit :
 +
 +  block drop inet from any to 151.153.227.25
 +  block drop inet from any to 54.186.19.95
 +  block drop inet from any to 165.143.57.178
 +  ...
 +
 +
 +Ceci est l'​illustration d'un des pire jeu de règles qui défie toutes les optimisations automatiques. Puisque chaque règle contient une adresse aléatoire, pf est forcé de traverser le jeu de règles en entier et d'​évaluer chaque règle pour chaque paquet. Charger un jeu de règles qui se compose de milliers de telles règles, et produire un flux continu de paquets qui doivent être filtrés inflige un charge importante même sur la meilleure machine du marché que vous pourrez trouver. Lorsque la machine est ainsi placée sous charge, vous pouvez vérifier le taux d'​interruption avec : 
 +
 +  $ vmstat -i
 +
 +Et regarder l'​état du CPU avec :
 +
 +  $ top
 +
 +
 +Cela vous donnera une idée de la façon dont réagit le matériel à une surcharge, et vous aidera à repérer des symptômes semblables lorsque vous utiliserez votre propre jeu de règles. Vous pouvez utiliser les mêmes outils pour vérifier les effets qu'​auront produit les optimisations.
 +
 +Ensuite, essayez l'​extrême opposé:
 +
 +
 +  $ pfctl -d
 +
 +Comparez alors les valeurs obtenues des commandes vmstat et top
 +
 +C'est une manière simple d'​obtenir une évaluation grossière et une limite sur ce que vous pouvez espérer de l'​optimisation. Si votre matériel gère convenablement votre trafic lorsque pf est désactivé,​ vous pouvez espérer obtenir des performances semblable lorsque pf est activé. Cependant, si le matériel montre déjà des problèmes lorsqu'​il gère le trafic avec pf désactivé,​ chercher à optimiser le jeu de règles de pf est probablement inutile, et d'​autres composants devraient être changés d'​abord.
 +
 +Si vous déjà avez un jeu de règles fonctionnel et si vous vous demandez si vous devriez passer du temps  à l'​optimiser pour gagner de la vitesse, répétez cette expérience avec votre jeu de règles et comparez les résultats aux deux cas extrêmes. Si utiliser votre jeu de règles montre des signes de surcharge, vous pouvez employer les conseils ci-dessous pour la réduire.
 +
 +<​del>​** PARAGRAPHE QUI CONCERNE LA DEUXIEME PARTIE DE PF **
 +Dans certains cas, le jeu de règles n'​induira pas de charge significative sur le matériel, mais les connexions transitant par la machine montreront des problèmes inattendus, comme des retards pendant l'​établissement de la connexion, des connexions stagnantes ou des débits décevants.
 +
 +Dans la plupart de ces cas, le problème n'est pas la performance de filtrage, mais une  mauvaise configuration du jeu de règles qui fait que des paquets sont perdus. Voir "​Testing Your Firewall"​ à propos de la manière d'​identifier et de traiter de tels problèmes. ​
 +
 + In most of these cases, the problem is not filtering performance at all, but a misconfiguration of the ruleset which causes packets to get dropped. See Testing Your Firewall about how to identify and deal with such problems.
 +</​del>​
 +
 +En conclusion, si votre jeu de règles est évalué sans causer de charge significative et si tout fonctionne comme prévu, la conclusion la plus raisonnable est de laisser le jeu de règles comme il est. Souvent, des jeux de règles écrits dans une approche directe sont évalués assez efficacement pour ne causer aucune perte de paquet. Les optimisations manuelles rendront seulement le jeu de règles plus dur à lire pour le mainteneur, tout en ayant un effet insignifiant sur les performances.
 +
 +
 +
 +
 +
 +===== Inspecter dynamiquement le traffic avec états =====
 +
 +Le travail effectué par pf s'​articule principalement autour de deux types d'​opérations : évaluations de jeux de règles, et recherche dans des tables d'​états.
 +
 +Pour chaque paquet, pf effectue d'​abord une recherche dans les tables d'​états. Si une entrée d'​état correspondante est trouvée dans la table d'​état,​ le paquet est immédiatement accepté. Autrement pf évalue le jeu de règles de filtrage pour trouver la dernière règle correspondante pour le paquet qui décide si il doit bloquer ou laisser passer. Si la règle dit de laisser passer le paquet, elle peut optionnellement créer une entrée d'​état en utilisant l'​option "keep state"​.
 +
 +En filtrant sans états, sans employer "keep state" pour créer des entrées d'​état pour les connexions, chaque paquet cause une évaluation du jeu de règles, et l'​évaluation du jeu de règles est la seule opération coûteuse que pf exécute dans ce scénario. Chaque paquet cause toujours une consultation de table d'​état,​ mais puisque la table est vide, le coût de la consultation est de zéro.
 +
 +Filtrer avec état signifie utiliser "keep state" dans les règles de filtrage, ainsi les paquets correspondant aux  règles créeront une entrée dans la table d'​états. D'​autres paquets relatifs à la même connextion correspondront aux entrées de la table d'​états,​ et passeront automatiquement,​ sans évaluations du jeu de règles. Dans ce scénario, seulement le premier paquet de chaque connexion cause une évaluation du jeu de règles, et les paquets suivants causent seulement une consultation d'​état.
 +
 +Maintenant, il faut savoir qu'une consultation d'​état est beaucoup moins coûteuse qu'une évaluation d'un jeu de règles. Un jeu de règles est fondamentalement une liste de règles qui doivent être évaluées de haut en bas. Le coût augmente avec chaque règle dans la liste, deux fois plus de règles égale deux fois plus de travail. Et l'​évaluation d'une règle simple peut causer la comparaison de nombreuses valeurs dans le paquet.
 + La table d'​état,​ d'un autre côté, est un arbre. Le coût de consultation augmente seulement logarithmiquement avec le nombre d'​entrées,​ deux fois plus d'​états signifie seulement une fraction de travail additionnelle. Et la comparaison est nécessaire seulement pour un nombre limité de valeurs dans le paquet.
 +
 +Il y a un certain coût à créer et à enlever des entrées dans la table d'​états. Mais assumant le fait que l'​état va correspondre à un certain nombre de paquets et donc économiser du temps d'​évaluation de jeu de règles pour eux, à la fin cela devient beaucoup plus rentable. Pour les connexions spécifiques comme les consultations de DNS, où chaque connexion se compose seulement de deux paquets (une demande et une réponse), le surcoût de la création d'​état pourrait être plus mauvais que deux évaluations de jeu de règles. Les connexions qui se composent de plus qu'une poignée de paquets, comme la plupart des connexions TCP, tireront bénéfice de la création d'une entrée dans la table d'​état.
 +
 +En bref, vous pouvez faire du coût d'une évaluation de jeu de règles qu'il soit payé par connexion au lieu qu'il soit payé par paquet. Vous pouvez obtenir facilement un gain de performances d'un facteur 100 ou plus. Par exemple, on voit les compteurs suivants lorsqu'​on lance :
 +
 +  $ pfctl -si
 +   
 +  State Table                          Total             Rate
 +    searches ​                      ​172507978 ​         887.4/s
 +    inserts ​                         1099936 ​           5.7/s
 +    removals ​                        ​1099897 ​           5.7/s
 +  Counters
 +    match                            6786911 ​          ​34.9/​s
 +
 +Ceci signifie que pf est appelé environ 900 fois par seconde. On filtre sur de multiples interfaces, cela signifie que  l'on transmet environ 450 paquets par seconde, chacun d'eux est filtré deux fois, une fois sur chaque interface qu'il traverse. Mais l'​évaluation du jeu de règles se produit seulement environ 35 fois par seconde, et les insertions et suppressions d'​état seulement 6 fois par seconde. Avec rien d'​autre qu'un tout petit jeu de règles, c'est une très bonne valeur en soi.
 +
 +Pour s'​assurer que vous créez vraiment un état pour chaque connexion, recherchez le mot-clef "​pass"​ dans des règles qui n'​emploient pas "keep state",​ comme dans :
 +
 +  $ pfctl -sr | grep pass | grep -v 'keep state'
 +
 +Assurez-vous d'​avoir une solide politique de bloquage par défaut, autrement des paquets pourraient passer non seulement grâce aux règles "​pass"​ "​explicites,​ mais aussi parce qu'ils ne correspondraient à aucune règle et passeraient par défaut.
 +
 +
 +
 +
 +=====Le revers de l'​inspection dynamique de paquets=====
 +
 +Le seul revers de l'​inspection dynamique de paquets est que les entrées de la table d'​états ont besoin de mémoire, autour de 256 octets pour chaque entrée. Quand pf ne réussit pas à assigner de la mémoire pour une nouvelle entrée d'​état,​ il bloque le paquet qui devrait avoir créé l'​entrée d'​état,​ et augmente un compteur de dépassement-de-mémoire montré par :
 +
 +  $ pfctl -si
 +  Counters
 +    memory ​                                ​0 ​           0.0/s
 +
 +La mémoire pour les entrées d'​états est allouée depuis la réserve de mémoire du noyau appellée "​pfstatepl"​. Vous pouvez utiliser vmstat(8) pour observer divers aspects de l'​utilisation de la réserve de mémoire :
 +
 +  $ vmstat -m
 +  Memory resource pool statistics
 +  Name        Size Requests Fail Releases Pgreq Pgrel Npage Hiwat Minpg Maxpg Idle
 +  pfstatepl ​   256  1105099 ​   0  1105062 ​  ​183 ​  ​114 ​   69   ​127 ​    0 625   62
 +
 +La différence entre "​Requests"​ et "​Releases"​ est égale au nombre d'​entrées de la table d'​états actuellement utilisée, qui devrait correspondre au compteur montré par :
 +
 +  $ pfctl -si
 +  State Table                          Total             Rate
 +    current entries ​                      36
 +
 +Les autres compteurs montrés par pfctl peuvent être remis à zéro avec la commande pfctl -Fi.
 +
 +Toute la mémoire de la machine n'est pas disponible pour le noyau, et la manière dont la quantité de RAM physique affecte la quantité disponible au noyau dépend de l'​architecture et les options et la version du noyau. Pour OpenBSD 3.6, un noyau i386 peut employer jusqu'​à 256Mo de mémoire. Avant la version 3.6, cette limite était beaucoup plus petite pour un i386. Vous pourriez avoir 8Go de RAM dans votre machine que pf n'​arrivera toujours pas a assigner la mémoire au delà d'une petite fraction de cette quantité. ​
 +
 +Pour rendre les choses encore pire, lorsque pf atteint vraiment la limite où pool_get(9) échoue, l'​échec n'est pas aussi gracieux que l'on pourrait souhaiter. Au lieu de cela, le système entier devient instable après cet incident, et éventuellement crashe. Ce n'est pas vraiment un défaut de pf, mais un problème général avec la gestion de la réserve de mémoire du noyau.
 +
 +Pour éviter cela, pf lui-même limite le nombre d'​entrées d'​état qu'il assignera en même temps, en utilisant pool_sethardlimit(9),​ également montré par vmstat -m. La valeur par défaut pour cette limite est 10.000 entrées, qui est sûre quelque soit le matériel utilisé. La limite peut être vue avec :
 +
 +  $ pfctl -sm
 +  states ​    hard limit  10000
 +  src-nodes ​ hard limit  10000
 +  frags      hard limit    500
 +
 +
 +Si vous avez besoin de plus d'​entrées concurrentes dans la table d'​états,​ vous pouvez augmenter la limite dans pf.conf avec :
 +
 +  set limit states 10000
 +
 +Le problème est de déterminer la plus grande valeur sûre pour laquelle ne sera pas déclenchée un échec d'​allocation de mémoire. C'est toujours un sujet trollesque, car il n'y a aucune formule simple pour calculer la valeur. Basiquement,​ vous devez augmenter la limite et vérifier que le PC reste stable après l'​atteinte de cette limite, en créant artificiellement beaucoup d'​entrées.
 +
 +
 +D'un autre côté, si vous avez 512Mo ou plus de RAM, vous pouvez maintenant employer 256Mo pour le noyau, quantité qui devrait suffire pour au moins 500 000 entrées dans la table d'​états. Et la plupart des personnes considèrent que c'est une grande quantité de connexions simultanées. Imaginez juste que chacune de ces connexions produise un seul paquet toutes les dix secondes, et vous vous retrouvez avec un flux de 50 000 paquets par seconde.
 +
 +De manière plus probable, vous n'​attendrez pas autant d'​états que cela. Mais quelque soit votre limite de nombre d'​états,​ il y a des cas où il sera atteint, comme pendant une attaque de déni-de-service. Rappelez-vous,​ pf échouera ​ quand la création d'​état échoue. Un attaquant pourrait créer des entrées dans la table d'​états jusqu'​à ce que la limite soit atteinte, juste afin d'​empêcher l'​accès à un(des) service(s) aux utilisateurs légitimes.
 +
 +Il y a plusieurs moyens de traiter ce problème.
 +
 +Vous pouvez limiter le nombre d'​états crées depuis une règle particulière,​ par exemple comme suit :
 +
 +  pass in from any to $ext_if port www keep state (max 256)
 +
 +Cela devrait limiter le nombre maximal de connexions simultanées au serveur web à 256, tandis que les autres règles pourraient continuer à créer des entrées dans la table d'​états. De manière similaire, le nombre maximal de connexions par adresse ip source pourrait être restreint comme suit :
 +
 +  pass keep state (source-track rule, max-src-states 16)
 +
 +Une fois qu'une entrée dans la table d'​états est crée, plusieurs délais d'​attente définissent quand elle est retirée. Par exemple:
 +
 +  $ pfctl -st
 +  tcp.opening ​                 30s
 +
 +Le délai d'​attente pour les états TCP qui ne sont pas encore entièrement établis est mis à 30 secondes. Ces délais peuvent être abaissés pour enlever les entrées de la table d'​états plus rapidement. Différents délais peuvent être placées globalement dans pf.conf :
 +
 + set timeout tcp.opening 20
 +
 +Ils peuvent aussi être placés dans des règles individuelles,​ et s'​appliqueront uniquement aux états crées par ces règles :
 +
 +  pass keep state (tcp.opening 10)
 +
 +Il y a de multiples jeux de délais globaux prédéfinis qui peuvent être choisis dans pf.conf:
 +
 +  set optimization aggressive
 +
 +Il y a aussi des délais adaptatifs, ce qui signifie que ces délais ne sont pas constants, mais variables. Ils peuvent être ajustés au nombre d'​entrées dans la table d'​états alloué. Par exemple :
 +
 +  set timeout { adaptive.start 6000, adaptive.end 12000 }
 +
 +pf emploiera des délais constants tant qu'il y a moins de 6 000 entrées dans la table d'​états. Quand il y a entre 6 000 et 12 000 entrées, touts les délais sont linéairement ajustés de 100% pour 6 000 entrées à 0% pour 12 000 entrées. Cela signifie par exemple qu'​avec 9 000 entrées toutes les délais sont réduits à 50%.
 +
 +En résumé, vous pouvez probablement indiquer un certain nombre d'​états maximum que vous comptez supporter. Placez-les comme limite pour pf. Attendez-vous à ce que la limite soit atteinte pendant certaines attaques, et définissez une stratégie de délais dans ces cas. Dans le pire des cas, pf rejettera des paquets quand l'​insertion dans la table d'​états échoue, et le compteur de dépassement-de-mémoire augmentera.
 +
 +
 +
 +=====Évaluation du jeu de règles=====
 +
 +Un jeu de règles est une liste linéaire de différentes règles, qui sont évaluées de haut en bas pour un paquet donné. Chaque règle correspond ou ne correspond pas au paquet, selon les critères de la règle et les valeurs correspondantes dans le paquet.
 +
 +Par conséquent,​ on peut estimer qu'en première approximation,​ le coût de l'​évaluation du jeu de règles se développe avec le nombre de règles présent. Cela n'est pas exactement vrai pour les raisons que nous allons bientôt expliquer, mais le concept général est correct. Un jeu de règles avec 10.000 règles causera presque certainement beaucoup plus de charge sur votre machine qu'un avec juste 100 règles. L'​optimisation la plus évidente est de réduire le nombre de règles.
 +
 +
 +
 +
 +
 +
 +
 +=====Trier le jeu de règles afin de maximiser les sauts d'​étapes=====
 +
 +La première raison pour laquelle l'​évaluation du jeu de règles peut être moins coûteuse que d'​évaluer individuellement chaque règle est appellée "saut d'​étape"​. C'est une optimisation transparente et automatique faite par pf quand le jeu de règles est chargé. Elle mieux est expliquée avec un exemple. Imaginez-vous avoir le jeu de règles simple suivant :
 +
 +  1. block in all
 +  2. pass in on fxp0 proto tcp from any to 10.1.2.3 port 22 keep state
 +  3. pass in on fxp0 proto tcp from any to 10.1.2.3 port 25 keep state
 +  4. pass in on fxp0 proto tcp from any to 10.1.2.3 port 80 keep state
 +  5. pass in on fxp0 proto tcp from any to 10.2.3.4 port 80 keep state
 +
 +Un paquet TCP arrive sur fxp0 avec comme adresse de destination 10.2.3.4 sur un certain port.
 +
 +pf commencera l'​évaluation du jeu de règles pour ce paquet avec la première règle, qui correspond entièrement. L'​évaluation continue avec la deuxième règle, qui correspond aux champs du paquet pour les critères "​in",​ "on fxp0" "proto tcp", "from any", mais ne correspond pas à "to 10.1.2.3"​. Ainsi la règle ne correspond pas, et l'​évaluation devrait continuer la troisième règle.
 +
 +Mais pf se rend compte que la troisième et quatrième règle indiquent également le même critère, "to 10.1.2.3",​ qui a fait que la deuxième règle n'a pas correspondu au paquet. Par conséquent,​ il est absolument certain que la troisième et quatrième règle ne puissent pas correspondre à ce paquet, et pf saute immédiatement à la cinquième règle, sauvant plusieurs comparaisons.
 +
 +Imaginez que le paquet sous inspection était un paquet UDP au lieu d'un paquet TCP. La première règle aurait correspondu,​ l'​évaluation aurait continué avec la deuxième règle. Là, le critère "proto tcp" n'​aurait pas correspondu avec le paquet. Puisque les règles suivantes indiquent également le même critère "proto tcp" qui s'est avéré ne pas correspondre au paquet, toutes pourraient être sans risque sautés, sans affecter les résultats de l'​évaluation.
 +
 +Voici comment pf analyse votre jeu de règles quand vous le chargez. Chaque règle peut contenir une liste de critères comme "to 10.1.2.3",​ limitant la règle aux paquets qui ont cette adresse de destination. Pour chaque critère dans chaque règle, pf compte le nombre de règles immédiatement au-dessous de cette règle qui spécifient exactement le même critère. Ceci peut être zéro, quand la prochaine règle n'​emploie pas exactement le même critère. Ou ce peut être tout nombre jusqu'​au nombre de règles restantes, quand toutes indiquent le même critère. Les nombres comptés sont stockés en mémoire pour usage postérieur. Ils s'​appellent des sauts d'​étapes parce qu'ils indiquent à pf combien d'​étapes suivantes (règles) peuvent être sautées quand n'​importe quel critère dans n'​importe quelle règle se trouve ne pas correspondre au paquet étant inspecté.
 +
 +L'​évaluation des règles compare les critères dans la règle avec les valeurs du paquet dans un ordre fixe : 
 +
 +  1. interface ('on fxp0')
 +  2. direction ('​in',​ '​out'​)
 +  3. famille d'​adresse ('​inet'​ or '​inet6'​)
 +  4. protocole ('​proto tcp')
 +  5. adresse source ('from 10.1.2.3'​)
 +  6. port source ('from port < 1024')
 +  7. adresse destination ('to 10.2.3.4'​)
 +  8. port destination ('to port 80')
 +
 +Si la règle correspond complètement,​ l'​évaluation continue sur la prchaine règle. Si la règle ne correspond pas, le premier critère de la liste ci-dessus qui ne correspond pas décide quel saut d'​étape est employé. Il pourrait y avoir plus d'un critère qui ne correspond pas, mais seulement le premier, dans l'​ordre de la liste ci-dessus, importe.
 +
 +Évidemment,​ l'​ordre des règles dans votre jeu de règles affecte les valeurs de saut d'​étape calculées pour chaque règle. Par exemple :
 +
 +  1. pass on fxp0
 +  2. pass on fxp1
 +  3. pass on fxp0
 +  4. pass on fxp1
 +
 +Ce jeu de règles produira des sauts d'​étapes de valeur zéro pour le critère d'​interface pour chaque règle, parce qu'​aucune règle adjacente ne contient le même critère d'​interface.
 +
 +Ces règles pourraient plutôt être dans cet ordre :
 +
 +  1. pass on fxp0
 +  2. pass on fxp0
 +  3. pass on fxp1
 +  4. pass on fxp1
 +
 +La valeur de saut d'​étape pour le critère d'​interface égalerait alors un dans la première et troisième règle.
 +
 +Ceci fait une petite différence quand le ruleset est évalué pour un paquet sur fxp2. Avant le tri, chacune des quatre règles est évalué parce qu'​aucune d'​entre elles ne peut être sautée. Après triage, seulement les règles une et trois doivent être évaluées, et les règles deux et quatre peuvent être sautées. La différence peut être insignifiante dans ce petit exemple, mais imaginez un jeu de règles contenir 1 000 règles et que toutes s'​appliquent seulement à deux interfaces différentes. Si vous triez ces règles de manière à ce que toutes les règles s'​appliquant à une interface soient adjacentes, suivi des règles s'​appliquant à l'​autre interface, pf peut sûrement sauter 500 règles dans chaque évaluation du jeu de règles, ramenant le coût de l'​évaluation de ruleset à 50%, quelque soit le genre de paquets qui compose votre traffic.
 +
 +Par conséquent,​ vous pouvez aider pf pour maximiser ses sauts d'​étapes en triant vos règles dans l'​ordre des critères énumérés ci-dessus, c'​est-à-dire trier d'​abord vos règles par interface. Dans le bloc de règles pour la même interface, trier les règles par direction. Dans le bloc pour la même interface et direction, trier par famille d'​adresse,​ etc.
 +
 +Pour vérifier les effets, lancez
 +
 +  $ pfctl -gsr
 +
 +pfctl montre les valeurs calculées de sauts d'​étapes pour chaque critère de chaque règle, par exemple
 +
 +  @18 block return-rst in quick on kue0 proto tcp from any to any port = 1433
 +  [ Skip steps: i=38 d=38 f=41 p=27 sa=48 sp=end da=43 ]
 +
 +Dans cet exemple, '​i'​ signifie interface, '​d'​ direction, '​f'​ famille d'​adresse,​ etc. La partie "​i=38"​ signifie que les paquets ne correspondant pas à "on kue0" sauteront les 38 prochaines règles.
 +
 +Cela affecte aussi le nombre d'​évaluations comptées pour chaque règle, essayez :
 +
 +  $ pfctl -vsr
 +
 +pfctl compte combien de fois chaque règle a été évaluée, combien de paquets et d'​octets la règle a fait passer et combien d'​états elle a créé. Lorsqu'​une règle est sautée par le saut d'​étapes durant l'​évaluation,​ ses compteurs d'​évaluations ne sont pas incrémentés.
 +
 +
 +
 +=====De l'​utilisation des tables pour les listes d'​adresses=====
 +
 +L'​utilisation des listes dans des accolades permet d'​écrire des règles très compactes dans pf.conf, comme :
 +
 +  pass proto tcp to { 10.1.2.3, 10.2.3.4 } port { ssh, www }
 +
 +Mais ces listes ne sont pas réellement chargées dans une règle simple dans le noyau. Au lieu de cela, pfctl développe la règle à une ligne à des règles multiples pour le kernel, dans ce cas-ci :
 +
 +  $ echo "pass proto tcp to { 10.1.2.3, 10.2.3.4 } port { ssh, www }" |
 + pfctl -nvf -
 +  pass inet proto tcp from any to 10.1.2.3 port = ssh keep state
 +  pass inet proto tcp from any to 10.1.2.3 port = www keep state
 +  pass inet proto tcp from any to 10.2.3.4 port = ssh keep state
 +  pass inet proto tcp from any to 10.2.3.4 port = www keep state
 +
 +
 +La syntaxe concise dans pf.conf trahit le vrai coût de l'​évaluation. Votre pf.conf pourrait être seulement constitué d'une douzaine de règles, mais si celles-ci se développent en centaines de règles dans le noyau, le coût d'​évaluation est comme si vous aviez mis ces centaines de règles dans pf.conf en premier lieu. Pour voir quelles règles vraiment sont évaluées, tapez :
 +
 +  $ pfctl -sr
 +
 +Pour un type spécifique de liste, adresses, il y a un conteneur dans le noyau, appelé "​table"​. Par exemple :
 +
 +  pass in from { 10.1.2.3, 10.2.3.4, 10.3.4.5 }
 +
 +La liste des adresses peut être mise sous la forme d'une table :
 +
 +  table <​clients>​ const { 10.1.2.3, 10.2.3.4, 10.3.4.5 }
 +  pass in from <​clients>​
 +
 +Cette construction peut être chargée comme une règle unique (et une simple table) dans le noyau, tandis que la version sans tables aurait été développée en trois règles.
 +
 +Pendant l'​évaluation de la règle contenant la table, pf fera une consultation de l'​adresse source du paquet dans la table pour déterminer si la règle correspond au paquet. Cette consultation est très peu coûteuse, et le coût n'​augmente pas avec le nombre d'​entrées dans la table.
 +
 +Si la liste d'​adresses est grande, le gain d'​exécution d'une évaluation de règle avec une consultation de table contre une évaluation de règle pour chaque adresse est significatif. En général, les tables sont meilleur marché quand la liste contient six adresses ou plus. Pour une liste de 1 000 adresses, la différence sera d'​unfacteur 1 000.
 +
 +
 +
 +
 +=====Utiliser quick pour arrêter l'​évaluation lorsqu'​une règle correspond=====
 +
 +Quand une règle correspond, pf (à la différence d'​autres produits de filtrage de paquets) n'​arrête pas l'​évaluation,​ mais continue jusqu'​à ce que toutes les règles aient été évaluées. Quand la fin des règles est atteinte, la dernière règle correspondante prend la décision.
 +
 +L'​option "​quick"​ peut être employée dans les règles pour leur faire arrêter l'​évaluation du jeu de règles quand elles correspondent. Quand "​quick"​ est employé sur chaque règle simple, le comportement du pf devient "​premier trouvé, de suite appliqué",​ mais ce n'est pas le cas par défaut.
 +
 +Par exemple, pf filtre des paquets passant par n'​importe quelle interface, y compris les interfaces virtuelles telles que l'​interface de boucle locale. Si, comme la plupart des personnes, vous n'avez pas l'​intention de filtrer le trafic local, une règle comme suivt au début de pf.conf peut sauver beaucoup d'​évaluations de règle :
 +
 +  set skip on { lo0 }
 +
 +Le jeu de règles pourrait contenir des centaines de règles ne s'​appliquant pas à l'​interface lo0, et le trafic local pourrait juste correspondre à la règle par défaut de laisser passer les paquets. La différence est qu'il faudrait évaluer ces centaines de règles pour chaque paquet transitant sur l'​interface locale.
 +
 +Habituellement,​ vous placeriez une règle avec le mot-clef "​quick"​ tout en haut du jeu de règles, car elle aurait le potentiel de correspondre et en conséquence de sauver l'​évaluation des règles plus bas. Mais dans ces cas où la règle ne correspond pas à un paquet, le placement de la règle au dessus a causé une évaluation de plus.
 +
 +En bref, pour des questions de performance,​ la fréquence avec laquelle une règle est prévue pour correspondre est également en rapport avec l'​endroit auquel vous décidez de la mettre dans votre jeu de règles. Et la fréquence avec laquelle elle correspond dépend de votre trafic réel. ​
 +
 +Au lieu de deviner comment une règle correspond probablement,​ vous pouvez employer l'​évaluation de règle et les compteurs assortis qui sont montrés par : 
 +
 +  $ pfctl -vsr
 +
 +Quand vous voyez une règle dans le haut du jeu qui est beaucoup évaluée mais qui correspond peu, vous pouvez la déplacer plus loin dans le jeu de règles.
 +
 +
 +=====Ancres avec évaluation conditionnelle=====
 +
 +Une ancre est fondamentalement un jeu de règles séparé du jeu de règles principal. Vous pouvez charger des jeux de règles entiers dans des ancres, et les faire évaluer depuis le jeu de règles principal.
 +
 +Une autre manière de les regarder est de comparer les règles de filtrage à un langage de programmation. Sans ancres, tout votre code est dans une fonction principale, le jeu de règles principal. Les ancres, alors, sont juste des sous-programmes,​ codés dans des fonctions séparées que vous pouvez appeler depuis la fonction principale.
 +
 +Depuis OpenBSD 3.6, vous pouvez également emboîter des ancres dans des ancres, établissant une hiérarchie de sous-programmes,​ et appeler un sous-programme depuis un autre. Dans OpenBSD 3.5 et avant, on ne pouvait avoir qu'un seul niveau de profondeur d'​ancres,​ c'​est-à-dire que vous pouviez avoir des sous-programmes multiples, mais ne pouviez appeler des sous-programmes que depuis le jeu de règles principal.
 +
 +Par exemple:
 +
 +  pass in proto tcp from 10.1.2.3 to 10.2.3.4 port www
 +  pass in proto udp from 10.1.2.3 to 10.2.3.4
 +  pass in proto tcp from 10.1.2.4 to 10.2.3.5 port www
 +  pass in proto tcp from 10.1.2.4 to 10.2.3.5 port ssh
 +  pass in proto udp from 10.1.2.4 to 10.2.3.5
 +  pass in proto tcp from 10.1.2.5 to 10.2.3.6 port www
 +  pass in proto udp from 10.1.2.5 to 10.2.3.6
 +  pass in proto tcp from 10.1.2.6 to 10.2.3.7 port www
 +
 +Vous pouvez séparer le jeu de règles en deux sous-jeux de règles, une pour UDP appellée "​udp-only"​ :
 +
 +  pass in proto udp from 10.1.2.3 to 10.2.3.4
 +  pass in proto udp from 10.1.2.4 to 10.2.3.5
 +  pass in proto udp from 10.1.2.5 to 10.2.3.6
 +
 +Et une autre pour TCP appellée "​tcp-only":​
 +
 +  pass in proto tcp from 10.1.2.3 to 10.2.3.4 port www
 +  pass in proto tcp from 10.1.2.4 to 10.2.3.5 port www
 +  pass in proto tcp from 10.1.2.4 to 10.2.3.5 port ssh
 +  pass in proto tcp from 10.1.2.5 to 10.2.3.6 port www
 +  pass in proto tcp from 10.1.2.6 to 10.2.3.7 port www
 +
 +Les deux pouvant être appellés depuis le jeu de règles principal avec:
 +
 +  anchor udp-only
 +  anchor tcp-only
 +
 +Cela n'​améliorerait cependant pas trop les performances. En fait, il y a même du temps système de dépensé lorsque le noyau doit sauter dans et en dehors de ces sous-jeux de règles.
 +
 +Mais les appels d'​ancres peuvent également contenir des critères de filtrage, comme les règles suivantes :
 +
 +  anchor udp-only in on fxp0 inet proto udp
 +  anchor tcp-only in on fxp0 inet proto tcp
 +
 +Le sous-jeu est seulement évalué pour les paquets qui correspondent aux critères. En d'​autres mots, la sous-routine est évaluée conditionellement. Lorsque le critère ne correspond pas, l'​appel est sauté, et le coût de l'​évaluation est limité à la comparaison du critère dans l'​appel d'​ancre.
 +
 +Pour des questions de performance,​ ceci est principalement pertinent lorsque les sous-jeux contiennent beaucoup de règles et que les critères d'​appel ne sont pas eux optimisés d'​abord par les sauts d'​étapes.
 +
 +
 +
 +
 +
 +
 +=====Laisser pfctl faire le boulot à votre place=====
 +
 +Depuis OpenBSD 3.6, la plupart des optimisations que nous avons vu précédemment peuvent être automatisées avec pfctl -o. Le moteur d'​optimisation analyse le jeu de règles et effectue des modifications qui ne changent par les effets du jeu de règles.
 +
 +D'​abord,​ pfctl coupe le jeu de règles en blocs de règles adjacentes de telle manière que trier les règles à l'​intérieur d'un bloc ne puisse pas affecter les résultats de l'​évaluation quelque soit le paquet.
 +
 +Par exemple, les règles dans le bloc suivant peuvent être arbitrairement triées :
 +
 +  pass proto tcp to 10.1.2.3 port www keep state
 +  pass proto udp to 10.1.2.3 port domain keep state
 +  pass proto tcp to 10.1.0.0/16 keep state
 +
 +Mais dans la plupart des cas l'​ordre est pertinent. Par exemple:
 +
 +  block log all
 +  block from 10.1.2.3
 +  pass from any to 10.2.3.4
 +
 +Changer la position d'une de ces règles produira des effects complètement différents. Si vous changez l'​ordre des deux premières règles, les paquets venant de 10.1.2.3 seront toujours bloqués, mais ils seront aussi à présent loggués. Permutez les deux dernières et les paquets depuis 10.1.2.3 vers 10.2.3.4 seront subitement bloqués. Et permuter la première et la troisième règle bloquera tous les paquets.
 +
 +Dans tous les cas où l'on peut avoir des regroupements,​ pfctl coupe les règles en blocs séparés. Dans le pire des cas, quand même deux règles adjacentes ne peuvent être réordonnées,​ chaque règle devient un bloc séparé contenant seulement cette règle, et pfctl ne peut faire aucune modification.
 +
 +Autrement, pfctl trie les règles dans chaque bloc de sorte que les valeurs de saut d'​étapes soient maximisées :
 +
 +  $ cat example
 +  pass proto tcp from 10.0.0.3 to 10.0.0.8
 +  pass proto udp from 10.0.0.1
 +  pass proto tcp from 10.0.0.2
 +  pass proto tcp from 10.0.0.4
 +  pass proto udp from 10.0.0.6
 +  pass proto tcp from 10.0.0.3 to 10.0.0.7
 +
 +  $ pfctl -onvf example
 +  pass inet proto tcp from 10.0.0.3 to 10.0.0.8
 +  pass inet proto tcp from 10.0.0.3 to 10.0.0.7
 +  pass inet proto tcp from 10.0.0.2 to any
 +  pass inet proto tcp from 10.0.0.4 to any
 +  pass inet proto udp from 10.0.0.1 to any
 +  pass inet proto udp from 10.0.0.6 to any
 +
 +Lorsque des règles identiques sont trouvées, elles sont retirées:
 +
 +  $ cat example
 +  pass proto tcp from 10.0.0.1
 +  pass proto udp from 10.0.0.2
 +  pass proto tcp from 10.0.0.1
 +
 +  $ pfctl -onvf example
 +  pass inet proto tcp from 10.0.0.1 to any
 +  pass inet proto udp from 10.0.0.2 to any
 +
 +Les règles redondantes sont aussi retirées:
 +
 +  $ cat example
 +  pass proto tcp from 10.1/16
 +  pass proto tcp from 10.1.2.3
 +  pass proto tcp from 10/8
 +
 +  $ pfctl -onvf example
 +  pass inet proto tcp from 10.0.0.0/8 to any
 +
 +
 +Lorsque c'est possible et avantageux, de multiples règles sont combinées dans une simple règle en utilisant une table :
 +
 +  $ cat example
 +  pass from 10.1.2.3
 +  pass from 10.2.3.4
 +  pass from 10.3.4.5
 +  pass from 10.4.5.6
 +  pass from 10.5.6.7
 +  pass from 10.8.9.1
 +
 +  $ pfctl -onvf example
 +  table <​__automatic_0>​ const { 10.1.2.3 10.2.3.4 10.3.4.5 10.4.5.6
 +                                10.5.6.7 10.8.9.1 }
 +  pass inet from <​__automatic_0>​ to any
 +
 +Lorsque pfctl est invoqué avec le switch -oo, il consulte également les compteurs d'​évaluation indiqués par pfctl -vsr afin de trier les règles "​quick"​ en rapport avec la fréquence de correspondance.
 +
 +pfctl est très conservateur dans les changements,​ exécutant seulement les changements qui sont sûrs de ne pas affecter les résultats de l'​évaluation du jeu de règles dans n'​importe quelles circonstances pour n'​importe quel paquet. Ceci a l'​avantage que l'​optimiseur peut être employé sans risque avec n'​importe quel jeu de règles. L'​inconvénient est que pfctl peut ne pas changer quelque chose que vous auriez aimé voir changé, si vous pensez à l'​effet du changement. Comme l'​optimisation de sauts d'​étape,​ le gain de performances dépend grandement de la façon dont les blocs de règles sont triables. Par un tri manuel en premier lieu, vous pouvez potentiellement améliorer ce que produira l'​optimiseur.
 +
 +La manière la plus facile de voir ce que -o ou -oo fait avec votre ruleset est de comparer sa suggestion au jeu de règles original, comme ceci :
 +
 +  $ pfctl -nvf /​etc/​pf.conf >before
 +  $ pfctl -oonvf /​etc/​pf.conf >after
 +  $ diff -u before after
 +
 +Lorsque l'​optimiseur est exécuté sur un jeu de règles manuellement optimisé, les différences sont assez peu spectaculaires. Des améliorations significatives peuvent être attendues lorsqu'​on l'​utilise sur des règles produites par des frontaux.
 +
 +Copyright (c) 2004-2006 Daniel Hartmeier <​daniel@benzedrine.cx>​. Permission to use, copy, modify, and distribute this documentation for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
 +
 +Copyright (c) 2006 Mat <mat gcu-squad org>. Permission est donnée ici d'​utiliser,​ copier, modifier et redistribuer cette traduction pour quoi que cela soit avec ou sans profits, à condition que ce copyright et cette notice de permissions apparaissent sur toutes les copies.
bsd/pf_poilu_fr.txt · Last modified: 2010/01/12 13:29 (external edit)