Generierung von User Space-Verkehr


Verkehrserzeugung durch MoonGen + DPDK + Lua aus Sicht des Künstlers

Die Neutralisierung von DDoS-Angriffen unter realen Bedingungen erfordert vorläufige Tests und Tests verschiedener Techniken. Netzwerkgeräte und -software sollten unter künstlichen Bedingungen getestet werden, die den realen Bedingungen nahe kommen - mit intensiven Verkehrsströmen, die Angriffe simulieren. Ohne solche Experimente ist es äußerst schwierig, zuverlässige Informationen über die spezifischen Merkmale und Einschränkungen eines komplexen Werkzeugs zu erhalten.

In diesem Artikel werden einige der in Qrator Labs verwendeten Methoden zur Generierung von Datenverkehr vorgestellt.

WARNUNG

Wir empfehlen dem Leser dringend, die genannten Tools nicht zum Angriff auf Objekte mit realer Infrastruktur zu verwenden. Die Organisation von DoS-Angriffen ist gesetzlich strafbar und kann zu schweren Strafen führen. Qrator Labs führt alle Tests in einer isolierten Laborumgebung durch.

Modernes technisches Niveau


Eine wichtige Aufgabe in unserem Bereich ist die Sättigung der 10G-Ethernet-Schnittstelle mit kleinen Paketen, was die Verarbeitung von 14,88 Mpps (Millionen von Paketen pro Sekunde) impliziert. Im Folgenden betrachten wir die kleinsten Ethernet-Netzwerkpakete - 64 Byte -, da unser Hauptinteresse darin besteht, die Anzahl der übertragenen Pakete pro Zeiteinheit zu maximieren. Eine einfache Berechnung zeigt, dass wir nur etwa 67 Nanosekunden haben, um ein solches Paket zu verarbeiten.

Nur zum Vergleich: Diese Zeit entspricht in etwa dem, was ein moderner Prozessor benötigt, um Daten aus dem Speicher abzurufen, wenn der Cache fehlt. Alles wird noch komplizierter, wenn wir mit 40G- und 100G-Ethernet-Schnittstellen arbeiten und versuchen, diese bis zur Leitungsrate (der maximal möglichen deklarierten Leistung des Netzwerkgeräts) vollständig zu sättigen.

Da der Datenfluss im Normalfall durch die Anwendung im Benutzerbereich (Userspace) und dann durch den Kernel und schließlich zum Netzwerkcontroller (NIC) geleitet wird, besteht die erste und einfachste Idee darin, die Paketerzeugung direkt im Kernel zu konfigurieren. Ein Beispiel für eine solche Lösung ist das Kernmodul pktgen [2]. Mit dieser Methode können Sie die Leistung erheblich verbessern, sind jedoch nicht flexibel genug, da die geringste Änderung des Quellcodes im Kernel zu einem langen Erstellungszyklus, einem Neustart der Kernelmodule oder sogar des gesamten Systems und in der Tat zu Tests führt, wodurch die Gesamtproduktivität verringert wird (dh der Programmierer benötigt mehr Zeit) und Anstrengung).

Ein anderer möglicher Ansatz besteht darin, direkten Zugriff vom Benutzerbereich auf die Speicherpuffer des Netzwerkcontrollers zu erhalten. Dieser Weg ist komplizierter, aber die Mühe wert, eine höhere Produktivität zu erzielen. Nachteile sind hohe Komplexität und geringe Flexibilität. Beispiele für diesen Ansatz sind Netmap , PF_RING und DPDK [4].

Ein weiterer effektiver, wenn auch sehr kostspieliger Weg, um eine hohe Leistung zu erzielen, ist die Verwendung nicht universeller, sondern spezialisierter Geräte. Beispiel: Ixia .

Es gibt auch Lösungen, die auf DPDK basieren und Skripte verwenden. Dies erhöht die Flexibilität bei der Steuerung der Generatorparameter und ermöglicht es Ihnen, die Art der beim Start generierten Pakete zu variieren. Im Folgenden beschreiben wir unsere eigenen Erfahrungen mit einem dieser Tools - MoonGen.

MoonGen-Architektur


