Come creare un portale vincolato per la vostra azienda con un Raspberry Pi Pico W

configurazione di raspberry pi pico w captive portal

Se gestite un'azienda, la creazione di un captive portal può essere uno strumento importante per la vostra rete. In questo articolo, quindi, vi mostrerò come creare un captive portal con un Raspberry Pi Pico W.

Un captive portal è un modo sicuro per offrire il WiFi a ospiti, clienti o clienti. Richiede che gli utenti effettuino il login o si autentichino prima di poter utilizzare Internet.

Pensate a come funziona in un aeroporto o in una catena di caffetterie.

Un captive portal consente di controllare e monitorare la rete. Inoltre, offre l'opportunità di estendere il proprio marchio. È possibile personalizzare il captive portal con il proprio logo.

Cosa fa un portale vincolato?

Quando ci si collega a un Pico W che funge da punto di accesso, non viene visualizzata una pagina web. Con l'implementazione di un captive portal, una volta che il WiFi si connette all'hotspot, viene visualizzata una pagina web.

Pertanto, è possibile saltare la fase di connessione alla rete, quindi andare sul browser e digitare manualmente un indirizzo IP.

È a questo punto che devo riconoscere che Kevin McAleer per il suo video che funge da base per questa esercitazione.

La creazione di un portale vincolato con un Pico W è un'opportunità fantastica. Non solo un portale vincolato è indispensabile per la rete aziendale. A Raspberry Pi Pico W è di pochi euro al massimo, quindi è anche una soluzione estremamente conveniente.

Obiettivi di questa esercitazione

L'esercitazione di Kevin mostra solo come attivare un captive portal su un dispositivo Apple.

Questa esercitazione spiegherà come attivare il pop-up captive portal sui dispositivi Android, Windows e Apple.

Utilizzeremo Phew di Pimoroni, che è una libreria per un server Web Pico W. È un po' come Express per NodeJS.

Ho testato il mio codice su quattro dispositivi:

  • Apple iPhone 8 con versione OS 15.4.1 ✔️
  • Tablet Amazon Fire con Android 9 ✔️
  • PC Windows 10 ✔️
  • Google Pixel 6 con Android 13 ✔️
  • Samsung Note 9 con Android 10 ❌

Il codice ha funzionato su tutti, tranne che sul mio Samsung Note 9, e non l'ho testato su Linux.

Casi d'uso?

Questa è un po' difficile.

Inizialmente volevo creare qualcosa che facesse da Rickroll a qualcuno, ma mi sono reso conto che non potevo incorporare un video di YouTube perché non ci sarebbe stata alcuna connessione a Internet, dato che il Pico W non ha una connessione a Internet.

Poi, ho voluto creare un biglietto da visita digitale portatile in cui le persone si collegassero al Pico W e vedessero alcuni link. Un po' come le directory di Instagram con i link nelle biografie. Anche in questo caso, niente internet...

Suppongo che uno dei maggiori vantaggi del Pico W sia la possibilità di controllare i componenti in modalità wireless.

In il nostro mega-tutorial sui componentiIn questo articolo ho parlato di come si possa evitare l'uso di pulsanti e manopole per controllare LED, buzzer e servocomandi, utilizzando invece un'interfaccia web. Se implementate queste interfacce nel vostro captive portal, potrete controllare più facilmente i vostri dispositivi senza dovervi collegare a 192.168.4.1 ogni volta che volete accedere a un pannello di controllo.

Naturalmente, mi piacerebbe sapere cosa pensate sia possibile fare con un portale vincolato. Lasciate un commento qui sotto!

Come attivare il pop-up

Quando ci si connette a una rete wireless, i dispositivi Windows, Android e Apple eseguono il ping di siti web diversi.

Ognuno di questi ping richiede una risposta. La risposta giusta sblocca il pop-up. Ecco come si svolge la conversazione a seconda del sistema operativo:

Microsoft Windows 10

MS: "Psst... è /connecttest.txt lì?"

Pico W: "Sì, 200“.

MS: "OK, portami a /redirect

Pico W: "Sì, 302, vai a http://pico.wireless/ dove vi serviremo indice.html“.

Amazon Fire Android 9

