#include #include #include #include #include #include #include "httpd_utils/captive.h" #include "httpd_utils/fd_to_ipv4.h" #include "httpd_utils/redirect.h" #include static const char *TAG="captive"; const char * __attribute__((weak)) httpd_captive_redirect_get_domain(void) { return "fb_node.captive"; } esp_err_t __attribute__((weak)) httpd_captive_redirect_get_url(httpd_req_t *r, char *buf, size_t maxlen) { buf = append(buf, "http://", &maxlen); buf = append(buf, httpd_captive_redirect_get_domain(), &maxlen); append(buf, "/", &maxlen); return ESP_OK; } esp_err_t httpd_captive_redirect(httpd_req_t *r) { // must be static to survive being used in the redirect header static char s_buf[64]; wifi_mode_t mode = 0; esp_wifi_get_mode(&mode); // Check if we have an softap interface. No point checking IPs and hostnames if the client can't be on AP. if (mode == WIFI_MODE_STA || mode == WIFI_MODE_NULL) { goto no_redirect; } int fd = httpd_req_to_sockfd(r); tcpip_adapter_ip_info_t apip; tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &apip); u32_t client_addr; if(ESP_OK != fd_to_ipv4(fd, &client_addr)) { return ESP_FAIL; } ESP_LOGD(TAG, "[captive] Client addr = 0x%08x, ap addr 0x%08x, ap nmask 0x%08x", client_addr, apip.ip.addr, apip.netmask.addr ); // Check if client IP looks like from our AP dhcps if ((client_addr & apip.netmask.addr) != (apip.ip.addr & apip.netmask.addr)) { ESP_LOGD(TAG, "[captive] Client not in AP IP range"); goto no_redirect; } // Get requested hostname from the header esp_err_t rv = httpd_req_get_hdr_value_str(r, "Host", s_buf, 64); if (rv != ESP_OK) { ESP_LOGW(TAG, "[captive] No host in request?"); goto no_redirect; } ESP_LOGD(TAG, "[captive] Candidate for redirect: %s%s", s_buf, r->uri); // Never redirect if host is an IP if (strlen(s_buf)>7) { bool isIP = 1; for (int x = 0; x < strlen(s_buf); x++) { if (s_buf[x] != '.' && (s_buf[x] < '0' || s_buf[x] > '9')) { isIP = 0; break; } } if (isIP) { ESP_LOGD(TAG, "[captive] Access via IP, no redirect needed"); goto no_redirect; } } // Redirect if host differs // - this can be e.g. connectivitycheck.gstatic.com or the equivalent for ios if (0 != strcmp(s_buf, httpd_captive_redirect_get_domain())) { ESP_LOGD(TAG, "[captive] Host differs, redirecting..."); httpd_captive_redirect_get_url(r, s_buf, 64); return httpd_redirect_to(r, s_buf); } else { ESP_LOGD(TAG, "[captive] Host is OK"); goto no_redirect; } no_redirect: return ESP_ERR_NOT_FOUND; }