Seite 1 von 1

Reguläre Ausdrücke aus Datei laden

Verfasst: Samstag 13. Dezember 2008, 19:36
von PNS-Richi
Hallo,

ich hab zwar immer wieder in Python Programmiert, aber immer nur kleiner Sachen und dazwischen größere Pausen mit anderen Sprachen verbracht.

Nun will ich mich wieder mehr mit Python beschäftigen. FUSE und Netfilter.

Mein Problem nun:
Ich will Reguläre Ausdrücke Zeilenweise aus einer Textdatei Laden. Dies klappt auch so weit. Nur wenn ich die Reguläre Ausdrücke aus dieser Datei verwenden will gibts kein "matching" mehr. Also keiner der Ausdrücke ist passend. Wenn ich diese als String einfüge, also direkt in den Quellcode, dann funktioniert es.

Code: Alles auswählen

#! /usr/bin/env python
# -*- UTF8 -*-

import re
import ipqueue

f = open('/etc/l7-filter.reg', 'r')
regex = f.readlines()
f.close();

q = ipqueue.IPQ(ipqueue.IPQ_COPY_PACKET)
print "fileno is", q.fileno()
while 1:
	ipqueue_send=False
	
	t = q.read()

	for reg in regex:
		p = re.compile(reg.replace("\n", ""), re.IGNORECASE)
		m = p.match(t[9])
		if m:
			print "Drop returned:", q.set_verdict(t[0], ipqueue.NF_DROP)
			ipqueue_send=True
			break

	if ipqueue_send==False:
		print "Accept returned:", q.set_verdict(t[0], ipqueue.NF_ACCEPT)
Danke für eure Hilfe.

lg Richi

Verfasst: Samstag 13. Dezember 2008, 19:56
von joshi
Ich denke, du musst die Datei im Modus 'rb' öffnen, da in deinen patterns wahrscheinlich backslashes sind, oder?

Verfasst: Samstag 13. Dezember 2008, 20:20
von lunar
Und was hat der Backslash jetzt mit Binärdateien zu tun?

Dein Problem ist wohl – ohne das ich die Ausdrücke kennen – die Tatsache, dass ".match()" nur am Anfang der Zeichenkette, nicht aber an beliebigen Stellen sucht. Ich denke, du suchst ".search()".

Zu deinem Code noch ein paar Anmerkungen. Statt ".replace('\n', '')" besser ".rstrip('\n')". Desweiteren kannst du statt ".readlines()" auch über das Dateiobjekt iterieren. Zuguterletzt hat Python auch bool'sche Literale: "while True" ist die bessere Variante einer unbedingten Schleife.

Verfasst: Samstag 13. Dezember 2008, 20:21
von PNS-Richi
Hallo,

ist mir schon aufgefallen, ich hab es mit

Code: Alles auswählen

reg = reg.encode('utf-8').decode('string_escape').decode('utf-8')
gelöst.

Du meinst also so was wie:

Code: Alles auswählen

f = open('/etc/l7-filter.reg', 'r')
for reg in f:
   ...
f.close(); 
Ich wollte es direkt am Anfang in eine Variable laden. Ansonsten würde er doch bei jedem Schleifndurchgang die Datei erneut laden, oder?

"match" müsste reichen, ich will ja immer nur die ersten Teile einer Verbindung überprüfen, aber danke für den Hinweis. Theoretisch sollte man aber mit Regulären Ausdrücken das so flexibel gestallten das ich auch mit match einen treffer landen kann, wenn der Teil den ich brauche irgendwo in der mitte auftaucht, oder ich irre mich jetzt.

Falls du noch einen Hinweis/Tipp für mich hast nur raus damit, damit ich schnell in Python rein komme :)

Code: Alles auswählen

#! /usr/bin/env python
# -*- coding: utf-8 -*-

import re
import ipqueue

f = open('/etc/l7-filter.reg', 'r')
regex = f.readlines()
f.close();

q = ipqueue.IPQ(ipqueue.IPQ_COPY_PACKET)
print "fileno is", q.fileno()
while True:
	ipqueue_send=False
	
	t = q.read()
	print "I read a packet:", t
	#print "Accept returned:", q.set_verdict(t[0], ipqueue.NF_ACCEPT)

	for reg in regex:
		
		reg = reg.rstrip('\n')

		reg = reg.encode('utf-8').decode('string_escape').decode('utf-8')

		p = re.compile(reg, re.IGNORECASE)
		m = p.match(t[9])
		if m:
			print "Drop returned:", q.set_verdict(t[0], ipqueue.NF_DROP)
			ipqueue_send=True
			break

	if ipqueue_send==False:
		print "Accept returned:", q.set_verdict(t[0], ipqueue.NF_ACCEPT)

Verfasst: Samstag 13. Dezember 2008, 20:49
von str1442
Die Datei wird einmal geladen und ist dann ein "iterable", wie eine Liste.

Verfasst: Samstag 13. Dezember 2008, 21:15
von BlackJack
Nein nicht wie eine Liste. PNS-Richi macht das schon richtig. Über eine Datei kann mal nur einmal iterieren, über eine Liste beliebig oft. Natürlich könnte man die Datei erneut öffnen oder mit `seek()` wieder an den Anfang springen, aber ich denke eine Liste ist hier der bessere Weg.