AMZ: "Psst... dov'è /generazione_204 lì?"

Pico W: "Per impostazione predefinita, stavo per dire 204ma so che quello che vuoi veramente è 302 reindirizzare a http://pico.wireless/ (che rende index.html, alias la pagina vincolata)".

Apple iPhone 8 con iOS 15

iPhone: "Sono un figo e tutto il resto, quindi sto solo cercando il file /rilevazione degli hotspot.html

Pico W: "Sì, vai a http://pico.wireless/

iPhone: "Hmm, sembra completamente diverso da quello che ho chiesto, ma mi fido di te, quindi ora ci andrò".

Codice di risposta 200: "OK", 204: "Nessun contenuto", 302: "Trovato".

Come si può vedere, i diversi dispositivi chiedono percorsi diversi e pagine web diverse. E se rispondete correttamente, attiveranno il pop-up.

Ecco un riepilogo di ciò che è necessario per inviare e ricevere:

Windows 10

URLRisposta di attivazione
www.msftconnecttest.com/ncsi.txt200 OK
www.msftconnecttest.com/connecttest.txt200 OK
www.msftconnecttest.com/redirect302 reindirizzamento (al portale vincolato, ad esempio index.html)

Android 9, 10

URLRisposta di attivazione
connectivitycheck.gstatic.com/generate_204302 reindirizzamento (alla pagina del portale vincolato)

Altre versioni Android potrebbero interrogare altri URL. Credo che le versioni Android più recenti abbiano /generazione_204 come ripiego.

Ecco due risorse per gli Androidi più vecchi:

https://lemariva.com/blog/2017/11/white-hacking-wemos-captive-portal-using-micropython

https://enterprisenetworkingatlarge.wordpress.com/2018/04/21/captive-portal-detection-on-android-and-others-client-vendors-vs-ap-vendors/

iOS 15

URLRisposta di attivazione
captive.apple.com/hotspot-detect.html200 OK (risponde con una pagina web)

Il mio Samsung Note 9 con Android 10 è stato il più difficile da decifrare. In apparenza, si dovrebbero seguire gli schemi tipici di Android ma, ahimè, non ha funzionato nulla!

Sono riuscito a ottenere il prompt "Sign-in required", ma solo dopo aver cambiato il DNS con un IP della LAN pubblica (un IP al di fuori dell'intervallo '10.0.0.0/8, 172.16.0.0/12, o 192.168.0.0/16'). Si veda questo commento di Stack Exchange.

Ma facendo quanto sopra si è rotto il portale vincolato di ogni altro dispositivo...

Libreria Pimoroni Phew per il portale vincolato Pico W

Il fiuto di Pimoroni La libreria rende molto più semplice la creazione di un portale vincolato, perché ha fatto tutto il lavoro pesante.

Per prima cosa, è necessario scaricare la libreria. Io ho usato la versione 0.0.3 che può essere scaricato qui.

Quindi, estrarre i file e caricare la cartella denominata fiuuu sul Pico W. Personalmente, ho usato l'IDE Thonny e si può imparate a caricare i file qui.

Alla fine dell'esercitazione, si dovrebbe avere una directory con questo aspetto.

Codifichiamo il pop-up dell'hotspot!

Perciò, lasciatemi iniziare con 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")

Per essere chiari, ho adattato questo codice da Kevin McAleer e l'ho modificato per i nostri scopi. Se volete vedere la spiegazione approfondita di Kevin su come funzionano le cose, guardare questo video di YouTube.

Ma permettetemi di passare brevemente in rassegna le diverse sezioni.

Ci sono tre sezioni con i commenti "#android redirects", "#apple redir" e "# microsoft windows redirects". Queste sezioni gestiscono i test che ogni sistema operativo effettua e rispondono con la risposta giusta.

Alla fine delle risposte, esse vengono reindirizzate a http://{DOMAIN}/, tranne che per il percorso Apple (perché Kevin l'ha scritto così e se non è rotto...).

Il reindirizzamento al DOMAIN, dichiarato come "pico.wireless", ci darebbe un URL meno sgradevole.

Quindi, invece di vedere "www.msftconnecttest.com" sulla barra degli indirizzi, vedremo "pico.wireless" sulla barra degli indirizzi. Naturalmente, questo è un aspetto da tenere presente per il captive portal della vostra azienda.

Pimoroni Phew riduce il codice da scrivere

La cosa bella di Phew è che si scrive molto meno codice rispetto a quello che si scriverebbe partendo da zero.

Ad esempio, se si volesse lanciare il SoftAP sul Pico W, si dovrebbe scrivere un codice simile a questo:

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

Con Pimoroni's Phew, il vostro onere si riduce a:

ap = access_point("Pico W Captive")

A mio parere, la parte migliore è la dns.run_catchall() che esegue un carico di codice vitale ma complicato:

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 semplifica anche la scrittura delle rotte. Tutto ciò che si deve fare è scrivere qualcosa di simile:

@server.route("/[your_route_here]", methods=["GET"])
def your_function_here(request):
  pass

@server.catchall()
def catchall(request):
  pass

Come si può vedere sopra, creare un percorso è facilissimo. Tutto ciò che si deve fare è usare @server.routee passare una rotta e i metodi. Quindi definire una funzione sottostante con l'opzione richiesta parametro.

Infine, c'è il @server.catchall() che gestisce tutte le rotte non assegnate.

Questo rende tutto molto semplice!

Visitate il repo Github di Phew qui.

indice.html

Si tratta di una semplice prova di concetto. indice.html che emette un <h1> dicendo "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>

Conclusione

Ecco fatto. Ecco tutto ciò che occorre sapere per configurare un portale vincolato su Pico W per la vostra azienda.

Se avete domande, non esitate a farcele sapere nei commenti qui sotto!

8 commenti

  1. cinos in Gennaio 8, 2023 il 4:11 pm

    Un buon sostituto di piratebox (anche se senza funzione di chat e upload).

  2. OkinKun in Marzo 31, 2023 il 5:07 pm

    Questo è esattamente ciò che stavo cercando!
    Le cose funzionano per lo più, tuttavia il sito web non si apre da solo, ma viene visualizzato un errore:

    2023-03-31 12:02:35 [info / 160kB] > GET /generate_204 (302 Found) [236ms]
    L'eccezione del task non è stata recuperata
    futuro: coro=
    Traceback (ultima chiamata più recente):
    File "uasyncio/core.py", linea 1, in run_until_complete
    File "phew/server.py", riga 242, in _handle_request
    File "phew/server.py", riga 161, in _parse_headers
    ValueError: servono più di 1 valori da decomprimere

    Mi chiedo se forse ha qualcosa a che fare con il mio vecchio telefono che è ancora Android 6..

  3. Dingleberry in Giugno 21, 2023 il 10:57 pm

    Come si può modificare il codice per includere il codice HTML all'interno del programma? Ho fatto un tentativo ma non ha funzionato.

    Trovo che il flusso del programma sia molto confuso.

    • Adam Bobeck in Giugno 26, 2023 il 2:51 pm

      Ciao, sono felice di aiutarti! Potresti descrivere il tuo problema in modo più dettagliato e dirmi quale dispositivo stai usando per il captive portal?

  4. NewbiePicoWHacker in Ottobre 1, 2023 il 3:36 pm

    Salve! Sto cercando di far funzionare questo sistema su un Pico W. L'AP si avvia, il DNS si avvia, il server web non si avvia mai o impiega molto tempo (diversi minuti) per avviarsi. Avete qualche idea/indizio/suggerimento sul perché? Grazie!

  5. Prithwiraj Bose in Novembre 5, 2023 il 3:43 pm

    Potete per favore aiutarmi a capire quale riga di codice applica/automatizza l'apertura del captive portal sul browser del cliente, dopo una connessione riuscita all'hotspot? Non sembra aprire automaticamente nulla. Mi sto connettendo dal mio portatile.

  6. Peter in Novembre 24, 2023 il 8:13 pm

    Grazie per la bella descrizione.

    Vorrei aggiungere un secondo o addirittura un terzo SSID allo stesso AP. Esiste un modo per farlo con Phew?

    Qualche idea?

    • Toby in Maggio 28, 2024 il 5:13 pm

      No, è necessario utilizzare un raspberry pi pico per ogni ssid.

Lascia un commento