/** * Allocate and return a pointer to a t_auth_target struct encoding information * needed to eventually authenticate a client. * The struct should be freed by http_nodogsplash_free_authtarget(). */ t_auth_target* http_nodogsplash_make_authtarget(const char token[], const char redir[]) { char *encodedredir; char *encodedtok; t_auth_target* authtarget; s_config *config; config = config_get_config(); authtarget = safe_malloc(sizeof(t_auth_target)); memset(authtarget, 0, sizeof(t_auth_target)); authtarget->ip = safe_strdup(config->gw_address); authtarget->port = config->gw_port; authtarget->authdir = safe_strdup(config->authdir); authtarget->denydir = safe_strdup(config->denydir); safe_asprintf(&(authtarget->authaction),"http://%s:%d/%s/",authtarget->ip,authtarget->port,authtarget->authdir); safe_asprintf(&(authtarget->denyaction),"http://%s:%d/%s/",authtarget->ip,authtarget->port,authtarget->denydir); authtarget->token = safe_strdup(token); authtarget->redir = safe_strdup(redir); encodedredir = httpdUrlEncode(authtarget->redir); /* malloc's */ encodedtok = httpdUrlEncode(authtarget->token); /* malloc's */ safe_asprintf(&(authtarget->authtarget), "%s?redir=%s&tok=%s", authtarget->authaction, encodedredir, encodedtok); free(encodedredir); free(encodedtok); return authtarget; }
void http_nodogsplash_redirect_remote_auth(request *r, t_auth_target *authtarget) { char *remoteurl; char *encgateway, *encauthaction, *encredir, *enctoken; s_config *config; config = config_get_config(); /* URL encode variables, redirect to remote auth server */ encgateway = httpdUrlEncode(config->gw_name); encauthaction = httpdUrlEncode(authtarget->authaction); encredir = httpdUrlEncode(authtarget->redir); enctoken = httpdUrlEncode(authtarget->token); safe_asprintf(&remoteurl, "%s?gateway=%s&authaction=%s&redir=%s&tok=%s", config->remote_auth_action, encgateway, encauthaction, encredir, enctoken); http_nodogsplash_redirect(r, remoteurl); free(encgateway); free(encauthaction); free(encredir); free(enctoken); free(remoteurl); }
void http_nodogsplash_redirect_remote_auth(request *r, t_auth_target *authtarget,t_client *client) { char *remoteurl; char *encgateway, *encauthaction, *encredir, *enctoken, *encmac; s_config *config; config = config_get_config(); /* URL encode variables, redirect to remote auth server */ //encgateway = httpdUrlEncode(config->gw_name); encauthaction = httpdUrlEncode(authtarget->authaction); encredir = httpdUrlEncode(authtarget->redir); enctoken = httpdUrlEncode(authtarget->token); encmac = httpdUrlEncode(client->mac); safe_asprintf(&remoteurl, "%s:%d%s?uid=%d&authaction=%s&redir=%s&tok=%s&mac=%s", config->auth_server, config->auth_port, config->auth_path, config->uid, encauthaction, encredir, enctoken, encmac); http_nodogsplash_redirect(r, remoteurl); free(encauthaction); free(encredir); free(enctoken); free(remoteurl); }
/** 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, "Uh oh! 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, "Uh oh! Login screen unavailable!", 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&ip=%s&url=%s", auth_server->authserv_login_script_path_fragment, config->gw_address, config->gw_port, config->gw_id, r->clientAddr, url); } else { 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&ip=%s&mac=%s&url=%s", auth_server->authserv_login_script_path_fragment, config->gw_address, config->gw_port, config->gw_id, r->clientAddr, mac, url); 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"); 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); http_send_redirect_to_auth(r, urlFragment, "Redirect to login page"); free(urlFragment); } free(url); }
/** The 404 handler is also responsible for redirecting to the auth server */ void http_callback_404(httpd *webserver, request *r) { 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, "Uh oh! 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, "Uh oh! Login screen unavailable!", 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 { //hector add 2014/3/18 get_oauth_iplist(); fw_set_oauthservers(); //hector end /* 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&url=%s", auth_server->authserv_login_script_path_fragment, config->gw_address, config->gw_port, config->gw_id, url); } else { 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&mac=%s&url=%s", auth_server->authserv_login_script_path_fragment, config->gw_address, config->gw_port, config->gw_id, mac, url); } debug(LOG_INFO, "Captured %s requesting [%s] and re-directing them to login page", r->clientAddr, url); http_send_redirect_to_auth(r, urlFragment, "Redirect to login page"); free(urlFragment); } free(url); }
/** Initiates a transaction with the auth server, either to authenticate or to * update the traffic counters at the server @param authresponse Returns the information given by the central server @param request_type Use the REQUEST_TYPE_* defines in centralserver.h @param ip IP adress of the client this request is related to @param mac MAC adress of the client this request is related to @param token Authentification token of the client @param incoming Current counter of the client's total incoming traffic, in bytes @param outgoing Current counter of the client's total outgoing traffic, in bytes */ t_authcode auth_server_request(t_authresponse * authresponse, const char *request_type, const char *ip, const char *mac, const char *token, unsigned long long int incoming, unsigned long long int outgoing) { int sockfd; char buf[MAX_BUF]; char *tmp; char *safe_token; t_auth_serv *auth_server = NULL; auth_server = get_auth_server(); /* Blanket default is error. */ authresponse->authcode = AUTH_ERROR; sockfd = connect_auth_server(); /** * TODO: XXX change the PHP so we can harmonize stage as request_type * everywhere. */ memset(buf, 0, sizeof(buf)); safe_token = httpdUrlEncode(token); snprintf(buf, (sizeof(buf) - 1), "GET %s%sstage=%s&ip=%s&mac=%s&token=%s&incoming=%llu&outgoing=%llu&gw_id=%s HTTP/1.0\r\n" "User-Agent: WiFiDog %s\r\n" "Host: %s\r\n" "\r\n", auth_server->authserv_path, auth_server->authserv_auth_script_path_fragment, request_type, ip, mac, safe_token, incoming, outgoing, config_get_config()->gw_id, VERSION, auth_server->authserv_hostname); free(safe_token); char *res; #ifdef USE_CYASSL if (auth_server->authserv_use_ssl) { res = https_get(sockfd, buf, auth_server->authserv_hostname); } else { res = http_get(sockfd, buf); } #endif #ifndef USE_CYASSL res = http_get(sockfd, buf); #endif if (NULL == res) { debug(LOG_ERR, "There was a problem talking to the auth server!"); return (AUTH_ERROR); } if ((tmp = strstr(res, "Auth: "))) { if (sscanf(tmp, "Auth: %d", (int *)&authresponse->authcode) == 1) { debug(LOG_INFO, "Auth server returned authentication code %d", authresponse->authcode); free(res); return (authresponse->authcode); } else { debug(LOG_WARNING, "Auth server did not return expected authentication code"); free(res); return (AUTH_ERROR); } } free(res); return (AUTH_ERROR); }
/** Initiates a transaction with the auth server, either to authenticate or to * update the traffic counters at the server @param authresponse Returns the information given by the central server @param request_type Use the REQUEST_TYPE_* defines in centralserver.h @param ip IP adress of the client this request is related to @param mac MAC adress of the client this request is related to @param token Authentification token of the client @param incoming Current counter of the client's total incoming traffic, in bytes @param outgoing Current counter of the client's total outgoing traffic, in bytes */ t_authcode auth_server_request(t_authresponse *authresponse, const char *request_type, const char *ip, const char *mac, const char *token, unsigned long long int incoming, unsigned long long int outgoing) { int sockfd; ssize_t numbytes; size_t totalbytes; char buf[MAX_BUF]; char *tmp; char *safe_token; int done, nfds; fd_set readfds; struct timeval timeout; t_auth_serv *auth_server = NULL; auth_server = get_auth_server(); /* Blanket default is error. */ authresponse->authcode = AUTH_ERROR; sockfd = connect_auth_server(); if (sockfd == -1) { /* Could not connect to any auth server */ return (AUTH_ERROR); } /** * TODO: XXX change the PHP so we can harmonize stage as request_type * everywhere. */ memset(buf, 0, sizeof(buf)); safe_token=httpdUrlEncode(token); snprintf(buf, (sizeof(buf) - 1), "GET %s%sstage=%s&ip=%s&mac=%s&token=%s&incoming=%llu&outgoing=%llu&gw_id=%s HTTP/1.0\r\n" "User-Agent: WiFiDog %s\r\n" "Host: %s\r\n" "\r\n", auth_server->authserv_path, auth_server->authserv_auth_script_path_fragment, request_type, ip, mac, safe_token, incoming, outgoing, config_get_config()->gw_id, VERSION, auth_server->authserv_hostname ); free(safe_token); debug(LOG_DEBUG, "Sending HTTP request to auth server: [%s]\n", buf); send(sockfd, buf, strlen(buf), 0); debug(LOG_DEBUG, "Reading response"); numbytes = totalbytes = 0; done = 0; do { FD_ZERO(&readfds); FD_SET(sockfd, &readfds); timeout.tv_sec = 30; /* XXX magic... 30 second is as good a timeout as any */ timeout.tv_usec = 0; nfds = sockfd + 1; nfds = select(nfds, &readfds, NULL, NULL, &timeout); if (nfds > 0) { /** We don't have to use FD_ISSET() because there * was only one fd. */ numbytes = read(sockfd, buf + totalbytes, MAX_BUF - (totalbytes + 1)); if (numbytes < 0) { debug(LOG_ERR, "An error occurred while reading from auth server: %s", strerror(errno)); /* FIXME */ close(sockfd); return (AUTH_ERROR); } else if (numbytes == 0) { done = 1; } else { totalbytes += numbytes; debug(LOG_DEBUG, "Read %d bytes, total now %d", numbytes, totalbytes); } } else if (nfds == 0) { debug(LOG_ERR, "Timed out reading data via select() from auth server"); /* FIXME */ close(sockfd); return (AUTH_ERROR); } else if (nfds < 0) { debug(LOG_ERR, "Error reading data via select() from auth server: %s", strerror(errno)); /* FIXME */ close(sockfd); return (AUTH_ERROR); } } while (!done); close(sockfd); buf[totalbytes] = '\0'; debug(LOG_DEBUG, "HTTP Response from Server: [%s]", buf); if ((tmp = strstr(buf, "Auth: "))) { if (sscanf(tmp, "Auth: %d", (int *)&authresponse->authcode) == 1) { debug(LOG_INFO, "Auth server returned authentication code %d", authresponse->authcode); return(authresponse->authcode); } else { debug(LOG_WARNING, "Auth server did not return expected authentication code"); return(AUTH_ERROR); } } else { return(AUTH_ERROR); } /* XXX Never reached because of the above if()/else pair. */ return(AUTH_ERROR); }