09.01.2014

Erbsen zählen mit Linux - IP Traffic accounting

Manche unter uns wurden geplagt von langsamem DSL.

Ein paar von denen sind mutig auf LTE umgestiegen, das die Telekom und andere Anbieter in unterversorgten Gebieten anbieten müssen (zwar nur im 800 MHz-Band, aber immerhin).

Und ein paar von denen sind neugierig, welcher Mitbewohner denn nun den Traffic verursacht und schon am 20. die Quote für den ganzen Monat aufgebraucht hat ;)

Das alles und noch viel mehr kann man mit einem Linux-Server machen, wenn man seine PCs und Smartphones im Haushalt nicht direkt ins Internet lässt, sondern den Linux-Rechner als Gateway dazwischenklemmt.

Dieser Ansatz hat nebenher noch den Vorteil, dass auf dem Linux-Server ein Caching Proxy laufen kann und damit potentiell ein bißchen vom Traffic nur einmal über die externe Internetverbindung abgerufen werden muss.

Hauptsächlich ist aber das interessanteste, dass nun wirklich jede Internetverbindung am Linux sichtbar ist.

Mit dem Modul "iptables", das bei jeder Linux-Distribution dabei sein sollte, kann man eine Statistik führen, welcher Rechner oder welches Smartphone wieviel Traffic verursacht hat.

Normalerweise wird "iptables" dazu verwendet, mit Regeln festzulegen, was erlaubt ist und was nicht. Nebenbei wird aber auch mitgezählt, wieviele Bytes durch die Regeln geflossen sind. Man kann diesen Mechanismus also für den Nebeneffekt des Zählens verwenden, wenn man schlicht "keine Regel" festlegt.

Nebenbei könnte man aber natürlich auch am Proxy datenintensive Sites wie spotify usw. sperren, die besonders viel vom Datenvolumen verbrauchen.

Grundsätzlich muss man dazu einen Linux-Server mit zwei Ethernet-Schnittstellen aufbauen. Manche Mainboards haben schon zwei davon; falls nicht, kann man für sehr wenig Geld eine zweite Karte in den PC einbauen. Es bietet sich an, den Linux-Server dann auch gleich zum NAS auszubauen mit einer zweiten Festplatte (für ein gespiegeltes RAID1) oder mit mehreren (wenn man ein RAID5 haben will).

Das wichtigste kommt nun: der Router (DSL oder LTE) kommt an die zweite Schnittstelle (oBdA ab jetzt eth1 genannt), und niemand sonst darf direkt mit dem Router verbunden sein. Es ist also sinnvoll, das WLAN am Router abzuschalten oder das Passwort so zu ändern, dass sich niemand mehr anmelden kann. Außerdem muss am Linux-Server das IP-Forwarding eingeschaltet sein, damit die anderen Systeme im Haushalt die Chance haben, trotzdem ins Internet zu kommen. Wenn man das WLAN am Router abschaltet, handelt man sich noch ein zu lösendes Problem ein: man benötigt einen separaten WLAN-Access Point für das interne Netz, der für Smartphones die Basisstation wird.

Alle anderen PCs und der Linux-Server mit seiner ersten Schnittstelle (eth0) müssen an einen "internen" Switch angeschlossen werden. Das kann der interne, neue WLAN-Access Point sein, oder eine eigene kleine Kiste, ganz nach Geschmack und örtlichen Gegebenheiten.

Am Linux muss nun prinzipiell das IP-Forwarding eingeschaltet werden. Dies bedeutet, dass aller Traffic, der an eth0 ankommt und nicht für eine andere interne Station gedacht ist, automatisch an eth1 weitergeleitet wird (und von dort natürlich weiter ins Internet).

Das deute ich hier nur an, für Details mal ein bißchen im Internet nach "linux ip forwarding" suchen.
    iptables -A FORWARD -j ACCEPT -m state --state ESTABLISHED
    echo 1 > /proc/sys/net/ipv4/ip_forward
    net=192.168.1.0/24
    iptables        -A FORWARD     -j ACCEPT     -i eth0 -s "$net"
    iptables -t nat -A POSTROUTING -j MASQUERADE -o eth1 -s "$net"

    iptables -A FORWARD -j REJECT
Statt des gesamten Netzes (in der Variablen $net) kann man auch gezielt einzelne Hostnamen oder IPs angeben, aber das Setup des IP-Forwardings soll hier nicht das Thema sein.


Stattdessen will ich ein bißchen genauer auf das eigentliche Thema eingehen: das Zählen des Traffics.

Dazu richtet man mit iptables zwei zusätzliche "Chains" ein, und klinkt beide in die immer vorhandene FORWARD-Chain mit ein. Das bedeutet so etwas wie ein Verdoppeln der Daten, wobei die Duplikate in den neuen Chains (eine für Input, eine für Output) nur für das Zählen verwendet und dann weggeworfen werden.
    iptables -N INET_OUT
    iptables -N INET_IN 
    iptables -I FORWARD -j INET_IN
    iptables -I FORWARD -j INET_OUT
Diese beiden neuen Chains stattet man als nächstes mit der Information aus, für welche IP-Adresse überhaupt gezählt werden soll. Dabei muss zum Zählen pro IP-Adresse natürlich dieselbige angegeben werden als "Selektor". Einmal muss der Selektor als "source" (ausgehender Traffic) und einmal als "destination" (eingehender Traffic) verwendet werden (die Variable $ip geeignet setzen).
    iptables -I INET_OUT -s "$ip"
    iptables -I INET_IN  -d "$ip"
Danach kann man schon mal ein bißchen mit dem Gerät spielen (am Smartphone den App Store/Play Store aufrufen oder eine andere App mit Internetabrufen) und beobachten, ob sich bei den Zählern etwas bewegt.
iptables -L INET_IN -v
Um das regelmäßig anzuschauen, kann man den Befehl "watch" verwenden, der ein anderes Kommando regelmäßig aufruft. Meinem Smartphone habe ich im DNS den Namen "nexus" gegeben, und nach diesem Namen suche ich nun:

# watch -n 60 "iptables -L INET_IN -v|grep nexus"

Every 60.0s: iptables -L INET_IN -v|grep nexus
1567 1198K all -- any any anywhere nexus.moeller-seeling.local
Das Interessanteste dürfte der "inbound" sein, der hereinkommt. Typischerweise ist das Downloadvolumen eher groß, und der "outbound" besteht hauptsächlich darin, die Anfragen zu verschicken. Außer natürlich, man lädt gerade große Bilder zu Flickr oder Videos zu Youtube hoch ;)

Als nächstes richtet man dann einen cron-job ein, der diese Daten in regelmäßigen Abständen protokolliert und daraus lustige Reports erstellt. Davon erzähle ich im nächsten Beitrag, wenn ich mit Programmieren fertig bin ;)


[Update: Idee von Robert Dahlem von der LUG Frankfurt, außerdem diese FAQ]