Linux als Proxy-Server - Optimierung

13.08.2004 von STEFAN RUBNER 
Der Proxy-Server Squid ist ein wertvolles Tool, um Zugriffe auf Web-Inhalte zu beschleunigen und den Traffic im Zaum zu halten. Mit ein paar Tricks und Kniffen lässt sich seine Leistung steigern und die Verwaltung vereinfachen.

Während der Einsatz einer Firewall zum Schutz des lokalen Netzes vor Angriffen aus dem Internet mittlerweile Standard ist, winken viele Administratoren beim Gedanken an einen Proxy-Server dankend ab. Vielen sind diese, ähnlich einer Firewall zwischen Firmennetz und Internet arbeitenden Zwischenspeicher noch in schlechter Erinnerung. Aufwändig zu konfigurieren, schwer zu verwalten und unzuverlässig seien Proxy-Server, so die häufige Aussage. Zugegeben: ganz einfach ist die richtige Konfiguration eines Proxy nicht, machbar aber alle Mal. Und als Lohn der Mühe winken Funktionen, die über das reine Vorhalten bereits abgerufener Web-Inhalte weit hinausgehen.

Im Linux-Umfeld ist Squid sicherlich der am weitesten verbreitete Proxy-Server. Diese Tatsache verdankt er vor allem seiner Flexibilität, mit Sicherheit aber nicht der einfachen Bedienung. Besonders das Erstellen der Access Control Lists (ACL) aber auch das Anpassen der restlichen Konfiguration überfordern oft Einsteiger wie Fortgeschrittene gleichermaßen. Schuld daran sind neben der Fülle an Optionen auch die komplexen Bedingungen, nach denen Squid die erstellten Regeln abarbeitet. Allerdings können Sie schon mit kleinen Änderungen an der Standardkonfiguration messbare Ergebnisse erzielen. Als Grundlage für die nachfolgend beschriebenen Maßnahmen dient ein wie im Artikel Linux als Proxy-Server beschrieben konfiguriertes Squid-System.

URL-Filterung

Abgesehen von der zeitlichen Beschränkung lässt sich auch eine Einschränkung der besuchten Seiten durch das Filtern der aufgerufenen URL erzielen. Um beispielsweise den Abruf anstößiger oder potenziell illegaler Inhalte zu verhindern, könnten Sie Filter der folgenden Art einsetzen:

acl no_show url_regex adult
acl no_show url_regex porn
acl no_show url_regex warez
acl no_show url_regex cracks
http_access deny no_show

Sieht das noch relativ einfach aus, verkompliziert sich die Sache erheblich, wenn bestimmte Anwender aus welchen Gründen auch immer Zugriff auf eine Web-Seite benötigen, die einen der gefilterten Begriffe enthält:

acl no_show url_regex adult
acl no_show url_regex porn
acl no_show url_regex warez
acl no_show url_regex cracks
acl do_show url_regel tupperwarez.com
acl do_show_users proxy_auth douser1 douser2 douser3
http_access allow do_show do_show_users <weitere Parameter ...>
http_access deny do_show
http_access deny no_show

Fehler erkennen mit debug_option

Speziell bei umfangreichen ACLs wird die Geschichte schnell unübersichtlich und damit fehleranfällig. Treten einmal unerwünschte Effekte auf, hilft eine spezielle Einstellung der Option debug_option weiter. Anstelle der Standard-Vorgabe setzen Sie folgende Zeile in die Squid-Konfiguration und starten den Proxy-Server neu:

debug_option ALL,1 33,2

Ab sofort zeigt Ihnen Squid in der Datei /opt/squid/var/logs/cache.log an, warum ein Request angenommen oder abgelehnt wurde. So lässt sich leichter ermitteln, welche Regel Schuld am fehlerhaften Verhalten ist. Sollte Ihnen auch diese Information nicht genügen, hilft eventuell die verschärfte Variante weiter:

debug_option ALL,1 33,2 28,9

Diese bewirkt, dass Squid auch den kompletten Regelweg bis zur Entscheidung ausgibt. Wegen der dabei anfallenden Datenmenge empfiehlt es sich jedoch, derartige Tests in ruhigen Zeiten durchzuführen.

Cache-Strategien anpassen

