Anmeldebildschirm ('splash screen') nachrüsten
Motivation
Die sog. "alte Firmware" (letzter Release 1.9.2013) brachte standardmäßig einen Anmeldebildschirm ('splash screen') mit. Die sog. "neue Firmware" hatte dann keinen mehr, was zu heftigen Diskussionen innerhalb des Vereins geführt hatte. Die Argumente der Befürworter des Anmeldebildschirms waren für mich nachvollziehbar, die der Gegner wirkten auf mich ein wenig vorgeschoben. Für einen Verein sollte es wichtig sein, alle Mitglieder mitzunehmen. Letztmalig habe ich diese Diskussion auf dem Freifunktag im März 2014 miterlebt, was mich damals zu der Aussage brachte: "Wenn die Entwickler das nicht machen wollen, dann werde ich eine Lösung zum Nachrüsten finden." Nun, der Freifunktag ist jetzt schon etwas länger her und ich habe vom Anmeldebildschirm nichts mehr gehört. Ich weiß nicht, ob irgendwo noch andere Freifunker an der Wiedereinführung des Anmeldebildschirms arbeiten. Wenn ja, dann wäre es schön einmal zu sehen, wie Ihr es gemacht habt.
(uwho)
Und hier meine Lösung:
Basis war die "neue Firmware" für Rheinufer (Release 25.2.2014). Der Routertyp spielt keine Rolle. Anfänglich war es mein Ziel, das alte Anmeldeverfahren bloß wieder gängig zu machen. Leider habe ich es nicht geschafft. Das liegt vor allem daran, daß die "neue Firmware" überwiegend auf ebtables und nicht auf iptables setzt und im Layer 2 einiges anders läuft. Kurz gesagt, ich habe das Anmeldeverfahren jetzt auch mit ebtables realisiert und so läuft's.
Fühlt Euch frei hier Verbesserungen einzubringen!
Jetzt geht es los!
1. Wir legen von der Komandozeile des Routers aus die Datei /etc/mksplash neu an
vi /etc/mksplash
und kopieren als Dateiinhalt die folgenden Zeilen hinein.
ebtables -t broute -F BROUTING ebtables -t broute -A BROUTING --mark ! 1/1 -p IPV4 --ip-protocol 6 --ip-destination-port 80 -j redirect --redirect-target ACCEPT
Speichern!
Danach wird die Datei noch mit
chmod 777 /etc/mksplash
ausführbar gemacht.
2. Anschließend tragen wir unsere neu erstellte Datei in /etc/rc.local ein, damit sie bei jedem Systemstart ausgeführt wird.
Dazu öffnen wir die Datei mit
vi /etc/rc.local
und schreiben den Dateinamen /etc/mksplash hinein.
# Put your custom commands here that should be executed once # the system init finished. By default this file does nothing. /etc/mksplash exit 0
Speichern und fertig.
3. Wir öffnen die Datei /etc/crontabs/root mit
vi /etc/crontabs/root
und tragen dort als letzte Zeile 0 3 * * * /etc/mksplash ein. Speichern! Bei mir sieht die Datei danach so aus:
*/3 * * * * /usr/sbin/fastd_watchdog # fastd watchdog 0 * * * * /usr/sbin/owm-update update_map # owm update */1 * * * * /usr/sbin/splash_sync queen # splash sync 0 3 * * * /etc/mksplash
Anschließend sorgen wir noch dafür, daß cron auch wirklich läuft.
/etc/init.d/cron enable
/etc/init.d/cron restart
4. Damit die Umleitung von Webseiten zuverlässig immer auf die Datei /index.html führt, müssen wir noch eine Konfigurationseinstellung des Routerwebservers (uhttpd) ergänzen. Dort muß die Fehlerseite ("Fehler 404") auf /index.html umgeleitet werden. Die Option dazu ist bei der verwendeten Firmware noch nicht eingetragen und wird neu angelegt.
Wir öffnen die Datei /etc/config/uhttpd und fügen für 'uhttpd service' die Option 'error_page /index.html' ein. Das sieht z.B. dann so aus: (Dateiausschnitt)
. . . # service instance config uhttpd service option home /www/service option listen_http 80 option error_page /index.html # Reject requests from RFC1918 IP addresses # directed to the servers public IP(s). . . .
Speichern!
Ab jetzt sollte jeder Versuch eine unverschlüsselte Webseite aufzurufen auf dem altbekannten Anmeldebildschirm landen. Das Anmelden selbst funktioniert aber noch nicht.
5. Ein Problem ist noch zu lösen: Der Anmeldebildschirm zeigt die Meldung, daß diese Wolke zz. kein Internet hat. Das liegt daran, daß das alte Verfahren zur Überprüfung des Internetstatus nicht mehr funktioniert. Hier ist also noch eine Baustelle! Ich habe vorerst auf diese Überprüfung verzichtet und den Inhalt von /www/service/cgi-bin/online.json wie folgt geändert.
vi /www/service/cgi-bin/online.json
Dateiinhalt gegen diesen hier austauschen:
#!/bin/sh -e . /www/service/cgi-bin/common.sh echo -e "Status: 200 OK\r Content-Type: application/json\r \r #$(have_internet && echo true || echo false)" $(echo true && echo true)"
Speichern!
6. Jetzt fehlt nur noch das eigentliche Verfahren zur Anmeldung. Das habe ich in der Datei /www/service/cgi-bin/splash_click.html untergebracht. Für jeden Client wird dort eine ebtables-Regel, die Datenpakete auf Port 80 von seiner MAC-Adresse zukünftig bis auf Widerruf durchläßt, erzeugt. Weiterhin erfolgt hier, wie gehabt, die Weiterleitung auf die Infoseite. Zz. ist hier die Freifunk Rheinland e.V. Webseite eingestellt.
Wir öffnen die bestehende Datei mit
vi /www/service/cgi-bin/splash_click.html
und tauschen den gesamten Inhalt gegen den Folgenden aus.
#!/bin/sh -e . $IPKG_INSTROOT/etc/functions.sh #. /etc/splash.sh . /www/service/cgi-bin/common.sh # decode request params URL="$(sed -n 's/^.*target_url=\([^&]*\).*$/\1/p' | urldecode || true)" #URL="" USER_MAC=$(grep ^$REMOTE_HOST </proc/net/arp | awk 'BEGIN { FS = " " } ; { print $4 }') [ -n "$USER_MAC" ] ebtables -t broute -I BROUTING -s $USER_MAC -p IPV4 --ip-protocol 6 --ip-destination-port 80 -j mark --set-mark 1 --mark-target CONTINUE echo -en "Status: 200 OK\r Content-Type: text/html\r \r " sed "s/targeturl/$(echo "$URL")/g" iframe.html exit 0 EOF
Speichern!
7. Da ein Verfahren zum URL-dekodieren nicht mehr wie in der "alten Firmware" funktioniert, habe ich die Dateien /www/service/index.html und /www/service/iframe.html anpassen müssen. Das URL-dekodieren ist jetzt über Javascript in diesen beiden Dateien gelöst. (Randeffekt: Rechenzeit auf dem Router eingespart.)
Wir öffnen die bestehende Datei mit
vi /www/service/index.html
und tauschen den gesamten Inhalt gegen den Folgenden aus.
<html lang="de"> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Freifunk Rheinland</title> <link rel="stylesheet" href="/css/bootstrap.min.css"> <link rel="stylesheet" href="/css/ffj.css"> </head> <body> <div class="navbar"><div class="navbar-inner"><div class="container-fluid"> <a class="brand" href="/">Freifunk Rheinland </a> <div class="nav-collapse hidden" id="nav"><ul class="nav"> <li><a href="/settings.html"><i class="icon-cog icon-white"></i> Einstellungen</a></li> </ul></div> </div></div></div> <div class="container-fluid"> <div class="hero-unit"> <img class="pull-right" src="/img/logo.png"> <h1><a id="content" name="content"></a>Willkommen!</h1> <p>Du bist jetzt mit dem freien Funknetz <a href="http://www.freifunk-rheinland.net">Freifunk Rheinland</a> verbunden.</p> <p>Wir sind ein experimentelles Gemeinschaftsnetzwerk, aber kein Internetanbieter.</p> <p><a href="http://www.freifunk-rheinland.net" class="btn btn-success btn-large">Mehr lernen</a></p> </div> <div class="alert alert-error hidden" id="offline"> <p><b>Das Internet ist in dieser Wolke vorrübergehend nicht verfügbar.</b><span class="hidden" id="local_services"> Die <a href="/services.html"><i class="icon-home"></i> lokalen Dienste</a> der Wolke stehen weiter zur Verfügung.</span></p> </div> <div class="row"> <div class="span4"> <h2>Lokales Netzwerk</h2> <p>Im Freifunknetz kann <emph>jeder</emph> Dienste anbieten: alle teilnehmenden Computer können direkt miteinander kommunizieren.<span class="hidden" id="settings"> Unter <a href="/settings.html" style="white-space: nowrap"><i class="icon-cog"></i> Einstellungen</a> kannst du festlegen, wie du das Netzwerk nutzen möchtest und Resourcen mit anderen Freifunkern teilen.</span></p> </div> <div class="span4"> <h2>Internet</h2> <p>Ein Zugang ins Internet ist möglich, da einige Freifunker ihre privaten Internetzugänge zur Verfügung stellen. Diese Zugänge müssen sich hier alle teilen. Bitte sei Dir dessen bewusst und verhalte Dich dementsprechend: </p> <ul> <li><strong>keine Filesharing-Programme</strong></li> <li><strong>keine unnötigen Downloads oder Streams</strong></li> <li><strong>keine illegalen Aktivitäten</strong></li> </ul> <p>Mit einem Klick auf <em>Akzeptieren</em> kannst du für 1 Stunde unser Netz verwenden. Dann wirst du erneut aufgefordet, diese Bedingungen zu akzeptieren.</p> <form name="akzept" action="/cgi-bin/splash_click.html" method="POST"> <input type="text" name="username" value="Freifunk" style="display:none"> <input type="password" name="password" value="Hotspot" style="display:none"> <input type="hidden" name="target_url" value="targeturl"/> <input type="submit" class="btn btn-primary" value="Akzeptieren" /> <a class="btn" href="/services.html">Ablehnen</a> </form> </div> <script language="javascript"> <!-- document.akzept.target_url.value = window.location.href; //--> </script> <div class="span4"> <h2>Mitmachen</h2> <p>Wenn Du unsere Idee gut findest und das Netz regelmässig benutzt, dann bitten wir Dich um Unterstützung: </p> <ul> <li><a href="http://www.freifunk-rheinland.net/">Werde selbst Freifunker</a>. Dazu muss man nur einen handelsüblichen WLAN-Router ins Fensterbrett stellen.</a></li> <li><a href="http://www.freifunk-rheinland.net/">Spende</a> ein paar Euro, damit wir unser Netz weiter betreiben und ausbauen können.</li> <li>Wenn Du selbst privat genutzte WLAN-Geräte betreibst nutze dafür bitte andere Kanäle als wir.</li> </ul> </div> </div> </div> <script src="/js/jquery.min.js"></script> <script src="/js/parse_services.js"></script> <script src="/js/bootstrap.min.js" defer></script> <script> $.getJSON("cgi-bin/online.json", function(haveInternet) { if(!haveInternet) $('#offline').removeClass('hidden'); }); $.getJSON("cgi-bin/client_net.json", function(clientInfo) { if(clientInfo.wired) { $('#settings').removeClass('hidden'); $('#nav').removeClass('hidden'); } }); $.when( $.getJSON('/cgi-bin/services.json'), $.ajax({url: '/js/parse_services.js', dataType: 'script', cache: true}) ).done(function(res) { services(res[0]).drawLine($('#service-ul')); $('p#service-loading').remove(); if (res[0].length > 0) $('#local_services').removeClass('hidden'); }); </script> </body> </html>
und wir öffnen die bestehende Datei mit
vi /www/service/iframe.html
und tauschen den gesamten Inhalt gegen den Folgenden aus.
<!doctype html> <html class="no-js" lang="de"> <head> <meta charset="utf-8"> <title>Freifunk Rheinland Redirect</title> </head> <body style="margin:0px;"> <div style="width:100%;padding:5px 0;background-color:#FFCB05;text-align:center;border-bottom:3px solid #E0256C"> <a style="color:#000;font-weight:bold;text-decoration:none" id="targeturl" href="targeturl">Weiter zur gesuchten Seite >>></a></div> <iframe id="frame" src="http://www.freifunk-rheinland.net/" width="99%"></iframe> <script> function pageY(elem) { return elem.offsetParent ? (elem.offsetTop + pageY(elem.offsetParent)) : elem.offsetTop; } function resizeIframe() { var height = document.documentElement.clientHeight; height -= pageY(document.getElementById('frame')) + 20 ; height = (height < 0) ? 0 : height; document.getElementById('frame').style.height = height + 'px'; } window.onresize = resizeIframe; resizeIframe(); </script> <script language="javascript"> var link = document.getElementById("targeturl"); var linkarr = decodeURIComponent( document.getElementById("targeturl").href ).split("//"); link.setAttribute( "href" , "http://" + linkarr[2] ); </script> </body> </html>
Speichern und fertig! Nach einem Reboot sollte der Freifunkrouter über eine Anmeldeseite ('splash screen') verfügen.
Ich habe diese Konfiguration bisher ausschließlich mit einer allein betriebenen Queen ohne Drohnen getestet. Wie sich das ganze mit Drohnen verhält, weiß ich noch gar nicht. Ich bin noch in der Bastelphase. Ich freue mich über Jeden, der mitbastelt.