String aus Logdatei Auswerten

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
lexnared
User
Beiträge: 4
Registriert: Donnerstag 9. April 2020, 19:26

Hallo!
Ich bin erstaunt wie sehr ich in den Jahren eingerostet bin, was Python betrifft.

Gerne würde ich die Logdatei meiner Firewall nach einem String z.B. "SPT=" durchsuchen.
Den folgenden Text für 5 Zeichen ausgeben.

Sinn dahinter.
Die Logdatei hat schon über 1000 Einträge über Ports die durch die Firewall geblockt werden.
Teilweise auch doppelt (Das bekomme ich aber schon hin)
Die gesperrte Ports, würde ich mir gerne anzeigen lassen.

Auszug aus meiner logDatei:

Code: Alles auswählen

Mar 11 10:21:53 nextcloudpi kernel: [17488.543867] [UFW BLOCK] IN=eth0 OUT= MAC=XXXX  SRC=192.168.1.4 DST=192.168.1.30 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=20855 DF PROTO=TCP[b] SPT=36194[/b] DPT=2010 WINDOW=490 RES=0x00 ACK FIN URGP=0
Mar 11 10:21:55 nextcloudpi kernel: [17490.303950] [UFW BLOCK] IN=eth0 OUT= MAC=XXXX  SRC=192.168.1.4 DST=192.168.1.30 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=20856 DF PROTO=TCP [b]SPT=31243[/b] DPT=2010 WINDOW=490 RES=0x00 ACK FIN URGP=0
Mar 11 10:22:19 nextcloudpi kernel: [17515.004099] [UFW BLOCK] IN=eth0 OUT= MAC=XXXX  SRC=192.168.1.4 DST=192.168.1.30 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=20859 DF PROTO=TCP [b]SPT=37890[/b] DPT=2010 WINDOW=490 RES=0x00 ACK FIN URGP=0
Ich habe schon einiges über readlines gelesen, bin aber etwas überfordert ob dies hier zutreffend ist.

Hier mein bisheriger Code:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import re
logfile = open("c:\\users\\lx\\desktop\\ufw.log", "r")		# oeffnen der datei
logfileinhalt = logfile.readlines()                         # einlesen des der logdatei
logfile.close()		                                        # schliessen der datei

def check_ufw():
    with open ("c:\\users\\lx\\desktop\\ufw.log") as logTemp:
        datafile = logTemp.readlines()
        
    for line in datafile:
        if "SPT" in line:
            print (line)


    
check_ufw()
Benutzeravatar
__blackjack__
User
Beiträge: 13938
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@lexnared: Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (PascalCase).

Du importierst das `re`-Modul, verwendest es aber nirgends. Du liest den Inhalt der Logdatei zweimal ein und machst mit `logfileinhalt` dann gar nichts.

Man muss auch nicht die Datei komplett in den Speicher lesen wenn man die nur zeilenweise untersuchen möchte. Also `readlines()` einfach weg lassen und direkt über das geöffnete Dateiobjekt iterieren.

Bei Textdateien sollte man die Kodierung explizit beim öffnen angeben.

Was genau ist jetzt eigentlich das Problem? Was funktioniert an den Code nicht, oder nicht so wie Du das erwartet hast? Bekommst Du eine Fehlermeldung? Falls ja welche? Macht das Programm etwas anderes als Du erwartet hast? Falls ja, was hast Du erwartet und wie weicht das Programm davon ab?

Du willst übrigens nicht die 5 folgenden Zeichen, weil eine Portnummer auch kürzer als 5 Zeichen sein kann.

Ich würde ja entweder gleich mit einem regulären Ausdruck auf jede Zeile losgehen, oder aber per `index()` nach der Position von " SPT=" suchen, also mit Leerzeichen davor und "=" danach, um auszuschliessen, dass nicht irgend wo ander "SPT" innerhalb eines anderen Wortes/Textes vorkommt.
“Java is a DSL to transform big Xml documents into long exception stack traces.”
— Scott Bellware
lexnared
User
Beiträge: 4
Registriert: Donnerstag 9. April 2020, 19:26