Der erste Schritt, den Sie zur Optimierung von Squid in Erwägung ziehen sollten, ist das Anpassen der Cache-Strategien auf Ihre Bedürfnisse. Standardmäßig setzt Squid die LRU-Methode (Last Recently Used) ein. Er hält also vorwiegend Objekte in seinem Cache, die erst kürzlich durch einen Anwender abgerufen wurden. Ältere Daten verwirft Squid dagegen recht schnell wieder. Dieses Verfahren eignet sich vor allem dann, wenn die Proxy-Nutzer häufig dieselben Web-Angebote besuchen, beispielsweise eine relativ statische Datenbank. Greifen die Benutzer jedoch auf ständig wechselnde Inhalte zu, hält Squid die im Cache abgelegten Daten schnell für veraltet und entfernt sie. Erneute Anforderungen können dann nicht mehr aus dem Cache bedient werden sondern erzwingen eine neue Übertragung der Daten vom anbietenden Server. Die Folge sind langsamere Zugriffszeiten und steigendes Transfervolumen - und genau diese Probleme sollte der Proxy ja eigentlich eliminieren.

Abhilfe schaffen hier zwei alternative Cache-Strategien: Greedy Dual Size Frequency (GDSF) und Least Frequently Used with Dynamic Aging (LFUDA). Hinter diesen beiden Akronym-Ungetümen verstecken sich Arbeitsweisen mit unterschiedlicher Zielsetzung. GSDF versucht, möglichst viele, dafür aber kleinere der häufig angeforderten Objekte im Cache zu halten. LFUDA hingegen optimiert den Cache auf eine möglichst hohe Byte-Trefferrate, hält also bevorzugt große Objekte im lokalen Zwischenspeicher.

Trennung von RAM- und Festplatten-Cache

Theoretisch steht der Administrator also nun vor einem Dilemma: Lieber GDSF und damit kurze Antwortzeiten oder eher weniger Traffic mit LFUDA? Einen Mittelweg bietet sich durch die Kombination der beiden Verfahren an. Ermöglicht wird dies durch die Tatsache, dass Squid sowohl einen Cache-Bereich im Hauptspeicher wie auch einen Cache auf der Festplatte verwaltet. Für beide lassen sich unterschiedliche Strategien angeben. Es bietet sich also an, den RAM-Cache mit GSDF, den Festplatten-Cache per LFUDA zu organisieren. Tragen Sie dazu einfach zwei Zeilen in die Konfigurationsdatei /etc/squid/squid.conf ein:

cache_replacement_policy heap LFUDA
memory_replacement_policy heap GDSF

Zwei weitere Parameter spielen eine ebenfalls nicht unwesentliche Rolle: maximum_object_size und maximum_object_size_in_memory. Letzterer bestimmt, wie groß ein Objekt maximal sein darf, um im Speicher gehalten zu werden. Voreingestellt sind hier 8 KByte. Überschreitet ein Objekt diese Größe, wird es in den Festplatten-Cache ausgelagert - dies allerdings nur, wenn es nicht größer ist als unter maximum_object_size angegeben. Der Vorgabewert ist hier mit 4096 KByte eher konservativ angesetzt. Besitzer von ausreichend freier Harddisk-Kapazität sollten daher lieber ein Limit von 100 MByte oder mehr wählen.

Vergessen Sie nach dem Anpassen der Parameter nicht, Squid neu zu starten. Wie immer bei Änderungen an der Konfiguration ist es ratsam, beim ersten Neustart die Parameter -N -debug zu verwenden. Nur so können Sie die Bildschirmausgaben von Squid sehen und eventuelle Probleme erkennen. Bemängelt Squid nach der Änderung der Cache-Strategien unbekannte Removal Policies, dann müssen Sie die Quelltexte neu übersetzen und dabei die Option --enable-removal-policies="lru heap" angeben.

Cache-Speicher vergrößern und verteilen

Selbst wenn Sie sich mit der LRU-Strategie begnügen, gilt für den Cache-Speicher von Squid die Faustregel "Speicher ist durch nichts zu ersetzen - außer durch mehr Speicher.". Es bietet sich daher an, den von Haus aus vorgesehenen Plattenplatz von 100 MByte für gespeicherte Objekte gehörig aufzustocken. Bei dieser Aktion sollten Sie auch gleich einen Wechsel des verwendeten Speichersystems ins Auge fassen. Normalerweise setzt Squid für diese Aufgabe das Unified File System (UFS) ein. Sein Vorteil ist, dass es auf allen Plattformen gleichermaßen gut - oder je nach Betrachtungsweise auch schlecht - funktioniert.

Eine bessere Alternative stellt Advanced UFS (AUFS) dar. Es verwendet so genannte Posix-Threads und sorgt so dafür, dass Squid nicht auf das Ergebnis eines Schreibvorgangs warten muss, bevor er seine Arbeit fortsetzt.