Besonderheiten von MoonGen sind:

  1. Die Verarbeitung von DPDK-Daten im Benutzerbereich ist der Hauptgrund für den Leistungsgewinn.
  2. Lua [ 5 ] -Stapel mit einfachen Skripten auf der obersten Ebene und Bindungen an die in C geschriebene DPDK-Bibliothek unten;
  3. Dank der JIT-Technologie (just in time) arbeiten Lua-Skripte schnell genug, was den allgemein akzeptierten Vorstellungen über die Effektivität von Skriptsprachen etwas widerspricht.

MoonGen kann als Lua-Wrapper um die DPDK-Bibliothek betrachtet werden. Auf der Ebene der Lua-Benutzeroberfläche sind mindestens die folgenden DPDK-Vorgänge sichtbar:

  • Netzwerkcontroller konfigurieren;
  • Zuweisung und direkter Zugriff auf Pools und Speicherpuffer, die zu Optimierungszwecken in kontinuierlich ausgerichteten Bereichen zugewiesen werden sollten;
  • Direkter Zugriff auf RSS-Warteschlangen von Netzwerkcontrollern;
  • API zur Verwaltung von Rechenabläufen unter Berücksichtigung der Heterogenität des Speicherzugriffs (NUMA- und CPU-Affinität) [ 12 ].



MoonGen-Architektur, Schema aus Material [ 1 ].

Moongen


MoonGen ist ein Skript-Hochgeschwindigkeitspaketgenerator, der auf der DPDK-Bibliothek basiert. Lua-Skripte steuern den gesamten Prozess: Das vom Benutzer erstellte Skript ist für das Erstellen, Ändern und Senden von Paketen verantwortlich. Dank der sehr schnellen LuaJIT- und DPDK-Paketverarbeitungsbibliothek können Sie mit dieser Architektur eine 10-Gigabit-Ethernet-Schnittstelle mit 64-Byte-Paketen mit nur einem Kern der CPU sättigen. Mit MoonGen können Sie diese Geschwindigkeit auch dann erreichen, wenn das Lua-Skript jedes Paket ändert. Es werden keine Tricks wie die Wiederverwendung des gleichen Puffers des Netzwerkcontrollers verwendet.

MoonGen kann auch Pakete empfangen, d. H. Überprüfen, welche Pakete vom zu testenden System verworfen wurden. Da der Paketempfang ausschließlich von einem benutzerdefinierten Lua-Skript gesteuert wird, können damit auch komplexere Testskripte erstellt werden. Sie können beispielsweise zwei Instanzen von MoonGen verwenden, um eine Verbindung untereinander herzustellen. Eine solche Konfiguration kann insbesondere zum Testen der sogenannten mittleren Boxen (Geräte zwischen dem Sende- und Empfangspunkt des Verkehrs), beispielsweise Firewalls, verwendet werden. MoonGen konzentriert sich auf vier Hauptbereiche:

  • Hohe Leistung und Multi-Core-Skalierung: mehr als 20 Millionen Pakete pro Sekunde auf einem einzelnen CPU-Kern;
  • Flexibilität: Jedes Paket wird in Echtzeit basierend auf einem vom Benutzer erstellten Lua-Skript generiert.
  • Genaue Zeitstempel: Bei normaler (Standard-) Hardware wird die Zeitmarkierung mit Millisekundengenauigkeit durchgeführt.
  • Genaue Kontrolle der Intervalle zwischen gesendeten Paketen: zuverlässige Erzeugung der erforderlichen Muster und Verkehrstypen auf normaler Hardware.

DPDK


DPDK steht für Data Plane Development Kit und besteht aus Bibliotheken, deren Hauptfunktionen darin bestehen, die Leistung beim Generieren von Netzwerkpaketen auf einer Vielzahl von Zentralprozessorarchitekturen zu steigern.

In einer Welt, in der Computernetzwerke zur Grundlage menschlicher Kommunikation werden, werden Leistung, Bandbreite und Latenz zunehmend zu kritischen Parametern für Systeme wie drahtlose Netzwerke und Kabelinfrastruktur, einschließlich aller ihrer einzelnen Komponenten: Router, Load Balancer, Firewalls; sowie Anwendungsbereiche: Medientransfer (Streaming), VoIP usw.

DPDK ist eine einfache und bequeme Möglichkeit, Tests und Skripte zu erstellen. Die Datenübertragung innerhalb des Benutzerraums wird nicht so häufig beobachtet, hauptsächlich weil die meisten Anwendungen über das Betriebssystem und den Kernel-Stack mit Netzwerkgeräten kommunizieren, was das Gegenteil des DPDK-Modells ist.

Lua


Der Hauptzweck der Existenz von Lua besteht darin, einfache und flexible Ausdruckswerkzeuge bereitzustellen, die für bestimmte aktuelle Aufgaben erweiterbar sind, anstatt einer Reihe von Grundelementen, die nur in einem Programmierparadigma anwendbar sind. Infolgedessen ist die Basissprache sehr leicht - der gesamte Interpreter benötigt nur 180 kB in kompilierter Form und passt sich problemlos an eine Vielzahl möglicher Implementierungen an.

Lua ist eine dynamische Sprache. Es ist so kompakt, dass es auf fast jedem Gerät platziert werden kann. Lua unterstützt eine kleine Reihe von Typen: Boolesche Werte, Zahlen (Gleitkomma mit doppelter Genauigkeit) und Zeichenfolgen. Herkömmliche Datenstrukturen wie Arrays, Mengen und Listen können durch die einzige in Lua integrierte Datenstruktur dargestellt werden - eine Tabelle, die ein heterogenes assoziatives Array ist.

Lua verwendet die JIT-Kompilierung (just in time) und zeigt daher als Skriptsprache eine Leistung, die mit kompilierten Sprachen wie C vergleichbar ist [ 10 ].

Warum Moongen?


Als Unternehmen, das sich auf die Neutralisierung von DDoS-Angriffen spezialisiert hat, benötigt Qrator Labs eine zuverlässige Methode zum Erstellen, Aktualisieren und Testen eigener Sicherheitslösungen. Für letztere Tests werden verschiedene Methoden zur Generierung von Datenverkehr benötigt, die echte Angriffe simulieren. Es ist jedoch nicht so einfach, einen gefährlichen, aber unkomplizierten Hochwasserangriff auf 2-3 Ebenen des OSI-Modells zu simulieren, vor allem aufgrund der Schwierigkeiten, eine hohe Leistung bei der Paketerzeugung zu erzielen.

Mit anderen Worten, für ein Unternehmen, das sich mit der kontinuierlichen Verfügbarkeit und Neutralisierung von DDoS befasst, ist die Simulation verschiedener DoS-Angriffe in einer isolierten Laborumgebung eine Möglichkeit zu verstehen, wie sich die verschiedenen Geräte, die Teil der Hardwarekomplexe des Unternehmens sind, in der Realität verhalten.

MoonGen ist eine gute Möglichkeit, mit einem Minimum an CPU-Kernen Verkehrswerte zu generieren, die nahe am Grenzwert für den Netzwerkcontroller liegen. Die Datenübertragung innerhalb des Benutzerraums verbessert die Leistung des betreffenden Stapels (MoonGen + DPDK) im Vergleich zu vielen anderen Optionen zum Generieren hoher Verkehrswerte erheblich. Die Verwendung von reinem DPDK erfordert viel mehr Aufwand, daher sollten Sie sich nicht über unseren Wunsch wundern, die Leistung zu optimieren. Wir unterstützen auch einen Klon [ 7 ] des ursprünglichen MoonGen-Repositorys, um die Funktionalität und Implementierung unserer eigenen Tests zu erweitern.

Um maximale Flexibilität zu erreichen, wird die Logik zum Generieren von Paketen vom Benutzer mithilfe des Lua-Skripts festgelegt, das eine der Hauptfunktionen von MoonGen ist. Bei einer relativ einfachen Paketverarbeitung arbeitet diese Lösung schnell genug, um die 10G-Schnittstelle auf einem einzelnen CPU-Kern zu sättigen. Eine typische Möglichkeit, eingehende Pakete zu ändern und neue zu erstellen, besteht darin, mit Paketen desselben Typs zu arbeiten, in denen sich nur einige Felder ändern.

