Posts mit dem Label Router werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Router werden angezeigt. Alle Posts anzeigen

10.09.2018

Die überraschende Firewall

Zur Abwechslung gibt es heute mal eine Anekdote einer interessanten und überraschenden Problemsuche bei einem Freund.

Besagter Freund wollte sich ein Emailkonto bei einem neuen Anbieter einrichten und es wollte nicht funktionieren. Das Emailkonto gehört zu einem Gesamtkunstwerk aus Website und Domainname eines Vereins. Durch Umzug der Website zu einem anderen Anbieter und Wechsel im Vereinsvorstand mussten wir ein Emailkonto für den Verein auf seinem PC neu einrichten.

Ich hatte vorher das Konto über die Verwaltungsseite des Anbieters angelegt, die technischen Daten für die Mailserver notiert (Pop, Imap, Smtp) und meinem Freund geschickt. Aber es wollte nicht funktionieren. Halt, das ist nicht ganz richtig. Mail abholen funktionierte, aber Mail versenden war nicht möglich.

Für mich erschwerend kam hinzu, dass es sich um einen Laptop mit Windows und Outlook handelt, und schon mit Windows tue ich mich sehr schwer. Mit Outlook habe ich eigentlich gar keine Erfahrung und musste mich durch eine etwas gewöhnungsbedürftige Bedienung durchkämpfen. Ich selbst verwende als Mailprogramm schon immer Thunderbird und bin sehr zufrieden damit.

Zuerst hatte ich die Sicherheitssoftware in Verdacht: Norton Antivirus hatte sich in Browser und Betriebssystem als Firewall eingeklinkt (der Windows-interne Firewall war abgeschaltet) und ich schaltete testweise Norton komplett ab, weil ich den Verdacht hatte, dass Norton ausgehende Mailverbindungen zu "komischen" Servernamen ablehnt (zur Unterdrückung von Spam). Aber das half nicht.

Also tiefer eingestiegen und mit einer Kommandozeile eine "telnet"-Verbindung zum Anbieter versucht. Auch das schlug fehl - es war also kein Outlookproblem, und da Norton abgeschaltet war, auch kein Nortonproblem. Ein "ping" war möglich. Zudem war das telnet-Programm zuerst gar nicht erreichbar, sondern ich musste es über die Systemsteuerung installieren (in der Systemsteuerung bei den Windows-Komponenten den "telnet-client" ankreuzen). Danach konnte ich auf der Kommandozeile mit dem schlichten Befehl "telnet mailservername 465" testen, ob der PC eine TCP-Verbindung zum Port 465 für SMTP über SSL aufbauen kann.

Nach mehreren erfolglosen Versuchen kam ich auf die Idee, im DSL-Router nachzuschauen - ein ziemlich neues Mietgerät von der Telekom für VDSL mit "Smarthome"-Fähigkeiten, also ziemlich neu. Und tatsächlich gibt es in diesem !$%&-DSL-Router einen Menüpunkt "Erlaubte Mailserver".

Der Router hat also tatsächlich einen Mini-Firewall auf Hostnamenebene eingebaut und kommt mit einer einigermaßen umfangreichen Liste von vordefinierten Mailanbietern und deren Hostnamen für Smtp-Mailablieferung. Nur "unser" Anbieter "Host Europe" war nicht in der Liste enthalten.

Also den Hostnamen unseres Smtp-Servers eingetragen und - bingo! Es ging immer noch nicht.

Erst nach einem Neustart des DSL-Routers wurde die Änderung funktionsfähig.

Der Neustart zog zwar weitere Probleme mit dem ISDN-Adapter der Telekom und der alten ISDN-Telefonanlage meines Freundes nach sich, aber diese Geschichte erzähle ich vielleicht ein anderes Mal ;-)

25.06.2018

Leserbrief: Heimrouter und Sicherheit

Die WZ hat regelmäßig in der Samstagsausgabe Sonderseiten zu bestimmten Themen, darunter auch Computer, Internet, Smartphones und verwandte Themen. Kürzlich erschien ein Artikel, wie nützlich und vielseitig die Router sind, die im privaten Heim den Internetzugang bereitstellen. Der Artikel ließ aber einen wesentlichen Aspekt aus, der mir als Berufsparanoiker sehr wichtig ist: die Sicherheit.

[veröffentlicht am 23.06.2018]

