HTTP-Request über Socket: Serverantwort ignorieren (DoS)

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
Onkel Schnitzel
User
Beiträge: 2
Registriert: Montag 18. Dezember 2006, 14:37

Servus,

ich schreibe an der Uni Tübingen gerade eine Studienarbeit, die sich mit DoS- und DDoS-Simulationen beschäftigt, die Ergebnisse der Arbeit werden verwendet, um einen Netzwerksimulator zu verbessern. Gleich vorweg: damit das Thema nicht wie in anderen Threads zu Grundsatzdiskussionen übers Hacken führt, bitte ich die Admins und Mods, notfalls meine IP zu überprüfen, ich schreibe den Beitrag von meinem Arbeitsplatz am Lehrstuhl. Es geht also wirklich nur um Forschung.

Ich beschäftige mich erst seit kurzem mit Python und bin noch ziemlicher Anfänger, vielleicht kann mir jemand bei dem Problem helfen, das mich gerade aufhält. Es geht darum, einen Server bis hin zum Paketverlust zu belasten. Dazu habe ich ein Skript, dass mehrere Threads öffnet. Jeder Thread läuft eine bestimmte Zeit, während dieser Zeit wird in jeder Sekunde ein Socket geöffnet (die Sekundenintervalle sind nur da um die Messungen besser vergleichen zu können), eine bestimmte Anzahl HTTP-GET-Requests (1.1) gesendet und dann der Socket wieder geschlossen. Das klingt sicher umständlich, aber ich habs nicht geschafft, mehrere parallele Sockets zu öffnen, keine Ahnung wie das geht.

Das Problem ist nun folgendes: nachdem der Socket geöffnet wurde und ich einen Request sende, bekomme ich vom Server immer nur Antworten, wenn ich diese z.B mit s.recv(4096) annehme. Wenn ich nur sende und die Antworten ignoriere, also kein s.recv... reinschreibe, schickt der Server keine Antwort, sondern nur ein TCP-ACK ohne das eigentliche Dokument (ich überprüfe alles mit Wireshark/Ethereal). Nur leider ist es so: wenn ich s.recv... verwende um die Antworten anzunehmen, ist das ein deutlicher Performanceverlust der mir alles verzögert. Gibt es eine Möglichkeit, HTTP-Requests zu senden und die Antwort komplett zu ignorieren? Der Server sollte aber schon antworten, es geht ja darum diesen unter Last zu setzen. Wenn ich den Empfangspuffer beim Client einfach niedrig setze und immer wieder lösche, resettet der Client trotzdem ständig die Socket-Verbindung, ich vermute wegen Pufferüberlauf.

Vielen Dank für Tips, notfalls kann ich mein primitives Skript noch posten falls es jemanden interessiert.
BlackJack

Wenn Du die Antwort nicht liest, dann wird sie vom Server auch nicht (komplett) gesendet werden. Das Abbrechen der Verbindungen bei nichtabholen der Antwort wird wohl eine Schutzmassnahme des Servers vor solchen DoS-Angriffen sein, die versuchen alle Threads bzw. Sockets zu belegen.

Was meinst Du mit mehreren parallelen Sockets?
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

BlackJack hat geschrieben:Was meinst Du mit mehreren parallelen Sockets?
Vielleicht mehrere Anfragen gleichzeitig per Threading verschicken???
Da hilft evtl. http://www.python-forum.de/topic-7447.html weiter ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

jens hat geschrieben:
BlackJack hat geschrieben:Was meinst Du mit mehreren parallelen Sockets?
Vielleicht mehrere Anfragen gleichzeitig per Threading verschicken???
Na das macht er ja jetzt schon, weil das mit den "parallelen Sockets" nicht funktioniert hat.
Onkel Schnitzel
User
Beiträge: 2
Registriert: Montag 18. Dezember 2006, 14:37

Ich hab inzwischen einen Tip bekommen was der Grund für mein Problem ist. Wenn ich beim Client kein TCP-Empfangsfenster einrichte (also sowas wie sock.recv(...) ), dann schickt der Server auch keine Antwort, was irgendwie logisch ist wenn man weiß wie TCP funktioniert. Dann kann ich also nicht so ohne weiteres die Antworten des Servers ignorieren.

Gibt es dann event. eine Möglichkeit folgenden Code ein bisschen effizienter zu schreiben, die Behandlung der Antwort über ein Empfangsfenster macht offenbar schon einen großen Unterschied aus, was Ressourcen betrifft. Der Client sollte die Antworten des Servers einfach so effizient wie möglich droppen, das was in der innersten Schleife mit response_string steht:

Code: Alles auswählen

# -*- coding: utf-8 -*-
import time
import threading
import socket

thr = 2

class clientThread(threading.Thread):

	def run(self):

		sec = 1
		run = 3
		req = 10
		url = '192.168.37.66'
		prt = 80
		get = """GET /anfrage_datenbank.php HTTP/1.1\r\nHost: 192.168.37.66\r\n\r\n"""

		startzeit = time.time()
		laufzeit = time.time()

		while (time.time() - startzeit) < run:
			if (time.time() - laufzeit) < sec:
				i = 0
				s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
				s.connect((url, prt))

				while i < req:
					s.send(get)
					response_string, server = s.recvfrom(4096)
					response_string = 0
					i += 1

				s.close()
				while (time.time() - laufzeit) < sec:
					time.sleep(0.01)
				laufzeit = time.time()


for x in xrange(thr):
	clientThread().start()
Wenn ich beide "response_string"-Zeilen auskommentiere, ist es ein deutlicher Performancegewinn, aber dann sendet der Server eben keine richtigen Antworten.

Mit "parallelen Sockets" meinte ich, dass ich zuerst versucht hatte, mehrere Sockets gleichzeitig zu öffnen, anstatt mehrere Threads mit jeweils einem Socket zu verwenden. Habe es aber nicht geschafft und deswegen erstmal Threads verwendet. Mehrere hundert parallele Sockets sollten eigentlich weniger Ressourcen beim Client benötigen als mehrere Threads.
BlackJack

Onkel Schnitzel hat geschrieben:Gibt es dann event. eine Möglichkeit folgenden Code ein bisschen effizienter zu schreiben, die Behandlung der Antwort über ein Empfangsfenster macht offenbar schon einen großen Unterschied aus, was Ressourcen betrifft. Der Client sollte die Antworten des Servers einfach so effizient wie möglich droppen, das was in der innersten Schleife mit response_string steht:
Da kannst Du eine ``for``-Schleife draus machen, damit wirst Du den Code zum ändern von `i` los. Und das Ergebnis brauchst Du an keine Namen binden, wenn Du es sowieso nicht brauchst:

Code: Alles auswählen

                for dummy in xrange(req):
                    s.send(get)
                    s.recvfrom(4096)
Mit "parallelen Sockets" meinte ich, dass ich zuerst versucht hatte, mehrere Sockets gleichzeitig zu öffnen, anstatt mehrere Threads mit jeweils einem Socket zu verwenden. Habe es aber nicht geschafft und deswegen erstmal Threads verwendet. Mehrere hundert parallele Sockets sollten eigentlich weniger Ressourcen beim Client benötigen als mehrere Threads.
Dann musst Du mit nichtblockierenden Sockets und `select.select()` arbeiten.
Antworten