Ein Beispiel ist der unten beschriebene l3-tcp-syn-ack-Flut-Test. Beachten Sie, dass jede Änderung des Pakets in demselben Puffer vorgenommen werden kann, in dem sich das im vorherigen Schritt generierte oder empfangene Paket herausgestellt hat. In der Tat werden solche Paketkonvertierungen sehr schnell durchgeführt, da sie keine teuren Vorgänge wie Systemaufrufe, Zugriff auf möglicherweise nicht zwischengespeicherte Speicherabschnitte und dergleichen beinhalten.

Tests auf Qrator Labs-Hardware


Qrator Labs führt alle Tests im Labor an verschiedenen Geräten durch. In diesem Fall haben wir die folgenden Netzwerkschnittstellen-Controller verwendet:

  • Intel 82599ES 10G
  • Mellanox ConnectX-4 40G
  • Mellanox ConnectX-5 100G

Wir stellen separat fest, dass bei der Arbeit mit Netzwerkcontrollern, die mit Standards über 10 G arbeiten, das Leistungsproblem immer akuter wird. Heute ist es nicht möglich, die 40G-Schnittstelle mit einem Kern zu sättigen, obwohl dies mit einer kleinen Anzahl von Kernen bereits realistisch ist.

Bei von Mellanox hergestellten Netzwerkcontrollern können einige Parameter und Einstellungen des Geräts mithilfe der vom Hersteller bereitgestellten Tuning-Anleitung [ 3 ] geändert werden. Auf diese Weise können Sie die Leistung steigern und in einigen besonderen Fällen das Verhalten der Netzwerkkarte vertiefen. Andere Hersteller verfügen möglicherweise über ähnliche Dokumente für ihre eigenen Hochleistungsgeräte, die für den professionellen Gebrauch bestimmt sind. Auch wenn Sie ein solches Dokument nicht öffentlich finden können, ist es immer sinnvoll, sich direkt an den Hersteller zu wenden. In unserem Fall waren die Vertreter von Mellanox sehr nett und beantworteten neben der Dokumentation schnell unsere Fragen, wodurch wir eine 100% ige Auslastung des Streifens erreichen konnten, was für uns sehr wichtig war.

TCP SYN Fluttest


L3-tcp-syn-ack-Flut ist ein Beispiel für die Simulation eines Angriffs wie SYN-Flut [ 6 ]. Dies ist eine erweiterte Qrator Labs-Version des l3-tcp-syn-Flood-Tests aus dem Haupt-Repository von MoonGen, das in unserem Repository-Klon gespeichert ist.

Unser Test kann drei Arten von Prozessen ausführen:

  1. Generieren Sie einen TCP-SYN-Paketstrom von Grund auf neu, indem Sie die erforderlichen Felder wie Quell-IP-Adresse, Quellportnummer usw. variieren.
  2. Erstellen Sie eine gültige ACK-Antwort für jedes empfangene SYN-Paket gemäß TCP.
  3. Erstellen Sie eine gültige SYN-ACK-Antwort für jedes empfangene ACK-Paket gemäß dem TCP-Protokoll.

Die interne (bzw. die "heißeste") Codeschleife zum Erstellen von ACK-Antworten lautet beispielsweise wie folgt:

local tx = 0 local rx = rxQ:recv(rxBufs) for i = 1, rx do local buf = rxBufs[i] local pkt = buf:getTcpPacket(ipv4) if pkt.ip4:getProtocol() == ip4.PROTO_TCP and pkt.tcp:getSyn() and (pkt.tcp:getAck() or synack) then local seq = pkt.tcp:getSeqNumber() local ack = pkt.tcp:getAckNumber() pkt.tcp:unsetSyn() pkt.tcp:setAckNumber(seq+1) pkt.tcp:setSeqNumber(ack) local tmp = pkt.ip4.src:get() pkt.ip4.src:set(pkt.ip4.dst:get()) pkt.ip4.dst:set(tmp) … -- some more manipulations with packet fields tx = tx + 1 txBufs[tx] = buf end end if tx > 0 then txBufs:resize(tx) txBufs:offloadTcpChecksums(ipv4) -- offload checksums to NIC txQ:send(txBufs) end 

