Skip to content

Das Ende ist nah! Die Synflut kommt!

Kabelfreak Mehrere Wochen lang war ein von mir gepflegter Webserver Ziel einer verteilten SYN-Flood. Sie führte mehrfach zu (teilweise massiven) Problemen bei der Auslieferung der Daten. Das fand ich… überraschend. Eigentlich hätte ich davon nämlich nichts merken dürfen.

Jede TCP-Verbindung beginnt mit einem Handshake: Rechner A schickt ein SYN-Paket ("Haage! Jemand za hage?") an Rechner B. Wenn sich auf Rechner B ein Programm bereit erklärt hat, auf dem gewünschten Port Verbindungen anzunehmen, antwortet Rechner B mit SYNACK ("Haage! Jajaja! Jemand za hage?"). Rechner A bestätigt das wiederum mit einem ACK-Paket ("Jajaja!") — und schon steht die Verbindung und die Nutzdaten (meist Spam oder Schweinegifs) können fließen.

Bei einer SYN-Flood (die Schreibung hab ich aus der Wikipedia, ich hatte mich eigentlich an "Synflood" gewöhnt) schickt der Angreifer eine Menge SYN-Pakete, ohne sich um die Antworten zu scheren. Der angegriffene Server reagiert auf jedes SYN mit einem SYNACK und steckt die "halb offene" Verbindung in eine Warteschlange, wo sie eine Weile auf das abschließende ACK wartet. Kommt das nicht, wird sie schließlich entsorgt. Das Ziel des Angreifers ist, diese Warteschlange zum Überlaufen zu bringen, damit der Server keine neuen Verbindungen mehr annehmen kann. In der Fachsprache bezeichen wir das als "clogging teh tubez".

Gegen eine SYN-Flood gibt es in der Theorie eine einfache Abhilfe: SYN-Cookies. Die werden automatisch eingesetzt, sobald die Warteschlange für halb offene Verbindungen voll ist: statt sich in der Warteschlange zu merken, dass er sich mit einer Gegenstelle mitten im Handshake befindet, markiert der Server das SYNACK-Paket so, dass er an der Antwort, am ACK-Paket, erkennen kann, dass es sich um einen gültigen Handshake handelt.

In der Praxis funktionierte das bei mir auch immer. Bis zu diesem Angriff auf diesen Server. War die Warteschlange voll, kamen nur noch vereinzelte Verbindungen beim Webserver an, es wurden kaum noch Daten ausgeliefert und die Serverlast ging gegen null. — "Er hat Jehova gesagt! Er hat Jehova gesagt! Jeder weiß doch, dass SYN-Cookies funktionieren müssen!" — Nein, ich hatte nicht bloß vergessen, sie anzuschalten:

TcpExt:
190431 SYN cookies sent
159509 SYN cookies received
233521 invalid SYN cookies received


Die nächste Seltsamkeit war mein Unvermögen, die Warteschlange zu verlängern. Egal an welchen Rädchen ich drehte und wie heftig der Angriff gerade lief, "netstat" behauptete stur, dass ich während der Spitzen des Angriffs nicht mehr als 512 Verbindungen im Zustand "SYN_RECV" hatte. Ich bin schließlich bei folgenden Einstellungen angelangt, die zumindest nicht zu einer Verschlechterung der Situation führten (Linux-Kernel 2.6.x, 2 GB RAM):

echo 5000 >/proc/sys/net/core/netdev_max_backlog
echo 4096 >/proc/sys/net/ipv4/tcp_max_syn_backlog
echo 2048 >/proc/sys/net/core/somaxconn
echo "389952 519936 779904" > /proc/sys/net/ipv4/tcp_mem
echo 131072 > /proc/sys/net/netfilter/nf_conntrack_max


Im Angesicht meines Unvermögens, die Warteschlange zu verlängern, musste ich dafür sorgen, dass 1) weniger halbfertige Verbindungen in die Warteschlange eingestellt wurden, dass 2) die Verbindungen, die zum Angriff gehörten, schneller weggeräumt wurden und/oder dass 3) legitime, vollständig aufgebaute Verbindungen schneller vom Webserver angenommen wurden.

Den ersten Punkt löste ich durch das Filtern der aktiveren Teilnehmer des verteilten Angriffs: wer mir mehr als hundert SYNs in zehn Sekunden schickt, kann es nicht gut mit mir meinen und wird erst mal für eine Weile ignoriert. Vermutlich wäre es elegant gewesen, das mit "iptables --limit" zu lösen, aber es entstand bei mir quasi aus der Diagnose heraus und passierte daher im gleichen Shellskript, das mich permanent über den Verlauf des Angriffs informierte und dazu eh schon die Verbindungen durchzählte. Natürlich macht das den Server angreifbar für Spoofing: wenn ein Angreifer die SYN-Pakete nicht mit seiner eigenen IP als Absender losschickt, sondern mit der IP eines Nachbarn (und der Provider das nicht erkennt und filtert), sperrt dieser Mechanismus den Falschen. Pech für den Nachbarn, aber das Wohl der Vielen wiegt mehr als das Wohl der Wenigen oder des Einzelnen.

Das beschleunigte Weggräumen von halbfertigen Verbindungen, die nicht schnell genug fertig aufgebaut werden, und die dadurch in den Verdacht geraten, Teil der Attacke zu sein, besorgt der Kernel nach dem Herabsetzen von tcp_synack_retries auf 1 oder, wenn das nicht reicht, auf 0. Der Nachteil hieran ist, dass wohl auch die ein oder andere legitime Verbindung von einer trägen Gegenstelle über die Klinge springen muss. Aber das Wohl der Vielen…

Den dritten Schritt, der nach den ersten beiden Schritten vermutlich überflüssig gewesen wäre, hab ich leider als erstes getan — davon ausgehend, dass SYN-Cookies funktionieren müssen, suchte ich den Flaschenhals zuerst beim Webserver.

Der angegriffene Server bekam auch schon im Normalfall sehr viele Verbindungen ab, weil er den gesamten statischen Content (hauptsächlich Bilder) für eine Reihe von anderen Sites ausliefert. Der bisher dahin dafür eingesetzte thttpd schien überfordert, lief (auf einer Maschine mit zwei Doppelkern-CPUs) single-threaded und bot kein KeepAlive.

Vielleicht hätte sich als Alternative lighttpd angeboten, aber mir schien der Zeitpunkt nicht wirklich geeignet für erste Experimente mit einem neuen Webserver, also griff ich auf Apache2 mit dem Worker-MPM zurück. Das Vergnügen hatte ich bisher nicht so oft, dank PHP bin ich praktisch überall auf das Prefork-MPM festgenagelt, das einen Pool von Prozessen verwaltet, die die Requests entgegennehmen, bearbeiten und dann für den nächsten Request frei sind. Das Worker-MPM arbeitet im Vergleich dazu mit einem zweistufigen System: es startet einen relativ kleinen Pool von Prozessen, die unentwegt Requests annehmen und dann jeweils in Threads abarbeiten. Beim Ausliefern statischer Dateien sollte das im Vergleich zum Prefork-MPM sowohl die Verzögerung beim Annehmen einer Verbindung als auch den Speicherverbrauch verringern.

Nach einigem Rumprobieren bin ich bei folgenden Einstellungen für das Worker-MPM angelangt, die ich vorher auch für übertrieben gehalten hätte:

StartServers 16
MaxClients 6400
ServerLimit 256
MinSpareThreads 25
MaxSpareThreads 6400
ThreadsPerChild 25
MaxRequestsPerChild 0


MaxSpareThreads auf MaxClients zu setzen führt übrigens dazu, dass ein einmal gestarteter Thread nie mehr weggeräumt wird. Wenn die Stärke des Angriffs zunahm, kamen die gültigen (!) Requests ab und an in heftigen Wellen, die es dann blitzschnell entgegenzunehmen galt, da wurden dann auch mal ein paar Tausend Threads losgetreten (während im "Normalbetrieb" ein paar Hundert ausreichen) — die nächste Welle wurde aber entsprechend leicht verdaut, weil die Threads bereits existierten und nur noch angeschubst werden mussten.

