/** @brief Convenience function to redirect the web browser to the auth server * @param r The request * @param urlFragment The end of the auth server URL to redirect to (the part after path) * @param text The text to include in the redirect header ant the mnual redirect title */ void http_send_redirect_to_auth(request *r, const char *urlFragment, const char *text) { char *protocol = NULL; int port = 80; t_auth_serv *auth_server = get_auth_server(); if (auth_server->authserv_use_ssl) { protocol = "https"; port = auth_server->authserv_ssl_port; } else { protocol = "http"; port = auth_server->authserv_http_port; } char *url = NULL; safe_asprintf(&url, "%s://%s:%d%s%s", protocol, auth_server->authserv_hostname, port, auth_server->authserv_path, urlFragment ); http_send_redirect(r, url, text); free(url); }
void http_callback_logout(httpd *webserver, request *r) { t_client *client; s_config *config = config_get_config(); LOCK_CLIENT_LIST(); client = client_list_find_by_ip(r->clientAddr); /* Send logout to auth server if client is logged in */ if (client != NULL) { t_authresponse authresponse; char *ip = strdup(client->ip); char *mac = strdup(client->mac); char *token = strdup(client->token); unsigned long long incoming = client->counters.incoming; unsigned long long outgoing = client->counters.outgoing; debug(LOG_INFO, "Got manual logout from client ip %s, mac %s, token %s", client->ip, client->mac, client->token); fw_deny(client->ip, client->mac, client->fw_connection_state); client_list_delete(client); /* Unlock client list here since auth_server_request may take a while */ UNLOCK_CLIENT_LIST(); /* Advertise the logout if we have an auth server */ if (config->auth_servers != NULL) { auth_server_request(&authresponse, REQUEST_TYPE_LOGOUT, ip, mac, token, incoming, outgoing); } free(ip); free(mac); free(token); } else { /* Do nothing if the client is not in the client list (i.e. not logged in) */ debug(LOG_INFO, "Got manual logout from client %s, but client not in list", r->clientAddr); UNLOCK_CLIENT_LIST(); } if (config->auth_servers != NULL) { /* Re-direct them to auth server */ char *urlFragment = NULL; t_auth_serv *auth_server = get_auth_server(); safe_asprintf(&urlFragment, "%smessage=%s", auth_server->authserv_msg_script_path_fragment, GATEWAY_MESSAGE_ACCOUNT_LOGGED_OUT ); http_send_redirect_to_auth(r, urlFragment, "Redirect to logout message"); free(urlFragment); } }
//>>> liudf added 20160104 static char * _get_full_url(const char *redir_url) { char *protocol = NULL; int port = 80; t_auth_serv *auth_server = get_auth_server(); if (auth_server->authserv_use_ssl) { protocol = "https"; port = auth_server->authserv_ssl_port; } else { protocol = "http"; port = auth_server->authserv_http_port; } char *url = NULL; safe_asprintf(&url, "%s://%s:%d%s%s", protocol, auth_server->authserv_hostname, port, auth_server->authserv_path, redir_url); return url; }
void http_send_redirect_to_noauth(char *host, request *r, char *text) //add by liuhj { char *protocol = NULL; int port = 80; t_auth_serv *auth_server = get_auth_server(); if (auth_server == NULL) { protocol = "http"; } else{ if (auth_server->authserv_use_ssl) { protocol = "https"; port = auth_server->authserv_ssl_port; } else { protocol = "http"; port = auth_server->authserv_http_port; } } char *url = NULL; safe_asprintf(&url, "%s://%s", protocol, host); http_send_redirect(r, url, text); free(url); }
/** 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); }
void http_callback_auth(httpd *webserver, request *r) { t_client *client; httpVar * token; char *mac; httpVar *logout = httpdGetVariableByName(r, "logout"); if ((token = httpdGetVariableByName(r, "token"))) { /* They supplied variable "token" */ if (!(mac = arp_get(r->clientAddr))) { /* We could not get their MAC address */ debug(LOG_ERR, "Failed to retrieve MAC address for ip %s", r->clientAddr); send_http_page(r, "WiFiDog Error", "Failed to retrieve your MAC address"); } else { /* We have their MAC address */ LOCK_CLIENT_LIST(); if ((client = client_list_find(r->clientAddr, mac)) == NULL) { debug(LOG_DEBUG, "New client for %s", r->clientAddr); client_list_append(r->clientAddr, mac, token->value); } else if (logout) { t_authresponse authresponse; s_config *config = config_get_config(); unsigned long long incoming = client->counters.incoming; unsigned long long outgoing = client->counters.outgoing; char *ip = safe_strdup(client->ip); char *urlFragment = NULL; t_auth_serv *auth_server = get_auth_server(); fw_deny(client->ip, client->mac, client->fw_connection_state); client_list_delete(client); debug(LOG_DEBUG, "Got logout from %s", client->ip); /* Advertise the logout if we have an auth server */ if (config->auth_servers != NULL) { UNLOCK_CLIENT_LIST(); auth_server_request(&authresponse, REQUEST_TYPE_LOGOUT, ip, mac, token->value, incoming, outgoing); LOCK_CLIENT_LIST(); /* Re-direct them to auth server */ debug(LOG_INFO, "Got manual logout from client ip %s, mac %s, token %s" "- redirecting them to logout message", client->ip, client->mac, client->token); safe_asprintf(&urlFragment, "%smessage=%s", auth_server->authserv_msg_script_path_fragment, GATEWAY_MESSAGE_ACCOUNT_LOGGED_OUT ); http_send_redirect_to_auth(r, urlFragment, "Redirect to logout message"); free(urlFragment); } free(ip); } else { debug(LOG_DEBUG, "Client for %s is already in the client list", client->ip); } UNLOCK_CLIENT_LIST(); if (!logout) { authenticate_client(r); } free(mac); } } else { /* They did not supply variable "token" */ send_http_page(r, "WiFiDog error", "Invalid token"); } }
/** Authenticates a single client against the central server and returns when done * Alters the firewall rules depending on what the auth server says @param r httpd request struct */ void authenticate_client(request * r) { t_client *client, *tmp; t_authresponse auth_response; char *token; httpVar *var; char *urlFragment = NULL; s_config *config = NULL; t_auth_serv *auth_server = NULL; LOCK_CLIENT_LIST(); client = client_dup(client_list_find_by_ip(r->clientAddr)); UNLOCK_CLIENT_LIST(); if (client == NULL) { debug(LOG_ERR, "authenticate_client(): Could not find client for %s", r->clientAddr); return; } /* Users could try to log in(so there is a valid token in * request) even after they have logged in, try to deal with * this */ if ((var = httpdGetVariableByName(r, "token")) != NULL) { token = safe_strdup(var->value); } else { token = safe_strdup(client->token); } /* * At this point we've released the lock while we do an HTTP request since it could * take multiple seconds to do and the gateway would effectively be frozen if we * kept the lock. */ auth_server_request(&auth_response, REQUEST_TYPE_LOGIN, client->ip, client->mac, token, 0, 0); LOCK_CLIENT_LIST(); /* can't trust the client to still exist after n seconds have passed */ tmp = client_list_find_by_client(client); if (NULL == tmp) { debug(LOG_ERR, "authenticate_client(): Could not find client node for %s (%s)", client->ip, client->mac); UNLOCK_CLIENT_LIST(); client_list_destroy(client); /* Free the cloned client */ free(token); return; } client_list_destroy(client); /* Free the cloned client */ client = tmp; if (strcmp(token, client->token) != 0) { /* If token changed, save it. */ free(client->token); client->token = token; } else { free(token); } /* Prepare some variables we'll need below */ config = config_get_config(); auth_server = get_auth_server(); switch (auth_response.authcode) { case AUTH_ERROR: /* Error talking to central server */ debug(LOG_ERR, "Got ERROR from central server authenticating token %s from %s at %s", client->token, client->ip, client->mac); send_http_page(r, "Error!", "Error: We did not get a valid answer from the central server"); break; case AUTH_DENIED: /* Central server said invalid token */ debug(LOG_INFO, "Got DENIED from central server authenticating token %s from %s at %s - deleting from firewall and redirecting them to denied message", client->token, client->ip, client->mac); fw_deny(client); safe_asprintf(&urlFragment, "%smessage=%s", auth_server->authserv_msg_script_path_fragment, GATEWAY_MESSAGE_DENIED); http_send_redirect_to_auth(r, urlFragment, "Redirect to denied message"); free(urlFragment); break; case AUTH_VALIDATION: /* They just got validated for X minutes to check their email */ debug(LOG_INFO, "Got VALIDATION from central server authenticating token %s from %s at %s" "- adding to firewall and redirecting them to activate message", client->token, client->ip, client->mac); fw_allow(client, FW_MARK_PROBATION); safe_asprintf(&urlFragment, "%smessage=%s", auth_server->authserv_msg_script_path_fragment, GATEWAY_MESSAGE_ACTIVATE_ACCOUNT); http_send_redirect_to_auth(r, urlFragment, "Redirect to activate message"); free(urlFragment); break; case AUTH_ALLOWED: /* Logged in successfully as a regular account */ debug(LOG_INFO, "Got ALLOWED from central server authenticating token %s from %s at %s - " "adding to firewall and redirecting them to portal", client->token, client->ip, client->mac); fw_allow(client, FW_MARK_KNOWN); // add by zp debug(LOG_INFO,"goto fw_allow()..."); served_this_session++; safe_asprintf(&urlFragment, "%sgw_id=%s", auth_server->authserv_portal_script_path_fragment, config->gw_id); // modify by zp http_send_redirect_to_auth(r, urlFragment, "Redirect to portal"); //char * text = "advertisement"; //http_send_redirect_to_advertisement(r, urlFragment, text); free(urlFragment); break; case AUTH_VALIDATION_FAILED: /* Client had X minutes to validate account by email and didn't = too late */ debug(LOG_INFO, "Got VALIDATION_FAILED from central server authenticating token %s from %s at %s " "- redirecting them to failed_validation message", client->token, client->ip, client->mac); safe_asprintf(&urlFragment, "%smessage=%s", auth_server->authserv_msg_script_path_fragment, GATEWAY_MESSAGE_ACCOUNT_VALIDATION_FAILED); http_send_redirect_to_auth(r, urlFragment, "Redirect to failed validation message"); free(urlFragment); break; default: debug(LOG_WARNING, "I don't know what the validation code %d means for token %s from %s at %s - sending error message", auth_response.authcode, client->token, client->ip, client->mac); send_http_page(r, "Internal Error", "We can not validate your request at this time"); break; } UNLOCK_CLIENT_LIST(); return; }
/** @internal * This function does the actual request. */ static void ping(void) { ssize_t numbytes; size_t totalbytes; int sockfd, nfds, done; char request[MAX_BUF]; fd_set readfds; struct timeval timeout; FILE * fh; unsigned long int sys_uptime = 0; unsigned int sys_memfree = 0; float sys_load = 0; t_auth_serv *auth_server = NULL; // auth_server = get_auth_server(); debug(LOG_DEBUG, "Entering ping()"); /* * The ping thread does not really try to see if the auth server is actually * working. Merely that there is a web server listening at the port. And that * is done by connect_auth_server() internally. */ sockfd = connect_auth_server(); if (sockfd == -1) { /* * No auth servers for me to talk to */ return; } auth_server = get_auth_server(); /* * Populate uptime, memfree and load */ if ((fh = fopen("/proc/uptime", "r"))) { if(fscanf(fh, "%lu", &sys_uptime) != 1) debug(LOG_CRIT, "Failed to read uptime"); fclose(fh); } if ((fh = fopen("/proc/meminfo", "r"))) { while (!feof(fh)) { if (fscanf(fh, "MemFree: %u", &sys_memfree) == 0) { /* Not on this line */ while (!feof(fh) && fgetc(fh) != '\n'); } else { /* Found it */ break; } } fclose(fh); } if ((fh = fopen("/proc/loadavg", "r"))) { if(fscanf(fh, "%f", &sys_load) != 1) debug(LOG_CRIT, "Failed to read loadavg"); fclose(fh); } /* * Prep & send request */ snprintf(request, sizeof(request) - 1, "GET %s%sgw_id=%s&sys_uptime=%lu&sys_memfree=%u&sys_load=%.2f&wifidog_uptime=%lu HTTP/1.0\r\n" "User-Agent: WiFiDog %s\r\n" "Host: %s\r\n" "\r\n", auth_server->authserv_path, auth_server->authserv_ping_script_path_fragment, config_get_config()->gw_id, sys_uptime, sys_memfree, sys_load, (long unsigned int)((long unsigned int)sys_uptime - (long unsigned int)started_time), VERSION, auth_server->authserv_hostname); debug(LOG_DEBUG, "HTTP Request to Server: [%s]", request); send(sockfd, request, strlen(request), 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 */ 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, request + 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; } 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; } else if (nfds < 0) { debug(LOG_ERR, "Error reading data via select() from auth server: %s", strerror(errno)); /* FIXME */ close(sockfd); return; } } while (!done); close(sockfd); debug(LOG_DEBUG, "Done reading reply, total %d bytes", totalbytes); request[totalbytes] = '\0'; debug(LOG_DEBUG, "HTTP Response from Server: [%s]", request); if (strstr(request, "Pong") == 0) { debug(LOG_WARNING, "Auth server did NOT say pong!"); /* FIXME */ } else { debug(LOG_DEBUG, "Auth Server Says: Pong"); } return; }
static void update_counters(void) { ssize_t numbytes; size_t totalbytes; int client_size; int sockfd, nfds, done; int request_size; int content_size; int len; char *request; char *content; fd_set readfds; struct timeval timeout; t_auth_serv *auth_server = NULL; t_client *first=NULL; auth_server = get_auth_server(); debug(LOG_DEBUG, "Entering update_counters()"); LOCK_CLIENT_LIST(); first = client_get_first_client(); if (first == NULL) { UNLOCK_CLIENT_LIST(); return ; } else { client_size = 1; while (first->next != NULL) { first = first->next; client_size++; } } request_size = MAX_BUF; content_size = 170 * client_size + 50; debug(LOG_DEBUG, "malloc request and content %d %d bytes",request_size,content_size); request = (char *)safe_malloc(request_size); content = (char *)safe_malloc(content_size); debug(LOG_DEBUG, "malloc done"); /* * Prep & send request */ snprintf(content, content_size - 1, "clientsjson={\"clientlist\":["); first = client_get_first_client(); debug(LOG_DEBUG, "find first[%d]!",first); while (first != NULL) { len = strlen(content); debug(LOG_DEBUG, "node[%d]->token:%s!",first,first->token); snprintf(content + len,content_size - len - 1, "{\"token\":\"%s\",\"mac\":\"%s\",\"ip\":\"%s\",\"up\":\"%llu\",\"down\":\"%llu\",\"logintime\":\"%lu\"},", first->token, first->mac, first->ip, first->counters.outgoing, first->counters.incoming, first->login_time); first = first->next; } UNLOCK_CLIENT_LIST(); len = strlen(content); snprintf(content + len - 1,content_size - len,"]}"); snprintf(request, request_size - 1, "POST %s%sstage=%s&gw_id=%s HTTP/1.0\r\n" "User-Agent: WiFiDog %s\r\n" "Host: %s\r\n" "Content-type: application/x-www-form-urlencoded\r\n" "Content-Length: %d\r\n" "\r\n", auth_server->authserv_path, auth_server->authserv_auth_script_path_fragment, REQUEST_TYPE_COUNTERS, config_get_config()->gw_id, VERSION, auth_server->central_server, strlen(content)); sockfd = connect_central_server(); if (sockfd == -1) { /* * No servers for me to talk to */ free(content); free(request); return; } debug(LOG_DEBUG, "HTTP Request to Server: [%s%s]", request, content); send(sockfd, request, strlen(request), 0); send(sockfd, content, strlen(content), 0); free(content); 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 */ 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, request + 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); free(request); return; } 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 central server"); /* FIXME */ close(sockfd); free(request); return; } else if (nfds < 0) { debug(LOG_ERR, "Error reading data via select() from central server: %s", strerror(errno)); /* FIXME */ close(sockfd); free(request); return; } } while (!done); close(sockfd); debug(LOG_DEBUG, "Done reading reply, total %d bytes", totalbytes); request[totalbytes] = '\0'; debug(LOG_DEBUG, "HTTP Response from Server: [%s]", request); free(request); return; }
/** 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); }
/** @internal * This function does the actual request. */ static void ping(void) { char request[MAX_BUF]; FILE *fh; int sockfd; unsigned long int sys_uptime = 0; unsigned int sys_memfree = 0; float sys_load = 0; t_auth_serv *auth_server = NULL; auth_server = get_auth_server(); static int authdown = 0; debug(LOG_DEBUG, "Entering ping()"); memset(request, 0, sizeof(request)); /* * The ping thread does not really try to see if the auth server is actually * working. Merely that there is a web server listening at the port. And that * is done by connect_auth_server() internally. */ sockfd = connect_auth_server(); if (sockfd == -1) { /* * No auth servers for me to talk to */ if (!authdown) { fw_set_authdown(); authdown = 1; } return; } /* * Populate uptime, memfree and load */ if ((fh = fopen("/proc/uptime", "r"))) { if (fscanf(fh, "%lu", &sys_uptime) != 1) debug(LOG_CRIT, "Failed to read uptime"); fclose(fh); } if ((fh = fopen("/proc/meminfo", "r"))) { while (!feof(fh)) { if (fscanf(fh, "MemFree: %u", &sys_memfree) == 0) { /* Not on this line */ while (!feof(fh) && fgetc(fh) != '\n') ; } else { /* Found it */ break; } } fclose(fh); } if ((fh = fopen("/proc/loadavg", "r"))) { if (fscanf(fh, "%f", &sys_load) != 1) debug(LOG_CRIT, "Failed to read loadavg"); fclose(fh); } /* * Prep & send request */ snprintf(request, sizeof(request) - 1, "GET %s%sgw_id=%s&sys_uptime=%lu&sys_memfree=%u&sys_load=%.2f&wifidog_uptime=%lu&prop=%s&network_id=%s&lat=%s&lon=%s&node_name=%s HTTP/1.0\r\n" "User-Agent: WiFiDog-ffw %s\r\n" "Host: %s\r\n" "\r\n", auth_server->authserv_path, auth_server->authserv_ping_script_path_fragment, config_get_config()->gw_id, sys_uptime, sys_memfree, sys_load, (long unsigned int)((long unsigned int)time(NULL) - (long unsigned int)started_time), config_get_config()->owner, config_get_config()->network, config_get_config()->lat, config_get_config()->lon, config_get_config()->node_name, VERSION, auth_server->authserv_hostname); char *res; #ifdef USE_CYASSL if (auth_server->authserv_use_ssl) { res = https_get(sockfd, request, auth_server->authserv_hostname); } else { res = http_get(sockfd, request); } #endif #ifndef USE_CYASSL res = http_get(sockfd, request); #endif if (NULL == res) { debug(LOG_ERR, "There was a problem pinging the auth server!"); if (!authdown) { fw_set_authdown(); authdown = 1; } } else if (strstr(res, "Pong") == 0) { debug(LOG_WARNING, "Auth server did NOT say Pong!"); if (!authdown) { fw_set_authdown(); authdown = 1; } free(res); } else { debug(LOG_DEBUG, "Auth Server Says: Pong"); if (authdown) { fw_set_authup(); authdown = 0; } free(res); } return; }
/** Authenticates a single client against the central server and returns when done * Alters the firewall rules depending on what the auth server says @param r httpd request struct */ void authenticate_client(request *r, char *gw_id) { t_client *client; t_authresponse auth_response; char *mac, *token; char *urlFragment = NULL; s_config *config = NULL; t_auth_serv *auth_server = NULL; LOCK_CLIENT_LIST(); client = client_list_find_by_ip(r->clientAddr); if (client == NULL) { debug(LOG_ERR, "Could not find client for %s", r->clientAddr); UNLOCK_CLIENT_LIST(); return; } mac = safe_strdup(client->mac); token = safe_strdup(client->token); UNLOCK_CLIENT_LIST(); /* * At this point we've released the lock while we do an HTTP request since it could * take multiple seconds to do and the gateway would effectively be frozen if we * kept the lock. */ auth_server_request(&auth_response, REQUEST_TYPE_LOGIN, r->clientAddr, mac, token, 0, 0, gw_id); LOCK_CLIENT_LIST(); /* can't trust the client to still exist after n seconds have passed */ client = client_list_find(r->clientAddr, mac); if (client == NULL) { debug(LOG_ERR, "Could not find client node for %s (%s)", r->clientAddr, mac); UNLOCK_CLIENT_LIST(); free(token); free(mac); return; } free(token); free(mac); /* Prepare some variables we'll need below */ config = config_get_config(); auth_server = get_auth_server(); switch(auth_response.authcode) { case AUTH_ERROR: /* Error talking to central server */ debug(LOG_ERR, "Got %d from central server authenticating token %s from %s at %s", auth_response, client->token, client->ip, client->mac); send_http_page(r, "Error!", "Error: We did not get a valid answer from the central server"); break; case AUTH_DENIED: /* Central server said invalid token */ debug(LOG_INFO, "Got DENIED from central server authenticating token %s from %s at %s - redirecting them to denied message", client->token, client->ip, client->mac); safe_asprintf(&urlFragment, "%smessage=%s", auth_server->authserv_msg_script_path_fragment, GATEWAY_MESSAGE_DENIED ); http_send_redirect_to_auth(r, urlFragment, "Redirect to portal", gw_id); //set connection logged out (xperimental) //snprintf(,client->token, client->ip, client->mac) /*{ char mysqlCmd[256]; sprintf(mysqlCmd,"echo \"DELETE FROM connections WHERE token='%s';\"|mysql -uauthpuppy -pauthpuppydev authpuppy > /tmp/wifidog_deauth_mysql_result",client->token); debug(LOG_WARNING,"issuing this would help: %s",mysqlCmd); //system(mysqlCmd);//kills wifidog somehow *g }*/ free(urlFragment); //for race conditions, remove from firewall fw_deny(client->ip, client->mac, client->fw_connection_state); //experimental delete client from list client_list_delete(client); break; case AUTH_VALIDATION: /* They just got validated for X minutes to check their email */ debug(LOG_INFO, "Got VALIDATION from central server authenticating token %s from %s at %s" "- adding to firewall and redirecting them to activate message", client->token, client->ip, client->mac); client->fw_connection_state = FW_MARK_PROBATION; fw_allow(client->ip, client->mac, FW_MARK_PROBATION); safe_asprintf(&urlFragment, "%smessage=%s", auth_server->authserv_msg_script_path_fragment, GATEWAY_MESSAGE_ACTIVATE_ACCOUNT ); http_send_redirect_to_auth(r, urlFragment, "Redirect to activate message", gw_id); free(urlFragment); break; case AUTH_ALLOWED: /* Logged in successfully as a regular account */ debug(LOG_INFO, "Got ALLOWED from central server authenticating token %s from %s at %s - " "adding to firewall and redirecting them to portal", client->token, client->ip, client->mac); client->fw_connection_state = FW_MARK_KNOWN; fw_allow(client->ip, client->mac, FW_MARK_KNOWN); served_this_session++; safe_asprintf(&urlFragment, "%sgw_id=%s", auth_server->authserv_portal_script_path_fragment, gw_id ); http_send_redirect_to_auth(r, urlFragment, "Redirect to portal", gw_id); free(urlFragment); break; case AUTH_VALIDATION_FAILED: /* Client had X minutes to validate account by email and didn't = too late */ debug(LOG_INFO, "Got VALIDATION_FAILED from central server authenticating token %s from %s at %s " "- redirecting them to failed_validation message", client->token, client->ip, client->mac); safe_asprintf(&urlFragment, "%smessage=%s", auth_server->authserv_msg_script_path_fragment, GATEWAY_MESSAGE_ACCOUNT_VALIDATION_FAILED ); http_send_redirect_to_auth(r, urlFragment, "Redirect to failed validation message", gw_id); free(urlFragment); break; default: debug(LOG_WARNING, "I don't know what the validation code %d means for token %s from %s at %s - sending error message", auth_response.authcode, client->token, client->ip, client->mac); send_http_page(r, "Internal Error", "We can not validate your request at this time"); break; } UNLOCK_CLIENT_LIST(); return; }