Zu meinem Problem.
Ich hätte gerne eine reine Ausgabe der Portnummern.
Leider benötige ich etwas Hilfe wie ich nur diese selektieren und Ausgeben kann.

Da hast du recht, das re wird nicht mehr verwendet. Bevor ich diesen Beitrag schrieb, habe ich einiges getestet.
Benutzeravatar
DeaD_EyE
User
Beiträge: 1206
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Code: Alles auswählen

import re


ufw_log = """Mar 11 10:21:53 nextcloudpi kernel: [17488.543867] [UFW BLOCK] IN=eth0 OUT= MAC=XXXX  SRC=192.168.1.4 DST=192.168.1.30 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=20855 DF PROTO=TCP[b] SPT=36194[/b] DPT=2010 WINDOW=490 RES=0x00 ACK FIN URGP=0
Mar 11 10:21:55 nextcloudpi kernel: [17490.303950] [UFW BLOCK] IN=eth0 OUT= MAC=XXXX  SRC=192.168.1.4 DST=192.168.1.30 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=20856 DF PROTO=TCP [b]SPT=31243[/b] DPT=2010 WINDOW=490 RES=0x00 ACK FIN URGP=0
Mar 11 10:22:19 nextcloudpi kernel: [17515.004099] [UFW BLOCK] IN=eth0 OUT= MAC=XXXX  SRC=192.168.1.4 DST=192.168.1.30 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=20859 DF PROTO=TCP [b]SPT=37890[/b] DPT=2010 WINDOW=490 RES=0x00 ACK FIN URGP=0"""


def ufw_read_lines(text: str) -> list[int]:
    regex = re.compile(r"SPT=(\d+)")
    results = []
    for line in text.splitlines():
        if match := regex.search(line):
            value = int(match.group(1))
            results.append(value)
    return results


def ufw_read_all(text: str) -> list[int]:
    return list(map(int, re.findall(r"SPT=(\d+)", text)))


def ufw_read_file(file: str) -> list[int]:
    with open(file) as fd:
        return list(map(int, re.findall(r"SPT=(\d+)", fd.read())))
Falls du die Daten nur in der Konsole ausgeben möchtest, musst du str nicht unbedingt in int konvertieren.
Wenn du z.B. die Postnummern mit einem Leerzeichen getrennt ausgeben willst, wäre ein join nützlich, aber das geht nur mit str und nicht mit int.
Alternativ kann man aber auch die print-funktion missbrauchen:

Code: Alles auswählen

zahlen = [42, 1337, 15]

for zahl in zahlen:
    print(zahl, end=" ")

print()
Oder mit str und der join methode:

Code: Alles auswählen

zahlen = ["42", "1337", "15"]


print(" ".join(zahlen))
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Sirius3
User
Beiträge: 18227
Registriert: Sonntag 21. Oktober 2012, 17:20

Dateinamen definiert man am besten am Anfang des Programms als Konstante, dann hat man einen schnellen Überblick, welche Dateien von wo gelesen werden.
Deine Zeilen sind ja sehr einfach aufgebaut. Du hast mehrere Parameter, die per Leerraum getrennt sind, in der Form key=value.

Diese Struktur läßt sich in ein Wörterbuch umwandeln, wo Du dann nur den Key "SPT" herauslesen mußt:

Code: Alles auswählen

UFW_FILENAME = "c:/users/lx/desktop/ufw.log"
def check_ufw():
    with open(UFW_FILENAME) as file:
        for line in file:
            parameter = dict(
                part.rpartition("=")[::2]
                for part in line.split()
            )
            print(parameter.get("SPT"))

if __name__ == "__main__":
    check_ufw()
Antworten