Der Angriff hält immer noch an, hat aber keine praktischen Auswirkungen mehr, im Gegenteil: durch die Umstellung auf den Apache (und das Einschalten von KeepAlive — natürlich nur auf ein paar Sekunden, ich will ja nur alle Bildchen, Javascripte und Stylesheets eines Seitenzugriffs in einer Verbindung abfackeln, für den nächsten Klick kann gerne 'ne neue kommen) liefern wir jetzt noch zackiger aus als vor dem Angriff. Interessant wird's erst wieder, wenn der Angreifer noch 'nen Zahl zulegt, sprich: wenn er die SYNs von mehr Absendern, also aus einem größeren Botnet, schickt, oder die Bandbreite des Angriffs massiv erhöht.

Propaganda der iPod Liberation Front

KabelfreakMedienjunkieSpielkind Neuigkeiten aus roothausen:

Leider hat nun mein komplettes bisheriges Audio-Setup fuer unterwegs den Geist aufgegeben. [...] also habe ich mir nun nach Weihnachten einen neuen Player gegoennt [...]

Der neue sollte mindestens das koennen was der alte auch konnte:

• Abspielen von mp3 und ogg-vorbis
• Reibungslose Zusammenarbeit mit GNU/Linux
• Datentransfer ohne zusaetzliche Software (also per USB-Storage)

Zudem sollte der neue eine lange Akkulaufzeit und eine Bookmarkfunktion fuer Podcasts vorweisen. Das waren unter anderem Dinge, die mir bisher gefehlt haben.

Nur mal als Anmerkung fuer die iPod-Fraktion: Ein iPod wuerde keine meiner Mindestvorraussetzungen erfuellen und waere somit unbrauchbar.


Ich stand kürzlich vor einem ähnlichen Problem: mein Rio Karma stellte den Dienst ein. Ich hab mich aber nach etwas Recherche widerwillig für einen iPod entschieden, weil die Hardware etabliert ist (sprich: für alle möglichen Probleme gibt es Lösungen) und weil es eine reichhaltige Auswahl an maßgeschneidertem Zubehör gibt.

Dank Rockbox, einem freien (GPL) Betriebssystem für MP3-Player, spielt mein iPod auch Ogg-Dateien (und ein Dutzend anderer Audioformate) und verhält sich, unabhängig von dem Betriebssystem, an das er rangestöpselt wird, wie ein stinknormaler USB-Massenspeicher. Spiele (z.B. DooM) und Videos laufen darauf natürlich auch, aber nicht ohne dass die Akkulaufzeit auf einen Bruchteil schrumpft…

DRM ist für meinen Rockbox-iPod übrigens ein Fremdwort und zu Windows und zur iTunes-Software hatte das Gerät genau einmal Kontakt, nämlich zum initialen Formatieren der Festplatte.

Weitere Rockbox-Features: Bookmarks, Gapless Playback, 5-Band-Equalizer, Audio-Ausgabe der Menüs (für Sehbehinderte), Themes, Sleep Timer, Regelung der Abspielgeschwindigkeit (für besonders langsam vorgetragene Hörbücher)… und natürlich ist jedes Detail konfigurierbar (sprich: es gibt keine Marketingabteilung, die eine idiotensichere One-Size-Fits-All-Minimalkonfiguration durchsetzt, die dann im Endeffekt für keinen der Nutzer so richtig passt).

Freie Software ist halt schon was feines.

Also, liebe iPod-Fraktion, werft Eure Player nicht einfach weg, sondern befreit sie lieber von ihrem proprietären Sklavendasein.

(Dies war ursprünglich ein Kommentar auf roothausen, der aber wohl wegen seiner Länge in der Moderationsschleife gelandet ist. Für solche Späße bin ich viel zu ungeduldig.)

Samsung M50-1860 und ALSA

Kabelfreak Unter ALSA, der fortschrittlichen Linuxklangarchitektur, hatte ich auf meinem Samsung-Notebook noch nie Ton auf dem Kopfhörer, ohne in patch_analog.c rumzufummeln. Ich hab seit letztem Jahr einen Bug dazu im ALSA-Bugtracker offen, der aber keine große Aufmerksamkeit erhalten hat. Der Trick, der für mich funktioniert: ich ersetze in der Zeile für das FSC V2060 (zu erkennen an der PCI-ID 0x144d 0xc01e, das ist zufällig genau die PCI-ID, die der Audiochip des Samsung-Notebooks verwendet) "AD1986A_LAPTOP" durch "AD1986A_LAPTOP_EAPD".

Ich hab den Verdacht, dass ich das noch für viele Kernel- und ALSA-Revisionen tun werde, bis irgendwann mal zufällig ein ALSA-Entwickler ein M50 erbt.

Nachtrag, 14. August 2007: Mit 2.6.18 ging das noch, mit 2.6.22 nicht mehr. Ich muss mir wohl was neues einfallen lassen.