Leserbrief zum Artikel über Auswahl des Routers für zuhause
Kürzlich hat die WZ einen Artikel über die Auswahl des richtigen Routers für zuhause abgedruckt.
Der Artikel war umfangreich, aber inhaltlich unbefriedigend. Ich habe z.B. vermisst, dass bestimmte Router nicht nur den Internetzugang bereitstellen, sondern auch als Heimserver dienen können, indem man Drucker und Speicher anschließt, die dann jeder nutzen kann. Manche Router können sogar über einen USB-Stick mit Mobilfunk einen alternativen Zugang bereitstellen, wenn die Internetverbindung ausfällt. Immerhin fand Erwähnung, dass neuere Router einen Gastzugang beherrschen.
Was mir aber massiv aufgestoßen ist, ist das Fehlen jeglicher Hinweise oder Empfehlungen auf die Sicherheit dieser Geräte. Immerhin ist der Router dasjenige Gerät, das direkt ans Internet angeschlossen ist, weil das naturgemäß der Sinn der Sache ist. Aus diesem Grund ist es immens wichtig, dass das Gerät regelmäßig Softwareupdates bekommt, um Sicherheitslücken zu schließen oder Fehler zu beheben. Die allermeisten Router funktionieren mit einem kleinen Linuxsystem, und hier gibt es regelmäßig Verbesserungen und Fehlerkorrekturen.
Erst vor kurzem wurde bekannt, dass sehr viele Router von durchaus bekannten Firmen (wie Asus, D-Link, Huawei, Linksys, Ubiquiti, Upvel, und ZTE, sowie verschiedene NAS und Router-Modelle von Linksys, Mikrotik, Netgear, Qnap und TP-Link) gegen einen bestimmten Angriff verwundbar sind und sich deshalb Trojaner einnisten konnten. Die c't berichtete, dass das FBI zwar den Kontrollserver dieses einen Botnetzes lahmlegen konnte, aber die Sicherheitslücken existieren nach wie vor für jeden anderen Bösewicht (eine Liste der betroffenen Geräte). In der Vergangenheit wurden auch schon oft Angriffe auf Heimrouter bekannt, aber mit zunehmender Breitbandversorgung wird es immer interessanter, diese Geräteklasse anzugreifen - eben weil sie schlecht gepflegt werden.
Das ist aus drei Gründen gefährlich:
Erstens haben die bösen Buben durch die weite Verbreitung dieser Geräte eine enorme Armee an Drohnen, die sie für ihre Zwecke einsetzen können, wie z.B. Erpressung mit einem sog. DDoS-Angriff (Distributed Denial of Service), bei dem der Angegriffene mit Anfragen überschwemmt wird und sein Geschäft nicht mehr ausüben kann,
zum Zweiten ist der Router in der Lage, jedes Gerät im Heimnetz anzusprechen und zu belauschen,
und zum Dritten ist es möglich, dass der Internetverkehr nicht nur belauscht, sondern auch manipuliert wird, so dass z.B. Kreditkarteninformationen, Passwörter, Electronic Banking usw. kompromittiert werden können.
Man kann es nicht oft genug wiederholen: Software-Updates werden immer wichtiger in einer Welt, in der es sich lohnt, elektronische Verbrechen zu begehen. Einer aktuellen Meldung von heise zufolge kann man mit Spam bis zu 300.000 Dollar pro Monat verdienen, mit Trojanern für Klickbetrug (simulierte Abrufe von Werbung) sogar Millionen. Das soll jetzt aber keine Werbung sein, hier ins Geschäft einzusteigen, bitteschön!
Niemand sollte einen Router kaufen oder sich vom Internetprovider aufstellen lassen, wenn die Updatefrage für dieses Modell nicht geklärt ist. Die Hersteller aus der o.g. Liste liefern auch Geräte, die von Vodafone, Telekom, 1&1 und anderen Internetprovidern unter eigener Marke ausgeliefert werden (die Telekom und Vodafone verwenden u.a. gern Geräte von Asus, ZyXEL und Huawei). Jeder Besitzer sollte darauf achten, dass die Updates entweder automatisch installiert werden oder es sich zur Angewohnheit machen, regelmäßig zu kontrollieren, ob es neue Updates gibt.
Im Zweifelsfall kann der Internetprovider eine Updategarantie natürlich nicht geben. Hier empfiehlt es sich, das Gerät nicht von diesem zu kaufen oder zu mieten, sondern sich über Tests in Fachzeitschriften selbst ein gut - und vor allem lang! - gepflegtes Modell auszusuchen.
Tipp am Rand: das Standardpasswort des Geräts sollte auch auf etwas eigenes geändert werden. Manche Standardpasswörter der Hersteller werden nach einem eher langweiligen Algorithmus erzeugt und sind leicht berechenbar.

28.02.2014

LTE-Empfangsqualität abfragen (Diagnose-Logfile)

Neulich hab ich mich beschwert, dass man beim alten Modell des LTE-Routers (Telekom LTE 1 bzw. Huawei B390s) nicht die Empfangsqualität abfragen kann.

Und es geht doch! Zwar ziemlich versteckt in den Tiefen der "Erweiterten Einstellungen", aber man kann es doch abfragen.

Wie üblich in Ihrem freundlichen Service-Blog auch gleich wieder die Möglichkeit, diese Daten automatisiert per Skript abzufragen und damit ggfs. regelmäßig zu protokollieren.

Der übliche Trick: mit dem ersten wget-Aufruf geschieht der Login, das Session-Cookie wird gespeichert, und mit dem zweiten Aufruf wird dann die interessante Seite abgerufen.
#!/bin/sh

