1# Captive Portal Detection 2 3## Background 4 5Wifi devices may face some interception of their connection to the 6internet, it's very common for, eg, coffee shop wifi to present some 7kind of login or other clickthrough before access to the Internet is 8granted. Devices may need to understand that they are in this 9situation, and there are several different techniques for trying to 10gague it. 11 12Sequence-wise the device has been granted a DHCP lease and has been 13configured with DNS, but the DNS may be wrongly resolving everything 14to an address on the LAN or a portal on the net. 15 16Whether there is a captive portal active should be a sticky state for a given 17connection if there is not going to be any attempt to login or pass the landing 18page, it only needs checking for after DHCP acquisition then. If there will be 19an attempt to satisfy the landing page, the test should be repeated after the 20attempt. 21 22## Detection schemes 23 24The most popular detection scheme by numbers is Android's method, 25which is to make an HTTP client GET to `http://connectivitycheck.android.com/generate_204` 26and see if a 204 is coming back... if intercepted, typically there'll be a 273xx redirect to the portal, perhaps on https. Or, it may reply on http with 28a 200 and show the portal directly... either way it won't deliver a 204 29like the real remote server does. 30 31Variations include expecting a 200 but with specific http body content, and 32doing a DNS lookup for a static IP that the device knows; if it's resolved to 33something else, it knows there's monkey business implying a captive portal. 34 35Other schemes involve https connections going out and detecting that the cert 36of the server it's actually talking to doesn't check out, although this is 37potentially ambiguous. 38 39Yet more methods are possible outside of tcp or http. 40 41## lws captive portal detect support 42 43lws provides a generic api to start captive portal detection... 44 45``` 46LWS_EXTERN LWS_VISIBLE int 47lws_system_cpd_start(struct lws_context *context); 48``` 49 50and two states in `lws_system` states to trigger it from, either 51`LWS_SYSTATE_CPD_PRE_TIME` which happens after DHCP acquisition but before 52ntpclient and is suitable for non https-based scheme where the time doesn't 53need to be known, or the alternative `LWS_SYSTATE_CPD_POST_TIME` state which 54happens after ntpclient has completed and we know the time. 55 56The actual platform implementation is set using `lws_system_ops_t` function 57pointer `captive_portal_detect_request`, ie 58 59``` 60 int (*captive_portal_detect_request)(struct lws_context *context); 61 /**< Check if we can go out on the internet cleanly, or if we are being 62 * redirected or intercepted by a captive portal. 63 * Start the check that proceeds asynchronously, and report the results 64 * by calling lws_captive_portal_detect_result() api 65 */ 66``` 67 68User platform code can provide this to implement whatever scheme they want, when 69it has arrived at a result, it can call the lws api `lws_system_cpd_result()` to 70inform lws. If there isn't any captive portal, this will also try to advance the 71system state towards OPERATIONAL. 72 73``` 74/** 75 * lws_system_cpd_result() - report the result of the captive portal detection 76 * 77 * \param context: the lws_context 78 * \param result: one of the LWS_CPD_ constants representing captive portal state 79 * \param redirect_url: NULL, or the url we were redirected to if result is 80 * LWS_CPD_HTTP_REDIRECT 81 * 82 * Sets the context's captive portal detection state to result. User captive 83 * portal detection code would call this once it had a result from its test. 84 */ 85LWS_EXTERN LWS_VISIBLE int 86lws_system_cpd_result(struct lws_context *context, int result, const char *redirect_url); 87``` 88 89