Ähnliches leistet auch das Speicherverfahren, das sich eines externen Prozesses bedient. Bei diesem, passender Weise diskd genannten Verfahren gibt Squid Schreib- und Leseanforderungen an die parallel laufenden Diskd-Prozesse weiter. Der Vorteil ist nicht nur, dass Squid weiterarbeiten kann, während Diskd sich um den Datentransport kümmert. Da die Zahl der Diskd-Prozesse einstellbar ist, bietet diese Methode auch bessere Möglichkeiten zur Optimierung. Für den generellen Betrieb stellt daher AUFS eine gute Wahl dar, wer gerne selbst an den Einstellungen schraubt, kann mit Diskd experimentieren. Welches System zum Einsatz kommt, bestimmt das Schlüsselwort cache_dir der Squid-Konfiguration. Für die Umstellung auf AUFS sieht die entsprechende Zeile zum Beispiel so aus:

cache_dir aufs /opt/squid/var/cache 1000 256 256

In diesem Beispiel haben wir zusätzlich noch weitere Parameter verändert. Die Angabe des Werts 1000 statt der Vorgabe 100 erweitert den verfügbaren Cache-Speicher auf der Platte von 100 MByte auf rund 1 GByte. Grundsätzlich sollten Sie für die Größe des Platten-Caches lieber zu viel Speicher angeben als zu wenig. Squid nutzt nur, was er wirklich braucht. Kommt er jedoch nahe an die festgelegte Obergrenze, muss er zwangsläufig mit Aufräumarbeiten beginnen. Das kostet Zeit und drückt deutlich auf die Performance.

Um eine schnelle Indizierung zu gewährleisten haben wir zudem die Anzahl der zur Speicherung verfügbaren Verzeichnisse von ursprünglich 16 auf 256 erhöht, den Wert für die weiteren Unterverzeichnisse jedoch auf 256 belassen. Diese beiden Parameter haben direkten Einfluss darauf, wie schnell Squid aus dem Cache angeforderte Daten findet. Je weniger Dateien sich in einem Verzeichnis befinden, desto kürzer sind die Laufzeiten der Betriebssystem-Prozesse zur Suche nach einem Dateinamen. Damit die Verzeichnisse auch wirklich verfügbar werden, müssen Squid über den Aufrufparameter -z anweisen die neuen Directorys anzulegen.

ACLs mit SquidGuard vereinfachen

Eine der größten Stolperschwellen beim Einsatz von Squid ist die richtige Konfiguration der Access Control Lists. Mit SquidGuard steht hier eine elegante Lösung zur Verfügung, die dem Administrator die Arbeit wesentlich erleichtert. Anstatt über eine Vielzahl von ACL-Kommandos in der Squid-Konfiguration Gruppen, Domains, URLs und Ports zu definieren, nutzt SquidGuard eine C-ähnliche Schreibweise. Selbst die Integration in Squid ist einfach: als Redirector aufgerufen führt es seine Arbeit aus und teilt Squid lediglich mit, wie dieser mit den eingehenden Anfragen zu verfahren hat.

Die Installation ist ebenfalls schnell erledigt. Laden Sie das Archiv von SquidGuard.Org herunter und entpacken Sie es beispielsweise nach /root/soft:

cd /root/soft
wget ftp://ftp.teledanmark.no/pub/www/proxy/squidGuard/squidGuard-1.2.0.tar.gz
tar xvzf squidGuard-1.2.0.tar.gz

Um die Komponenten von SquidGuard in die bestehende Verzeichnisstruktur von Squid zu übernehmen, sind ein paar Parameter an das Konfigurationsskript zu übergeben. Damit Sie diese nicht ständig von Hand eingeben müssen, ist es ratsam, eine Skriptdatei mit dem Namen cfg-squidGuard und folgendem Inhalt im Verzeichnis /root/soft anzulegen:

#!/bin/bash

cd squidGuard-1.2.0
if [ -f config.cache ]; then rm -f config.cache;
fi

./configure --prefix=/opt/squid \\
--sysconfdir=/etc \\
--with-db-inc=/usr/include/db4 \\
--with-sg-config=/etc/squidguard.conf \\
--with-sg-dbhome=/opt/squid/var/lib/squidGuard/db \\
--with-sg-logdir=/opt/squid/var/logs

SquidGuard aktualisieren