PATH=/opt/bin:/opt/sbin${PATH:+:$PATH}

H=vodafonemobile.cpe
C=/tmp/cookies.txt
U1="http://"$H"/login.cgi"
U2="http://"$H"/diagnosis_export.cgi?configId=$(date +%s)&FileName=diagnosis.txt"

wget --save-cookies "$C" \
     --keep-session-cookies \
     -q --tries=1 \
     -O /dev/null \
     --post-data 'Username=admin&Password=yourpw' \
     "$U1"

wget --load-cookies "$C" \
     -q --tries=1 \
     -O - \
     "$U2" | \
awk '
{if (NR>=5&&NR<=42){print}}
'

rm -f "$C"
Der Output sieht dann in etwa so aus wie da unten.

Besonders interessant sind die Zeilen bei "RSRP" und "RSRQ". Mit den Werten -90dBm und -8 dB zeigt mir der Router 4 von 5 Balken an. Laut Telekom-Auskunft sind Werte bis -60/-2 möglich, das wäre super-super-optimal. Wenn man das Gerät in der Ausrichtung verändert, darf  RSRP ruhig etwas schlechter werden, falls man dadurch RSRQ verbessern kann. Optimal wäre, wenn beide Werte größer werden (-90 --> -60, -8 --> -2).

Auch sehr hübsch: man erfährt den Funkmast, mit dem der Router verbunden ist, und zwar mit dem Parameter "CellId".

~~~~~~Product Information~~~~~~
003    Model:               B390s-2                    PASS
004    Software Version:    V200R001C35SP12            PASS
005    Hardware Version:    B390-B390RW2A Ver.C        PASS
006    SN:                  4UA5TC1110400163           PASS
007    IMEI:                354637040077555            PASS
008    LAN MAC Address:     F4:C7:14:**:**:**           PASS
009    WLAN MAC Address:    F4:C7:14:**:**:**           PASS
010    Check AT-Port:        Available                  PASS

~~~~~~LTE State~~~~~~
011    Dialing Mode:                                   PASS
012    APN:                  internet.home              PASS
013    DNS:                  8.8.8.8                    PASS
014    PDN Type:             IPv4                       PASS
015    Service Status:       Normal Service            PASS
016    Connection Status:    LTE STATE CONNECTED       PASS
017    Frequency:            816000 kHz               PASS
018    Bandwidth:            10MHz                    PASS
019    CellId:               392                       PASS

020    IP Address:           2.162.**.***             PASS
021    RSRP:                 -90dBm                    PASS

022    RSSI:                 -66dBm                    PASS
023    RSRQ:                 -7dB                      PASS 

024    Roam:                  no                       PASS
025    Antenna State:        Built-In                  PASS

~~~~~~DHCP~~~~~~
026    Gateway IP Address:    192.168.42.1           PASS
027    DHCP Enabled:          false                  PASS
028    Subnet Mask:          255.255.255.0          PASS
029    DHCP_ip_pool_start:    N/A                    PASS
030    DHCP_ip_pool_end:     N/A                     PASS
031    DHCP_lease_time(s):    N/A                     PASS

~~~~~~SIM/PIN State~~~~~~
032    sim_state:             SIM Card detected       PASS
033    PIN code:             READY                    PASS
 

18.01.2014

Erbsen zählen - Perl und CGI - Dritter Teil

Im dritten Teil beschreibe ich nun das Interessanteste: die Auswertung der Daten in Text- und Grafikform, deren Prinzip ich im ersten Teil und Sammlung im zweiten Teil beschrieben habe.

Genau wie schon früher beschrieben, verwende ich das Grafikmodul GD für Perl. Dort kann man ein paar Daten hineinstecken und dann mit einem Aufruf unterschiedliche Schaubilder erzeugen lassen, als "line"-Graph, "bar"-Graph und viele andere. Der Output ist dann HTTP-konform eine Grafikdatei im gewünschten Format, z.B. PNG oder GIF, zusammen mit einer Headerzeile und dem passenden MIME-Typ.

Beim Design gibt es zwei grundsätzliche Überlegungen:
  1. Die Logdateien sammeln Daten pro überwachtem Hostname, ich muss also noch eine Summe bilden, um den Verbrauch pro Host im Verhältnis zum Rest beurteilen zu können.
  2. Ich würde gern sowohl eine Tabelle mit den aktuellen Daten sehen als auch einen Graphen, aus dem man Trends ablesen kann. Ich brauche also im CGI-Skript eine Fallunterscheidung - Text oder Grafik.
Hier kommt das komplette CGI-Skript. An ein paar Stellen füge ich Kommentare in rot oder blau ein, wenn es etwas zu erklären gibt.

