![]() |
Indy10 TCPServer Spam erkennen, hohe CPU Auslastung
Hallo liebe Community,
ich habe seit längeren einen TCPServer basierend auf den Indy10 Komponenten in Betrieb. Das funktioniert grundsätzlich, Daten von den Clients kommen und werden abgearbeitet. In letzter Zeit bekomme ich gehäuft TCP-Connects und Content von offensichtlichen SPAM IP-Adressen. Grundsätzlich kann ich auch am Inhalt erkennen das es sich um SPAM handelt. In TIdTCPServer.OnConnect wird bei mir erstmals auf die PeerIp geschaut ob diese IP-Adresse auf einer BlackList ist und entsprechend sofort ein disconnect ausgelöst:
Delphi-Quellcode:
procedure TGPRSCommModuleFM.tcpConnect(AContext: TIdContext);
begin try if TRegEx.IsMatch(AContext.Connection.Socket.Binding.PeerIP, 'XX.XX.XX.') OR TRegEx.IsMatch(AContext.Connection.Socket.Binding.PeerIP, 'XX.XX.XX.') then begin AContext.Connection.Disconnect; end; except on E: Exception do end; end; Nun folgendes Problem: Mit jedem connect von einer solchen IP Adresse springt die CPU Auslastung des Programms extrem in die Höhe und verweilt dort. Das geht solange bis das Programm eine Auslastung von 100% CPU verursacht. Es muss irgendein Thread in den Indy Komponente sein der nicht richtig beendet wird. Gibt es eine Möglichkeit vor dem TCPconnect die IP abzugreifen und zu blockieren? Wie kann so ein Verhalten zu erklären sein? Schicken die im TCPHeader irgendwelchen Code mit der Fehler im Indy verursacht? Ist sowas möglich? beispielhafte SPAM IP: 147.45.112.147 Content:0300002A25E00000000000436F6F6B69653A206D73 7473686173683D546573740D0A0100080003000000 Vielen Dank |
AW: Indy10 TCPServer Spam erkennen, hohe CPU Auslastung
Erstmal solltest du dich mit regulären Ausdrücken dringend mal beschäftigen,
denn
Delphi-Quellcode:
'123456789' ~ '12.45.78.'
Weil . ist das, was im Dateisystem ein ? ist. Da doch sowieso immer nur am Anfang geschaut werden soll, noch ein ^ mit rein, einmal, damit nicht sinnlos nachfolgendes geprüft wird und weil
Delphi-Quellcode:
sonst auch trifft, obwohl 123 <> 3.
'123.45xxxx' ~ '3.45'
Delphi-Quellcode:
if TRegEx.IsMatch(AContext.Connection.Socket.Binding.PeerIP, '^(XX\.XX\.XX\.|XX\.XX\.XX\.)') then
Delphi-Quellcode:
Oder wie wäre es mit einem einfachen String-Vergleich, wenn es eh nur um einen String-Anfang geht?
// irgendwo vorher einmal initialisieren
RegEx := TRegEx.Create('^(XX\.XX\.XX\.|XX.XX\.XX\.)'); // und im Event nur noch if RegEx.IsMatch(AContext.Connection.Socket.Binding.PeerIP) then
Delphi-Quellcode:
if
StartsStr('XX.XX.XX.', AContext.Connection.Socket.Binding.PeerIP) OR StartsStr('XX.XX.XX.', AContext.Connection.Socket.Binding.PeerIP) |
AW: Indy10 TCPServer Spam erkennen, hohe CPU Auslastung
Ich nutze hier die public
function Match(const Input: string): TMatch; overload; Der Matchingteil funktioniert und ist an dieser Stelle auch nur zum schnellen Debugging und Test eingebaut. Auch wenn deine Variante die Elegantere ist versuche ich zuerst die Ursache für die CPU Auslastung zu finden. Anschließend fliegt das wieder raus und wird anders gestaltet. Die eingehenden SPAM Ips sind immer identisch daher hier testweise nur auf den String gefiltert . XX sind tatsächlich Zahlen. Ich fange hier im laufenden Programm tatsächlich die ungewünschten IPs ein und schreibe es ins Log. |
AW: Indy10 TCPServer Spam erkennen, hohe CPU Auslastung
X = Ziffer .... hatte ich mir fast schon selbst gedacht. :angle2:
Das Problem sind aber die Punkte, im RegEx. . \. oder [.] Zitat:
Die funktionieren jetzt vermutlich aber immernoch, also als Standalone ... nicht die IDE-Integration, aber egal. ![]() Direkt in der Firewall schon sperren? Den Port verschieben? |
AW: Indy10 TCPServer Spam erkennen, hohe CPU Auslastung
Der Sender scannt Ports und probiert es auf denen die frei sind. Ich habe das Phänomen schon auf mehreren Servern und verschiedenen Ports beobachtet.
Die IP Adressen sind zwar immer gleich allerdings kommt auch mal eine neue dazu. Ideal wäre wenn das Programm die Blacklist für sich selber generiert, was möglich ist. Allerdings verstehe ich nicht wie es zu der hohen CPU Auslastung kommt. Irgendwas innerhalb der Indy-Komponenten führt zu dem Verhalten. Am besten wäre die allererste Stelle zu finden an der ein Connect stattfindet und dort gleich IP Adressen zu blockieren. OnConnect scheint das nicht zu sein. Irgendwas schicken die bei dem TCP-Connect mit was zu dem Verhalten führt. |
AW: Indy10 TCPServer Spam erkennen, hohe CPU Auslastung
Was passiert wenn du anstatt AContext.Connection.Disconnect ein Abort machst?
|
AW: Indy10 TCPServer Spam erkennen, hohe CPU Auslastung
Ich sehe hier keine Möglichkeit einen Abort aufzurufen. Wie sieht der Aufruf für einen Abort aus?
|
AW: Indy10 TCPServer Spam erkennen, hohe CPU Auslastung
Ich weiß nicht, ob Indy wirklich vernünftig für so etwas ausgelegt ist.
Ich würde eher ein Tool wie nginx davorschalten, der sich um so etwas wie Rate Limitung, Blacklistung usw. kümmert. |
AW: Indy10 TCPServer Spam erkennen, hohe CPU Auslastung
Du kannst statt einem Disconnect ja mal ein
![]() |
AW: Indy10 TCPServer Spam erkennen, hohe CPU Auslastung
Zitat:
Delphi-Quellcode:
Ich würde allerdings eher mal den Stacktrace an der Stelle als Ausgangspunkt nehmen und schauen, was da vorher passiert. Sprich ein wenig debuggen und schauen, ob es einen besseren Eingriffspunkt gibt.
Abort;
// Das löst eine stille Exception aus. |
AW: Indy10 TCPServer Spam erkennen, hohe CPU Auslastung
Ich möchte meine Frage nach erweiterten Recherchen etwas anders darstellen.
Folgende Situation: TCPServer wird auf einem Port aktiviert und lauscht auf diesem auf eingehende TCPConnects und wertet die eingehenden Daten in Execute aus. Im einem Testprogramm klappt das mit bekannten Clients ohne Probleme. Jetzt bekomme ich Connects von offensichtlichen SPAM IP Addressen (Recherche Google). Nun wird wiefolgt darauf reagiert -> es wird ein Disconnect ausgelöst.
Delphi-Quellcode:
Dieser Disconnect führt aber NICHT dazu das der Socket geschlossen wird!
procedure TForm1.tcpSrvConnect(AContext: TIdContext);
begin try if TRegEx.IsMatch(AContext.Connection.Socket.Binding.PeerIP, '147.45.112.') OR TRegEx.IsMatch(AContext.Connection.Socket.Binding.PeerIP, '194.165.16.') then begin AContext.Connection.Disconnect; end; except on E: Exception do end; end; So wie ich das verstehe muss der zu sendende Client diesen Disconnect "bestätigen" damit tatsächlich auch ein "onDisconnect" Event ausgelöst und der Socket geschlossen wird? Ist das so? Jetzt die alles entscheidende Frage: Wie kann ich Serverseitig erzwingen, dass eine Verbindung geschlossen wird? Es ist mir egal was der CLient davon hält. Die Verbindung soll geschlossen werden. Am besten sollte es so erscheinen als ob der Port gar nicht erreichbar ist. Besagte Connects von den SpamIps führen dazu, dass die CPU-Auslastung mit jeder offenen Verbindung ins maximale ansteigt. Irgendwas passiert bei den Connects. Wenn ich den Server stoppe, dann werden auch die Spam-Verbindungen disconnected. Das ist im Log nachvollziehbar. Ein Server Neustart kann aber nicht die Lösung für solch ein Problem sein. Vielen Dank und viele Grüße |
AW: Indy10 TCPServer Spam erkennen, hohe CPU Auslastung
Hast du dir denn einmal den Stacktrace und davon ausgehend den Quelltext angeschaut?
|
AW: Indy10 TCPServer Spam erkennen, hohe CPU Auslastung
Hi,
Im Indy TCPServer gibt's ja die Parameter 'keep alive' und 'resuse Sokets'. Hast Du damit schon mal 'gespielt'? |
AW: Indy10 TCPServer Spam erkennen, hohe CPU Auslastung
Zitat:
|
AW: Indy10 TCPServer Spam erkennen, hohe CPU Auslastung
My knowledge and experience in Indy is quite shallow, i used different libraries and implement my own,
But i can say few things here: 1) The high CPU usage is .. well... wrong Execute loop, your loop is not existing, you should make sure after triggering "AContext.Connection.Disconnect;" that execute loop is not looping. 2) Just an assumption here, why are you using OnConnect instead of OnContextCreated ? this might solve your whole problem, as code calling Execute should check for formally valid and correct Context before executing Execute and this include connected status, this pure assumption form my part though. 3) About you idea of making the port look closed, in other words to refuse connection before connect and before creating Context: To look closed and hide the open port, the server should refuse to ACK connect, the closest thing you can do with Windows OS without using Firewall is to use WSAAccept : ![]() I have this working and it is just perfect, the callback will be called before accepting any socket, giving you the ability to refuse connection and implement a neat filtering system, with Indy it might be tricky due the multi layer and my lack of knowledge, or it could be very easy by replacing ... well here what i can't say for sure, it might be only TIdServerIOHandler inherited one or by adding your own TIdServerIOHandlerSocket with .. or simply by adding your own TIdServerIOHandlerStack. not so helpful i know :duck: Hope that helps. |
AW: Indy10 TCPServer Spam erkennen, hohe CPU Auslastung
Are you sure you Execute loop does check for AContext.Connection.Connected ?
|
AW: Indy10 TCPServer Spam erkennen, hohe CPU Auslastung
Zitat:
Das Akzeptieren kannst du ohne Modifikation des Indy-Quelltextes nicht verhindern (je nach Projekt lohnt es sich aber, das dort zu implementieren), aber es gibt dort schon einen entsprechenden Kommentar (IdCustomTCPServer.pas --> TIdListenerThread.Run):
Delphi-Quellcode:
Aber:
// TODO: under Windows at least, use SO_CONDITIONAL_ACCEPT to allow
// the user to reject connections before they are accepted. Somehow // expose an event here for the user to decide with... Dort wird auch die maximale Anzahl an Verbindungen geprüft. Wenn diese erreicht ist, wird dort mit Abort reagiert. Insofern ist das dort die korrekte Wahl, wenn du das im OnContextCreated auslöst. Das OnConnect wird dann gar nicht erst ausgeführt, insbesondere wird Server.Scheduler.StartYarn gar nicht erst erreicht. |
AW: Indy10 TCPServer Spam erkennen, hohe CPU Auslastung
Kurzes Update:
Shebang hatte vorgeschlagen einen DisconnectSocket zu machen. Ich habe in diese Richtung recherchiert und AContext.Connection.Socket.Binding.CloseSocket; gefunden und anstelle von Disconnect verwendet. Nun werden die Verbindungen tatsächlich komplett geschlossen sobald eine Connect von besagten IPs kommt. Die hohe CPU-Auslastung ist auch nicht mehr aufgetreten. Testen ist gar nicht so einfach. Ich muss nach jeder Änderung warten bis erneut connects von besagten IP-Adressen kommen. Als nächstes gehe ich die anderen Ideen von euch auch noch durch. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:23 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz