static int _special_process(request *r, const char *mac, const char *redir_url) { t_offline_client *o_client = NULL; LOCK_OFFLINE_CLIENT_LIST(); o_client = offline_client_list_find_by_mac(mac); if(o_client == NULL) { o_client = offline_client_list_add(r->clientAddr, mac); } else { o_client->last_login = time(NULL); } UNLOCK_OFFLINE_CLIENT_LIST(); if(_is_apple_captive(r->request.host)) { unsigned int interval = time(NULL) - o_client->first_login; debug(LOG_INFO, "Into captive.apple.com hit_counts %d interval %d\n", o_client->hit_counts, interval); LOCK_OFFLINE_CLIENT_LIST(); o_client->hit_counts++; UNLOCK_OFFLINE_CLIENT_LIST(); if(o_client->client_type == 1 ) { if(o_client->hit_counts < 5 && interval < 30 ) http_send_js_redirect_ex(r, redir_url); else { http_send_apple_redirect(r, redir_url); } } else { LOCK_OFFLINE_CLIENT_LIST(); o_client->client_type = 1; UNLOCK_OFFLINE_CLIENT_LIST(); http_send_js_redirect_ex(r, redir_url); } return 1; } return 0; }
/** The 404 handler is also responsible for redirecting to the auth server */ void http_callback_404(httpd * webserver, request * r, int error_code) { char tmp_url[MAX_BUF], *url, *mac; s_config *config = config_get_config(); t_auth_serv *auth_server = get_auth_server(); memset(tmp_url, 0, sizeof(tmp_url)); /* * XXX Note the code below assumes that the client's request is a plain * http request to a standard port. At any rate, this handler is called only * if the internet/auth server is down so it's not a huge loss, but still. */ snprintf(tmp_url, (sizeof(tmp_url) - 1), "http://%s%s%s%s", r->request.host, r->request.path, r->request.query[0] ? "?" : "", r->request.query); url = httpdUrlEncode(tmp_url); if (!is_online()) { /* The internet connection is down at the moment - apologize and do not redirect anywhere */ char *buf; safe_asprintf(&buf, "<p>We apologize, but it seems that the internet connection that powers this hotspot is temporarily unavailable.</p>" "<p>If at all possible, please notify the owners of this hotspot that the internet connection is out of service.</p>" "<p>The maintainers of this network are aware of this disruption. We hope that this situation will be resolved soon.</p>" "<p>In a while please <a href='%s'>click here</a> to try your request again.</p>", tmp_url); send_http_page(r, "Internet access unavailable!", buf); free(buf); debug(LOG_INFO, "Sent %s an apology since I am not online - no point sending them to auth server", r->clientAddr); } else if (!is_auth_online()) { /* The auth server is down at the moment - apologize and do not redirect anywhere */ char *buf; safe_asprintf(&buf, "<p>We apologize, but it seems that we are currently unable to re-direct you to the login screen.</p>" "<p>The maintainers of this network are aware of this disruption. We hope that this situation will be resolved soon.</p>" "<p>In a couple of minutes please <a href='%s'>click here</a> to try your request again.</p>", tmp_url); send_http_page(r, "Auth server is not online!", buf); free(buf); debug(LOG_INFO, "Sent %s an apology since auth server not online - no point sending them to auth server", r->clientAddr); } else { /* Re-direct them to auth server */ char *urlFragment; if (!(mac = arp_get(r->clientAddr))) { /* We could not get their MAC address */ debug(LOG_INFO, "Failed to retrieve MAC address for ip %s, so not putting in the login request", r->clientAddr); safe_asprintf(&urlFragment, "%sgw_address=%s&gw_port=%d&gw_id=%s&channel_path=%s&ssid=%s&ip=%s&url=%s", auth_server->authserv_login_script_path_fragment, config->gw_address, config->gw_port, config->gw_id, g_channel_path?g_channel_path:"null", g_ssid?g_ssid:"null", r->clientAddr, url); } else { t_client *clt = NULL; debug(LOG_INFO, "Got client MAC address for ip %s: %s", r->clientAddr, mac); safe_asprintf(&urlFragment, "%sgw_address=%s&gw_port=%d&gw_id=%s&channel_path=%s&ssid=%s&ip=%s&mac=%s&url=%s", auth_server->authserv_login_script_path_fragment, config->gw_address, config->gw_port, config->gw_id, g_channel_path?g_channel_path:"null", g_ssid?g_ssid:"null", r->clientAddr, mac, url); //>>> liudf 20160106 added if(_special_process(r, mac, urlFragment)) { free(urlFragment); free(url); free(mac); return; } if(is_roaming(mac)) { fw_set_roam_mac(mac); http_send_redirect(r, tmp_url, "device roaming"); free(urlFragment); free(url); free(mac); return; } // if device has login; but after long time reconnected router, its ip changed LOCK_CLIENT_LIST(); clt = client_list_find_by_mac(mac); if(clt && strcmp(clt->ip, r->clientAddr) != 0) { fw_deny(clt); free(clt->ip); clt->ip = safe_strdup(r->clientAddr); fw_allow(clt, clt->fw_connection_state); UNLOCK_CLIENT_LIST(); http_send_redirect(r, tmp_url, "device has login"); free(urlFragment); free(url); free(mac); return; } UNLOCK_CLIENT_LIST(); // if device is wired and wired device no need auth if(config->wired_passed == 1 && is_device_wired(mac)) { debug(LOG_INFO, "wired_passed: %s is wired device", mac); t_trusted_mac *pmac = add_trusted_mac(mac); fw_set_trusted_mac(mac); http_send_redirect(r, tmp_url, "device no need login"); if(pmac != NULL) pmac->ip = safe_strdup(r->clientAddr); free(urlFragment); free(url); free(mac); return; } //<<< liudf added end free(mac); } // if host is not in whitelist, maybe not in conf or domain'IP changed, it will go to here. debug(LOG_INFO, "Check host %s is in whitelist or not", r->request.host); // e.g. www.example.com t_firewall_rule *rule; //e.g. example.com is in whitelist // if request http://www.example.com/, it's not equal example.com. for (rule = get_ruleset("global"); config->js_filter != 1 && rule != NULL; rule = rule->next) { debug(LOG_INFO, "rule mask %s", rule->mask); if (strstr(r->request.host, rule->mask) == NULL) { debug(LOG_INFO, "host %s is not in %s, continue", r->request.host, rule->mask); continue; } int host_length = strlen(r->request.host); int mask_length = strlen(rule->mask); if (host_length != mask_length) { char prefix[1024] = {0}; // must be *.example.com, if not have ".", maybe Phishing. e.g. phishingexample.com strncpy(prefix, r->request.host, host_length - mask_length - 1); // e.g. www strcat(prefix, "."); // www. strcat(prefix, rule->mask); // www.example.com if (strcasecmp(r->request.host, prefix) == 0) { debug(LOG_INFO, "allow subdomain"); fw_allow_host(r->request.host); http_send_redirect(r, tmp_url, "allow subdomain"); free(url); free(urlFragment); return; } } else { // e.g. "example.com" is in conf, so it had been parse to IP and added into "iptables allow" when wifidog start. but then its' A record(IP) changed, it will go to here. debug(LOG_INFO, "allow domain again, because IP changed"); fw_allow_host(r->request.host); http_send_redirect(r, tmp_url, "allow domain"); free(url); free(urlFragment); return; } } debug(LOG_INFO, "Captured %s requesting [%s] and re-directing them to login page", r->clientAddr, url); if(config->js_filter) http_send_js_redirect_ex(r, urlFragment); else http_send_redirect_to_auth(r, urlFragment, "Redirect to login page"); free(urlFragment); } free(url); }