Eine grundsätzliche Bemerkung vorneweg: die Datenübergabe erfolgt immer in Form von Referenzen (in C wären das Zeiger auf Datenstrukturen), deshalb verwende ich im Skript i.a. auch gleich Variablen, Arrays und Hashes, die Referenzen enthalten, damit die Übergabe an GD nicht noch unnötig Datenformate umwandeln muss.

Um das CGI-Skript bequem testen zu können, habe ich einen "Testmodus" eingebaut. Man kann generell Skripte, die das CGI-Modul verwenden, auch auf der Kommandozeile aufrufen. Die Argumente, die normalerweise in der Request-URL nach dem "?" folgen, schreibt man einfach als Pärchen mit "name=wert" hinter den Skriptnamen in die Kommandozeile, wie man hier am Beispiel sieht.
# ./accounting.pl scale=1000 testmode=99 xmax=400 ymax=300
Bei diesem Testmodus ist noch zu bedenken, dass natürlich die Umgebungsvariablen des Webservers nicht gesetzt  sind (QUERY_STRING, PATH_INFO, die SSL_*-Variablen, wenn das Skript mit https aufgerufen wurde, usw.). Ggfs. müsste man diese Variablen manuell mit passenden gefälschten Inhalten setzen, damit das Skript an den entsprechenden Stellen sinnvolle Werte bekommt.

Dem Skript kann man einen Parameter "filter" übergeben, um nur einen ganz bestimmten Hostnamen auszufiltern. Deshalb gibt es eine etwas unübersichtliche Fallunterscheidung, ob ein Filter gesetzt ist oder nicht.

Mit "mode=1" wird eine Grafik in voller Größe mit mehreren Graphen und der Gesamtsumme angezeigt; "mode=16" erzeugt eine Tabelle in Textform mit einer Zeile pro Hostname in der Logdatei und hinter jedem Hostnamen in einer Extraspalte eine wönzig kleine Grafik mit der Gesamtsumme und dem Verbrauch dieses Hosts.

#!/usr/bin/perl -w

use strict 'vars';
use strict 'refs';

use GD::Graph;
use GD::Graph::lines;
use GD::Graph::bars;
use GD::Graph::hbars;

# Die GD-Module zeichnen die verschiedenen Typen von Graphen
use CGI qw(:standard);

#use lib "/usr/local/bin";

my @data;

# Array mit Beschriftung, x-Skala und ein oder mehreren y-Datenpunkten
my %hosts;

# Array zum Speichern der Daten pro Hostname
my $graph;
my $format;
my ($xmax,$ymax);

# Größe des auszugebenden Bilds
my $query;
my $range;
my $filter;

# Regexfilter für Hostnamen
# mode=0 full graph mode all hosts
# mode=9 sum only graph
# mode=16 text mode
# mode=99 debug text mode
my $mode;
my @x;
my @y1;

# y1=summierte Daten IN
my @y2;

# y2=summierte Daten OUT
my $scale;
#my $offset;
my $title="LTE volume statistics";

# X-Beschriftung
# werte1
# werte2
# ...
@data=(
);

%hosts=(
# "dummy.moeller-seeling.local" => { "IN " => [ 0 ], "OUT" => [ 0 ] }
);

my $max=0;
my $lines=0;

# logfile inbound, outbound
my ($login,$logout);


$query=new CGI();
$mode=$query->param( 'mode' ) || 0;
$range=$query->param( 'range' ) || "60";
#$offset=$query->param( 'offset' ) || "0";
$scale=$query->param( 'scale' ) || "2500";
$filter=$query->param( 'filter' ) || "";
$xmax=$query->param( 'xmax' ) || "800";
$ymax=$query->param( 'ymax' ) || "600";
$login=$query->param( 'infile' ) || "/var/log/lte-acct.in";
$logout=$query->param( 'outfile' ) || "/var/log/lte-acct.out";
$graph = GD::Graph::lines->new($xmax, $ymax);
$format = $graph->export_format;

# 20140108-110202 IN  i9100.moeller-seeling.local              91M
# 20140108-110202 IN  lifetab.moeller-seeling.local            42M
# 20140108-110202 IN  nexus.moeller-seeling.local              8748K
# 20140108-110202 IN  vettie68.moeller-seeling.local           143M

#my $d;

sub readfile {
  my ($file,$tag,$y)=@_;

  if (open(F,"<",$file)) {
    my ($dt,$old)=("","");

      while (<F>) {
      my ($name,$num,$unit,$hm,$m);

      chomp;
# 20140107-184506 IN  lifetab.moeller-seeling.local            0
# dieser Regex zerlegt eine Zeile, $tag ist IN oder OUT      if ($filter) {
        ($name,$num,$unit,$dt,$hm,$m)=($filter,$7,$8,"$1$2$3-$4$5$6","$4$5",$5)
          if (/^(\d{4})(\d{2})(\d{2})-(\d{2})(\d{2})(\d{2}) $tag\s+$filter.*?\s*(\d+)([KMG]?$)/);
      }
      else {
        ($name,$num,$unit,$dt,$hm,$m)=($7,$8,$9,"$1$2$3-$4$5$6","$4$5",$5)
          if (/^(\d{4})(\d{2})(\d{2})-(\d{2})(\d{2})(\d{2}) $tag\s+([a-z.-][0-9a-z.-]+)\s*(\d+)([KMG]?)/);
      }
      if ($name && defined($num) && defined($unit)) {

        ++$lines;
        if ($unit eq "")  { $num>>=10; }
#       if ($unit eq "K") { $num<<=10; }
        if ($unit eq "M") { $num<<=10; }
        if ($unit eq "G") { $num<<=20; }
# alle Zahlenwerte sind in KB        if ($num>1000) {
          if ($ymax<100) { push(@x,$m); }
          else { push(@x,$hm); }
          $num>>=10;
          push(@{$hosts{$name}->{$tag}},$num);
if ($mode==99) { print STDERR "# <$_>\n# $hm $tag $filter $num $unit | $max\n"; }

# in den Logfiles stehen kumulierte Daten pro Host
# alle Werte vom selben Timestamp addieren für Gesamtsumme
          if ($dt eq $old) { $num+=pop(@{$y}); }
#         else { $num+=$offset; }
          push(@{$y},$num);
          $old=$dt;

# Timestamp aufheben für Vergleich mit nächster Zeile
          if ($max<$num) { $max=$num; }

# Maximum merken für y-Skalierung
if ($mode==99) { print STDERR "# @{$y}\n"; }
        }
      }

    }
    close(F);
  }
}

readfile($login, "IN ",\@y1);
readfile($logout,"OUT",\@y2);

if ($mode==99) {
  local($,=", ");
  foreach my $h (keys(%hosts)) {
    print STDERR "# h $h\n";
    print STDERR "# i @{$hosts{$h}->{'IN '}}\n";
    print STDERR "# o @{$hosts{$h}->{'OUT'}}\n";
  }
  print STDERR "# Sum\n";
  print STDERR "# i @y1\n";
  print STDERR "# o @y2\n";
}


# maximal die letzten $range werte aus der Datei darstellen


if ($range>0) {
  splice(@x,0,-$range);
  splice(@y1,0,-$range);
  splice(@y2,0,-$range);
  $lines=$range;
}
$data[0]=\@x;

# mode=9 nur die Summe
# mode !=9 alle Hostnamen auch einzeln zeigen
if ($mode!=9) {
  foreach my $h (keys(%hosts)) {

# inbound ist interessanter
# man könnte aber in und out anzeigen
    push(@data,$hosts{$h}->{'IN '});
#   push(@data,$hosts{$h}->{'OUT'});
  }
}
# sum of all hosts IN
push(@data,\@y1);
# sum of all hosts OUT
#push(@data,\@y2);

$max=$scale*int($max/$scale+1);

# sinnvolle obere y-Grenze ausrechnen

if ($mode==99) { print STDERR "# max=$max\n"; }

# Daten übergeben$graph->set(
  x_label       => 'Volume Date/Time, ' . $lines . " samples",
  y_label       => 'max ' . $max . ' GB',
  title         => 'LTE volume (GB)',
  y_max_value   => $max,
  y_tick_number => 20,
  y_label_skip  => ($ymax<200) ? 5: 2,
  x_labels_vertical => 1,
  x_label_skip  => $lines / 12,
) or die $graph->error;

# optional die Farben selbst festlegen
#$graph->set( dclrs => [ qw(green lred blue cyan) ] );

# gibt es überhaupt daten?

if ($lines>0) {
  if ($mode<16) {

# bilddatei erzeugen
# binmode ist nur mit windows-webserver wichtig
    print header("image/$format");
    binmode STDOUT;
    print $graph->plot(\@data)->$format();
  }

# textmodus output als tabelle
  elsif ($mode==16) {
    print CGI::header();

    print <<__HEADER__;
<HTML>
<HEAD>
<TITLE>$title</TITLE>
<META http-equiv="refresh" content="300" />
<style type="text/css">
th {
  padding : 3px;
  text-align : left;
}
td {
  padding : 3px;
  text-align : right;
}
</style>
</HEAD>
__HEADER__

print "<!-- ";
print join( " -->\n<!-- ",
           map( "$_ => $ENV{$_}", sort(keys(%ENV)))
          );
print "-->\n";

    print <<__BODY__;
<BODY>
<H1>$title</H1>
<table border="1">
<tr>
<th> Hostname </th>
<th> Download </th>
<th> Upload </th>
</tr>
__BODY__

    foreach my $h (keys(%hosts)) {
      print "<tr>\n";
      print "<th> $h</th>\n";
      print "<td>",pop(@{$hosts{$h}->{'IN '}})," MB </td>\n";
      print "<td>",pop(@{$hosts{$h}->{'OUT'}})," MB </td>\n";

# hinter jeden hostnamen einen wönzigen Detailgraphen anzeigen
if (defined($ENV{'HTTP_HOST'})) {
      print "<td><IMG SRC=http://",$ENV{'HTTP_HOST'},$ENV{'SCRIPT_NAME'},"?filter=$h&xmax=300&ymax=100&scale=",int($max/10),"</IMG></td>\n";
}
      print "</tr>\n";
    }
    print "<tr>\n";
    print "<th style='text-align:right'> &Sigma; </th>\n";
    print "<td>",pop(@y1)," MB </td>\n";
    print "<td>",pop(@y2)," MB </td>\n";
if (defined($ENV{'HTTP_HOST'})) {
      print "<td><IMG SRC=http://",$ENV{'HTTP_HOST'},$ENV{'SCRIPT_NAME'},"?mode=9&xmax=300&ymax=100&scale=",int($max/10),"</IMG></td>\n";
}
    print "</tr>\n";

    print <<__BODY__;
</table>
<DIV>
<HR/>
<ADDRESS>
ths, last changed 09.01.2014
</ADDRESS>
</DIV>
</BODY>
</HTML>
__BODY__

  }
}


