Fällt der Internetprovider aus, sitzt der Nutzer zu Hause auf dem Trockenen. Es sei denn, er hilft sich wie ein Profi und schaltet auf die Konkurrenz um. Ein Perl-Skript konfiguriert dann den Rechner neu.
In Kalifornien gibt es derzeit zwei große Konkurrenten für Internetanschlüsse in Privathaushalten: die Telefongesellschaft AT&T mit ihrem DSL und die Kabelfirma Comcast, die durch das Fernsehkabel ebenfalls Breitband-Internet anbietet. Ein DSL- oder Kabelmodem zapft die Daten aus der Leitung, ein vorgeschalteter Router verbindet sämtliche Rechner des Haushalts im Handumdrehen mit dem Internet (Abbildung 1).
Billig oder schnell
Beide Anbieter haben Vor- und Nachteile. So leidet die Kabelverbindung, wenn zu viele Kinder in der Nachbarschaft “World of Warcraft” spielen, weil die Bandbreite mit der Zahl der Nutzer abnimmt. Der legendäre Werbespot “Web Hog!” [2] des DSL-Anbieters Southern Bell illustriert humorvoll, wie sich friedfertige Nachbarn einer Kleinstadt über Nacht in Berserker verwandeln, weil sie sich angeblich gegenseitig das Internet lahmlegen. Das DSL der Telefongesellschaft ist zumindest in der langsamen Billigversion preisgünstiger und jeder bekommt die gleiche Bandbreite. Allerdings hängen Verfügbarkeit und tatsächlicher Durchsatz von der Entfernung zum nächsten Knotenpunkt ab.
Keines der beiden Verfahren ist jedoch absolut zuverlässig, immer wieder gibt\’s Probleme: ein Stromausfall oder ein Bauarbeiter, der ein Kabel anbohrt, – schon fällt das Internet aus. Ärgerlich für den, der es gerade dringend braucht. Da aber sowohl DSL als auch Kabel-Internet im Sonderangebot monatlich nur etwa 20 Dollar kosten, habe ich mir beide bestellt. Wenn ein Anbieter ausfällt, schalte ich einfach auf den anderen um.
Schalter-Skript
Das Skript »isp-switch« (Listing 1) nimmt als Parameter entweder »cable« oder »dsl« auf der Kommandozeile entgegen und führt die zum Umschalten nötigen Schritte aus. In dem Skript bestimmt Zeile 21 die möglichen Werte dieser Parameter. Bei unbekannten Providernamen bricht es mit »pod2usage()« ab und gibt eine Fehlermeldung sowie die verkürzte Bedienungsanleitung aus.
Die weiche Referenz »$switch_to->()« in Zeile 31 ruft dann die weiter unten definierten Funktionen »cable()« oder »dsl()« auf. Damit der Perl-Interpreter im Strict-Modus bei diesem schmutzigen Trick nicht ausflippt, muss das Skript die Strenge mit »no strict \’refs\’« etwas abmildern. Das umschließende »eval«-Konstrukt fängt etwaige Fehler ab und lässt es weiterrattern, auch wenn nicht alle Schritte erfolgreich ablaufen.
Das Skript nutzt Log::Log4perl für die Status- und Fehlermeldungen. Das in Zeile 48 verwendete Makro »ALWAYS« kam allerdings erst mit Version 1.13 hinzu, deshalb fordert Zeile 9 mindestens diese Version an.
Patch mich!
Mein Linux-Rechner hat eine statische 192.er-IP im lokalen Netzwerk, nutzt also kein DHCP. Unter Fedora konfiguriert er in der Datei »/etc/sysconfig/network« sein Default-Gateway, also den Router, der Anfragen ins Internet weiterleitet. Abbildung 2 zeigt die Datei im Originalzustand. Das Gateway ist ein Gerät der Firma Buffalo vom Typ G54, das seit Jahren den internen Netzwerkverkehr der Perlmeister-Studios zuverlässig mit dem DSL-Modem und damit dem Internet verbindet.
Kommt wegen eines DSL-Ausfalls jedoch die Kabelverbindung zum Einsatz, benötigt sie einen anderen Router. Wie lassen sich sie Konfigurationsdateien verändern und zugleich ihr Originalzustand speichern, der jederzeit wiederherstellbar sein soll?
Modul für Patches
Das CPAN-Modul Config::Patch fügt Patches in System-Konfigurationsdateien ein und merkt sich den Originaltext als Base-64-kodierte Kommentare. Möchte der User das Patch wieder entfernen, liest das Modul die Base-64-Kodierung, extrahiert den Originaltext und restauriert ihn wieder.
Abbildung 3 zeigt die Datei »network«, nach dem Einspielen des Patch. Die ab Zeile 60 definierte Funktion »gateway _patch« erhält als Parameter die IP-Adresse des Gateway. Der Konstruktor des Config::Patch-Objekts bekommt den Namen der zu patchenden Datei und einen Schlüssel. Diese Zeichenkette speichert typischerweise den Projekt- oder Applikationsnamen und hilft dem Modul, Patches ein und derselben Datei durch verschiedene Schlüssel zu unterscheiden und getrennt zu bearbeiten. Bereits gepatchte Bereiche markiert das Modul als verbotene Zonen und verhindert so überlappende Patches.
Config::Patch kann Patches wahlweise am Anfang einer Datei, zwischen zwei Zeilen oder am Ende einfügen. Die Methode »replace« ersetzt gar eine mit Hilfe eines regulären Ausdrucks spezifizierte Zeile oder einen Zeilenbereich mit der angegebenen Ersatzzeile. Der Aufruf
$patcher->replace( qr(^GATEWAY=.*)m, "GATEWAY=$ip");
sucht nach einer Zeile, die mit »GATEWAY=« beginnt. Da der Regex über mehrere Zeilen greift, ist der Modifizierer »/m« relevant, damit das Metazeichen »^« auch tatsächlich sämtliche Zeilenanfänge erkennt und nicht nur den der ersten Zeile. Die auf diese Weise gefundene Gateway-Zeile kodiert Config::Patch zu einem Merker, kommentiert diesen anschließend aus und ersetzt die Zeile durch einen Gateway-Eintrag mit der neuen IP-Adresse.
Um die Datei wieder in den Ursprungszustand zurückzuversetzen, genügt der Aufruf »$patcher->remove()«, denn der Patcher benötigt nur den Dateinamen und den Key, die bereits im Konstruktor des Objekts vorliegen. Die Methode »patched()« stellt fest, ob es sich um eine bereits mit dem angegebenen Schlüssel gepatchte Datei handelt, und liefert im positiven Fall einen wahren Wert zurück.
Strom auf Kommando
Der Kabel-Router ist im DSL-Betrieb abgeschaltet. Mit Hilfe der in [3] vorgestellten X10-Schnittstelle schaltet das CPAN-Modul X10::Home ihn über das Stromnetz ein. Das besorgt der Eintrag in »/etc/x10.conf«, der die Ansteuerung des Kabel-Routers über den Namen »cable_router« erlaubt. Beide Router sind baugleich und arbeiten auch als DHCP-Server. Hängt sich ein Computer ins Hausnetz, erhält er so eine dynamische IP zugewiesen und weiß, an welchen DNS-Server er sich wenden muss, um Hostnamen aufzulösen. Zwei DHCP-Server, die zeitgleich den gleichen Service anbieten, lösen allerdings Chaos aus, schließlich sollen die Rechner im Kabelbetrieb nicht mehr den alten, sondern den neuen DHCP-Server mit dessen Kabel-Gateway nutzen.
DHCP-Doppel verhindern
Um das Problem zu lösen, kontaktiert das CPAN-Modul Buffalo::G54 die Konfigurationsoberfläche des Routers und fummelt mittels Screenscraping über das Modul WWW::Mechanize so lange daran herum, bis der DHCP-Server des DSL-Routers abgestellt ist. Allerdings ist dazu das Admin-Passwort des Routers erforderlich, welches das Skript »isp-switch« mit der Funktion »password_read()« aus dem CPAN-Modul Sysadm::Install beim User abfragt.
Im umgekehrten Fall, wenn es durch das Kommando »dsl« wieder zurück ans DSL geht, aktiviert das Skript den DHCP-Server des DSL-Routers wieder und dreht dem Kabel-Router per X10 den Strom ab. Da es eine Zeit dauert, bis der neue Router hochgefahren ist, wartet »isp-switch« mit »sleep()« 20 Sekunden, bevor es weitere Aktionen einleitet.
Rechner mit dynamischen Adressen holen sich nach einem Reboot oder Restart des Netzwerks eine neue IP-Adresse vom neuen DHCP-Server. Die Linux-Box mit der statischen IP-Adresse muss ebenfalls ihr Netzwerk-Initialisierungsskript neu starten, damit sie Requests an das neue und nicht mehr an das alte Gateway schickt.
Dazu lässt »isp-switch« das Linux-Startup-Skript »/etc/rc.d/init.d/network« mit dem Parameter »restart« laufen. Dafür sind Root-Rechte erforderlich, aber ein Eintrag mit »NOPASSWD« in »/etc/sudoers« für das Skript erlaubt es auch dem nicht privilegierten User »mschilli«, das Netzwerk neu zu initialisieren. Die Funktion »tap« aus dem fast unerschöpflichen Fundus des CPAN-Moduls Sysadm::Install führt das Kommando aus und schluckt dessen Ausgabe.
Mit diesen drei Maßnahmen schaltet »isp-switch« zwischen den beiden Internetanbietern hin und her. Der Internetanschluss ist auf diese Weise zwar auf einmal doppelt so teuer, dafür aber auch doppelt so zuverlässig. Als Alternative könnte man einen dritten Router einsetzen, der als Gateway arbeitet und Requests wahlweise an den Kabel- oder den DSL-Router weiterleitet. Er könnte auf einem Linux-PC oder einem unter FreeWRT laufenden Linksys-Router des Typs WRT54GL arbeiten.
Wer möchte, schreibt sich selber noch ein kleines Nagios-Plugin, das periodisch die Internetverbindung prüft und bei Problemen automatisch umschaltet – ohne dass der User überhaupt etwas mitbekommt. (jcb)
|
Listing 1: |
|---|
001 #!/usr/bin/perl -w
002 use strict;
003 use Getopt::Std;
004 use Pod::Usage;
005 use Sysadm::Install qw(:all);
006 use Config::Patch;
007 use Buffalo::G54;
008 use X10::Home;
009 use Log::Log4perl 1.13 qw(:easy);
010
011 my @isps = qw(cable dsl);
012 my($switch_to) = @ARGV;
013
014 Log::Log4perl->easy_init($INFO);
015
016 if(! defined $switch_to) {
017 pod2usage(
018 "Specify what ISP to switch to");
019 }
020
021 if(! grep { $_ eq $switch_to } @isps) {
022 pod2usage("Unknown isp, use ",
023 join(", ", @isps));
024 }
025
026 my $x10 = X10::Home->new();
027
028 my $P = password_read("Router password: ");
029
030 no strict 'refs';
031 eval { $switch_to->(); };
032 network_restart();
033
034 ###########################################
035 sub dsl {
036 ###########################################
037 gateway_patch("192.168.10.1");
038 $x10->send("bridge", "off");
039 dhcp("on");
040 }
041
042 ###########################################
043 sub cable {
044 ###########################################
045 gateway_patch("192.168.10.98");
046 $x10->send("bridge", "on");
047 dhcp("off");
048 ALWAYS "Waiting for bridge to start up";
049 sleep 20;
050 }
051
052 ###########################################
053 sub network_restart {
054 ###########################################
055 tap "sudo", "/etc/rc.d/init.d/network",
056 "restart";
057 }
058
059 ###########################################
060 sub gateway_patch {
061 ###########################################
062 my($ip) = @_;
063
064 my $patcher = Config::Patch->new(
065 file => "/etc/sysconfig/network",
066 key => "isp-switch",
067 );
068
069 if($patcher->patched()) {
070 # patched already? Remove old patch
071 $patcher->remove();
072 }
073
074 $patcher->replace(qr(^GATEWAY=.*)m,
075 "GATEWAY=$ip");
076 }
077
078 ###########################################
079 sub dhcp {
080 ###########################################
081 my($onoff) = @_;
082
083 DEBUG "Setting dhcp to $onoff";
084
085 my $b = Buffalo::G54->new();
086 DEBUG "Connecting";
087 $b->connect(password => $P);
088
089 if(defined $onoff) {
090 INFO "Setting DHCP to $onoff";
091 $b->dhcp($onoff);
092 }
093
094 INFO "DHCP is now ", $b->dhcp() ?
095 "on" : "off";
096 }
097
098 __END__
099
100 =head1 NAME
101
102 isp-switch - Cable or DSL?
103
104 =head1 SYNOPSIS
105
106 isp-switch [dsl|cable]
107
108 =head1 DESCRIPTION
109
110 isp-switch switches between Comcast cable
111 and Pacbell DSL.
112
113 =head1 AUTHOR
114
115 2007, Mike Schilli <cpan@perlmeister.com>
|
|
Der Autor |
|---|
|
|
|
Infos |
|---|
|
[1] Listings zum Artikel: [ftp://www.linux-magazin.de/pub/listings/magazin/2007/11/Perl] [2] Web Hog: [http://www.youtube.com/watch?v=ubc7zFSyEbg] [3] M. Schilli, “Heimschaltwarte”: Linux-Magazin 04/07, [https://www.linux-magazin.de/heft_abo/ausgaben/2007/04/heimschaltwarte] |









