Samstag, 9. April 2011

Vorstellung der Senderseite des ICMPFrameworks

Guten Abend,

Das Projekt ist dazu da, Daten in eine Richtung durch Firewalls, Proxies, Router und dergleichen zu schleusen, denn während diese praktisch immer TCP Pakete und UDP Datagramme abfangen und filtern, fallen ICMP Echo Requests (auch bekannt als Ping) meist unter den Tisch. Abgesehen davon fallen solche Pakete als Ping request/reply natürlich in einem etwaigen Sniffer weniger auf. Ein solches ICMP-Paket bietet noch Platz für Nutzdaten, sodass man diese meist unbemerkt (wenn es nicht zu viele Daten sind) versenden kann. Das Problem hierbei ist vorrangig, dass ICMP nicht gewährleistet, dass – und in welcher Reihenfolge – Pakete ankommen; das muss das Framework also managen, und das möglichst ohne den User damit zu behelligen. Aus diesem Grund habe ich (mit tatkräftiger Unterstützung von f0Gx) ein Projektdesign entworfen, das ich im Nachfolgenden vorstellen möchte.

Hier sehen wir also rechts das Herzstück des Frameworks, die Klasse ICMPGateway, die für die Kommunikation mit dem Netzwerk verantwortlich ist. Innerhalb dieser Klasse gibt es zwei Threads, einen receiveThread, der genau das macht, was der Name verspricht. Er empfängt Bestätigungspakete von der Gegenseite und leitet das Nachsenden von fehlenden Paketen ein; das geschieht dann im resendThread. Links davon ist die Klasse DataSupply zu sehen, die als Interface für verschiedene Daten-sendede Klassen dient (hier nur PlainDataSender). ICMPGateway verwaltet die DataSupplies um ihre Pakete zuverlässig zustellen zu können. Das Zustellen der Pakete wird mit ICMPGateway::send eingeleitet. Diese Funktion ist blockend bis alle Daten bei der Gegenseite angekommen sind.

Die DataSupply-Klasse hat einen internen Zwischenspeicher für Pakete, auf die das ICMPGateway zugreift. Diese Storage lässt sich mit der funktion insertData füllen und hinterher mit dispatchStorage dann via ICMPGateway versenden.
Schließlich gibt es noch die (Beispiel-)Klasse PlainDataSender. Sie baut auf dem Framework auf und nutzt es um einfache Datenbuffer zu versenden. Hierfür sind 2 Funktionen verfügbar: dispatch und store. Store speichert daten in einem internen Speicher zwischen, bis dispatch aufgerufen wird und die Daten versendet werden. Diese Klasse ist dank dem Framework sehr einfach und greift nur auf die Funktionen von DataSupply zurück.
Ein weiteres Beispiel für eine solche Klasse, die das Framework nutzt wäre vielleicht ScreenShotSender, welche beispielsweise in bestimmten Intervallen Screenshots per ICMP an den Empfänger senden könnte. Da das ganze Projekt für Multithreading ausgelegt ist, funktioniert das alles auch simultan. Als kleiner Abschluss hier noch die Beispielsource von PlainDataSender.
PlainDataSender.h

01#include "DataSupply.h"
02
03#define PACKETSIZE 28
04#define PLAINDATASENDER_ID 0
05
06class PlainDataSender : public DataSupply {
07public:
08    void store(const byte *data, uint len);
09    void dispatch(std::string host);
10    byte getID() {
11        return PLAINDATASENDER_ID;
12    }
13private:
14    std::vector<byte> storage;
15};
PlainDataSender.cpp

01#include "PlainDataSender.h"
02
03void PlainDataSender::store(const byte *data, uint len) {
04    for (int i = 0; i < len; i++)
05        storage.push_back(data[i]);
06}
07
08void PlainDataSender::dispatch(std::string host) {
09    uint packetsize = PACKETSIZE;
10    uint done = 0, toDo = storage.size();
11
12    while (done < toDo) {
13        if (toDo - done < packetsize)
14            packetsize = toDo - done;
15        insertData((byte *)(&storage[0] + done), packetsize);
16        done += packetsize;
17    }
18
19    storage.clear();
20    dispatchStorage(host);
21}
Diese Klasse implementiert also mithilfe des Frameworks einen einfachen „buffernden“ Datensender. Die ID, die oben definiert ist, dient dazu den Sendertyp dem passenden Empfänger zuzuordnen.
main.cpp

01#include "PlainDataSender.h"
02
03int main() {
04    PlainDataSender i;
05    string a = "Hallo, Test";
06
07    i.store((byte *)a.c_str(), a.length());
08    i.store((byte *)a.c_str(), a.length());
09
10    i.dispatch("192.168.0.101");
11    return 0;
12}
Mit diesem Code kommt also zwei mal „Hallo, Test“ an. Garantiert ;)
So viel zur kleinen Vorschau zum Framework. Ich hoffe ich werde die Empfängerseite (die übrigens für Linux ausgelegt ist) morgen fertig stellen können, und dann das Framework hier weiter im Detail vorstellen und veröffentlichen können.

~fred

Keine Kommentare:

Kommentar veröffentlichen