[Update 20140122: Links zum 1. und 2. Teil eingefügt]

10.01.2014

Erbsen zählen - zweiter Teil

Nachdem ich also im 1. Teil das Grundprinzip des Erbsenzählens beschrieben habe, kommt hier ein bißchen mehr Skripting zum Einsatz, damit sich der Tag "Automation" auch lohnt ;)

Das Datensammeln an sich ist eine triviale Sache. Man braucht ein kleines Skript, das mit Hilfe von cron regelmäßig ausgeführt wird.

Ich habe einfach mal willkürlich festgelegt, dass es einmal stündlich laufen soll:

2 * * * * /usr/local/sbin/ip-accounting.sh -I /var/log/lte-acct.in -O /var/log/lte-acct.out >/dev/null 2>&1

Der Inhalt des Skripts sieht ein bißchen aufgebläht aus, weil ein paar Kommandozeilenargumente ausgewertet werden wollen. Die wichtigste Zeile im Skript habe ich nochmal extra rot markiert, das ist die eigentliche Datensammlung.
#!/bin/sh

PATH=/opt/sbin:/opt/bin:/usr/bin:/usr/sbin${PATH:+:$PATH}

bytesin=0
bytesout=0
while getopts "iI:oO:" opt
do
  case "$opt" in
  i) bytesin=1;;
  I) filein="$OPTARG";;
  o) bytesout=1;;
  O) fileout="$OPTARG";;
  esac
done
shift $(expr $OPTIND - 1)
if [ "$bytesin$bytesout$filein$fileout" = "00" ]
then
  bytesin=1
  bytesout=1
fi

dt=$(date +%Y%m%d-%H%M%S)

out=$(iptables -L INET_OUT -v | awk -v D="$dt" '{if(NR>2){printf"%s OUT %-40s %s\n",D,$7,$2}}'|sort)
if [ "$bytesout" -eq 1 ]
then
  echo "$out"
fi
if [ -n "$fileout" ]
then
  echo "$out" >> "$fileout"
fi

out=$(iptables -L INET_IN  -v | awk -v D="$dt" '{if(NR>2){printf"%s IN  %-40s %s\n",D,$8,$2}}'|sort)
if [ "$bytesin" -eq 1 ]
then
  echo "$out"
fi
if [ -n "$filein" ]
then
  echo "$out" >> "$filein"
fi
Und was genau macht diese rot markierte Zeile? Schauen wir mal genauer hin. Es sind mehrere Befehle in einer Zeile, verbunden mit dem Weiterleitungszeichen | (pipe). Diese Pipe verbindet den Output des Programms vorne mit dem Input des Programms dahinter.
iptables -L INET_IN  -v |

Der erste Befehl zeigt die bis dahin aufgelaufene Datenmenge für alle überwachten Systeme an. Wichtig ist der Switch -v, sonst bekomme ich die Datenmenge nicht zu sehen.
awk -v D="$dt" '{if(NR>2){printf"%s IN  %-40s %s\n",D,$8,$2}}' |

Die Ausgabe enthält allerdings ziemlich viel Kram, der mich gar nicht interessiert, deswegen verwende ich awk, um mir gezielt nur das zu extrahieren, was ich für meine Neugier brauche. Natürlich könnte ich normalerweise auch grep verwenden, um etwas zu suchen, aber weil ich gleichzeitig ein wenig programmieren will und einzelne Felder aus jeder Zeile des Outputs ausschneiden will, verwende ich ganz gern awk, statt grep mit cut o.ä. zu kombinieren. Spart ein wenig CPU ;)

Bei diesem Befehl benutze ich zwei eingebaute Fähigkeiten von awk: es zählt automatisch die Zeilennummern in der Variablen NR (number of records) mit, was ich verwende, um die ersten zwei Zeilen mit der Überschrift des iptables-Outputs wegzuwerfen, und es zerlegt automatisch die Zeile in "Felder" gemäß einem vorgegebenen Trennzeichen (üblicherweise Whitespace). awk arbeitet also den printf-Befehl nur ab der dritten Zeile des Inputs ab und zeigt davon nur das achte und das zweite Feld an (Hostname und Datenmenge)