Leider ist der Source von SquidGuard schon etwas älter und nutzt daher zwei mittlerweile veraltete Aufrufe für Datenbank-Routinen. Um dieses Problem zu beheben, müssen Sie die Quelldatei sgDb.c editieren. Sie finden die Datei im Verzeichnis /root/soft/squidGuard-1.2.0/src. Ersetzen Sie die beiden Zeilen 101 und 107, die den folgenden Inhalt haben

Db->dbp->open(Db->dbp, dbfile, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {

durch

Db->dbp->open(Db->dbp, NULL, dbfile, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {

und speichern Sie die Datei. Zum Übersetzen der Quelldateien und dem Installieren der Software sind dann nur noch wenige Kommandos nötig:

cd /root/soft
chmod 755 cfg-squidGuard
./cfg-squidGuard
cd squidGuard-1.2.0
make
make install

Der letzte Befehl sorgt nicht nur dafür, dass die ausführbare Datei squidGuard im Verzeichnis /opt/squid/bin abgelegt wird. Darüber hinaus kopiert das Kommando auch eine Konfigurationsvorlage nach /etc/squidguard.conf. Zwar ist diese für den direkten Einsatz ungeeignet, sie verdeutlicht aber anschaulich die Arbeitsweise von SquidGuard.

Einschränkung nach Zeit

Gehen wir also daran, ein bereits aus dem einleitenden Artikel Linux als Proxy-Server bekanntes Beispiel mithilfe von SquidGuard zu realisieren: Den Zugriff auf das Internet nur während der Geschäftszeiten zu erlauben. Um dies zu erreichen, muss squidguard.conf folgenden Inhalt haben:

logdir /opt/squid/var/logs
dbhome /opt/squid/var/db

src our_networks {
ip 192.168.1.0/24
}

time inet_time {
weekly mtwhf 08:00-18:00
}

acl {
our_networks within inet_time {
pass all
}
default {
pass none
}
}

Wie sie sehen, ist die Regelerstellung bei SquidGuard deutlich logischer aufgebaut als bei Squid selbst. Doch damit nicht genug: SquidGuard bietet auch erhebliche Vereinfachungen bei der Verwaltung von unerwünschten Domains. Dazu stützt es sich auf Datenbanken im Berkeley-Format, deren Manipulation über Textdateien erfolgt.

Blockierung nach Domains

Um den Zugriff auf unerwünschte Domains zu sperren, fügen Sie einen zusätzlichen Block in die Konfiguration ein und ändern die ACL ein wenig ab:

logdir /opt/squid/var/logs
dbhome /opt/squid/var/db

src our_networks {
ip 192.168.1.0/24
}

dest blocked {
domainlist blocked/domains
}

time inet_time {
weekly mtwhf 08:00-18:00
}

acl {
our_networks within inet_time {
pass !blocked all
}
default {
pass none
redirect http://<proxy-server>/cgi-bin/squidGuard-simple.cgi?clientaddr=%a&clientname=%n&clientident=%i&clientgroup=%s&destinationgroup=%t&url=%u }
}

Erstellen der Domain-Datenbank

Im nächsten Schritt legen Sie die Datei /opt/squid/var/db/blocked/domains an. Dabei handelt es sich um eine reine Textdatei, die pro Zeile eine zu blockierende Domain beinhaltet. Zuvor müssen Sie jedoch noch das Datenbank-Verzeichnis anlegen und mit den richtigen Benutzerrechten versehen.

mkdir -p /opt/squid/var/db/blocked
chown -R squid /opt/squid/var/db

Für den Anfang genügt als Inhalt der Textdatei mit den Domainnamen eine recht kurze Liste:

adult
porn
warez
cracks

Damit SquidGuard mit den so erfassten Daten auch etwas anfangen kann, müssen Sie diese in eine Berkeley-Datenbank überführen. Diese Aufgabe übernimmt SquidGuard, wenn Sie es mit dem Parameter -C, gefolgt vom Namen der umzuwandelnden Datei aufrufen.

/opt/squid/bin/squidGuard -C /opt/squid/var/db/blocked/domains

Einbinden von SquidGuard in Squid

Zum Abschluss sorgen Sie nur noch dafür, dass SquidGuard von Squid auch tatsächlich aufgerufen wird. Suchen Sie dazu in der Konfigurationsdatei /etc/squid/squid.conf nach dem Schlüsselwort redirect_program und fügen in dessen Umfeld folgende Zeile ein:

redirect_program /opt/squid/bin/squidGuard

Die Blockade funktioniert übrigens nicht nur für Web-Seiten sondern bezieht sich auf alle URLs - und damit auch zum Beispiel FTP-Zugriffe - die diese Domain enthalten.

Damit die Clients im Fall eines von SquidGuard abgeblockten Zugriffs auch informiert werden, fehlt nun nur noch eine Kleinigkeit. Wie in der Beispielkonfiguration zu sehen, leitet SquidGuard abgelehnte URLs auf ein CGI-Skript um. Dieses müssen Sie manuell auf dem Quellverzeichnis von SquidGuard in das CGI-Directory des Web-Servers kopieren und mit dem Attribut "Ausführbar" versehen:

cd /root/soft/squidGuard-1.2.0/
cp sample/squidGuard-simple.cgi /srv/www/cgi-bin
chmod 755 /srv/www/cgi-bin/squidGuard-simple.cgi

Voraussetzung dafür, dass die Anwender dann auch die vom CGI-Script angezeigte Fehlermeldung sehen können, ist dann allerdings, dass auf dem als Proxy-Server arbeitenden Rechner auch ein Web-Server installiert ist.

Wer sich nicht die Mühe machen will, alle Seiten mit unerwünschten Inhalten selbst in die SquidGuard-Datenbank einzutragen, kann sich übrigens der auf den SquidGuard-Seiten bereitgestellten Blacklist bedienen. Sie enthält - geordnet nach den Kategorien Werbung, Gewalt, Musik, Video, Drogen, Gewinnspiele, Pornografie und Raubkopien - vom SquidGuard-Robot wöchentlich neu erstellte Listen entsprechender Seiten, fertig vorbereitet zur Integration in SquidGuard.

Squid als Anonymisierer

Eine weitere, oft übersehene Funktion von Squid ist die Möglichkeit, die ausgehenden Anfragen zu anonymisieren. Da Squid sowieso die Header-Daten von HTTP-Requests umschreiben muss, können hier auch beliebige Informationen an die Zielsysteme im Internet versendet werden. Auf diese Weise können Sie die von den Anwendern verwendete Browser-Software nebst Version ebenso verstecken wie die reale interne IP-Adresse des benutzten Rechners. Da diese Änderungen am HTTP-Request nicht dem Standard entsprechen sind sie in der Grundkonfiguration deaktiviert. Um einen komplett anonymisierten Zugang ins Internet zu realisieren, tragen Sie folgende Zeilen in die Datei /etc/squid/squid.conf ein:

header_access Allow allow all
header_access Authorization allow all
header_access WWW-Authenticate allow all
header_access Cache-Control allow all
header_access Content-Encoding allow all
header_access Content-Length allow all
header_access Content-Type allow all
header_access Date allow all
header_access Expires allow all
header_access Host allow all
header_access If-Modified-Since allow all
header_access Last-Modified allow all
header_access Location allow all
header_access Pragma allow all
header_access Accept allow all
header_access Accept-Charset allow all
header_access Accept-Encoding allow all
header_access Accept-Language allow all
header_access Content-Language allow all
header_access Mime-Version allow all
header_access Retry-After allow all
header_access Title allow all
header_access Connection allow all
header_access Proxy-Connection allow all
header_access All deny all

Mit diesen Einstellungen versehen sendet Squid nur noch die absolut notwendigen Header-Informationen ins Internet. Allerdings sollten Sie wissen, dass damit möglicherweise Seiten nicht mehr richtig funktionieren, die zum Beispiel den verwendeten Browser abfragen um bekannte Fehler einiger Programme zu umgehen. Dem gegenüber steht natürlich die Tatsache, dass auch gezielte Angriffe auf bekannte Schwachstellen einiger Browser möglicherweise ins Leere laufen, die Sicherheit Ihres Netzes durch diese Maßnahme also steigt.

Ausblick

Mit den hier vorgestellten Verfahren und Einstellungen sind Sie ausreichend gewappnet, einen funktionierenden Proxy-Server für Ihr Netz aufzusetzen. Allerdings bietet Squid wesentlich mehr Funktionen als sich in einem einzigen Beitrag beschreiben lassen. Speziell ACLs und Authentifizerung sind Gebiete, die deutlich mehr Optionen bieten als hier angerissen. Weiterführende Dokumentation zu diesen Bereichen finden Sie auf der Homepage von Squid. Besonders die dort enthaltene FAQ liefert nicht nur Antworten auf häufig gestellte Fragen sondern beinhaltet auch interessante Beispiele für Dinge, die man mit Squid noch anstellen kann. (mha)