@PNS-Richi: Dieses Tänzchen mit dem Kodieren habe ich nicht so recht verstanden? Was soll das mit UTF-8? Vor allem das Du am Anfang *enkodierst*!? Das ist Unsinn und fällt sofort auf die Nase wenn `reg` mal etwas ausserhalb von ASCII enthalten sollte.

Kannst Du die Ausdrücke nicht gleich richtig in die Datei schreiben, so dass sie nicht noch einmal nachbearbeitet werden müssen?

Ausserdem würde ich das vor der Endlosschleife machen und dann auch gleich in `re`-Objekte kompilieren, denn das Ergebnis ist ja immer das gleiche.

Verfasst: Samstag 13. Dezember 2008, 21:29
von BlackJack
Ungetestet:

Code: Alles auswählen

import re
import ipqueue


def main():
    regex_file = open('/etc/l7-filter.reg', 'r')
    regexes = [re.compile(r.rstrip('\n'), re.IGNORECASE) for r in regex_file]
    regex_file.close()
    
    queue = ipqueue.IPQ(ipqueue.IPQ_COPY_PACKET)
    print "fileno is", queue.fileno()
    
    while True:
        packet = queue.read()
        print "I read a packet:", packet
        
        if any(r.match(packet[9]) for r in regexes):
            text, verdict = 'Drop', ipqueue.NF_DROP
        else:
            text, verdict = 'Accept', ipqueue.NF_ACCEPT
        
        print text, 'returned:', queue.set_verdict(packet[0], verdict)


if __name__ == "__main__":
    main()

Verfasst: Samstag 13. Dezember 2008, 22:48
von str1442
Nein nicht wie eine Liste. PNS-Richi macht das schon richtig. Über eine Datei kann mal nur einmal iterieren, über eine Liste beliebig oft. Natürlich könnte man die Datei erneut öffnen oder mit `seek()` wieder an den Anfang springen, aber ich denke eine Liste ist hier der bessere Weg.
Natürlich. Ich hätte auch Generator sagen können, und wäre damit der Wahrheit doch näher gekommen. Aberwieviele Anfänger verstehen sofort das Konzept eines Generators und / oder kennen dieses? Wichtig war nur, das das Dateiobjekt genau einmal geladen wird und es sich dann (im Gebrauch mit einer einfachen Forschleife) wie eine Liste (die nunmal das Objekt ist, mit dem Forschleifen eingeführt werden) verhält.

Verfasst: Samstag 13. Dezember 2008, 23:08
von lunar
Das ist so trotzdem irreführend. Ein fundamentaler Unterschied zwischen einer Iteration über einer Liste und der über einem Dateiobjekt ist, dass ersteres den Status der Liste selbst nicht ändert, letzteres dagegen den Dateizeiger verschiebt. Das kann bei geschachtelten Schleifen oder erneuter Iteration lustige Effekte haben ;)

Verfasst: Sonntag 14. Dezember 2008, 00:21
von PNS-Richi
Auszug aus der Datei mit den Regulären Ausdrücken:

Code: Alles auswählen

(E|E )(\\x00|\\xc5|\\xd4)
^(gnd[\x01\x02]?.?.?\x01|gnutella connect/[012]\.[0-9]\x0d\x0a|get /uri-res/n2r\?urn:sha1:|get /.*user-agent: (gtk-gnutella|bearshare|mactella|gnucleus|gnotella|limewire|imesh)|get /.*content-type: application/x-gnutella-packets|giv [0-9]*:[0-9a-f]*/|queue [0-9a-f]* [1-9][0-9]?[0-9]?\.[1-9][0-9]?[0-9]?\.[1-9][0-9]?[0-9]?\.[1-9][0-9]?[0-9]?:[1-9][0-9]?[0-9]?[0-9]?|gnutella.*content-type: application/x-gnutella|...................?lime)
Ein Paket von aMule:

Code: Alles auswählen

E\x00\x00\x86LR@\x00@\x06\x8bG\xc0\xa8\x00\x01H\xacY\x83\x96\x06\x125y#\xe9\xb9\xae\x96\xf53\x80\x18\x00\\\xd4\x01\x00\x00\x01\x01\x08\n\x01\x13\xa6A\x00\x00\x00\x00\xe3M\x00\x00\x00\x01\xf9\x19\xdde\x03\x0e\xf7\xa5\xd90N)\x1e\xc0o\x1a\x00\xd2\x00\x006\x12\x04\x00\x00\x00\x02\x01\x00\x01\x14\x00http://www.aMule.org\x03\x01\x00\x11<\x00\x00\x00\x03\x01\x00 \x1d\x07\x00\x00\x03\x01\x00\xfb\x80\x08\x04\x03
Also muss ich das ja escapen, oder kennt wer eine andere Lösung? DasProblem ist das ich von ähnlichen Lösungen die Regulären Aussdrücke übernehmen will und die unterschiedlich vorliegen.

Wenn ich nun

Code: Alles auswählen

(E|E )(\\x00|\\xc5|\\xd4)
in

Code: Alles auswählen

(E|E )(\x00|\xc5|\xd4)
ändere, muss ich nicht mehr escapen.

Das Script ist derzeit etwas unschön, soll ja auch nurmal zum testen reichen.

Im Endeffekt soll es die Firewall erweitern, da z.B.: Tauschbörsen auf verschiedenen Ports anzutreffen sind und irgendwie muss ich das ja unterbinden.

Danke für eure Hilfe.

@BlackJack: Danke für die schönere Strukturierung - hat mir einiges von der Python Syntax näher gebracht.

lg Richi