Bei der Chain INET_OUT ist  übrigens  der Hostname im siebten Feld enthalten, und bei der Chain INET_IN im achten Feld, weil ich ja einmal nach "source" und einmal nach "destination" suche.

Randbemerkung: damit awk einen Timestamp mit ausgeben kann, gebe ich dem Aufruf von awk einen solchen vorgefertigten Timestamp auf der Kommandozeile mit dem Switch -v NAME=WERT mit. Das können nicht alle awk unter allen Unix-Varianten, m.W. wurde das mit dem "new awk" (nawk) unter SunOS eingeführt, GNU awk unter Linux kann es auf jeden Fall.
sort
Der letzte Befehl sortiert das ganze schlicht und einfach alphabetisch. Ich könnte auch iptables mit dem Switch -n verwenden, um die IP-Adressen zu sehen anstatt der Hostnamen. Dann wäre es angebracht, bei sort ebenfalls -n zu verwenden, um numerische Sortierung zu erzwingen.

Dieses Skript sammelt also stündlich Daten pro überwachtem Hostname. Die gesammelten Daten sehen dann so aus:
server:/share/www/cgi-bin # tail -n2 /var/log/lte-acct.in /var/log/lte-acct.out
==> /var/log/lte-acct.in <==
20140109-150202 IN  nexus.moeller-seeling.local              23M
20140109-150202 IN  vettie68.moeller-seeling.local           286M


==> /var/log/lte-acct.out <==
20140109-150202 OUT nexus.moeller-seeling.local              6752K
20140109-150202 OUT vettie68.moeller-seeling.local           13M

Wie man sieht, ist der Output menschenfreundlich und es wird immer eine halbwegs lesbare Größenordnung bei der Datenmenge angezeigt: KB, MB oder GB. Ohne Einheit sind "Byte" gemeint. Diese Kleinigkeit ist beim Programmieren einer kleiner Stolperstein gewesen ;)

Das Auswerte-Skript habe ich als CGI-Skript in Perl gelöst. Es kann sowohl eine Tabelle als auch eine Grafik erzeugen (mit dem Perl-Modul GD). Das folgt dann im nächsten Teil.

Am Ersten des Monats sollte man übrigens die Zähler wieder auf Null setzen:
iptables -L INET_IN -Z
iptables -L INET_OUT -Z
Ich habe schon ein Skript, das mir meinen Verbrauchszähler auf Null setzt, dort werde ich das noch mit einbauen.

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]

31.05.2013

Die Telekom und die Störungshotline

Eben gerade hat es die Telekom überraschend geschafft, mich positiv zu verblüffen.

Ich bin ja eher gern und schnell dazu bereit, zu meckern, aber wer genau hinguckt, stellt fest, dass diesmal wirklich das Tag "Gejammer" bei diesem Artikel fehlt ;). Aber so ganz ohne geht es nicht, deswegen hab ich ja auch wieder ein Thema zum Schreiben ;)

Kurz nach 10 Uhr fiel unser LTE plötzlich und unerwartet aus. Eben noch ein paar Dinge bei Google gesucht, und plötzlich ging nix mehr ...

Ein bißchen hab ich mich schon daran gewöhnt, dass der LTE-Router nicht so das zuverlässigste Stück Technik im Haushalt ist, und deshalb einen nächtlichen Cron-Job im Server eingerichtet, der einen Reset des LTE-Routers durchführt.

Spontan und unerwartet fiel also die Internet-Verbindung aus, und als ich bei der Telekom-Hotline anrief, um eine Dreiviertelstunde später die Störung zu melden, befürchtete ich schon das Schlimmste ... Der Sprachcomputer nahm meine Kategorie "Störung" entgegen und bestand dann darauf, dass ich die Nummer des gestörten Anschlusses eingab. Nach einigen Knacksern und dem "Durchführen einer vorläufigen Prüfung" wurde mir dann mehrfach hintereinander mitgeteilt, dass "alle Plätze belegt" seien und ich später wieder anrufen solle.

Na klasse, die Telekom rechnet sich ihre SLAs schön ... In meinem Vertrag bzw. in den AGB steht drin, dass sie innerhalb von 24 Stunden auf Störungsmeldungen reagieren müssen. Da macht es sich in der Statistik doch gut, wenn man die Störungsmeldungen einfach noch ein bißchen hinauszögert oder gar nicht erst annimmt.

Nach dem dritten oder vierten Versuch und dem ebensovielten virtuellen Hinauswurf fing ich an, mit den Servicenummern zu spielen (0800-330-xy00) und wenige Versuche später hatte ich dann tatsächlich ganz ohne Warteschleife einen echten Menschen am Telefon und konnte mein Leid loswerden. Darin enthalten war ausdrücklich der Hinweis, dass der LTE-Router keine Verbindung ins Internet bekommt und gelegentlich "Fehler 44 beim Verbindungsaufbau" anzeigt. Allerdings konnte die Hotline-Dame niemanden in "der Technik" erreichen und bat mich, ein paar Minuten später nochmal anzurufen.

Wenig später dann ganz überraschend (wirklich ein Tag voller Wunder) ein Rückruf auf dem Handy von derselben Dame, dass sie doch jemanden in der Technik erreicht habe und meine Störungsmeldung weitergegeben wurde. Wahnsinn!

Wenige Minuten später ein Anruf auf der Festnetznummer, und das folgende Gespräch war so unterhaltsam, das hat mir wirklich den Freitag gerettet!

Eine andere Dame war in der Leitung, die annahm, ich hätte ein "PC-Problem". Vom Teamleiter wurde ihr das Problemticket zugeteilt, und der Anrufer (also ich) wäre wohl so ein "altes Op'chen" und hätte wohl ein Problem, weil er mit seinem PC nicht ins Internet kommt. Wir konnten das Mißverständnis dann schnell aufklären, dass es am LTE-Router liegt und kein PEBKAC ist. Ich fand es sehr schmeichelhaft, dass sie während unseres Gesprächs meinte, dass ich am Telefon nicht wie ein alter Opa klinge, ganz im Gegenteil. Hach, war das nett ;). Dabei geh ich doch auch schon auf die Fünfzig zu ...

Mittlerweile schlug die SMS mit der Ticketnummer bei mir auf, und eine knappe Stunde später lief wieder alles. Juhu.

Und nochmal ein paar Minuten später kam nochmal ein Anruf auf dem Handy von einer weiteren Dame aus "der Technik", die zuerst nachfragte, ob meine Telefonleitung immer noch gestört sei. Ich wies sie darauf hin, dass es um LTE geht und schon gelöst ist, und fragte sie, warum ich bei der Störungsannahme eine Telefonnummer angeben musste. Sie lachte und konnte mir dann freundlicherweise noch eine spezielle Hotline-Telefonnummer für LTE-Probleme mitteilen: 0800-311-3221.

Im  großen und ganzen lief diese Störungsmeldung und -behebung erstaunlich erfolgreich ab, und ich bin positiv überrascht, wie intensiv der Kundenkontakt ist. Wenn auch die Störungsannahme mich erst mal als "alten Opa mit PC-Problem" eingeordnet hat ;)

22.03.2013

Huawei-LTE-Router per Skript resetten

Mal wieder ein kleines Skript aus der Abteilung "Nützliches für Kommandozeilenbastler".
Der LTE-Router von Huawei hat ab und zu mal Schluckauf und muss neu gestartet werden. Das umfasst den Aufruf der Adminseite mit einem Browser, Anmelden und durch drei Webseiten durchklicken, bis der Router sich wirklich zu einem Reset bequemt.

Mit demselben Trick wie neulich (Statusabfrage des Transfervolumens) ist es möglich, das Problem mit dem zweimaligen Aufruf von wget zu erschlagen. Beim ersten wget-Aufruf wird eine Anmeldung mit User und Passwort durchgeführt und das Session-Cookie gespeichert. Mit dem zweiten Aufruf wird dann direkt die URL aufgerufen, die den Reboot erzwingt (und die ganzen "Sind Sie sicher?"-Abfragen überspringt).

An der rot markierten Stelle "YOURPASSWORD" muss das eigene Router-Passwort eingesetzt werden. Wenn es Sonderzeichen enthält, müssen die als Entities geschrieben werden (Plus als %2B, Minus %2D, @ als %40 usw.). Ebenso muss an der rot markierten Stelle der Hostname oder die IP-Adresse des LTE-Routers eingesetzt werden (Telekom: speedport.ip, Vodafone: vodafonemobile.cpe, oder schlicht die IP, wenn die fix ist).

#!/bin/sh
verbose=0

while getopts "v" opt
do
  case "$opt" in
  v) verbose=1;;
  esac
done
shift $(expr $OPTIND - 1)


PATH=/opt/bin:/opt/sbin${PATH:+:$PATH}
LTE=192.168.42.1


C=/tmp/cookies.txt
U1="http://$LTE/login.cgi"
U2="http://$LTE/reboot.cgi"


wget --save-cookies "$C" \
     --keep-session-cookies \
     -q --tries=1 \
     -O /dev/null \
     --post-data 'Username=admin&Password=YOURPASSWORD' \
"$U1"
wget --load-cookies "$C" \
     -q --tries=1 \
     -O /dev/null \
     "$U2"
rm -f "$C"


c=1
echo -n "# waiting for ping "
until [ $c -gt 20 ]
do
  echo -n "."
  sleep 5
  c=$(expr $c + 1)
  ping -qc1 $LTE > /dev/null && break
done
echo " rc=$?"