Neuer Hotspot - pfSense
Im Folgenden wird beschrieben, wie Sie eine pfSense Firewall (Version 2.7.2, Community Version) konfigurieren und wie man diese mit unserer Hotspot-Lösung SyCes verbindet.
Für die Installation der pfSense Community Edition (pfSense CE) oder der pfSense Plus Software wird die offizielle Dokumentation Netgate Docs empfohlen.
Voraussetzungen
Um eine pfSense zu konfigurieren, benötigen Sie darauf Administratorzugriff. Dieses Tutorial zeigt die Konfiguration über die GUI-Weboberfläche der pfSense.
Für die Konfiguration benötigen Sie außerdem Informationen über die RADIUS-IP und das Secret des neuen Systems. Diese Informationen können aus SyCes🡕 ausgelesen werden.
Um den Router für SyCes einzurichten, muss der Standort, der diesen Router verwaltet, in der neuen Datenbank vorhanden sein. Für die Konfiguration werden die Mandant-ID und der für den Standort erstellte Token benötigt. Wenn Sie diese Werte auslesen möchten, benötigen Sie gültige Zugangsdaten für SyCes.
Navigieren Sie zur Standortseite des entsprechenden Mandanten und klicken Sie auf der Karte Angaben zum Standort auf den Kopieren
Button neben dem Token im Feld Token. Der Link im URL-Feld sollte wie folgt aussehen: /login/<tenant_id>/<location_id>/
.
Schritt 1: Einrichten der Netzwerkschnittstelle
Im Reiter Interfaces > Assignment
ist zunächst ein Interface zu konfigurieren. Die dazugehörige Schnittstelle des Geräts sollte mit einem Wireless Access Point (WAP) ausgestattet sein, sodass sich nach der Konfiguration die Kundengeräte über die Schnittstelle verbinden können.
Nach dem Klick auf Add
wird ein neues Interface hinzugefügt. Danach müssen die Interface-Einstellungen mit Save
gespeichert werden. Anschließend kann das Interface durch einen Klick auf dessen Namen weiter konfiguriert werden.
Aktivieren Sie die Schnittstelle und geben Sie ihr optional einen beschreibenden Namen, z. B. GUESTNET. Setzen Sie die IPv4-Konfiguration auf Static IPv4
und geben Sie eine IP-Adresse (z. B. 192.168.5.1) mit einer passenden Netzwerkmaske ein (z. B. /24).
Beispielhafte Interface-Einstellungen können dem folgenden Bild entnommen werden:
Speichern Sie die Einstellungen mit Save
und wenden Sie diese mit Apply Changes
an.
Schritt 2: DHCP-Server Konfiguration
Für das neu erstellte Interface muss nun ein DHCP-Server eingerichtet werden. Dies kann in Services > DHCP Server
erfolgen. Falls als DHCP Backend
noch ISC DHCP eingestellt ist (Werkseinstellungen), empfiehlt es sich, das DHCP Backend unter System > Advanced > Networking
auf DHCP umzustellen.
Wählen Sie im Tab Services > DHCP Server
das erstellte Interface aus.
Hier muss der DHCP-Server durch einen Klick auf das Kontrollkästchen bei Enable
aktiviert werden. Setzen Sie anschließend den DHCP-Bereich für die von Ihnen gewünschten IP-Adressen. Optional kann der DNS Server auf 1.1.1.1 (Cloudflare) und/oder 8.8.8.8 (Google) gesetzt werden.
Speichern Sie die Einstellungen mit Save
und wenden Sie diese mit Apply Changes
an.
Schritt 3: Erstellen der Firewall-Regeln
Im nächsten Schritt müssen die Firewall-Regeln erstellt werden, um den Zugriff von Endgeräten aus dem Hotspot-Netzwerk zu ermöglichen.
Navigieren Sie dafür zu Firewall > Rules
.
Wählen Sie hier das im Schritt 2 erstellte Interface aus. Fügen Sie mit dem Klick auf Add
eine neue Firewall-Regel hinzu. Diese Regel dient dazu, den Zugriff aud das Captive Portal zu ermöglichen.
Setzen Sie die Regel auf Pass
, das Protokoll auf TCP
, die Quelle auf Interface Subnetz
, das Ziel auf Interface Adresse
und geben Sie im Feld Destination port range
den Bereich 8000 to 10000
ein. Dies bedeutet, dass der Datenverkehr auf allen Ports zwischen 8000 und 10000 erlaubt wird. In der Praxis wird für das Captive Portal jedoch meist nur Port 8000 benötigt.
Optional kann die Protokollverfolgung aktiviert werden, um den Datenverkehr zu überwachen und potenzielle Probleme zu diagnostizieren.
Speichern Sie die Einstellungen mit Save
und wenden Sie diese mit Apply Changes
an.
Fügen sie nun eine weitere Regel hinzu, um den Internetzugang für Hotspot-Nutzer zu ermöglichen. Setzen Sie diese Regel auf Pass
, das Interface auf das neue Interface (z. B. GUESTNET), das Protocol auf Any
, die Quelle auf Interface subnets
und das Ziel auf Any
. Optional können sie dieser Regel eine Beschreibung hinzufügen.
Speichern Sie die Einstellungen mit Save
und wenden Sie diese mit Apply Changes
an.
Schritt 4: RADIUS-Server-Konfiguration
In diesem Abschnitt wird der RADIUS Server auf den SyCes2-Webserver eingestellt. Dafür muss dieser zunächst im User Manager
unter System > User Manager
im Reiter Authentication Servers
angelegt werden.
Klicken Sie auf Add
, um einen Authentifizierungs-Server hinzuzufügen.
Geben Sie dem Authentifizierungs-Server einen Namen und wählen Sie bei Type
den Typ RADIUS
aus. Zusätzlich müssen die RADIUS IP
und das RADIUS Secret
angegeben werden.
Diese Informationen können auf SyCes gefunden werden. Speichern Sie die Eingaben anschließend mit Save
.
Schritt 5: Einrichten des Captive Portals
Navigieren Sie zu Services > Captive Portal
, um das Captive Portal einzurichten.
Fügen Sie mit Add
eine neue Zone für das Captive Portal hinzu.
Für die Zone kann optional ein Name und eine Beschreibung eingegeben werden. Klicken Sie anschließend auf Save / Continue
.
Aktivieren Sie nun das Captive Portal, wählen Sie das GUESTNET-Interface aus und legen Sie einen Idle-Timeout fest (z.B 5 Minuten).
Scrollen Sie zum Abschnitt Authentication
, wählen Sie Use an Authentication backend
als Authentifizierungsmethode aus und wählen Sie bei Authentication Server
den im vorherigen Schritt hinzugefügten Server aus.
Scrollen Sie nun zum Abschnitt Accounting
, aktivieren Sie das Senden von RADIUS-Accounting-Paketen und wählen Sie den konfigurierten RADIUS-Server als Accounting-Server aus.
Wählen Sie Keine Updates
oder Interim
-Updates, aktivieren Sie den Idle-Timeout und speichern Sie die Einstellungen mit Save
.
Schritt 6: Testen des Captive Portals
Verbinden Sie ein Gerät mit dem in den vorherigen Schritten eingerichteten Netz und rufen Sie mit einem Browser eine Webseite auf, um das Captive Portal zu testen. Nun sollte das Captive Portal erscheinen, in dem Sie sich mit Ihren Anmeldedaten anmelden können.
Das Standard-pfSense Captive Portal sollte wie folgt aussehen:
Sollten bei der Konfiguration Ihres Routers Probleme oder unerwartetes Verhalten auftreten, kontaktieren Sie uns bitte über [email protected].
Schritt 7: Anpassung des lokalen Captive Portals (optional)
PfSense bietet eine Möglichkeit, anstatt des vordefinierten Captive Portals, eine benutzerfreundliche Portalseite hochzuladen. Dafür muss man im Reiter Services > Captive Portal
die in Schritt 5 konfigurierte Zone bearbeiten.
Stellen Sie sicher, dass das Kontrollkästchen bei Enable Captive Portal
gesetzt ist. Scrollen sie danach zur Schaltfläche Use custom captive portal page
und aktivieren Sie auch hier das Kontrollkästchen. Anschließend können Sie über Browse
eine HTML-Datei hochladen. Alternativ können Sie den unten bereitgestellten Webseiten-Code verwenden, um eine von uns vorgeschlagene Seite einzustellen. Mit View Page Contents
können Sie die gerenderte Seite anzeigen lassen.
Auch andere Seiten des Captive-Portals und die Logos können in diesem Tab angepasst werden. Im folgenden Abschnitt finden Sie ein Beispiel für eine benutzerdefinierte Anmeldeseite.
Um von einem Hotspot-Endgerät auf SyCes ein Benutzeraccount erstellen zu können, muss die URL für das SyCes-Backend vor der Authentifizierung verfügbar gemacht werden. Klicken Sie dafür in Services > Captive Portal
auf den Reiter Allowed Hostnames
und dann auf Add
, um einen neuen Eintrag hinzuzufügen. Geben Sie unter Hostname
backend.syces.de
ein. Sie können optional eine Beschreibung für den Eintrag hinzufügen. Der Rest der Einstellungen kann auf default bleiben. Speichern Sie die Einstellungen anschließend mit Save
.
Anmeldeseite
Nachfolgend finden Sie den Website-Code für die oben dargestellte angepasste Anmeldeseite. Dort finden Sie auch den Code für Seiten, die nur die Funktion Anonym oder Login nutzen. Anmeldeseiten auf Englisch finden Sie unter New Hotspot - pfSense
Dieser Code kann für die Funktionalität kopiert werden, folgende Felder müssen jedoch noch ersetzt werden:
<tenant_id>
: Ersetzen Sie dies durch Ihre Mandanten-ID in SyCes<location_identification_token>
: Ersetzen Sie dies durch den Token des konfiguriertenStandorts
in SyCes mit RoutertyppfSense
. Dies ist für dieAnonym
Funktion erforderlichconst tenant_domain = "";
: Variable setzen, um das automatische Anhängen der Mandanten-Domäne an den Benutzernamen vor der Anmeldung zu ermöglichen. Dadurch wird die Anmeldung mit "Accountname" anstelle von "Accountname@Mandantendomäne" ermöglicht. Die Domäne kann von der Mandantenseite in SyCes kopiert werden.
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>SyCes® - Hotspot</title>
<link rel="stylesheet" href="https://backend.syces.de/static/login/css/styles.css">
</head>
<body>
<div class="message-container">
<div>
<img
src="https://backend.syces.de/static/login/img/logo2.png"
alt="SyCes-Logo"
width="500"
height="139"
class="img"
/>
</div>
<div class="center window">
<h1>Benutzer-Login</h1>
<form id="default_login" action="$PORTAL_ACTION$" method="post">
<input name="redirurl" type="hidden" value="$PORTAL_REDIRURL$" />
<input name="zone" type="hidden" value="$PORTAL_ZONE$" />
<input name="accept" type="hidden" value="Continue" />
<table>
<tr>
<td><label for="pf_un">Benutzername:</label></td>
<td><input name="auth_user" type="text" id="pf_un" /></td>
</tr>
<tr>
<td><label for="pf_pd">Passwort:</label></td>
<td><input name="auth_pass" type="password" id="pf_pd" /></td>
</tr>
<tr>
<td>
<label for="tos_check_login"
>Ich akzeptiere die
<a href="https://backend.syces.de/login/<tenant_id>/tos/"
>Geschäftsbedingungen</a
>:</label
>
</td>
<td>
<label class="checkbox">
<input
type="checkbox"
name="tos"
id="tos_check_login"
onclick="handleTOSClick(this)"
/>
<span class="checkmark"></span>
</label>
</td>
</tr>
<tr>
<td></td>
<td>
<button
class="primary"
type="submit"
id="submit_btn_login"
disabled
>
Absenden
</button>
</td>
</tr>
</table>
</form>
</div>
<div class="center window">
<h1>Anonym registrieren</h1>
<form id="anon_login">
<table>
<tr>
<td>
<label for="tos_check_reg">
Ich akzeptiere die
<a href="https://backend.syces.de/login/<tenant_id>/tos/"
>Geschäftsbedingungen</a
>:
</label>
</td>
<td>
<label class="checkbox">
<input
type="checkbox"
name="tos"
id="tos_check_reg"
onclick="handleTOSClick(this)"
/>
<span class="checkmark"></span>
</label>
</td>
</tr>
<tr>
<td></td>
<td>
<button
class="primary"
type="submit"
id="submit_btn_reg"
disabled
>
Absenden
</button>
</td>
</tr>
</table>
</form>
</div>
</div>
</body>
<script>
const url =
"https://backend.syces.de/login/token_login/<location_identification_token>/";
const anon_form = document.getElementById("anon_login");
const default_form = document.getElementById("default_login");
const tos_checkbox_reg = document.getElementById("tos_check_reg");
const tos_checkbox_login = document.getElementById("tos_check_login");
const submit_button_reg = document.getElementById("submit_btn_reg");
const submit_button_login = document.getElementById("submit_btn_login");
function handleTOSClick(cb) {
if (cb.checked === true) {
tos_checkbox_reg.checked = true;
tos_checkbox_login.checked = true;
submit_button_reg.disabled = false;
submit_button_login.disabled = false;
} else {
tos_checkbox_reg.checked = false;
tos_checkbox_login.checked = false;
submit_button_reg.disabled = true;
submit_button_login.disabled = true;
}
}
function sendRequest() {
fetch(url)
.then((response) => response.json())
.then((data) => {
let field_username = document.getElementById("pf_un");
let field_password = document.getElementById("pf_pd");
field_username.value = data.login_name;
field_password.value = data.password;
default_form.submit();
})
.catch((error) => console.error(error));
}
function appendDomainIfMissing() {
const tenant_domain = "";
let form_input_user = document.getElementById("ft_un");
let username = form_input_user.value;
if (
tenant_domain !== "" &&
!username.includes("@") &&
!username.endsWith("@" + tenant_domain)
) {
form_input_user.value = username + "@" + tenant_domain;
}
}
anon_form.addEventListener("submit", function (e) {
e.preventDefault();
sendRequest();
});
default_form.addEventListener("submit", function (e) {
appendDomainIfMissing();
});
</script>
</html>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>SyCes® - Hotspot</title>
<link rel="stylesheet" href="https://backend.syces.de/static/login/css/styles.css">
</head>
<body>
<div class="message-container">
<div>
<img
src="https://backend.syces.de/static/login/img/logo2.png"
alt="SyCes-Logo"
width="500"
height="139"
class="img"
/>
</div>
<div class="center window">
<h1>Benutzer-Login</h1>
<form id="default_login" action="$PORTAL_ACTION$" method="post">
<input name="redirurl" type="hidden" value="$PORTAL_REDIRURL$" />
<input name="zone" type="hidden" value="$PORTAL_ZONE$" />
<input name="accept" type="hidden" value="Continue" />
<table>
<tr>
<td><label for="pf_un">Benutzername:</label></td>
<td><input name="auth_user" type="text" id="pf_un" /></td>
</tr>
<tr>
<td><label for="pf_pd">Passwort:</label></td>
<td><input name="auth_pass" type="password" id="pf_pd" /></td>
</tr>
<tr>
<td>
<label for="tos_check_login">
Ich akzeptiere die
<a href="https://backend.syces.de/login/<tenant_id>/tos/">
Geschäftsbedingungen
</a>:
</label>
</td>
<td>
<label class="checkbox">
<input
type="checkbox"
name="tos"
id="tos_check_login"
onclick="handleTOSClick(this)"
/>
<span class="checkmark"></span>
</label>
</td>
</tr>
<tr>
<td></td>
<td>
<button
class="primary"
type="submit"
id="submit_btn_login"
disabled
>
Absenden
</button>
</td>
</tr>
</table>
</form>
</div>
</div>
</body>
<script>
const default_form = document.getElementById("default_login");
const tos_checkbox_login = document.getElementById("tos_check_login");
const submit_button_login = document.getElementById("submit_btn_login");
function handleTOSClick(cb) {
if (cb.checked === true) {
tos_checkbox_login.checked = true;
submit_button_login.disabled = false;
} else {
tos_checkbox_login.checked = false;
submit_button_login.disabled = true;
}
}
function appendDomainIfMissing() {
const tenant_domain = "";
let form_input_user = document.getElementById("ft_un");
let username = form_input_user.value;
if (
tenant_domain !== "" &&
!username.includes("@") &&
!username.endsWith("@" + tenant_domain)
) {
form_input_user.value = username + "@" + tenant_domain;
}
}
default_form.addEventListener("submit", function (e) {
appendDomainIfMissing();
});
</script>
</html>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>SyCes® - Hotspot</title>
<link rel="stylesheet" href="https://backend.syces.de/static/login/css/styles.css">
</head>
<body>
<div class="message-container">
<div>
<img
src="https://backend.syces.de/static/login/img/logo2.png"
alt="SyCes-Logo"
width="500"
height="139"
class="img"
/>
</div>
<div class="center window">
<h1>Anonym registrieren</h1>
<form id="anon_login">
<table>
<tr>
<td>
<label for="tos_check_reg">
Ich akzeptiere die
<a href="https://backend.syces.de/login/<tenant_id>/tos/">
Geschäftsbedingungen
</a>:
</label>
</td>
<td>
<label class="checkbox">
<input
type="checkbox"
name="tos"
id="tos_check_reg"
onclick="handleTOSClick(this)"
/>
<span class="checkmark"></span>
</label>
</td>
</tr>
<tr>
<td></td>
<td>
<button
class="primary"
type="submit"
id="submit_btn_reg"
disabled
>
Absenden
</button>
</td>
</tr>
</table>
</form>
<form
id="default_login"
action="$PORTAL_ACTION$"
method="post"
style="display:none"
>
<input name="redirurl" type="hidden" value="$PORTAL_REDIRURL$" />
<input name="zone" type="hidden" value="$PORTAL_ZONE$" />
<input name="accept" type="hidden" value="Continue" />
<h1>
Login
</h1>
<table>
<tr>
<td><label for="pf_un">Username:</label></td>
<td><input name="auth_user" type="text" id="pf_un" /></td>
</tr>
<tr>
<td><label for="pf_pd">Password:</label></td>
<td><input name="auth_pass" type="password" id="pf_pd" /></td>
</tr>
<tr>
<td>
<label for="tos_check_login"
>I agree to the
<a href="https://backend.syces.de/login/<tenant_id>/tos/"
>Terms and conditions</a
>:</label
>
</td>
<td>
<label class="checkbox">
<input
type="checkbox"
name="tos"
id="tos_check_login"
onclick="handleTOSClick(this)"
/>
<span class="checkmark"></span>
</label>
</td>
</tr>
<tr>
<td></td>
<td>
<button
class="primary"
type="submit"
id="submit_btn_login"
disabled
>
Submit
</button>
</td>
</tr>
</table>
</form>
</div>
</div>
</body>
<script>
const url =
"https://backend.syces.de/login/token_login/<location_identification_token>/";
const anon_form = document.getElementById("anon_login");
const default_form = document.getElementById("default_login");
const tos_checkbox_reg = document.getElementById("tos_check_reg");
const tos_checkbox_login = document.getElementById("tos_check_login");
const submit_button_reg = document.getElementById("submit_btn_reg");
const submit_button_login = document.getElementById("submit_btn_login");
function handleTOSClick(cb) {
if (cb.checked === true) {
tos_checkbox_reg.checked = true;
tos_checkbox_login.checked = true;
submit_button_reg.disabled = false;
submit_button_login.disabled = false;
} else {
tos_checkbox_reg.checked = false;
tos_checkbox_login.checked = false;
submit_button_reg.disabled = true;
submit_button_login.disabled = true;
}
}
function sendRequest() {
fetch(url)
.then(response => response.json())
.then(data => {
let field_username = document.getElementById("pf_un");
let field_password = document.getElementById("pf_pd");
field_username.value = data.login_name;
field_password.value = data.password;
default_form.submit();
}
)
.catch(error => console.error(error));
}
anon_form.addEventListener("submit", function(e) {
e.preventDefault();
sendRequest();
});
</script>
</html>
Mit Restore Default Page
können Sie die Einstellungen wieder auf das voreingestellte Captive Portal zurücksetzen.