Die allgemeine Idee zum Erstellen eines Antwortpakets lautet wie folgt. Zuerst müssen Sie das Paket aus der Empfangswarteschlange entfernen und dann prüfen, ob der Pakettyp mit dem erwarteten übereinstimmt. Bereiten Sie im Falle eines Zufalls eine Antwort vor, indem Sie einige Felder des Originalpakets ändern. Fügen Sie das erstellte Paket schließlich mit demselben Puffer in die TX-Warteschlange ein. Um die Leistung zu verbessern, anstatt Pakete einzeln zu nehmen und einzeln zu ändern, aggregieren wir sie, extrahieren alle verfügbaren Pakete aus der Empfangswarteschlange, erstellen die entsprechenden Antworten und stellen sie alle in die TX-Warteschlange. Trotz einer relativ großen Anzahl von Manipulationen an einem Paket bleibt die Leistung hoch, hauptsächlich aufgrund der Tatsache, dass Lua JIT all diese Operationen in einer kleinen Anzahl von Prozessoranweisungen kompiliert. Viele andere Tests, nicht nur TCP SYN / ACK, arbeiten nach dem gleichen Prinzip.

Die folgende Tabelle zeigt die Ergebnisse des SYN-Fluttests (SYN-Generierung ohne Antwortversuche) mit Mellanox ConnectX-4. Diese Netzwerkkarte verfügt über zwei 40G-Ports mit einer theoretischen Leistungsobergrenze von 59,52 Mpps an einem Port und 2 * 50 Mpps für zwei Ports. Die spezifische Implementierung des Verbindens der Netzwerkkarte mit PCIe schränkt die Bandbreite etwas ein (2 * 50 anstelle der erwarteten 2 * 59,52).
Kerne pro Port1 Port, Mpps2 Ports, Mpps pro Port
12019
23836
356,547
459,550

SYN-Hochwassertest; Netzwerkkarte: Mellanox Technologies MT27700-Familie (ConnectX-4), dualer 40G-Port; CPU: Intel® Xeon® Silver 4114 CPU bei 2,20 GHz

Die folgende Tabelle zeigt die Ergebnisse des gleichen SYN-Fluttests, der an einem Mellanox ConnectX-5 mit einem 100G-Port durchgeführt wurde.
KerneMpps
135
269
3104
4127
5120
6131
7132
8144

SYN-Hochwassertest; Netzwerkkarte: Mellanox Technologies MT27800-Familie (ConnectX-5), einzelner 100G-Port; CPU: Intel® Xeon® Silver 4114 CPU bei 2,20 GHz

Beachten Sie, dass wir in allen Fällen mehr als 96% der theoretischen Leistungsobergrenze für eine kleine Anzahl von Prozessorkernen erreichen.

Erfassen Sie eingehenden Datenverkehr und speichern Sie ihn in PCAP-Dateien


Ein weiteres Beispiel für den Test ist rx-to-pcap, bei dem versucht wird, den gesamten eingehenden Datenverkehr zu erfassen und in einer bestimmten Anzahl von PCAP-Dateien zu speichern [ 8 ]. Obwohl dieser Test nicht speziell die Generierung von Paketen als solche betrifft, dient er als Beweis dafür, dass das Dateisystem das schwächste Glied bei der Organisation der Datenübertragung über den Benutzerbereich ist. Selbst das virtuelle Dateisystem von tmpfs verlangsamt den Stream erheblich. In diesem Fall werden 8 Kerne des Zentralprozessors für die Nutzung von 14,88 Mpps benötigt, während nur ein Kern ausreicht, um dieselbe Menge an Datenverkehr zu empfangen (und zurückzusetzen oder umzuleiten).

Die folgende Tabelle zeigt den Datenverkehr (in Mpps), der empfangen und in PCAP-Dateien gespeichert wurde, die sich im ext2-Dateisystem auf der SSD (zweite Spalte) oder im tmpfs-Dateisystem (dritte Spalte) befinden.
Kerneauf SSD, Mppsauf tmpfs, Mpps
11.481,62
244.6
36.948.1
49,7511.65
512.113.8
613.3814.47
714.414.86
814.8814.88

Rx-to-pcap-Test; Netzwerkkarte: Intel 82599ES 10-Gigabit; CPU: Intel® Xeon® CPU E5-2683 v4 bei 2,10 GHz

MoonGen-Änderung: tman Task Manager


Wir möchten dem Leser auch unsere eigene Erweiterung der MoonGen-Funktionalität vorstellen, die eine weitere Möglichkeit bietet, eine Gruppe von Aufgaben zum Testen zu starten. Die Hauptidee hierbei ist es, die allgemeine Konfiguration und die Einstellungen für jede Aufgabe zu trennen, sodass Sie eine beliebige Anzahl verschiedener Aufgaben (d. H. Lua-Skripte) gleichzeitig ausführen können. In unserem Klon des MoonGen-Repositorys wird die Implementierung von MoonGen mit dem Task-Manager [ 9 ] vorgestellt. Hier werden die Hauptfunktionen nur kurz aufgelistet.

Über die neue Befehlszeilenschnittstelle können Sie mehrere Aufgaben unterschiedlichen Typs gleichzeitig ausführen. Das Grundszenario lautet wie folgt:

 ./build/tman [tman options...] [-- <task1-file> [task1 options...]] [-- <task2-file> [task2 options...]] [-- ...] 

Zusätzlich bietet ./build/tman -h detaillierte Hilfe.

Es gibt jedoch eine Einschränkung: Normale Lua- Jobdateien sind nicht mit der tman- Schnittstelle kompatibel. Die tman-Jobdatei sollte die folgenden Objekte klar definieren:

  • Die Funktion configure (Parser), die die Jobparameter beschreibt.
  • Die Taskfunktion (taskNum, txInfo, rxInfo, args), die den eigentlichen Taskprozess beschreibt. Hier sind txInfo und rxInfo Arrays von RX- bzw. TX-Warteschlangen; args enthält die Parameter des Task-Managers und der Task selbst.
  • Beispiele finden Sie in examples / tman.

Die Verwendung des Task-Managers bietet Ihnen mehr Flexibilität beim Ausführen heterogener Tests.

Schlussfolgerungen


Die von MoonGen angebotene Methode hat sich als gut für unsere Ziele erwiesen und die Mitarbeiter mit den erzielten Ergebnissen zufrieden gestellt. Wir haben ein Tool mit hoher Leistung erhalten, bei dem sowohl die Testumgebung als auch die Sprache recht einfach sind. Die hohe Leistung dieses Setups wird dank zweier Hauptmerkmale erreicht: direkter Zugriff auf die Puffer der Netzwerkschnittstellen-Controller und Just-In-Time-Kompilierungstechnik in Lua.

In der Regel ist das Erreichen einer theoretischen Obergrenze für die Leistung eines Netzwerkschnittstellen-Controllers eine realisierbare Aufgabe. Wie wir gezeigt haben, kann ein einzelner Kern ausreichen, um einen 10G-Port zu sättigen, während eine volle Auslastung eines 100G-Ports bei einer größeren Anzahl von Kernen kein besonderes Problem darstellt.

Wir danken insbesondere dem Mellanox-Team für die Hilfe bei der Ausrüstung und dem MoonGen-Team für die Reaktion auf die Korrektur der Fehler.

Material


  1. MoonGen: Ein skriptfähiger Hochgeschwindigkeitspaketgenerator - Paul Emmerich et al., Internet Measurement Conference 2015 (IMC'15), 2015
  2. Pktgen
  3. Mellanox Tuning Guide
  4. Data Plane Development Kit
  5. Lua
  6. Syn Flut
  7. Qrator Labs 'Klon des MoonGen-Repositorys
  8. PCAP-Dateiformat
  9. Task-Manager
  10. Lua Leistung
  11. Whitepaper zur Netzwerkfunktionen-Virtualisierung
  12. NUMA, ungleichmäßiger Speicherzugriff

Source: https://habr.com/ru/post/de423957/


All Articles