| # Captive Portal Detection |
| |
| ## Background |
| |
| Wifi devices may face some interception of their connection to the |
| internet, it's very common for, eg, coffee shop wifi to present some |
| kind of login or other clickthrough before access to the Internet is |
| granted. Devices may need to understand that they are in this |
| situation, and there are several different techniques for trying to |
| gague it. |
| |
| Sequence-wise the device has been granted a DHCP lease and has been |
| configured with DNS, but the DNS may be wrongly resolving everything |
| to an address on the LAN or a portal on the net. |
| |
| Whether there is a captive portal active should be a sticky state for a given |
| connection if there is not going to be any attempt to login or pass the landing |
| page, it only needs checking for after DHCP acquisition then. If there will be |
| an attempt to satisfy the landing page, the test should be repeated after the |
| attempt. |
| |
| ## Detection schemes |
| |
| The most popular detection scheme by numbers is Android's method, |
| which is to make an HTTP client GET to `http://connectivitycheck.android.com/generate_204` |
| and see if a 204 is coming back... if intercepted, typically there'll be a |
| 3xx redirect to the portal, perhaps on https. Or, it may reply on http with |
| a 200 and show the portal directly... either way it won't deliver a 204 |
| like the real remote server does. |
| |
| Variations include expecting a 200 but with specific http body content, and |
| doing a DNS lookup for a static IP that the device knows; if it's resolved to |
| something else, it knows there's monkey business implying a captive portal. |
| |
| Other schemes involve https connections going out and detecting that the cert |
| of the server it's actually talking to doesn't check out, although this is |
| potentially ambiguous. |
| |
| Yet more methods are possible outside of tcp or http. |
| |
| ## lws captive portal detect support |
| |
| lws provides a generic api to start captive portal detection... |
| |
| ``` |
| LWS_EXTERN LWS_VISIBLE int |
| lws_system_cpd_start(struct lws_context *context); |
| ``` |
| |
| and two states in `lws_system` states to trigger it from, either |
| `LWS_SYSTATE_CPD_PRE_TIME` which happens after DHCP acquisition but before |
| ntpclient and is suitable for non https-based scheme where the time doesn't |
| need to be known, or the alternative `LWS_SYSTATE_CPD_POST_TIME` state which |
| happens after ntpclient has completed and we know the time. |
| |
| The actual platform implementation is set using `lws_system_ops_t` function |
| pointer `captive_portal_detect_request`, ie |
| |
| ``` |
| int (*captive_portal_detect_request)(struct lws_context *context); |
| /**< Check if we can go out on the internet cleanly, or if we are being |
| * redirected or intercepted by a captive portal. |
| * Start the check that proceeds asynchronously, and report the results |
| * by calling lws_captive_portal_detect_result() api |
| */ |
| ``` |
| |
| User platform code can provide this to implement whatever scheme they want, when |
| it has arrived at a result, it can call the lws api `lws_system_cpd_result()` to |
| inform lws. If there isn't any captive portal, this will also try to advance the |
| system state towards OPERATIONAL. |
| |
| ``` |
| /** |
| * lws_system_cpd_result() - report the result of the captive portal detection |
| * |
| * \param context: the lws_context |
| * \param result: one of the LWS_CPD_ constants representing captive portal state |
| * \param redirect_url: NULL, or the url we were redirected to if result is |
| * LWS_CPD_HTTP_REDIRECT |
| * |
| * Sets the context's captive portal detection state to result. User captive |
| * portal detection code would call this once it had a result from its test. |
| */ |
| LWS_EXTERN LWS_VISIBLE int |
| lws_system_cpd_result(struct lws_context *context, int result, const char *redirect_url); |
| ``` |
| |