diff --git a/doc/review_3/chapters/1-einleitung.tex b/doc/review_3/chapters/1-einleitung.tex index fdb425d..5985256 100644 --- a/doc/review_3/chapters/1-einleitung.tex +++ b/doc/review_3/chapters/1-einleitung.tex @@ -6,12 +6,12 @@ \section{Problemstellung} Denial-of-Service-Angriffe stellen eine ernstzunehmende und stetig wachsende Bedrohung dar. -Im digitalen Zeitalter sind viele Systeme über das Internet oder private Netzwerke miteinander verbunden. Viele Unternehmen, Krankenhäuser und Behörden sind durch unzureichende Schutzmaßnahmen und große Wirkung zu beliebten Angriffszielen geworden\cite{infopoint_security_cyber_angriffe}. Bei solchen Angriffe werden in der Regel finanzielle oder auch politische Gründe verfolgt, selten aber auch die bloße Störung oder Destruktion des Ziels. +Im digitalen Zeitalter sind viele Systeme über das Internet oder private Netzwerke miteinander verbunden. Viele Unternehmen, Krankenhäuser und Behörden sind durch unzureichende Schutzmaßnahmen und große Wirkung zu beliebten Angriffszielen geworden\cite{infopoint_security_cyber_angriffe}. Bei solchen Angriffen werden in der Regel finanzielle oder auch politische Gründe verfolgt, selten aber auch die bloße Störung oder Destruktion des Ziels. Bei DoS\footnote{Denial of Service, dt.: Verweigerung des Dienstes, Nichtverfügbarkeit des Dienstes}- und DDoS\footnote{Distributed Denial of Service}-Attacken werden Server und Infrastrukturen mit einer Flut sinnloser Anfragen so stark überlastet, dass sie von ihrem normalen Betrieb abgebracht werden. Daraus kann resultieren, dass Nutzer die angebotenen Dienste des Betreibers nicht mehr erreichen und Daten bei dem Angriff verloren gehen können. Hierbei können schon schwache Rechner große Schaden bei deutlich leistungsfähigeren Empfängern auslösen. In Botnetzen können die Angriffe zusätzlich von mehreren Computern gleichzeitig koordiniert werden, aus verschiedensten Netzwerken stammen \cite{tecchannel_gefahr_botnet} und damit gleichzeitig die Angriffskraft verstärken und die Erkennung erschweren. -Das Ungleichgewicht zwischen der Einfachheit bei der Erzeugung von Angriffen gegenüber komplexer und ressourcenintensiver DoS-Abwehr verschärft das Problem zusätzlich. Obwohl gelegentlich Erfolge im Kampf gegen DoS-Angriffe erzielt werden (z.B. Stilllegung einiger großer ,,DoS-for-Hire'' Webseiten), vergrößert sich das Datenvolumen der DoS-Angriffe stetig weiter. Allein zwischen 2014 und 2017 hat sich die Frequenz von DoS-Angriffen um den Faktor 2,5 vergrößert und das Angriffsvolumen verdoppelt sich fast jährlich \cite{neustar_ddos_report}. Die Schäden werden weltweit zwischen 20.000 und 40.000 US-Dollar pro Stunde geschätzt \cite{datacenterknowledge_study}. +Das Ungleichgewicht zwischen der Einfachheit bei der Erzeugung von Angriffen gegenüber komplexer und ressourcenintensiver DoS-Abwehr verschärft das Problem zusätzlich. Obwohl gelegentlich Erfolge im Kampf gegen DoS-Angriffe erzielt werden (z.B. Stilllegung einiger großer \glqq DoS-for-Hire\grqq{} Webseiten), vergrößert sich das Datenvolumen der DoS-Angriffe stetig weiter. Allein zwischen 2014 und 2017 hat sich die Frequenz von DoS-Angriffen um den Faktor 2,5 vergrößert und das Angriffsvolumen verdoppelt sich fast jährlich \cite{neustar_ddos_report}. Die Schäden werden weltweit zwischen 20.000 und 40.000 US-Dollar pro Stunde geschätzt \cite{datacenterknowledge_study}. Im Bereich kommerzieller DoS-Abwehr haben sich einige Ansätze hervorgetan (z.B. Project Shield\cite{projectshield}, Cloudflare\cite{cloudflare} oder AWS Shield\cite{aws_shield}). Der Einsatz kommerzieller Lösungen birgt jedoch einige Probleme, etwa mitunter erhebliche Kosten oder das Problem des notwendigen Vertrauens, welches dem Betreiber einer DoS-Abwehr entgegengebracht werden muss. Folglich ist eine effiziente Abwehr von DoS-Angriffen mit eigenen Mitteln ein oft gewünschtes Ziel - insbesondere wenn sich dadurch mehrere Systeme zugleich schützen lassen. @@ -32,11 +32,11 @@ Zu Beginn des Projekts wurde sich auf den Unified Process als Vorgehensmodell ge Dieses dritte Review-Dokument bezieht sich auf die Validierungssphase. Das heißt, dass es auf den Ergebnissen der vorhergehenden Phase und dem zweiten Review-Dokument vom 23. Juni 2021 aufbaut. -Das erste Review-Dokument enthält die gängigen Inhalte eines Pflichtenhefts wie die funktionalen und nicht-funktionalen Anforderungen, eine Aufwands- und Risikoanalyse und Überlegungen zum Vorgehen und der internen Organisation. Außerdem umfasste es eine Entwurfsdokumentation für den Grobentwurf, die Anforderungsanalyse, ein Kapitel zu den Technologien und Entwicklungswerkzeugen, Ergebnisse zu den Machbarkeitsanalysen und Beispielrealisierungen und ein Testdrehbuch. +Das erste Review-Dokument enthält die gängigen Inhalte eines Pflichtenhefts wie die funktionalen und nicht-funktionalen Anforderungen, eine Aufwands- und Risikoanalyse und Überlegungen zum Vorgehen und der internen Organisation. Außerdem umfasst es eine Entwurfsdokumentation für den Grobentwurf, die Anforderungsanalyse, ein Kapitel zu den Technologien und Entwicklungswerkzeugen, Ergebnisse zu den Machbarkeitsanalysen und Beispielrealisierungen und ein Testdrehbuch. -Im zweiten Review-Dokument wurden im Kapitel zum Grobentwurf zusätzlich zur erneuten Erläuterung der grundlegenden Architektur die für den Unified Process üblichen Überarbeitungen des Grobentwurfs dargestellt und begründet. Dabei wurde, genauso wie beim darauffolgenden Feinentwurf, Paket für Paket vorgegangen. Schließlich wurden in einem Bug-Review die offenen Anforderungen und Fehler beschrieben und die mittels des Tools Kimai erfassten Arbeitszeiten ausgewertet. +Im zweiten Review-Dokument werden im Kapitel zum Grobentwurf zusätzlich zur erneuten Erläuterung der grundlegenden Architektur die für den Unified Process üblichen Überarbeitungen des Grobentwurfs dargestellt und begründet. Dabei wird, genauso wie beim darauffolgenden Feinentwurf, Paket für Paket vorgegangen. Schließlich werdeb in einem Bug-Review die offenen Anforderungen und Fehler beschrieben und die mittels des Tools Kimai erfassten Arbeitszeiten ausgewertet. -In diesem dritten Review-Dokument kommt nun ein ausführliches Kapitel zu sämtlichen Tests dazu. Außerdem behandelt es verschiedene Softwaremetriken und Statistiken, wie Konventionen und den Umfang der Software. Das Kapitel zur Auswertung der erfassten Arbeitszeiten enthält nun auch diese letzte Phase des Softwareprojekts. Am Ende des Dokuments kommt es zur umfangreichen Auswertung des Projekts. +In diesem dritten Review-Dokument kommt nun ein ausführliches Kapitel zu sämtlichen Tests dazu. Außerdem behandelt es verschiedene Softwaremetriken und Statistiken, wie Konventionen und den Umfang der Software. Das Kapitel zur Auswertung der erfassten Arbeitszeiten enthält nun auch diese letzte Phase des Softwareprojekts. Am Ende des Dokuments kommt es zu einer umfangreichen Auswertung des Projekts. Es bleibt also anzumerken, dass einige Teile dieses Dokuments dem ersten und zweiten Review-Dokument entnommen sind, weil dies vom Fachgebiet empfohlen wurde und dadurch die Veränderungen besonders gut dargestellt werden können. diff --git a/doc/review_3/chapters/10-abkuerzungsverzeichnis.tex b/doc/review_3/chapters/10-abkuerzungsverzeichnis.tex index 54208c0..42d873e 100644 --- a/doc/review_3/chapters/10-abkuerzungsverzeichnis.tex +++ b/doc/review_3/chapters/10-abkuerzungsverzeichnis.tex @@ -7,7 +7,7 @@ \item[DDoS] Distributed Denial-of-Service \item[DoS] Denial-of-Service \item[DRoS] Distributed Reflected Denial-of-Service - \item[Gbps] Giga bit pro sekunde + \item[Gbps] Giga bit pro Sekunde \item[KW] Kalenderwoche \item[LoC] Lines of Code \item[Mpps] Million packets per second diff --git a/doc/review_3/chapters/2-grobentwurf.tex b/doc/review_3/chapters/2-grobentwurf.tex index b93d0c7..6cb5049 100644 --- a/doc/review_3/chapters/2-grobentwurf.tex +++ b/doc/review_3/chapters/2-grobentwurf.tex @@ -11,7 +11,7 @@ In folgendem Unterkapitel werden die grundlegenden Entscheidungen des Entwurfs e \subsection{Netzwerkaufbau} \begin{figure}[h] \centering - \includegraphics[width=1.0\linewidth]{img/Netzwerkplan-Real} + \includegraphics[width=1.0\linewidth]{img/Netzwerkplan-Real.png} \caption{Realaufbau unter Verwendung eines Angreifers} \label{fig:netzwerkplan-real} \end{figure} @@ -23,7 +23,7 @@ Leider ist durch Begrenzungen im Budget, der Ausstattung der Universität sowie \begin{figure}[h] \centering - \includegraphics[width=0.7\linewidth]{img/Netwerkplan-Versuch} + \includegraphics[width=0.7\linewidth]{img/Netwerkplan-Versuch.png} \caption{Versuchsaufbau} \label{fig:Versuchsaufbau} \end{figure} @@ -47,13 +47,13 @@ In diesem Abschnitt soll veranschaulicht werden, wie genau die Behandlung eines \begin{figure}[h] \centering - \includegraphics[angle=90, width=0.8\linewidth]{img/activity_control_flow.pdf} + \includegraphics[angle=270, width=0.8\linewidth]{img/activity_control_flow.pdf} \caption{Schematische Darstellung des Kontrollflusses} \label{fig:control_flow} \end{figure} \subsubsection{Verwendung von Receive-Side-Scaling} -Ein weiterer grundlegender Vorteil ergibt sich durch das von der Netzwerkkarte und von DPDK unterstützte Receive Side Scaling (RSS), siehe Abbildung \ref{fig:Receive-Side-Scaling}: Ein auf einem Port eingehendes Paket wird einer von mehreren sogenannten RX-Queues zugeordnet. Eine RX-Queue gehört immer zu genau einem Netzwerkkartenport, ein Port kann mehrere RX-Queues besitzen. Kommen mehrere Pakete bei der Netzwerkkarte an, so ist die Zuordnung von Paketen eines Ports zu seinen RX-Queues gleich verteilt~-- alle RX-Queues sind gleich stark ausgelastet. Diese Zuordnung wird durch eine Hashfunktion umgesetzt, in die Quell- und Ziel-Port-Nummer und IP-Adresse einfließen. Das führt dazu, dass Pakete, die auf einem Port ankommen und einer bestimmten Verbindung zugehören, immer wieder zu der selben RX-Queue dieses Ports zugeordnet werden. Mit ,,Port'' im Folgenden entweder der physische Steckplatz einer Netzwerkkarte gemeint oder jener Teil der Netzwerkadresse, die eine Zuordnung zu einem bestimmten Prozess bewirkt. Die Bedeutung erschließt sich aus dem Kontext. +Ein weiterer grundlegender Vorteil ergibt sich durch das von der Netzwerkkarte und von DPDK unterstützte Receive Side Scaling (RSS), siehe Abbildung \ref{fig:Receive-Side-Scaling}: Ein auf einem Port eingehendes Paket wird einer von mehreren sogenannten RX-Queues zugeordnet. Eine RX-Queue gehört immer zu genau einem Netzwerkkartenport, ein Port kann mehrere RX-Queues besitzen. Kommen mehrere Pakete bei der Netzwerkkarte an, so ist die Zuordnung von Paketen eines Ports zu seinen RX-Queues gleich verteilt~-- alle RX-Queues sind gleich stark ausgelastet. Diese Zuordnung wird durch eine Hashfunktion umgesetzt, in die Quell- und Ziel-Port-Nummer und IP-Adresse einfließen. Das führt dazu, dass Pakete, die auf einem Port ankommen und einer bestimmten Verbindung zugehören, immer wieder zu der selben RX-Queue dieses Ports zugeordnet werden. Mit \glqq Port\grqq{} im Folgenden entweder der physische Steckplatz einer Netzwerkkarte gemeint oder jener Teil der Netzwerkadresse, die eine Zuordnung zu einem bestimmten Prozess bewirkt. Die Bedeutung erschließt sich aus dem Kontext. \begin{figure}[H] \centering @@ -62,11 +62,11 @@ Ein weiterer grundlegender Vorteil ergibt sich durch das von der Netzwerkkarte u \label{fig:Receive-Side-Scaling} \end{figure} -Ferner besteht die Möglichkeit, Symmetric RSS einzusetzen. Dieser Mechanismus sorgt dafür, dass die Pakete, die auf dem einen Port der Netzwerkkarte ankommen, nach genau der selben Zuordnung auf dessen RX-Queues aufgeteilt werden, wie die auf dem anderen Port ankommenden Pakete auf dessen RX-Queues. Dabei ist die Zuordnung auf dem einen Port ,,symmetrisch'' zu der auf dem anderen Port. Das heißt, wenn bei Port 0 ein Paket mit \texttt{Src-IP: a, Dst-IP: b, Src-Port: x, Dst-Port: y} ankommt, wird es genauso dessen RX-Queues zugeteilt, wie ein Paket mit \texttt{Src-IP: b, Dst-IP: a, Src-Port: y, Dst-Port: x} auf RX-Queues von Port 1. So ergeben sich Paare von RX-Queues, die jeweils immer Pakete von den gleichen Verbindungen beinhalten. Angenommen, die RX-Queues sind mit natürlichen Zahlen benannt und RX-Queue 3 auf Port 0 und RX-Queue 5 auf Port 1 sind ein korrespondierendes RX-Queue-Paar. Wenn nun ein Paket P, zugehörig einer Verbindung V auf RX-Queue 3, Port 0 ankommt, dann weiß man, dass Pakete, die auf Port 1 ankommen und der Verbindung V angehören immer auf RX-Queue 5, Port 1 landen. +Ferner besteht die Möglichkeit, Symmetric RSS einzusetzen. Dieser Mechanismus sorgt dafür, dass die Pakete, die auf dem einen Port der Netzwerkkarte ankommen, nach genau der selben Zuordnung auf dessen RX-Queues aufgeteilt werden, wie die auf dem anderen Port ankommenden Pakete auf dessen RX-Queues. Dabei ist die Zuordnung auf dem einen Port \glqq symmetrisch\grqq{} zu der auf dem anderen Port. Das heißt, wenn bei Port 0 ein Paket mit \texttt{Src-IP: a, Dst-IP: b, Src-Port: x, Dst-Port: y} ankommt, wird es genauso dessen RX-Queues zugeteilt, wie ein Paket mit \texttt{Src-IP: b, Dst-IP: a, Src-Port: y, Dst-Port: x} auf RX-Queues von Port 1. So ergeben sich Paare von RX-Queues, die jeweils immer Pakete von den gleichen Verbindungen beinhalten. Angenommen, die RX-Queues sind mit natürlichen Zahlen benannt und RX-Queue 3 auf Port 0 und RX-Queue 5 auf Port 1 sind ein korrespondierendes RX-Queue-Paar. Wenn nun ein Paket P, zugehörig einer Verbindung V auf RX-Queue 3, Port 0 ankommt, dann ist einem bekannt, dass Pakete, die auf Port 1 ankommen und der Verbindung V angehören immer auf RX-Queue 5, Port 1 landen. -Neben RX-Queues existieren auch TX-Queues (Transmit-Queues), die ebenfalls zu einem bestimmten Port gehören. Darin befindliche Pakete werden von der Netzwerkkarte auf den entsprechenden Port geleitet und gesendet. Auf Basis dieses Mechanismus sollen die Threads wie folgt organisiert werden: Einem Thread gehört ein Paar von korrespondierenden RX-Queues (auf verschiedenen Ports) und daneben eine TX-Queue auf dem einen und eine TX-Queue auf dem anderen Port. Das bringt einige Vorteile mit sich: Es müssen zwei Arten von Informationen entlang der Pipeline gespeichert, verarbeitet und gelesen werden: Informationen zu einer Verbindung und Analyseinformationen/Statistiken. Daher ist kaum Inter-Thread-Kommunikation nötig, weil alle Informationen zu einer Verbindung in Datenstrukturen gespeichert werden können, auf die nur genau der bearbeitende Thread Zugriff haben muss. An dieser Stelle soll auch kurz auf eine Besonderheit von DPDK eingegangen werden: Im Linux-Kernel empfängt ein Programm Pakete durch Interrupt-Handling. Gegensätzlich dazu werden bei DPDK alle empfangenen Pakete, die sich derzeit in den RX-Queues der Netzwerkkarte befinden, auf einmal von der Anwendung geholt. In der zu entwickelnden Software geschieht dieses Paket-holen (engl. ,,Polling'') durch den einzelnen Thread stets zu Beginn eines Pipeline-Durchlaufes. +Neben RX-Queues existieren auch TX-Queues (Transmit-Queues), die ebenfalls zu einem bestimmten Port gehören. Darin befindliche Pakete werden von der Netzwerkkarte auf den entsprechenden Port geleitet und gesendet. Auf Basis dieses Mechanismus sollen die Threads wie folgt organisiert werden: Einem Thread gehört ein Paar von korrespondierenden RX-Queues (auf verschiedenen Ports) und daneben eine TX-Queue auf dem einen und eine TX-Queue auf dem anderen Port. Das bringt einige Vorteile mit sich: Es müssen zwei Arten von Informationen entlang der Pipeline gespeichert, verarbeitet und gelesen werden: Informationen zu einer Verbindung und Analyseinformationen/Statistiken. Daher ist kaum Inter-Thread-Kommunikation nötig, weil alle Informationen zu einer Verbindung in Datenstrukturen gespeichert werden können, auf die nur genau der bearbeitende Thread Zugriff haben muss. An dieser Stelle soll auch kurz auf eine Besonderheit von DPDK eingegangen werden: Im Linux-Kernel empfängt ein Programm Pakete durch Interrupt-Handling. Gegensätzlich dazu werden bei DPDK alle empfangenen Pakete, die sich derzeit in den RX-Queues der Netzwerkkarte befinden, auf einmal von der Anwendung geholt. In der zu entwickelnden Software geschieht dieses Paket-holen (engl. \glqq Polling\grqq{}) durch den einzelnen Thread stets zu Beginn eines Pipeline-Durchlaufes. -Im Falle eines Angriffes ist die Seite des Angreifers (entsprechender Port z.B. ,,Port 0'') viel stärker belastet, als die Seite des Servers (z.B. ,,Port 1''). Wegen der gleich verteilten Zuordnung des eingehenden Verkehrs auf die RX-Queues und weil ein Thread von RX-Queues von beiden Ports regelmäßig Pakete pollt, sind alle Threads gleichmäßig ausgelastet und können die Pakete bearbeiten. Ein günstiger Nebeneffekt bei DDoS-Angriffen ist, dass die Absenderadressen von Angriffspaketen oft sehr unterschiedlich sind. Das begünstigt die gleichmäßige Verteilung von Paketen auf RX-Queues, weil das Tupel aus besagten Adressen der Schlüssel der RSS-Hash-Funktion sind. +Im Falle eines Angriffes ist die Seite des Angreifers (entsprechender Port z.B. \glqq Port 0\grqq{}) viel stärker belastet, als die Seite des Servers (z.B. \glqq Port 1\grqq{}). Wegen der gleich verteilten Zuordnung des eingehenden Verkehrs auf die RX-Queues und weil ein Thread von RX-Queues von beiden Ports regelmäßig Pakete pollt, sind alle Threads gleichmäßig ausgelastet und können die Pakete bearbeiten. Ein günstiger Nebeneffekt bei DDoS-Angriffen ist, dass die Absenderadressen von Angriffspaketen oft sehr unterschiedlich sind. Das begünstigt die gleichmäßige Verteilung von Paketen auf RX-Queues, weil das Tupel aus besagten Adressen der Schlüssel der RSS-Hash-Funktion sind. \section{Überarbeiteter Grobentwurf} Die in diesem Abschnitt erläuterten Änderungen wurden im Laufe der Implementierungsphase vorgenommen. Für das bei diesem Softwareprojekt genutzte Vorgehensmodell des Unified Process ist es typisch, dass sich auch während der Implementierung Änderungen am Entwurf ergeben. Für die Teammitglieder ist es besonders aufgrund der geringen Erfahrung bezüglich der Thematik des Projekts unerlässlich, wichtige Verbesserungen direkt vornehmen zu können. @@ -88,7 +88,7 @@ Die extrahierten Informationen werden von der \texttt{Inspection} verwendet, um Sowohl \texttt{Treatment}, als auch \texttt{Inspection} und \texttt{PacketDissection} verwenden das \\ \texttt{ConfigurationManagement}, welches Parameter für die Programmbestandteile in Form von Konfigurationsdateien vorhält. Das \texttt{ConfigurationManagement} bietet die Möglichkeit für den Nutzer, aktiv Einstellungen am System vorzunehmen. \subsection{NicManagement} -Das \texttt{NicManagement} übernimmt, wie im letzten Review-Dokument erwähnt, das Senden, das Pollen und das Löschen von Paketen. Dieses Paket wurde eingeführt, um bestimmte Funktionen und Initialisierungsschritte vom DPDK zu kapseln. Dabei handelt es sich vor allem um folgende Operationen: \texttt{rte\_eth\_rx\_burst()} und \texttt{rte\_eth\_tx\_burst()} Es hat sich allerdings herausgestellt, dass die Operationen ,,Senden'', ,,Empfangen'' und ,,Löschen'' in der Implementierung sehr wenig Aufwand bereiten. Das Zusammenbauen von Paketen wird von der Komponente \texttt{PacketDissection} übernommen. Der aufwändigere Teil ist die Initialisierung des DPDK, insbesondere die Ermöglichung von Multithreading und die Konfigurierung von symmetric Receive-Side-Scaling. Die dazu notwendigen Schritte werden jedoch von \texttt{Initializer} bzw in der main.cpp-Datei vor dem Starten der einzelnen Threads durchgeführt und sind nicht mehr Teil des \texttt{NicManagements}. +Das \texttt{NicManagement} übernimmt, wie im letzten Review-Dokument erwähnt, das Senden, das Pollen und das Löschen von Paketen. Dieses Paket wurde eingeführt, um bestimmte Funktionen und Initialisierungsschritte vom DPDK zu kapseln. Dabei handelt es sich vor allem um folgende Operationen: \texttt{rte\_eth\_rx\_burst()} und \texttt{rte\_eth\_tx\_burst()} Es hat sich allerdings herausgestellt, dass die Operationen \glqq Senden\grqq{}, \glqq Empfangen\grqq{} und \glqq Löschen\grqq{} in der Implementierung sehr wenig Aufwand bereiten. Das Zusammenbauen von Paketen wird von der Komponente \texttt{PacketDissection} übernommen. Der aufwändigere Teil ist die Initialisierung des DPDK, insbesondere die Ermöglichung von Multithreading und die Konfigurierung von symmetric Receive-Side-Scaling. Die dazu notwendigen Schritte werden jedoch von \texttt{Initializer} bzw in der main.cpp-Datei vor dem Starten der einzelnen Threads durchgeführt und sind nicht mehr Teil des \texttt{NicManagements}. Aus diesem Grund und weil jeder nicht notwendige Funktionsaufruf Rechenzeit kostet, könnte das \texttt{NicManagement} aufgelöst und die bereitgestellten Funktionen an anderer Stelle implementiert werden. Die einzige Klasse, die das \texttt{NicManagement} zum jetzigen Zeitpunkt verwendet, ist die \texttt{PacketContainer}-Klasse in der Komponente \texttt{PacketDissection}. Es wäre möglich, den Inhalt der \texttt{NicManagement}-Aufgaben in diese Klasse zu verschieben. @@ -115,7 +115,7 @@ Das Paket \texttt{ConfigurationManagement} kümmert sich um die Initialisierung \begin{figure}[h] \centering - \includegraphics[width=0.4\linewidth]{img/configurator.pdf} + \includegraphics[width=0.4\linewidth]{img/Configurator.pdf} \caption{Klassendiagramm: \texttt{Configurator}} \label{config} \end{figure} @@ -144,12 +144,12 @@ Dafür war geplant, in dieser Komponente die Repräsentation eines Paketes - die Aus diesem Grund wurde eine neue Klasse namens \texttt{PacketContainer} eingeführt. Diese dient als Repräsentation einer Folge von Paketen, die empfangen wurden. Enthalten sind sowohl die Pointer auf die tatsächlichen Pakete, als auch Metadaten in Form mehrerer Objekte der \texttt{PacketInfo}-Klasse. Im \texttt{PacketContainer} ist es möglich, Pakete zu entnehmen, hinzuzufügen und zu löschen. Weiterhin gibt es jeweils eine Methode zum Pollen neuer Pakete und zum Senden aller vorhandener Pakete. -Die \texttt{PaketInfo}-Klasse stellt immer noch alle relevanten Header-Informationen eines Paketes zur Verfügung. Allerdings werden Informationen nur noch auf Abruf extrahiert. Hierbei werden für die IP Versionen 4 und 6, sowie die Layer 4 Protokolle TCP, UDP und ICMP unterstützt. Darüber hinaus soll sie auch das verändern einzelner Informationen im Header ermöglichen. +Die \texttt{PaketInfo}-Klasse stellt immer noch alle relevanten Header-Informationen eines Paketes zur Verfügung. Allerdings werden Informationen nur noch auf Abruf extrahiert. Hierbei werden für die IP Versionen 4 und 6, sowie die Layer 4 Protokolle TCP, UDP und ICMP unterstützt. Darüber hinaus soll sie auch das Verändern einzelner Informationen im Header ermöglichen. Die letzte Klasse in der \texttt{PacketDissection} ist der namensgebende \texttt{HeaderExtractor}. Seine Aufgabe wandelte sich vom Extrahieren der Informationen zum Vorbereiten des Extrahierens auf Bedarf. \subsection{Inspection} -Die zuvor globale Auswertung von Angriffen aller Threads durch eine einzige Instanz wurde ersetzt durch eine lokale threadeigene Auswertung. Berechnete Zahlen und Statistiken wie Paketrate und Angriffsrate werden per Interthreadkommunikation nur noch an eine globale Statistikinstanz gesendet. Dadurch können die Threads unabhängig voneinander agieren und reagieren, die Implementation der Methoden ist deutlich einfacher ausgefallen und die Interthreadkommunikation konnte auf ein Minimum begrenzt werden, was der Auswertungsgeschwindigkeit jedes Inspection-Threads zugute kommt und ein Bottleneck-Problem an der Inspection vorbeugt. +Die zuvor globale Auswertung von Angriffen aller Threads durch eine einzige Instanz wurde ersetzt durch eine lokale threadeigene Auswertung. Berechnete Zahlen und Statistiken wie Paketrate und Angriffsrate werden per Interthreadkommunikation nur noch an eine globale Statistikinstanz gesendet. Dadurch können die Threads unabhängig voneinander agieren und reagieren, die Implementierung der Methoden ist deutlich einfacher ausgefallen und die Interthreadkommunikation konnte auf ein Minimum begrenzt werden, was der Auswertungsgeschwindigkeit jedes Inspection-Threads zugute kommt und ein Bottleneck-Problem an der Inspection vorbeugt. \begin{figure}[h] \centering @@ -158,7 +158,7 @@ Die zuvor globale Auswertung von Angriffen aller Threads durch eine einzige Inst \label{InspectionOld} \end{figure} -Durch den Einsatz von symetric Receive Side Scaling ist sowohl die Auslastung jeder Inspektion ausgeglichen und zusätzlich werden gleiche Paketströme (selbe Paketquelle und -Empfänger) durch denselben Thread verarbeitet. Dies erleichtert die Erkennung legitimer Pakete, da diese über eine eigene Patchmap für bestimmte Fälle von großteils illegitimen Verkehr unterscheidbar ist und die Variationen geringer sind. +Durch den Einsatz von symetric Receive Side Scaling ist sowohl die Auslastung jeder Inspektion ausgeglichen und zusätzlich werden gleiche Paketströme (selbe Paketquelle und -Empfänger) durch denselben Thread verarbeitet. Dies erleichtert die Erkennung legitimer Pakete, da diese über eine eigene Patchmap für bestimmte Fälle von großteils illegitimen Verkehr unterscheidbar sind und die Variationen geringer sind. Die Statistik wird statt durch eine eigene Klasse direkt in der \texttt{Inspection} erstellt und das Ergebnis an eine globale Statistik Instanz gesendet, um diese an den Nutzer auszugeben. Die \texttt{Inspection}-Klasse ist dadurch schlanker und folgt einem linearen Pipelinemodell für Paketverarbeitung. diff --git a/doc/review_3/chapters/3-feinentwurf.tex b/doc/review_3/chapters/3-feinentwurf.tex index 1e24188..6b31995 100644 --- a/doc/review_3/chapters/3-feinentwurf.tex +++ b/doc/review_3/chapters/3-feinentwurf.tex @@ -110,7 +110,7 @@ Ausgehender Verkehr aus dem internen System wird grundsätzlich vertraut und nic Nach jedem Durchlauf eines \texttt{PacketContainer}s werden die lokalen und globalen Statistiken aktualisiert. Die Weitergabe der Informationen an die Statistik erfolgt über einen eigenen Interthread- Kommunikationskanal zum globalen Statistik-Thread. Die globale Statistik führt alle einzelnen Informationen zusammen und macht sie dem Nutzer in einfacher Weise abrufbar. \begin{figure}[h] \centering - \includegraphics[angle=90, width=\linewidth]{img/inspection_ablauf.png} + \includegraphics[angle=270, width=\linewidth]{img/inspection_ablauf.png} \caption{Aktivitätsdiagramm der Methode \texttt{analyzeContainer()} der Inspection} \label{inspection_activity} \end{figure} @@ -129,7 +129,7 @@ Wird ein SYN-ACK von extern empfangen, so ist dies ohne Veränderung an das inte Werden Pakete ohne gesetzte Flags, beziehungsweise nur mit gesetztem ACK-Flag verschickt, so findet eine Sequenznummernzuordnung und eine Anpassung von Sequenznummern statt. Hierzu wird eine Densemap mit individueller Hashfunktion, in diesem Fall XXH3, verwendet. Bei der Densemap handelt es sich um eine besonders effiziente Hashmap, welche ein Einfügen, Suchen und Löschen in bis zu vier mal weniger Zeit als eine unordered\_map ermöglicht. Die Auswahl der Hashfunktion XXH3 ist dadurch motiviert, dass sie extrem schnell ist und dennoch kaum Kollisionen erzeugt. Insbesondere werden durch sie bereits auf handelsüblichen Computersystemen Hashraten von bis zu 31.5 Gbit/s erzielt. -Der Ablauf bei Empfang eines solchen Paketes ist wie folgt: Bei eingehenden Paketen wird ein zuvor berechneter Offset, welcher in der Offsetmap für jede Verbindung gespeichert ist, von der ACK-Nummer subtrahiert. +Der Ablauf beim Empfang eines solchen Paketes ist wie folgt: Bei eingehenden Paketen wird ein zuvor berechneter Offset, welcher in der Offsetmap für jede Verbindung gespeichert ist, von der ACK-Nummer subtrahiert. Wird ein ACK empfangen, welches zu einer Verbindung gehört, in deren Info finseen auf true gesetzt ist, so muss die ACK-Nummer angepasst, das Paket an den internen Server geschickt und der Eintrag in der Densemap verworfen werden. @@ -137,11 +137,11 @@ Falls ein Paket mit gesetztem RST-Flag von extern empfangen wird, wird der Eintr Sollte ein FIN empfangen werden, so muss im Info-Struct, welches Teil der Offsetmap ist, der Wert finseen auf true gesetzt werden. In diesem Fall ist das Paket nach Anpassung der ACK-Nummer weiterzuleiten. -Im zweiten Fall der übergeordneten Fallunterscheidung erhält das Programm anschließend den \texttt{PacketContainer} der Pakete, welche das Netz von intern nach extern verlassen wollen. Auch hier wird, bevor ein Paket der Behandlung unterzogen wird, geprüft, ob das Paket nicht bereits gelöscht wurde, oder es sich um ein Paket falschen Typs handelt. +Im zweiten Fall der übergeordneten Fallunterscheidung erhält das Programm anschließend den \texttt{PacketContainer} der Pakete, welche das Netz von intern nach extern verlassen wollen. Auch hier wird, bevor ein Paket der Behandlung unterzogen wird, geprüft, ob das Paket nicht bereits gelöscht wurde oder es sich um ein Paket falschen Typs handelt. Erhält das System ein SYN-Paket von einem internen Server, so wird dieses an das im Paket spezifizierte Ziel weitergeleitet. Eine Anpassung der Sequenznummer findet in diesem Fall nicht statt. -Erhält das System ein SYN-ACK aus dem internen Netz, so muss das System die Differenz aus der ACK-Nummer dieses Pakets, und der des in der ACKmap gespeicherten Paketes berechnen, und den Wert als Offset in der Offsetmap eintragen. Das von intern empfangene SYN-ACK Paket muss verworfen werden. +Erhält das System ein SYN-ACK aus dem internen Netz, so muss das System die Differenz aus der ACK-Nummer dieses Pakets. und der des in der ACKmap gespeicherten Paketes berechnen. Dieser Wert wird als Offset in der Offsetmap eintragen. Das von intern empfangene SYN-ACK Paket muss verworfen werden. Das zuvor in der ACKmap zwischengespeicherte Paket muss nun mit angepasster ACK-Nummer intACK = extACK-offset an den internen Host geschickt werden. Wird ein Paket ohne gesetzte Flags oder mit gesetztem ACK-Flag von Intern nach Extern verschickt, so findet eine weitere Fallunterscheidung statt. @@ -175,7 +175,7 @@ Des weiteren könnte es unter Umständen erforderlich werden, die Einträge mit \label{check_syn_cookie} \end{figure} Nachdem ein ACK als Reaktion auf ein SYN-ACK bei dem zu entwerfenden System angekommen ist, wird die Methode \texttt{check\_typ\_syn\_cookie()} aufgerufen. -Grundsätzlich wird hier überprüft, ob der Hash-Wert aus dem empfangenen Paket mit dem eigens berechneten Hash-Wert übereinstimmt. Falls dies nicht der Fall ist oder die Differenz der Zeitstempel zu groß ist, wird ein Paket mit gesetzten Reset-Flag (RST) an den Sender geschickt. Dieses Flag zeigt an, dass die Verbindung beendet werden soll. Andernfalls wird die Verbindung als legitim erkannt und das Paket in der ACKmap zwischengespeichert, bis die Verbindung mit dem internen System erfolgreich war. +Grundsätzlich wird hier überprüft, ob der Hash-Wert aus dem empfangenen Paket mit dem eigens berechneten Hash-Wert übereinstimmt. Falls dies nicht der Fall ist oder die Differenz der Zeitstempel zu groß ist, wird ein Paket mit gesetzten Reset-Flag (RST) an den Sender geschickt. Dieses Flag zeigt an, dass die Verbindung beendet werden soll. Andernfalls wird die Verbindung als legitim erkannt und das Paket in der ACKmap zwischengespeichert bis die Verbindung mit dem internen System erfolgreich war. Abbildung \ref{createcookiesecret} zeigt die parameterlose Methode \texttt{create\_cookie\_secret()}. Zu Beginn werden drei 16 Bit lange Zufallszahlen generiert, wobei auf die Funktion \texttt{rand()} aus der C Standardbibliothek zugegriffen wird. Der erste mit \texttt{rand()} generierte Wert wird um 48 Bit nach links verschoben, der zweite um 32 Bit. Diese beiden Werte werden danach bitweise ODER miteinander verknüpft. Dieser verknüpfte Wert wird dann wiederum mit der dritten zufälligen 16 Bit Zahl bitweise ODER verknüpft. Das Ergebnis dieser Verknüpfung ist eine 64 Bit lange Zufallszahl, die von der Methode zurückgegeben wird. diff --git a/doc/review_3/chapters/4-tests.tex b/doc/review_3/chapters/4-tests.tex index 4d9c85c..dfd6f68 100644 --- a/doc/review_3/chapters/4-tests.tex +++ b/doc/review_3/chapters/4-tests.tex @@ -11,7 +11,7 @@ In sogenannten Unit-Tests, die auch als Modultest oder Komponententest bezeichne Da die Unit-Tests im vorliegenden Softwareprojekt bereits in der Implementierungsphase durchgeführt werden konnten, noch vor der eigentlichen Validierungsphase, war es möglich, Fehler bereits frühzeitig zu erkennen. Ein weiterer Vorteil des Unit-Testens besteht darin, dass beim Auftreten eines Fehlers dieser sehr genau eingegrenzt werden kann. Somit kann dieser Fehler schneller gefunden und dann auch behoben werden. Außerdem ermöglichen Unit-Tests eine parallele Bearbeitung, denn das Testbed existiert schließlich nur einmal. -\subsection{Mocking: \texttt{libdpdk\_dummy}} +\subsection{Mocking: libdpdk\_dummy} Mocking (dt.: Nachbildung oder Imitation) findet innerhalb der Unit-Tests Verwendung, um so isolierte Tests durchführen zu können. Da in diesem Projekt Tests bereits frühzeitig stattfinden sollten, sich DPDK jedoch nicht mit Unit Tests kompilieren ließ, wurde die Mocking-Bibliothek \texttt{libdpdk\_dummy} erstellt. Diese kleine Bibliothek weist zwar eine geringere Funktionalität als das komplette DPDK-Framework auf, setzt aber genau das um, was bei den Unit-Tests gebraucht wird. So wurden genau die Header-Dateien nachgebildet, deren Funktionalitäten beim Testen benötigt wurden. Diese Nachbildung entstand durch Kopieren aus den \glqq Original-DPDK-Headern\grqq{} und individuelle Anpassung an die Anforderungen des Projekts. \begin{lstlisting} [caption= {Unit-Test zu \texttt{lipdpdk\_dummy}}, label={libdpdk}] @@ -27,29 +27,54 @@ TEST_CASE("rte_mbuf", "[]"){ Auch zu \texttt{lipdpdk\_dummy} existiert ein Unit-Test, um zu überprüfen, ob sie so wie beabsichtigt arbeitet (vgl. Codeausschnitt \ref{libdpdk}). Hier werden zuerst Pointer auf einen \texttt{rte\_mbuf} und einen \texttt{rte\_mempool} angelegt. Danach wird überprüft, ob die Methode \texttt{rte\_pktmbuf\_alloc()} richtig arbeitet, indem gecheckt wird, ob nach der Allokation in \texttt{mbuf} kein Nullpointer liegt. Auf das triviale Löschen des \texttt{mbuf}s wird an dieser Stelle verzichtet, weil es bei diesem Test lediglich auf die grundlegende Funktionalität ankommt. Da das Löschen sehr einfach ist, ist das es in diesem Fall nicht unbedingt notwendig. \subsection{ConfigurationManagement} -... %\todo -\textcolor{red}{toDo Leon} + +Das ConfigurationManagement bietet eine Schnittstelle zu den Konfigurationsdateien (config.json und default\_config.json). In der Datei config.json kann der Endnutzer Einstellungen wie die Anzahl der verwendeten Threads ändern. In der Standarddatei default\_config.json hingegen stehen Standardwerte, die vom Programm vorgegeben sind und verwendet werden, wenn die Daten der anderen Datei fehlerhaft oder nicht vorhanden sind. + +Da die Klasse \texttt{Configurator} als \texttt{Singleton} implementiert ist, es also nur ein Objekt der Klasse gibt, kann im Code nicht über einen Konstruktor, sondern nur über eine Methode \texttt{instance()} auf die Klasse zugegriffen werden. + +Die folgenden Tests sollen prüfen, ob die Dateien korrekt erkannt werden und ob Einstellungen sowie Standardwerte richtig eingelesen werden. \subsubsection{Beispiel: Einlesen einer JSON-Datei} + +Dieser Test prüft, ob die Konfigurationsdatei erkannt und richtig eingelesen wird. + \begin{lstlisting} [caption= {Unit-Test zum Einlesen einer JSON-Datei}, label={config1}] TEST_CASE("Json Datei einlesen", "[]") { - REQUIRE_NOTHROW(Configurator::instance()->read_config( - "../test/ConfigurationManagement/config_test.json")); + REQUIRE_NOTHROW(Configurator::instance()->read_config("../test/ConfigurationManagement/config_test.json")); - REQUIRE(Configurator::instance()->get_config_as_bool("BOOLEAN") == true); REQUIRE(Configurator::instance()->get_config_as_unsigned_int( - "UNSIGNED_INT") == 42); - REQUIRE(Configurator::instance()->get_config_as_string("STRING") == - "Hello World."); + REQUIRE(Configurator::instance()->get_config_as_bool("BOOLEAN") == true); + REQUIRE(Configurator::instance()->get_config_as_unsigned_int("UNSIGNED_INT") == 42); + REQUIRE(Configurator::instance()->get_config_as_string("STRING") == "Hello World."); REQUIRE(Configurator::instance()->get_config_as_float("FLOAT") == 1.337f); REQUIRE(Configurator::instance()->get_config_as_double("DOUBLE") == -3.001); } \end{lstlisting} + \subsubsection{Beispiel: Nicht exisitierende JSON-Datei} + +Dieser Test prüft, ob das Programm bei einem falschen Pfad zu einer Konfigurationsdatei auch tatsächlich keine Datei einliest. + \begin{lstlisting}[caption= {Unit Test: Nicht existierende JSON-Datei}, label={config2}] TEST_CASE("nicht existierende Json-Datei", "[]") { REQUIRE_THROWS(Configurator::instance()->read_config("non-existent.json")); - REQUIRE_THROWS(Configurator::instance()->read_config("non-existent.json", - "typo.json")); + REQUIRE_THROWS(Configurator::instance()->read_config("non-existent.json", "typo.json")); +}\end{lstlisting} + +\subsubsection{Beispiel: Default Config} + +Dieser Test prüft, ob, wenn und nur wenn ein Eintrag in der normalen Datei nicht existiert, die Daten aus der Standarddatei gelesen werden. + +Die Methoden zum Auslesen der Konfigurationsdateien ermöglichen es, zusätzlich einen optionalen Übergabewert auf \texttt{true} zu setzen. Dadurch wird erzwungen, dass die Standarddatei zum Auslesen verwendet wird. + +\begin{lstlisting}[caption= {Unit Test: Default Config}, label={config4}] +TEST_CASE("Default Config") { + REQUIRE_NOTHROW(Configurator::instance()->read_config( + "../test/ConfigurationManagement/config_test.json", + "../test/ConfigurationManagement/default_config_test.json")); + + REQUIRE(Configurator::instance()->get_config_as_unsigned_int("UNSIGNED_INT") == 42); + REQUIRE(Configurator::instance()->get_config_as_unsigned_int("UNSIGNED_INT", true) == 666); + REQUIRE(Configurator::instance()->get_config_as_string("X") == "80085"); }\end{lstlisting} \subsection{PacketDissection} @@ -115,11 +140,11 @@ SECTION("get_empty_packet", "[]") { Im Codeausschnitt \ref{pc2} zur Methode \texttt{get\_empty\_packet()} wird überprüft, ob die Getter-Methode zum Erhalten eines leeren Paketes wie gewünscht funktioniert. Zunächst wird dazu in Z. 4 f. sichergestellt, dass die bisherige Zahl der (gepollten) Pakete null ist. Anschließend wird für eine \texttt{PacketInfo}-Referenz die entsprechende Methode aufgerufen, wie in Z. 7 zu erkennen ist. In den anschließenden Code-Zeilen wird gecheckt, ob es keine Null-Pointer gibt und ob es sich um \texttt{IPv4TCP} handelt. Außerdem ist es wichtig, dass die Anzahl der Pakete insgesamt größer als die der abgefragten Pakete ist, genauer gesagt eins und null. Die entsprechenden Assertions sind in Z. 27 - 30 zu finden. -Die darauf folgende Section \texttt{IPv4TCP} unterscheidet sich nur insofern von der default-Variante, dass hier in Z. 22 beim Aufruf der \texttt{get\_empty\_packet()}-Methode zusätzlich \texttt{IPv4TCP} übergeben wird. Die Beschreibung der weiteren Bestandteile der Sektion findet man demzufolge im vorhergehenden Absatz. +Die darauf folgende Section \texttt{IPv4TCP} unterscheidet sich nur insofern von der default-Variante, dass hier in Z. 22 beim Aufruf der \texttt{get\_empty\_packet()}-Methode zusätzlich \texttt{IPv4TCP} übergeben wird. Die Beschreibung der weiteren Bestandteile der Sektion kann demzufolge im vorhergehenden Absatz gefunden werden. Im Codeausschnitt \ref{pc3} wird \texttt{get\_empty\_packet()} so oft aufgerufen, bis die \texttt{BURST\_SIZE} erreicht ist. Direkt danach wird sichergestellt, dass die gesamte Anzahl an Paketen auch wirklich der \texttt{BURST\_SIZE} entspricht. -\begin{lstlisting} [caption= {Sektion ,,Create more packets than burst size'' mit den zwei Untersektionen ,,fill till BURST\_SIZE'' und ,,fill till BURST\_SIZE + 1''}, label={pc3}] +\begin{lstlisting} [caption= {Sektion \texttt{Create more packets than burst size} mit den zwei Untersektionen \texttt{fill till BURST\_SIZE} und \texttt{fill till BURST\_SIZE + 1}}, label={pc3}] SECTION("create more packets than burst size", "[]") { SECTION("fill till BURST_SIZE", "[]") { @@ -127,7 +152,6 @@ SECTION("create more packets than burst size", "[]") { PacketInfo* pkt_info = pkt_container->get_empty_packet(); CHECK(pkt_info != nullptr); } - CHECK(pkt_container->get_total_number_of_packets() == BURST_SIZE); } @@ -136,7 +160,6 @@ SECTION("create more packets than burst size", "[]") { PacketInfo* pkt_info = pkt_container->get_empty_packet(); CHECK(pkt_info != nullptr); } - CHECK(pkt_container->get_total_number_of_packets() == BURST_SIZE + 1); } @@ -151,7 +174,7 @@ Die Test-Section, die in Codeabschnitt \ref{pc4} zu sehen ist, dient zum Test de In ersterer wird zunächst in Z. 5 ein leeres Paket hinzugefügt und wieder die Richtigkeit der Anzahl der Pakete getestet. Darauf hin kommt es für \texttt{pkt\_info\_1} zum Aufruf der\\ \texttt{get\_packet\_at\_index()}-Methode. Dabei wird der mit Hilfe von\\ \texttt{get\_total\_number\_of\_packets()} ermittelte Index des zu Beginn erstellten leeren Pakets übergeben. Anschließend wird wieder einmal gecheckt, ob es sich auch wirklich um ein valide Paket handelt und die Anzahl aller Pakete und der abgerufenen Pakete korrekt ist. In Z. 18 f. wird zunächst getestet, ob es bei der bereits in Z. 9 aufgerufenen Methode auch wirklich zu keinen Fehlern kommt. Bei der Übergabe eines Indexes, unter dem kein Paket zu finden ist, muss es allerdings zum Wurf einer Exception kommen, was in Z. 20 kontrolliert wird. -\begin{lstlisting} [caption= {Sektion ,,get\_packet\_at\_index'' mit den zwei Untersektionen ,,general'' und ,,test out of bounds error''}, label={pc4}] +\begin{lstlisting} [caption= {Sektion \texttt{get\_packet\_at\_index} mit den zwei Untersektionen \texttt{general} und \texttt{test out of bounds error}}, label={pc4}] SECTION("get_packet_at_index", "[]") { SECTION("general", "[]") { @@ -200,7 +223,7 @@ SECTION("get_packet_at_index", "[]") { In der zweiten Section des Codeabschnitts \ref{pc4} wird wieder ähnlich wie oben vorgegangen. Zu Beginn wird für jedes \texttt{i} von 0 bis \texttt{BURST\_SIZE / 2} ein leeres Paket abgerufen und geprüft, ob die Anzahl der Pakete stimmt. Somit darf es auch beim Aufruf von \texttt{get\_packet\_at\_index} für die erste Hälfte des Intervalls von null bis \texttt{BURST\_SIZE} zu keinem Fehler kommen, was in Z. 32 ff. getestet wird. In der darauf folgenden for-Schleife muss es hingegen zu einer Exception kommen. Die letzten beiden Checks in Z. 40 - 43 sind äquivalent zu denen in Z. 18 - 21. -\begin{lstlisting} [caption= {Sektion ,,take\_packet and add\_packet''}, label={pc5}] +\begin{lstlisting} [caption= {Sektion \texttt{take\_packet and add\_packet}}, label={pc5}] SECTION("take_packet and add_packet", "[]") { PacketInfo* pkt_info_0 = pkt_container->get_empty_packet(); @@ -230,7 +253,7 @@ In Codeabschnitt \ref{pc5} wird getestet, ob das Herausnehmen und das Hinzufüge Die Methode \texttt{drop\_packet()} wird durch die im Codeabschnitt \ref{pc6} dargestellte Sektion getestet. Auch hierfür werden in den Zeilen 4 - 7 die gleichen Initialisierungen wie in der vorherigen Section vorgenommen. Nach dem einmaligen Aufruf der Methode \texttt{drop\_packet()} werden die üblichen Checks durchgeführt. Besonders interessant ist Zeile 13, in der getestet wird, ob die Methode \texttt{get\_packet\_at\_index()} für den Index 0 einen Null-Pointer zurückgibt. In Zeile 15 wird sicher gestellt, dass es beim erneuten Aufruf von \texttt{drop\_packet()} nicht zu einer Exception kommt. Die letzten drei Zeilen können mit Z. 11 - 13 verglichen werden. -\begin{lstlisting} [caption= {Sektion ,,drop\_packet''} \label{pc6}] +\begin{lstlisting} [caption= {Sektion \texttt{drop\_packet}} \label{pc6}] SECTION("drop_packet", "[]") { SECTION("default") { @@ -255,7 +278,7 @@ SECTION("drop_packet", "[]") { Der letzte beispielhafte Codeabschnitt für den \texttt{PacketContainer} ist der für den Test von\\ \texttt{poll\_packets}. Auch hierfür wird zu Beginn überprüft, ob die Anzahl der Pakete null ist. In Zeile 6 wird der vorzeichenlose 16-bit-Ganzzahlwert \texttt{nb\_pkts\_polled} definiert. Zum Aufruf der Methode \texttt{poll\_packets} kommt es in Z. 7. Anschließend wird erneut geprüft, ob die Anzahl der Pakete richtig ist. Die Zeilen 13 - 17 sind für den Test von \texttt{get\_packet\_at\_index()} mit der Übergabe des Wertes \texttt{nb\_pkts\_polled - 1} wichtig. So darf es auch hier nicht zum Wurf einer Exception kommen und sowohl \texttt{pkt\_info} als auch \texttt{pkt\_info->get\_mbuf()} dürfen kein Null-Pointer sein. Damit soll getestet werden, ob die Variablen, die von den entsprechenden Getter-Methoden zurückgegeben werden, richtig berechnet worden sind. -\begin{lstlisting} [caption= {Sektion ,,poll\_packets''}, label={pc7}] +\begin{lstlisting} [caption= {Sektion \texttt{poll\_packets}}, label={pc7}] SECTION("poll_packets", "[]") { CHECK(pkt_container->get_number_of_polled_packets() == 0); @@ -276,11 +299,57 @@ SECTION("poll_packets", "[]") { }\end{lstlisting} -Auf die Sektion ,,poll\_packets'' würde noch eine weitere Sektion mit neun Untersektionen folgen, die das Senden von Paketen testet. Diese Sektion wird hier jedoch nicht näher beschrieben. +Auf die Sektion \texttt{poll\_packets} würde noch eine weitere Sektion mit neun Untersektionen folgen, die das Senden von Paketen testet. Diese Sektion wird hier jedoch nicht näher beschrieben. \subsubsection{Beispiel aus der PacketInfo} -... %\todo -\textcolor{red}{toDo für Tobias} + +In der unten stehenden Testsektion (siehe Abb. \ref{utpi}) wird das Beibehalten des Datentyps für \texttt{IPv4ICMP}, \texttt{IPv4TCP} und \texttt{IPv4UDP} getestet. In den Zeilen 6-9, 12-15 und 18-21 werden jeweils neue Objekte erstellt und gecastet. Am Ende geht es um die Überprüfung des korrekten Typs in den \texttt{CHECK}-Statements. In Z. 24 f. wird validiert, dass eine neue \texttt{PacketInfo} auch tatsächlich \texttt{NONE} beim Aufruf von \texttt{get\_type()} zurückgibt. Die letzten Zeilen des Codeabschnitts sind für das Löschen zuständig. + +\begin{lstlisting} [caption= {Testfall \texttt{Transformation} im Unit-Test zur \texttt{PacketInfo}}, label={utpi}] +TEST_CASE("Transformation", "[]") { + + SECTION("keeping Type", "[]") { + PacketInfo* pkt_inf; + // pkt_inf = PacketInfoCreator::create_pkt_info(IPv4ICMP); + pkt_inf = new PacketInfoIpv4Icmp; + PacketInfoIpv4Icmp* pkt_inf_icmp; + pkt_inf_icmp = static_cast(pkt_inf); + CHECK(pkt_inf_icmp->get_type() == IPv4ICMP); + + // PacketInfoCreator::create_pkt_info(IPv4TCP) + pkt_inf = new PacketInfoIpv4Tcp; + PacketInfoIpv4Tcp* pkt_inf_tcp; + pkt_inf_tcp = static_cast(pkt_inf); + CHECK(pkt_inf_tcp->get_type() == IPv4TCP); + + // PacketInfoCreator::create_pkt_info(IPv4UDP) + pkt_inf = new PacketInfoIpv4Udp; + PacketInfoIpv4Udp* pkt_inf_udp; + pkt_inf_udp = static_cast(pkt_inf); + CHECK(pkt_inf_udp->get_type() == IPv4UDP); + + // PacketInfoCreator::create_pkt_info(NONE) + pkt_inf = new PacketInfo; + CHECK(pkt_inf->get_type() == NONE); + + PacketInfo* pkt_inf_arr[5]; + pkt_inf_arr[0] = pkt_inf_icmp; + pkt_inf_arr[1] = pkt_inf_tcp; + pkt_inf_arr[2] = pkt_inf_udp; + pkt_inf_arr[3] = pkt_inf; + CHECK(pkt_inf_arr[0]->get_type() == IPv4ICMP); + CHECK(pkt_inf_arr[1]->get_type() == IPv4TCP); + CHECK(pkt_inf_arr[2]->get_type() == IPv4UDP); + CHECK(pkt_inf_arr[3]->get_type() == NONE); + + // clean up + delete pkt_inf; + delete pkt_inf_icmp; + delete pkt_inf_tcp; + delete pkt_inf_udp; + delete pkt_inf_arr; + } +}\end{lstlisting} \subsection{Inspection} Die Unit-Tests der \texttt{Inspection} können in drei Teile gegliedert werden. @@ -426,7 +495,7 @@ Die Methode \texttt{check\_syn\_cookie()} (vgl. Codeausschnitt \ref{checksc}) ü \begin{lstlisting} [caption= {Unit-Test für die Methode \texttt{check\_cookie\_secret()} in \texttt{Treatment\_test.cpp}}, label = ut_checksc] TEST_CASE("check_syn_cookie", "[]"){ - .... + ... SECTION("check_syn_cookie(): diff==1 with random numbers (without using the PacketDissection)", "[]"){ //Create a Treatment object Treatment_friend treat; @@ -457,10 +526,9 @@ TEST_CASE("check_syn_cookie", "[]"){ d._intip = intip; d._extport = extport; d._intport = intport; - CHECK(treat.check_syn_cookie(cookie_value, d)); } -.... + ... } \end{lstlisting} Im Unit-Test in Codeausschnitt \ref{ut_checksc} wird untersucht, ob die Methode \texttt{check\_syn\_cookie()} als Rückgabewert \texttt{true} hat (siehe Zeile 34). Zudem wird in Zeile 15 überprüft, ob der Timestamp korrekt inkrementiert wurde. @@ -509,7 +577,6 @@ TEST_CASE("Benchmark", "[]"){ clock_t tr; clock_t td; densemap.set_empty_key(Data(0,0,0,0)); - Info flix; flix._offset = 123; flix._finseen = 0; @@ -526,7 +593,6 @@ TEST_CASE("Benchmark", "[]"){ for(long r = 0; r < runs; ++r) { - for(long i = 0; i < runner; ++i){ arr[i]._extip = rand(); arr[i]._intip = rand(); @@ -550,7 +616,6 @@ TEST_CASE("Benchmark", "[]"){ tu = clock() - tu; auto finishu = std::chrono::high_resolution_clock::now(); - auto startd = std::chrono::high_resolution_clock::now(); td = clock() ; for(long i = 0; i < runner; ++i) { @@ -572,7 +637,6 @@ TEST_CASE("Benchmark", "[]"){ uclock[r] = tu; BOOST_LOG_TRIVIAL(info) << "Elapsed time of unordered: " << elapsedu. count(); BOOST_LOG_TRIVIAL(info) << "Elapsed time of dense: " << elapsedd. count(); - } int sumd = 0; int sumu = 0; @@ -590,7 +654,7 @@ Das Ergebnis des Benchmarks in Abb. \ref{benchmark} zeigt, dass die Densemap in This is the average clock count of unordered\_map of 10 rounds, of each 600000 elements inserted, and 2400000 elements searched : 614058 \end{lstlisting} -Ebenfalls getestet wurde die Patchmap von 1ykos. Hierbei stellte sich allerdings heraus, dass die Performanz nicht den Erwartungen genügte. +Ebenfalls getestet wurde die Patchmap von 1ykos. Hierbei stellte sich allerdings heraus, dass die Performance nicht den Erwartungen genügte. \subsubsection{Beispiel: Densemap} Um die Verhaltensweise der Densemap vor deren Nutzung im Code besser kennenzulernen, wurden mehrere Tests geschrieben, welche die Grundfunktionalitäten der Map wie zum Beispiel das Löschen oder Hinzufügen von Werten testen. @@ -714,7 +778,7 @@ TEST_CASE("RandomNumberGeneratorStatistics", "[]") { double chisquare = 0.0; for (int i = 0; i < r; i++) { // chi square is calculated - chisquare = chisquare + ((f[i] - n / r) * (f[i] - n / r) / (n / r)); + chisquare = chisquare + ((f[i] - n / r)*(f[i] - n / r) / (n / r)); } std::cout << "chi square is: " << chisquare << std::endl; double k = sqrt(chisquare / (n + chisquare)); @@ -735,7 +799,7 @@ Ein Problem des Chi-Quadrats ist allerdings die Abhängigkeit von n. Da sich bei \end{align} Das hierbei errechnete Ergebnis ist eine Zahl zwischen 0 und K\textsubscript{max} mit K\textsubscript{max}$\approx$1, welche \texttt{n} berücksichtigt. Eine niedriger Kontingenzkoeffizient heißt, dass die generierten Zahlen gut verteilt sind und die tatsächlichen Werte nah an die theoretischen heranreichen. Ein höherer Kontingenzkoeffizient bedeutet, dass vermehrt Zahlen häufiger bzw. seltener als gewollt vorkommen. -Mit dem oben dargestellten Test hat sich ein \texttt{k} von ca. 0,003 ergeben, was sich als ein sehr gutes Ergebnis bezeichnen lässt. Wird allerdings die Methode \texttt{gen\_rdm\_16\_bit\_in\_interval()} der im Codeausschnitt \ref{rng} dargestellten Datei aufgerufen und dabei die Werte 1024 und 49151 übergeben, so verschlechtert sich der Kontingenzkoeffizient auf einen mittelmäßig guten Wert von ca. 0,59. +Mit dem oben dargestellten Test hat sich ein \texttt{k} von ca. 0,003 ergeben, was sich als ein sehr gutes Ergebnis bezeichnen lässt. Wird allerdings die Methode \texttt{gen\_rdm\_16\_bit\_in\_interval()} aufgerufen und dabei die Werte 1024 und 49151 übergeben, so verschlechtert sich der Kontingenzkoeffizient auf einen mittelmäßig guten Wert von ca. 0,59. Es lässt sich somit festhalten, dass die Verkleinerung des Intervalls der zurückgegebenen Zahl auf das von validen Portnummern eine Verschlechterung der Zufälligkeit des Algorithmus mit sich bringt, was allerdings kein Problem darstellt. Das ist eine logische Konsequenz aus der Tatsache, dass keine Zahlen außerhalb des Intervalls mehr zurückgegeben werden. @@ -744,7 +808,7 @@ Die Methode \texttt{gen\_rdm\_32\_bit()} und \texttt{gen\_rdm\_64\_bit()} konnte \subsubsection{Zeitlicher Vergleich mit rand()} Da der auf Xorshift basierende \texttt{RandomNumberGenerator} insbesondere aufgrund einer besseren Effizienz als die der Standardfunktion \texttt{rand()} implementiert wurde, ist ein Vergleich beider Zufallszahlengeneratoren von Interesse. Der für einen Vergleich benutze Test wird im Codeausschnitt \ref{rngtime} beispielhaft für die Methode \texttt{gen\_rdm\_32\_bit()} gezeigt. Es wurden ebenfalls zwei äquivalente Sections für die andere Methode geschrieben. Dabei wurde stets darauf geachtet, dass die mit \texttt{rand()} generierten Zahlen das gleiche Intervall und die gleiche Größe wie beim RNG haben. -\begin{lstlisting}[caption= {Test zum Vergleich der Zeiten vom RandomNumberGenerator mit rand()}, label = rngtime] +\begin{lstlisting}[caption= {Test zum Vergleich der Zeiten vom RandomNumberGenerator mit \texttt{rand()}}, label = rngtime] TEST_CASE("RandomNumberGeneratorTime", "[]") { ... SECTION("TestTime32", "[]") { @@ -828,12 +892,97 @@ TEST_CASE("tsc timer", "[]"){ << "seconds : " << seconds << "\t" << std::endl; } } \end{lstlisting} -Im Testfall ,,tsc timer'' werden die seit dem Teststart vergangenen Sekunden gezählt und ausgegeben (vgl. Codeausschnitt \ref{timer}). Der Code zur Ausgabe befindet sich in den Zeilen 9 bis 11 und 21 bis 23. +Im Testfall \texttt{tsc timer} werden die seit dem Teststart vergangenen Sekunden gezählt und ausgegeben (vgl. Codeausschnitt \ref{timer}). Der Code zur Ausgabe befindet sich in den Zeilen 9 bis 11 und 21 bis 23. Nach 30 Sekunden endet der Test. %Wofür wird dieser Test benötigt? Kein Check bzw. Require + \section{Testen anhand des Testdrehbuchs} +\label{tdblabel} +%wird genutzt, um bei der Überprüfung der nichtfunktionalen Anforderungen eine pageref auf diese Seite zu ermöglichen + + Das Testdrehbuch ist das Mittel zur Überprüfung der nichtfunktionalen Anforderungen. + Diese können, im Gegensatz zu funktionalen Anforderungen, nicht hinzugefügt werden, wenn noch Zeit ist, sondern müssen von Anfang an mit bedacht werden. + Dementsprechend war es sehr ungünstig, dass erst im Verlauf der dritten Phase mehrere Komponenten zusammen funktionierten und dementsprechend getestet werden konnten. + + Darüber hinaus musste im Verlauf des Projekts festgestellt werden, dass Reihenfolge, Umsetzung und Kriterien der Tests in der Planungsphase sehr logisch erschien, in der Praxis aber unserem Vorgehen in der Umsetzungs- und Testphase zuwider lief und teilweise auch zu aufwendig geplant war. + + Auch wurde festgestellt, dass der Aufbau des Testbeds die geplante Umsetzung einzelner Tests unmöglich macht. + Dies wird im Zuge der einzelnen Tests ausfürhlich erläutert. + +\subsection{Test 1: Paketweiterleitung} + Dies ist der einzige Test, der bereits in der Planungsphase angegangen und dessen erste Hälfte auch erfolgreich abgeschlossen wurde. + Dieser erste Prototyp besaß allerdings kaum selbst programmierten Code. + Er ermöglichte aber, Erfahrung im Umgang mit DPDK zu gewinnen. + + Der simple Weiterleitungstest war auch fast der einzige Test, der in der Implementierungsphase überprüft wurde, da bereits in der \texttt{PacketDissection} immer wieder Fehler und Bugs entdeckt wurden. + Im Zuge der dritten Phase wurde der Test leicht umformuliert, sodass er als bestanden gilt, wenn erfolgreich durch AEGIS hindurch gepingt werden kann. + Dieser Test wird im Allgemeinem Ping-Test genannt und ist mittlerweile bei jedem Build von AEGIS erfolgreich. + Trotzdem wird der Ping-Test immer noch durchgeführt, um sicher zu gehen. + + Den Last-Weiterleitungstest konnten wir nicht im gewünschten Ausmaß durchführen, da es uns nicht gelang, ausreichend Angriffstraffic zu generieren, um den Link vollständig auszulasten oder den Server zum Absturz zu bringen. + Allerdings besitzt unser Testbed im Gegensatz zum Einsatzgebiet von AEGIS nur einen Angreiferrechner und dieser deutlich weniger Rechenleistung als der verwendete Server. + +\subsection{Test 2: Lasttest Server} + Wie bereits unter Test 1 erwähnt, wurde keine ausreichende Angriffsrate erreicht, um Ausfälle zu erzeugen. + Dementsprechend kann das ursprüngliche Kriterium, des Systemausfalls, nicht verwendet werden. + Als Ersatz dient der eingehende Verkehr am Server im Verhältnis zur verursachten CPU Last. + +\subsection{Test 3: (D)DoS-Erkennung} + Im Laufe des Projekts verschob sich der Fokus sehr auf die Abwehr der verschiedenen SYN-Flood Varianten. + Diese können ohne Erkennung mithilfe von SYN-Cookies abgewehrt werden, sodass dieser Test deutlich an Bedeutung verloren hat. + + Alle Angriffe können von AEGIS erkannt werden, allerdings wurde das Detektions-Modul zum Zeitpunkt der Niederschrift noch nicht integriert, sodass ausführliche Test nicht durchgeführt werden konnten. + +\subsection{Test 4: (D)DoS Abwehr} + Bei der SYN-Flood beträgt die Abwehrrate dank SYN-Cookies 100\%. + + Sowohl SYN-FINs als auch SYN-FIN-ACKs werden bei Erkennung sofort gelöscht, sodass auch diese vollständig abgewehrt werden. + +\subsection{Test 5: Transparenz} + Es hat sich als sehr aufwendig herausgestellt, die Angriffsrate schrittweise zu erhöhen, weshalb dieser Test nur bei voller Last, keiner Last und ohne AEGIS durchgeführt wurde. + + Der TCP-Handshake dauerte ohne Aegis 4,045 ms, mit hingegen 4,365. Beim Ping steht der Zeit von 0,523 ms ohne das System ein Wert von 0,564 mit eingeschalteter Software gegenüber. + + Dementsprechend lässt sich schlussfolgern, dass der Einfluss von Aegis im Nichtangriffsfall messbar, aber nicht signifikant ist. + Eine SYN-Flood ist deutlich auffälliger, der Server ist aber immer noch in akzeptabler Zeit erreichbar. + +\subsection{Test 6: Eigensicherheit} + Der erste Teil des Tests ist erfolgreich, denn die Mitigation-Box ist über den überwachten Link selbst nicht erreichbar. + Sie kann also auch nicht durch (D)DoS Angriffe über diesen Link beeinträchtigt werden. + + Den zweiten Teil bestand das System auch. Denn meisten Aufwand verursacht die SYN-Flood. + SYN-Pakete müssen nicht nur betrachtet und analysiert werden, sondern auch noch beantwortet. + +\subsection{Test 7: Paketflut} + Dieser Test kann nicht als Erfolg bezeichnet werden. Die Paketrate war mit 18,5 Mpps nicht ausreichend, um einen Verbindungsaufbau zu verhindern. + +\subsection{Test 8: Datenrate} + Wie mehrfach erwähnt, waren wir nicht in der Lage, die angezielten Datenraten zu erreichen. + + Die Angriffsrate beträgt 7,7 Gbit/s. Da nur TCP-SYN-Pakete verschickt werden, ist der Ethernet-1-Frame verhältnismäßig groß zum eigentlichen Paket, sodass wir eine Datenrate von 11,9 Gbit/s auf dem Kabel erreichen. + Dies liegt primär daran, dass der Rechenaufwand für die Berechnung von Checksummen unterschätzt wurde. + + Die Menge an legitimen Daten kann nicht gemittelt werden, da wir während eines laufenden Angriffs nur sporadisch legitimen Verkehr starteten. + \section{Sonstige Tests am Testbed} -\textcolor{red}{toDo} +Schon zu Beginn des Projekt wurde sich darauf geeinigt, zum Testen der entwickelten Software ein Testbed zu verwenden. Dabei handelt es sich um \glqq eine wissenschaftliche Umgebung für Experimente dar. Anders als Softwaresimulatoren bestehen Testbeds aus realer Hardware und unterliegen den physikalischen Einflüssen ihrer Umgebung.\grqq\cite{testbed} + +In der KW 19 wurde dieses im Raum 3033 im Zusebau der TU Ilmenau aufgebaut. Zunächst bestand das Testbed aus drei Rechnern, für die Abschlusspräsentation wurde allerdings noch ein weiterer hinzugefügt. SSH (Secure Shell) erlaubt den Zugriff auch von außerhalb des Universitätsgebäude. Auf diesen PCs wurde Ubuntu 20.04 LTS installiert. Dabei handelt es sich um das gleiche Betriebssystem, das auch alle Teammitglieder für die Entwicklung installiert haben. + +Alle vier Rechner wurden zur einfacheren Unterscheidung mit Namen versehen. \textbf{Alice} sendet legitimen Verkehr an Bob (und ist damit der \glqq freundliche Server von nebenan \grqq). Dagegen handelt es sich bei \textbf{Mallory} um den bösartigen Angreifer, der unter Anderem für die Ausführung der DoS-Attacken zuständig ist. Die Mitigation-Box, die für die Ausführung von Aegis verantwortlich ist, wurde \textbf{Dave} genannt. \textbf{Bob} ist der empfangende Server. + + +Beim Testen stellte sich heraus, dass die Angriffe eventuell mit externem Verkehr interferieren könnten und Anfragen durch Bob automatisch verworfen wurden, da die Quell-IPs aus dem falschen Netzbereich kamen. Dies lies sich durch die Verwendung von Network Namespaces umgehen, da diese Bob und Alice vorgaukeln, allein im Internet zu sein. + +\subsection{Pingtest} + +Um das entwickelte Programm auf dem Testbed auszuführen, müssen zunächst drei seperate Kommandozeilenfenster geöffnet werden. Um die einzelnen Programme ausführen zu können werden die Rechte eines \texttt{super-users} benötigt. In diesen Modus kann durch den Befehl \texttt{su} gewechselt werden, \texttt{exit} ermöglich den Wechsel zurück. Die Passwörten für das erfolgreiche Ausführen dieses Befehls können in einem Wiki-Eintrag in GitLab gefunden werden. Weiterhin ist zu Beginn eine SSH-Verbindung aufzubauen. + +Verwendet werden können die NICs, also die Netzwerkkarten, indem die folgende Syntax beachtet wird: \texttt{su} und danach \texttt{ip netns exec AEGISNS [YOUR COMMAND HERE]}. Diese Commands sind in einem Wiki-Eintrag zusammengefasst. TShark ermöglicht die Analyse des Netzwerkverkehrs. Mittels verschiedener Parameter können Probleme bei der Übertragung gefunden werden. + +\subsection{Verbindungstests} + +Um zu überprüfen, ob das entwickelte Produkt den Anforderungen bezüglich der Ermöglichung von TCP-Verbindungen zwischen Alice und Bob genügt, mussten beispielhafte Verbindungen simuliert werden. Hierzu wurde sich der Tools wget und iperf3 bedient. Hierbei zeigte sich, dass Verbindungen zwischen Alice und Bob korrekt aufgebaut wurden, die Funktion des TCP Proxies inklusive des Erstellens und Überprüfens von SYN-Cookies wie vom Auftraggeber gewünscht funktionieren. Auch der Verbindungsabbau zeigte sich nach einigen Anpassungen an die Besonderheiten der drei Wege Verbindungstermination voll funktionsfähig. Ein weiterer wichtiger Test war die Übertragung von Dateien verschiedener Größen sowie die Realisation eines Livestreams von Bob zu Alice. Auch diese Tests verliefen mit insgesamt positivem Ergebnis. \end{document} diff --git a/doc/review_3/chapters/5-anforderungen.tex b/doc/review_3/chapters/5-anforderungen.tex index 30e5555..2fcaa5e 100644 --- a/doc/review_3/chapters/5-anforderungen.tex +++ b/doc/review_3/chapters/5-anforderungen.tex @@ -4,20 +4,22 @@ \chapter{Überprüfung der Anforderungen}\thispagestyle{fancy} -In diesem Kapitel wird geklärt, in wie fern das entwickelte System den zu Beginn des Projekts aufgestellten funktionalen und nichtfunktionalen Anforderungen gerecht wird. Dafür wird zunächst kurz auf deren Priorisierung eingangen. Anschließend werden die Anforderungen aufgelistet und kurz erklärt, ob diese erfüllt worden oder nicht. - +In diesem Kapitel wird geklärt, in wie fern das entwickelte System den zu Beginn des Projekts aufgestellten funktionalen und nichtfunktionalen Anforderungen gerecht wird. Dafür wird zunächst kurz auf deren Priorisierung eingangen. Anschließend werden die Anforderungen aufgelistet und kurz erklärt, ob diese erfüllt worden sind oder nicht. +\vspace{-0.2cm} \section{Priorisierung der Anforderungen}\thispagestyle{fancy} Um Anforderungen zu strukturieren und nach Wichtigkeit zu priorisieren, wird in der Regel ein System zur Klassifizierung der Eigenschaften verwendet. Hier wurde eine Priorisierung nach der \textbf{MuSCoW}-Methode vorgenommen: \begin{description} \item{\textbf{Must}:} Diese Anforderungen sind unbedingt erforderlich und nicht verhandelbar. Sie sind erfolgskritisch für das Projekt. \item{\textbf{Should}:} Diese Anforderungen sollten umgesetzt werden, wenn alle Must-Anforderungen trotzdem erfüllt werden können. \item{\textbf{Could}:} Diese Anforderungen können umgesetzt werden, wenn die Must- und Should-Anforderungen nicht beeinträchtigt werden. Sie haben geringe Relevanz und sind eher ein \glqq Nice to have\grqq. - \item{\textbf{Won't}:} Diese Anforderungen werden im Projekt nicht explizit umgesetzt, werden aber eventuell für die Zukunft vorgemerkt. + \item{\textbf{Won't}:} Diese Anforderungen werden im Projekt explizit nicht umgesetzt, werden aber eventuell für die Zukunft vorgemerkt. \end{description} +\vspace{-0.2cm} + \section{Funktionale Anforderungen} -Die funktionalen und die nichtfunktionalen werden in einzelnen Unterkapiteln getrennt behandelt. Für beide Arten wird zunächst die Tabelle aus dem Pflichtenheft erneut dargestellt. Nach der Auflistung wird eine Überprüfung zum einen anhand des Testdrehbuch und nach anderen Methoden vorgenommen. +Die funktionalen und die nichtfunktionalen Anforderungen werden in einzelnen Unterkapiteln getrennt behandelt. Für beide Arten wird zunächst die Tabelle aus dem Pflichtenheft erneut dargestellt. Nach der Auflistung wird eine Überprüfung zum einen anhand des Testdrehbuch und nach anderen Methoden vorgenommen. \subsection{Auflistung der funktionalen Anforderungen} % Sie beschreiben das Systemverhalten durch Spezifikation der erwarteten Input-/Output-Beziehungen @@ -39,7 +41,7 @@ Funktionale Anforderungen legen konkret fest, was das System können soll. Hier \end{itemize} Dabei ist vorausgesetzt, dass das Ziel eines Angriffes eine einzelne Station in einem Netzwerk ist und kein Netzwerk von Stationen. Es sind also direkte Angriffe auf einzelne Server, Router, PC, etc. gemeint. & Must \\ F03 & Keine zusätzliche Angriffsfläche & Besonders darf das System den unter ,,Angriffsarten'' spezifizierten Angriffen keine zusätzliche Angriffsfläche bieten, d.h. es darf es auch nicht durch Kenntnis der Implementierungsdetails möglich sein, das System mit diesen Angriffen zu umgehen. & Must \\ - F04 & L3/ L4 Protokolle & Das System muss mit gängigen L3/ L4 Protokollen klarkommen. & Must \\ + F04 & L3/ L4 Protokolle & Das System muss mit gängigen L3/L4 Protokollen klarkommen. & Must \\ F05 & Modi & Passend zum festgestellten Angriffsmuster muss das System eine passende Abwehrstrategie auswählen und ausführen. & Must \\ F06 & Position & Das System soll zwischen dem Internet-Uplink und dem zu schützenden System oder einer Menge von Systemen platziert werden. & Must \\ F07 & Weiterleiten von Paketen & Das System muss legitime Pakete vom externen Netz zum Zielsystem weiterleiten können. & Must \\ @@ -69,77 +71,107 @@ Funktionale Anforderungen legen konkret fest, was das System können soll. Hier \end{longtable} %fehlt: Pakete weiterleiten, Pakete verwerfen \subsection{Überprüfung der funktionalen Anforderungen} -Jede einzelne funktionale Anforderungen wird hier unter einer eigenen kleinen Überschrift überprüft. Die Reihenfolge ist dabei die gleiche wie in der oben stehenden Tabelle. +Jede einzelne funktionale Anforderungen wird hier in einem kleinen Unterkapitel überprüft. Die Reihenfolge ist dabei die gleiche wie in der oben stehenden Tabelle. \subsubsection{F01: Lokale Administration} -% Leon fragen, Screenshot? %cli2 könnte laufen -Diese Muss-Anforderung wurde erfüllt. Ein Command-Line-Interace wurde mithilfe von Konventionen wie ,,Human first design'' oder der Forderung, dass das Programm bei der Benutzung unterstützt. So soll es beispielsweise vorschlagen, was als Nächstes gemacht werden kann. +Diese Muss-Anforderung wurde erfüllt. Ein Command-Line-Interace wurde mithilfe von Konventionen wie \glqq Human first design\grqq{} erstellt. So soll es beispielsweise den Nutzer nicht mit für Menschen irrelevanten Informationen überschütten und vorschlagen, was als Nächstes gemacht werden kann. -Mit Hilfe der Kommandos ,,help'' oder ,,h'' bekommt der Nutzer alle gültigen Eingaben angezeigt. +Mit Hilfe der Kommandos \texttt{help} oder \texttt{h} bekommt der Nutzer alle gültigen Eingaben angezeigt. Bei einer ungültigen Eingabe wird auf diesen Hilfsbefehl verwiesen. Die Eingabe von \texttt{exit} beendet das Programm, sodass zur normalen Kommandozeile zurückgekehrt wird. Der nachfolgende Bildschirmausschnitt (vgl. Abb \ref{cli}) zeigt diese Funktionen beispielhaft. -Die Eingabe von ,,exit'' +\begin{figure} [h] + \centering + \includegraphics[width = \linewidth, trim=0pt 0pt 0pt 2pt, clip]{img/CLIAegis.png} + \caption{Screenshot des CLIs von Aegis} + \label{cli} +\end{figure} + +%Cli Attacker \subsubsection{F02: Angriffsarten} % Test Nr. 6 (Überprüfung Widerstandsfähigkeit der Miditation-Box) % Das System muss die Folgen der aufgelisteten (D)DoS-Angriffe abmildern können: -Das System kann alle geforderten (D)DoS Angriffe abmildern oder gänzlich verhindern. SYN-FIN, SYN-FIN-ACK sowie Zero Window und Small Window können vollständig erkannt und abgewehrt werden. Die UDP-/TCP- und ICMP-Flood können in ihrer Form abgemildert werden. +AEGIS ist in der Lage folgende Angriffe vollständig abzuwehren: +\begin{itemize} + \setlength{\parskip}{-2pt} + \item SYN-FIN Attack, + \item SYN-FIN-ACK Attack, + \item SYN-Flood +\end{itemize} + +Nach Integration des bereits implementierten Pakets \texttt{Inspection} wäre AEGIS in der Lage folgende Angriffe abzumildern: +\begin{itemize} + \setlength{\parskip}{-2pt} + \item UDP-Flood, + %\item ICMP-Flood, + \item Zero-Window, + \item Small-Window +\end{itemize} + +Es wird von abmildern geschrieben, da es legitime Pakete geben kann, die die sieben Charakteristiken besitzen wie Angriffspakete. Dementsprechend ist es notwendig ,eine gewisse Menge dieser Pakete zu tolerieren. +Allerdings wurde das Modul zur Abwehr letzterer Angriffe, zum Zeitpunkt der Niederschrift, noch nicht integriert. \subsubsection{F03: Keine zusätzliche Angriffsfläche} % Test Nr. 4 (Überprüfung Abwehrmaßnahmen) % Besonders darf das System den unter ,,Angriffsarten'' spezifizierten Angriffen keine zusätzliche Angriffsfläche bieten, d.h. es darf es auch nicht durch Kenntnis der Implementierungsdetails möglich sein, das System mit diesen Angriffen zu umgehen. -Durch unvollständigkeit des Systems kann diese Anforderung nicht vollständig überprüft werden jedoch ist diese soweit das System implementiert wurde beständig. +SYN-Cookies besitzen eine kryptographische Schwäche. Dadurch ist es theoretisch möglich, mit SYN-Floods AEGIS zu umgehen. Allerdings ist das Fenster zum Ermitteln der geheimen Komponenten und zum Ausnutzen dieses Wissens gering. Gegen Ende der Validierungsphase ist die Anforderung erfüllt. Bei späterer Integration der UDP-Flood-Abwehr könnte AEGIS möglicherweise eine größere Angriffsfläche bieten. + +%%Hat dieser Absatz überhaupt irgendwas mit der Anforderung zu tun? +%Die Abwehr von Angriffen wie UDP-Flood oder Zero-Window besitzt Schwellen, bis zu denen solche Pakete toleriert werden. +%Diese Schwellen kann man ausnutzen. Das Gefahrenpotential dieser Schwellen ist aber gering und der Server muss in der Lage sein, mit dem unterschwelligen Lasten klar zu kommen. Ist dies nicht der Fall, müssen die Schwellen verringert werden. Damit wurde die Anforderung ... \subsubsection{F04: L3/L4 Protokolle} -Sowohl Protokoll L3, zuständig für die Vermittlung von Daten über einzelne Verbindungsanschnitte und Netzwerkknoten und Adressierung der Kommunikationspartner, als auch Protokoll L4, das die Quell- und Zieladressen und weitere Informationen des Pakets enthält, werden vom System akzeptiert und verwendet. +Die Informationen welche in den Headern der Layer 3 und 4 gespeichert sind werden von AEGIS zur korrekten Verarbeitung der Pakete verwendet und benötigt. So wird beispielsweise im Treatment sowohl die Information über Quell- und Zieladresse aus dem L3, und damit dem IP Header, als auch die Quell- und Zielports aus dem TCP-Header für beispielsweise die Berechnung eines eindeutigen Schlüssels für die Densemap verwendet. \subsubsection{F05: Modi} -% Test Nr. 3 (Kalibirierung von (D)DOS Erkennung) -% Passend zum festgestellten Angriffsmuster muss das System eine passende Abwehrstrategie auswählen und ausführen. -Das System erkennt und unterscheidet verschiedene Angriffsmethoden und errechnet selbst die passende Abwehrstrategie sowie eine Anpassung der Durchlassrate von Paketen. Die Abwehrstrategie wird von jedem Worker-Thread an seinen eigenen Verkehr angepasst. +In der Implementierung wurde sich primär auf die verschiedenen SYN-Flood Varianten konzentriert. Eine SYN-Flood wird abgewehrt, ohne dass dieser Angriff zuvor detektiert wurde. Dementsprechend wird die passende Abwehrstrategie hierfür dauerhaft ausgeführt. + +Trotzdem kann das System theoretisch verschiedene Angriffsmethoden erkennen und unterscheiden, sowie dementsprechend die passende Abwehrstrategie wählen und Anpassung an den Durchlassraten von Paketen vornehmen. Dies geschieht in jedem Worker-Thread abhängig von seinen eigenen Verkehr. +Allerdings ist das Modul, welches diese Abwehrstrategien umsetzt, zum Zeitpunkt der Niederschrift noch nicht integriert. \subsubsection{F06: Position} In Kapitel 2 ist auf Seite \pageref{fig:Versuchsaufbau} in Abbildung \ref{fig:Versuchsaufbau} der Versuchsaufbau zu sehen. Das System wurde im Labor im Zusebau der TU Ilmenau auch tatsächlich in dieser Reihenfolge aufgebaut. Damit ist diese Anforderung erfüllt. \subsubsection{F07: Weiterleiten von Paketen} -Zur Überprüfung dieser Anforderung ist der erste Test des in der Planungs- und Entwurfsphase geschriebenen Testdrehbuchs gedacht. Für den Test der Paketweiterleitung werden zunächst Pakete mit DPDK von einem Port der Netzwerkkarte entgegengenommen und auf den andern Port weitergegeben. Danach wurde begonnen, einzelne Ping-Anfragen vom äußeren System über die Mitigation-Box zum Server laufen zu lassen. Im Anschluss wurde ein Lasttest durchgeführt. Diese Tests haben ergeben, dass... % to do! +Zur Überprüfung dieser Anforderung ist der erste Test des in der Planungs- und Entwurfsphase geschriebenen Testdrehbuchs gedacht. Für den Test der Paketweiterleitung werden zunächst Pakete mit DPDK von einem Port der Netzwerkkarte entgegengenommen und auf den andern Port weitergegeben. Danach wurde begonnen, einzelne Ping-Anfragen vom äußeren System über die Mitigation-Box zum Server laufen zu lassen. Im Anschluss wurde ein Lasttest durchgeführt. Diese Tests haben ergeben, dass für die Richtung von Alice zu Bob Datenraten von bis zu 4 Gbit/s erreicht wurden. Für die entgegengesetzte Richtung wurden Datenraten bis zu 9,8 Gbit/s erzielt. + +\subsubsection{F08: Installation und Deinstallation} +Das System wird mit einer Installationsanleitung und Installationsskripten ausgeliefert. Das Installationsskript für abhängige und notwendige Systemeinstellungen und Programme installiert alle notwendigen zusätzlichen Programme und Bibiliotheken und nimmt alle notwendigen Einstellungen vor. Bei Fehlern wird dem Benutzer ein Hinweis zur Lösung des Problems angezeigt. Die Installation kann auch selbst mit der Installationsanleitung vorgenommen werden, die einzelnen Schritte sind in eigenen Unterkapiteln genauer erklärt. -\subsubsection{F08: Installation und Deinstallation} -Das System wird mit einer Installationsanleitung und Installationsskripten ausgeliefert. Das Installationsskript für abhängige und notwendige Systemeinstellungen und Programme installiert alle notwendigen zusätzlichen Programme und Bibiliotheken und nimmt alle notwendigen Systemeinstellungen vor, soweit möglich. Bei Fehlern wird dem Benutzer ein Hinweis zur Lösung des Problems angezeigt. Die Installation kann auch selbst mit der Installationsanleitung vorgenommen werden, die einzelnen Schritte sind in eigenen Unterkapiteln genauer erklärt. Für einen lokalen Bau der Software kann \texttt{Meson} und \texttt{Ninja} verwendet werden, deren Benutzung in der die Installationsanleitung fortführenden Seite \texttt{Usage} erklärt wird. Dort ist auch ein kurzer Einstieg in die Benutzung von \texttt{AEGIS} erklärt. Zur systemweiten Installation von \texttt{AEGIS} kann ebenfalls \texttt{Meson} genutzt werden, das durch ein Installationsskript erweitert wurde. -Das gesamte Programm und zusätzlich installierten Programme können mit einem Deinstallationsskript wieder vom System gelöscht werden. +Das gesamte Programm und die zusätzlich installierten Programme können mit einem Deinstallationsskript wieder vom System gelöscht werden. -Diese Anforderung ist erfüllt. +Diese Anforderung ist somit erfüllt. \subsubsection{F09: Mehrere Angriffe nacheinander und zeitgleich} % Test Nr. 4 (Überprüfung Abwehrmaßnahmen) -Das System ist darauf spezifiziert, einzelne Angriffe und kombinierte Angriffe zu erkennen. Kombinierte Angriffe aus unterschiedlichen angriffsmethoden können erkannt und abgewehrt werden. Ein vollständiger Test konnte mit dem bisherigen Stand des Projektes noch nicht durchgeführt werden. +Das System ist darauf spezifiziert, einzelne Angriffe zu erkennen. Kombinierte Angriffe aus unterschiedlichen Angriffsmethoden können nicht als solche erkannt, aber trotzdem einzeln abgewehrt werden. Auch eine Serie von unterschiedlichen Angriffen, soweit von AEGIS unterstützt, bereitet keine Probleme. + +Ein vollständiger Test konnte mit dem bisherigen Stand des Projektes allerdings noch nicht durchgeführt werden. \subsubsection{F10: IPv4} % Das System muss mit IPv4-Verkehr zurechtkommen. -Das System kann IPv4 Verkehr vollständig verarbeiten, verwalten und stößt auf keine Probleme dabei. Diese Anforderung ist erfüllt. +Das System kann IPv4 Verkehr vollständig verarbeiten, verwalten und stößt auf keine Probleme dabei. Hierbei werden die Pakete so verarbeitet, dass TCP-Verbindungen zwischen Alice und Bob problemlos auf- und abgebaut werden können. Diese Anforderung ist erfüllt. \subsubsection{F11: Hardware} Diese Should-Anforderung wurde mit dem entwickelten System nicht erfüllt. Die Software läuft im derzeitigen Zustand ausschließlich auf dem Testbed im Rechenlabor. Durch kleine Anpassung kann die Nutzung auf alternativer Hardware allerdings ermöglicht werden. -Eine zusätzliche Beschränkung der Hardware besteht in der Nutzung von DPDK und Kernel Bypässen die von der verbauten Netzwerkkarte der Hardware unterstützt werden muss. +Eine zusätzliche Beschränkung der Hardware besteht in der Nutzung von DPDK und Kernel Bypässen, die von der verbauten Netzwerkkarte unterstützt werden muss. \subsubsection{F12: Zugriff} -Es ist ein ssh-Zugriff auf das System möglich. Die Konfiguration ermöglicht die Authentifizierung nicht mit einem Passwort möglich ist. Mithilfe des Befehls \texttt{ssh-keygen} kann ein Schlüsselpaar generiert werden und ein Public-Key ist in einer Textdatei zu finden. Weiterhin ist es möglich, zu überprüfen, welche anderen Teammitglieder derzeit auf diese Art mit dem System verbunden sind. +Es ist ein SSH-Zugriff auf das System möglich. Die Konfiguration ermöglicht es, dass für die Authentifizierung kein Passwort nötig ist. Mithilfe des Befehls \texttt{ssh-keygen} kann ein Schlüsselpaar generiert werden und ein Public-Key ist in einer Textdatei zu finden. Weiterhin ist es möglich, zu überprüfen, welche anderen Teammitglieder derzeit auf diese Art mit dem System verbunden sind. \subsubsection{F13: Betrieb} % Das System soll auf Dauerbetrieb ohne Neustart ausgelegt sein. -Zum Zeitpunkt des Projektendes konnte das System in kurzer Zeit betriebsfähig gehalten werden jedoch kein Dauerbetrieb mit Dauerbelastung ausreichend getestet werden. Neustarts zwischen starten und stoppen des Systems waren nicht notwendig. +Zum Zeitpunkt des Projektendes konnte das System in kurzer Zeit betriebsfähig gehalten werden, jedoch konnte kein Dauerbetrieb mit Dauerbelastung ausreichend getestet werden. Neustarts zwischen Starten und Stoppen des Systems waren nicht notwendig. Die Anforderung wurde teilweise erfüllt. \subsubsection{F14: Privacy} % Das System soll keine Informationen aus der Nutzlast der ihm übergebenen Pakete lesen oder verändern. -Dem System ist es möglich auf Paketdaten zuzugreifen und zu lesen. Die Implementierung wurde jedoch genau darauf eingeschränkt, nur Teile der Paketdaten, die zur Erfüllung der Systemaufgaben notwendig sind, zu lesen und gegebenfalls zu verändern. Von dem System kann dadurch keine Nutzlast von Paketen gelesen oder verändert werden. Wird ein Paket als (D)DoS Attacke erkannt wird das Paket mitsamt seiner Nutzlast gelöscht. Ein Eingriff in Privatsphäre oder Analyse von Benutzerdaten außerhalb der systemrelevanten Spezifikationen erfolgt zu keiner Zeit. - -Damit ist diese Anforderung erfüllt. +Dem System ist es möglich, auf Paketdaten zuzugreifen und diese zu lesen. Die Implementierung wurde jedoch genau darauf eingeschränkt, nur Teile der Paketdaten, die zur Erfüllung der Systemaufgaben notwendig sind, zu lesen und gegebenenfalls zu verändern. Von dem System kann dadurch keine Nutzlast von Paketen gelesen oder verändert werden. Wird ein Paket als (D)DoS Attacke erkannt, wird das Paket mitsamt seiner Nutzlast gelöscht. Ein Eingriff in Privatsphäre oder Analyse von Benutzerdaten außerhalb der systemrelevanten Spezifikationen erfolgt zu keiner Zeit. Damit ist diese Anforderung erfüllt. \subsubsection{F15: Konfiguration} -Der Administrator kann die Einstellungen von \texttt{AEGIS} durch zwei Konfigurationsdateien anpassen. Innerhalb der \texttt{meson\_options.txt} Datei kann der Bau von Unit Tests und der Dokumentation ein- und ausgeschalten werden. In der Datei \texttt{config.json} können verschiedene Einstellungen wie die zu verwendenden Systemkerne und Durchlassraten eingestellt werden. +Der Administrator kann die Einstellungen von \texttt{AEGIS} durch zwei Konfigurationsdateien anpassen. Innerhalb der \texttt{meson\_options.txt} Datei kann der Bau von Unit-Tests und der Dokumentation ein- und ausgeschaltet werden. In der Datei \texttt{config.json} können verschiedene Einstellungen wie die zu verwendenden Systemkerne und Durchlassraten eingestellt werden. \subsubsection{F16: Abrufen der Statistiken} % Der Administrator soll Statistiken über das Verhalten des Systems abrufen können. @@ -147,18 +179,20 @@ Die globale Statistik mit Informationen über den Datenverkehr soll innerhalb de \subsubsection{F17: Starten und Stoppen des Systems} % Der Administrator soll das System starten und stoppen können. -Das Programm \texttt{AEGIS} kann über ein Terminal vom Benutzer gestartet und gestoppt werden. Das CLI unterstützt den Nutzer dabei mit Hinweisen. Die Anforderung ist erfüllt. +Das Programm \texttt{AEGIS} kann über ein Terminal (wie in F01 beschrieben) vom Benutzer gestartet und gestoppt werden. Das CLI unterstützt den Nutzer dabei mit Hinweisen. Die Anforderung ist erfüllt. \subsubsection{F18: Informieren über graphische Oberfläche} %GUI -Für die Präsentation ist eine graphische Oberfläche in Arbeit. Diese ist bisher aber nicht fertig und erfüllt die Anforderung noch nicht. +Für die Abschlusspräsentation wurde eine graphische Oberfläche entwickelt. Diese zeigt mit einem Bild an, ob gerade vom Angriffsprogramm ein Angriff läuft. Es wird aber nicht erkannt, ob das Abwehrsystem gerade einen Angriff abwehrt oder normal läuft. Diese Can-Anforderung ist also nicht erfüllt. -\subsubsection{F19: Administration über grafische Oberfäche} +\subsubsection{F19: Administration über grafische Oberfläche} Diese Can-Anforderung wurde aus Zeitgründen nicht umgesetzt. Die Administration erfolgt stattdessen über das in F01 beschriebene CLI. \subsubsection{F20: IPv6} %schon einzelne Dinge da, auf die darauf aufgebaut werden kann, oder? -Das System ist vorerst auf IPv4 ausgelegt und funktionsfähig aber schon darauf ausgerichtet auch IPv6 zu unterstützen. Die Anforderung ist nicht erfüllt kann aber später ohne große Abänderung am gegebenen System hinzugefügt werden. +Das System ist aktuell ausschließlich auf IPv4 ausgelegt, aber bereits darauf ausgerichtet auch IPv6 zu unterstützen. Die Anforderung ist nicht erfüllt kann aber mit geringen Anpassungen hinzugefügt werden. + +Reines IPv6 kann sogar mit minimalen Änderungen hinzugefügt werden. Aufwand verursacht allerdings das Hinzufügung von getunneltem IPv6. Dies geschah aus Zeitgründen bisher nicht. \subsubsection{F21: Weitere Angriffsarten} % Bei den Anforderungen F21 - F27 handelt es sich solche, die mit Won't priorisiert wurden. Das heißt, dass sie nicht erfüllt werden dürfen. Bei dem während des Softwareprojekts entwickelten System gibt es auch keine Anzeichen dafür, dass es ungewollter Weise vor anderen Gefahren schützt. @@ -166,14 +200,14 @@ Das System ist vorerst auf IPv4 ausgelegt und funktionsfähig aber schon darauf Das System schützt nur vor den in F02 angegebenen (D)DoS Angriffen und stellt keinen Schutz gegen weitere mögliche Angriffe. Die Verwendung weiterer Sicherheitsmechanismen ist weiterhin unerlässlich. \subsubsection{F22: Anzahl der zu schützende Systeme} -Das System schützt nur ein einzelnes System. Mit moderaten Änderungen kann die Software aber auf anderen Servern etc. installiert werden und dadurch mehrere schützen. Aus hardwareseitigen Gründen wurde dies aber auch nicht getestet. +Aegis schützt ein einzelnes System. %Mit moderaten Änderungen kann die Software aber auf anderen Servern etc. installiert werden und dadurch mehrere schützen. Aus hardwareseitigen Gründen wurde dies aber auch nicht getestet. \subsubsection{F23: Fehler des Benutzers} Auch nach der Entwicklung kann festgehalten werden, dass das System durch einen kompetenten Administrator installiert und genutzt werden muss. Fehler durch den Benutzer oder falsche Verwendung können vom System selbst nicht behoben werden. \subsubsection{F24: Softwareupdates} -Das System, das während des Projekts entwickelt wurde, wird nach Abschluss der Lehrveranstaltung nicht direkt weiterentwickelt. Während der Erstellung dieses Dokuments wird allerdings davon ausgegangen, dass einige Studierende der Gruppe auch nach Abschluss der Lehrveranstaltung evtl. noch an dem System weiterarbeiten. Features, die möglicherweise dadurch noch hinzugefügt werden, können allerdings nicht als Softwareupdates angesehen werden. +Das System, welches während des Projekts entwickelt wurde, enthält keine Softwareupdates und wird nicht von den Studierenden gewartet. \subsubsection{F25: Router-/Firewall-Ersatz} Auch diese Won't-Anforderung wurde nicht erfüllt. Eine Firewall oder vergleichbare schützende Systeme bleiben nach wie vor unerlässlich. @@ -182,7 +216,7 @@ Auch diese Won't-Anforderung wurde nicht erfüllt. Eine Firewall oder vergleichb Aegis kann keine Hardwareausfälle beheben. \subsubsection{F27: Fehler in Fremdsoftware} -Ebenso gibt keine Möglichkeit das System vor Fehlern einer anderen Software oder Softwareabhängigkeit zu schützen. Der Benutzer ist für die korrekte Installation und Konfiguration aller notwendigen Fremdsoftware und Abhängigkeiten verantwortlich. Die Installations- und Deinstallationsskripte, sowie Dokumentation bieten dem Benutzer Hilfe diese Fehler zu umgehen. +Ebenso gibt keine Möglichkeit das System vor Fehlern einer anderen Software oder Softwareabhängigkeit zu schützen. Der Benutzer ist für die korrekte Installation und Konfiguration aller notwendigen Fremdsoftware und Abhängigkeiten verantwortlich. Die Installations- und Deinstallationsskripte, sowie Dokumentation bieten dem Benutzer Hilfe beim Umgehen dieser Fehler. \section{Nichtfunktionale Anforderungen} @@ -193,7 +227,7 @@ Auch hier wird genau wie bei den funktionalen Anforderungen vorgegangen. \subsection{Auflistung der nichtfunktionalen Anforderungen} -Nichtfunktionale Anforderungen gehen über die funktionalen Anforderungen hinaus und beschreiben, wie gut das System eine Funktion erfüllt. Hier sind zum Beispiel Messgrößen enthalten, die das System einhalten soll. Im folgenden werden diese nichtfunktionalen Anforderungen beschrieben. +Nichtfunktionale Anforderungen gehen über die funktionalen Anforderungen hinaus und beschreiben, wie gut das System eine Funktion erfüllt. Im folgenden werden diese nichtfunktionalen Anforderungen beschrieben. \begin{longtable}[ht] { p{1cm} p{4cm} p{7cm} l } \toprule @@ -210,33 +244,49 @@ Nichtfunktionale Anforderungen gehen über die funktionalen Anforderungen hinaus \end{longtable} \subsection{Überprüfung der nichtfunktionalen Anforderungen} -Auch bei den nichtfunktionalen Anforderungen werden jeweils einzelne Unterkapitel genutzt. +%Auch bei den nichtfunktionalen Anforderungen werden jeweils einzelne Unterkapitel genutzt. Jedoch erhält nur die erste nichtfunktionale Anforderung an dieser Stelle einen eigenen Abschnitt. Eine Erklärung zu den anderen ist unten zu finden. \subsubsection{NF01: Betriebssystem} Die genannte Software, also Ubuntu 20.04 LTS und DPDK 20.11.1, wurde von allen Teammitgliedern installiert. Schließlich wurde auch nur mit diesen Versionen des Betriebssystems bzw. Frameworks entwickelt und getestet. Es kann also dokumentiert werden, dass das System unter diesen Voraussetzungen wie bei den anderen Tests beschrieben funktioniert. Es kann keine Aussage darüber getroffen werden, inwiefern das System unter anderen Versionen funktioniert. \subsubsection{NF02: Verfügbarkeit} % Test Nr. 5 (Analyse Effekt auf Verbindungen) +Verfügbarkeit beschreibt eine langzeitige Statistik. Eine solche konnten wir nicht aufstellen. \subsubsection{NF03: Datenrate} % Test Nr. 8 (allgemeine Bestimmungen) +Diese Anforderung konnten wir nicht überprüfen, da wir keine Quelle für legitime Anfragen besitzen, die die geforderte Datenrate erreicht. \subsubsection{NF04: Paketrate} % Test Nr. 7 (Ermittlung maximaler Paketrate) +Durch Aegis hindurch haben wir eine maximale Paketrate von 5,6 Gbps erreicht. +Der erreichte Wert liegt deutlich über dem geforderten Wert. Dementsprechend wurde diese Anforderung erfüllt. \subsubsection{NF05: Transparenz} % Test Nr. 5 (Analyse Effekt auf Verbindungen) +Tests haben ergeben, dass Aegis einen reinen TCP Verbindungsaufbau um 0,32 ms verzögert. +Diese Verzögerung ist im Alltag nicht spürbar. Dementsprechend wurde diese Anforderung erfüllt. \subsubsection{NF06: Abwehrrate SYN-Flood} % Test Nr. 7 (Ermittlung maximaler Paketrate) +Eine SYN-Flood wird mithilfe von SYN-Cookies vollständig abgewehrt. In mehreren Versuchen konnten kein Paket der SYN-Flood festgestellt werden, dass Aegis durchquert hat. Dementsprechend wurde diese Anforderung erfüllt. \subsubsection{NF07: False Positive} % Test Nr. 5 (Analyse Effekt auf Verbindungen) +Diese Anforderung lässt sich nicht eindeutig überprüfen. Bei UDP-Paketen, ICMP-Paketen und TCP-Paketen mit kleinem Empfangsfenster / Receive-Window ist es nicht möglich eindeutig zu entscheiden ob ein Paket legitim ist oder nicht. Dementsprechend werden auch bösartige Pakete zu 100\% durchgelassen, solange sie zusammen mit dem legitimen Verkehr die Detektionsschwelle nicht überschreiten. + +Allerdings können SYN, SYN-FIN und SYN-FIN-ACK Floods zu 100\% abgewehrt werden. \subsubsection{NF08: False Negative} - +Diese Anforderung lässt sich nicht eindeutig überprüfen. +Wie bereits in NF07 erwähnt werden SYN-, SYN-FIN- und SYN-FIN-ACK-Floods zu 100\% abgewehrt. Hingegen können die geforderten Raten für UDP-, ICMP-Flood und Zero-, Small-Window aus den oben genannten Gründen nur bei Angriffsraten 20mal höher als der Schwellenwert zuverlässig erreicht werden. \subsubsection{NF09: Round Trip Time} % Test Nr. 5 (Analyse Effekt auf Verbindungen) +Ein TCP Verbindungsaufbau benötigt 2 Round-Trip-Times. Im Nichtangriffsfall wird dieser um durchschnittlich 0,32 ms verzögert, was einer Erhöhung der Round-Trip-Time um 0,16 ms entspricht. + +Ein Ping durch Aegis hindurch ist 0,031 ms verzögert. + +Beide Werte liegen innerhalb des erlaubten Rahmens. Dementsprechend wird die Anforderung erfüllt. \end{document} diff --git a/doc/review_3/chapters/6-bugreview.tex b/doc/review_3/chapters/6-bugreview.tex index 5c7e009..c297019 100644 --- a/doc/review_3/chapters/6-bugreview.tex +++ b/doc/review_3/chapters/6-bugreview.tex @@ -4,33 +4,39 @@ \chapter{Bug-Review}\thispagestyle{fancy} -In diesem Bug-Review werden verschiedene Fehler gesammelt. Dabei wird auf die Datei, in der sie auftreten, auf eine Beschreibung und eine Kategorisierung eingegangen. Major Bugs sind versionsverhindernd, critical bugs können auch zur Arbeitsunfähigkeit anderer führen und minor bugs haben eine geringe Auswirkung und somit eine niedrige Priorität. +In diesem Bug-Review werden verschiedene Fehler gesammelt. Dabei wird auf die Datei, in der sie auftreten, auf eine Beschreibung und eine Kategorisierung eingegangen. Major Bugs sind versionsverhindernd, Critical Bugs können auch zur Arbeitsunfähigkeit anderer führen und Minor Bugs haben eine geringe Auswirkung und somit eine niedrige Priorität. -\begin{longtable} [h] {p{3cm} p{8.7cm} l} +\begin{longtable} [h] {p{3cm} p{6cm} p{2cm} l} \toprule - \textbf{Datei} & \textbf{Beschreibung} & \textbf{Kategorie} \\ \endhead + \textbf{Datei} & \textbf{Beschreibung} & \textbf{Kategorie} & \textbf{Status} \\ \midrule + \endhead - PacketInfoIpv4Icmp & - Wenn von einem Paket die Header extrahiert werden soll (fill\_info), wird zuerst der mbuf in der \texttt{PacketInfo} verlinkt, dann IP version (IPv4) und Layer 4 Protokol (ICMP) ermittelt. Danach wird die \texttt{PaketInfo} in die entsprechende protokolspezifische \texttt{PacketInfo} gecastet. Auf dieser verwandelten \texttt{PacketInfo} wird set\_ip\_hdr ausgeführt und es kommt zum segmentation fault, der im Abbruch des Threads mündet. & - critical bug \\ - - %Ist dieser Bug nun gelöst? - %PacketInfo & - %Wenn in der internen IP-Pakete-Weiterleitungstabelle Änderungen vorgenommen werden, kommt %es beim nächsten Paket im Zuge der Headerextraction zu einem segmentation fault. & - %minor bug \\ - - Initializer & - Die maximale Anzahl an Threads ist 16. Das stellt kein Problem dar, weil nur 12 Threads benötigt werden. mlx5\_pci: port 1 empty mbuf pool; mlx5\_pci: port 1 Rx queue allocation failed: Cannot allocate memory. - - Dieser Fehler tritt beim Ausführen von rte\_eth\_dev\_start(port) auf. Womöglich handelt es sich dabei um ein mempool problem. - & minor bug \\ + PacketInfoIpv4Icmp & + Wenn von einem Paket die Header extrahiert werden sollte (\texttt{fill\_info}), wurdr zuerst der \texttt{mbuf} in der \texttt{PacketInfo} verlinkt, dann IP version (IPv4) und Layer 4 Protokol (ICMP) ermittelt. Danach wurde die \texttt{PaketInfo} in die entsprechende protokollspezifische \texttt{PacketInfo} gecastet. Auf dieser verwandelten \texttt{PacketInfo} wird \texttt{set\_ip\_hdr} ausgeführt und es kam zum Segmentation-Fault, der im Abbruch des Threads mündete. Diesen Fehler gab es, weil die \texttt{PacketInfo} nicht richtig gesetzt wurde, d. h. der \texttt{PacketContainer} erhielt bei der Initialisierung leere \texttt{PacketInfos}. Beim Polling wurden dann die \texttt{mbufs} verlinkt und die \texttt{PacketInfos} wurden erstellt, aber nicht richtig gespeichert, sodass sie noch die initialen enthielten. Durch Veränderung der Übergabe eines Pointes konnte dieser Bug behoben werden. & + Critical Bug & + Geschlossen \\ + Initializer & + Die maximale Anzahl an Threads ist 16. Das stellt kein Problem dar, weil nur 12 Threads benötigt werden. mlx5\_pci: port 1 empty mbuf pool; mlx5\_pci: port 1 Rx queue allocation failed: Cannot allocate memory. Dieser Fehler tritt beim Ausführen von rte\_eth\_dev\_start(port) auf. Womöglich handelt es sich dabei um ein Mempool Problem. Dieses Problem wurde umgangen und stellt kein großes Hindernis dar. & Minor Bug & Geschlossen \\ + + Attacker & + Bei diesem Fehler handelt es sich um ein Speicherleck, weil Objekte angelegt wurden, die schließlich aber nicht korrekt gelöscht worden. Dieses Problem wurde bei Verschlankung des Attackers behoben, denn diese Objekte wurden dann nicht mehr benötigt. & + Critical Bug & + Geschlossen \\ + + PacketContainer & + Auch diese Fehler war ein Speicherleak. Durch das Hinzufügen eines spezialisierten Destruktors für die konkreten PacketInfos konnte auch dieses Problem behoben werden. & + Major Bug & + Geschlossen \\ + + Treatment & + Beim Verbindungsaufbau zwischen AEGIS sowie dem Server Bob wurde zwar das SYN erzeugt, allerdings kam dies nie auf einem der verbundenen Rechner an. Das Problem lag hier darin, dass das Architekturmuster mit getrennten Funktionen des Treatments für die unterschiedliche Richtung der Pakete die selbst erzeugten Pakete teilweise selbst noch einmal durch die Methode des Treatments für die Gegenrichtung behandelt wurden. Dies sorgte für den Verlust des erzeugten Paketes. Der Fehler wurde behoben und stellt nun kein Problem mehr dar. & + Major Bug & + Geschlossen \\ + \bottomrule + \end{longtable} -Schon während der Implementierungsphase wurden Bugs wenn möglich behoben. An den in dieser Tabelle genannten Problemen wird noch gearbeitet. Die Fehlerliste wird auch in der Validierungsphase laufend erweitert, sodass im Idealfall für das abschließende Review-Dokument eine vollständige Bug-Statistik erstellt werden kann. - -\textcolor{red}{toDo} - \end{document} diff --git a/doc/review_3/chapters/7-statistiken.tex b/doc/review_3/chapters/7-statistiken.tex index b689fec..cb4eb36 100644 --- a/doc/review_3/chapters/7-statistiken.tex +++ b/doc/review_3/chapters/7-statistiken.tex @@ -3,16 +3,17 @@ \begin{document} \chapter{Softwaremetriken und Statistiken}\thispagestyle{fancy} -Der Zweck von Softwaremetriken besteht in der ,,Definition von Software-Kenngrößen und Entwicklungsprozessen'' und der ,,Abschätzung des Prozess- und Kostenaufwands oder dem Qualitätsmanagement''\cite{swmetriken}. +Der Zweck von Softwaremetriken besteht in der \glqq Definition von Software-Kenngrößen und Entwicklungsprozessen\grqq{} und der \glqq Abschätzung des Prozess- und Kostenaufwands oder dem Qualitätsmanagement\grqq{}\cite{swmetriken}. Da das Reviewdokument noch vor Projektende fertiggestellt werden musste, sind die Daten, auf denen dieses Kapitel basiert, vom 10.07.2021. + \section{Benennungs- und Programmierkonventionen} Während der Meetings wurde sich auf zahlreiche Konventionen geeinigt. Diese wurden dann wiederum sowohl in den einzelnen Meetingprotokollen als auch in einem eigenen Wikieintrag festgehalten. -Unter Programmierkonventionen werden ,,Vorgaben für Programmierer über die Gestaltung von Programmen''\cite{progkonv} verstanden. Sie zeigen auf, wie der Code sowohl formal als auch strukturell gestaltet sein soll. Diese Konventionen sollen zur Verbesserung der Softwarequalität führen, was sich unter anderem in der durch die Konventionen gesteigerten Verständlichkeit und Änderungsfreundlichkeit des Codes zeigt. +Unter Programmierkonventionen werden \glqq Vorgaben für Programmierer über die Gestaltung von Programmen\grqq{} \cite{progkonv} verstanden. Sie zeigen auf, wie der Code sowohl formal als auch strukturell gestaltet sein soll. Diese Konventionen sollen zur Verbesserung der Softwarequalität führen, was sich unter anderem in der durch die Konventionen gesteigerten Verständlichkeit und Änderungsfreundlichkeit des Codes zeigt. \subsection{C/C++ und UML} -Das System wird in der Programmiersprache C++ entwickelt. Um dieses System zu entwerfen, wurden verschiedene Modelle und Diagramme im Rahmen des Softwareprojektes erstellt (z.B. Klassendiagramme, Aktivitätsdiagramme, Sequenzdiagramme). Diese Diagramme wurden mithilfe der Unified Modeling Language (UML) entwickelt. Die UML gibt bereits einige Richtlinien vor, wie zum Beispiel die grafische Notation oder die Bezeichner für die bei einer Modellierung wichtiger Begriffe. +Das System wird in der Programmiersprache C++ entwickelt. Um dieses System zu entwerfen, wurden verschiedene Modelle und Diagramme im Rahmen des Softwareprojektes erstellt (z. B. Klassendiagramme, Aktivitätsdiagramme, Sequenzdiagramme). Diese Diagramme wurden mithilfe der Unified Modeling Language (UML) entwickelt. Die UML gibt bereits einige Richtlinien vor, wie zum Beispiel die grafische Notation oder die Bezeichner für die bei einer Modellierung wichtiger Begriffe. \subsubsection{Namenskonventionen} Im Folgenden werden die Namenskonventionen im vorliegenden Softwareprojekt aufgezeigt und mit kurzen Beispielen unterlegt: @@ -24,10 +25,10 @@ Für \textbf{Methoden} werden ausschließlich Kleinbuchstaben verwendet. Sollte Für \textbf{Variablen} gelten die gleichen Konventionen wie für Methoden, sodass \texttt{packet\_inside} als Bespiel dienen kann. Zusätzlich soll ein Unterstrich vor dem Namen darauf hinweisen, dass es sich um eine Membervariable handelt, wie z. B. bei \texttt{\_cookie\_secret}. Statische Membervariablen beginnen somit mit \texttt{\_s\_}, wie bei \texttt{\_s\_timestamp}. -Auch bei \textbf{Objekten} gilt, dass nur Kleinbuchstaben verwendet werden sollen und mehrere Worte durch einem Unterstrich verbunden werden, wie in \texttt{nic\_man}. +Auch bei \textbf{Objekten} gilt, dass nur Kleinbuchstaben verwendet werden sollen und mehrere Worte durch eine Unterstrich verbunden werden, wie in \texttt{nic\_man}. \subsubsection{Formatierungs-Richtlinien} -Die Formatierungsrichtlinien legen unter anderem fest, dass nur ASCII-Zeichen, also zum Beispiel keine Umlaute oder ß, verwendet werden dürfen. Die Einrückung im Code beträgt vier Leerzeichen. Zudem sollen ,,dauerhaft'' geschweifte Klammern verwendet werden. Das heißt zum Beispiel, dass auch geschweifte Klammern einzeiliger if-Blöcken verwendet werden. Nach Methoden- und Klassennamen (oder Ähnlichem) stehen öffnende geschweifte Klammer. Hier soll kein Zeilenumbruch entstehen. Dies zeigt der Codeausschnitt \ref{klammern} beispielhaft. +Die Formatierungsrichtlinien legen unter anderem fest, dass nur ASCII-Zeichen, also zum Beispiel keine Umlaute oder ß, verwendet werden dürfen. Die Einrückung im Code beträgt vier Leerzeichen. Zudem sollen \glqq dauerhaft\grqq{} geschweifte Klammern verwendet werden. Das heißt zum Beispiel, dass auch geschweifte Klammern einzeiliger if-Blöcken verwendet werden. Nach Methoden- und Klassennamen (oder Ähnlichem) stehen öffnende geschweifte Klammern. Hier soll kein Zeilenumbruch entstehen. Dies zeigt der Codeausschnitt \ref{klammern} beispielhaft. \begin{lstlisting} [caption= {Formatierungsrichtlinie: Setzen von Klammern}, label = {klammern}] int i = rand(); @@ -70,7 +71,7 @@ Bei \texttt{@brief} lässt sich sofort erkennen, dass es sich um eine \textbf{Ku \texttt{@param} leitet hingegen die Beschreibung eines \textbf{Parameters}, der in eine Methode ein- oder von einer Methode ausgegeben wird, ein. \texttt{@param[in]} steht vor der Beschreibung eines \textbf{Eingabeparameters} und \texttt{@param[out]} vor einem \textbf{Ausgabeparameter}. Bei diesem handelt es sich um einen Parameter, der im C-Style einer Funktion mit Call-by-reference übergeben wird, damit er mit Werten gefüllt wird. Zur Beschreibung von Parametern, die sowohl ein- als auch ausgegeben werden, kann \texttt{@param[in, out]} verwendet werden. -Der Command \texttt{@return} hilft bei der Beschreibung eines \textbf{Rückgabewertes} und \texttt{@file} zur Erklärung des \textbf{Zwecks} einer Datei, also z. B. einer Klasse oder eines structs. +Der Command \texttt{@return} hilft bei der Beschreibung eines \textbf{Rückgabewertes} und \texttt{@file} zur Erklärung des \textbf{Zwecks} einer Datei, also z. B. einer Klasse oder eines Structs. \subsubsection{Source-Dateien} Pro Paket (vgl. Abb. \ref{fig:dospaketdiagramm}) wird ein Ordner in \texttt{source/} angelegt, der den gleichen Namen wie das Paket erhält. Alle zu diesem Paket zugehörigen Klassen befinden sich dann wiederum in diesem Ordner. Pro cpp-Klasse soll es eine eigene .cpp-Datei geben. Die dazugehörige Header-Datei wird mit \texttt{\#include } inkludiert. Im ganzen Projekt gibt es eine \texttt{main.cpp}-Datei in \texttt{source/} mit der main-Routine. @@ -84,18 +85,18 @@ Im Softwareprojekt wird die GitLab zur Versionsverwaltung genutzt. Diese Webanwe \subsubsection{Git} Außer in Präsentationen und Review-Dokumenten werden in Git nur ASCII-Zeichen verwendet. Die \textbf{Sprache} ist auch hier grundsätzlich Englisch, wobei diese Festlegung auch bei den Präsentationen und Review-Dokumenten abweicht. -Die \textbf{Branchnamen} sind klein geschrieben. Die Worte in diesem werden mit Unterstrich (,,\_'') verbunden. Dieselbe Regelungen gelten bei \textbf{Ordner- und Dateinamen}. +Die \textbf{Branchnamen} sind klein geschrieben. Die Worte in diesem werden mit Unterstrich (\glqq \_\grqq{}) verbunden. Dieselbe Regelungen gelten bei \textbf{Ordner- und Dateinamen}. \subsubsection{Issue} -Grundsätzlich werden die Issues in Englisch benannt. Lediglich deutsche ,,Eigennamen'' werden auf Deutsch geschrieben (Beispiel: Pflichtenheft). +Grundsätzlich werden die Issues in Englisch benannt. Lediglich \glqq Eigennamen\grqq{} werden auf Deutsch geschrieben (Beispiel: Pflichtenheft). Die Issues werden klein und im Imperativ geschrieben. Leerzeichen sind erlaubt. -Wenn Issues nicht nur einer sondern mehreren Personen zugeordnet werden sollen, wird dem eigentlichen Issue-Namen mit ,,@'' die Namen der zuständigen Teammitgliedern angehängt. Das heißt, der Issue-Name weist folgende Struktur auf: \texttt{ @ }). +Wenn Issues nicht nur einer, sondern mehreren Personen zugeordnet werden sollen, wird dem eigentlichen Issue-Namen mit \glqq @\grqq{} die Namen der zuständigen Teammitgliedern angehängt. Das heißt, der Issue-Name weist folgende Struktur auf: \texttt{ @ }). -Mit \texttt{@all} ist das Issue für alle Teammitglieder für die Bearbeitung offen. Derjenige, der mit der Bearbeitung dieser Aufgabe beginnt, löscht ,,@all'' trägt seinen eigenen Vornamen mit ,,@'' in den Issue-Namen ein. +Mit \texttt{@all} ist das Issue für alle Teammitglieder für die Bearbeitung offen. Derjenige, der mit der Bearbeitung dieser Aufgabe beginnt, löscht \glqq @all\grqq{} trägt seinen eigenen Vornamen mit \glqq @\grqq{} in den Issue-Namen ein. \subsubsection{Label} -In diesem Projekt werden die Labels grundsätzlich für zwei verschiedene Kategorien von Aufgaben verwendet verwendet: Zum einen für Status-Issues und zum anderen für Super-Issues (bzw. Tasks). Bei diesen Super-Issues handelt es sich um große Aufgaben, denen wiederum verschiedene Issues als Teilaufgaben zugeordnet werden. +In diesem Projekt werden die Labels grundsätzlich für zwei verschiedene Kategorien von Aufgaben verwendet: Zum einen für Status-Issues und zum anderen für Super-Issues (bzw. Tasks). Bei diesen Super-Issues handelt es sich um große Aufgaben, denen wiederum verschiedene Issues als Teilaufgaben untergeordnet werden. Die Benennung sieht Folgendes vor: @@ -121,15 +122,15 @@ Label für \texttt{Super-Issues bzw. Tasks} werden folgendermaßen benannt: \tex \caption{Beispiel: Label für außerordentliche Kategorien} \label{extra} \end{figure} -Label, die keiner dieser beiden Kategorien zugeordnet werden könne, werden folgendermaßen benannt: \texttt{EXTRA: