Plugin System

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
AxXel001
User
Beiträge: 29
Registriert: Sonntag 7. Juni 2015, 22:22

Hey Leute,

ich arbeite momentan an einem Tool zur Erkennung von Anomalien in einem Netzwerk auf Basis statistischer Tests. Dafür möchte ich die Möglichkeit anbieten, die Eingangsdatenquelle beliebig zu wählen (zB direkt vom Protokoll Stack, aus einer PCAP Datei oder sonst was). Das System nimmt unabhängig von der Datenquelle erstmal nur rohe Bytestrings entgegen (andere Module sind dann zum Erkennen und Umwandeln in Pakete zuständig).

Meine Idee war nun, eine Art Plugin System zu entwickeln.
Beispiel: Das Programm funktioniert mit PCAP Dateien, man kann also IP Pakete aus PCAP Dateien auslesen schön und gut. Jetzt hat irgendein schlauer Mensch ein anderen Datenformat zum Speichern von Traffic entwickelt (zB PCAPNG), mein Programm kann damit aber nicht arbeiten.
Jetzt soll es so funktionieren, dass man lediglich den Teil des Programm neu implementieren muss, der die neue Datenquelle verarbeiten und Bytestrings generieren kann.
Man könnte zB vorgeben, dass jedes dieser Module eine Klasse mit dem selben Namen enthalten muss, welche eine Methode read_byte_string() enthalten muss.

Bisher würde ich sagen, das lässt sich gut mit imp und exec machen. Wer sich jetzt laut über die unzähligen Sicherheitsprobleme bei exec beschweren will dem sei vorher gesagt, das Tool ist nicht dafür ausgelegt als root auf irgendeinem Server zu laufen. Außerdem kann jeder die Plugins, die er sich herunterlädt vorher selbst überprüfen oder von einer vertrauenswürdigen Webseite herunterladen (will sagen, der Sicherheitsaspekt sei hier mal hinten angestellt).

Bitte um Anregungen, Vorschläge und natürlich die lange Liste von Gründen, warum mein Konzept ganz schrecklich ist ;)
LG, Alex
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Dazu brauchst du kein exec(). Guckstu: https://docs.python.org/3/library/impor ... ort_module. Und in Python 2 kannst du die builtin function __import__() verwenden.
In specifications, Murphy's Law supersedes Ohm's.
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@AxXel001: exec ist für ein Plugin-System überflüssig und Sicherheitsprobleme holst Du Dir ja nur rein, wenn jemand Unbefugtes Input liefern kann, der böse Sachen macht, also wenn Du die Netzwerkpakete mit exec bearbeitest.

Da Python eine Dynamische Sprache ist, ist so ein Plugin-System quasi schon eingebaut. Am besten legst Du Dir ein plugin-Verzeichnis an, in das alle Module kommen, das Du dann in den Suchpfad einfügen kannst und über __import__ importieren, oder halt per "imp. load_module" mit komplettem Dateinamen.

Du kannst entweder alle Plugins beim Programmstart laden und die Module registrieren ihre Klassen an einer zentralen Stelle, oder in Deinen Config-Dateien steht sowas wie "modulname.Klasse" und Du lädst das Modul erst bei Bedarf. Dass die Klassen ein festes Interface (read_byte_string) haben, ist normal, aber dass die Klassen einen festen Namen haben, ist eine unnötige Einschränkung. Dann können auch verschiedene Varianten in einem Modul zusammen genutzt werden.
AxXel001
User
Beiträge: 29
Registriert: Sonntag 7. Juni 2015, 22:22

Vielen Dank für die schnelle Hilfe.
Du kannst entweder alle Plugins beim Programmstart laden und die Module registrieren ihre Klassen an einer zentralen Stelle, oder in Deinen Config-Dateien steht sowas wie "modulname.Klasse" und Du lädst das Modul erst bei Bedarf. Dass die Klassen ein festes Interface (read_byte_string) haben, ist normal, aber dass die Klassen einen festen Namen haben, ist eine unnötige Einschränkung. Dann können auch verschiedene Varianten in einem Modul zusammen genutzt werden.
Ja genau so hatte ich mir das auch überlegt. Ich nenne die Klassen, die Eingangsdaten liefern 'scanner', hab auch ein entsprechendes Verzeichnis angelegt und wollte den Import dann über imp regeln.
Die Sache mit dem Klassen registrieren hab ich noch nicht ganz verstanden.
Also, in der Konfigdatei gebe ich dann zB an

Code: Alles auswählen

[scanner]
path: 'pfad/zu/scanner1;pfad/zu/scanner2;...;pfad/zu/scanner_n'
Nur nach welchem Muster sollte ich die Scannerklassen dann selbst aufbauen? Beim Modulimport müsste dann ja jedes Plugin Modul irgendwo eine Instanz von seiner entsprechenden Scannerklasse speichern. Vor allem sollte diese Instanz ja für das eigentliche System in einer Liste o.ä. gespeichert werden, damit alle Plugins nacheinander aufgerufen werden können.

Wie sollte man da am besten vorgehen?
LG
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

setuptool bietet entry points an um Plugins zu finden. Wenn du die nutzt lassen sich Plugins einfach mit pip installieren und deine Anwendung könnte die danach finden ohne das ein User noch irgendwas machen muss.
AxXel001
User
Beiträge: 29
Registriert: Sonntag 7. Juni 2015, 22:22

Das Finden von Plugins ist ja nicht das Problem, die sollen sowieso alle in den plugin Ordner. Das Problem ist, wie mache ich es richtig, dem System zur Laufzeit eine Instanz jeder Pluginklasse zu übergeben und sicherzustellen, dass die erforderlichen Methoden vorhanden sind.
Zusammenhacken kann ich mir das sicherlich auch, vielleicht kennt aber jemand 'den' richtigen Weg? ;)

LG
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Entry points würden nicht nur auf irgendeine Datei zeigen. Plugin Autoren könnten damit direkt auf eine bestimmte Funktion oder Klasse zeigen, die du dann aufrufen könntest. Wo genau sich diese dann befindet oder wie die heisst könnte dir dann egal sein.

Ob eine Pluginklasse funktioniert wie sie soll ist nicht zu ermitteln. Du musst einfach davon ausgehen dass sie sich so verhält wie sie sich Verhalten soll. Das einzige was du machen könntest wäre eine Abstraktionsschicht zu schreiben die falls irgendwelche unerwarteten Exceptions auftreten diese abfängt. Dies könnte auch beeinhalten Plugins in einem eigenen Prozess laufen zu lassen ob dies machbar oder sinnvoll ist hängt dann von deiner Anwendung ab.
AxXel001
User
Beiträge: 29
Registriert: Sonntag 7. Juni 2015, 22:22

Alles klar vielen Dank, ich werd mich in setuptools erstmal einlesen und bei weiteren fragen nochmal melden. Vielen Dank noch mal!! :)
AxXel001
User
Beiträge: 29
Registriert: Sonntag 7. Juni 2015, 22:22

Okay, ich muss zugeben ich habe einige Probleme beim Verständnis von setuptools.
Vorweg, meine Verzeichnisstruktur sieht ca so aus

Code: Alles auswählen

MyApplication/
    /start.py
    /dosomething.py
    /plugins/
        /plugin1/
            /__init__.py
            /plugin1.py
        /plugin2/
            /__init__.py
            /plugin2.py
Ich hab also einen plugin Ordner, in dem alle weiteren plugins als Pakete installiert werden sollen (jemand eine bessere Idee?).
Die Plugins können natürlich (wenn sie zB irgendwann mal von einer Webseite heruntergeladen werden) überall im Dateisystem liegen. Ich definiere ja für jedes eine setup.py in der dann auch die Entrypoints angegeben werden (dazu komme ich gleich noch).
Erstmal habe ich das Problem, dass beim normalen 'python setup.py install' das Paket im site-packages Ordner landet. Da dieses Paket ja aber nur für das Programm 'MyApplication' sichtbar sein soll, möchte ich den Installationspfad anpassen. Dazu habe ich nichts Einheitliches bzw. Schlüssiges gefunden.

So, nun zu den Entrypoints. Ich hab das so verstanden, dass ich jetzt als Entwickler von MyApplication hingehe und sage 'okay, jeder der ein Plugin schreiben will kann das tun, ABER er muss den Entrypoint load_plugin definieren' (als Beispiel jetzt). Wenn ich load_plugin aufrufe soll das Plugin mir ein Objekt zurück geben, das eine Methode read_bytestring besitzt und mir wie im ersten Post erklärt meine Daten zurückgibt.

Wenn mein Ansatz soweit richtig ist dann habe ich zumindest nur noch Syntaxprobleme. Die würde ich in diesem Fall dann genauer beschreiben.
Antworten