Zo maak je een Captive Portal voor je bedrijf met een Raspberry Pi Pico W
Als je een bedrijf runt, dan kan het opzetten van een captive portal een belangrijk hulpmiddel zijn voor je netwerk. In dit artikel laat ik je zien hoe je een captive portal kunt maken met een Raspberry Pi Pico W.
Een captive portal biedt een veilige manier om WiFi aan te bieden aan gasten, klanten of cliënten. Het vereist dat gebruikers inloggen of zich authenticeren voordat ze het internet kunnen gebruiken.
Denk aan hoe het werkt op een vliegveld of bij een koffieshopketen.
Met een captive portal kun je je netwerk zowel controleren als monitoren. Het biedt ook de mogelijkheid om je merk uit te breiden. Je kunt de captive portal aanpassen met je logo.
Wat doet een captive portal?
Wanneer je inlogt op een Pico W die als toegangspunt fungeert, krijg je geen webpagina te zien. Met een captive portal geïmplementeerd, zal er een webpagina verschijnen zodra je WiFi verbinding maakt met je hotspot.
Daarom kun je de stap van verbinding maken met het netwerk overslaan, waarna je naar je browser gaat en handmatig een IP-adres intypt.
Het is op dit punt dat ik het volgende moet vermelden Kevin McAleer voor zijn video die als basis dient voor deze tutorial.
Het creëren van een captive portal met een Pico W is een fantastische mogelijkheid. Niet alleen is een captive portal noodzakelijk voor het netwerk van je bedrijf. A Raspberry Pi Pico W is hooguit een paar euro, dus het is ook een zeer kosteneffectieve oplossing.
Doelen voor deze tutorial
Kevin's tutorial laat alleen zien hoe je een captive portal activeert op een Apple apparaat.
Deze tutorial gaat verder door uit te leggen hoe je de pop-up captive portal activeert op Android, Windows en Apple apparaten.
We gebruiken Phew van Pimoroni, een bibliotheek voor een Pico W webserver. Het is een beetje wat Express is voor NodeJS.
Ik heb mijn code op vier apparaten getest:
- Apple iPhone 8 met OS versie 15.4.1 ✔️
- Amazon Fire-tablet met Android 9 ✔️
- Windows 10 PC ✔️
- Google Pixel 6 met Android 13 ✔️
- Samsung Note 9 met Android 10 ❌
De code werkte op allemaal, behalve op mijn Samsung Note 9, en ik heb het niet getest op Linux.
Gebruiksgevallen?
Dit is een lastige.
In eerste instantie wilde ik iets maken dat iemand zou Rickrollen, maar ik realiseerde me dat ik geen YouTube-video kan insluiten omdat er geen internetverbinding is omdat de Pico W geen internetverbinding heeft.
Vervolgens wilde ik een draagbaar digitaal visitekaartje maken waarop mensen verbinding kunnen maken met de Pico W en een paar links kunnen zien. Een beetje zoals die Instagram link-in-bio mappen. Nogmaals, geen internet...
Ik denk dat een van de grootste voordelen van de Pico W is dat je er componenten draadloos mee kunt bedienen.
In onze mega-handleiding voor componentenheb ik het gehad over hoe je het gebruik van fysieke knoppen en draaiknoppen kunt vermijden om LED's, zoemers en servo's te bedienen door in plaats daarvan een webinterface te gebruiken. Als je deze implementeert in je captive portaal, kun je je apparaten eenvoudiger bedienen omdat je niet elke keer hoeft in te loggen op 192.168.4.1 als je naar een bedieningspaneel wilt gaan.
Natuurlijk hoor ik graag wat jij denkt dat er mogelijk is met een captive portal. Laat hieronder een reactie achter!
De pop-up activeren
Wanneer je verbinding maakt met een draadloos netwerk, pingen Windows-, Android- en Apple-apparaten verschillende websites.
Elk van deze pings vereist een antwoord. Het juiste antwoord ontgrendelt de pop-up. Dit is hoe het gesprek verloopt, afhankelijk van het besturingssysteem:
Microsoft Windows 10
MS: "Psst... is /connecttest.txt daar?"
Pico W: "Ja, 200“.
MS: "Oké, breng me naar /redirect“
Pico W: "Eh, ja, 302ga naar http://pico.wireless/ waar we u van dienst zijn index.html“.
Amazon Fire Android 9
AMZ: "Psst... waar is /genereren_204 daar?"
Pico W: "Standaard zou ik zeggen 204maar ik weet dat wat je echt wilt is 302 doorverwijzen naar http://pico.wireless/ (die index.html aka je captive pagina weergeeft)".
Apple iPhone 8 met iOS 15
iPhone: "Ik ben cool en zo, dus ik ben gewoon op zoek naar het bestand". /hotspot-detect.html“
Pico W: "Ja, ga naar http://pico.wireless/“
iPhone: "Hmm, lijkt heel anders dan waar ik om vroeg, maar ik vertrouw je dus ik ga er nu heen."
Responscode 200: "OK", 204: "Geen inhoud", 302: "Gevonden".
Zoals je kunt zien, vragen verschillende apparaten om verschillende routes en verschillende webpagina's. En als je correct antwoordt, activeren ze de pop-up.
Hier volgt een overzicht van wat je nodig hebt om te verzenden en te ontvangen:
Windows 10
URL | Initiërende reactie |
www.msftconnecttest.com/ncsi.txt | 200 OK |
www.msftconnecttest.com/connecttest.txt | 200 OK |
www.msftconnecttest.com/redirect | 302 doorsturen (naar captive portaal, bijv. index.html) |
Android 9, 10
URL | Initiërende reactie |
connectiviteitscontrole.gstatic.com/genereren_204 | 302 doorsturen (naar gesloten portaalpagina) |
Andere Android-versies kunnen andere URL's opvragen. Ik geloof dat de nieuwere Android-versies /genereren_204 als noodoplossing.
Hier zijn twee bronnen voor oudere Androids:
https://lemariva.com/blog/2017/11/white-hacking-wemos-captive-portal-using-micropython
iOS 15
URL | Initiërende reactie |
captive.apple.com/hotspot-detect.html | 200 OK (antwoorden met een webpagina) |
Mijn Samsung Note 9 met Android 10 was het moeilijkst te kraken. Ogenschijnlijk zou je de typische Android-patronen volgen, maar helaas, niets werkte!
Het lukte me wel om de "Sign-in required" prompt te krijgen, maar alleen nadat ik de DNS had gewijzigd naar een publiek LAN IP (een IP buiten het '10.0.0.0/8, 172.16.0.0/12, of 192.168.0.0/16' bereik). Zie dit commentaar op Stack Exchange.
Maar door het bovenstaande te doen, werd de gesloten portal van elk ander apparaat verbroken...
Pimoroni Phew-bibliotheek voor Pico W gesloten portaal
Pimoroni's Oef bibliotheek maakt het veel gemakkelijker om een gesloten portaal te maken omdat zij al het zware werk hebben gedaan.
Eerst moet je de bibliotheek downloaden. Ik heb de versie 0.0.3 gebruikt die hier kan worden gedownload.
Pak vervolgens de bestanden uit en upload de map met de naam phew op je Pico W. Persoonlijk heb ik de Thonny IDE gebruikt en je kunt Lees hier hoe u bestanden uploadt.
Laten we de hotspot pop-up coderen!
Dus laat ik beginnen met main.py:
from phew import logging, server, access_point, dns
from phew.template import render_template
from phew.server import redirect
DOMAIN = "pico.wireless" # This is the address that is shown on the Captive Portal
@server.route("/", methods=['GET'])
def index(request):
""" Render the Index page"""
if request.method == 'GET':
logging.debug("Get request")
return render_template("index.html")
# microsoft windows redirects
@server.route("/ncsi.txt", methods=["GET"])
def hotspot(request):
print(request)
print("ncsi.txt")
return "", 200
@server.route("/connecttest.txt", methods=["GET"])
def hotspot(request):
print(request)
print("connecttest.txt")
return "", 200
@server.route("/redirect", methods=["GET"])
def hotspot(request):
print(request)
print("****************ms redir*********************")
return redirect(f"http://{DOMAIN}/", 302)
# android redirects
@server.route("/generate_204", methods=["GET"])
def hotspot(request):
print(request)
print("******generate_204********")
return redirect(f"http://{DOMAIN}/", 302)
# apple redir
@server.route("/hotspot-detect.html", methods=["GET"])
def hotspot(request):
print(request)
""" Redirect to the Index Page """
return render_template("index.html")
@server.catchall()
def catch_all(request):
print("***************CATCHALL***********************\n" + str(request))
return redirect("http://" + DOMAIN + "/")
# Set to Accesspoint mode
# Change this to whatever Wifi SSID you wish
ap = access_point("Pico W Captive")
ip = ap.ifconfig()[0]
# Grab the IP address and store it
logging.info(f"starting DNS server on {ip}")
# # Catch all requests and reroute them
dns.run_catchall(ip)
server.run() # Run the server
logging.info("Webserver Started")
Om duidelijk te zijn, ik heb deze code van Kevin McAleer aangepast voor onze doeleinden. Als je Kevin's uitgebreide uitleg over hoe het werkt wilt bekijken, bekijk deze YouTube-video.
Maar laat me kort de verschillende secties bespreken.
Er zijn drie secties met opmerkingen "#android redirects", "#apple redir" en "# microsoft windows redirects". Deze secties behandelen de tests die elk besturingssysteem uitvoert en antwoorden met het juiste antwoord.
Aan het einde van de reacties worden ze doorgestuurd naar http://{DOMAIN}/, behalve voor de Apple route (omdat Kevin het zo geschreven heeft en als het niet kapot is...).
Doorverwijzen naar DOMAIN, opgegeven als "pico.wireless" zou ons een minder lelijke URL geven.
Dus in plaats van "www.msftconnecttest.com" in de adresbalk, zien we "pico.wireless" in de adresbalk. Dit is natuurlijk iets om in gedachten te houden voor de captive portal van je bedrijf.
Pimoroni Phew vermindert de code die je moet schrijven
Het mooie van Phew is dat je aanzienlijk minder code schrijft dan wanneer je het vanaf nul zou moeten schrijven.
Als je bijvoorbeeld de SoftAP op de Pico W wilt starten, zou je code schrijven die er ongeveer zo uitziet:
import network
# start up network in access point mode
wlan = network.WLAN(network.AP_IF)
wlan.config(essid=ssid)
if password:
wlan.config(password=password)
else:
wlan.config(security=0) # disable password
wlan.active(True)
return wlan
Met Pimoroni's Phew wordt je last gereduceerd tot:
ap = access_point("Pico W Captive")
Naar mijn mening is het beste deel de dns.run_catchall() functie die een heleboel belangrijke, maar ingewikkelde code uitvoert:
import uasyncio, usocket
from . import logging
async def _handler(socket, ip_address):
while True:
try:
yield uasyncio.core._io_queue.queue_read(socket)
request, client = socket.recvfrom(256)
response = request[:2] # request id
response += b"\x81\x80" # response flags
response += request[4:6] + request[4:6] # qd/an count
response += b"\x00\x00\x00\x00" # ns/ar count
response += request[12:] # origional request body
response += b"\xC0\x0C" # pointer to domain name at byte 12
response += b"\x00\x01\x00\x01" # type and class (A record / IN class)
response += b"\x00\x00\x00\x3C" # time to live 60 seconds
response += b"\x00\x04" # response length (4 bytes = 1 ipv4 address)
response += bytes(map(int, ip_address.split("."))) # ip address parts
socket.sendto(response, client)
except Exception as e:
logging.error(e)
def run_catchall(ip_address, port=53):
logging.info("> starting catch all dns server on port {}".format(port))
_socket = usocket.socket(usocket.AF_INET, usocket.SOCK_DGRAM)
_socket.setblocking(False)
_socket.setsockopt(usocket.SOL_SOCKET, usocket.SO_REUSEADDR, 1)
_socket.bind(usocket.getaddrinfo(ip_address, port, 0, usocket.SOCK_DGRAM)[0][-1])
loop = uasyncio.get_event_loop()
loop.create_task(_handler(_socket, ip_address))
Phew maakt het ook gemakkelijk om routes te schrijven. Je hoeft alleen maar zoiets als dit te schrijven:
@server.route("/[your_route_here]", methods=["GET"])
def your_function_here(request):
pass
@server.catchall()
def catchall(request):
pass
Zoals je hierboven kunt zien, is het maken van een route super eenvoudig. Het enige wat je hoeft te doen is @server.routeen geef zowel een route als de methoden door. Definieer dan hieronder een functie met de verzoek parameter.
Tot slot is er de @server.catchall() functie, die alle routes afhandelt die je niet hebt toegewezen.
Oef, dat maakt het supergemakkelijk!
Bezoek de Github repo van Phew hier.
index.html
Het is een heel eenvoudig proof-of-concept index.html die een <h1> met de tekst "Pico W Captive Portal".
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Pico W Captive Portal</title>
</head>
<body>
<h1>Pico W Captive Portal</h1>
</body>
</html>
Conclusie
Dat was het dan. Dat is alles wat je moet weten om een captive portaal op een Pico W in te stellen voor je bedrijf.
Als je vragen hebt, aarzel dan niet om het ons te laten weten in de reacties hieronder!
Een goede vervanging voor een piratenbox (hoewel zonder chatfunctie en upload).
Dit is precies wat ik zocht!
De meeste dingen werken, maar de website verschijnt niet vanzelf en in plaats daarvan zie ik een foutmelding:
2023-03-31 12:02:35 [info / 160kB] > GET /generate_204 (302 Gevonden) [236ms]
Taakuitzondering niet opgehaald
toekomst: coro=
Traceback (meest recente oproep laatst):
Bestand "uasyncio/core.py", regel 1, in run_until_complete
Bestand "phew/server.py", regel 242, in _handle_request
Bestand "phew/server.py", regel 161, in _parse_headers
ValueError: meer dan 1 waarden nodig om uit te pakken
Ik vraag me af of het misschien iets te maken heeft met het feit dat mijn oude telefoon nog steeds Android 6 is.
Hoe kun je die code bewerken om de HTML-code in het programma op te nemen? Ik heb het geprobeerd en het werkte niet voor mij.
Ik vind het programmaverloop erg verwarrend.
Hallo, ik help je graag! Kun je je probleem gedetailleerder beschrijven en me vertellen welk apparaat je gebruikt voor de captive portal?
Hallo! Ik probeer dit uit te voeren op een Pico W. Het AP start op, de DNS start op, de webserver start ofwel nooit op ofwel duurt het eenoooooo lange tijd (meerdere minuten) om op te starten. Hebben jullie ideeën/aanwijzingen/suggesties waarom dit zo is? Bedankt!
Kunt u me alstublieft helpen begrijpen welke regel code de captive portal op de browser van de client afdwingt/auto-opent na een succesvolle verbinding met de hotspot? Het lijkt niets automatisch te openen. Ik maak verbinding vanaf mijn laptop.
Bedankt voor de goede beschrijving.
Ik wil graag een tweede of zelfs derde SSID toevoegen aan hetzelfde AP. Is er een manier om dat te doen met Phew?
Iemand een idee?
Nee, je zou voor elke ssid een raspberry pi pico moeten gebruiken.