Massive Attack : an overview on advanced DDoS mitigation cns at minithins.net Last Update > 07/03/2004 > ongoing JunOS 6.2 support, Cisco's uRPF and CAR fixed To Do > feed me with configurations for Foundry (ACL, rate-limit, AQM, CBAC-like, {black,sink}holing) http://www.foundrynet.com/services/documentation/ > DocBook translation (then make a big chunky html) "Semper ego auditor tantum ? Nunquamne reponam ?" Thomas de Quincey, De l'Assassinat considéré comme un des Beaux-Arts Résumé Cet article offre un aperçu - un instantané même - des méthodes les plus avancées, en cours de déploiement, d'expérimentation ou de développement, permettant de lutter contre les Distributed Denial of Service et même, parfois, d'identifier leurs auteurs. Ces techniques agissant soit directement sur le chemin, soit sur le management de queues, elles s'appliquent de facto à l'infrastructure réseau et en particulier aux routeurs, constituant le coeur du net, son squelette. Ce document se focalise sur le matériel Cisco mais abordera éventuellement d'autres systèmes, libres (*BSD, Linux, Zebra) ou propriétaires (Juniper, Foundry). Il est admis que vous connaissez au moins basiquement ces systèmes et que vous possédez une bonne compréhension du modèle TCP/IP et des disciplines d'évitement de congestion des implémentations TCP (New)Reno. La sécurisation complète d'infrastructure Cisco (pas uniquement contre les DoS) est par ailleurs résumée dans une présentation en [FIS02]. 1. Rappels 2. Path-oriented 2.1. ACL 2.2. RPF 2.3. Route filtering 2.4. {Black,Sink}hole 2.5. NBAR 2.6. iTrace 2.7. SPIE 2.8. IP Source Tracker 3. Exhaustion-oriented 3.1. RED 3.2. ECN 3.3. CAR 3.4. ACC 3.5. CBAC 3.6. TCP SYN Cookies 4. Conclusion 5. Références 1. Rappels Tout d'abord, quelques rapides rappels sur ce que sont les DoS et leurs différents types, qui ne cessent d'augmenter et de s'étoffer de jour en jour [CHAR]. Un Denial of Service ou DoS est une attaque destinée à limiter ou empêcher le bon fonctionnement, la disponibilité d'une machine. Les DoS agissent la plupart du temps par Ressource Starvation, c'est-à-dire qu'ils consomment un maximum de ressources (CPU, RAM...) de la machine attaquée afin de la rendre inopérante. Avec assez de ressources du côté attaquant, n'importe quelle machine est susceptible d'être victime d'un DoS par 'ressource starvation'. Mais il existe plusieurs méthodes permettant de faire beaucoup de dégâts avec peu de ressources. En premier lieu desquelles, et sans doute par ordre de célébrité, on trouve les smurfs. Les smurfs agissent à partir du protocole ICMP et des adresses IP broadcast. L'attaquant envoie un paquet ICMP echo request à une ou même plusieurs adresses broadcast (de préférence appartenant à des réseaux de classes B voire A) en usurpant l'adresse de l'hôte cible, ainsi les echo reply de la totalité des hôtes se trouvant derrière l'adresse broadcast (jusqu'à 65535 machines pour une classe B) répondront à la machine cible tous en même temps entraînant la situation de DoS. Le réseau de l'adresse broadcast agit ici comme réflecteur pour le DoS. Une autre méthode très répandue est le SYN flood. Elle exploite TCP en créant un nombre important de connexions semi-ouvertes dans un intervalles de temps restreint. Chaque segment TCP avec le flag SYN déclenche chez l'hôte cible la création d'un espace mémoire communément appelée TCP Control Block (TCB) contenant les informations relatives à la connexion. Une fois le SYN reçu, l'hôte renvoie un SYN/ACK puis attendant de recevoir un ACK afin de compléter le processus d'initialisation. Cependant, les segments du SYN flood auront été spoofé de sorte que l'hôte cible ne reçoive jamais de ACK en réponse et reste en état SYN-RECEIVED. La succession rapide de création de TCB remplissant les queues de connexions en état incomplet finit par consommer assez de mémoire pour ralentir ou stopper l'hôte cible. Une variation récente de cette attaque, appelée Naptha [NAP00], a été dévoilé. Le principe reste le même, à savoir la consommation des ressources mémoire par la création rapide d'un grand nombre de TCB. Mais afin de contourner les nombreuses parades qui ont été mise en place contre les SYN floods, le naptha tente d'initialiser complètement une connexion puis de laisser l'hôte cible en état ESTABLISHED après avoir envoyé un unique ACK après le SYN/ACK, ou en état CLOSE-WAIT après lui avoir un ACK suivi d'un FIN initialisant le four-way handshake de déconnexion. Pour éviter de consommer un TCB de son côté, l'attaquant doit ici réaliser une connexion en TCP blind spoofing. Ce dernier détail rend l'attaque bien plus complexe puisqu'elle nécessite la prédiction de Sequence Number TCP générés par des Pseudo Random Number Generator (PRNG). Cependant de récents travaux [ZAL01] sur l'utilisation des attracteurs étranges pour l'identification de patterns de génération pourrait faciliter la mise en application des napthas. Mais une condition de DoS peut aussi apparaître avec un faible nombre de paquets par exemple à cause d'une erreur dans une application. Ce cas de figure s'est par exemple présenté début 2002 dans BlackICE Defender, outil de sécurité réseau propriétaire. En interceptant un paquet ICMP similaire à un Ping of Death - c'est-à-dire légitime mais fragmenté et forgé de manière à être hors limite une fois réassemblé par le destinataire, causant crash ou ralentissement - crashait à son tour, entraînant parfois son hôte à sa suite. La faille, qui s'est finalement avérée être un buffer overflow, était ici due à un bug de gestion du trafic en sortie du driver propriétaire utilisé par BlackICE pour l'interception des paquets sous Windows 2000 et Windows XP. De même il y a quelques années existait le small footprint DoS, contre TCPdump et ses dérivés, consistant en un unique paquet avec les champs IP Version et IP Total Length mis à 0. Ces cas sont doublement dangereux puisqu'ils représentent des DoS applicatifs nécessitant une signature mais attaquent en plus les applications utilisant ces signatures. Ces types de vulnérabilités peuvent être spécifiques à un système, un logiciel, ou même une configuration particulière de plusieurs d'entre eux. Plus simple mais tout aussi destructeur, une attaque, semblable aux SYN flood que nous avons vus, peut être ciblé contre une machine ou un service critique dont la dégradation des performances entraînera un effet de bord assimilable à un DoS. C'est par exemple ce qu'à souligné un récent draft IETF sur la sécurité du protocole BGPv4 [MUR03]. Toutes ces méthodes peuvent aisément être combinées. Une dizaine d'année de cela, les ISP ont remarqué le développement inquiétant du phénomène de 'route flap'. Ce terme désigne le retrait et l'annonce successive et répétée de routes sur une courte échelle de temps. Chaque flap pousse le routeur à mettre à jour sa table de routage, causant une surcharge non néglibéable. D'autre part, les délais de convergence des routes au niveau global donnent aux flaps un impact important sur la stabilité du routage. En réponse, les organisations liées au routage ont rapidement déployée une proposition de Curtis Villamizar, résumée ensuite dans la RFC 2439 [2439], nommée route flap damping. Cette technique consiste à surveiller les retraits et réannonces, en ajoutant une pénalité à une route à chaque retrait. Lorsqu'on dépasse une certaine valeur de pénalité, c'est-à-dire qu'on observe un nombre de flap élevé sur une courte période, la route n'est plus utilisée ni annoncée pour une durée prédéterminée partant du dernier flap ; chaque flap redéclenchant le timer en augmentant le compteur de pénalité. En effet, ce compteur diminue en fonction du temps, tant qu'on observe plus aucun nouveau flap. Lorsqu'il repasse en-dessous d'un seuil de réutilisation, la route retrouve sa place dans les tables de routage. Le problème vient alors du fait qu'un attaquant peut très bien forcer une route à "flapper" pour subir des pénalités et donc disparaître d'Internet. Une vaste attaque coordonnée peut même complétement couper un réseau de ses voisins. Il suffit de lancer un flood sur le routeur, en particulier sur le port 179/tcp habituellement utilisé pour les sessions BGP. Le manque de ressources provoquera éventuellement des timeouts voire un reboot du routeur. Cette interruption des sessions, si répétée, sera rapidement assimilée à du flapping, et donc pénalisée. Le RIPE a publié un document très complet sur la bonne utilisation du damping [RIPE01] encourageant notamment l'utilisation des messages BGP du type REFRESH et des équivalents à la 'soft-configuration' de Cisco. Ces deux techniques permettent en effet de modifier une politique BGP sans nécessiter une réinitialisation de la session, potentiellement assimilée à du flapping. De même, le "proggressive damping" incite à pénaliser plus fortement les prefixes courts puisque les prefixes longs sont plus stables et leur suppression causerait, selon toute vraisemblance, plus de désagréments pour les utilisateurs. Cela revient concrêtement à encourager fortement l'agrégation des routes. Enfin, les serveurs racines DNS sont protégés et listés comme 'Golden Networks'. Malgré tout, ce type d'attaques combinées, entraînant un DoS en cascade, demeure réalisable pour qui dispose de connaissances et d'une organisation rigoureuse. La dernière classe de DoS que nous aborderons n'est pas réellement une méthode en soit mais plutôt un raffinement. Il s'agit de faire partir l'attaque non plus d'un unique hôte attaquant, mais d'une multitude de serveurs esclaves contrôlés par un client maître, potentiellement via plusieurs proxies. C'est ainsi que fonctionnent les outils Trinoo, Tribal Flood Network 2000 (TFN2k) et Stacheldaht dont vous pourrez trouver des analyses individuelles détaillées sur le site de Dave Dittrich [DITT]. Stacheldaht s'est rendu célèbre début 2001 lors des impressionnantes mais triviales attaques contre Yahoo!, CNN, eBay et bien d'autres. Ces outils agissent habituellement par une génération simple d'un grand nombre d'ICMP echo reply ou d'UDP echo sans grande finesse. Mais n'importe laquelle des attaques déjà décrites peut être appliquée à cette architecture distribuée, à laquelle on a attribué la dénomination DDoS pour Distributed Denial of Service. Ils nécessitent de plus le contrôle d'un nombre important de machines ce qui pousse leurs utilisateurs à l'intrusion massive, quasiment industrielle, allant jusqu'à exploiter des worms, comme ce fut le cas de Code Red II en 2001 dont chaque instance ciblait le site de la Maison Blanche. Outre les DoS massifs ou non, protocolaires ou applicatifs, il faut également remarquer une autre source involontaire mais néanmoins dévastatrice : les worms. Depuis 1988 et l'Internet Worm de Robert Morris, ces applications automatiques se propageant sur les réseaux au gré des vulnérabilités ont énormément évolués [PAX+02]. Ainsi les nouvelles concernant l'apparition de nouveaux worms se sont multipliés ces dernières années, et des noms comme Code Red et Nimda entre juillet et septembre 2001, ou Sapphire début 2003, sont désormais célèbres. L'analyse de ce dernier [WEA+03], a permis d'établir une classification entre Sapphire, restraint par la bande passante, et Code Red et Nimda de l'autre côté, limités par la latence. En effet, Sapphire, exploitant une faille SQL Microsoft, ne nécessitait qu'un unique paquet UDP de 404 octets, permettait une propagation rapide et aveugle. Le vers a ainsi pu contaminé 90% des hôtes vulnérables en 10 minutes, utilisant dans ce laps de temps énormément de bande passante : "[Sapphire] caused considerable harm simply by overloading networks and taking database servers out of operation. Many individual sites lost connectivity as their access bandwidth was saturated by local copies of the worm and there were several reports of Internet backbone disruption" [WEA+03] A l'opposé, Code Red et Nimda utilisaient des transmissions TCP et se trouvaient limités par la durée de synchronisation, imposée par le protocole via le three-way handshake, et les procédures d'acquittement. La vitesse de propagation étaient donc fonction des délais dans les réseaux. La quantité de mise en tampon - Code Red faisant 4ko et Nimda 60ko - a nécessairement dégradé ces délais et la fiabilité des transmissions. Malgré cela, une meilleure utilisation du multithreading aurait pu rendre ces vers tout aussi dévastateurs, du point de vue des DoS, que Sapphire, comme l'ont montré Paxson & al. en [WEA+03]. Plus particulièrement, Code Red I, attaquant les serveurs Microsoft IIS à l'instar de Code Red II et Nimda, se propageait par l'intermédiaire de 99 threads concurrents avec en plus un bug qui poussait un thread particulier à scanner la même séquence d'adresses IP, pouvant créer des situations de DoS vers ces adresses. Nimda quant à lui utilisait jusqu'à 5 vecteurs de propagation, du web au mail en passant par les partitions partagés, multipliant d'autant l'apparition de conditions de DoS pendant son expansion. Comme vous le voyez, le risque est omniprésent et nécessite donc une large protection. Notez cependant que les technologies présentées dans cet article ne concernent en aucun cas les attaques applicatives, du fait de leur spécifité. Les seules protections résideraient alors en un processus complexe d'audit permettant de dégager des signatures uniques. Celles-ci pourraient ensuite être éventuellement utilisées par un IDS pour détecter ces attaques, et parfois même les arrêter. Bien que le principe de contre-mesures soit encore bien peu développé dans le domaine de la sécurité, vous pouvez déjà trouver quelques exemples d'application dans les IDS Prelude et les développements de Snort tels Guardian, Hogwash ou encore FlexResp (ou même, dans une certaine mesure, Cisco Firewall IDS et NBAR, étudiés dans cet article). Cette catégorie d'outils intégrés étant désormais nommés Intrusion Prevention System. Nous nous intéresserons ici principalement aux technologies capables de détecter, prévenir ou identifier un DDoS. Elles doivent alors pouvoir s'appliquer à un réseau entier à travers le matériel en formant l'architecture. C'est à cause de cette optique généraliste que les technologies étudiées suivront le plus souvent un modèle anomaly-based et se baseront sur les statistiques. Les deux orientations que nous avons suivies pour notre étude sont l'identification et le contrôle des DDoS en fonction de leur chemin (path-oriented) ou en fonction de l'utilisation des ressources (exhaustion-oriented). La première partie accueille également les descriptions de plusieurs schémas d'identification de la source. Ce n'est pas seulement un élément utile lors de la phase de forensic mais également, devant le manque criant de mesures automatiques dans la lutte contre les DDoS, une source d'information essentielle à obtenir le plus rapidement afin d'appliquer des mesures réactives au plus près de la source. La seconde approche s'est quant à elle vu récemment confirmée dans un article évoquant la limitation des DoS par une surveillance stricte du Quality of Service (QoS) [RED+02]. 2. Path-oriented Les DoS ont toujours une source, qu'elle soit directe ou indirecte. Une solution évidente pour arrêter un DoS est tout simplement de bloquer les paquets vecteurs de condition de DoS. Cependant, lorsqu'on s'intéresse plus particulièrement aux DDoS, non applicatifs le plus souvent, les sources se multiplient et se falsifient plus aisément. Il dévient alors des plus ardus d'en identifier la source afin de constituer un agrégat capable de servir au pistage, dit traceback, ou au simple blocage. D'autre part, le protocole BGP, utilisé pour l'annonce de routes entre routeurs, offre certaines possibilités de configuration dangereuse, telles l'annonce de routes vers des adresses privées ou non allouées ainsi que, plus généralement, l'annonce de prefixes n'appartenant pas au réseau annonceur. Ces erreurs, intentionelles ou non, peuvent alors renforcer un DDoS en suscitant d'importantes quantités de messages ICMP host unreachable, éventuellement en supprimant toute possibilité de communication avec les prefixes illégalement annoncés. Nous observons donc que les DDoS viennent ne tirent pas seulement partie d'approximations dans le design des protocoles de niveau OSI 3 ou 4, mais également des erreurs de configurations de l'infrastructure réseau. Ces deux conditions réunies offrent aux DDoS la possibilité de résonner plus fort encore et de causer plus de dégâts. Dans cette première partie, nous allons donc nous intéresser en particulier aux procédés touchant à la caractérisation et au cheminement du paquet dans le réseau. Plus concrètement, cela indique une étude poussée des mécanismes liés au filtrage, blocage ou comptabilité du trafic. Les deux premiers permettent de restreindre ou supprimer complétement l'impact d'un DDoS en limitant ses capacités de résonance. Le dernier point, quant à lui, permettra de compenser à la fois les erreurs de design et de configuration pour réduire l'anonymité de l'attaque. Ceci aura pour effet de faciliter la prise de contre-mesures actives en identifiant cibles et attaquants, tout en rendant l'attaque moins aisée et séduisante à entreprendre. 2.1. ACL ACL, pour Access Control List, est le terme désignant les règles de filtrage sur les systèmes Cisco. Plus généralement, nous aborderons les techniques logicielles permettant, à un routeur ou un firewall, de filtrer le trafic selon agrégat. Les principales DDoS ne possédant pas de signature particulière ou bien facilement modifiable, la détection par pattern matching comme dans les IDS s'avère inopérante. Le filtrage dynamique brut contre un attaquant s'avère également peu utile puisque la bande passante en amont s'avère toujours utilisée. Ce point force d'ailleurs les responsables d'une infrastructure réseau à placer les protections le plus proche possible de l'attaquant, donc généralement au niveau des border routers. Mais la principale opposition au filtrage dynamique est tout simplement l'utilisation systématique du spoofing dans ces techniques. Pour limiter cela, quelques règles simples peuvent être appliquées. D'abord pour éviter que notre réseau ne serve de réflecteur pour un smurf, nous avons la possibilité chez Cisco d'interdire les réponses à un broadcast issue d'une adresse unicast. Notez que cette configuration est celle par défaut depuis IOS 12.0. router(config)#interface ethernet 0 router(config-if)#no ip directed-broadcast Nous allons ensuite filtrer plusieurs blocs d'adresses que nous savons attribuées à des réseaux privés non routables sur Internet, ou bien réservées à des usages expérimentaux. Cette politique de filtrage ingress est résumée parfaitement dans la RFC 2267 [1812][2267]. Plusieurs de ces adresses sont indiquées dans la RFC 1918 accompagnées de leur politique de routage comme ci-dessous "Because private addresses have no global meaning, routing information about private networks shall not be propagated on inter-enterprise links, and packets with private source or destination addresses should not be forwarded across such links. Routers in networks not using private address space, especially those of Internet service providers, are expected to be configured to reject (filter out) routing information about private networks. If such a router receives such information the rejection shall not be treated as a routing protocol error." Les blocs que nous filtreront selon la RFC 1918 sont : - 0.0.0.0/8 représentant une machine sans adresse ce qui ne doit pas exister - 127.0.0.0/8 représentant l'interface de loopback - 169.254.0.0/16 utilisé comme adresse d'autoconfiguration en cas d'échec avec DHCP - 192.0.2.0/24 réservé pour documentation et test - 192.168.0.0/16 ; 172.16.0.0/12 et 10.0.0.0/8 pour les adresses privées - 224.0.0.0/3 représentant des réseaux multicast de classe D notamment utilisé par OSPF et certains broadcast videos, et expérimentaux de classe E Pour plus d'informations sur l'assignation d'espaces d'adresses et même de numéros d'Autonomous System (privés de 64512 à 65535), référez vous aux RFC 1166 et 1466 et aux registres de l'IANA [IANA] sur l'adressage IPv4 listant plusieurs classes C. Enfin, fin 2002, l'IANA a souhaité résumé en un seul document ces contenus dispérsés au sein de la RFC 3330 [3330]. Nous ne nous sommes cependant pas appuyés sur les listes proposées et très régulièrement mises à jours par Cymru [CYMRU], du fait justement de l'instabilité de cette liste. Elle est cependant de plus en plus reconnue et digne de confiance. Elle est, de plus, accompagnée de configuration prête-à-l'emploir pour Cisco et Juniper. Sur les routeurs Cisco, nous allons configurer des access-list. Cette opération s'effectue en mode 'configure terminal' : router#configure Configuring from terminal, memory, or network [terminal]? Enter configuration commands, one per line. End with CNTL/Z. router(config)# La commande access-list se décompose de la manière suivante : access-list {permit | deny | remark} [log [log-input]] Number a la double fonction de numéroter l'access list, et donc par extension, l'access group, tout en spécifiant le type d'ACL souhaité. De 1 à 99 ce sont des ACL standards tout comme de 1300 à 1999 si cela ne suffit pas ; de même, de 100 à 199 et de 2000 à 2699, nous avons affaire à des Extended ACL. La liste n'est pas exhaustive, et vous en apprendrez bien plus en tapant : router#access list ? Nous utiliserons les EACL contrôlant la source, la destination, le protocole et le port. Les différents mots-clés qu'elles nous permettent d'utiliser sont les suivants : - 'permit' et 'deny' permettent de laisser passer ou de bloquer un paquet tandis que 'remark' permet de placer un commentaire - 'protocol' matche les paquets d'un protocole donnée (eigrp, gre, icmp, igmp, igrp, ip, ipinip, nos, ospf, tcp, ou udp) - 'source' correspond à l'adresse IP à bloquer, et 'source mask' à son masque de sous-réseau en notation inversée. En mettant ce champ à any, votre règle sera valable quelque soit l'adresse. - le champ suivant est constitué d'un opérateur 'lt' pour inférieur à, 'gt' pour supérieur à, 'eq' pour égal ou 'neq' pour différent, suivi du numéro de port source. L'utilisation de comparateurs permettra de filtrer selon une gamme de ports. - 'destination', 'destination mask' et 'destination port', sont équivalent aux champs précédents pour la destination - 'options' peut prendre pour valeur 'tos' (max-reliability, max-throughput, min-delay, min-monetary-cost, normal) ou 'precedence' (critical, flash, flash-override, immediate, internet, network, priority, routine) avec le protocole IP pour filtrer selon le ToS ou l'IP Precedence, respectivement. Mais vous pouvez également spécifier l'état 'established' pour TCP vérifiant ainsi la présence du flag ACK, ou bien, pour ICMP, la paire type/code ou simplement le nom du message. - Les derniers mots-clés coïncident avec les instructions de journalisation, soit 'log' pour une journalisation classique des informations du paquet, suivi éventuellement de 'log-input' pour ajouter à ces informations les adresses MAC et l'interface de réception. Notez qu'un paquet unique n'est enregistré qu'une seule fois toute les 5 minutes, les données journalisées se voyant alors complétées par un compter du nombre d'occurence. ------------------------------------ SNiP ------------------------------------- no access-list 101 ! filtrage selon les RFCs 1918, 1166, 1466 et 3330 access-list 101 deny ip 0.0.0.0 0.255.255.255 any log log-input access-list 101 deny ip 10.0.0.0 0.255.255.255 any log log-input access-list 101 deny ip 14.0.0.0 0.255.255.255 any log log-input access-list 101 deny ip 24.0.0.0 0.255.255.255 any log log-input access-list 101 deny ip 127.0.0.0 0.255.255.255 any log log-input access-list 101 deny ip 169.254.0.0 0.0.255.255 any log log-input access-list 101 deny ip 172.16.0.0 0.15.255.255 any log log-input access-list 101 deny ip 192.0.2.0 0.0.0.255 any log log-input access-list 101 deny ip 198.18.0.0 0.1.255.255 any log log-input access-list 101 deny ip 192.88.99.0 0.0.0.255 any log log-input access-list 101 deny ip 192.168.0.0 0.0.255.255 any log log-input access-list 101 deny ip 224.0.0.0 31.255.255.255 any log log-input access-list 101 deny ip 240.0.0.0 15.255.255.255 ant log log-input ! Bonus Track : Sun Microsystems cluster interconnects access-list 101 deny ip 204.152.64.0 0.0.0.255 any log log-input ! adresses internes arrivant depuis l'extérieur access-list 101 deny ip any log log-input ------------------------------------ SNiP ------------------------------------- Il ne reste plus qu'à appliquer cette configuration à votre routeur, sur l'interface de sortie, bien entendu : router(config)#interface ethernet 0 router(config-if)#ip access-group 101 in router(config-if)#^Z router#write Building configuration... [OK] router# Cette configuration est à appliquer sur l'interface externe en entrée. Mais elle peut - et même doit ! - s'appliquer tout aussi bien en output sur l'une des interfaces pour éviter de laisser fuir des adresses non-autorisées. Si vous êtes chargés de l'administration d'un réseau important, et remaquez que vos access-lists s'allongent de manière inquiètante pour les performances de vos routeurs, sachez qu'il existe une solution. En effet, depuis IOS 12.0(6)S, les ACL ont la possibilité d'être compilées, devenant ainsi des Turbo ACL. Le ruleset est remplacé par une structure de données, dites lookup tables, proche des tables de routage. Le parcours du ruleset est alors remplacé par des comparaisons avec entre les en-têtes de paquets et ces lookup tables. Le tout en conservant la règle du "first match win" (arrêt à la première équivalence entre un paquet et une règle) propres aux ACL Cisco. Il suffit, pour effectuer la compilation, d'entrée la ligne suivante : router(config)#access-list compiled La documentation Cisco [TACL] affirme que pour des rulesets de plus de 3 entrées, grâce aux lookup tables, la charge CPU et la durée de recherche de concordance sont désormais fixes, quelqu'eût été la taille du ruleset d'origine maintenant compilé. La compensation est une consommation supérieure à la normale de mémoire, de l'ordre de un Mo par access-group. Il devient alors capital de correctement grouper ses règles. D'autre part, si votre ruleset comporte des ACL de type reflexive, dynamique ou bornées dans le temps, celles-ci se verront exclues de la compilation. Ce genre de configuration peut créer des situations peu confortables ou ACL exotiques en liste et ACL classiques compilées fonctionnent parallèlement. Les Turbo ACL demeurent toutefois intéressantes pour obtenir un filtrage restrictif qui ne pénalise les opérations de routage à son profit. La commande 'show access-list compiled' propose des informations très complètes en particulier pour déterminer les règles exotiques qui n'ont pas pu être compilées. Celle-ci seront alors affichées par la commande accompagnées de la mention "Unsuitable" dans la colonne "State" : router#show access-list compiled Vous trouverez plus de détails sur les ACL en [RIP]. Sachez également, dans un souci d'interopérabilité, que la configuration et la syntaxe des ACL sont très similaires pour GNU Zebra [ZEBRA], le sous-système de routage libre le plus complet à ce jour. Pour aller encore un peu plus loin avec les technologies Cisco, sachez que vous disposez d'un des rares dispositifs intégrés liant IDS et firewall, au sein du Firewall IDS [FIDS], présent depuis IOS 12.0(5)T. Comme tout bon IDS, il inspecte chaque paquets ou sessions traversant le routeur, à la recherche d'analogies avec l'une de ses 59 signatures. Il est alors capable, en outre de la classique journalisation, de prendre des actions en réponses à une alerte afin de contrecarrer une attaque en cours, et ce de manière complètement automatisée. Pour les amateurs de Cisco jusqu'au bout des ongles, il sera même possible de l'intégré comme senseur du Secure IDS (c'est-à-dire NetRanger) et d'obtenir un système de journalisation des alertes centralisé. Les signatures utilisées sont basiquement hierarchisée, entre 'atomic' pour celles concernant un unique paquet et 'compound' lorsqu'on surveille une suite d'actions ou d'états (hierarchie interne au système), ou entre 'info' pour les actions de reconnaissances (généralement atomiques) et 'attack' pour les attaques complètes (plutôt compound). Les réponses, quant à elles, sont 'alarm' pour alerter via syslog, 'drop' pour rejeter le paquet et 'reset', reservé au transmission TCP, qui permet de terminer une connexion en envoyant un segment RST à chaque extrêmité. Vous pouvez tout d'abord configurer le comportement par défaut pour les deux types de signatures attack et info, c'est-à-dire une ou plusieurs des 3 actions présentées : router(config)#ip audit info action alarm router(config)#ip audit attack action alarm drop reset Comme notre sujet se concentre sur les DDoS, il est assez inutile de consommer des ressources au niveau des routeurs pour tenter de détecter toutes les attaques. Firewall IDS est en effet un gros consommateur de ressources, comme tout IDS ou firewall, à cause de la recherche de correspondances ou de la notification. D'autre part, il apparaît évident que 59 signatures sont bien peu de choses face aux nouvelles attaques découvertes chaque jour. Même si la volonté de Cisco était de constituer un système à jour, ce qui nécessiterait des mises à jour régulières, la méthodologie de mise à jour d'IOS deviendrait vite épuisante. Un IDS dédié sera plus à même de se consacrer à la détection d'attaques, disposant d'un ruleset certainement plus à jour. Heureusement, Firewall IDS offre la possibilité de désactiver des signatures. router(config)#ip audit signature {disable | list } Signature-id est un numéro d'identification d'une signature. Vous pourrez trouver la liste complète dans la documentation Cisco [FIDS] ou dans la NetRanger Network Security Database. Dans notre cas, elles seront toutes désactivées (disable) à l'exception des signatures 3050 (SYN flood), 2154 (Ping of Death) et 3106 (spam). La seconde option, list, permet d'attacher une signature à un numéro d'ACL. Mais cette opération sera de toutes manières réalisée par la commande suivante : router(config)#ip audit name {info | attack} [list ] [action [alarm] [drop] [reset]] 'ip audit name' permet d'attacher un type entier de signatures à une ACL, tout en définissant les actions à prendre. Ces dernières prendront le dessus sur la configuration par défaut. Vous trouverez ci-dessous un exemple d'application avec et sans couplage à une ACL. ------------------------------------ SNiP ------------------------------------- ! application sans ACL ip audit signature 1000 disable ip audit name reco info action alarm ! seules les Standard ACL sont acceptées ip audit name forged list 99 alarm drop reset access-list 99 deny 198.162.0.0 0.0.255.255 ------------------------------------ SNiP ------------------------------------- Remarquez que lier une règle d'audit et une ACL n'est absolument pas obligatoire. Cette méthode permet seulement, avec 'ip audit signature', de personnaliser totalement le set de signatures utilisées selon l'hôte ou le réseau, pour protéger ce qu'on appelle communemment des trusted hosts. Il ne reste plus alors qu'à attacher vos règles d'audit à une interface, comme pour une ACL : router(config)#interface ethernet 0 router(config-if)#ip audit {in | out} Typiquement, on attachera les règles dans le sens rentrant (in) pour une interface externe et dans le sens sortant (out) pour une interface interne. Notez que la règle 3106 se rapportant à la détection du spam nécessite une petite configuration supplémentaire. Elle se base en effet sur le nombre d'adresses mails contenues par le champ SMTP RCPT TO, c'est-à-dire le champ indiquant les destinataires. La valeur par défaut est 250, mais vous avez tous loisirs de l'ajuster de la manière suivante : router(config)#ip audit smtp spam 50 Enfin, pour la notification par la journalisation, vous avez également une marge de configuration permettant de définir son format (syslog par défaut). Ceci vous permettra par exemple d'adopter un format lisible en cas de notification distante vers NetRanger. Ci-dessous, la commande en question : router(config)#ip audit notify log [nr-director | syslog] Enfin, vous disposez des habituelles commandes d'afficage du sous-système, toutefois un peu plus complètes qu'à l'habitude pour le Firewall IDS. Outre l'afficache de la configuration globale, vous pouvez consulter la configuration par interface, ainsi que des statistiques d'utilisation : router#show ip audit configuration router#show ip audit interface router#show ip audit statistics Ces dernières peuvent être remises à zéro de la manière suivante : router#clear ip audit statistics Tandis que la configuration globale d'audit peut être supprimée avec la commande qui suit : router#clear ip audit configuration Bien sûr vous pouvez vouloir appliquer une protection minimale contre les paquets forgés, tirant parti d'adresses non routables, sans avoir un large réseau disposant de routeurs. Pour cela il vous suffit d'appliquer la même configuration à vos firewalls. Ci-dessous un exemple de configuration pour IPFilter [IPF] (et sans doute Packet Filter d'OpenBSD). Ce firewall existe sur de nombreux systèmes et le ruleset est aisément traduisible. ------------------------------------ SNiP ------------------------------------- # bloque et log les paquets avec les adresses sources suivante en entrée sur # l'interface fxp0, assumant que celle-ci est l'interface externe extinf=fxp0 us=/ block in log quick on $extinf from 0.0.0.0/8 to any block in log quick on $extinf from 10.0.0.0/8 to any block in log quick on $extinf from 14.0.0.0/8 to any block in log quick on $extinf from 24.0.0.0/8 to any block in log quick on $extinf from 127.0.0.0/8 to any block in log quick on $extinf from 169.254.0.0/16 to any block in log quick on $extinf from 172.16.0.0/12 to any block in log quick on $extinf from 192.0.2.0/24 to any block in log quick on $extinf from 192.18.0.0/15 to any block in log quick on $extinf from 192.88.99.0/24 to any block in log quick on $extinf from 192.168.0.0/16 to any block in log quick on $extinf from 204.152.64.0/24 to any block in log quick on $extinf from 224.0.0.0/3 to any block in log quick on $extinf from 240.0.0.0/4 to any block in log quick on $extinf from $us to any ------------------------------------ SNiP ------------------------------------- Afin de vous faciliter la vie, voici les mêmes règles traduites pour iptables, le firewall du projet Netfilter, disponible depuis Linux 2.4.x. ------------------------------------ SNiP ------------------------------------- # même principe, interface d'exemple eth0 EXTINF=eth0 US=/ iptables -A INPUT -i $EXTINF -s 0.0.0.0/8 -j DROP iptables -A INPUT -i $EXTINF -s 10.0.0.0/8 -j DROP iptables -A INPUT -i $EXTINF -s 14.0.0.0/8 -j DROP iptables -A INPUT -i $EXTINF -s 24.0.0.0/8 -j DROP iptables -A INPUT -i $EXTINF -s 127.0.0.0/8 -j DROP iptables -A INPUT -i $EXTINF -s 169.254.0.0/16 -j DROP iptables -A INPUT -i $EXTINF -s 172.16.0.0/12 -j DROP iptables -A INPUT -i $EXTINF -s 192.0.2.0/24 -j DROP iptables -A INPUT -i $EXTINF -s 192.18.0.0/15 -j DROP iptables -A INPUT -i $EXTINF -s 192.88.99.0/24 -j DROP iptables -A INPUT -i $EXTINF -s 192.168.0.0/16 -j DROP iptables -A INPUT -i $EXTINF -s 204.152.64.0/24 -j DROP iptables -A INPUT -i $EXTINF -s 224.0.0.0/3 -j DROP iptables -A INPUT -i $EXTINF -s 240.0.0.0/4 -j DROP iptables -A INPUT -i $EXTINF -s $US -j DROP iptables -A INPUT -i £EXTINF -j LOG -log-prefix "incoming pkts on extif:" ------------------------------------ SNiP ------------------------------------- Pour les programmes de DDoS, il ne sert à rien d'essayer de filtrer les ports de leur daemons et proxies puisqu'ils utiliseront en général pour communiquer des covert channels, tels que la célèbre paire ICMP echo request/reply. Pour utiliser un système similaire au Cisco Firewall IDS, vous pouvez utiliser Snort couplé à Guardian [GRD]. Ce dernier scan les logs Snort et, en cas d'alertes, exécute un shell script insérant une règle dynamique dans le firewall. Ce mécanisme fonctionne avec iptables, ipchains et ipfwadm sur Linux et ipfw sur FreeBSD. Cependant cette alternative est peu élégante et multiplie les possibilités d'erreurs ou d'abus, nous faisant préférer des systèmes intégrés comme Cisco IOS ou bien, en open source, Prelude IDS [PREL]. L'intérêt principal, dans le fait d'aborder le filtrage, est de donner un aperçu des capacités disponibles sur tous les systèmes récents. Vous disposez ainsi d'un moyen simple de vous protéger unilatéralement d'attaques par spoofing des plus basiques, ainsi que d'erreurs ou d'exploitation dans des configurations BGP laxistes. Toutes ces erreurs peuvent mener à des DDoS. 2.2. RPF Le Reverse Path Forwarding est une technologie initiée par Cisco, mais désormais largement répandue dans les développeurs d'infrastructure réseau et même cité en 1995 dans la RFC 1812 [1812], qui peut s'avérer très utile dans la lutte contre le spoofing. Cette vulnérabilité du protocole IP est en effet très liée aux attaques DDoS. En bloquant partiellement ou totalement la possibilité de faire entrer des paquets forgés dans un réseau, nous réduisons grandement l'exposition de ce réseau aux DDoS. Lorsqu'un paquet arrive sur une interface, RPF vérifie que l'interface ayant reçu ce paquet coïncide avec le plus court chemin du routeur à la source. C'est seulement à cette condition que le routeur pourra faire suivre le paquet. Dans le cas contraire, cela signifie que le paquet est illégitime (délibérément construit lors d'une attaque, ou bien issue d'une erreur de routage) et il est donc rejeté. Le Unicast RPF atteint ce but en recherchant le "best return-path", celui-ci étant défini par sa métrique. Lorsqu'un paquet arrive sur une interface, le routeur vérifie dans sa table de routage quelle serait l'interface de sortie pour un paquet dont la source correspondrait à la destination de celui qui est traité par RPF. Si la réponse correspond à l'interface d'arrivée du paquet examiné, alors celui-ci passe. Dans le cas contraire, il est rejeté. L'évaluation effectuée sur le paquet revient concrètement à déterminer si il est bien passé par l'interface correspondant au chemin le plus court. Le processus ainsi décrit est nommé strict mode. Il existe en effet un processus d'évaluation différent, appelé 'loose mode' qui ne fait plus le test de l'interface d'arrivée, mais se contente de vérifier qu'il existe bien, dans la table de routage, d'une route vers l'adresse source du paquet évalué. Remarquez que ce test est sous-entendu par le strict mode. Dans tous les cas, RPF agira comme un filtre vis-à-vis des routes non-existantes. En utilisant largement le loose mode, même au niveau du coeur de l'infrastructure, il devient alors possible de filtrer les paquets dont la source n'est pas allouée ou même privée, si la distribution des routes est filtrée correctement. Il existait en effet plusieurs limitations ennuyeuses à RPF. Tout d'abord, en cas de présence de routes par défaut sur une ou plusieurs interfaces, le comportement devient plus laxiste, puisque nous disposerons dans tous les cas d'une route vers l'adresse source. Le loose mode devient alors complétement inutile, et il se contente de laisser passer tous les paquets. Le strict mode conserve encore un peu de son utilité, mais il ne dépend plus que de la présence ou non d'une route par défaut pour l'interface d'arrivée du paquet évalué. D'autre part, RPF éprouve des difficultés face aux routes asymétriques inhérentes au processus de décision des protocoles de routage dynamique modernes, qui n'autorise à choisir qu'une seule et unique route vers une destination donnée. La conséquence est mineure à la frontière entre client et ISP qui n'est généralement constituée qu'un unique peering. Du point de vue de RPF, elle devient bien plus importante pour ce qui est des frontières entre plusieurs ISP, en particulier dans les Internet eXchange Point (IXP). Dans ces environnements spécifiques, il est courant de voir se développer des routes asymétriques entre flux ascendant et descendant par exemple. L'implémentation originale de RPF, qui correspond au strict mode, interdisait totalement son utilisation aux frontières ISP-ISP, sauf à définir explicitement des filtres protégeant les routes que l'on savait asymétriques du rejet par RPF. C'est également pour cela qu'a été développé le loose mode, qui enlève la barrière de la vérification d'interface, et permet un fonctionnement normal en presque toutes circonstances. On observe la première implémentation de Unicast RPF (uRPF) par Cisco dans IOS 11.1(17)CC [IOSRPF]. Celle-ci n'implémentait que le strict mode et ne prévoyait pas de traitement spécial contre le problème des routes par défaut. Sa configuration, par interface, s'avère très simple. Le seule pre-requis, comme pour toutes les implémentations de uRPF, est l'activation de la technologie Cisco Express Forwarding, CEF, afin de tirer parti de son design optimal pour le forwarding. L'exemple ci-dessous configurera l'uRPF en strict mode uniquement pour tous les IOS plus récents que la 11.1 ------------------------------------ SNiP ------------------------------------- ip cef ! strict mode incluant les routes par defaut interface ethernet 0 ip verify unicast reverse-path ------------------------------------ SNiP ------------------------------------- Cependant, comme nous le laissions entendre, Cisco a entièrement repenser uRPF en 2001, pour adresser les limitations que nous avons décrites. Barry Greene, à qui l'on doit de nombreuses innovations chez Cisco contre les DDoS, ainsi qu'une riche documentation sur le sujet, a écrit un white paper [GRE+01] énonçant clairement les problèmes motivant la reconception de uRPF et les solutions apportées. Le résultat est une nouvelle commande disponible cependant pour les routeurs de la série 12000 uniquement, avec IOS 12.0(22)S. Celle-ci permet de préciser si le test d'interface est effectuée (option 'rx') ou ignorée (option 'any'). Il permet également d'indiquer si les routes par défaut doivent être prises en compte ou non lors de l'évaluation, grâce à l'option 'allow-default'. Il est enfin possible d'autoriser le routeur à se pinger lui-même, ce que RPF interdirait en règle générale. Le patron [CNS] de la commande est donc le suivant : router(config-if)#ip verify unicast source reachable-via {rx | any} [allow-default] [allow-self-ping] [acl] Et l'exemple précédent revient à celui ci-après. ------------------------------------ SNiP ------------------------------------- ip cef ! strict mode incluant les routes par defaut interface ethernet 0 ip verify unicast source reachable-via rx allow-default ------------------------------------ SNiP ------------------------------------- Les deux commandes peuvent prendre en dernier argument un numéro d'ACL afin de permettre aux paquets échouant au test RPF de subir un traitement spécial. Par exemple, en ajoutant des règles 'permit', les paquets lui correspondant seront transmis quel que soit le résultat de RPF, tandis que 'deny' les rejettera toujours. Cette astuce vous permet également de loguer plus précisément les paquets évalués par RPF. Juniper a également très rapidement (dès la série JunOS 5.x) pourvu son système de la même fonctionnalité. La configuration de uRPF nécessite cependant quelques étapes supplémentaires. Il est tout d'abord nécessaire de l'activer globalement dans la hierarchie 'routing-options' de la CLI. Le point intéressant est que vous êtes alors en mesure de préciser si la vérification RPF doit s'effectuer contre les routes actives, c'est-à-dire en terminologie Juniper, installées dans le Forwarding Engine (en fait la FIB), ou contre les routes possibles, c'est-à-dire apprises par le Routing Engine (à travers les différents protocoles de routage dynamique). Le premier cas est appliqué avec la déclaration 'active-paths' et le second avec 'feasible-paths'. Le patron [JRPFR] de la commande est le suivant. ------------------------------------ SNiP ------------------------------------- [edit] routing-options { forwarding-table { unicast-reverse-path (active-paths | feasible-paths); } } ------------------------------------ SNiP ------------------------------------- Cette méthode règle efficacement la plupart des problèmes liés au routage asymétrique, et ceux sans réduire la protection offerte par RPF en passant en loose mode. Il ne reste plus qu'à configurer uRPF pour chacune de vos interfaces avec la déclaration 'rpf-check'. JunOS supporte parfaitement les deux modes tels que décrit théoriquement. De même, vous pouvez spécifier un 'fail-filter' à la commande 'rpf-check' pour spécifier un traitement spécial à certains paquets qui échoueraient au test RPF. Ce fail-filter est un firewall filter défini au même niveau hiérarchique que rpf-check. Le mode par défaut est strict mode. Pour spécifier le mode désiré, il suffit d'ajouter 'mode (loose | strict)' au même niveau que rpf-check. Les lignes ci-dessous sont le patron [JRPFI] de la commande. ------------------------------------ SNiP ------------------------------------- [edit] interfaces { fe-0/0/0 { unit 0 { family inet { rpf-check fail-filter ; mode (loose | strict); } } } } ------------------------------------ SNiP ------------------------------------- Devant l'intérêt suscité par cette fonctionnalité, il n'a pas fallu attendre longtemps pour en retrouver des équivalents dans le logiciel libre. L'importance d'une telle commande est de simplifier le travail de l'administrateur en remplaçant aisément les configurations complexes nécessaires auparavant pour atteindre le même but. En effet, sur tout firewall gérant correctement les opérateurs logiques, il sera possible d'écrire une règle empêchant tous paquets marqués d'une certaine adresse de passer par autre chose que l'interface à laquelle cette adresse est normalement attachée. Cette technique ne correspond pas à une réelle implémentation de l'algorithme RPF, mais reste intéressante. Par exemple, en suivant une syntaxe type IPF (ou PF), la configuration serait telle que ci-dessous (avec extif l'interface externe et subnet le réseau privé) : block drop in on !$extif inet from $subnet to any Depuis Linux 2.4, vous pouvez activer une telle fonctionnalité par interface via les variables disponibles dans /proc/sys/net/ipv4/conf/. Même si il est exprimé différemment, le raisonnement reste le même. Pour Linux, si l'interface par laquelle le paquet analysé est supposé quitter son réseau ne correspond pas à celle par laquelle il rentre, alors il est considéré comme invalide et rejeté. Clairement, cela revient à effectuer les mêmes vérifications dans la table de routage que celle exprimée dans le cas général. Pour l'activer dans une interface donnée, exécutez la ligne suivante : # echo "1" > /proc/sys/net/ipv4/conf//rp_filter Où 'interface' est à remplacer par le nom de l'interface. Pour étendre cette configuration à l'ensemble de vos interfaces, remplacez 'interface' par 'default" ou 'all'. Enfin, pour la rendre persistante, il vous faudra ajouter cette commande sous forme de script à /etc/rc.d/init.d/. Linux ne semble pas être en mesure de faire la distinction entre strict mode et loose mode, ce qui nous interdit de le placer à un autre endroit qu'à la frontière client/ISP. Pour détecter quels paquets sont effectivement rejetés, afin de corriger éventuellement une configuration indésirable, ajoutez également cette entrée : # echo "1" >/proc/sys/net/ipv4/conf//log_martians Pour étendre cette configuration, suivez les mêmes instructions que pour rp_filter. Plus de détails dans le Linux Advanced Routing & Traffic Control (LARTC) Howto [LARTC]. Pour ce qui est de FreeBSD, la ré-implémentation d'IPFW, sous le nom IPFW2, a vu l'ajout de deux mots-clés supplémentaires : verrevpath [VRP] pour le strict mode et versrcreach [VSR] pour le loose mode. Le premier est apparu à partir de FreeBSD 4.8 (avec l'option IPFW2) et FreeBSD 5.0 (avec l'option IPFW), tandis que le second existe à partir de FreeBSD 5.3 suite à la simple demande d'un utilisateur. Toutes deux font une évidente référence aux commandes RPF de Cisco. Le fonctionnement de ces deux options est strictement le même que pour Cisco ou Juniper, ce qui place FreeBSD au rang des systèmes adaptés aux infrastructures réseau. Pour chaque paquet correspondant à une règle 'verrevpath', IPFW vérifie, au sein de la table de routage, si l'interface d'arrivée du paquet coincide avec celle liée à la route vers l'adresse source du paquet. Par précaution, tous les paquets issus de la machine elle-même, ainsi que ceux qui ne possèderaient pas d'interface de sortie correspondante à leur adresse source, passe le test. Les règles versrcreach effectuent, pour leur part, le test RPF en loose mode. Le kernel se contente alors de vérifier si l'adresse source est simplement joignable par n'importe quelle route présente dans la table de routage, sans distinction d'interface. Une règle ipfw appliquant une vérification RPF stricte à tous les paquets entrant dans un réseau ressemblera à celle qui suit, avec extif représentant l'interface d'entrée : ipfw add 100 allow log all from any to any recv ${extif} verrevpath Il n'y a qu'à changer verrevpath pour versrcreach pour qu'IPFW utilise le loose mode et que cette configuration soit utilisable dans le coeur de l'infrastructure ou entre des ISP disposant de plusieurs peerings. Le dernier à suivre le mouvement fut OpenBSD, avec PF [PF]. Depuis la release 3.3, celui-ci dispose du mot-clé 'antispoof' sur lequel vous trouverez des informations complètes dans pf.conf(5) [MANPF]. La commande type IPF que nous avons vu plus haut, peut désormais être remplacée, dans pf.conf, grâce à antispoof, de la façon suivante : antispoof for $extif inet Outre la vérification qu'aucun paquet ayant pour source une adresse du réseau auquel est attachée une certaine interface (ici extif) ne sorte pas une autre, une seconde protection, spécifique à OpenBSD, est ajoutée en rejetant complétement tout paquet ayant pour source l'adresse de l'interface protégée. Elle remplace donc aussi la règle suivante, où 192.168.0.1 correspondait à l'interface protégée du firewall : block drop in inet from 192.168.0.1 to any Notez que les applications qui communiquent avec les interfaces locales via l'interface loopback peuvent se trouver perturbées, comme précisé dans la man page pf.conf(5). Pensez alors à ajouter une règle autorisant explicitement les transmissions depuis l'interface de loopback. Enfin, vous aurez certainement remarqué que bien qu'antispoof soit très utile, il ne représente en aucun cas une vraie implémentation de l'algorithme RPF. Elle permet cependant d'automatiser une vérification utile et, au final, apporte le même résultat. Par contre, tout comme Linux, OpenBSD ne comprend pas la différence entre loose mode et strict mode, le releguant aux bordures de réseaux ne possédant qu'une seule connexion entre eux. 2.3. Route filtering Poursuivant notre lutte acharnée contre le spoofing, il apparaît rapidement judicieux et nécessaire d'éviter simplement la possibilité de router un paquet apparemment forgé. En effet, les auteurs de spam et de DDoS disposent de plusieurs techniques permettant l'usurpation ou le détournement temporaire d'adresses afin de lancer leurs attaques. Un routeur malin peut ainsi servir à introduire dans la table BGP Internet globale des annonces de routes de courte durée vers des adresses privées. Dans la même veine, la désagrégation consiste à annoncer des routes plus spécifiques, c'est-à-dire d'une longueur de prefixe (en notation CIDR) plus grande, la rendant ainsi prioritaire dans le processus de prise de décision BGP pour l'installation d'une route. Afin de contrôler au plus près les annonces reçues et distribuées, Cisco (et, par extension, Zebra) dispose de plusieurs mécanismes à même d'effectuer un filtrage des routes propagées, via BGP, au niveau de vos routeurs externes, dits routeurs eBGP. Chaque réseau se voit attribué dans sa globalité un numéro d'AS (Autonomous System). La distinction entre routeur externe (eBGP) et interne (iBGP) se base alors sur les numéros d'AS utilisés pendant une session. Si'ils diffèrent entre deux routeurs voisins, nous nous trouvons en présence d'une liaison eBGP, c'est-à-dire entre deux réseaux, soutendant des modes de propagation de routes différents. Les méthodes décrites ci-après permettent de ne pas tenir compte de certaines annonces de routes en les filtrant simplement dès l'entrée de votre réseau. Ainsi, il n'y aura jamais aucune route, dans nos tables de routage, vers ces adresses. Les deux méthodes en question ont pour noms 'distribute-list' et 'prefix-list'. Bien que relativement redondantes, nous évoquerons les deux pour plusieurs raisons. Tout d'abord, elles sont mutuellement exclusive, ce qui signifie que vous ne pouvez en aucun cas les appliquer simultanément sur un même routeur. Il est même recommander de rester cohérent de d'utiliser la même technique à l'échelle de votre réseau. La différence majeure entre ces deux commandes demeure la catégorisation des informations. Dans un cas, 'distribute-list', il est fait appel aux ACL pour filtrer les adresses annoncées, tandis que 'prefix-list' utilise un mécanisme qui lui est propre. Les deux schémas se configurent de manière similaire en mode BGP config. Les distribute-list, présentes depuis IOS 10.0, comme toutes les innombrables options de la commande 'neighbor', pourront s'appliquer individuellement à chaque routeur voisin selon leur adresse IP, ou bien à tous les routeurs voisins définis au sein d'un peer group. Voyez la documentation Cisco [CBGP] pour de plus amples informations sur cette configuration très pratique. Une distribute-list est en réalité une simple invocation d'une Standard ACL contre laquelle les messages BGP seront testés. Pour appliquer une telle liste aux messages en provenance d'un routeur voisin, utilisez la commande suivante : router(config-router)#neighbor { | } distribute-list { | } {in | out} Comme vous le voyez, la commande est assez simple. Outre la définition du voisin ou du groupe de voisins auquel les ACL s'appliqueront, vous pouvez ensuite spécifier le numéro de ces fameuses ACL ou bien, à défaut, préciser le nom d'une prefix-list. La configuration finale, en reprenant les ACL vues à la section 2.1., ressemblera à l'exemple suivant. ------------------------------------ SNiP ------------------------------------- ! filtrage de route annoncées par le voisin d'adresse x.x.x.x neighbor x.x.x.x distribute-list 101 in ------------------------------------ SNiP ------------------------------------- La description des distribute-list a pu vous intringuer par la mise sur un pied d'égalité des ACL et des prefix-list. En effet, ces dernières, apparues seulement sur IOS 12.0, constituent un réel remplacement des ACL. Le but est de fournir une amélioration des performances pour ce qui est du chargement de la liste et des vérifications de validité des routes. D'après Cisco, l'objectif est atteint, en particulier lorsque l'utilisateur manipule des listes importantes. Le remplacement pur et simple des ACL a également conduit à quelques modifications dans le fonctionnement du filtrage. Ainsi désormais, une politique restrictive est appliquée par défaut, ce qui signifie que, dès lors qu'une prefix-list est activée, tout ce qui n'est pas expressement autorisé se voit implicitement rejeté, comme l'explique la documentation Cisco attenante. Un autre changement est intervenu dans l'ordonnancement des règles elles-mêmes. En lieu et place des numéros d'ACL, les règles des prefix-list sont désignées de manière unique par un numéro de séquence. Ces numéros s'incrémentent, par défaut, de 5 à chaque nouvelle règle. L'idée sous-jacente est de pouvoir ajouter des règles intermédiaires après coup, simplifiant la mise à jour de la liste. Cependant, désactiver cette génération automatique peut s'effectuer très simplement : router(config-router)#no ip prefix-list sequence number Il devient alors obligatoire de préciser le numéro de séquence de chacun de vos règles. Cette option restait possible dans la configuration par défaut, conservant l'incrément automatique de 5 entre une règle au numéro de séquence spécifié et une laissée au soin de la génération automatique. Cette opération est réalisé à travers l'option 'seq' de la commande 'ip prefix-list' qui suit : router(config-router)#ip prefix-list [seq ] {deny | permit} [ge ] [le ] Cette commande permet d'une manière générale de créer une liste (dont le nom remplace 'name') et d'ajouter des règles en spécifiant une adresse IP suivant de la longueur de son masque de sous-réseau, juste après avoir précisé l'action 'deny' pour rejeter la route ou 'permit' pour l'autoriser. Les options ge (greater-or-equal, >=) et le (lesser-or-equal, =<) sont des comparateurs permettant de définir des seuils pour le masque de sous-réseau. Un masque inférieur à 8 dénote par exemple une route très générale, et peut être considéré comme suspect. Appliquer une prefix-list à un routeur voisin peut s'effectuer, comme nous l'avons vu, par une distribute-list, ou bien par une option séparée de neighbor dédiée aux prefix list, bien qu'identique à distribute-list : router(config-router)#neighbor { | } prefix-list {in | out} La configuration finale, suivant les RFCs RFC 1918, 1166 et 1466, sera telle que celle ci-dessous. ------------------------------------ SNiP ------------------------------------- ! prefix-list 'rfc', avec seq automatique no preflix-list rfc ip prefix-list rfc deny 0.0.0.0/8 ip prefix-list rfc deny 10.0.0.0/8 ip prefix-list rfc deny 14.0.0.0/8 ip prefix-list rfc deny 24.0.0.0/8 ip prefix-list rfc deny 127.0.0.0/8 ip prefix-list rfc deny 169.254.0.0/16 ip prefix-list rfc deny 172.16.0.0/12 ip prefix-list rfc deny 192.0.2.0/24 ip prefix-list rfc deny 192.18.0.0/15 ip prefix-list rfc deny 192.88.99.0/24 ip prefix-list rfc deny 192.168.0.0/16 ip prefix-list rfc deny 204.152.64.0/24 ip prefix-list rfc deny 224.0.0.0/3 ip prefix-list rfc deny 240.0.0.0/4 ip prefix-list rfc permit any ! application au neighbor x.x.x.x de la liste 'rfc' router bgp neighbor x.x.x.x prefix-list rfc in ------------------------------------ SNiP ------------------------------------- Retenez qu'une troisième solution était encore possible, qui apporte une plus grande clarté dans la configuration, avec l'utilisation de route-map. En effet, ces dernières disposent comme match criteria de 'match ip address' acceptant des ACL ou des prefix-list. Dans tous les cas (distribute-list, prefix-list ou route-map) 'in' indiquera de filtrer les routes en provenance du voisin, tandis que 'out' appliquera une liste donnée aux annonces que votre routeur émet vers son voisin. Les deux configurations simultanées sont souhaitables. Plus de précisions, en particulier sur les commandes 'show' attenantes, sont disponibles en [CBGP]. Le routage BGP exige une certaine rigueur dans les configurations pour éviter d'annoncer n'importe quoi n'importe comment. Comme nous avons déjà pu l'évoquer, filtrer strictement les routes sortant ou entrant dans notre réseau permet de se prévenir de nombreuses situations assimilables à un DoS. Une configuration rejettant par défaut et autorisant explicitement (restrictive stance) permettrait quant à elle d'éviter une bonne partie des attaques tirant parti de configurations laxistes de la part des titulaires d'AS. En plus du filtrage des adresses "spéciales" que nous venons de voir, vérifiez toujours que vous n'annoncez effectivement que les préfixes sur lesquels vous avez une autorité. Et n'oubliez jamais que la sécurité tient une place primordiale dans l'amélioration de la qualité et de la continuité du service. 2.4. {Black,Sink}hole Au sein de l'infrastructure réseau, nous avons également la possibilité de définir un 'blackhole' [GRE02]. Un tel dispositif permet de faire totalement disparaître le trafic à destination d'une machine. Ainsi, lorsqu'un DoS est détecté, il suffit de "blackholer" la cible de l'attaque pour la protéger au niveau de l'infrastructure. Sous Cisco, cela correspondra à la définition d'une route statique sur nos routeurs, liant l'adresse de la cible et la pseudo-interface null0. Concrètement, l'invocation de null0, sur les routeurs disposant de la technologie CEF, implique une gestion particulière au sein de l'Adjacency Table, entraînant à son tour le rejet pur et simple des paquets transitant par la pseudo-interface. Il est alors intéressant de noter que les processeurs utilisés dans les routeurs Cisco sont optimisés afin d'être plus efficace dans des conditions de rejets que dans celles de forwarding. Il existe cependant quelques inconvénients intrinsèques aux blackholes. D'abord, la détection du DoS reste bien évidemment à la charge de l'administrateur réseau via un dispositif parallèle. Cela implique que le blackhole nécessite l'intervention manuelle du même administrateur pour être mis en place, réduisant, par ce délai, l'efficacité de la mesure. L'autre désavantage majeur est qu'aucune distinction ne peut être faite entre les paquets effectivement à l'origine du DoS et le trafic légitime. Outre que cette méthode se voit plutôt à des cas extrêmes et manifestes, dans lesquels une interruption temporaire du service est préférable, le blackhole se verra surtout utilisé ponctuellement afin d'identifier le point d'entrée de l'attaque dans le réseau à partir des messages ICMP unreachable, puis de placer sur ce point d'entrée des ACLs ou des politiques de limitation de débit (voir sections 2.1 et 3.3 respectivement). La technique que nous décrivons nécessiterait cependant la configuration de chacun de nos routeurs, travail ô combien fastidieux. Le bon sens nous indique donc d'utiliser BGP pour redistribuer les informations concernant le blackhole. L'idée est de préparamétrer sur tous les routeurs une route vers null0 attribuée à un bloc d'adresses inutilisé (très important puisque tous les routeurs rejetteront de fait les paquets de et vers ces adresses) tel qu'un bloc d'adresses RFC 1918. Attention dans ce cas aux interfaces sur lesquelles vous appliquez vos filtres distribute-list, afin de ne pas empêcher la redistribution de vos routes blackhole. La ligne suivante permet de lier le bloc choisi à une route vers null0 : router(config)#ip route 255.255.255.0 null0 Il est ensuite nécessaire de définir un routeur de moindre importance, dit 'blackhole server', depuis lequel nous définirons le blackhole et le propagerons par BGP à toute l'infrastructure. Cette étape sera réalisée, sous IOS, à l'aide d'une politique route-map. Celle-ci appliquera aux routes statiques locales affublées d'un certain tag un nouveau next-hop correspondant au bloc d'adresses inutilisé. Comme ce dernier est partout routé vers null0, tous les paquets appartenant à ces routes statiques locales seront supprimés. La route-map policy est de forme similaire à celle ci-dessous. ------------------------------------ SNiP ------------------------------------- ! on the blackhole server (configuration phase) in 'configure bgp' mode redistribute static route-map blackhole route-map blackhole permit 10 match tag 1337 set ip next-hop set local-preference 500 set community no-export set origin igp ------------------------------------ SNiP ------------------------------------- Bien que la commande route-map soit sans doute l'une des plus familière aux administrateurs Cisco, analysons cette séquence plus en détail. Le nom de la politique est 'blackhole' et son numéro de séquence (cf. ACL et filter-list) 10. Cette politique s'applique à toutes les routes statiques possédant le tag '1337'. Pour cette route, une série de 'set options' est alors prise. Le next-hop est remplacé par le bloc inutilisé sélectionné précédemment, la préférence locale est mise à 500 pour que la route vers le nouveau next-hop soit choisie à coup sûr comme best-path selon le processus de décision de BGP pour les routes de provenance interne (iBGP), le champ community est mis à no-export pour ne pas annoncer cette nouvelle route en dehors de notre AS (risque de blackhole complet de la part des peers), et enfin le 'BGP origin code' est 'igp' indiquant que la source est un routeur interne. L'application d'une politique route-map sur les routes reçues peut se faire soit sur la base d'une interface, soit pour un voisin (neighbor) désigné. Dans le premier cas, pour IOS, il faudra simplement entre en mode configuration interface : router(config)#interface ethernet 0 router(config-if)#ip policy route-map blackhole Dans le second cas de figure, il sera préférable de créer un groupe réunissant l'ensemble des routeurs internes et d'appliquer à toutes les routes reçues depuis ce groupe notre politique. Cette procédure s'effectue en mode configuration bgp pour IOS. ------------------------------------ SNiP ------------------------------------- neighbor peer-group neighbor route-map blackhole in neighbor remote-as neighbor w.x.y.z peer-group ------------------------------------ SNiP ------------------------------------- Dans cette séquence, nous créons un peer-group que nous nommons (en remplaçant pg-name) et dont les routeurs appartiennent à l'AS local puisqu'il regroupe les routeurs internes (remplacer AS par le numéro d'AS local), nous lui appliquons la route-map blackhole sur les routes entrantes, et enfin nous y ajoutons autant de routeurs que nécessaires (en iBGP entièrement connecté, sans réflecteurs de routes, cela correspond à la totalité des routeurs iBGP). Lorsqu'un DoS occure, il suffira alors de placer, sur le blackhole server, une route statique marquée du tag correspondant à la route-map policy, comme dans l'exemple qui suit, en remplaçant par la cible du DoS : router(config)#ip route 255.255.255.255 null0 tag 1337 Mais le mécanisme de blackhole permet également de remonter la source de l'attaque spoofée, ceci en journalisant les paquets ICMP * unreachable et l'interface qui les génère. Cela vous indiquera ainsi par déduction le point d'entrée du trafic spoofé dans votre domaine. Appliquer cette méthode à de larges échelles permettrait de remonter plus facilement la source d'un trafic spoofé en passant d'AS en AS. La journalisation s'effectue très simplement par les ACL : router#access-list 101 permit icmp any any unreachables log log-input Notez cependant que la redirection vers null0 risque de générer une forte quantité de messages ICMP unreachable. Afin de ne pas surcharger le routeur, il sera alors nécessaire de limiter le débit de ces messages - comme indiqué en section 3.3. de cet article - ou bien carrément de les supprimer totalement avec 'no ip unreachables'. Comme nous l'avons déjà rapidement abordé, la méthode originale de blackholing provoque un rejet complet du trafic à destination de la cible de l'attaque, incluant le trafic potentiellement légitime. BGP offre pourtant des attributs permettant d'identifier des chemins (path) distincts et donc de leur appliquer des règles différentes. Face à ce constat, une méthodologie améliorée de mise en oeuvre d'un blackhole est apparu en tant que draft IETF [TURK02]. Pour décrire ce raffinement du blackhole, nous prendrons un numéro d'AS d'exemple, 1337. L'idée est que chaque routeur dispose d'une politique route-map se déclenchant selon une valeur de l'attribut BGP community différente pour chaque routeur. Pour simplifier la lecture de nos configurations et aussi nous conformer à la RFC 1997 spécifiant le format de l'attribut community (AS:NN, où AS est le numéro d'AS et NN un nombre quelconque, chacun sur deux octets), entrez la commande suivante en mode de configuration globale : router(config)#ip bgp-community new-format Comme pour un blackhole normal, il faut s'assurer que les routeurs en bordure du réseau possède bien une route statique orientant le bloc inutilisé, servant de nouveau next-hop en cas d'attaque, vers la pseudo-interface null0 : router(config)#ip route 255.255.255.0 null0 Il est ensuite demandé de créer une AS-Path ACL permettant d'identifier les annonces BGP provenant bien de notre AS (1337). Ceci servira ensuite à empêcher un réseau externe d'utiliser nos valeurs de community pour blackholer n'importe quel réseau en envoyant des annonces qui déclencheraient notre blackhole amélioré. Il faut créer d'abord une ACL classique qui matchera tout le trafic, puis l'appliquer à une AS-Path ACL qui cherchera une correspondance (regexp) entre l'attribut AS et notre numéro d'AS. Dans le processus BGP, lorsqu'un routeur transmet une route, il y ajoute son numéro d'AS au début de l'attribut AS path, avant de transmettre l'annonce. 1337 sera donc recherché en tout début d'AS path, le reste important peu. ------------------------------------ SNiP ------------------------------------- access-list 1 permit ip any ! appliquez-la à toutes les interfaces interface ethernet 0 ip access-group 1 out ! 1337 doit se trouver au debut d'AS Path, peu importe ce vient ensuite ! voyez la documentation Cisco concernant les regexp ip as-path access-list 1 permit ^1337 .* ------------------------------------ SNiP ------------------------------------- L'utilisation de la valeur de l'attribut community parmis les match criterions de nos politiques route-map nécessite la création préalable de community ACL. Chaque routeur devant chercher sa propre community ainsi que celle englobant la totalité des borders routers, il existera deux règles dans la liste ; la première étant spécifique à chaque routeur. ------------------------------------ SNiP ------------------------------------- no ip community-list 1 ! la première ligne change pour chaque routeur ip community-list 1 permit 1337:01 ip community-list 1 permit 1337:411 ------------------------------------ SNiP ------------------------------------- Il ne reste plus qu'à installer sur chacun de nos border routers une politique route-map permettant de déclencher un blackhole à l'appel de sa valeur de community. C'est ici que l'on se rend particulièrement compte de l'intérêt de cette méthode par rapport à la précédente. Au lieu de voir tous les routeurs relayer la mesure de blackhole, seul le peer eBGP désiré le fait, laissant les autres routes supposées légitimes intactes. Une mesure de blackhole générale est cependant prévue par l'auteur de cette technique améliorée puisqu'il préconise d'installer également une politique route-map se déclenchant à la réception de la valeur de community correspondant à l'ensemble des routeurs eBGP (1337:411). Cette étape a été simplifié en utilisant un numéro de community-list englobant les deux valeurs community (une community-list se comportant comme une ACL). ------------------------------------ SNiP ------------------------------------- redistribute bgp route-map enhanced_blackhole route-map enhanced_blackhole permit 20 match community 1 match as-path 1 set ip next-hop set local-preference 500 set community no-advertise set origin igp ------------------------------------ SNiP ------------------------------------- En cas d'attaque, il ne reste plus qu'à annoncer, par l'intermédiaire de BGP, les routes vers la cible affublées de la valeur de community du peer eBGP identifié comme point d'entrée de l'attaque. Vous remarquerez cependant ici une lacune importante du draft. Celui-ci semble assumer que l'administrateur est capable d'identifier le routeur eBGP par lequel transite l'attaque. Non seulement ce postulat n'est pas évident dans la vie réelle mais, de plus, dans le cas d'une attaque distribuée (DDoS), les points d'entrée peuvent être assez nombreux. Il faudrait alors plutôt voir dans ce raffinement du blackhole un remplacement du filtering classique apportant, en outre, une capacité d'activation distante. La modification de la valeur de community nécessite de passer par BGP, donc par une politique route-map, à l'instar des route-maps utilisées pour la route statique null0 sur un serveur blackhole. Suivez la séquence de commandes suivante, en remplaçant 'ebgp_community' par la valeur de community du peer eBGP point d'entrée présumé de l'attaque. Retenez bien que nous voulons ici modifier la valeur 'community' d'une route statique annoncée aux autres peers, elle sera donc à appliquer en sortie. ------------------------------------ SNiP ------------------------------------- redistribute static route-map trigger_blackhole route-map trigger_blackhole permit 30 match tag 318 set community no-export : set local-preference 500 set origin igp ------------------------------------ SNiP ------------------------------------- Comme à votre habitude, lorsqu'un DoS est détecté, il suffira d'ajouter localement une route statique vers null0 pour déclencher le processus de blackhole : router(config)#ip route 255.255.255.255 null0 tag 318 De façon relativement récente, on a vu apparaître un raffinement supplémentaire au blackhole. Le principe en est succintement décrit dans le draft abordant la méthode de blackhole améliorée [TURK02] vue auparavant. Cette nouvelle technique, nommée sinkhole par analogie aux blackholes dont elle reprend une partie de la configuration, consiste, non plus à ré-annoncer une route donnée afin que tout le trafic vers sa destination soit supprimé, mais à la place à orienter ce trafic vers une installation dédiée à des fins d'analyse. Si nous sommes effectivement face à une attaque de type DDoS, il peut être nécessaire pour l'opérateur d'analyser le trafic d'attaque et d'en extraire le plus possible d'information avant, éventuellement, de le faire suivre à sa destination légitime, pour n'éveiller aucun soupçons. Dans une conférence [GRE+03] donnée au NANOG (North American Network Operators Group), Barry Greene comparait quant à lui les sinkholes aux honeypots. En effet, si vous décidez d'annoncer, depuis un sinkhole, des adresses supposées non-routables ou non-attribuées, vous obtiendrez un trafic exclusivement illégitime issue, par exemple, de scans manuels ou annoncant des worms. Vous le voyez donc, les sinkholes représentent des outils nouveaux dont le spectre d'utilisations est plus qu'intéressant. Ils peuvent ainsi se voir complexifier à volonté : d'une simple machine basée sur Zebra réalisant une classification par des ACL jusqu'à un vrai petit réseau d'analyse rassemblant plusieurs types de sondes (IDS, honeypot, firewall avec tarpit ou IPS, ...). La configuration est en soit très proche de celle d'un blackhole. Le système sera constitué d'un serveur, c'est-à-dire un routeur depuis lequel nous déclenchons le reroutage vers le routeur sinkhole, et de ce dernier. Sur le serveur, la configuration reste la même que d'habitude. ------------------------------------ SNiP ------------------------------------- redistribute static route-map trigger_sinkhole route-map trigger_sinkhole permit 40 match tag 374 set next-hop set community no-export : set origin igp ------------------------------------ SNiP ------------------------------------- La redirection vers le sinkhole se fait encore une fois via une route statique affublée du tag correspondant à notre route-map : router(config)#ip route 255.255.255.255 null0 tag 374 La configuration du sinkhole s'effectue également comme les autres avec une route-map applicable sur la base d'une interface ou bien des échanges avec un voisin (neighbor) ou groupe de voisins (peer-group). La route-map sera très simple, et ressemblera à celle ci-dessous, en remplaçant analysis par l'IP de l'interface connectée réseau d'analyse. ------------------------------------ SNiP ------------------------------------- route-map sinkhole_redirect permit 50 match community : set ip next-hop ------------------------------------ SNiP ------------------------------------- Il faudrait alors faire correspondre cette IP à ladite interface, par laquelle tout le trafic sera redirigé : router(config)#ip route 255.255.255.255 interface ethernet 0 Le routeur va alors tenter plusieurs requêtes ARP afin de trouver le destinataire final du trafic qui devrait, selon toute vraisemblance, lui être attaché à la sortie de la route statique. Comme ce n'est pas le cas et que nous voulons simplement transmettre le trafic via cette interface pour qu'il soit analysé avant d'être forwardé, nous ajoutons une entrée ARP statique fausse (fake MAC address) dans le cache de notre routeur sinkhole, 'arpa' désignant le type de l'adresse, ethernet : router(config)#arp arpa La réelle difficulté dans la mise en place d'un sinkhole viendra plus probablement de l'installation d'un réseau d'analyse passif derrière la passerelle sinkhole. En lieu et place d'une cible soumise à un DDoS, nous aurions pu créer une route statique vers des espaces d'adresses invalides ou réservées. C'est de cette configuration qui permet de transformer le sinkhole en routeur puisqu'ainsi, nous redirigeons pour analyse un trafic qui est purement illégitime, qu'il soit malicieux ou issue d'erreurs de configuration. Mieux encore ! le réseau d'analyse n'étant qu'un simple brin ethernet dépourvu du moindre adressage ou routage - un simple switch permettra de dupliquer le trafic pour chaque senseur - nous pouvons ajouter un routeur à la sortie de ce réseau en le chargeant de diriger le trafic analysé vers sa destination originelle. Lorsqu'une attaque est détectée, nous faisons transiter le trafic par le sinkhole et son réseau d'analyse de manière complétement transparente avant de le rediriger vers sa destination originelle. Le seul danger viendra du nombre de hops rajoutés. Il est également capital de bien configurer les ACL bornant le réseau d'analyse. Si celles-ci laissent passer le moindre trafic, le sinkhole devient totalement inefficace et perd tout son intérêt. Il faut de plus les créer de façon suffisament fine pour qu'elles puissent servir également à la comptabilité des données transitant, en sus des sondes spécialisées. Il a été fait état de bien d'autres utilisations des sinkholes encore. L'une d'elle en particulier, même si elle peut s'avérer relativement coûteuse à mettre en place à cause de sa complexité et de la difficulté de sa maintenance, est des plus prometteuses pour la protection des routeurs eux-mêmes. Les protocoles de routage peuvent se regrouper généralement en deux groupes distincts selon l'interface qu'ils voudront utiliser. On trouve des protocoles loopback (utilisant leur adresse de loopback avec une configuration multihop) et des protocoles adjacents nécessitant une connectivité directe. La question est alors de savoir si vos routeurs internes d'importance stratégique nécessitent réellement un accès multihop, le rendant plus vulnérable depuis l'extérieur. Imaginons alors un backbone composé de routeurs directement connectés ; si nous utilisons un sinkhole annonçant - via un IGP, c'est-à-dire uniquement pour les autres routeurs directement connectés, qui prendront ainsi le pas sur toute autre type d'annonce - les adresses des interfaces directement connectées depuis celles des interfaces non connectées, nous pouvons alors éloigner toutes attaques directes contre ces routeurs. N'oubliez pas qu'un sinkhole empêche le moindre paquet d'échapper au sinkhole, de même qu'il n'est qu'un réseau (ou une machine) passif et distinct du routeur. Vous protégez d'un seul coup vos routeurs contre l'identification par des mécanismes fonctionnant sur le modèle de traceroute, mais également les attaques depuis le réseau interne qui n'aurait donc pas pu être filtrée par les ACL en bordure de réseau, et enfin contre les attaques DoS par réflexion. Si un attaquant lance un paquet broadcast spoofant l'adresse de l'un des routeurs disposant du sinkhole que nous avons décrit, ce paquet atteindra sa destination, mais sa réponse - qui entraînerait un DDoS - est irrémédiablement aspirée par le sinkhole. Dans toutes les techniques vues précédemment, gardez à l'esprit que la propagation d'une route peut être affinée. Par exemple, selon l'application de vos politiques route-map sur une interface ou pour tous les voisins, la route se verra distribuée uniquement aux routeurs en amont ou bien plus largement. Ces variations de configuration dépendront également de la manière dont vous introduisez des routes : au niveau du *hole routeur ou bien via un routeur serveur distinct. Encore une fois, ne sont présentés ici que des exemples, l'expérimentation réfléchie est la meilleure façon d'apprendre. Vous le voyez, les blackholes et les sinkholes sont des techniques aux applications multiples qui n'ont pour limite que l'imagination des administrateurs. Faire des essais avec ces techniques est le meilleur moyen de les apprivoiser et d'en affiner la configuration. Ils sont réellement l'évolution, à l'échelle du réseau, des techniques de sécurité développées ces dernières années, du firewall au honeypot. A la fois en tant que méthode de filtrage à l'efficacité redoutable (blackhole) ou comme technique d'analyse, d'identification et de protection (sinkhole), elles sont réellement capitales pour la défense d'un réseau relativement important face aux DDoS. Le projet Guardian, offrant des scripts de filtrage réagissant à des alertes Snort, dispose, quant à lui, d'un script équivalent null0 pour Linux. Ce dernier est cependant considéré comme peu stable, aussi bien par l'auteur que par la communauté. De plus amples informations, en particulier pour les matériels Juniper, sont à votre disposition en [UUBH]. 2.5. NBAR A partir da la version 12.0(5)XE2 d'IOS, Cisco propose une nouvelle technologie propriétaire nommée NBAR, pour Network-Based Application Recognition [NBAR]. La problématique initiale à laquelle cette fonctionnalité vient répondre est due à l'augmentation du nombres de protocoles induisant des spécificités nécessitant une gestion particulière au niveau d'un quelconque classificateur de paquets. Pour chaque protocole nouveau dans la couche OSI application, l'utilisation grandissante de canaux de contrôles et de données séparés ainsi que de ports dynamiques, ou encore les échanges basées sur la reconnaissance et la mémoire d'états, requièrent en effet une connaissance plus intime de chaque protocole afin de pouvoir gérer au mieux ses accès et ses limitations. NBAR est donc, au départ, une initiative destinée à étendre l'application de politiques de QoS à divers protocoles spécifiques de cette couche application, comme ceux utilisés lors d'appels de procédure distants (RPC, SQL, LDAP, ...), les applications multimedia (RTP, H.323, même IRC) ou de simples protocoles d'échanges de données (FTP, HTTP, ...). Quant à nous, nous exploiterons les possibilités de NBAR pour reconnaître quelque signatures de DDoS protocolaires connues (en particulier le cas des DDoS induits par des worms) pour ensuite lui appliquer des limitations strictes telles celles présentées dans cet article (ACL, CAR, blackhole). Comme c'est le cas de nombreuses technologies spécifiques à Cisco, les informations publiques ne donnent que peu d'informations sur le fonctionnement interne de telle ou telle fonctionnalité. Ainsi, il est fait mention d'un algorithme de Protocol Discovery permettant de classifier les données traitées en protocoles de couche 4 à 7. Cet algorithme se base sur plusieurs indices très variés. Il examine tout d'abord les ports TCP ou UDP afin de vérifier s'il ne correspond pas à un service connu pour utiliser ce port. Cette première étape n'est pas plus efficace qu'un administrateur système entrant manuellement des ACL de classification pour les ports usuels des services qu'il souhaite analyser et traiter. Il existe donc toute une batterie de tests supplémentaires consistant en une analyse exhaustive de chaque paquet. C'est cette capacité d'analyse exceptionnelle qui est effectivement appelée Protocol Discovery. Cet algorithme est capable d'identifier des protocoles fonctionnement sur des ports TCP ou UDP alloués dynamiquement en reconnaissant le protocole par la construction particulière des données (en particulier les en-têtes) ainsi que la forme des échanges. C'est également l'approche en vogue dernièrement dans le domaine des IDS avec, en particulier, les productions de Robert Graham (autrefois BlackIce, racheté depuis par ISS). Mais il sait également utiliser des expressions rationnelles (regexp) pour retrouver certaines chaînes de caractères biens spécifiques dans le contenu TCP. Cependant, certainement pour des raisons de vitesse et d'utilisation mémoire, ce type de recherche est limitée au 400 premiers octets du payload. Outre ces mesures génériques, NBAR offre l'intérêt de proposer des gestions particulières pour certains protocoles complexes ou très intéressant à traiter. Nous noterons en particulier la gestion des protocoles HTTP, RTP, ainsi que FastTrack et Gnutella. Pour le premier, il sera possible de créer des configurations NBAR basées sur l'identification des URL, hostnames et même type MIME (jusqu'à 24 occurences concurrentes, puisqu'il est ici aussi question de regexp), sans jamais se baser sur les ports usuels, offrant une souplesse et une fiabilité supplémentaire. Pour RTP, protocole utilisé de streaming il est possible de faire la distinction entre un flux audio ou vidéo - l'analyse protocolaire ne couvrant pas RTCP, le canal de contrôle allant de paire avec RTP (comme FTP et FTP-DATA). Enfin, FastTrack et Gnutella sont les deux protocoles de peer-to-peer supportés par NBAR. Le premier est par exemple utilisé par KaZaa tandis que le second est exploité par de nombreux clients comme LimeWire ou Gnucleus. Ils sont si répandus que les protocoles alternatifs sont souvent basés dessus permettant, avec le support de ces deux-là uniquement, de couvrir l'immense majorité des échanges P2P. La gestion particulière permettra ici de créer des configurations NBAR basées sur les noms des fichiers échangés. Enfin, même si Cisco conserve le monopole de la création des fichiers de descriptions de protocoles, il existe une commande afin d'ajouter un support succint pour des protocoles supplémentaires. Son format est le suivant : router(config)#ip nbar custom { } {source | destination} {tcp | udp} {range | } Comme vous l'avez sans doute devinez, l'identification ne peut s'effectuer que par des critères de recherche très limités. Au premier rang desquels on trouve la recherche d'occurence située à 'offset' (de 256 octets maximum par rapport au début du paquet), le format de recherche ('ascii', 'hex' ou 'decimal') et enfin la valeur recherchée dont la longueur maximale varie seulement le format de recherche (16 caractères ASCII, 4 octets en hexadécimal ou 4 octets en décimal). Ensuite, vous pouvez éventuellement spécifier la direction du flux, ce qui revient à indiquer si les numéros de ports à rechercher sont les ports 'source' ou 'destination'. Vous indiquez alors le type de protocole de transport ('udp' ou 'tcp') avant de finalement spécifier un espace de ports borné par un nombre de départ et de fin, en sus ou à la place de un à 16 ports statiques. Comme nous l'avons brièvement évoqué, Cisco tient à conserver le monopole de l'ajout de descriptions de protocoles à l'algorithme de Protocol Discovery. Ces descriptions sont réunies dans un Packet Description Language Module (PDLM) permettant certes l'ajout de nouveaux protocoles sans un flashage complet d'IOS mais dont l'aspect totalement propriétaire et fermé coupe Cisco d'une belle occasion d'obtenir un support communautaire bénévole susceptible d'étendre de manière importante les capacités et donc le succès de NBAR. D'autre part, NBAR connait plusieurs inconvénients qui peuvent s'avérer très dommageables. Le moins sévère est l'impossibilité de gérer les requêtes HTTP/1.1 dites 'pipeline', c'est-à-dire le cas de figure où plusieurs requêtes sont envoyées groupées. Même si ce détail n'est pas capital, il laisse planer des questions sur la fiabilité de la gestion particulière de HTTP puisqu'il peut signifier que NBAR a besoin d'au moins un échange complet pour classifier un flux HTTP, ouvrant la porte à des tentatives d'évasion. D'autre part - et c'est encore plus grave du point de vue de l'évasion - la fragmentation n'est pas supportée. Ce détails, résolus par les IDS depuis fort longtemps sans atteintes notables aux performances, empêche NBAR d'être un candidat idéal pour la classification des données du point de vue de la sécurité. Enfin, mais c'est là le lot de tous les dispositifs d'analyse "en ligne", des flux asymétriques induits par l'architecture de routage empêcheront NBAR d'effectuer la moindre analyse, semblant indiquer encore que NBAR nécessite un échange complet (comme la plupart des fonctionnalités similaires, encore une fois). La question des performances est quant à elle amplement détaillée par Cisco (et plus ou moins confirmée sur plusieurs mailing-lists). NBAR apparaît ainsi induire une augmentation de l'utilisation du CPU de 20% en plus d'une consommation de 150 octets par flux appelant un suivi d'états. Un emplacement mémoire de 1Mo (soit environ 5000 flux concurrents) est allouée une première fois, puis étendu si besoin est par tranche de 200 à 400 octets. Venons au fait ! Grâce à ses capacités de reconnaissance de protocole ainsi que la souplesse d'interfacage avec des ACL ou des règles de QoS, NBAR va nour permettre d'identifier des flux applicatifs susceptibles de causer un (D)DoS et de les réprimer. Etudions tout d'abord une configuration NBAR typique. Le Protocol Discovery s'active séparemment pour chaque interface comme c-après : router(config)#interface router(config-if)#ip nbar protocol-discovery Nous allons maintenant créer une class-map qui définira les protocoles que nous souhaitons surveiller. Une class-map peut contenir un ou plusieurs critères de correspondance. Dans le cas d'une liste de critères, vous pouvez choisir si vous désirez définir votre class-map pour les paquets contenant tous ces critères (match-all) ou seulement l'un d'eux (match-any), selon la même différence qu'entre un ET et un OU logique. L'exemple suivant créé une classe 'test' surveillant les protocoles HTTP et SMTP, où seul l'un des deux protocoles suffit pour qu'un flux soit géré par cette classe. router(config)#class-map match-any test router(config-cmap)#match protocol http router(config-cmap)#match protocol smtp La classe de trafic ainsi définie doit alors être liée à la structure définissant les politiques de QoS, une policy-map. Celle-ci comprendra le nom de classe de trafic qu'elle contraindra, suivi de une ou plusieurs commande QoS, comme dans l'exemple ci-dessous, toujours avec la classe 'test'. router(config)#policy-map test router(config-pmap)#class test router(config-pmap-c)# ! entrez ici vos commandes QoS Enfin, la policy-map résultante (ici encore 'test') est elle-même attachée à une interface, pour être appliquée en entrée ou en sortie. router(config)#interface ethernet 0 router(config-if)#service-policy [input | output] test L'utilisation de NBAR dans une optique sécuritaire se base entièrement sur les commandes QoS disponibles avec policy-map et les opérations qu'elles nous permettent d'effectuer. Notre premier exemple utiliser le rate-limiting (voir section 3.3.) pour limiter le débit d'un type de trafic particulier via la commande 'police'. Pour reprendre la configuration classique NBAR, il faudra d'abord créer une class-map identifiant le trafic incriminé. Pour reprendre des exemples existants et simplifier les démonstrations de configuration, nous utiliserons les vers Code Red et Nimda qui utilisaient notamment des vulnérabilités contre les services ISAPI du serveur HTTP Microsoft IIS 4.0 et 5.0. L'attaque était relativement simple à détecter puisqu'elle se traduisait le plus souvent par une invocation à une DLL nommée idq.dll, via le fichier default.ida. Nous pouvons donc rechercher cette dernière chaîne de caractère dans les URL, grâce à NBAR. C'est ce que nous faisons avec la classe 'worms' ci-dessous, la chaîne de caractère étant une regexp entre guillemets. router(config)#class-map match-any worms router(config-cmap)#match protocol http url "*default.ida*" router(config-cmap)#match protocol http url "*cmd.exe*" router(config-cmap)#match protocol http url "*root.exe*" Nous appliquons alors une limitation en débit grâce à la commande 'police' dans une policy-map nommée 'worms-policed'. Ici, nous avons pris l'exemple d'un lien ethernet 10 mbps. router(config)#policy-map worms-policed router(config-pmap)#class worms router(config-pmap)#police 6000 900 1500 conform-action transmit exceed-action set-dscp-transmit 2 violate-action drop Poursuivez ensuite la configuration NBAR comme décrit plus haut. La méthode ainsi réalisée est la plus simple pour ce qui est de la syntaxe. Pour utiliser de véritables Committed Access Rate (CAR) et donc la commande rate-limit, nous passerons par un autre schéma de configuration. Au lieu d'utiliser directement les QoS commandes disponibles au sein d'une policy-map, nous utiliserons celle-ci pour marquer les paquets incriminés d'une certaine valeur dans les différents champs IP QoS disponibles (IP Precedence, Quality-of-Service, DiffServ Codepoint). Pour cela, nous réutiliserons la même class-map, mais modifierons la policy-map de la manière suivante : router(config)#policy-map worms-cared router(config-pmap)#class worms router(config-pmap)#set ip dscp 1 Dans ce cas particulier, tous les paquets classés comme appartenant à un flux HTTP dangereux verra son champ DSCP (DiffServ Codepoint) mis à 1. Il pourra ainsi être reconnu dans la suite du processus de forwarding et traité en conséquence. Cette particularité nécessite cependant une configuration plus rigoureuse. Jusqu'à maintenant, le choix de l'interface sur laquelle appliquer notre policy-map était conduit uniquement par le désir de limiter le trafic dans le sens ascendant ou descendant. Pour avoir une configuration plus lisible et moins sensible aux erreurs, nous placerons désormais nos policy-map sur l'interface d'entrée/externe (appelée ethernet 0) pour classer le trafic, et nos actions sur l'interface de sortie/interne (appelée ethernet 1). Dans les cas où vous avez plusieurs commandes à appliquer sur une même interface, référez à l'excellente documentation pour vérifier l'ordre d'opération [OP]. Par exemple, les ACL sont traitées avant les CAR qui sont traitées avant 'police'. router(config)interface ethernet 0 router(config-if)service-policy input worms-cared Après cela, nous appliquons donc notre action, ici la commande 'rate-limit', en sortie, grâce aux lignes suivantes : router(config)#access-list 103 permit ip any any dscp 1 router(config)#access-list 103 permit ip any any router(config)#interface ethernet 1 router(config-if)#ip access group 103 out router(config-if)#rate-limit output access-group 103 6000 900 1500 conform-action transmit exceed-action drop La configuration finale est résumée ci-dessous. ------------------------------------ SNiP ------------------------------------- ! class-map 'worms' class-map match-any worms match protocol http url "*default.ida*" match protocol http url "*cmd.exe*" match protocol http url "*root.exe*" ! policy-map 'worms-cared' policy-map worms-cared class worms set ip dscp 1 ! interface d'entrée interface ethernet 0 service-policy input worms-cared no access-list 103 access-list 103 permit ip any any dscp 1 ! interface de sortie interface ethernet 1 ip access group 103 out rate-limit output access-group 103 6000 900 1500 conform-action transmit exceed-action drop ------------------------------------ SNiP ------------------------------------- Nous pouvons utiliser exactement le même schéma que pour 'rate-limit' avec des ACL pour simplement rejeter le trafic marqué au lieu de le limiter. Il suffira de reprendre la même configuration que précédemment en retirant la ligne sur rate-limit et en changeant 'permit' en 'deny' dans l'ACL correspondant aux paquets marqués. La configuration résultante sera alors telle que ci-dessous. ------------------------------------ SNiP ------------------------------------- ! class-map 'worms' class-map match-any worms match protocol http url "*default.ida*" match protocol http url "*cmd.exe*" match protocol http url "*root.exe*" ! policy-map 'worms-dropped' policy-map worms-dropped class worms set ip dscp 1 ! interface d'entrée interface ethernet 0 service-policy input worms-dropped no access-list 103 access-list 103 deny ip any any dscp 1 access-list 103 permit ip any any ! interface de sortie interface ethernet 1 ip access group 103 out ------------------------------------ SNiP ------------------------------------- Enfin, nous pouvons réutiliser les configurations étudiées lors de la section 2.4 pour rejeter les paquets avec de meilleures performances, ou simplement les détourner pour analyse. Le début de la configuration étant toujours le même, nous ne décrirons que la partie qui change. ------------------------------------ SNiP ------------------------------------- ! class-map 'worms' class-map match-any worms match protocol http url "*default.ida*" match protocol http url "*cmd.exe*" match protocol http url "*root.exe*" ! policy-map 'worms-nulled' policy-map worms-nulled class worms set ip dscp 1 ! interface d'entrée interface ethernet 0 service-policy input worms-nulled no access-list 104 access-list 104 permit ip any any dscp 1 access-list 104 permit ip any any route-map worms-nulled 10 match ip address 104 set interface null0 ! interface de sortie interface ethernet 1 ip access group 104 out ip policy route-map worms-nulled ------------------------------------ SNiP ------------------------------------- Nous avons simplement repris les EACL de classification précédentes, qui ici ne rejettent aucun paquet, puis nous avons ajouter une route-map appelée 'worms-nulled' qui va créer une route vers null0 pour les paquets correspondant à nos EACL. Ces EACL et la route-map sont alors appliquées à l'interface de sortie. Notez que dans le sens sortant (outbound), les ACL seront bien examinées avec la route-map, permettant la concordance entre les deux. Les trois approchent que nous avons décrites (CAR avec police ou rate-limit, EACL simples, et enfin null0) furent proposées et utilisées avec succès lors des alertes qui ont suivi l'apparition respective des vers Code Red [CR] puis Nimda [NIMDA] que nous avons déjà évoqués. Ici encore, c'est dans la diversité des environnements open source que réside leur faiblesse. Le manque de cohérence et la généralité expliquent en grande partie qu'on ne dispose pas aussi facilement des mêmes fonctionnalités que chez Cisco, par exemple. Les seules propositions s'en rapprochant sont peut-être les IPS, pour Intrusion Prevention System. Ces logiciels ne sont en fait que le résultat logique du mariage entre les IDS et les firewalls. On pourrait même les réduire à de simples firewalls équipés d'un engin de pattern matching. La plupart des projets d'IPS libres sont basés sur Snort. Cependant, il ne sera possible dans tous les cas que de rejeter des paquets suite à une alerte, et non de les traitant de manière aussi variée que chez les vendeurs spécialisés. Parmis les projets les plus séduisants, on retiendra cependant SnortSam, qui permet de filtrer dynamiquement certaines IP suite à la génération d'alertes Snort. Son architecture est constituée d'un output plugin chargé par Snort qui surveillera chaque arrivée d'alerte. Si l'une d'elle correspond à une ligne dans son fichier de configuration, il envoie les règles de filtrage à un agent placé sur un firewall, éventuellement distant. Le contenu de cette communication est chiffré pour plus de sécurité. L'avantage majeur de cette approche est l'interopérabilité puisque SnortSam supporte plusieurs types de firewalls (iptables, pf, ipf, Cisco Pix et ACL classiques, Checkpoint Firewall-1, etc.). Sa faiblesse est justement introduite par cette même interopérabilité. En se réduisant à un dénominateur commun, le jeu d'instructions disponibles s'appauvrit. Une documentation complète, bien que pas toujours à jour, est disponible sur le site officiel de SnortSam [SAM] Toujours pour Snort, vous aurez très certainement entendu parler des FlexResp. Cette fonctionnalité permet de bloquer une connexion en se basant directement sur les protocoles utilisés. Au lieu de supprimer un paquet au niveau de la machine, l'IDS sortira de son rôle passif pour envoyer des segments RST en cas de flux TCP, ou des messages ICMP en cas de flux UDP, dans tous les cas spoofés afin de faire croire à une ou aux deux extrêmités de la connexion que celle-ci a été fermé, entraînant la suppresion des blocs de contrôles et donc l'oubli de la connexion. Reprenant la documentation Snort [RESP], les différents mots-clés disponibles à ajouter à vos règles sont les suivants : - rst_snd envoie un segment TCP RST à l'initiateur de la session - rst_rcv envoie un segment TCP RST au destinataire de la session - rst_all envoie un segment TCP RST aux deux extrêmités de la session - icmp_net envoie un message ICMP 'network unreachable' à l'initiateur de la connexion UDP - icmp_host envoie un message ICMP 'host unreachable' à l'initiateur de la connexion UDP - icmp_port envoie un message ICMP 'port unreachable' à l'initiateur de la connexion UDP - icmp_all envoie les trois messages ICMP précédents à l'initiateur de la connexion UDP Pour utiliser les FlexResp, il suffit d'ajouter 'resp:;' à votre règle Snort, en remplaçant 'keyword' par l'un des mots-clés présentés. Pour reprendre notre exemple bien particulier des vers basés sur la faille ISAPI d'IIS, nous utiliserons le préprocesseur HTTP de Snort en lui indiquant d'interpréter tous flux HTTP comme étant destiné à un serveur IIS, afin de déjouer les tentatives d'évasions. Puis, nous ajouterons une règle recherchant la chaîne de caractère 'default.ida' dans l'URL des messages HTTP contenus dans un segment TCP ACK. Lorsqu'un tel paquet est detecté, un segment RST est envoyé aux deux extrêmités de la transmission. ------------------------------------ SNiP ------------------------------------- preprocessor http_inspect_server: server default \ profile iis ports { 80 8080 } alert tcp any any -> any any (uricontent:"default.ida"; flags:A; \ resp:rst_all: msg:ISAPI buffer overrun) ------------------------------------ SNiP ------------------------------------- Notez que des deux approches, SnortSam est la plus sûre et fiable. Un IDS ne devrait en effet pas pouvoir envoyer la moindre donnée vers un attaquant au risque de trahir sa présence. De plus, un attaquant pourra aisément utiliser un une pile TCP/IP modifiée (même un worm) ignorant les segments RST, s'immunisant de cette façon. Enfin, la facilité d'emploi du spoofing risquerait de transformer cette mesure de sécurité en une tentante invitation au DoS. Il suffit en effet d'interpréter les rulesets Snort, d'envoyer des paquets construits pour y répondre mais avec des adresses forgés appartenant aux machines ou au réseau qu'on souhaite couper, pour disposer d'un moyen anonyme de créer des DoS. En tentant de réduire le risque de DDoS, on aura alors faciliter l'exploitation de DoS, en permettant d'utiliser l'IDS comme relai. 2.5. iTrace Les nombreuses possibilités d'attaques spoofées, en particulier dans les cas de DDoS, et la difficulté qu'elles entraînent dans la recherche de la source réelle, ont poussé Steve Bellovin - au palmarès évocateur puisqu'il se cache derrière le livre "Firewalls and Internet Security", la RFC 1948 et pushback qui est présenté un peu plus loin - à développer, au sein de l'IETF, un nouveau type de message ICMP (sans code) permettant de suivre le chemin d'un paquet : l'ICMP Traceback Message [ITRACE]. La génération est définie au niveau de chaque routeur et s'effectue suite au passage de 1 paquet sur 20000 selon la valeur par défaut recommandée qui peut bien sûr être adaptée ; sans jamais dépasser les 1/1000. La paquet traceback est toujours généré avec un TTL de 255 pour contre-vérifier la distance par rapport au routeur. Ce message est formé d'une série de champs organisés chacun selon le format TLV (Tag-Length-Value) indiquant d'abord le type d'information, puis sa longueur et enfin sa valeur proprement dite. Les tags sont les suivant : 0x01 Back Link 0x02 Forward Link 0x03 Interface Name 0x04 IPv4 Address Pair 0x05 IPv6 Address Pair 0x06 MAC Address Pair 0x07 Operator-Defined Link Identifier 0x08 Timestamp 0x09 Traced Packet Contents 0x0A Probability 0x0B RouterId 0x0C HMAC Authentication Data 0x0D Key Disclosure List 0x0E Key Disclosure 0x0F Public-Key Information Un traceback doit contenir un back link ou un forward link et éventuellement les 2. Un *link inclut au minimum une paire d'adresses IPv4 ou IPv6 dans le sens du parcours du paquet (source puis destination) au-dessus du routeur dans le cas d'un backlink et au-dessous du routeur pour un forward link, avec éventuellement un nom d'interface du point de vue du générateur (le routeur à l'origine du traceback) ainsi qu'une paire d'adresses physiques (MAC ou chaînes de caractères définies par l'opérateur). Le tag timestamp spécifie le moment au format Network Time Protocol auquel le paquet tracé est arrivé au niveau du générateur. Le tag traced packet contents doit contenir si il est spécifié au moins l'header IP et les 8 premiers octets du payload. Probablity indique la probabilité avec laquelle le paquet tracé a été sélectionné pour générer un traceback, cette probabilité étant définissable pour chaque routeur. RouterId est un identifiant qui ne devrait généralement avoir de sens que pour l'organisation propriétaire du routeur générateur. Les derniers tags sont utilisés pour l'authentification des traceback. Un attaquant pourrait en effet vouloir générer des faux traceback afin de brouiller les pistes remontant jusqu'à lui. Le tag HMAC Authentification est impératif, il est subdivisé en champs algorithme (HMAC-MD5-128, HMAC-SHA1-160, probable utilisation des ISAKMP codepoints), keyid, timestamp de génération de la clé au format NTP toujours et Message Authentification Code pour l'authentification proprement dite. Les derniers champs permettent de donner des informations sur les clés précédemment utilisées ainsi que des informations sur la PKI utilisée afin de vérifier l'identité du routeur (via le certificat de son organisation). Divers aspects de la sécurité comme le spoofing et les Denial of Service sont pris en compte dans le design de ce nouveau type ICMP. Ainsi il est conseillé de baser la probabilité de génération sur un pseudo random number generator plutôt que sur un simple comptage cyclique. Comme nous l'avons dit, par défaut la génération par probabilité est de l'ordre de 1 pour 20000 afin de ne rajouter que 0.1% de trafic sur la totalité d'Internet (supputant une largueur moyenne de 20 hops). Cependant lors d'un DDoS, le nombre de paquets augmentera essentiellement autour du point de convergence qu'est la victime et donc ce seront les routeurs les plus proches qui auront le plus de chance de générer des messages ICMP traceback. Pour remédier à ce problème, un draft supplémentaire [MAN+01], spécifiant comment obtenir délibérément des ICMP traceback, a été rédigé. Il recommande d'attacher à chaque route une "Intention Value" indiquant la probabilité d'envoi de traceback désirée pour cette route. Le routeur sélectionne le forwarding path pour un paquet réceptionné, consulte l'Intention Value pour cette route, et envoi un ICMP traceback à la destination si nécessaire. De plus, elle spécifie également qu'un routeur qui reçoit un traceback à router peut réutiliser ces informations afin de constituer un agrégat qui entraînera à son tour la génération de traceback vers la source. Enfin l'Intention Value devra être redistribuée entre les routeurs à l'aide de BGP. Mais comme vous l'avez sans doute remarqué, cette méthode se limite par sa conception au traceback forward link, réduisant son utilité. Mais n'oubliez pas que l'iTrace n'est encore qu'au stade de proposition et aucune implémentation n'est encore projeté. D'ailleurs, en février 2002, le schéma Intention Driven devait encore être réécrit pour s'adapter à tous types de tag link. Et fin 2003, les documents relatifs à sa mise en place avaient même disparu du site de l'IETF, pour n'être que pauvrement remplacé en octobre 2003 par un draft [ATP] (très mal écrit) définissant un Active Traceback Protocol. Celui-ci se contente de réutiliser l'infrastructure conçue par Steve Bellovin pour iTrace afin d'y adjoindre un mécanisme compatible déclenchant le tracking à la suite d'une requête d'un administrateur ayant obtenu une Security Association avec l'origine du tracking, comme il est prévu de pouvoir le faire avec iTrace. La compatibilité s'étend également à la reconnaissance de numéro d'identification de génération de traceback classique afin de pouvoir recouper traceback actif (ATP) et passif (iTrace). Le problème reste le même : à savoir une implémentation inexistante doublée de zone de floue autour des règles et mécanismes de génération des traceback. Si iTrace présent l'intérêt d'un outil statistique multi-usage facile à mettre en place au sein des réseaux pré-existant, Intention-driven iTrace ou ATP, qui tente de répondre à l'envie des administrateurs de contrôler très précisément la génération des traceback afin d'en améliorer la précision, n'apportent pas de réelles solutions. L'examen des techniques suivantes semblent démontrer que, si le tracking passif s'intègre très bien par des solutions protocolaires, sa contre-partie active doit reposer plus abondamment sur des outils logiciels originaux. 2.7. SPIE Source Path Isolation Enfine, ou SPIE [SPIE], désigne un système d'IP traceback mis au point par le MIT et BBN Technologies avec des fonds du DARPA, et se trouve à l'étude auprès de l'IETF [IPPT]. Contrairement à l'iTrace, SPIE fournit des informations relatives au traçage d'un paquet en réponse à des requêtes explicites au lieu de se baser sur des probabilités. SPIE est également remarquable pour l'attention faite à la protection de la vie privée - notamment quant à la subversion de SPIE en système généralisé de surveillance et d'accounting - ainsi que les performances en particulier au niveau de l'encombrement mémoire. Le problème du traceback est bien souvent de stocker les informations d'accounting relatives à chaque paquet transmis. Ce problème est éludé avec iTrace en effectuant une génération immédiate mais probabiliste. SPIE résout quant à lui le problème en stockant des hash de chaque paquet IP à partir de 28 bits d'entête excluant les champs Time to Live, checksum, Type of Service et IP Options qui peuvent être modifiés à chaque hop. Les agents effectuant les hash sur les routeurs sont nommés DGA pour Data Generation Agent et peuvent aussi bien être software que hardware (attaché à une interface par exemple). Lorsqu'un paquet est intercepté au niveau du forwarding path d'un routeur, le DGA fait coïncider chaque fonction universelle de hashage avec un vecteur d'initialisation unique, à un bit dans un filtre en fleur nommé digest table. Ce mécanisme facilite les tests de traceback qui se résument pour chaque agents "vérifieurs" à prendre le hash d'une requête et à rechercher la présence d'un bit à la position correspondant à cette fonction de hashage dans le filtre en fleur. Le risque de collision est au plus de 0.139% sur un LAN, lorsqu'il y a manque de diversité de trafic. Les hashs sont finalement stockés dans des digest tables. L'utilisation des hashs permet aussi de préserver la vie privée des utilisateurs légitimes du réseau en ne stockant ni ne transmettant aucune information claire. ------------------------------------ SNiP ------------------------------------- Bloom filter _ 1st hash() -----> |1| | | | | 2nd hash() -----> |1| | | | | 2^n bits 3rd hash() -----> |0| | | | | 4th hash() -----> |1| _| <- n bits -> Représentation d'un filtre en fleur Reproduction de la figure 4 de [SPIE] ------------------------------------ SNiP ------------------------------------- Les DGA ne conservent les hash que peu de temps. Pour un stockage à plus long terme, les digest tables sont rapatriées sur des agents SPIE Collection and Reduction (SCAR) qui servent de points de concentration pour une zone du réseau, chapeautant plusieurs routeurs/DGA. Lorsqu'un administrateur souhaite vérifier le parcourt d'un paquet, il calcule son hash, fait une requête via le STM (SPIE Traceback Manager) qui relait auprès des tous les SCAR. Les requêtes sont constituées du hash du paquet recherché, du temps de réception et du dernier hop avant la destination. Chaque SCAR construit un graphe connexe par simulation du Reverse Path Forwarding représentant le parcourt du paquet pour sa zone d'autorité, puis le STM assemble la totalité de ces graphes pour former le parcours complet du paquet jusqu'aux DGA à l'extrémité du domaine (edges). L'utilisation des hash et des filtres en fleur permettent à SPIE de ne générer aucun faux négatifs, et seulement d'éventuels faux positifs créant un surplus d'information représenté par des branches supplémentaires - généralement limitées à un hop puisque les vecteurs des fonctions de hashage changent - dans le graphe d'un SCAR donné. L'un des objectifs originaux de SPIE est de supporter les multiples transformations légitimes que les paquets peuvent subir lors de leur transmission comme celles induites par le Network Port & Address Translation (NPAT), ainsi qu'IPSec et la fragmentation. Pour gérer convenablement ces transformations et éviter d'offrir là un moyen d'évasion, chaque DGA maintient simultanément à chaque digest table, une Transform Lookup Table (TLT) listant toutes les transformations effectuées dans la même période de temps que la génération d'un digest. Chaque entrée TLT comporte un digest, le type de transformation et un extrait du nouveau paquet suite à la transformation pour poursuivre le traceback. Lorsque le flag I est présent, le 4ème partie doit être considérée comme un pointeur vers une structure externe contenant les informations permettant de retrouver la trace du paquet. Ce flag peut aussi servir à conserver des données temporairement lorsque plusieurs digest signalent une même transformation. --------------------------------------- | Digest | Type | I | Packet Data | | 29 bits | 3 bits | flag | 32 bits | --------------------------------------- En conclusion, bien que plus complexe que l'iTrace, SPIE semble bien plus abouti comme système de traceback notamment au niveau de la protection de la vie privée et des performances. Une première implémentation, destinée à démontrer les qualités du système, a été rendu publique par BBN Technologies en mars 2002. Elle a été développé pour FreeBSD et son nombre important de dépendances (Zebra, net-SNMP, ...) se voit contre-balancé par une démonstration d'interface graphique en PerlTk. Notez enfin que la technologie a été soumis à l'IETF, ce qui laisse espérer une future généralisation de SPIE. 2.8. IP Source Tracker Face à ces nombreuses technologies de tracking en cours de standardisation ou de développement, Cisco a rapidement réagi en proposant dans les versions 12.0(21)S d'IOS une fonctionnalité originale, l'IP Source Tracker. Dans l'esprit de ces concepteurs [IPST], IP Source Tracker remplace un processus fastidieux de tracking que tout opérateur Cisco était à même de réaliser à partir d'ACL. En effet, lorsqu'une attaque de type DoS est détectée, il restait possible à l'administrateur du réseau de placer des ACL sur ses routeurs, en partant du plus proche de la cible du DoS, puis de se servir des logs produits par ces ACL pour remonter de routeurs en routeurs jusqu'au point d'entrée de l'attaque dans le réseau. Afin donc de faciliter la vie des administrateurs, Cisco propose une solution automatisée, basée, comme pour RPF, sur la technologie CEF. Après être parvenu à déterminer l'adresse cible du DoS, il vous suffit de taper la ligne suivante en configuration globale : router(config)#ip source-track
L'intérêt majeur est que le tracking de tous les paquets se dirigeant vers cette adresse s'effectuera automatiquement sur l'ensemble des interfaces du routeurs, sans avoir à configurer d'ACL sur chacune d'elle. Vous pouvez, bien sûr, paramètrez quelques options relatives au source tracker. En particulier, vous pouvez indiquez le nombre maximal d'adresses suivies simultanément - par défaut, non restraint - en limitant le nombre d'instance de la commande 'ip source-track' possibles. Tapez simplement la commande ci-dessous : routeur(config)#ip source-track address-limit Il faut également savoir que sur les modèles de routeurs Cisco sur lesquels l'IP Source Tracker est disponible, les données sont collectées au niveau des chaque carte réseau individuellement, puis exportées vers le processeur central. Il est donc possible de paramétrer l'intervalle, en secondes, entre ces exportations : routeur(config)#ip source-track export-interval Pour visionner les données issues du tracking, on trouve également plusieurs options différentes d'après le squelette suivant : router#show ip source-track {address} {summary | cache | export flows} L'adresse est optionnelle, vous permettant ainsi de visionner les statistiques pour une adresse suivies ou pour toutes les adresses suivies. Les options d'affichages qui viennent ensuite sont relativement auto-explicatives : 'summary' donne un court résumé des statistiques, 'cache' affiche les données collectées au niveau des cartes réseaux et 'export flows' délivre celles qui ont été exporté vers le processeur central. Notons toutefois plusieurs limitations importantes qui font essentiellement d'IPST, une simple solution d'appoint. D'abord, le système n'étant en aucun cas distribué - à moins éventuellement que vous ne scriptiez de manière simultanée et automatique sur l'ensemble des routeurs, puis fassiez remonter d'une quelconque manière ces données afin de les corréler et synthétiser -, le tracking n'est pas instantané à travers la totalité de votre parc de routeurs. Outre la tâche de configuration fastidieuse, cela signifie aussi qu'il vous restera à construire seul le graphe représentant le parcours des paquets. On retrouve donc ici les mêmes problèmes que pour les blackholes, à savoir le manque de coopération entre les différentes technologies Cisco. Le rate limiting ou RED - deux techniques qui sont étudiées ultérieurement - sont supportées par Cisco et pourraient être utilisées pour déclencher le tracking. D'autre part, contrairement à SPIE et iTrace, IP Source Tracker n'a pas une vocation universelle. Toutes les informations collectées s'arrêteront donc, au mieux, au niveau du point d'entrée de l'attaque dans votre réseau. Une coordination entre ISPs peut cependant rendre cette technologie intéressante, pour eux uniquement. C'est donc véritablement, comme énoncé honnêtement par Cisco, un simple remplacement plus productif de la méthode de recherche manuelle à base d'ACL. Enfin, si aucun impact sur les performances brutes des routeurs ne sont à déplorer, il faut tout de même remarquer que la surcharge sur les cartes réseaux peut provoquer des rejets de paquets. Ce n'est donc pas une technique à appliquer une bonne fois pour toute, mais bien une option temporaire en réaction à une attaque, comme le blackholing. D'autre part, un tel dispositif, ainsi que toutes les technologies de tracking présentes ou futures, ne vous dispensent en aucun cas de collecter le plus de données possible sur le trafic de votre réseau. Vous pourrez ainsi pallier en toute occasion les défauts ou défaillances de vos systèmes de tracking, et apporter un complément d'information dans les autres cas. Nous avons ainsi fait remarquer à quel point l'utilisation du logging au niveau des règles de firewall, ou bien le reporting lorsque vous employez un IDS, s'avère important. Dans le même ordre d'idée, Cisco propose de nombreuses commandes permettant de surveiller l'utilisation des ressources sur un routeur. L'une d'entre elle est Netflow. une autre technologie propriétaire Cisco basée sur CEF. Celle-ci permet de générer des statistiques détaillées du trafic passant par un routeur, et même éventuellement de les exporter vers une machine distantes d'administration, typiquement équipée de NetflowCollector. Sa configuration, sous IOS, s'effectue par interface : router(config)#interface ethernet 0 router(config-if)#ip route-cache flow Les statistiques peuvent alors aisément être affichés et vidées grâce aux commandes suivantes, respectivement : router#show ip cache flow router#clear ip flow stats Vous disposez également de quelques raffinements, comme le choix du nombre maximal d'entrées présentes dans le cache Netflow. La valeur par défaut est de 65536, sachant que chaque entrée nécessite approximativement 64 octets pour son stockage. Cette valeur pouvant varier de 2^10 à 2^19, voici la commande permettant de la choisir : router(config)#ip flow-cache entries Vous pouvez également, comme nous l'avons brièvement dit, exporter les données vers une console d'administration lorsqu'elle expire sur le routeur, afin d'en conserver une trace. Cette fonctionnalité facilite grandement le tracking manuel en permettant de centraliser vos données vers une seule et unique machine. La commande d'export est telle que ci-dessous, avec version indiquant le format qu'est capable de recevoir le logiciel destinataire, de 1, par défaut, à 5 : router(config)#ip flow-export [version ] Vous disposez d'une dernière fonctionnalité permettant de résumer les données collectées par Netflow au sein d'un Aggregation Cache (AC). Pour ce faire, appliquez le fichier de configuration ci-dessous. ------------------------------------ SNiP ------------------------------------- configure terminal ip flow-aggregation cache cache entries 2046 cache timeout inactive 120 cache timeout active 60 export destination enabled ------------------------------------ SNiP ------------------------------------- La plupart des options ont la même signification que les options Netflow classiques. La différence vient de la possibilité de spécifier les valeurs de timeout pour des entrées inactives et actives, avant de les voir supprimées et donc exportées. 'Scheme' permet, quant à elle, de définir le critère d'agrégation des paquets. Elle peut prendre comme valeur 'as' pour l'autonomous system auquel appartient le routeur, 'protocol-port' pour le type de protocole au niveau transport, 'destination-prefix' pour l'adresse de destination du paquet, 'source-destination' pour l'adresse source et 'prefix' les deux simultanément. Pour toutes agrégation basée sur le prefixe IP, vous pouvez indiquer une valeur minimale pour le masque de sous-réseau, selon la notation CIDR. Choissisez, parmis les séquences suivantes à entrer en mode configuration globale, celle qui équivaudra à votre agrégat. ------------------------------------ SNiP ------------------------------------- ! pour prefix ip flow-aggregation cache prefix mask source minimum 24 mask destination minimum 24 ! pour source-prefix ip flow-aggregation cache source-prefix mask source minimum 28 ! pour destination-prefix ip flow-aggregation cache destination-prefix mask destination minimum 28 ------------------------------------ SNiP ------------------------------------- Enfin, n'oubliez pas que, sous IOS, les informations délivrées par n'importe quelle commande 'show' peuvent être triées à l'aide d'expressions rationnelles. Pour ce faire, juste après la commande, tapez un pipe, suivi de 'begin' pour conserver les lignes commençant par l'expression, 'include' contenant l'expression et 'exclude' ne contenant pas l'expression. Puis, finissez par l'expression elle-même. Pour que Netflow n'affiche que les paquets orientés vers null0, la commande serait comme ci-dessous : router#show ip cache flow | include null Pour les systèmes libres compatibles Unix, vous pouvez utiliser l'excellent outil d'audit ARGUS (Audit Record Generation and Utilization System) [ARGUS]. Nous ne nous attarderons pas sur sa configuration qui a été déjà longuement décrite pour le public francophone dans d'autres documentations [BER02] dont une rédigée par CNS. 3. Exhaustion-oriented Notre première approche sert efficacement son but : limiter l'impact d'un DDoS en refoulant les paquets qui le véhicule à l'entrée du réseau protégée, ainsi qu'en permettant d'identifier rapidement l'origine de l'attaque (ou au moins son point d'entrée) pour y répondre par des contre-mesures appropriées. Mais même le plus efficace des filtrages ne suffit pas à réduire à néant les effets d'un DDoS puisque la bande passante reste monopolisée en amont. On remarquera par contre que de telles attaques impliquent généralement une forte augmentation de la congestion réseau, à mesure que l'on se rapproche de la cible dans le cas d'une attaque distribuée, ou bien le long du chemin d'attaque pour un DoS plus ciblé. Il est donc judicieux d'envisager la défense face aux DDoS sous l'angle de la lutte contre l'exhaustion des ressources. Même si cela paraît nous faire sortir légèrement de notre sujet initial, c'est dans cette optique de lutte généralisée contre la congestion que nous nous intéresserons tout particulièrement au domaine de l'Active Queue Management, très bien défini par la citation ci-après. "It is useful to distinguish between two classes of router algorithms related to congestion control: "queue management" versus "scheduling" algorithms. To a rough approximation, queue management algorithms manage the length of packet queues by dropping packets when necessary or appropriate, while scheduling algorithms determine which packet to send next and are used primarily to manage the allocation of bandwidth among flows. While these two router mechanisms are closely related, they address rather different performance issues." [2309] Des disciplines d'AQM sont notamment disponibles dans les QoS commands d'IOS, dans ALTQ [ALTQ] fourni avec les *BSD (natif à partir de FreeBSD 5.0, OpenBSD 3.0, NetBSD 1.6A et disponible auparavant via les patchs ALTQ ou les snapshots KAME), et dans iproute2 [IPR2] fourni avec Linux. L'AQM a pour nous un avantage important par rapport au scheduling également cité. Les disciplines disponibles s'appuient en effet sur les statistiques et ne demanderont donc pas une configuration spécifique à chaque réseau basée quant à elle sur une étude complexe des flux traversant le réseau. Une telle configuration serait de plus bien trop sensible aux variations du type de trafic, laissant la porte grande ouverte aux attaquants qui n'auraient qu'à modifier légèrement le type de trafic utilisé lors du DDoS pour non seulement contourner les mesures de scheduling mais également l'abuser en offrant une plus grande priorité aux flux liés à l'attaque. En étudiant de manière la plus généraliste possible la diminution de la congestion et la réduction de la consommation en bande passante, nous nous assurons d'une qualité et d'une continuité de service exemplaire en toutes situations, incluant en particulier les DDoS. Nous pourrions bien entendu suivre notre idée et aller jusqu'à évoquer les mesures d'optimisation de l'utilisation des ressources système (CPU, mémoire, etc.) de nombreux systèmes, ou même étudier le matériel le plus performant ou encore les différents algorithmes d'évitement de congestion sur les hôtes. Cependant, nous choississons d'étudier les mesures les plus génériques tant par leur portée - c'est-à-dire s'appliquant au niveau OSI 3 ou 4 de la pile TCP/IP et sur le matériel d'infrastructure réseau plutôt que sur les hôtes - que par leur implémentation. Nous nous écartons cependant parfois des AQM pour évoquer des technologies permettant elles aussi de réduire l'utilisation de la bande passante ou de supporter une plus forte charge sans interruption des services proposés, ou bien des technologies moins largement adoptées, mais pour autant répondant parfaitement à la problématique des DDoS. 3.1. RED Lorsqu'un routeur reçoit un paquet, il le place dans une queue FIFO pendant la durée de son traitement le long du forwarding path. Ces queues consommant des ressources, il a rapidement fallut trouver des solutions pour remédier aux dépassements potentiels causant des perturbations du réseau. La réponse traditionnelle a pendant longtemps été la discipline drop-tail. Elle consiste à remplir la queue jusqu'à un certain nombre de paquets ou d'octets, puis à simplement rejeter toute nouvelle donnée qui dépasserait. Malgré sa simplicité, elle présente un certain nombre d'inconvénients. Tout d'abord elle est considérée comme injuste, favorisant les connexions longue durée, le trafic unidirectionnel, et les paquets de taille fixe pour leurs faibles variations et donc leur monopolisation des ressources dit phénomène de lock-out. Ce problème provoquant de surcroît un autre phénomène dit de synchronisation des retransmissions. Le lockout de quelques connexions va en effet entraîner une bouffée de rejets simultanés causant une seconde bouffée décalée de retransmissions et donc, une nouvelle congestion. Enfin, à cause du fonctionnement de TCP - notamment le regroupement des segments en bouffée, et l'utilisation d'algorithmes de recouvrement basés sur le segment -, ce rejet massif entraînera également des difficultés de recouvrement des segments perdus. Cette caractérisation très précise des flux favorisés par drop-tail et les défauts inhérents à TCP évoqués rendent les routeurs et passerelles basés sur drop-tail extrêmement sensible à des DoS ciblant l'infrastructure du réseau. C'est pourquoi nous allons ici étudier les mesures développées pour remplacer drop-tail et supprimer ses effets pervers. En effet, pour résoudre ces divers problèmes, Sally Floyd et Van Jacobson (déjà à l'origine des algorithmes de Congestion Avoidance pour TCP) développèrent en 1993 l'algorithme RED [FLO+93], pour Random Early Detection, basé sur un rejet probabiliste, dans le sens où la probabilité d'un paquet d'être rejeté croît proportionnellement à l'augmentation de la taille moyenne de la queue FIFO (notée AVG). L'utilisation d'une estimation moyenne dans le calcul du rejet permet de répondre à une augmentation persistante de la queue, et non à une hausse instantanée potentiellement due à un trafic par bouffée, tel TCP. L'algorithme RED est donc divisé en réalité en 2 parties : à chaque arrivée de paquet il estime AVG, puis effectue la décision de marquage ou non. ------------------------------------ SNiP ------------------------------------- initialization avg = 0 count = -1 for each packet arrival calculate the new average queue size avg : if the queue is non empty avg = (1 - w)avg + wq else m = (time - q_time) / s avg = avg(1 - w)^m if minth =< avg < maxth increment count calculate probability Pa : Pb = Pmax(avg - minth) / (maxth - minth) Pa = Pb / (1 - count * Pb) with probability Pa : mark the arriving packet count = 0 else if maxth =< avg mark the arriving packet count = 0 else count = -1 when queue become empty q_time = time Variables sauvegardés : avg : taille moyenne de la queue q_time : début du temps d'inactivité de la queue count : nombre de paquets depuis le dernier marqué Paramètres fixes : w : poids de la queue minth : seuil en dessous duquel aucun paquet n'est rejeté maxth : seuil au dessus duquel tous les paquets sont rejetés Pmax : valeur maximum pour Pb Divers : Pa : probabilité actuelle de marquage de paquet q : taille actuelle de la queue time : temps actuel Pseudo-code de l'algorithme RED Reproduction de la figure 2 de [FLO+93] ------------------------------------ SNiP ------------------------------------- Lorsque nous déchiffrons ce pseudo-code, nous remarquons que l'algorithme est exécuté pour chaque nouveau paquet traversant la passerelle, mais son overhead reste cependant négligeable (lors d'expérimentations, RED offrant même de meilleurs débits avec des queues plus petites que drop-tail). Comme dit précédemment, l'algorithme se divise en 2 parties : le calcul de AVG (dit par Exponential Weighted Moving Average), et le calcul de probabilité de marquage qui en dépend. Dans ce premier, la moyenne avg = avg(1-w) + wq dans lequel q est la mesure instantanée de la queue. W, le poids de la queue, doit être sélectionné avec une extrême précaution. Une valeur trop importante rendrait l'algorithme plus sensible et provoquerait une détection de congestion instantanée, tandis qu'une valeur trop faible offrira une réactivité minime à tout type de congestion. Vous trouverez en [FLO+93] des propositions permettant de déterminer les limites supérieure et inférieure de AVG. Dans un grand nombre de document, vous rencontrerez w = 0.002, ce qui correspond à 200 arrivées de paquets. Un cas spécial existe lorsque la queue est vide. Comme RED calcule la moyenne de la taille de cette queue à chaque arrivée de paquet, on calcule dans ce cas en se basant sur le nombre m de paquets qui pourrait avoir été transmis durant le temps d'idle. M vaut (time - q_time) / s où time est l'horaire actuel, q_time l'horaire de départ du temps d'idle, et s une durée typique de transmission. Enfin, pour le paramétrage de minth et maxth, il est simplement recommandé que l'espace entre les 2 soit supérieur à l'augmentation de la AVG en un roundtrip time (RTT). Ce qui en règle générale équivaut à un paramétrage de maxth au moins égal à 2 fois minth. Une fois cette moyenne calculée selon le cas de figure observé, on vérifie qu'elle est comprise entre minth et maxth. En dessous de minth, aucun paquet n'est marqué ; au dessus de maxth, tous les paquets sont marqués, avec une probabilité de 1 ; entre les 2, l'algorithme marque selon la probabilité Pa. Pour déterminer Pa, on prend Pb qui varie de 0 à Pmax lorsque la AVG varie de minth à maxth. Alors, Pb = Pmax(avg - minth) / (maxth - minth) puis Pa = Pb / (1 - count * Pb) où count est la mesure du nombre de paquets passés depuis le dernier marquage. Une autre formule est cependant disponible si vous désirez plutôt vous baser sur un nombre d'octets. De récentes études ont démontré que le mode par octets s'avérait environ 15% plus efficace que le mode par paquet lorsque le trafic était composé de paquets de faible taille (moins de 300 octets). Cette tendance s'inverse cependant lorsqu'il s'agit de jumbogrammes, c'est-à-dire plus grands que 1500 octets. Entre ces deux limites, la bande passante disponible ne varie que de 1% selon le mode choisi. En [RED], vous trouverez des indications pertinentes sur le choix des valeurs à attribuer à tous les paramètres fixes que nous avons évoqués ainsi que de plus amples explications sur les rouages de l'algorithme. Bien que n'étant pas un mécanisme strictement conçu afin de contrer les DoS, RED offre la possibilité de détecter simplement les flux utilisant une large partie de la bande passante. En effet, d'après l'algorithme, la probabilité de marquage d'un paquet appartenant à un flux spécifique est proportionnelle à la part actuelle de la bande passante dédié à ce flux. Nous disposons donc à travers cette application du théorème de Hoeffding d'inégalité de variables aléatoires limitées (précision à l'intention du lecteur excessivement curieux), d'un moyen de détecter un mauvais flux et d'utiliser cette information à un niveau supérieur pour agir contre elle avec par exemple la limitation de son utilisation de la bande passante ou son rejet, comme par exemple dans la technologie ACC. RED est désormais largement déployé au sein des systèmes d'exploitation notamment grâce à sa description et recommandation [2309] pour les routeurs par l'IETF en 1998. Ainsi, confirmant son histoire d'OS experimental, Linux supporte cette discipline via l'option CONFIG_NET_SCH_RED, et ce depuis le kernel 2.1.90. Il sera ensuite nécessaire de tirer partie de iproute2 afin d'en configurer les paramètres par interfaces. Via la commande 'tc', nous pouvons placer en sortie sur une interface une 'qdisc', c'est-à-dire une queueing discipline afin de traiter les paquets. L'une de ces disciplines se trouve être RED. Il suffira alors, pour l'activer et la paramétrer, d'utiliser la commande suivante : # tc qdisc add dev root handle 1: qdisc red limit 25600 min 2560 \ max 10240 avpkt 512 burst 15 bandwidth 10mbps probability 0.1 Jusqu'au mot-clé 'qdisc', la commande est standard et ajoute une qdisc sur le device $DEV, à remplacer par l'interface sur laquelle vous souhaiter activer RED. 'root' indique que cette qdisc se trouve à l'origine de la hiérarchie des qdisc sur cette interface et traite donc la totalité du trafic y arrivant, tandis que 'handle' permet de définir un identifiant unique pour cette règle. La suite est constituée des paramètres configurables de RED que nous avons étudié théoriquement. Vous pouvez alors choisir les valeurs de seuils maximal et minimal ainsi que la taille moyenne des paquets en octets, puis la taille maximal des bursts en nombre de paquets, avant de préciser la bande passante de votre interface (utilisée dans le cas spécifique d'une queue vide que nous avons décrit théoriquement) en bps, et enfin la probabilité maximal (pmax) de rejet qui est ici de 10%. FreeBSD quant à lui utilise par défaut la discipline drop-tail. Cependant, le support de RED existe depuis la release 2.2.1 grâce à ALTQ et son option kernel ALTQ_RED. Vous devrez ensuite éditer le fichier altq.conf pour activer RED sur une base par interface avec le raffinement de pouvoir paramétrer les valeurs du seuil minimal, du seuil maximal, l'inverse de la probabilité maximale de rejet et la taille maximale de la queue en paquets (voir altq.conf(5) pour de plus amples détails et des exemples). L'ajustement des leurs valeurs donne pour ALTQ la configuration suivante : interface bandwidth qlimit 50 red thmin 5 thmax 20 \ invpmax 10 Depuis de la release 2.2.8, FreeBSD supporte également un mécanisme de gestion de queue et bande passante nommé Dummynet. Son intérêt principal était son intégration au main tree FreeBSD tandis qu'ALTQ n'était qu'un ajout experimental de la pile KAME. Les fréquentes synchronisation du code FreeBSD sur KAME rendent cet argument désuet, mais Dummynet demeure intéressant pour sa configuration intégrée à ipfw et son développement contigu à celui-ci. Dummynet supporte depuis toujours l'algorithme RED et une variante, Gentle RED. Cette dernière se distingue par une probabilité pour les taux de rejet allant de Pmax, pour une AVG à maxth, jusqu'à 1, pour une AVG à 2 * maxth. Pour utiliser ces algorithmes, il faut faire appel le mot clé ipfw 'pipe' pour renvoyer à un pipe dummynet qui émule un lien avec un delai, une bande passante etc. donné. Ajoutez par exemple les règles suivantes dans /etc/rc.firewall. ------------------------------------ SNiP ------------------------------------- ipfw -q add pipe 001 all from any to any via any ipfw -q pipe 001 config red 0.0026/5/20/10 ------------------------------------ SNiP ------------------------------------- D'abord nous créons une règle valable pour tout type de paquets, depuis et vers n'importe quelle adresse, et ce par n'importe quelle interface. Puis nous appliquons RED sur ce pipe. Toutes les variables RED ajoutez dans cette ultime règle sont les mêmes que celles du pseudo-code et de la configuration d'ALTQ. Vous pouvez en sus configurer certaines variables via la MIB sysctl concernant le calcul de la AVG après un temps d'inactivité : # sysctl -w net.inet.ip.dummynet.red_lookup_depth=256 # sysctl -w net.inet.ip.dummynet.red_avg_pkt_size=512 # sysctl -w net.inet.ip.dummynet.red_max_pkt_size=1500 OpenBSD utilise, tout comme FreeBSD, drop-tail. Et comme FreeBSD, ceci peut être changer à l'aide d'ALTQ. Seulement les bouleversements du sous-système de classification et de filtrage de paquets, intervenus depuis la release 3.0, avec l'arrivée de Packet Filter (PF) en remplacement d'IPFilter, ont donné lieu à une intégration différente de ALTQ. En effet, depuis la release 3.0, ALTQ est disponible dans le système de base, et depuis la release 3.3, sa configuration est liée à celle de PF et se trouve donc dans le même ficher : /etc/pf.conf [MANPF]. La syntaxe originale d'ALTQ, basée sur le trio interface/class/filter, se trouve donc quelque peu modifiée. Pour séparer le queueing du firewalling, la séquence de commande se démarque par le mot-clé 'altq on' comme ci-dessous : altq on bandwidth [qlimit ] \ [tbrsize ] queue { queue_list } queue bandwidth [priority ] [qlimit ] \ [(sched_options)] { queue_list } Il y a donc deux commandes distinctes : altq on et queue. La première permet de définir à quelle interface on applique telle discipline ou scheduler (cbq ou priq) à laquelle on attribue tant de bande passante (bandwidth, en % ou bps). Queue, suivi d'une liste, spécifie alors les différentes classes de trafic pour lesquelles cette configuration est valable. La définition des queues est alors du même type que les classes ALTQ classiques. Elles suivent donc une architecture en arbre partant d'une queue racine. Chaque queue est identifiée par un nom qui doit avoir été défini dans queue_list, ainsi qu'une bande passante, une discipline de queueing qui doit être partagée par toutes les branches de l'arbre de queues, et enfin d'éventuelles branches fils listées dans queue_list. Pour RED, nous nous intéresserons aux options de la discipline (notées sched_options). Ces options sont default pour indiquer la queue racine, red, rio, ecn et borrow ayant le même sens que dans la configuration classique d'ALTQ. L'option red active donc RED sur la classe de trafic désirée. Si nous voulons appliquer RED sur tout le trafic passant par l'interface, il suffit de placer l'option sur la queue racine. Vous trouver ci-dessous un exemple de configuration avec RED sur la queue racine et une queue supplémentaire pour la trafic HTTP. Vous pourrez remarquer que les filtres ALTQ sont remplacés, sur OpenBSD, par les règles de firewall de PF auxquelles on ajoute l'option 'queue' suivi du nom d'une queue défini dans 'altq on' et 'queue'. ------------------------------------ SNiP ------------------------------------- # au début de votre ruleset altq on fxp0 cbq bandwidth 100% queue { std, http } queue std bandwidth 95% cbq(default red) queue http bandwidth 10% cbq(borrow red) # puis parmis vos autres règles pass in quick on fxp0 from any to any port 80,8080 queue http block in quick on fxp0 all queue default ------------------------------------ SNiP ------------------------------------- Pour toutes les autres options que 'altq on' ou 'queue' que nous n'avons pas abordé, reportez-vous à la documentation OpenBSD [FAQPF] ou aux manpages. Cisco enfin utilise une légère variante de RED nommée WRED [CONAV][CBWRD]. Le W, pour weighted, signifie que l'algorithme utilisé par IOS intègre d'autres éléments dans la décision de marquer ou non un paquet. En l'occurrence, WRED tient compte des valeurs des champs IP Precedence pour IPv4 ou DiffServ code point pour IPv6 (DiffServ étant depuis devenu le modèle de classification de trafic unique à toutes les versions d'IP) permettant d'attribuer des priorités ou des ordres spécifiques de traitement représentés dans WRED par des probabilités de marquage différentes. WRED est désactivé par défaut bien que présent depuis IOS 11.1. Pour l'activer [WRED], vous devez utiliser la séquence suivante : ------------------------------------ SNiP ------------------------------------- policy-map class bandwidth percent 100 random-detect 5 20 0.0026 ------------------------------------ SNiP ------------------------------------- Cette dernière commande active effectivement WRED cependant vous avez la possibilité de paramètrer certaines valeurs : random-detect [dscp-based | prec-based] - dscp-based ou prec-based indique de se baser sur les champs DSCP ou IP Precedence (choix par défaut) avec éventuellement leurs valeurs - min_threshold, max_threshold et mark_probability permettent de spécifier les valeurs de ces variables avec la même signification que pour RED. Vous pouvez donc suivre les mêmes recommandations. Pous finir, nous appliquons la configuration choisie à nos interfaces : router(config)#interface ethernet 0 router(config-if)#service-policy output A la suite de RED, les recherches dans le domaine de l'AQM se sont multipliées s'orientant au choix vers des perfectionnements de RED ou bien des mécanismes totalement nouveaux et innovants. Nous étudierons brièvement un algorithme de chacune des 2 catégories digne d'intérêt : Adaptive RED et Random Exponential Marking (REM). Adaptive RED est de conception assez récente puisque son article de référence [FLO+01] date de 2001. Il compte parmis ses auteurs Sally Floyd, Ramakrishna Gummadi et Scott Schenker. Ils ont pu noté qu'un problème majeur du RED original était sa forte sensibilité aux paramètres fixes ainsi qu'à l'intensité de la congestion. Il est ainsi fait remarqué qu'un congestion faible et une configuration favorisant une incrémentation de Pmax lente mène à une AVG proche de minth, tandis qu'une congestion forte et une configuration tendant à une incrémentation rapide de Pmax pousse la AVG vers maxth ou plus, comme par exemple en mode Gentle. A cela, les concepteurs d'Adaptive RED ont répondu en apportant à RED la capacité d'adapter ses paramètres à la charge, en particulier Pmax et w, déjà décrit plus haut. W, le coefficient de pondération de la queue qui, dans les exemples de configuration précédents prenait des valeurs de l'ordre de 0.002, est, dans le nouvel algorithme, choisi en fonction de la célérité du lien. Ceci s'explique par l'importance de w dans le calcul de AVG. Ainsi, diminuer w à mesure que la vitesse du lien augmente (et inversement) permet d'améliorer succinctement les performances de RED en faisant intervenir de petits multiples du RTT au lieu de fractions. Mais la principale mesure développée par les 3 auteurs, réside dans le paramétrage automatique et dynamique de la variable Pmax. Désormais, RED tente de conserver AVG dans un intervalle à mi-chemin entre les seuils minth et maxth, ce qui correspond à des valeurs allant de 0.01 à 0.5, permettant de limiter AVG à un facteur connu de Pmax et donc l'AVG désirée (dite cible). L'algorithme Adaptive RED va ensuite adapter Pmax. Pour ce faire, le mode d'incrémentation et de décrémentation de Pmax est profondément modifié. L'ancienne formule était basée sur le principe du MIMD (multiplicative-increase and decrease), tandis qu'elle est remplacée dans l'évolution de RED par une AIMD (addtitive-increase and multiplicative-decrease). Ci-dessous, vous trouverez le pseudo-code issue du nouveau calcul de Pmax. ------------------------------------ SNiP ------------------------------------- Every interval seconds : if (avg > target and Pmax =< 0.5) increase Pmax by Pmax + alpha elseif (avg < target and Pmax >= 0.01) decrease Pmax by Pmax * beta Paramètres fixes : interval : durée entre chaque itération, fixé à 0.5 secondes target : taille ciblée pour AVG = [minth + 0.4 * (maxth - minth),minth + 0.6 * (maxth - minth)] alpha : incrément = min(0.01,Pmax/4) beta : coefficient de décrémentation = 0.9 Pseudo-code de l'algorithme Adaptive RED Reproduction de la figure 10 de [FLO+01] ------------------------------------ SNiP ------------------------------------- Nous voyons apparaître de nouvelles variables : alpha et beta. Comme brièvement expliqué dans le pseudo-code, alpha est le terme utilisé pour l'incrémentation par addition, et beta est le coefficient utilisé pour la décrémentation par multiplication. Notez que l'AIMD permet de remarquer une nouvelle caractéristique liée à Adaptive RED (encore une !) : sa nature plus "lente" que l'algorithme RED original. Le paramétrage dynamique s'effectue en effet sur des intervalles de temps bien plus grand qu'un RTT (ici 0.5 secondes). L'idée est de rendre RED plus robuste et plus prévisible. Il est donc important d'éviter les fortes oscillations de AVG créées par l'ancienne formule trop sensible. Cependant, pour limiter le coût d'une réactivité insuffisante aux congestions instantanées, la durée entre chaque adaptation de Pmax permet de conserver le même comportement réactif que RED sur des périodes intermédiaires. Pour plus d'informations sur Adaptive RED - et en particulier des explications précises motivant les choix de l'intervalle cible pour Pmax, ainsi que les valeurs des nouvelles variables alpha et beta - reportez-vous à [FLO+01]. Pour le second algorithme d'exemple, nous avons choisi REM, présenté à l'intérêt de la communauté début 2001. Cet algorithme offre l'intérêt de compter plusieurs similarités avec RED tout développant un principe de fonctionnement rigoureusement différent - comme ses auteurs le soulignent d'ailleurs abondemment en [REM01]. Nous pourrons de cette manière décrire plus rapidement l'algorithme en le comparant. En effet, le point le plus innovant dans l'algorithme REM peut s'exprimer par une franche démarcation vis-à-vis de RED. Les auteurs de REM affirment avoir, contrairement aux algorithmes de la famille RED, être parvenus à différencier la mesure de la congestion de celle des performances. RED peut se baser sur la longueur des files pour déterminer sa probabilité de marquage mais seulement au coût de voir AVG augmenter proportionnellement à celui du nombre d'utilisateurs sur le réseau. C'est là que se trouve la motivation primordiale des limites minth et maxth qui permettent d'encadrer cette propriété. A l'opposé, même si REM assume également que la congestion varie selon le nombre d'utilisateurs, l'algorithme tente de stabiliser les caractéristiques de performances que sont les pertes et la longue de file autour d'une cible prédéfinie. En faisant coller au plus près les débits des utilisateurs et la capacité du réseau, tout en restant proche de la cible pour AVG, REM permet d'atteindre à la fois une forte utilisation et de faibles délais. Notez que c'était également le but revendiqué par les chercheurs à l'origine d'Adaptive RED. Afin d'y parvenir, il a été nécessaire de changer quelque peu le paradigme. REM ajoute donc un certain niveau d'abstraction en définissant, pour chaque queue, des "prix" permettant de déterminer une probabilité de marquage. Les modifications apportées aux prix dépendent de "mismatch", c'est-à-dire tout simplement de différences, entre le débit d'entrée et la capacité réseau d'un côté, et la longueur de queue et sa cible de l'autre. Un prix est alors incrémenté si la somme pondérée des différences est positive, et inversement. Innovant à plus d'un titre, REM est cependant d'hors et déjà un algorithme mature théoriquement puisqu'il se base beaucoup sur les nombreux travaux effectués autour de l'algorithme RED. Il peut par exemple d'hors et déjà assurer le même résultat que la technologie ECN grâce à la notion de "somme des prix" qui permet d'obtenir, à travers le marquage, une mesure précise de la congestion sur la totalité d'un chemin. D'autre part, les simulations présentées par les auteurs indiquent des améliorations signifiantes des performances - en particulier un meilleur débit - mais, plus surprenant, en conservant une AVG très basse malgré une augmentation du nombre d'utilisateurs. En dépit de toutes ces qualités, aucune implémentation n'est en vue au moment de la rédaction. Quel est l'intérêt d'avoir passé en revue aussi exhaustivement les algorithmes de gestion de queue ? Ceux-ci participent certes d'une réduction de la congestion du réseau, et cette congestion peut très bien avoir pour origine une attaque de type Denial-of-Service. Tous ces algorithmes assument cependant que les flux corrigés seront coopératifs, et prendront en compte les indications données par la perte de données. Un DoS est pourtant loin d'être coopératif, au contraire. L'intérêt de RED et ses dérivés résident dans la détection et son apport dans la prévention des DoS. Sans capacité à informer automatiquement l'infrastructure qu'une congestion est en cours, et dans quelle magnitude, il est totalement impossible d'envisager la moindre mesure réactive de protection. La partie intéressante des mécanismes d'AQM dans la lutte contre les DoS tient donc dans la source d'informations qu'ils représentent. 3.2. ECN L'Explicit Congestion Notification (ECN) est une addition à la pile TCP/IP conçue en 1994 par Sally Floyd [ECN] et standardisée en septembre 2001 par l'IETF dans la RFC 3168 [3168]. C'est un autre mécanisme d'AQM permettant aux routeurs d'avertir les extrémités d'une connexion de congestion sur le chemin. Elle se place ainsi au même rang que RED qui prévient les hôtes en rejetant des paquets dont la perte déclenchera les mécanismes de congestion TCP comme décrit à la section précédente. ECN utilise une autre méthode qui consiste à placer, dans les entêtes IP et TCP des paquets subissant une congestion, un codepoint l'indiquant. ECN réduit ainsi l'impact des pertes sur des flux sensibles à la latence ; et en tant qu'exact remplacement du rejet de paquets, il évite le traitement injuste et facilite son déploiement progressif. ECN a en effet été développé pour coexister avec RED et se déployer au fur et à mesure, mais aussi pour résoudre les problèmes de congestion avec le routage asymétrique (upstream et downstream prenant des chemins différents), et être appliqué suite à une congestion persistante plutôt qu'instantanée, c'est-à-dire dénotée par une augmentation prolongée de la taille de queue au niveau du routeur. ECN constitue donc 2 ajouts distincts, l'un à l'entête IP et l'autre à TCP. Pour la première, il a été décidé de placer ECN dans l'en-tête régulière et non dans les options IP pour éviter les mauvaises interprétations par certains routeurs. L'ajout consiste en 2 bits représentant 4 codepoints : 00 ou Not-ECT indiquant que le paquet ne supporte pas ECN, 01 et 10 traités de la même manière et signifiant ECN-Capable Transport ou ECT (voir la RFC 3168 sections 20.2 et 21 pour justification), et enfin 11 pour Congestion Experienced (CE) placé par un routeur sur un paquet au lieu de le rejeter pour informer d'une congestion. Ces codepoints ont été ajouté à la place des 6 et 7ème bits inutilisés des champs IPv4 Type of Service et IPv6 Traffic Class, englobés sous l'appellation Differentiated Services Codepoint comme décrit dans les RFC 2472 et 2780. Comme nous parlons ici d'IP, ECN doit supporter d'une manière ou d'un autre les transformations que représentent la fragmentation ou l'encapsulation. Pour cette première transformation, si un fragment IP inspecté est marqué ECT, le routeur place le codepoint CE sur le paquet réassemblé, mais si l'un des fragments est Not-ECT, alors le paquet réassemblé est marqué Not-ECT. Sinon le paquet réassemblé peut être rejeté. Le support de l'encapsulation (notamment IPSec) est plus complexe puisqu'il propose 2 politiques, limited functionnality option et full functionnality option. La première spécifie de placer le codepoint Not-ECT sur l'entête IP externe et de laisser l'entête encapsulée intouchée. La seconde méthode précise de sélectionner le champ ECN de l'entête externe en fonction de l'entête encapsulée : lors d'un décapsulation, si le codepoint CE est placé sur l'entête externe, et que l'entête encapsulée est ECT, alors le condepoint CE est copié sur l'entête encapsulée ; lors l'encapsulation les bits ECN sont copiés dans l'entête externe excepté si c'est le codepoint CE. Pour IPSec plus particulièrement, il a également été ajouté un nouvel attribut de SA (association de sécurité déterminant les règles d'application du tunnel) appelé ECN Tunnel avec pour valeur allowed ou forbidden. Plus d'informations sur cet attribut optionnel dans la RFC 2401. Lorsque l'hôte TCP reçoit un paquet IP marqué Congestion Experienced, le système doit déclencher rigoureusement les mêmes mécanismes de contrôle de congestion qu'en cas de perte de paquets. ECN assume donc que la source (qui corrigera la congestion) utilise les algorithmes Slow Start, Fast Retransmit et Fast Recovery décrit dans la RFC 2581. De plus pour éviter de bloquer totalement une transmission, il ne peut y avoir qu'une seule réduction de la congestion window (cwnd) par window TCP (déterminant la quantité de données envoyée par un hôte TCP). Maintenant il faut se souvenir que la congestion est engendrée par la source du paquet qui a été marqué CE par un routeur sur le chemin. Cette source n'est donc pas encore informée de la congestion et ne peut pas encore activer ses mécanismes de contrôle. Pour permettre l'échange d'information, ECN ajoute 2 flags à l'entête TCP dans le champ réservé entre header length et les flags TCP classiques. Ces flags sont ECE-Echo (ECE) placé par le récepteur d'un paquet CE sur chaque ACK afin de notifier la congestion et de demander une réaction (consistant à une réduction de la fenêtre de congestion via l'algorithme Van Jacobson Congestion Avoidance), et Congestion Window Reduced (CWR) envoyé par la source après la réception d'un segment ECE pour indiquer d'arrêter de placer le flag ECE. Pour tous ces flags, il existe une phase de négociation similaire à un 3 way handshake, appelée TCP ECN negociation qui peut être effectuée à tout moment dans une transmission. Tant qu'elle n'est pas complète, aucun paquet muni du codepoint ECT ne peut être envoyé. Elle consiste à l'envoi d'un segment ECN-setup SYN dans lequel les flags ECE et CWR sont activés indiquant que cet hôte est ECT. En réponse à ce paquet, un segment ECN-setup SYN-ACK est envoyé ne comportant que le flag ECE, indiquant que cet hôte est également ECT. La réponse est asymétrique afin d'éviter le phénomène d'écho systématique des bits réservés (désormais flags ECN) reçus, constaté sur certaines implémentations TCP/IP [PROB]. Pour en finir avec les additions à TCP, il faut préciser quelques cas spéciaux. Ainsi les segments ACK purs ne comportant aucune donnée sont marqués Not-ECT car TCP ne possède aucun mécanisme capable d'éviter la congestion sans données à réduire. Le codepoint ECT est également prohibé des segments retransmis, assumant que l'algorithme Fast Retransmit corrige déjà la congestion. Ceci évite aussi des risques de DoS basé sur l'incompréhension du codepoint CE pour des paquets out-of-window avec la question de savoir si oui ou non on doit envoyer un ECN-Echo en cas de ACK dupliqué ? Enfin, lors des window probes (déclenchés par la source suite à une window du receveur annoncée à 0), le codepoint ECT et le flag CWR sont également interdits, puisque leur perte n'est pas détectée en temps normal comme un signe de congestion et qu'ils transportent peu de données (motivation similaire aux segments retransmis). Pour résumer, ECN utilise les flags ECT et CE dans l'entête IP pour que les routeurs signalent la congestion aux extrémités de la connexion, et les flags ECE et CWR dans l'entête TCP pour signaler la congestion entre hôtes TCP. ECN bien que standardisé récemment est déjà implémenté sur une vaste liste de plateforme même si il ne représente pas encore une part important des mécanismes d'AQM face à RED et ses variantes. Sous Linux, le support est complet depuis le passage à la série 2.4. Il vous faudra d'abord activer l'option CONFIG_INET_ECN lors de la configuration de votre kernel, puis entrer la commande suivante : # echo "1" > /proc/sys/net/ipv4/tcp_ecn Ceci active le support client. Pour utiliser Linux en tant que routeur ECN-capable, il sera nécessaire d'utiliser la qdisc 'red' fourni par iproute2, lequel dispose d'un mot-clé 'ecn' pour activer le marquage des paquets avec les bits ECN. Sous FreeBSD, le support ECN est divisé en 3 partie : le marquage des paquets en tant que routeur, les mécanismes TCP de réaction en tant que client, et les règles de transformations pour tout type d'hôte. Ces fonctionnalités sont disponibles, via ALTQ - partie intégrante de la pile KAME - depuis FreeBSD 2.2.5, mais a été souvent réécrit et plus particulièrement début 2002. Pour activer le support ECN, il faut d'abord placer l'option TCP_ECN dans votre fichier de configuration kernel, puis une fois la recompilation terminée, il suffit de paramétrer votre MIB sysctl pour activer le support client : # sysctl -w net.inet.tcp.ecn=1 Le support routeur se fait à travers la configuration de ALTQ, simplement en ajoutant à votre configuration par interface le keyword ecn comme ci-dessous : interface [ifname] bandwidth [bwsize] red ecn Pour la configuration spécifique d'OpenBSD, il s'agira simplement d'ajouter l'option ecn à la discipline choisie dans le mot-clé 'queue'. Cette option implique automatiquement l'activation de RED. Enfin pour les matériels Cisco, ECN existe par défaut depuis IOS 12.2 via le support de la discipline Weighted RED (WRED, une variante de RED avec des queues par classe de trafic) [WRDECN]. Pour vérifier, rechercher la chaîne "explicit congestion notification" après avoir exécuté la commande suivante : router#show policy-map Dans le cas contraire, pour l'activer, il vous suffira d'appliquer le script ci-dessous déjà rencontré en partie dans la section 3.1. ------------------------------------ SNiP ------------------------------------- policy-map policy_map_name ! définition de notre classe class class_default ! pourcentage de bande passante pour cette classe bandwidth percent 90 ! active WRED puis ECN random-detect random-detect ecn ------------------------------------ SNiP ------------------------------------- Il vous reste ensuite à appliquer cette politique pour vos interfaces via la séquence ci-dessous : router(config)#interface ethernet 0 router(config-if)#service-policy out policy_map_name Comme nous l'avons éxpliqué à la fin de la section 3.1, les mécanismes d'AQM RED et ECN présente surtout un intérêt pour les capacités de détection statistique de la congestion offertes. Mais ECN est en réalité une exploitation du mécanisme de détection de congestion que représente RED. L'intérêt de le citer est donc de montrer un exemple d'application de RED à la réduction de la congestion et de la consommation de la bande passante. Il existe un autre intérêt plus concret. En ne s'appliquant qu'aux flux coopératifs, on pourrait penser que le couple RED/ECN n'aura que peu de prise sur le trafic généré par un DDoS. Cependant, en adaptant les flux coopératifs à la congestion importante détectée lors d'un DDoS, RED/ECN permet de limiter l'effet négatifs des flux légitimes lors d'un DDoS, tout en évitant à ce dernier de supprimer totalement ces mêmes flux légitimes. Nous voyons donc que RED/ECN apportent également sa pierre à la conservation de la qualité et de la continuité du service. Nous verrons, dans la suite de ce document, d'autres méthodes tirant parti des mêmes informations qu'ECN et les combinant à des instruments de lutte contre les DoS plus efficaces, tel le rate-limiting. 3.3. CAR Si les disciplines d'AQM sont les plus avancées en ce qui concerne la réduction de la congestion, il est des mécanismes beaucoup plus simples mais dont les effets contre les DDoS se sont montrés, experimentalement, extrêmement efficaces. C'est le cas de plusieurs méthodes permettant limiter le débit ou les rafales de paquets (bursts, inhérents au fonctionnement par paquets), et même de prendre des mesures contre les flux qui s'aviseraient de contourner ces limites. Ces techniques, appelées CAR pour Committed Access Rate chez Cisco, sont certes moins élégantes et perfectionnées que l'AQM, mais elles peuvent offrir une première ligne de défense vis-à-vis de l'extérieur et, notamment par l'élimination des bursts, protéger les queues sur lesquelles opèrent les algorithmes d'AQM. La première de ces commandes est 'police', apparue à partir de IOS 12.1(1)E, qui permet de limiter les bursts d'une classe de trafic, signes éventuellement annonciateurs du début d'une attaque massive. La formule permettant de caractériser une telle rafale est simple : (T - T1 * avg_rate / 8) où T1 et T sont les temps d'arrivée respectifs de deux paquets successifs et avg_rate le débit moyen du lien en bit par secondes. La division par 8 permet alors de parler en octets. Limiter les bursts consiste ensuite à compter les octets par rapport aux limites de conformité, d'excès et de violation, suivant quelques règles décrites abondemment, exemples à l'appui, en [QRF]. Le modèle final de la commande police est tel que ci-dessous : police conform-action exceed-action [violate-action ] En premier lieu, nous spécifions ce fameux débit en bps, puis la quantité normale et maximale d'un burst en octets. Si aucun burst n'est constaté, le système agit selon l'ordre spécifiée par conform-action, puis exceed-action si il y a dépassement de la limite normale, et enfin, optionellement, violate-action si la limite maximale est aussi dépassée. Les actions à votre disposition sont transmit, drop, et set-prec-transmit, set-qos-transmit ou set-dscp-transmit pour paramétrer une valeur d'IP Precedence, de QoS ou de DiffServ CodePoint pour par exemple signifier aux routeurs suivant un traitement particulier de ces paquets. Vous pourriez même imaginez, afin de favoriser au mieux les hôtes coopératifs, un système de bonus/malus en utilisant conform-action pour élever la priorité des paquets et violate-action pour la diminuer. Ci-dessous un exemple d'application pour un débit théorique de 10Mbps. ------------------------------------ SNiP ------------------------------------- policy-map class bandwidth percent 98 ! 8mbps with 8.5/normal and 9/max in burst police 8388608 8704 9216 conform-action transmit exceed-action set-dscp-transmit 1 violate-action drop ! appliquer police à une interface interface ethernet 0 service-policy input ------------------------------------ SNiP ------------------------------------- Comme 'police' est une commande disponible au sein d'une classe de trafic, il est possible d'utiliser les différents "match criterion" proposés par cette structure. Par exemple, nous pourrions restreindre le champ d'application de la limitation de débit en spécifiant une ou plusieurs ACL, à travers leur numéro de groupe, qui agiront alors comme classificateur de trafic pour police. Dans l'exemple suivant, nous limitons le trafic HTTP vers nos serveurs, afin de prévenir un DDoS contre ceux-ci, en utilisant des critères de classification. La même méthodologie peut être suivie pour protéger les sessions BGP entre peers lors d'une attaque, le protocole BGP fonctionnant sur le port tcp/149. ------------------------------------ SNiP ------------------------------------- no access-list 911 access-list 911 permit ip any 80 log interface ethernet 0 ip access-group 911 in class-map our-webservers match access-group 911 policy-map behave-http class our-webservers bandwidth percent 20 ! 1.5mbps with 1.65/normal and 1.85/max in burst police 1572864 1690 1895 conform-action transmit exceed-action set-qos-transmit 1 violate-action drop interface ethernet 1 service-policy input behave-http ------------------------------------ SNiP ------------------------------------- Nous disposons d'une seconde commande, combinant limitation du débit à celle des rafales de paquets. Mais surtout, 'rate-limit', qu'on trouve sur IOS depuis la release 11.1CC, s'applique par interface au lieu de s'appliquer à une classe de trafic. Tout comme police, elle offre des possibilités très intéressantes d'interaction avec les ACL pour ce qui est de la classification du trafic. Notez toutefois que cette nouvelle commande nécessite l'activation du Cisco Express Forwarding, comme RPF. Le squelette de cette commande est comme suit : rate-limit {input | output} [access-group [rate-limit] ] conform-action exceed-action Vous ne devriez pas être trop dépaysé puisque input/output ont toujours le même sens depuis les ACL, tout comme access-group. Les options suivantes ont également le même sens que pour la commande police. Seules les actions changent légèrement puisque en plus des {set-*-}transmit et de drop, nous disposons maintenant de {set-*-}continue pour évaluer le paquet par rapport à la règle rate-limit suivante. De même, les set-* voient arriver le support du champ "experimental" de MPLS. Il ne reste plus alors qu'à suivre le modèle comme dans le fichier de configuration suivant. ------------------------------------ SNiP ------------------------------------- ip cef no access-list 102 access-list 102 permit ip any any interface ethernet 0 ip access group 102 in rate-limit input access-group 102 8388608 8704 9216 conform-action transmit exceed-action drop ------------------------------------ SNiP ------------------------------------- Dans notre exemple, la règle rate-limit s'applique au trafic défini par l'EACL, c'est-à-dire tout trafic IP. Mais vous pouvez spécifier des règles pour différents types de trafic, la classification de paquets étant effectuée par les ACL. Notez d'autre part qu'il existe un type particulier d'access-group, dit rate-limit, dont le squelette est ci-dessous : access-list rate-limit {precedence | mac-address | exp mask } Ces ACL d'un genre particulier se basent uniquement sur les valeurs d'IP Precedence ou de forwarding classes MPLS, et d'adresses MAC. L'effet majeur est de reporter l'étape de classification du trafic indépendante du routeur, en utilisant uniquement des informations liées au QoS ou aux interfaces adjacentes. Comme toutes les ACL, celles-ci sont à effectuer en configuration globale. La documentation complète des commandes rate-limit ainsi que plusieurs exemples intéressants, comme la configuration de la limitation de débit entre ISP dans un IXP, est disponible auprès de Cisco [CAR]. Malgré la prépondérance de Cisco, il ne faudrait pas penser pour autant que les systèmes libres sont à la traîne. Revenons un instant sur ALTQ, le framework de traffic shaping des systèmes *BSD, déjà évoqué. Son principal intérêt, dans notre optique d'interopérabilité, réside dans ses points communs avec les méthodes proposées par Cisco. Il existe, en effet, une manière de limiter le trafic assez similaire à 'rate-limit' en cela qu'elle s'applique par interface. A vrai dire, il est même possible de limiter la bande passante d'une classe de trafic, mais cette méthode nécessite l'emploi d'une discipline de queueing, CBQ. Or, CBQ ne peut pas être aussi efficace pour le rate-limiting du fait même de son design qui assume que le débit est contraint par la vitesse du lien et ne peut aller au-delà. Pour parvenir à restreindre le débit sur une interface, ALTQ s'appuie sur une structure interne appelée token-bucket regulator (TBR) dont le sujet est de réguler et contrôler le comportement d'un driver de carte réseau. Plus précisément, un TBR permet de contrôler la quantité de paquets qu'un driver peut faire sortir d'une queue. Un TBR est donc caractérisé par un 'token rate' et une 'bucket size' qui déterminent respectivement la vitesse à laquelle le bucket du TBR se remplit et jusqu'à quelle quantité. La taille des paquets déterminant la quantité de tokens (jetons) dans le bucket (seau), les paquets peuvent alors quitter leur queue tant que cette quantité est positive. Si cette quantité devient négative, indiquant une disparité entre la vitesse à laquelle les paquets se présentent et celle à laquelle les tokens remplissent le bucket, les premiers seront retenus jusqu'à ce que la quantité redevienne positive, entraînant un délai qui ménera éventuellement au rejet. Concrétement, en sélectionnant un certain token rate, on impose une limite supérieure au trafic, limitant ainsi le débit sur une interface. D'autre part, lorsque la quantité de tokens est toujours positive mais qu'il ne reste plus de paquets à envoyer - signifiant que le débit du trafic est plus faible que celui des tokens - le prochain cycle d'horloge créera un burst de faible taille. Par conséquent,la taille des rafales de paquets dependent directement de la bucket size, ainsi que de la fréquence d'horloge du kernel. Cette dernière contrôle la fréquence à laquelle les événements kernel sont générés et traités, par exemple les interruptions. Ainsi, avec des débits élevés, les queues de paquets se remplissent plus vite et, pour limiter les pertes et réduire la taille des bursts, nous sommes contraints d'utiliser une fréquence d'horloge plus élevée. Sous FreeBSD, OpenBSD et NetBSD (sur certaines architectures seulement pour ce dernier), il suffira d'ajouter la ligne suivante à sa configuration kernel pour utiliser une fréquence de 1 kHz. options HZ=1000 La complexité intervient au moment du calcul des valeurs à attribuer au token rate et à la bucket size. Pour tenter d'approcher le meilleur débit possible, il est logique d'adopter pour le token rate le débit maximum de l'interface. Une valeur trop faible entraînerait des délais puisque le kernel serait paré à transmettre (via une interruption système) alors que le bucket n'est toujours pas rempli et que le TBR empêche donc la sortie des paquets. D'un autre côté, une valeurs trop élévée causerait une désynchronisation entre la queue à vider et l'interruption, cette dernière portant alors sur la queue de paquets suivante. La variable d'ajustement du TBR sera donc la bucket size, qui devra être déterminée en fonction de l'intervalle entre deux interruptions. La formule de calcul de la bucket size est finalement assez simple : desired_rate(en bps) / 8 / HZ. Les auteurs d'ALTQ la considère même conservatrice puisqu'elle ne tient compte que des interruptions kernel, sans envisager d'éventuels événements kernel imprévus diminuant la latence. On obtient ainsi finalement un délai quasi-minimal pour un débit donné. Il ne nous reste plus qu'à exploiter cette propriété en faisant croire à ALTQ que le débit maximal de l'interface, équivalent au token rate, vaut le débit limité que nous désirons. Nous utiliserons pour la configuration l'outil tbrconfig(8) de la manière suivante : # tbrconfig { | auto} 'Token rate' est bien sûr à remplacer par votre limite de débit. Pour éviter de calculer la bucket size, utilisez l'option auto qui applique la formule décrite plus haut. Le caractère conservateur de celle-ci vous permet d'ajuster ensuite la valeur de la bucket size par expérimentation. Vous pouvez par exemple obtenir des données statistiques intéressantes avec altqstat(1). Pour supprimer un TBR, tapez simplement : # tbrconfig -d Maintenant si vous voulez rendre cette configuration permanente, il suffit d'ajouter la ligne suivante au fichier /etc/altq.conf. interface bandwidth tbrsize Si vous disposez d'or et déjà d'une configuration en place sur une interface, cela a créé un TBR qui ne pourra pas être supprimé sans décharger/recharger ALTQ s'il fonctionne en KLD, ou la machine autrement. Des explications détaillées sur les mécanismes internes d'ALTQ sont disponibles en [TIPS]. Le développement d'ALTQ se fait désormais au sein de PF, ce qui en limite la portée. Heureusement, le grand enthousiasme entourant PF a fait naître des initiatives en vu de son port vers NetBSD et FreeBSD, et l'intégration dans ces deux systèmes est à l'ordre du jour. Pour effectuer des opérations similaires à partir du kernel 2.2.x, Linux dispose de iproute2. Parmis de nombreuses autres fonctionnalités, iproute2 [IPR2] offre les mêmes services que ALTQ pour ce qui est du queueing et du traffic shaping. Ce domaine spécifique est appelé 'Traffic Control' sous Linux, et se commande à travers la commande 'tc'. Il faudra d'abord vous assurer de la présence des options suivantes dans votre kernel, et au besoin en recompiler un avec leur support. CONFIG_NET_SCHED=y CONFIG_NET_SCH_TBF=y CONFIG_NET_SCH_INGRESS=y CONFIG_NET_QOS=y CONFIG_NET_ESTIMATOR=y CONFIG_NET_CLS=y CONFIG_NET_CLS_POLICE=y CONFIG_NETLINK=y La syntaxe de 'tc' propose 3 options principales : qdisc, class et filter. La première - que nous avons déjà évoqué en étudiant RED - permet d'installer, sur un périphérique réseau, une discipline de queueing. Les qdisc sont arrangées hiérarchiquement et peuvent donc fournir des classes, comme CBQ ou HTB, ou bien être constituées d'un noeud unique. comme RED ou token-bucket filter (TBF). Pour les premières, les classes subséquentes seront configurées grâce à l'option class. Enfin, avec l'option filter, tc est capable d'identifier à quel type de trafic attacher telle ou telle qdisc. Les classes et les filtres nécessitent donc la présence de qdisc correspondantes tandis que ces dernières peuvent exister indépendamment. Pour limiter le débit sur une interface ou une partie de son trafic, nous nous intéresserons en particulier et tour à tour à une qdisc, TBF, et un type de filtre, les policing filters. Le principe de fonctionnement d'un token-bucket filter est exactement le même que celui des token bucket regulator présents dans ALTQ. A savoir, lorsque l'arrivée des paquets se fait au même rythme que le remplissage du bucket par les tokens, ni délai ni perte ne sont introduits tandis que, si le débit du trafic est lent, des bursts apparaîtront et enfin, si le débit du trafic est plus rapide, les paquets seront retardés puis rejetés. Plusieurs paramètres sont disponibles lors de la définition de votre TBF. On trouve ainsi 'limit' indiquant le nombre maximal d'octets qui peuvent être retardés dans la queue. Cette option peut être remplacée par 'latency' désignant alors le délai maximal pendant lequel un paquet peut être retenu dans la queue. 'burst' permet ensuite de préciser la taille du bucket en octets. La formule proposée par ALTQ peut également s'appliquer ici. Pour finir, 'rate', précise le token rate, c'est-à-dire le débit auquel nous voulons limiter le trafic. Notre exemple final pourrait alors ressembler à la ligne suivante, assumant une limitation de débit à 500 kb/s, un délai de 50ms entre chaque paquet au-delà, et une bucket size, par calcul, de 640 octets. # tc qdisc add dev root tbf rate 512kbit latency 40ms burst 655b Une explication plus complète de l'implémentation Linux ainsi que le jeu complet des options disponibles se trouvent dans le Linux Advanced Routing & Traffic Control Howto (LARTC) [TBF]. La seconde solution à notre disposition est d'utiliser les policing filters. Avec n'importe quelle qdisc, vous pouvez appliquer un filtre auquel vous adjoindrez le mot-clé 'police'. L'intérêt pour nous est que celui-ci inclut sa propre implémentation d'un TBF, mais en y ajoutant la possibilité de prendre des mesures vis-à-vis du trafic dépassant la limite imposée. Ces actions peuvent être 'pass' pour laisser passer un paquet ou 'drop' pour le rejeter dans le cas où le débit dépasserait la limite fixée par le TBR. Notez que l'implémentation du TBR dans les policing filters a entraîné une modification de son design : il ne peut désormais plus retenir les paquets, oblitérant du coup les mot-clés limit et latency, et se contente de les laisser passer ou de les rejeter. Pour appliquer un tel filtre, il va falloir l'attacher à une qdisc. Si vous ne souhaitez n'installer que cette configuration, ou encore séparer le rate limiting du reste de la configuration, ou même n'avait l'intention d'appliquer cette limitation que sur une partie du trafic, vous utiliserez la qdisc fifo (qui est la discipline par défaut) ou encore la qdisc ingress, qui s'applique en entrée d'une interface au lieu de la sortie. Il en résultera les lignes suivantes : # tc qdisc add dev root handle 1: # tc filter add dev parent 1: protocol ip \ police rate 512kbps burst 655b drop Ou, avec une qdisc ingress : # tc qdisc add dev root handle 1: ingress # tc filter add dev parent 1: protocol ip \ police rate 512kbps burst 655b drop Ici aussi, le LARTC peut s'avérer une lecture enrichissante pour appréhender toutes les finesses de cette configuration [POL]. Comme avec ALTQ, il semble logique d'augmenter la fréquence d'horloge du kernel afin d'améliorer les performances générales des discplines de queueing. Malheureusement, comparé aux *BSD, cette modification n'est pas aussi aisée sous Linux puisqu'il n'existe aucune option, dans la branche principale du kernel, la permettant. Il est nécessaire de modifier la macro HZ dans /sys/include/asm-{your-arch}/param.h où 'your-arch' désigne l'architecture de votre microprocesseur. Cependant, des patchs existent pour la branche 2.6.x du kernel, ajoutant une option CONFIG_HZ avec laquelle vous pourrez sélectionner la fréquence de votre choix. D'autre part, les kernels de la série 2.6.x font désormais une distinction entre HZ et USER_HZ. La première concerne le fonctionnement du kernel, et la seconde certaines interfaces utilisateur uniquement. L'intérêt est que la première macro a, depuis peu, pour valeur 1000 sur l'architecture x86, épargnant toutes modifications aux utilisateurs concernés. Encore une fois, le rate-limiting n'évite pas la congestion ni les DoS, mais cette technique permet de prendre des mesures préventives afin de réduire au maximum les risques de saturation de l'infrastructure réseau. Placer des limites en débit le long d'un chemin, ou au sein d'un réseau, permet d'éviter des problèmes dûs à la présence de goulots d'étranglement, tel qu'une augmentation excessive des rafales de paquets entraîner des délais et des pertes accrus en plus d'augmenter la charge du matériel d'infrastructure. Comme lors d'un DDoS on retrouve ces mêmes problèmes dû à la défaillance d'un ou plusieurs composant de l'infrastructure dès lors qu'on s'approche de la cible du DDoS, lutter contre des mêmes effets s'avère bénéfique. Ainsi, contraindre artificiellement le débit permet de contenir les effets d'une attaque par saturation. Enfin, il existe sur plusieurs systèmes des dispositifs spécifiques destinés à limiter la génération de paquets ICMP. Ces mesures permettent principalement de limiter l'effet reflecteur de l'une de vos passerelles lorsque une attaque de type smurf est lancée contre votre réseau. Le plus simple serait alors de supprimer purement et simplement tout ou partie des types ICMP, comme c'est le cas sous IOS depuis la version 12.0. Cependant, comme nous nous soucions de l'identification des auteurs de DoS, et que nous avons placés de nombreux systèmes de limitation ou filtrage du trafic, les messages ICMP nous sont indispensables pour détecter ou analyser une attaque, en particulier dans le cadre de l'utilisation de blackholes ou de sinkholes. Sous IOS, il faudra réactiver les messages ICMP unreachable de la manière suivante : router#ip unreachables Entrez alors la commande de rate-limiting de ces types de messages en spécifiant l'écart autorisé, en millisecondes, entre deux paquets : router#ip icmp rate-limit unreachable Typiquement, 5 millisecondes entre chaque paquets est une limitation suffisante pour un routeur, en supposant un taux de pertes relativement faible (moins de 10% sur un lien Fast Ethernet, en tirant partie d'une latence moyenne de 30 ms) et des applications ne nécessitant pas une trop grande réactivité. Sous FreeBSD, la limitation des paquets ICMP est seulement optionnelle. Il sera donc nécessaire, avant de pouvoir faire quoi que ce soit, d'ajouter à votre fichier de configuration kernel l'option ICMP_BANDLIM, disponible depuis la branche 4.x, puis de recompiler. Le paramétrage du débit des paquets ICMP s'effectue ensuite par l'intermédiaire de sysctl, en paquets par seconde. Pour arriver à un paquet toutes les 5 millisecondes, entrez la commande suivante : # sysctl -w net.inet.icmp.icmplim=200 Pour rendre la configuration permanente, rajouter la ligne ci-dessous au fichier /etc/sysctl.conf : net.inet.icmp.icmplim=200 Nous arrivons enfin à Linux, dont la configuration dans ce domaine est - oserons-nous dire "encore une fois" - pour le moins surprenante. La configuration que nous nous apprêtons à décrire date du kernel 2.4.17. A partir de cette version en effet, le rate limiting ICMP peut être déployé sous Linux à partir de deux variables situées dans /proc/sys/net/ipv4 : icmp_ratelimit et icmp_ratemask. La première entrée définit précisément le nombre de jiffies que le kernel doit laisser passer entre deux envois de messages ICMP. Le jiffy est l'unité de temps interne spécifique au kernel Linux, représentant 1/100ème de seconde sur la plupart des architectures à l'exception notable des Alpha et IA64 où un jiffy vaut 1/1024 de seconde. La justification de ces valeurs tient dans le mode de calcul de la seconde, sous Linux, qui vaut en réalité jiffies / HZ soit, dans le cas général, (1/100) / (1/100) = 1. Cette limitation semble rendre les configurations précédentes intransposables, excepté sur IA64 et Alpha. Nous pouvons au mieux obtenir un débit de 100 messages par seconde grâce à la limite suivante, qui s'avère être la valeur par défaut : # echo "1" > /proc/sys/net/ipv4/icmp_ratelimit Notez qu'une valeur de 0 à icmp_ratelimit indiquera au kernel de n'appliquer aucune limite (0 jiffies entre chaque message, donc aucun délai). Pour les plus déçus, faisons remarquer que le manque de précision provient d'une valeur inappropriée de HZ et que pour affiner notre limite, il suffira de modifier cette valeur, comme cela a été vu précédemment. Pour déterminer de quel type de messages ICMP il doit limiter le débit, le kernel Linux nécessite qu'on lui indique un ratemask, en réalité un OR logique des différents types que l'ont souhaite voir limiter. Concrétement, la méthode consiste à effectuer la somme de deux à chacune des puissances correspondant aux différents types que l'on souhaite restraindre. Pour y voir plus clair, commençons par rappeler ci-dessous les différents types ICMP en usage : Type | Signification ------------------------ 0 | Echo reply 3 | Destination unreachable 4 | Source quench 5 | Redirect 8 | Echo request 9 | Router advertisement 10 | Router solicitation 11 | Time exceeded 12 | Parameter problem 13 | Timestamp request 14 | Timestamp reply 15 | Information request 16 | Information reply 17 | Address mask request 18 | Address mask reply Les types concernés par le rate-limiting par défaut sont 'destination unreachable', 'source quench', 'time exceeded' et 'parameter problem'. Le ratemask obtenu est 6168 en décimal. Pour obtenir ce résultat, il suffit de prendre chacun des types concernés, c'est-à-dire 3, 4, 11 et 12. Puis on fait la somme de deux à ces puissances, soit ratemask = 2^3 + 2^4 + 2^11 + 2^12 = 6168. Si l'on souhaite ajouter les messages 'echo request' et 'echo reply', on ajoutera à cette somme 2^0 et 2^8, ce qui donne un ratemask final de 6425. Tous ces détails sont à portée de main dans /usr/src/linux/Documentation/network/ip-sysctl.txt ainsi que dans un howto très complet [FRO] abordant l'ensemble de l'arborescence /proc/sys/net/ipv4/. Pour clore ce chapitre concernant les limitations de débit, notons qu'il est possible d'activer de telles politiques à un niveau inférieur, c'est-à-dire au niveau des commutateurs eux-mêmes (niveau OSI 2). Plus particulièrement, les switchs Cisco Catalyst (qui sont en réalité des switch de niveau 3) offre la possibilité d'enclencher une suppression des broadcast/multicast [CAST]. Ce terme désigne en réalité n'importe quel type de trafic arrivant à un port et dépassant un certain seuil défini par l'administrateur. Cette définition correspond en tous points à un simple mécanisme de rate-limiting. De plus, comme elle se concentre sur le trafic broadcast/multicast, elle peut s'avérer particulièrement utile contre de large DDoS. Pour être précis, il existe deux méthodes d'inspection de ces seuils dans les Catalyst. Le principe est en réalité le même dans les deux cas : le switch surveille le nombre de paquets broadcast, distingués par leur adresse IP, entrant au niveau d'un port pendant une seconde. Si durant cette seconde, ce nombre dépasse un seuil préconfiguré, alors les paquets sont rejetés pour le reste de la seconde. Dans des réseaux au débit élevé subissant des bursts ou des DoS majeurs, cette base de une seconde s'avère largement suffisante. Il y a cependant quelques petites différences qui ont nécessité la distinction entre deux méthodes. La première, dite bandwidth-based, est une composante hardware qui ne peut appliquer de seuils que selon un pourcentage de bande passante alloué aux paquets broadcast, au-delà, tous les paquets sont rejetés, jusqu'à la seconde suivante. La seconde méthode, dite packet-based, est quant à elle software et consiste à littéralement compter le nombre de paquets broadcast par secondes en les rejetant tous jusqu'à la prochaine seconde si ce nombre dépasse un seuil prédéfini. Pour déterminer de quelle fonctionnalité vous disposez exactement, utilisez la commande 'show capabilities command'. La configuration proprement dite est relativement simple et similaire pour les deux méthodes. Il faudra à chaque fois entrer en mode privilégié en tapant 'enable' puis la commande 'set port broadcast' suivi du numéro du port concerné (ou d'un espace de ports) et enfin du seuil. Ce seuil est à inscrire en pourcentage pour la suppression bandwidth-based et en nombre de paquets pour la suppression packet-based. Le résultat est semblable à la ligne ci-dessous : Console> (enable) set port broadcast 1-8 15% ou Console> (enable) set port broadcast 1-8 500 Utilisez ensuite la commande 'show port broadcast' pour obtenir quelques statistiques sur la suppression, et 'clear port broadcast' pour supprimer une configuration. Ces deux commandes peuvent bien sûr être affinées par un numéro de port. L'intérêt de toutes ces techniques de rate-limiting, c'est de prévenir les DoS ciblés, qui ne consomment jamais la totalité de la bande passante. Même si cette façon de faire est nettement moins radicale que le bloquage des adresses sources, elle permet néanmoins de préserver une connectivité même lorsqu'une attaque est en cours et donc d'assurer une meilleure disponibilité. Notez cependant que limiter le débit demande bien plus de ressources que de simplement supprimer des paquets (en particulier chez Cisco). C'est un argument de plus en faveur d'une mise en oeuvre de manière ciblé sur des fractions de réseau (et non chez des ISP comme certains ont pu le suggérer). 3.4. ACC ACC [ACC] signifie Aggregate-based Congestion Control. Ce mécanisme fait parti d'une proposition soutenue par de fameux chercheurs du laboratoire ICIR comme Vern Paxson, concepteur de Bro et du concept de normalisation réseau, ou Sally Floyd, à l'origine de RED et ECN, mais aussi Steve Bellovin d'AT&T déjà derrière iTrace, ainsi que des sociétés comme Juniper Networks et Cisco. Il a enfin fait l'objet d'un draft IETF arrivé à expiration en janvier 2002. Le système ACC est en réalité divisé en 2 sous-systèmes : le Local ACC (LACC) et les messages pushback. LACC est une proposition de méthode de reconnaissance de congestion. Les routeurs surveillent le taux de rejet de paquets pour chaque queue afin de vérifier qu'il ne dépasse pas un seuil défini par l'administrateur et signe de congestion. Les intervalles de vérification devraient varier afin d'éviter les effets de la synchronisation des flux (due par exemple aux variations de window TCP au niveau d'une passerelle commune, à la synchronisation horaire via NTP, ou encore à l'architecture client/serveur entraînant la synchronisation de plusieurs clients en attente d'un serveur surchargé ou bloqué) et d'empêcher un attaquant de déterminer le schéma de détection de la congestion du LACC. Lorsque une congestion est détectée par un routeur, il tente de définir un agrégat, par exemple à partir de prefixes/adresses de destination/source, ou bien par type de trafic en considérant le protocole et le port. Le problème est qu'un attaquant peut changer continuellement de trafic pour évader cette agrégation. Contre cela, les auteurs d'ACC proposent de définir l'agrégat du trafic créant la situation de congestion à partir d'un échantillonnage de paquets obtenu depuis les rejets de mécanismes type RED, donc aléatoire. L'ACC assume que cet agrégat forme une signature de congestion pour un trafic donné. Mais contrairement aux signatures d'attaque d'IDS par exemple, les signatures de congestion ne donnent aucune précision quant au caractère bénin ou agressif du trafic agrégé. Cette caractéristique existe afin d'éluder le problème de l'inclusion, dans l'agrégat, de trafic légitime, concomitant à la forte montée en charge. ACC protège donc des DoS en protégeant de la congestion dans l'absolu. Les administrateurs doivent bien sûr pouvoir configurer le système pour qu'il épargne explicitement certains flux lors de la définition de l'agrégat ou bien qu'il leurs appliquent des limites spécifiques. Enfin, le routeur applique à chaque paquet coïncidant avec cette signature de congestion une limite de débit se traduisant par le placement dans une queue virtuelle. La limitation est automatique de sorte que le débit du trafic limité ajouté à celui des autres n'excède pas une limite définie par l'administrateur. En sus de ce mécanisme de limitation de congestion, ACC prévoit la possibilité pour un routeur ayant défini un agrégat de demander à tous les routeurs en amont (upstream) de limiter le trafic envoyé pour un agrégat donné, propageant ainsi l'agrégat le long du chemin à l'origine de la congestion. De plus comme ces messages passent de routeurs en routeurs suivant un arbre en transportant l'agrégat, ils peuvent éventuellement servir de traceback en cas de DoS spoofé. Le messages pushback sont utiles lorsque la signature de congestion n'est pas assez précise, et nécessite donc un meilleur échantillonnage. Si un trafic particulier entraîne la congestion, un pushback propagé permettra de savoir exactement quel trafic est envoyé vers le routeur victime. Ceci peut par exemple entraîner l'affinage du masque de sous réseau contenu dans une signature de congestion. Pour affiner une signature, le partage d'informations de routage sera à l'avenir nécessaire, amplifiant encore le caractère coopératif d'ACC. L'envoi de messages pushback peut aussi être originaire d'IDS ou firewall reconnaissant un trafic comme offensif (typiquement un DoS applicatif) bien que n'entraînant pas de congestion. Il existe plusieurs types de messages pushback mais tous partagent une entête commune composée du numéro de version du protocole pushback, de la famille d'adresse (v4 ou v6), du type de message (request, refresh, status et cancel), d'un numéro de session pushback unique au niveau du routeur d'origine, l'adresse IP de ce routeur et enfin l'adresse IP de provenance du message pushback. Ce dernier champ semble dupliquer l'adresse source contenue dans toute entête IP mais cette explicitation s'avère utile lorsque le paquet ne fait que passer d'une interface à une autre ou lorsque les routeurs ne sont pas directement connectés. Les 2 derniers champs cités sont bien sûr prêt pour IPv6 et font donc 128 bits. Avant d'approfondir les différents types de message, notez qu'invariablement la signature de congestion est un champ de longueur variable indiqué au format TLV (Type-Length-Value) dont pour le moment les seuls types autorisés sont SRC_PREFIX pour un agrégat basé sur l'adresse source et DST_PREFIX pour un agrégat basé sur l'adresse de destination. A l'avenir, il sera possible d'utiliser le champ IP protocol ou les numéros de port au layer 4. Il existe 4 types de messages pushback. Le premier, REQUEST, est envoyé à un routeur amont (upstream) en vue de limiter le débit d'un agrégat. Ses différents champs sont les suivant : - Ptype indique le type de pushback et donc le comportement du routeur le recevant. Ses valeurs sont pour le moment limitées à 3 valeurs, 0 ou HI_DROP_PROP pour propager l'agrégat si il entraîne un fort taux de rejet, 1 ou ALWAYS_DROP pour propager l'agrégat quelque soit le taux de rejet (c'est ce type qui devrait être employé par les IDS) et 2 ou DUMMY_DROP qui n'entraîne pas de limitation mais permet de s'informer du débit d'arrivée d'un agrégat en amont. - SRMode indique le mode de rapport des routeurs en amont après réception d'un pushback. Les valeurs sont 0 ou COMPACT ne nécessitent de renvoyer que le débit total (tout le long de la route) d'arrivée pour l'agrégat, 1 ou CLOSEST spécifiant aux routeurs en amont d'inclure le détail de chaque routeur ou du moins des plus proches en terme de hops, 2 ou FURTHEST est similaire à CLOSEST au détail près qu'il préfère les routeurs les plus éloignés, et SAMPLE demande de choisir les routeurs aléatoirement. Ces différentes méthodes donneront des informations intéressantes pour effectuer un semblant de traceback. - MaxDepth indique le nombre maximal de hops jusqu'auquel un message pushback sera propagé. Il existe 2 valeurs spéciales, 255 indiquant aucune limite de propagation et 254 spécifiant de ne pas sortir des limites de l'AS. - depth in tree indique la distance du routeur générant le REQUEST par rapport au routeur congestionné qui forme la racine de l'arbre de pushback. Cette racine aura donc une profondeur de zero et chaque enfant aura une profondeur supérieure de 1 à la profondeur minimale de ses parents. Cette donnée sert à calculer les variations de temps pour le champ status frequency augmentant plus le routeur est éloigné de la racine puisqu'il reçoit le REQUEST en dernier et que ses messages mettront plus de temps à atteindre la racine. - bandwidth limit indique selon une valeur de 32 bits en octets par seconde la limite supérieure de débit autorisée pour l'agrégat accompagnant le REQUEST. Bien sûr, si le routeur recevant le message subit lui-même une congestion, il peut offrir encore moins de bande passante. - expiration time indique la période de temps après laquelle la limitation expire si aucun REFRESH n'est arrivé. - status frequency indique la fréquence à laquelle un routeur doit envoyé un message STATUS à ses parents. Status frequency et expiration time sont en millisecondes encodés sur 32 bits. Viennent ensuite les messages de type REFRESH dont la composition est rigoureusement similaire au REQUEST. Il permet à un routeur ayant perdu l'état du pushback (i.e. en crashant) de le récupérer, et aux routeurs sans problèmes de se contenter de comparer le champ RLSID. Il permet surtout de mettre à jour n'importe quel champ d'une session pushback et notamment le temps d'expiration, la limitation de bande passante, la fréquence d'envoi de statut et la signature de congestion. Il doit tout comme REQUEST être propagé aux enfants du routeur le recevant. Le type de message CANCEL est également décrit et permet évidemment de stopper la limitation de débit en rapport avec un agrégat. Il ne comporte aucun champ en plus de l'entête commune. Enfin, le dernier type de message est STATUS qui est envoyé par chaque routeur à ses parents. Ses champs additionnels sont les suivant : - arrival rate estimate indiquant le débit de l'agrégat si il n'y avait pas de limitation. Cette estimation est calculée depuis la réception du REQUEST pour le premier STATUS puis par rapport au dernier STATUS. - SRMode similaire au champ SRMode d'un REQUEST, mais ici indicatif - height indiquant la profondeur du routeur envoyant le STATUS dans l'arbre de pushback où 0 désigne une extrémité de l'arbre, et où chaque parent ajoute un à la profondeur maximale de ses enfants. Ce champ permet à chaque routeur de savoir la profondeur de l'arbre de pushback en amont. - NumElem ne sert pas pour le SRMode COMPACT. Il indique le nombre de routeurs listés. - Pour chaque routeur listé, le message STATUS donne un identificateur, des informations supplémentaires (pour le moment uniquement la profondeur dans l'arbre de pushback) avec éventuellement un flag S indiquant qu'aucun STATUS n'a été reçu en provenance du routeur upstream depuis le dernier STATUS envoyé localement, et enfin le débit en entrée pour l'agrégat. Bien que son draft ait expiré en laissant plusieurs zones d'ombre, le concept est séduisant et bien conçu par des chercheurs aux excellentes références déjà citées. Vous pourrez trouver en [IOA+02] de plus amples précisions sur l'implémentation d'ACC et apprendre notamment que l'un des concepteurs travaille à un implémentation prototype sur FreeBSD. ACC n'est donc prêt d'être largement déployé. Cependant, il faut voir en cette technique une formidable opportunité de transformer RED ou le rate-limiting en protection distribuée. En utilisant en effet les systèmes de rate-limiting ou RED comme mécanismes de Local ACC, il paraît possible de tirer partie d'un seul routeur couplé à des peers coopérants pour disposer d'une infrastructure distribuée de détection et réduction de congestion. De plus, en se basant uniquement sur la constitution d'agrégat et la détection statistique, il devient alors possible de lutter automatique contre un DDoS sur la totalité du chemin que son trafic emprunte, en escamotant l'étape difficile d'identification de la source. Par son caractère distribué et l'automatisation importante qu'il propose, ACC est certainement le mécanisme le plus prometteur dans la lutte contre la congestion et donc contre les DoS. 3.5. CBAC CBAC [CBAC][SANS] est encore une technologie Cisco, signifiant Context-Based Access Control, et disponible sur IOS depuis les versions 11.2. Elle constitue une extension au firewall (ACL) Cisco en proposant des fonctionnalités de stateful inspection similaires aux instances 'keep state' des firewalls *BSD ou au conntrack pour Linux. Pour conserver des informations sur chacune des sessions inspectées, CBAC utilise une state table par session avec plusieurs agrégats. CBAC peut de cette manière parfaitement gérer les flux TCP en suivant la progression des numéros de séquence, ainsi que les transmissions UDP à l'aide de valeurs de timeout. CBAC supporte également parfaitement la fragmentation IP avec pour règle d'ignorer les fragments non initiaux s'il n'existe pas de state table pour cette session. CBAC fonctionne en créant et supprimant des entrées ACL en fonction des state tables afin de permettre les réponses et même les flux additionnels appartenant à une même session. Pour qu'une connexion soit inspectée par CBAC, elle ne doit pas être filtrée par les ACL qu'elle est susceptible de passer (inbound ACL sur l'interface externe et outbound ACL sur l'interface interne), cependant CBAC n'est d'aucune utilité si la totalité du trafic est autorisé. CBAC servant à séparer un réseau interne de confiance d'un autre ou d'Internet, la session doit être initiée depuis le réseau interne. Mais nous pouvons configurer CBAC pour effectuer l'inspection à la fois en entrée et en sortie. Notez qu'à partir de IOS 12.3(4)T, Cisco a doté CBAC d'une fonction nommé ACL Bypass [BYPASS], qui permet de s'affranchir de ces subtilités de configuration. Le modèle en place introduisait trois points distincts d'examen des paquets : ACL in, CBAC et ACL out. L'examen est alors réduit à une seule recherche de correspondance contre une liste de 'sessions identifiers' conservant en mémoire ports et adresses source et destination, ainsi que l'interface de réception. Ce mécanisme permet de retrouver les particularités offertes par des ACL. Cette garantie étant offerte, cet unique examen permet de contourner l'examen auprès des ACL, accélérant le processus global d'inspection. Il va également falloir définir une interface sur laquelle appliquer cette inspection : en général l'interface externe. CBAC possède aussi une compréhension poussée de plusieurs protocoles applicatifs dont FTP, HTTP (avec la possibilité de bloquer des applets java), SMTP, les r* commandes Unix, les sun rpc (en se basant sur les numéros de programmes) mais aussi H.323 pour la vidéoconférence et RTSP over TCP pour le streaming audio, tous 2 utilisant aléatoirement des ports UDP élevés. Mais ce qui nous intéresse réellement dans CBAC et ses capacités de stateful inspection, ce sont les valeurs de timeouts pour certains états TCP et UDP susceptibles de créer des situations de DoS. Il peut détecter les sessions TCP half open et les connexions UDP de longue durée. Il peut ensuite surveiller les les sessions half open par unité de temps et par hôte. Selon tous ces seuils, il peut détruire l'entrée d'une connexion dans la state table pour UDP, ce qui entraîne un rejet des paquets suivants, ou bien, pour TCP, envoyer un RST aux deux extrêmités ou bien bloquer tous nouveaux segments SYN. Ci-dessous, vous pouvez configurer le temps à attendre avant qu'une connexion atteigne l'état ESTABLISHED, le temps avant la suppression complète de la state table après détection d'un FIN, le temps d'idle pour TCP (en tenant compte des keepalive), le temps d'idle pour UDP, la valeur de timeout pour une résolution de nom DNS, le nombre de sessions half open avant de commencer puis d'arrêter d'en supprimer, le nombre de sessions half open par minute avant de commencer puis d'arrêter d'en supprimer puis, pour finir, le nombre maximal de sessions half open vers la même destination et le temps de blocage en cas de dépassement : router(config)#ip inspect tcp synwait-time 20 router(config)#ip inspect tcp finwait-time 10 router(config)#ip inspect tcp idle-time 300 router(config)#ip inspect udp idle-time 60 router(config)#ip inspect dns-timeout 5 router(config)#ip inspect max-incomplete high 400 router(config)#ip inspect max-incomplete low number 300 router(config)#ip inspect one-minute high 200 router(config)#ip inspect one-minute low 150 router(config)#ip inspect tcp max-incomplete host 50 block-time 15 A titre informatif, la commande 'ip inspect name', proposée par CBAC et suivant le modèle ci-dessous, offre des garanties de sécurité intéressantes pour des protocoles multimédias comme RealAudio (streaming audio) ou H.323 (streaming video). Elle se compose d'une liste d'options impressionante que je vous laisse découvrir dans les guides Cisco [CBAC] : router(config)#ip inspect name RealAudio realaudio timeout 120 router(config)#ip inspect name NetMeeting h323 timeout 120 La commande show rattachée à CBAC est ensuite extrêmement complète : router#show ip inspect {name | config | interfaces | session [detail] | all} Vous pouvez ainsi respectivement afficher la configuration d'une règle en particulier ou bien la totalité de la configuration CBAC, la configuration des interfaces en fonction de CBAC et des ACL, les sessions en cours de traitement avec plus ou moins de détails, ou la combinaison de la configuration et des sessions suivies, en totalité. ------------------------------------ SNiP ------------------------------------- ! acl on the external if access-list 100 deny tcp any any access-list 100 deny udp any any access-list 100 permit icmp any any access-list 100 deny ip any any interface ethernet 1 ip access-group 100 in ! cbac example rules ! les timeouts prennent le pas sur les valeurs generales definies plus bas ip inspect name RealAudio realaudio timeout 120 ip inspect name NetMeeting h323 timeout 120 ! application des règles à une interface ! l'application en in _et_ en out permet de prendre en compte des transmissions ! initiées depuis l'intérieur ou l'extérieur du réseau interface ethernet 0 ip inspect RealAudio in ip inspect RealAudio out ip inspect NetMeeting in ip inspect NetMeeting out ! general timeouts and thresholds ! durée laissée à une connexion pour atteindre l'état 'established' ip inspect tcp synwait-time 20 ! durée de surveillance supplémentaire après détection d'un 4WHS ip inspect tcp finwait-time 15 ! durée limite d'inactivité pour TCP ip inspect tcp idle-time 300 ! durée limite d'inactivité pour UDP ip inspect udp idle-time 60 ! pareil que finwait-ime pour les lookups DNS ip inspect dns-timeout 5 ! seuils absolus de connexions half-open avant d'en lancer/arrêter le rejet ip inspect max-incomplete high 400 ip inspect max-incomplete low number 300 ! seuils de connexions half-open par minute avant d'en lancer/arrêter le rejet ip inspect one-minute high 200 ip inspect one-minute low 150 ! seuils de connexions half-open vers une même destination ! et temps de blocage en minutes ip inspect tcp max-incomplete host 50 block-time 15 ------------------------------------ SNiP ------------------------------------- Assez étrangement, les fonctions de timeout assurées par CBAC sont dédoublées par une autre fonction, pourtant apparues dans IOS 11.2F - c'est-à-dire quasiment en même temps que CBAC - mais quant à elle entièrement dédiée à la protection contre les SYN floods : TCP intercept [CSYN]. Le principe de ce mécanisme est d'intercepter chaque requête de connexion TCP afin de la valider. Pour être précis, il existe deux modes de fonctionnement. Le premier est le watch mode et se rapproche beaucoup d'une fonctionnalité de stateful inspection. Le routeur se contente alors de surveiller passivement tous les segments SYN et de clore la transmission en cas d'échec de la négociation entre client et serveur dans un intervalle de temps configurable au niveau du routeur. Ce n'est pas sans rappeler les options 'idle time' de CBAC. Le second mode, dit intercept mode, ressemble quant à lui une attaque de type man-in-the-middle (MITM) autorisée et encadrée. Le principe est en effet d'intercepter tous segments SYN analogue à une EACL donnée. Le routeur prétend alors être le client auprès du serveur, et le serveur auprès du client, exactement comme lors d'une attaque MITM. Si les connexions sur chaque moitié réussissent, les transmissions sont fusionnées de manière transparentes. Le routeur continuera alors à intercepter et à faire suivre les segments pour le reste de la transmission, en contrôlant les temps de timeout. Du fait de ces timeouts, dont les valeurs sont réduites en cas de nombre de transmission incomplète dans l'absolu ou sur une minute, et l'intercept mode, les segments forgés sont très rapidement découverts et ignorés. Les SYN flood sont ainsi écartés puisqu'aucun connexion ne peut rester indéfiniment en attente de complétion. Ce mode est celui par défaut. Vous pouvez spécifier le mode que vous désirez utiliser avec la ligne suivante : router(config)#ip tcp intercept mode {intercept | watch} L'inconvénient majeur soulevé par la documentation est que les options TCP ne sont pas négociables lorsqu'on se trouve en intercept mode. En effet, le problème est bien connu, en particulier dans le domaine des IDS : une machine tierce interceptant une transmission ne peut pas connaître les fonctionnalités supportées par les deux extrêmités. C'est ce que certains appellent le problème de connaissance ("awareness problem"). L'étape suivante dans la configuration de TCP Intercept est la même que pour CBAC : la configuration des valeurs de timeouts et des seuils de paquets. Il faut alors faire la différence entre les valeurs valables en mode intercept ou watch normal, et les valeurs utilisées une fois qu'une attaque a été détecté. Occupons-nous d'abord des valeurs de timeouts normales. Vous trouverez ci-dessous les commandes permettant de choisir la durée laissée à une connexion pour atteindre l'état ESTABLISHED en watch mode (défaut à 30 secondes), puis la durée entre l'interception d'une synchronisation FIN ou d'un segment RST et l'arrêt complet du suivi de la connexion (défaut à 5 secondes), ainsi que la durée avant l'arrêt du suivi d'une connexion inactive (24 heures par défaut) : router(config)#ip tcp intercept watch-timeout 20 router(config)#ip tcp intercept finrst-timeout 15 router(config)#ip tcp intercept connection-timeout 300 Il faut ensuite indiquer les valeurs définissant la séparation entre comportement normal et agressif. Pour entrer en mode agressif, il suffit que le nombre maximal de half open ou bien le nombre maximal de half open en une seule minute soient dépassés. Pour revenir à un mode normal, il faut que ces valeurs repassent en dessous des deux seuils inférieurs. Les valeurs par défaut des seuils supérieurs sont 1100, et 900 pour les seuils inférieurs. Vous trouverez à la suite ci-dessous les commandes des seuils supérieurs (high) et inférieurs (low) : router(config)#ip tcp intercept max-incomplete high 800 router(config)#ip tcp intercept one-minute high 600 router(config)#ip tcp intercept max-incomplete low 600 router(config)#ip tcp intercept one-minute low 400 Encore une fois, le rapprochement avec CBAC est inévitable ; les commandes sont exactement les mêmes. Pensez à ce propos que les valeurs ne doivent pas être uniquement dictées par le débit, mais aussi par la consommation de mémoire au niveau de votre routeur et des destinataires. Gardez également à l'esprit qu'il s'agit là de limites pour des connexions incomplètes, pas pour un nombre de session en cours. En retenant cet aspect, on peut considérer ces valeurs comme suffisantes. Maintenant, que ce passe-t-il lorsque TCP Intercept entre en mode agressif, c'est-à-dire que les seuils supérieurs sont dépassés ? Dans ce cas, les connexions en cours de complétion sont rejetés jusqu'au retour au mode normal, selon la politique décrite précédemment. Vous avez la possibilité de paramétrer la politique de rejet. Vous pouvez rejeter les plus anciennes connexions, ce qui est le comportement par défaut, ou bien rejeter aléatoirement. Choississez votre politique à l'aide de la commande suivante : router(config)#ip tcp intercept drop-mode {oldest | random} L'autre conséquence de l'entrée en mode agressif, est la modification des valeurs de timeout de retransmission (RTO, voir RFC 2988). Le RTO initial utilisé par l'intercept mode, et constaté pour le watch mode, est ainsi réduit de moitié. Ceci permet, en retransmettant un segment SYN deux fois plus vite, de diviser par deux le temps maximal nécessaire à la complétion d'une connexion, et donc de réduire au plus vite le nombre de connexions incomplètes, afin revenir à un mode normal. En pratique, cela se traduit, pour l'intercept mode, et du fait de son fonctionnement exponentiel original - une première retransmission à 1 secondes, puis à 2, 4, 8 et 16 secondes, avant d'abandonner, soit 31 secondes - à un timeout maximal à 15.5 secondes. Pour le watch mode, c'est simplement le suivi de la transmission qui est abandonné après un maximum de 30 secondes (par défaut) en temps normal, soit 15 secondes en mode agressif. N'oubliez cependant pas que le timeout normal du mode watch peut être configuré manuellement par 'ip tcp intercept watch-timeout'. Le fonctionnement de type MITM devrait palier aux éventuels détérioriation du trafic (congestion, pertes de débit, ...) causés par la modification brutale des RTO. Détail amusant, ce type de modification brutale au niveau de l'infrastructure réseau est sans doute, à l'heure actuelle, la seule défense disponible contre les dernières générations d'identificateurs d'OS, tels que RINGv2. Il ne reste plus qu'à activer TCP Intercept par ACL. Cette manière de faire offre beaucoup de souplesse. Vous pouvez ainsi appliquer l'interception à la totalité du trafic TCP ou bien, et c'est le plus intéressant, le définir pour certaines destinations. L'intérêt réside, pour une ferme de serveurs protégée derrière notre routeur, dans l'interception de chaque requête client, évitant ainsi toute interruption de service. Il est de plus très reducteur de définir l'interception sur des sources puisque cela signifie que vous connaissez par avance l'origine d'un SYN flood. Le seule bénéfice serait d'éviter une attaque après usurpation d'une console administrative, par exemple. Ci-après un exemple d'interception de tous les paquets vers un serveur. ------------------------------------ SNiP ------------------------------------- configure terminal ip tcp intercept list 101 ! utilisez des EACL access-list 101 permit tcp any ------------------------------------ SNiP ------------------------------------- Pour finir, affichez les connexions en attente de complétion actuellement tracées en tapant : router#show tcp intercept connections Ou bien obtenez des statistiques plus générales : router#show tcp intercept statistics Notez que la documentation Cisco disponible pour TCP Intercept étant plus précise quant au fonctionnement interne du sous-système, et les deux mécanismes étant très proche dans l'utilisation, nous pouvons affirmer sans risques qu'il ont quasiment le même fonctionnement. La description de TCP Intercept vous aidera donc à mieux comprendre CBAC, qu'elle que soit la technologie que vous déciderez d'appliquer sur vos routeurs. Les systèmes libres ne sont pas nécessairement en reste, même s'il ne sont pas non plus à la pointe de l'innovation. En 2000, Guido van Rooij avait ainsi proposé un mécanisme de sondage dynamique (dynamic probe) pour IPFilter, inspiré des firewalls Checkpoint-1, afin de déterminer si un segment TCP ACK perçu par un firewall appartenait ou non à une transmission valide. Si le même segment mais avec un flag SYN aurait été autorisé selon les règles chargées, alors le filtre supprimait le payload et modifiait le numéro de séquence en conséquence, avant d'envoyer le segment ACK à son destinataire. Si le ACK n'appartenait à aucune connexion, l'hôte de réception aurait renvoyé un RST, intercepté ensuite par le firewall pour parer à une tentative de scanning. Si le segment appartenait bien à une transmission valide, alors le ACK renvoyé par le destinataire aurait créé une entrée dans la state table du firewall. Ce système permettait de résoudre avec élégance le problème des "cold starts" en cas de rédémarrage en ligne du firewall, remis au goût du jour par la normalisation réseau de Vern Paxson. Ce dernier n'hésitera d'ailleurs pas à proposer une solution similaire, à la différence près qu'il limite la création d'état, et donc la consommation de mémoire, en assumant que le ACK éventuellement renvoyé par l'hôte TCP se trouvant derrière le firewall provient d'un réseau dit de confiance (trusted), et crée donc un nouvel état automatiquement. Vous remarquerez que CBAC et TCP Intercept reprennent une logique similaire mais étendu à toutes les transmissions, de même que synproxy, implémenté par OpenBSD dans PF, que nous verrons plus loin. Cependant, les exactes solutions proposées par Guido van Rooij puis Vern Paxson n'ont jamais été réellement implémenté dans les systèmes libres, ni firewall, ni IDS. Plus concrètement, vous disposez tout de même sur toutes les versions récentes des systèmes libres de paramètres ajustables quant aux valeurs de timeout utilisées par leurs firewalls pendant le suivi des transmissions à travers une table d'états (state table). Ainsi depuis le kernel 2.4 qui a vu l'introduction du sous-système de firewall Netfilter, Linux dispose d'une véritable gestion d'état. Cependant, loin d'être parfaite, ses valeurs de timeout sont encore statiques. Seul l'ajout du patch tcp-window-tracking [TWT] vous permettra d'utiliser l'aborescence /proc/sys/net/ipv4/netfilter/ pour les modifier dynamiquement. Toutes les entrées sont à spécifier en jiffies - que nous avons déjà évoqué au moment du rate-limiting - représentant en général 1/100ème de seconde. Nous trouvons d'abord là deux valeurs génériques. La première, ip_conntrack_generic_timeout est la valeur de timeout utilisé par le connection tracking (conntrack) de netfilter lorsque celui-ci n'est pas en mesure de déterminer le protocole utilisé et donc de se référer à des valeurs plus spécifiques selon l'état. La seconde, ip_conntrack_tcp_timeout_none, représente quant à elle la valeur de timeout utilisé lorsque conntrack n'a pas encore pu classer le flux (en icmp, tcp, udp ou generic). Cela peut par exemple être le cas après un redémarrage du firewall où celui-ci observe des paquets revenant à des sessions déjà ouvertes. En général, conntrack considère l'état NONE très peu de temps avant d'identifier. Le peu d'importance de ces valeurs pour notre sujet permet de les laisser à leurs valeurs par défaut (600 et 1800 secondes respectivement). Nous pouvons ensuite altérer les valeurs de timeout pour les échanges ICMP et UDP. Même si ceux-ci ne possède pas réellement de notion d'états, conntrack peut tout de même créer des règles dynamiques pour laisser passer les réponses ICMP et UDP. Les premières sont contrôlées par ip_conntrack_icmp_timeout. Au passage d'un message ICMP autorisé, conntrack laissera une règle autorisant la réponse par le destinataire du premier message pendant un temps valant ip_conntrack_icmp_timeout. La valeur par défaut est de 30 secondes et peut sans risque être diminuée. Pour UDP, il est fait distinction entre deux états par netfilter. Le premier timeout, ip_conntrack_udp_timeout, s'applique au début d'un échange UDP, incluant jusqu'à plusieurs paquets dans les deux sens, afin que conntrack soit certain que la transmission a atteint l'équivalent d'un état ESTABLISHED. C'est alors ip_conntrack_udp_timeout_stream qui prend le relais jusqu'à la fin de la transmission. Ces entrées ont pour valeur par défaut respectives 30 et 180 secondes. Dans d'autres systèmes de gestion de state table, la première valeur pourrait certainement être diminuée. Cependant comme netfilter considère que ce pseudo-état englobe plusieurs datagrammes, il est préférable de laisser une valeur assez élevée comme celle par défaut. Il en est de même pour la deuxième. Enfin, arrive la partie qui nous intéresse le plus, c'est-à-dire les timeouts relatifs à TCP, là où les risques sont les plus grands. En premier desquels on trouve les entrées relatives au 3WHS, ip_conntrack_tcp_timeout_syn_sent commençant à la detection d'un SYN envoyé (120 secondes par défaut), ip_conntrack_tcp_timeout_sy_recv à la suite d'un SYN reçu et d'un SYN/ACK renvoyé (60 secondes) et ip_conntrack_tcp_timeout_established indiquant la transition vers l'état ESTABLISHED depuis l'un des deux états précédents (432000 secondes, soit 5 jours, par défaut). La dernière en particulier peut sans risque être affinée pour correspondre à la réalité des transferts. Le seul problème pourrait venir de systèmes défectueux gérant pas ou mal les keepalives. Les autres valeurs doivent être choisies en gardant à l'esprit les durées maximales de retransmissions (un peu au-delà de 20 secondes pour Linux) afin de laisser toutes ses chances à la connexion de s'établir. # echo "25000" > /proc/sys/net/ipv4/ip_conntrack_tcp_timeout_syn_sent # echo "25000" > /proc/sys/net/ipv4/ip_conntrack_tcp_timeout_syn_recv # echo "300000" > /proc/sys/net/ipv4/ip_conntrack_tcp_timeout_established Examinons maintenant - chronologiquement ! - les timeouts du 4WHS de fermeture de la transmission. Le premier d'entre eux est ip_conntrack_tcp_timeout_close. Il est décrit comme intervenant juste après le cas de figure où une machine envoie un FIN mais reçoit juste après un FIN et répond pas un FIN/ACK. On remarquera ici une petite erreur de compréhension puisqu'il n'existe absolument pas d'état TCP CLOSE, mais seulement un appel utilisateur du même nom et un état CLOSING. L'erreur peut venir du fait que l'état réellement décrit est un passage en FINWAIT-1 juste après une requête utilisateur CLOSE, suivi immédiatement par un passage à CLOSING suite à la réception d'un segment FIN. Sa valeur est de seulement 10 secondes, ce qui est tout à fait adapté. Le suivant est ip_conntrack_tcp_timeout_fin_wait qui s'applique aux deux états FINWAIT-1 (segment FIN envoyé dans un sens) et FINWAIT-2 (FIN/ACK reçu en réponse).Ils représentent donc la procédure normale de fermeture pour un hôte TCP actif. La valeur par défaut est de 120 secondes (un MSL) mais peut être réduit sans risque puisque ce timeout concerne un échange dynamique. Lorsque l'hôte TCP est au contraire passif dans le 4WHS, l'état suivant dans lequel il entre s'appelle CLOSE-WAIT (réception d'un FIN et renvoit d'un FIN/ACK). Son timeout, ip_conntrack_tcp_timeout_close_wait, est de 43200 secondes par défaut, ce qui laisse énormément de marge pour le ramener à des valeurs plus faibles, en accord avec les autres. Si le programme déclenche alors un appel utilisateur CLOSE, causant l'envoi d'un FIN pendant CLOSE-WAIT, TCP entrez dans un nouvel état, appelé LAST-ACK, qui a pour conséquence de clore immédiatement la connexion. La durée de vie de l'entrée conntrack pour cet état dépend de ip_conntrack_tcp_timeout_last_ack dont la valeur par défaut est 30 secondes. Elle peut éventuellement être diminué puisque, sur requête explicite du programme, la connexion est entrée en CLOSED (plus aucun TCB). Il ne semble donc pas pertinent de prolonger la durée de vie de l'entrée conntrack correspondante. Il en est tout autrement de la dernière entrée, ip_conntrack_timeout_time_wait. Cette dernière est l'ultime état atteint par un hôte TCP passif, prenant donc place après un FINWAIT-2 ou un CLOSING. Dans le premier cas, un FIN a été reçu et un FIN/ACK répondu complétant le 4WHS débuté par le passage en FINWAIT-1. Dans le second, c'est la réception d'un FIN/ACK qui déclenche le changement d'état. La valeur par défaut de cette variable est 120 secondes. Il est déconseillé de la diminuer. En effet, TIME-WAIT ne fait que laisser passer un timeout avant la destruction définitive du bloc de contrôle (TCB). Le but est de laisser le temps aux données envoyées avant la complétion du 4WHS, et donc encore en cours de transmission (inflight) d'arriver à leur destination ainsi que d'être réordonnées. A cette fin, un timeout égal à un MSL est laissé afin de s'assurer que tous les segments sont soit arrivés soit ont expiré. # echo "25000" > /proc/sys/net/ipv4/ip_conntrack_tcp_timeout_close # echo "60000" > /proc/sys/net/ipv4/ip_conntrack_tcp_timeout_fin_wait # echo "20000" > /proc/sys/net/ipv4/ip_conntrack_tcp_timeout_close_wait # echo "20000" > /proc/sys/net/ipv4/ip_conntrack_tcp_timeout_last_ack # echo "120000" > /proc/sys/net/ipv4/ip_conntrack_timeout_time_wait Mais outre les valeurs de timeout, il peut également s'avérer primordial de modifier le nombre de connexions suivies simultanément par conntrack. L'avantage est ici que cette variable par défaut sans l'application d'aucun patch via l'ajustement de ip_conntrack_max. Quelques restrictions cependant. D'abord, chaque entrée supplémentaires dans la state table, c'est 350 octets de mémoire vive. Or Netfilter ne peut en aucun cas "swapper" (utilisant le disque dur comme mémoire vive pendant des périodes de faible utilisation d'un programme). C'est donc uniquement votre RAM qui est consommée. D'autre part, il est fortement recommendé d'augmenté le nombre de buckets de la table de hashage. Un chiffre constant en augmenterait la profondeur et, intrinsèquement, le temps de parcours, grèvant d'autant les performances. Cependant cette dernière variable doit être précisé au moment du chargement du module ip_conntrack.o, quand il n'est pas lié statiquement au kernel. Voici tout de même la séquence qui vous permettra ces modifications, si votre configuration le permet : # echo "12000" > /proc/sys/net/ipv4/ip_conntrack_max # modprobe ip_conntrack hashsize=1500 Du côté de FreeBSD, IPFW propose plusieurs entrées sysctl permettant de paramétrer votre state table et de rejeter plus agressivement des connexions non réactives, congestionnées ou lentes. Pour ce faire, ipfw utilise un mécanisme de lifetime qui permet de conserver une règle dynamique active en attente d'un nouveau paquet qui relancera la décrémentation de ce lifetime. Si le lifetime arrive à zéro sans nouveau paquet, alors la règle dynamique disparaît et les paquets sont refusés. Successivement, nous configurons les valeurs de timeout pour l'état established, syn wait, fin wait et closed pour TCP, puis le timeout entre les paquets UDP. Les entrées sysctl suivantes vous permettent de spécifier et consulter la taille de la table hashage destinée aux règles dynamiques de votre ruleset. Tout ceci ne fonctionne qu'après un 'ipfw -f' vidant les tables, et s'applique à toutes règles keep-state. Notez que sous FreeBSD, le temps maximal de retransmission est moindre, tout comme le seront donc les valeurs choisient. # sysctl -w net.inet.ip.fw.dyn_ack_lifetime=300 # sysctl -w net.inet.ip.fw.dyn_syn_lifetime=20 # sysctl -w net.inet.ip.fw.dyn_fin_lifetime=60 # sysctl -w net.inet.ip.fw.dyn_rst_lifetime=5 # sysctl -w net.inet.ip.fw.dyn_udp_lifetime=15 # sysctl -w net.inet.ip.fw.dyn_short_lifetime=30 Appliquant très partiellement les idées développées par Guido van Rooij, ainsi que les fonctionnalités proposées par TCP Intercept, Luiggi Rizzo a implémenté, à partir de FreeBSD 4.8, un mécanisme de keepalive pour les connexions TCP gérées par des règles keep-state. Lorsqu'il ne reste plus que 20 secondes au lifetime, des segments keepalive sont envoyés toutes les 5 secondes aux deux extrêmités afin de tenter de réactiver la session. Cette fonctionnalité n'est pas directement dirigée contre les DoS mais permet tout de même de distinguer les connexions légitimes de celles illégitimes, offrant ainsi une plus grande fiabilité aux utilisateurs tout en combattant les risques de DoS avec des lifetimes modifiés. Utilisez l'entrée sysctl suivante pour activer les keepalive : # sysctl -w net.inet.ip.fw.dyn_keepalive=1 Vous disposez à partir d'OpenBSD 3.2 de fonctionnalités similaires grâce au travail exemplaire des développeurs - en particulier Daniel Hartmeier - de Packet Filter (pf), le sous-système de firewall par défaut depuis OpenBSD 3.0 [PF]. Les Options vous permettent en effet de paramétrer des valeurs de timeouts selon le protocole et son état, mais aussi des limites d'utilisation mémoire. Les options décrites sont globales et doivent intervenir au début de votre ruleset (typiquement pf.conf(5) [MANPF]) avec l'un des 2 syntaxes suivantes : set option parameter value ou set option { parameter value, parameter value } Les options les plus intéressantes pour nous sont les 'timeout' qui s'appliqueront à tout filtre contenant les mots clés 'keep state' ou 'modulate state'. D'abord nous devons configurer 2 variables globales, interval indiquant le temps à attendre entre la purge des états expirés et celle des fragments expirés, et frag spécifiant le temps avant qu'un fragment non attaché à une connexion ne soit déclaré expiré. Nous avons ensuite la possibilité de modifier plusieurs valeurs indiquant la durée d'un état avant de considérer une connexion comme expirée. Chaque nouveau paquet correspondant à une entrée dans la state table remettra le compteur de l'état actuel de la connexion à zéro. Une première série de timeouts sont valables pour la totalité des états TCP : tcp.first déclenché après l'arrivée du 1er paquet, tcp.opening avant que la destination n'envoit un paquet, tcp.established après le passage en état établis c'est-à-dire après le 3WHS (three-way handshake, poignée de main d'initialisation), tcp.closing après l'envoi du premier FIN par un des 2 hôtes, tcp.finwait après l'échange de FIN et la complétion du 4WHS (four-way handshake, poignée de main de fermeture), et enfin tcp.closed après l'envoi d'un RST par un hôte (présent à cause de certains OS non conformes qui continuent d'envoyer des données malgré la fermeture de connexion). Notez que comme tcp.closing englobe tous les paquets transitant pendant un 4WHS, il est nécessaire de lui donner une valeur relativement importante. En effet, pendant ce processus, il est traditionnellement laissé le temps aux paquets encore en chemin le temps de revenir et en particulier d'être remis en ordre. On attribue donc à cet état spécifique une valeur égale à un MSL (Maximum Segment Life), soit 120 secondes. Viennent ensuite les timeouts pour UDP et ICMP et ce même si ces protocoles n'ont pas de notion d'état. udp.first indique le timeout après l'envoi du premier datagramme, udp.single avant l'envoi par la destination d'un paquet, udp.multiple lorsque les 2 hôtes ont échangé des paquets. De même, icmp.first est le timeout après l'envoi d'un premier message ICMP et icmp.error après la réception d'un message d'erreur en réponse à un autre message ICMP (echo reply/request par exemple). Enfin, les autres protocoles sont traités sans connaissance de leur gestion ou non d'état et donc assimilés dans la state table à UDP avec other.first, other.single et other.multiple. Enfin, si vous ne voulez pas risquer de détériorer vos connexions à l'aveugle, les développeurs de PF ont prévu plusieurs solutions pour vous. Il y a tout d'abord la possibilité de réduire les valeurs de timeout automatiquement selon un coefficient dépendant de la taille de la state table. Ainsi, plus cette table grossira, plus les timeouts se trouveront réduits. Pour utiliser cette stratégie adaptive, il sera nécessaire de paramétrer deux variables : adaptive.start et adaptive.end. La première précise le nombre d'entrées dans la state table déclenchant son "adaptation" tandis que la seconde indique le seuil à partir duquel toutes les valeurs de timeout sont mises à zéro. Ces deux paramètres servent en fait à calculer le coefficient d'adaptation des timeouts en suivant la formule suivante : (adaptive.end - current_states_number) / (adaptive.end - adaptive.start) Le résultat, appelez "facteur d'échelle" (scale factor), n'est pris en compte qu'à partir du moment où le nombre d'états atteint la valeur d'adaptive.start. Le timeouts conservent donc leur valeur originale avant cela (100%). Dès que l'adaptation commence, le facteur d'échelle commence à décroître linéairement, plus ou moins rapidement selon la distance entre adaptive.start et adaptive.end. Périodiquement, PF vérifie s'il doit supprimer des états (voir 'set interval' pour plus de détails). En mode adaptation, il récupère les valeurs de timeout originales qu'il multiplie par le facteur d'échelle calculé. Pour savoir quand un état va expirer, il suffit alors d'ajouter la valeur de timeout, modifiée par le facteur d'échelle, à l'instant du dernier segment reçu (ayant donc mis à jour la valeur de timeout). Si l'état est plus ancien ou égal au timeout modifié, il expire. Par exemple, avec la valeur par défaut de 'tcp.established' (84600 secondes), d'adaptive.start et d'adaptive.end (6000 et 12000 respectivement), lorsque le nombre d'entrées dans la state table atteint 9000, le timeout original est réduit par un facteur d'échelle de 0.5, soit 42300 secondes. Selon toute logique, réduire l'espace entre adaptive.start et adaptive.end entraînera une diminution plus rapide des timeouts. Attention dans ce cas au risque de synchronisation des retransmissions - phénomène qui risquerait de surcharger la machine par vague. Notez que, adaptive.end n'étant pas supposé être atteint et servant uniquement au calcul du facteur d'échelle, il n'y a en aucun cas double emploi avec l'option 'state limit'. L'espacement par défaut entre les deux valeurs d'adaptation semblent - empiriquement - acceptables. Ajustez alors adaptive.end pour éviter une trop grande disparité avec 'state limit'. Comme toutes les options 'timeout', vous pouvez spécifiez les valeurs contrôlant l'adaptation sur la base d'une règle possédant l'attribut 'keep state' ou 'scrub'. Dans ce cas, le nombre courant d'états sera celui des états créés par la règle en question. De même, les timeouts modifiés seront uniquement ceux des états créés par cette même règle. Il est alors évident que les valeurs d'adaptation doivent être diminuées, une seule règle créant moins d'états qu'un ruleset complet. Mais ce n'est pas tout. Pour simplifier la vie des admins, sont également apparues les options 'optimization'.Celles-ci permettent de sélectionner automatiquement les valeurs de timeout en fonction du comportement désiré pour la machine. Ces comportements sont divisés selon le type d'environnement réseau : normal, high-latency ou satellite lorsque la sensibilité au délai est grande, aggressive pour réduire l'utilisation des ressources d'un firewall via de faibles valeurs de timeout, et conservative qui sélectionne de grandes valeurs de timeout pour ne risquer en aucun cas de rejeter une connexion légitime. En combinant les options 'timeout' et 'optimization', vous avez tout loisir d'affiner les valeurs de timeout au cas par cas. Choississez un comportement par défaut via 'set optimization' puis, ajoutez des options 'timeout' pour les protocoles ou états dont les valeurs sélectionnées par le comportement choisi ne vous plairaient pas. Nous disposons aussi dans le domaine de configuration de la state table d'une spécification de la mémoire allouée pour la conservation d'états et de fragments via des memory pools. Comme pool(9) vous le dira, ces pools sont utilisés par OpenBSD pour assurer un minimum de mémoire en cas d'épuisement du heap sur lequel alloue malloc(9). Ces limites sont appliqués par les mots clés 'limit states' et 'limit frags', limitant la mémoire disponible pour les entrées générées respectivement par les règles 'keep state' et 'scrub'. D'autre part, toutes les limites, ainsi que les timeouts et leur adaptation dépendent d'une mesure précise du nombre d'états. Par défaut, PF vérifiera ces options toutes les 10 secondes, limitant ainsi la surcharge de travail qui pourrait pénaliser la qualité du service, c'est-à-dire ce que nous cherchons justement à protéger. Vous pouvez tout de même améliorer sensiblement cette valeur en en spécifiant une nouvelle via 'set interval', en secondes. Cet intervalle peut de plus devenir crucial si votre firewall se trouve sur une liaison rapide avec des possibilités d'arrivées de paquets nombreuses en peu de temps. Notez que toutes les options 'timeout' peuvent également être appliquées individuellement à des règles en les utilisant comme paramètres aux mots-clés de stateful inspection 'keep state' et 'modulate state'. Ils supportent aussi en paramètres l'option 'max' indiquant le nombre maximum d'états concurrents - et donc de connexions concurrentes dans un même état, chiffre capable de fortes variations selon l'utilisation du serveur - qu'une règle peut créer. Lorsque la limite est atteinte, les nouveaux états sont rejetés jusqu'à ce qu'un des anciens timeout. Pour appliquer ces options à une règle spécifique suivez l'exemple suivant. pass in proto tcp from any to any port www flags S/SA \ keep state (max 100, tcp.established 60, tcp.closing 5) Ci-dessous, la partie option de notre pf.conf. ------------------------------------ SNiP ------------------------------------- # make pf "aware" (c) jcvd set interval 5 # Engine Optimization set optimization aggressive # ou si vous préférez choisir vous-même vos valeurs... # TCP states timeouts set timeout tcp.first 25 set timeout tcp.opening 25 set timeout tcp.established 300 set timeout tcp.closing 25 set timeout tcp.finwait 60 set timeout tcp.closed 10 # stateless timeouts set timeout udp.first 10 set timeout udp.single 10 set timeout udp.multiple 30 set timeout icmp.first 10 set timeout icmp.error 5 set timeout other.first 10 set timeout other.single 10 set timeout other.multiple 30 # Adaptation set adaptive.start 6000 set adaptive.end 12000 # memory pool(9) limits set limit states 12000 set limit frags 12000 # concurrent states set max 400 ------------------------------------ SNiP ------------------------------------- Mais les développeurs d'OpenBSD ne se sont pas arrêtés là. Pour PF, il avait déjà ajouté la fonction 'modulate state' qui permettait d'utiliser le firewall pour réécrire l'ISN TCP de manière fortement aléatoire en début de connexion pour des hôtes, du réseau protégé par PF, dont l'OS n'offrirait pas de PRNG suffisamment puissant. En combinant cette fonction au classique 'keep state', ils ont alors eu l'idée d'ajouter, à partir d'OpenBSD 3.4, un mécanisme de synproxy dont le concept rejoint en tout point les fonctions mises en oeuvre par Cisco dans TCP Intercept, et avant cela par CheckPoint pour SYN Defender et SYN Relay. Le principe de fonctionnement est simple. Lorsqu'un hôte TCP décide d'initialiser une transmission TCP, c'est-à-dire qu'il est l'extrêmité active, PF, au lieu de faire suivre le segment SYN en conservant en mémoire l'état de la connexion pour laisser passer la réponse, va terminer le 3WHS au nom du destinataire original, l'extrêmité passive, en y ajoutant une meilleure randomization de l'ISN (comportement hérité de 'modulate state'). Dans le même temps, PF va également lancer un 3WHS complet vers l'extrêmité passive, au nom de l'extrêmité active, toujours en faisant profiter d'un renforcement du choix de l'ISN. Vous le voyez, PF applique donc une véritable attaque de type man-in-the-middle (MITM) entre les deux hôtes. La protection provient du fait que PF ne laisser effectivement passer les données que si l'extrêmité active répond correctement en complétant le 3WHS depuis l'adresse donnée dans le segment SYN. Ainsi, si l'extrêmité passive était en réalité menacée d'un SYN flood, celui-ci sera intercepté par PF qui, ne parvenant pas à conclure le 3WHS, rejettera la demande de connexion. De cette façon, l'extrêmité passive ne prend à aucun instant part à l'initialisation de la transmission, conservant toutes ses ressources mémoire et processeur pour des connexions légitimes. Même sur le firewall lui-même peu de ressources supplémentaires sont utilisées. En effet, le mécanisme mis en oeuvre pour faire suivre les segments, une fois le 3WHS réussi des deux côtés de la transmission, est le même que pour 'modulate state', c'est-à-dire une simple différence sur 32 bits entre les ISN des paires active/firewall et firewall/passive. Vous ajoutez même ici à la protection contre les DoS et le spoofing, un renforcement de la génération d'ISNs. Pour appliquer ce mécanisme à vos transmission TCP, il suffit d'utiliser le mot-clé 'synproxy state' comme ci-dessous : pass in proto tcp from any to any flags S/SA synproxy state Une limitation introduite et évidente est que cette technique ne peut pas fonctionner si vous utilisez PF en tant que bridge firewall. Cela casserait toute logique de tout pouvoir envoyer des segments depuis une machine dont le code au-dessus du layer 2 a été inhibé. Il peut par contre être intéressant de faire varier les valeurs de timeouts pour l'initialisation de la transmission en fonction de la position de l'interface, interne ou externe (en utilisant éventuellement des tags pour simplifier le ruleset). Vous pourrez ainsi décider de laisser suffisament de temps aux machines internes tout en utilisant des timeouts agressifs vis-à-vis du monde extérieur afin de ne pas laisser votre firewall attendre trop longtemps. pass in on $extif proto tcp from any to any flags S/SA synproxy state \ { set timeout tcp.first 10 } tag extOK pass on ! $extif tagged extOK pass in on $intif proto tcp from any to any flags S/SA synproxy state \ { set timeout tcp.first 30 } tag intOK pass on ! $intif tagged intOK Il ne vous reste plus qu'à charger votre ruleset. Vous pouvez avec l'option -F ne charger que les filtres et avec -O, que les options. En utilisant le mot-clé 'anchor' vous pouvez même rendre vos rulesets suffisammment modulaires pour modifier vos options dans un fichier indépendant. # pfctl -O -f /etc/pf.conf Vous pourrez ensuite consultez les valeurs des timeouts globaux et des états via la commande pfctl -s timeouts, state ou memory pour lister respectivement les valeurs globales de timeout, le contenu de la state table ou les limites du memory pool. Nous vous recommandons également de vous renseigner quant aux capacités de normalisation réseau - pour le moment exclusives - de pf. Toutes les valeurs de timeouts ci-dessus sont agressives et peuvent poser des problèmes de rejets de segments retransmis. Reportez vous aux RFC 793, 1122 et 2988 pour plus d'informations sur le retransmission timer ou les timeouts d'états encodés. Toutes les techniques présentées dans cette section sont un aperçu de ce que votre infrastructure peut faire pour limiter activement les DoS tirant partie de faiblesse dans le design des protocoles de la pile TCP/IP. Nous nous sommes particulièrement intéressés ici aux attaques basées sur TCP, telles que les SYN floods. Les technologies assimilables à CBAC permettent de contrôler au plus près le débit des flux TCP et la vitesse à laquelle de nouveaux flux vont être accepté. En cela, elles participent comme le rate-limiting à la limitation de l'utilisation de la bande passante au niveau de notre infrastructure. Au-delà de cette protection de l'infrastructure, particulièrement efficace en bordure de celle-ci, vous garantissez aux mieux la continuité de vos services de filtrage par une plus grande résistance aux floods massifs. Les moyens présentés ici répondent donc à une demande ancienne pour une plus grande résilience dans le filtrage des périphériques réseaux [MFA]. 3.6. TCP SYN Cookies Le principe de cookie existe depuis longtemps en informatique. Il permet par exemple au protocole HTTP pourtant transactionnel de gérer la notion d'états en conservant les informations qui y sont relatives dans un fichier à chaque extrêmité de la transmission. En 1996, Dan J. Bernstein et Eric Schenk proposèrent l'utilisation de cookies cryptographiques encodés dans l'Initial Sequence Number (ISN) TCP [DJB] afin de supprimer totalement le cache d'information jusqu'à la complétion de la connexion. Ceci permet en effet d'éliminer le risque de SYN flood, puisque le SYN n'entraîne aucune allocation de mémoire, ne remplit pas la queue d'écoute des connexions incomplètes, et prévient donc tout épuisement de ressources. Les syncookies sont la première méthode que nous étudions qui ne s'applique pas à une passerelle mais directement aux hôtes finaux. L'encodage dans l'ISN tel que présenté par Bernstein et Schenk est le suivant : - Les 5 premiers bits valent t mod 32 où t est un compteur temporel allant de paire avec un secret - les 3 bits suivant indiquent la MSS (Maximum Segment Size) sélectionnée par le serveur. Cet encodage est indispensable puisque le serveur ne conserve pas l'état de la connexion en cours de complétion et oublit donc plusieurs options TCP comme le MSS, le window scale, etc. - les derniers 24 bits correspondent au secret sélectionné par le serveur. Ce secret est un hash MD5 de l'adresse source, de l'adresse de destination, du port source, du port de destination et enfin du compteur t. secret = hash(saddr,sport,daddr,dport, t) Pour FreeBSD, que nous prendrons en exemple puisqu'il possède une implémentation récente et bien documentée [LEM02], l'encodage est sensiblement différent. Le compteur temporel, destiné à rendre caduc la collecte et la réutilisation de cookies par un attaquant, possède une durée de vie limitée à 4 secondes censée permettre à la connexion de se compléter. Ce choix permet de limiter le ACK flood puisqu'il faudrait générer un très grand nombre de paquets en seulement 4 secondes. Il reste donc 25 bits pour le secret, et 7 bits encodant les informations de window et de MSS. Comme nous l'avons déjà fait remarquer, les syncookies créent quelques problèmes en ne conservant aucun état avant la complétion effective de la connexion. Il perd notamment toutes les options contenues dans le SYN et il ne peut pas non plus retransmettre de SYN/ACK en cas de disparité d'états entre le client et le serveur due à des pertes par exemple. Mais les syncookies peuvent également poser des problèmes de sécurité. Un attaquant peut ainsi tenter un ACK flood en espérant tomber sur quelques cookies, complétant ainsi une connexion et consommant tout de même des ressources. Cette attaque a de plus la capacité d'outrepasser les règles de stateful inspection se basant sur les segments SYN puisque la connexion est désormais initialisée en réalité par le segment ACK. Pour ce dernier problème, Bernstein a proposé de conserver un timestamp du plus récent dépassement par queue d'écoute des connexions incomplètes, et de ne pas créer d'état à la suite d'un ACK coïncidant avec un cookie si il n'y a pas eu de dépassement récent. Cette solution se traduit concrètement par un fonctionnement classique de TCP en temps normal, et un basculement sur le mécanisme de syncookie en cas de détection de SYN flood via un remplissage des queues. Il y a sur ce point une divergence entre Linux et FreeBSD probablement due à la différence d'âge des 2 implémentations (respectivement 1997 et 2002). Linux utilise très classiquement les syncookies comme une solution de secours suite à un flood détecté sur des queues classiques. FreeBSD a décidé de modifier son système stockant les états afin de le rendre plus résistant, avant de passer en dernier recours à un mécanisme de syncookie. FreeBSD utilise donc désormais un syncache pour conserver l'état d'une connexion jusqu'à sa complétion. Il a ainsi été décidé de limiter fortement les données conservées en utilisant, en lieu et place de la classique liste linéaire par sockets, une table de hashage dans laquelle les sockets sont indexées par bucket via des listes chaînées. Ensuite, en cas de détection de flood, la plus ancienne entrée (d'un bucket ou du cache entier) est supprimée, avant de basculer sur les syncookies. Ce mécanisme permet à la fois de diminuer l'occupation mémoire et d'accélérer le parcours de la structure de données. Notez bien si vous décidez de modifier les valeurs maximales de cache et de bucket que la première influence la mémoire consommée tandis que la seconde influence la rapidité de parcours de la structure (sa profondeur). Sous FreeBSD, les syncookies et le syncache sont présent par défaut depuis la release 4.5. Il vous suffit de vérifier ou adapter les entrées de la MIB sysctl suivantes : # sysctl -w net.inet.tcp.syncookies=1 # sysctl -w net.inet.tcp.syncache.hashsize=512 # sysctl -w net.inet.tcp.syncache.cachelimit=15359 # sysctl -w net.inet.tcp.syncache.bucketlimit=30 # sysctl -w net.inet.tcp.syncache.rexmtlimit=3 Elles permettent de paramétrer les caractéristiques du syncache, avec d'abord l'activation des syncookies, la taille de la table de hash, la limite de création d'entrée dans le cache, la limite de création de bucket, et la limite de réémission de paquets (ici 3 tentatives soit 15 secondes). Les syncookies sont présents sous Linux depuis les kernels 2.0.29 et 2.0.30, avec cependant quelques problèmes dans la branche 2.2 jusqu'au 2.2.14, et rien à signaler en 2.4. Pour les utiliser, vous devez activer l'option CONFIG_SYNCOOKIES lors de la configuration de votre kernel puis recompiler. Vous pourrez ensuite activer effectivement les syncookies de la manière suivante : # echo "1" > /proc/sys/net/ipv4/tcp_syncookies D'autre part, comme nous l'avons fait remarquer, l'implémentation de ces syncookies diffèrent entre Linux et FreeBSD. Sous FreeBSD, la queue d'écoute, sera limitée par les dimensions de la table de hashage au lieu de l'être par kern.ipc.somaxconn qui n'affecte plus alors que les appels à listen() dans lequel il est possible de spécifier un nombre maximal de connexions entrantes. Tandis que pour Linux, la queue d'écoute reste classique ; il sera donc nécessaire de l'augmenter pour éviter d'être trop sensible aux rafales subites de connexions. Pour cela, ajustez la ligne suivante : # echo "2048" > /proc/sys/net/ipv4/tcp_max_syn_backlog De même, vous diposez d'une entrée permettant de définir le nombre maximal de tentatives de réémission du ACK après un SYN (ici 3, soit 21 secondes) grâce à l'entrée ci-dessous : # echo "2" > /proc/sys/net/ipv4/tcp_synack_retries Les SYN Cookies sont certes une technologie qui s'applique aux machines clientes, alors que nous nous sommes engagés à exposer des solutions pour passerelles. Cependant, son efficacité et sa tendance à l'ubiquité - les cookies sont désormais une partie standard de la phase de négociation dans le nouveau protocole de transport produit par l'IETF, SCTP - nous ont semblés suffisament manifestes pour la voir décrite dans cet article. De plus, en conformité avec notre engagement, les SYN Cookies représentent bien une solution purement protocolaire et permettent à l'infrastructure réseau, au même titre que CBAC ou le rate-limiting, de supporter une charge bien plus importantes sans interruption totale du service attaqué. 4. Conclusion Toutes les techniques présentées n'offrent évidemment pas une protection imparable face aux DDoS, d'autant plus que de nouvelles attaques sont découvertes régulièrement. D'autant plus que, comme nous l'avons souligné tout au long de l'article, les technologies présentées s'intéressent non seulement à la protection mais aussi à la prévention et à la détection. En cela, elles permettent toutes de limiter l'altération de vos services et d'en assurer la qualité, ce qui représente bien l'objectif premier des DDoS. Mais surtout elles permettent de réduire le risque potentiel, augmentant chaque jour au fur et à mesure que Internet se démocratise, pour votre réseau d'être utilisé comme réflecteur dans une attaque DDoS. Encore une fois, ces mesures ne deviennent sérieusement efficaces que si elles se trouvent appliquées par le plus grand nombre, supprimant la matière première de ces attaques aussi dévastatrices qu'exaspérantes. Une protection plus directe et générale des DoS consistera à établir une politique de sécurité incluant le traffic shaping et une définition stricte et effective des flux autorisés. Enfin, ce document n'est en aucun cas un manuel à suivre pas à pas. Les techniques sont présentées sont parfois en concurrence, et c'est donc à vous de tirer le meilleur parti des informations que nous vous délivrons pour faire le choix qui correpondra le mieux à votre infrastructure. 5. Références [FIS02] Protecting your IP network infrastructure http://www.securite.org/presentations/secip/ [CHAR] Characterizing and Tracing Packet Floods Using Cisco Routers http://www.cisco.com/warp/public/707/22.html [DITT] Distributed Denial of Service (DDoS) Attacks/tools http://staff.washington.edu/dittrich/misc/ddos/ [NAP00] The Naptha DoS vulnerabilities http://razor.bindview.com/publish/advisories/adv_NAPTHA.html [ZAL01] Strange Attractors and TCP/IP Sequence Number Analysis http://razor.bindview.com/publish/papers/tcpseq.html [MUR03] BGP Security Vulnerabilities Analysis http://www.ietf.org/internet-drafts/draft-ietf-idr-bgp-vuln-00 [2439] BGP Route Flap Damping http://www.ietf.org/rfc/rfc2439.txt [RIPE01] RIPE Routing-WG Recommendations for Coordinated Route-flap Damping Parameters http://www.ripe.net/ripe/docs/routeflap-damping.html [PAX+02] How to 0wn the Internet in your Spare Time http://www.icir.org/vern/papers/cdc-usenix-sec02/ [WEA+03] The Spread of the Sapphire/Slammer Worm http://www.cs.berkeley.edu/~nweaver/sapphire/ [RED+02] Mitigation of DoS Attacks through QoS Regulation http://ee.tamu.edu/~reddy/papers/iwqos02.pdf [1812] Requirements for IP Version 4 Routers http://www.ietf.org/rfc/rfc1812.txt [2267] Network Ingress Filtering : Defeating Denial of Service Attacks which employ IP Source Address Spoofing http://www.ietf.org/rfc/rfc2267.txt [IANA] Internet Protocol v4 Address Space http://www.iana.org/assignments/ipv4-address-space [3330] Special-Use IPv4 Addresses http://www.ietf.org/rfc/rfc3330.txt [CYMRU] The Team Cymru Bogon Reference Page http://www.cymru.com/Bogons/ [RIP] IP Service Commands http://www.cisco.com/univercd/cc/td/doc/product/software/ios113ed/113ed_cr/np1_r/1rip.htm [TACL] Turbo Access Control Lists http://www.cisco.com/univercd/cc/td/doc/product/software/ios121/121newft/121t/121t5/dttacl.htm [FIDS] Configuring Cisco IOS Firewall Intrusion Detection System http://www.cisco.com/univercd/cc/td/doc/product/software/ios122/122cgcr/fsecur_c/ftrafwl/scfids.htm [ZEBRA] GNU Zebra Documentation : Filtering http://www.zebra.org/zebra/Filtering.html [IPF] IP Filter Based Firewalls HOWTO http://www.obfuscation.org/ipf/ipf-howto.txt [GRE+01] Unicast Reverse Path Forwarding (uRPF) Enhancements for the ISP-ISP Edge http://www.cisco.com/public/cons/isp/documents/uRPF_Enhancement.pdf [CNS] Configuring Unicast Reverse Path Forwarding http://www.cisco.com/univercd/cc/td/doc/product/lan/cat6000/122yo/swcg/secure.htm#1036546 [IOSRPF] Configuring Unicast Reverse Path Forwarding http://www.cisco.com/univercd/cc/td/doc/product/software/ios122/122cgcr/fsecur_c/fothersf/scfrpf.htm [JRPFR] Enable Unicast Reverse Path-Forwarding Check http://www.juniper.net/techpubs/software/junos/junos62/swconfig62-routing/html/routing-generic-config11.html [JRPFI] Configure Unicast RPF http://www.juniper.net/techpubs/software/junos/junos62/swconfig62-interfaces/html/interfaces-family-config17.html [LARTC] Linux Routing & Traffic Control Howto : 13.1. Reverse Path Filtering http://lartc.org/howto/lartc.kernel.html [VRP] Anti-Spoofing Option in ipfw2 on FreeBSD http://www.freebsdforums.org/forums/showthread.php?threadid=7677 [VSR] ipfw_versrcreach.diff http://www.nrg4u.com/freebsd/ipfw_versrcreach.diff [CBGP] Configuring BGP http://www.cisco.com/univercd/cc/td/doc/product/software/ios121/121cgcr/ip_c/ipcprt2/1cdbgp.htm [GRE02] Remote Triggering Black Hole Filtering http://www.ispbook.com/supplements/Remote_Triggered_Black_Hole_Filtering-02.pdf [TURK02] Enhanced Remotely Triggered Black holing using BGP Communities http://www.ietf.org/internet-drafts/draft-turk-ertb-00.txt [GRE+03] Deploying and Using Sinkhole http://www.nanog.org/mtg-0306/sink.html [UUBH] BlackHole Route Server and Tracking Traffic on an IP Network http://www.secsup.org/Tracking/ [NBAR] Network-Based Application Recognition http://www.cisco.com/univercd/cc/td/doc/product/software/ios122/122newft/122t/122t8/dtnbarad.htm [OP] Quality of Service Order of Operation http://www.cisco.com/warp/public/105/qos_orderofop_3.html [CR] Using Network-Based Application Recognition and Access Control Lists for Blocking the "Code Red" Worm at Network Ingress Points http://www.cisco.com/warp/public/63/nbar_acl_codered.shtml [NIMDA] How to Protect Your Network Against the Nimda Virus http://www.cisco.com/warp/public/63/nimda.shtml [RESP] SnortUsers Manual 2.1.0 http://www.snort.org/docs/snort_manual/ [ITRACE] ICMP Traceback Messages http://www.research.att.com/~smb/papers/draft-bellovin-itrace-00.txt [MAN+01] On Design and Evaluation of "Intention-Driven" ICMP Traceback http://seclab.cs.ucdavis.edu/papers/327-IITrace.pdf [ATP] Active Traceback Protocol http://www.ietf.org/internet-drafts/draft-yamada-active-trace-00.txt [SPIE] Source Path Isolation Engine (SPIE) http://www.bbn.com/networking/spie.html [IPPT] New Protocols to Support Internet Traceback http://www.ietf.org/internet-drafts/draft-partridge-ippt-discuss-00.txt [IPST] IP Source Tracker http://www.cisco.com/univercd/cc/td/doc/product/software/ios120/120newft/120limit/120s/120s21/ipst.htm [ARGUS] ARGUS http://www.qosient.com/argus/ [BER02] HSC - Brèves - Argus http://www.hsc.fr/ressources/breves/argus_fr.html [2309] Recommendations on Queue Management and Congestion Avoidance in the Internet http://www.ietf.org/rfc/rfc2309.txt [RED] References on RED (Random Early Detection) Queue Management http://www.icir.org/floyd/red.html [FLO+93] Random Early Detection gateways for Congestion Avoidance http://www.icir.org/floyd/papers/red/red.html [FAQPF] OpenBSD FAQ : PF: Queueing http://www.openbsd.org/faq/pf/queueing.html [FLO+01] Adaptive RED : An Algorithm for Increasing the Robustness of RED's Active Queue Management http://www.icir.org/floyd/papers/adaptiveRed.pdf [CONAV] Congestion Avoidance Overview http://www.cisco.com/univercd/cc/td/doc/product/software/ios121/121cgcr/qos_c/qcprt3/qcdconav.htm [WRED] Configuring Weighted Random Early Detection http://www.cisco.com/univercd/cc/td/doc/product/software/ios121/121cgcr/qos_c/qcprt3/qcdwred.htm [CBWRD] Class-Based Weighted Fair Queueing and Weighted Random Early Detection for the VIP Using the Modular QoS CLI http://www.cisco.com/univercd/cc/td/doc/product/software/ios120/120newft/120limit/120xe/120xe5/mqc/mqcfm/cbdwred.htm [REM01] REM : Active Queue Management http://netlab.caltech.edu/pub/papers/cbef.pdf [ECN] ECN (Explicit Congestion Notification) in TCP/IP http://www.icir.org/floyd/ecn.html [3168] The Addition of Explicit Congestion Notification (ECN) to IP http://www.ietf.org/rfc/rfc3168.txt [PROB] ECN Problems http://www.icir.org/floyd/ecnProblems.html [WRDECN] WRED : Explicit Congestion Notification http://www.cisco.com/univercd/cc/td/doc/product/software/ios122/122newft/122t/122t8/ftwrdecn.htm [CAR] Committed Access Rate http://www.cisco.com/univercd/cc/td/doc/product/software/ios111/cc111/car.htm [QRF] Cisco IOS Quality of Service Solutions Command Reference, Release 12.2 http://www.cisco.com/univercd/cc/td/doc/product/software/ios122/122cgcr/fqos_r/ [TIPS] ALTQ Tips http://www.csl.sony.co.jp/person/kjc/TIPS.txt [TBF] LARTC : 9.2.2. Token Bucket Filter http://lartc.org/howto/lartc.qdisc.classless.html#AEN691 [POL] LARTC : 12.3. Policing filters http://lartc.org/howto/lartc.adv-filter.policing.html [FRO] Ipsysctl tutorial 1.0.4 : 3.4 ICMP Variables http://ipsysctl-tutorial.frozentux.net/chunkyhtml/icmpvariables.html [CAST] Configuring Broadcast/Multicast Suppression http://www.cisco.com/en/US/products/hw/switches/ps679/products_configuration_guide_chapter09186a008007f77e.html [ACC] Aggregate-Based Congestion Control (ACC) and Pushback http://www.icir.org/pushback/ [IOA+02] Implementing Pushback : Router-based Defense against DDoS Attack http://www.isoc.org/isoc/conferences/ndss/02/proceedings/papers/ioanni.pdf [CBAC] Configuring Global Timeouts and Thresholds http://www.cisco.com/univercd/cc/td/doc/product/software/ios121/121cgcr/secur_c/scprt3/scdcbac.htm#xtocid27 [SANS] CBAC - Cisco IOS Firewall Feature Set Foundations http://rr.sans.org/firewall/CBAC.php [BYPASS] Firewall ACL Bypass http://www.cisco.com/univercd/cc/td/doc/product/software/ios123/123newft/123t/123t_4/gt_aclby.htm [CSYN] Configuring TCP Intercept (Prevent Denial-of-Service Attacks) http://www.cisco.com/univercd/cc/td/doc/product/software/ios113ed/113ed_cr/secur_c/scprt3/scdenial.htm [TWT] Patch-O-Matic Listing - extra : tcp-window-tracking http://www.netfilter.org/documentation/pomlist/pom-extra.html#tcp-window-tracking [PF] OpenBSD Packet Filter http://www.benzedrine.cx/pf.html [MANPF] pf.conf(5) http://www.openbsd.org/cgi-bin/man.cgi?query=pf.conf&sektion=5&arch=i386&apropos=0&manpath=OpenBSD+Current [MFA] Maximizing Firewall Availability : Techniques on Improving Resilience to Session Table DoS Attacks http://www.qorbit.net/documents/maximizing-firewall-availability.htm [DJB] SYN Cookies http://cr.yp.to/syncookies.html [LEM02] Resisting SYN flood DoS attacks with SYN cache http://people.freebsd.org/~jlemon/papers/syncache.pdf [PREL] Prelude Hybrid IDS http://www.prelude-ids.org [SNORT] Snort.org http://www.snort.org [GRD] Official Guardian Web http://www.chaotic.org/guardian/ [SAM] SnortSam http://www.snortsam.net/ [ALTQ] ALTQ : Alternate Queueing for BSD UNIX http://www.csl.sony.co.jp/person/kjc/programs.html#ALTQ [IPR2] iproute2 http://www.lartc.org/howto ------------------------------------------------------------------------------- Copyright (c) 2003 CNS Free Document Dissemination Licence -- FDDL version 1 http://pauillac.inria.fr/~lang/licence/v1/fddl.html This document may be freely read, stored, reproduced, disseminated, translated or quoted by any means and on any medium provided the following conditions are met: * every reader or user of this document acknowledges that he his aware that no guarantee is given regarding its contents, on any account, and specifically concerning veracity, accuracy and fitness for any purpose; * no modification is made other than cosmetic, change of representation format, translation, correction of obvious syntactic errors, or as permitted by the clauses below; * comments and other additions may be inserted, provided they clearly appear as such; translations or fragments must clearly refer to an original complete version, preferably one that is easily accessed whenever possible; * translations, comments and other additions must be dated and their author(s) must be identifiable (possibly via an alias); * this licence is preserved and applies to the whole document with modifications and additions (except for brief quotes), independently of the representation format; * whatever the mode of storage, reproduction or dissemination, anyone able to access a digitized version of this document must be able to make a digitized copy in a format directly usable, and if possible editable, according to accepted, and publicly documented, public standards; * redistributing this document to a third party requires simultaneous redistribution of this licence, without modification, and in particular without any further condition or restriction, expressed or implied, related or not to this redistribution. In particular, in case of inclusion in a database or collection, the owner or the manager of the database or the collection renounces any right related to this inclusion and concerning the possible uses of the document after extraction from the database or the collection, whether alone or in relation with other documents. Any incompatibility of the above clauses with legal, contractual or judiciary decisions or constraints implies a corresponding limitation of reading, usage, or redistribution rights for this document, verbatim or modified.