static void ndsctl_deauth(int fd, char *arg) { t_client *client; char *ip, *mac; debug(LOG_DEBUG, "Entering ndsctl_deauth..."); LOCK_CLIENT_LIST(); /* arg can be IP or MAC address of client */ debug(LOG_DEBUG, "Argument: %s (@%x)", arg, arg); /* We get the client or return... */ if ((client = client_list_find_by_ip(arg)) != NULL); else if ((client = client_list_find_by_mac(arg)) != NULL); else if ((client = client_list_find_by_token(arg)) != NULL); else { debug(LOG_DEBUG, "Client not found."); UNLOCK_CLIENT_LIST(); write(fd, "No", 2); return; } /* We have the client. Get both ip and mac address and deauthenticate */ ip = safe_strdup(client->ip); mac = safe_strdup(client->mac); UNLOCK_CLIENT_LIST(); auth_client_action(ip, mac, AUTH_MAKE_DEAUTHENTICATED); free(ip); free(mac); write(fd, "Yes", 3); debug(LOG_DEBUG, "Exiting ndsctl_deauth..."); }
static void wdctl_reset(int fd, char *arg) { t_client *node; debug(LOG_DEBUG, "Entering wdctl_reset..."); LOCK_CLIENT_LIST(); debug(LOG_DEBUG, "Argument: %s (@%x)", arg, arg); /* We get the node or return... */ if ((node = client_list_find_by_ip(arg)) != NULL); else if ((node = client_list_find_by_mac(arg)) != NULL); else { debug(LOG_DEBUG, "Client not found."); UNLOCK_CLIENT_LIST(); write(fd, "No", 2); return; } debug(LOG_DEBUG, "Got node %x.", node); /* deny.... */ /* TODO: maybe just deleting the connection is not best... But this * is a manual command, I don't anticipate it'll be that useful. */ fw_deny(node->ip, node->mac, node->fw_connection_state); client_list_delete(node); UNLOCK_CLIENT_LIST(); write(fd, "Yes", 3); debug(LOG_DEBUG, "Exiting wdctl_reset..."); }
static void ndsctl_auth(int fd, char *arg) { t_client *client; char *ip, *mac; debug(LOG_DEBUG, "Entering ndsctl_auth..."); LOCK_CLIENT_LIST(); /* arg should be IP address of client */ debug(LOG_DEBUG, "Argument: %s (@%x)", arg, arg); /* Add client to client list... */ if ((client = client_list_add_client(arg)) == NULL) { debug(LOG_DEBUG, "Could not add client."); UNLOCK_CLIENT_LIST(); write(fd, "No", 2); return; } /* We have a client. Get both ip and mac address and authenticate */ ip = safe_strdup(client->ip); mac = safe_strdup(client->mac); UNLOCK_CLIENT_LIST(); auth_client_action(ip, mac, AUTH_MAKE_AUTHENTICATED); free(ip); free(mac); write(fd, "Yes", 3); debug(LOG_DEBUG, "Exiting ndsctl_auth..."); }
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); } }
/** Initialize the firewall rules */ int fw_init(void) { int result = 0; int new_fw_state; t_client *client = NULL; if (!init_icmp_socket()) { return 0; } debug(LOG_INFO, "Initializing Firewall"); result = iptables_fw_init(); if (restart_orig_pid) { debug(LOG_INFO, "Restoring firewall rules for clients inherited from parent"); LOCK_CLIENT_LIST(); client = client_get_first_client(); while (client) { new_fw_state = client->fw_connection_state; client->fw_connection_state = FW_MARK_NONE; fw_allow(client, new_fw_state); client = client->next; } UNLOCK_CLIENT_LIST(); } return result; }
void http_callback_auth(httpd *webserver, request *r) { t_client *client; httpVar * token; char *mac; 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 { debug(LOG_DEBUG, "Client for %s is already in the client list", client->ip); } UNLOCK_CLIENT_LIST(); authenticate_client(r); free(mac); } } else { /* They did not supply variable "token" */ send_http_page(r, "WiFiDog error", "Invalid token"); } }
int auth_client_auth(const unsigned id, const char *reason) { t_client *client; int rc; LOCK_CLIENT_LIST(); client = client_list_find_by_id(id); /* Client should already have hit the server and be on the client list */ if (client == NULL) { debug(LOG_ERR, "Client %u to authenticate is not on client list", id); rc = -1; goto end; } rc = auth_change_state(client, FW_MARK_AUTHENTICATED, reason); if (rc == 0) { authenticated_since_start++; } end: UNLOCK_CLIENT_LIST(); return rc; }
/** * Add client making a request to client list. * Return pointer to the client list entry for this client. * * N.B.: This does not authenticate the client; it only makes * their information available on the client list. */ t_client * http_nodogsplash_add_client(request *r) { t_client *client; LOCK_CLIENT_LIST(); client = client_list_add_client(r->clientAddr); UNLOCK_CLIENT_LIST(); return client; }
/** See if they are still active, * refresh their traffic counters, * remove and deny them if timed out */ static void fw_refresh_client_list(void) { t_client *cp1, *cp2; s_config *config = config_get_config(); const int preauth_idle_timeout_secs = 60 * config->preauth_idle_timeout; const int auth_idle_timeout_secs = 60 * config->auth_idle_timeout; const time_t now = time(NULL); /* Update all the counters */ if (-1 == iptables_fw_counters_update()) { debug(LOG_ERR, "Could not get counters from firewall!"); return; } LOCK_CLIENT_LIST(); for (cp1 = cp2 = client_get_first_client(); NULL != cp1; cp1 = cp2) { cp2 = cp1->next; if (!(cp1 = client_list_find_by_id(cp1->id))) { debug(LOG_ERR, "Client was freed while being re-validated!"); continue; } int conn_state = cp1->fw_connection_state; int last_updated = cp1->counters.last_updated; if (cp1->session_end > 0 && cp1->session_end <= now) { /* Session ended (only > 0 for FW_MARK_AUTHENTICATED by binauth) */ debug(LOG_NOTICE, "Force out user: %s %s, connected: %ds, in: %llukB, out: %llukB", cp1->ip, cp1->mac, now - cp1->session_end, cp1->counters.incoming / 1000, cp1->counters.outgoing / 1000); auth_change_state(cp1, FW_MARK_PREAUTHENTICATED, "timeout_deauth"); } else if (preauth_idle_timeout_secs > 0 && conn_state == FW_MARK_PREAUTHENTICATED && (last_updated + preauth_idle_timeout_secs) <= now) { /* Timeout inactive preauthenticated user */ debug(LOG_NOTICE, "Timeout preauthenticated idle user: %s %s, inactive: %ds, in: %llukB, out: %llukB", cp1->ip, cp1->mac, now - last_updated, cp1->counters.incoming / 1000, cp1->counters.outgoing / 1000); client_list_delete(cp1); } else if (auth_idle_timeout_secs > 0 && conn_state == FW_MARK_AUTHENTICATED && (last_updated + auth_idle_timeout_secs) <= now) { /* Timeout inactive user */ debug(LOG_NOTICE, "Timeout authenticated idle user: %s %s, inactive: %ds, in: %llukB, out: %llukB", cp1->ip, cp1->mac, now - last_updated, cp1->counters.incoming / 1000, cp1->counters.outgoing / 1000); auth_change_state(cp1, FW_MARK_PREAUTHENTICATED, "idle_deauth"); } } UNLOCK_CLIENT_LIST(); }
/** * Add client making a request to client list. * Return pointer to the client list entry for this client. * * N.B.: This does not authenticate the client; it only makes * their information available on the client list. */ static t_client * add_client(const char *ip_addr) { t_client *client; LOCK_CLIENT_LIST(); client = client_list_add_client(ip_addr); UNLOCK_CLIENT_LIST(); return client; }
/** Take action on a client. * Alter the firewall rules and client list accordingly. */ void auth_client_action(const char ip[], const char mac[], t_authaction action) { t_client *client; LOCK_CLIENT_LIST(); client = client_list_find(ip,mac); /* Client should already have hit the server and be on the client list */ if (client == NULL) { debug(LOG_ERR, "Client %s %s action %d is not on client list", ip, mac, action); UNLOCK_CLIENT_LIST(); return; } switch(action) { case AUTH_MAKE_AUTHENTICATED: if(client->fw_connection_state != FW_MARK_AUTHENTICATED) { client->fw_connection_state = FW_MARK_AUTHENTICATED; iptables_fw_access(AUTH_MAKE_AUTHENTICATED, client); authenticated_since_start++; } else { debug(LOG_INFO, "Nothing to do, %s %s already authenticated", client->ip, client->mac); } break; case AUTH_MAKE_DEAUTHENTICATED: if(client->fw_connection_state == FW_MARK_AUTHENTICATED) { iptables_fw_access(AUTH_MAKE_DEAUTHENTICATED, client); } client_list_delete(client); break; default: debug(LOG_ERR, "Unknown auth action: %d",action); } UNLOCK_CLIENT_LIST(); return; }
void http_callback_disconnect(httpd * webserver, request * r) { const s_config *config = config_get_config(); /* XXX How do you change the status code for the response?? */ httpVar *token = httpdGetVariableByName(r, "token"); httpVar *mac = httpdGetVariableByName(r, "mac"); if (config->httpdusername && (strcmp(config->httpdusername, r->request.authUser) || strcmp(config->httpdpassword, r->request.authPassword))) { debug(LOG_INFO, "Disconnect requested, forcing authentication"); httpdForceAuthenticate(r, config->httpdrealm); return; } if (token && mac) { t_client *client; LOCK_CLIENT_LIST(); client = client_list_find_by_mac(mac->value); if (!client || strcmp(client->token, token->value)) { UNLOCK_CLIENT_LIST(); debug(LOG_INFO, "Disconnect %s with incorrect token %s", mac->value, token->value); httpdOutput(r, "Invalid token for MAC"); return; } /* TODO: get current firewall counters */ logout_client(client); UNLOCK_CLIENT_LIST(); } else { debug(LOG_INFO, "Disconnect called without both token and MAC given"); httpdOutput(r, "Both the token and MAC need to be specified"); return; } return; }
void ndsctl_json(int fd) { t_client *client; int indx; unsigned long int now, durationsecs = 0; unsigned long long int download_bytes, upload_bytes; now = time(NULL); /* Update the client's counters so info is current */ iptables_fw_counters_update(); LOCK_CLIENT_LIST(); cprintf(fd, "{\n\"client_length\": %d,\n", get_client_list_length()); client = client_get_first_client(); indx = 0; cprintf(fd, "\"clients\":{\n"); while (client != NULL) { cprintf(fd, "\"%s\":{\n", client->mac); cprintf(fd, "\"client_id\":%d,\n", indx); cprintf(fd, "\"ip\":\"%s\",\n\"mac\":\"%s\",\n", client->ip, client->mac); cprintf(fd, "\"added\":%lld,\n", (long long) client->added_time); cprintf(fd, "\"active\":%lld,\n", (long long) client->counters.last_updated); cprintf(fd, "\"duration\":%lu,\n", now - client->added_time); cprintf(fd, "\"token\":\"%s\",\n", client->token ? client->token : "none"); cprintf(fd, "\"state\":\"%s\",\n", fw_connection_state_as_string(client->fw_connection_state)); durationsecs = now - client->added_time; download_bytes = client->counters.incoming; upload_bytes = client->counters.outgoing; cprintf(fd, "\"downloaded\":\"%llu\",\n\"avg_down_speed\":\"%.6g\",\n\"uploaded\":\"%llu\",\n\"avg_up_speed\":\"%.6g\"\n", download_bytes/1000, ((double)download_bytes)/125/durationsecs, upload_bytes/1000, ((double)upload_bytes)/125/durationsecs); indx++; client = client->next; cprintf(fd, "}"); if(client) { cprintf(fd, ",\n"); } } cprintf(fd, "}}" ); UNLOCK_CLIENT_LIST(); }
void http_callback_auth(httpd * webserver, request * r) { t_client *client; httpVar *token; char *mac; httpVar *logout = httpdGetVariableByName(r, "logout"); const s_config *config = config_get_config(); 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 { t_redir_node *node; int index = 0; LOCK_REDIR(); node = redir_list_find(mac); if (node) { index = node->wlindex; } UNLOCK_REDIR(); /* 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 = client_list_add(r->clientAddr, mac, token->value); client->fw_connection_state = FW_MARK_REDIR; client->counters.active_duration = config->sessiontimeout[index-1]; } else if (logout) { logout_client(client); } else { debug(LOG_DEBUG, "Client for %s is already in the client list", client->ip); } UNLOCK_CLIENT_LIST(); if (!logout) { /* applies for case 1 and 3 from above if */ authenticate_client(r); } free(mac); } } else { /* They did not supply variable "token" */ send_http_page(r, "WiFiDog error", "Invalid token"); } }
/** Ping clients to see if they are still active, * refresh their traffic counters, * remove and deny them if timed out */ void fw_refresh_client_list(void) { t_client *cp1, *cp2; time_t now, added_time, last_updated; s_config *config = config_get_config(); /* Update all the counters */ if (-1 == iptables_fw_counters_update()) { debug(LOG_ERR, "Could not get counters from firewall!"); return; } LOCK_CLIENT_LIST(); for (cp1 = cp2 = client_get_first_client(); NULL != cp1; cp1 = cp2) { cp2 = cp1->next; if (!(cp1 = client_list_find(cp1->ip, cp1->mac))) { debug(LOG_ERR, "Node %s was freed while being re-validated!", cp1->ip); } else { now = time(NULL); last_updated = cp1->counters.last_updated; added_time = cp1->added_time; if (last_updated + (config->checkinterval * config->clienttimeout) <= now) { /* Timing out inactive user */ debug(LOG_NOTICE, "%s %s inactive %d secs. kB in: %llu kB out: %llu", cp1->ip, cp1->mac, config->checkinterval * config->clienttimeout, cp1->counters.incoming/1000, cp1->counters.outgoing/1000); if (cp1->fw_connection_state == FW_MARK_AUTHENTICATED) { iptables_fw_access(AUTH_MAKE_DEAUTHENTICATED, cp1); } client_list_delete(cp1); } else if (added_time + (config->checkinterval * config->clientforceout) <= now) { /* Forcing out user */ debug(LOG_NOTICE, "%s %s connected %d secs. kB in: %llu kB out: %llu", cp1->ip, cp1->mac, config->checkinterval * config->clientforceout, cp1->counters.incoming/1000, cp1->counters.outgoing/1000); if (cp1->fw_connection_state == FW_MARK_AUTHENTICATED) { iptables_fw_access(AUTH_MAKE_DEAUTHENTICATED, cp1); } client_list_delete(cp1); } } } UNLOCK_CLIENT_LIST(); }
void ndsctl_clients(int fd) { t_client *client; int indx; unsigned long int now, durationsecs = 0; unsigned long long int download_bytes, upload_bytes; now = time(NULL); /* Update the client's counters so info is current */ iptables_fw_counters_update(); LOCK_CLIENT_LIST(); cprintf(fd, "%d\n", get_client_list_length()); client = client_get_first_client(); if(client) { cprintf(fd, "\n"); } indx = 0; while (client != NULL) { cprintf(fd, "client_id=%d\n", indx); cprintf(fd, "ip=%s\nmac=%s\n", client->ip, client->mac); cprintf(fd, "added=%lld\n", (long long) client->added_time); cprintf(fd, "active=%lld\n", (long long) client->counters.last_updated); cprintf(fd, "duration=%lu\n", now - client->added_time); cprintf(fd, "token=%s\n", client->token ? client->token : "none"); cprintf(fd, "state=%s\n", fw_connection_state_as_string(client->fw_connection_state)); durationsecs = now - client->added_time; download_bytes = client->counters.incoming; upload_bytes = client->counters.outgoing; cprintf(fd, "downloaded=%llu\navg_down_speed=%.6g\nuploaded=%llu\navg_up_speed=%.6g\n\n", download_bytes/1000, ((double)download_bytes)/125/durationsecs, upload_bytes/1000, ((double)upload_bytes)/125/durationsecs); indx++; client = client->next; } UNLOCK_CLIENT_LIST(); }
void auth_client_deauth_all() { t_client *cp1, *cp2; LOCK_CLIENT_LIST(); for (cp1 = cp2 = client_get_first_client(); NULL != cp1; cp1 = cp2) { cp2 = cp1->next; if (!(cp1 = client_list_find_by_id(cp1->id))) { debug(LOG_ERR, "Client was freed while being re-validated!"); continue; } auth_change_state(cp1, FW_MARK_PREAUTHENTICATED, "shutdown_deauth"); } UNLOCK_CLIENT_LIST(); }
/* @breif get number of client * @PARAMETER:none * @RETURN_VALUE:the number of current connected client * GaomingPan lonely-test:no * */ int get_curconn(void) { int count; t_client *first; LOCK_CLIENT_LIST(); first = client_get_first_client(); if (first == NULL) { count = 0; } else { count = 1; while (first->next != NULL) { first = first->next; count++; } } UNLOCK_CLIENT_LIST(); return count; }
/** * @brief Logout a client and report to auth server. * * This function assumes it is being called with the client lock held! This * function remove the client from the client list and free its memory, so * client is no langer valid when this method returns. * * @param client Points to the client to be logged out */ void logout_client(t_client * client) { t_authresponse authresponse; const s_config *config = config_get_config(); fw_deny(client); client_list_remove(client); /* Advertise the logout if we have an auth server */ if (config->auth_servers != NULL) { UNLOCK_CLIENT_LIST(); auth_server_request(&authresponse, REQUEST_TYPE_LOGOUT, client->ip, client->mac, client->token, client->counters.incoming, client->counters.outgoing); if (authresponse.authcode == AUTH_ERROR) debug(LOG_WARNING, "Auth server error when reporting logout"); LOCK_CLIENT_LIST(); } client_free_node(client); }
/** Update the counters of all the clients in the client list */ int iptables_fw_counters_update(void) { FILE *output; char *script, ip[16], rc; unsigned long long int counter; t_client *p1; struct in_addr tempaddr; int fd; /* Look for outgoing traffic */ safe_asprintf(&script, "%s %s", "iptables", "-v -n -x -t mangle -L " TABLE_WIFIDOG_OUTGOING); iptables_insert_gateway_id(&script); output = popen(script, "r"); free(script); if (!output) { debug(LOG_ERR, "popen(): %s", strerror(errno)); return -1; } fprintf(stderr,"popen:"); /* skip the first two lines */ while (('\n' != fgetc(output)) && !feof(output)) ; while (('\n' != fgetc(output)) && !feof(output)) ; /*set nonblocking -> would need to change fscanf against read and buffer and other parsing logic fd = fileno(output); fcntl(fd, F_SETFL, O_NONBLOCK); */ while (output && !(feof(output))) { fprintf(stderr,"#"); rc = fscanf(output, "%*s %llu %*s %*s %*s %*s %*s %15[0-9.] %*s %*s %*s %*s %*s %*s", &counter, ip); //rc = fscanf(output, "%*s %llu %*s %*s %*s %*s %*s %15[0-9.] %*s %*s %*s %*s %*s 0x%*u", &counter, ip); fprintf(stderr,"!"); if (2 == rc && EOF != rc) { /* Sanity*/ if (!inet_aton(ip, &tempaddr)) { debug(LOG_WARNING, "I was supposed to read an IP address but instead got [%s] - ignoring it", ip); continue; } debug(LOG_DEBUG, "Read outgoing traffic for %s: Bytes=%llu", ip, counter); //here we deadlock sometimes,... LOCK_CLIENT_LIST(); if ((p1 = client_list_find_by_ip(ip))) { if ((p1->counters.outgoing - p1->counters.outgoing_history) < counter) { p1->counters.outgoing = p1->counters.outgoing_history + counter; p1->counters.last_updated = time(NULL); debug(LOG_DEBUG, "%s - Updated counter.outgoing to %llu bytes. Updated last_updated to %d", ip, counter, p1->counters.last_updated); } } else { debug(LOG_ERR, "Could not find %s in client list", ip); } UNLOCK_CLIENT_LIST(); } } pclose(output); /* Look for incoming traffic */ safe_asprintf(&script, "%s %s", "iptables", "-v -n -x -t mangle -L " TABLE_WIFIDOG_INCOMING); iptables_insert_gateway_id(&script); output = popen(script, "r"); free(script); if (!output) { debug(LOG_ERR, "popen(): %s", strerror(errno)); return -1; } fprintf(stderr,"popen:"); /* skip the first two lines */ while (('\n' != fgetc(output)) && !feof(output)) ; while (('\n' != fgetc(output)) && !feof(output)) ; while (output && !(feof(output))) { fprintf(stderr,"#"); rc = fscanf(output, "%*s %llu %*s %*s %*s %*s %*s %*s %15[0-9.]", &counter, ip); fprintf(stderr,"!"); if (2 == rc && EOF != rc) { /* Sanity*/ if (!inet_aton(ip, &tempaddr)) { debug(LOG_WARNING, "I was supposed to read an IP address but instead got [%s] - ignoring it", ip); continue; } debug(LOG_DEBUG, "Read incoming traffic for %s: Bytes=%llu", ip, counter); LOCK_CLIENT_LIST(); if ((p1 = client_list_find_by_ip(ip))) { if ((p1->counters.incoming - p1->counters.incoming_history) < counter) { p1->counters.incoming = p1->counters.incoming_history + counter; debug(LOG_DEBUG, "%s - Updated counter.incoming to %llu bytes", ip, counter); } } else { debug(LOG_ERR, "Could not find %s in client list", ip); } UNLOCK_CLIENT_LIST(); } } pclose(output); return 1; }
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"); } }
/** Perform username/password check if configured to use it. */ int http_nodogsplash_check_userpass(request *r, t_auth_target *authtarget) { s_config *config; t_client *client; config = config_get_config(); int attempts = 0; char *ip; char *mac; if(!config->passwordauth && !config->usernameauth) { /* Not configured to use username/password check; can't fail. */ return 1; } ip = r->clientAddr; if (!(mac = arp_get(ip))) { /* we could not get their MAC address; fail */ debug(LOG_NOTICE, "Could not arp MAC address for %s to check user/password", ip); return 0; } /* We have their MAC address, find them on the client list and increment their password attempt counter */ LOCK_CLIENT_LIST(); client = client_list_find(ip,mac); if(client) attempts = ++(client->attempts); UNLOCK_CLIENT_LIST(); if(!client) { /* not on client list; fail */ debug(LOG_NOTICE, "Client %s %s not on client list to check user/password", ip, mac); free(mac); return 0; } if(attempts > config->passwordattempts) { /* too many attempts; fail */ debug(LOG_NOTICE, "Client %s %s exceeded %d password attempts", ip, mac, config->passwordattempts); free(mac); return 0; } if ((!config->usernameauth || (authtarget->username && !strcmp(config->username,authtarget->username))) && (!config->passwordauth || (authtarget->password && !strcmp(config->password,authtarget->password)))) { /* password and username match; success */ debug(LOG_NOTICE, "Client %s %s username/password '%s'/'%s'", ip, mac, authtarget->username, authtarget->password); free(mac); return 1; } /* fail */ debug(LOG_NOTICE, "Client %s %s bad username/password '%s'/'%s'", ip, mac, authtarget->username, authtarget->password); free(mac); return 0; }
/** The multipurpose authentication action handler */ void http_nodogsplash_callback_action(request *r, t_auth_target *authtarget, t_authaction action) { t_client *client; char *mac; const char *ip; char *clienttoken = NULL; const char *requesttoken = authtarget->token; const char *redir = authtarget->redir; ip = r->clientAddr; if(!requesttoken) { debug(LOG_NOTICE, "No token in request from ip %s", ip); return; } if(!redir) { debug(LOG_NOTICE, "No redirect in request from ip %s", ip); return; } if (!(mac = arp_get(ip))) { /* We could not get their MAC address */ debug(LOG_NOTICE, "Could not arp MAC address for %s action %d", ip, action); return; } /* We have their MAC address, find them on the client list */ LOCK_CLIENT_LIST(); client = client_list_find(ip,mac); if(client && client->token) { clienttoken = safe_strdup(client->token); } UNLOCK_CLIENT_LIST(); if(!client) { debug(LOG_NOTICE, "Client %s %s action %d is not on client list", ip, mac, action); http_nodogsplash_serve_info(r, "Nodogsplash Error", "You are not on the client list."); free(mac); return; } /* We have a client */ /* Do we have a client token? */ if(!clienttoken) { debug(LOG_NOTICE, "Client %s %s action %d does not have a token", ip, mac, action); free(mac); return; } debug(LOG_DEBUG, "Action %d: %s %s tokens %s, %s", action, ip, mac, clienttoken, requesttoken); debug(LOG_DEBUG, "Redirect: %s", redir); /* Check token match */ if (strcmp(clienttoken,requesttoken)) { /* tokens don't match, reject */ debug(LOG_NOTICE, "Client %s %s tokens %s, %s do not match", r->clientAddr, mac, clienttoken, requesttoken); http_nodogsplash_serve_info(r, "Nodogsplash Error", "Tokens do not match."); free(mac); free(clienttoken); return; } /* Log value of info string, if any */ if(authtarget->info) { debug(LOG_NOTICE, "Client %s %s info: %s", ip, mac, authtarget->info); } /* take action */ switch(action) { case AUTH_MAKE_AUTHENTICATED: auth_client_action(ip,mac,action); http_nodogsplash_redirect(r, redir); break; case AUTH_MAKE_DEAUTHENTICATED: auth_client_action(ip,mac,action); http_nodogsplash_serve_info(r, "Nodogsplash Deny", "Authentication revoked."); break; default: debug(LOG_ERR, "Unknown auth action: %d", action); } free(mac); free(clienttoken); return; }
/** Update the counters of all the clients in the client list */ int iptables_fw_counters_update(void) { FILE *output; char *script, ip[16], rc; unsigned long long int counter; t_client *p1; struct in_addr tempaddr; debug(LOG_DEBUG, "begin iptables_fw_counters_update"); /* Look for outgoing traffic */ // modified by lijg , 2013-05-18, 修改获取上行流量 safe_asprintf(&script, "%s %s", "iptables", "-v -n -x -t mangle -L " TABLE_WIFIDOG_OUTGOING); iptables_insert_gateway_id(&script); output = popen(script, "r"); free(script); if (!output) { debug(LOG_ERR, "popen(): %s", strerror(errno)); return -1; } /* skip the first two lines */ while (('\n' != fgetc(output)) && !feof(output)) ; while (('\n' != fgetc(output)) && !feof(output)) ; while (output && !(feof(output))) { rc = fscanf(output, "%*s %llu %*s %*s %*s %*s %*s %15[0-9.] %*s %*s %*s %*s %*s %*s", &counter, ip); //rc = fscanf(output, "%*s %llu %*s %*s %*s %*s %*s %15[0-9.] %*s %*s %*s %*s %*s 0x%*u", &counter, ip); //debug(LOG_DEBUG, "outgoing >> %s -- %llu (%u)", ip, counter, rc); if (2 == rc && EOF != rc) { /* Sanity*/ if (!inet_aton(ip, &tempaddr)) { debug(LOG_WARNING, "I was supposed to read an IP address but instead got [%s] - ignoring it", ip); continue; } debug(LOG_DEBUG, "Read outgoing traffic for %s: Bytes=%llu", ip, counter); LOCK_CLIENT_LIST(); if ((p1 = client_list_find_by_ip(ip))) { if ((p1->counters.outgoing - p1->counters.outgoing_history) < counter) { p1->counters.outgoing = p1->counters.outgoing_history + counter; p1->counters.last_updated = time(NULL); debug(LOG_DEBUG, "%s - Updated counter.outgoing to %llu bytes. Updated last_updated to %d", ip, counter, p1->counters.last_updated); } } else { debug(LOG_ERR, "iptables_fw_counters_update(): Could not find %s in client list, this should not happen unless if the gateway crashed", ip); debug(LOG_ERR, "Preventively deleting firewall rules for %s in table %s", ip, TABLE_WIFIDOG_OUTGOING); iptables_fw_destroy_mention("mangle", TABLE_WIFIDOG_OUTGOING, ip); debug(LOG_ERR, "Preventively deleting firewall rules for %s in table %s", ip, TABLE_WIFIDOG_INCOMING); iptables_fw_destroy_mention("mangle", TABLE_WIFIDOG_INCOMING, ip); } UNLOCK_CLIENT_LIST(); } } pclose(output); /* Look for incoming traffic */ safe_asprintf(&script, "%s %s", "iptables", "-v -n -x -t mangle -L " TABLE_WIFIDOG_INCOMING); iptables_insert_gateway_id(&script); output = popen(script, "r"); free(script); if (!output) { debug(LOG_ERR, "popen(): %s", strerror(errno)); return -1; } /* skip the first two lines */ while (('\n' != fgetc(output)) && !feof(output)) ; while (('\n' != fgetc(output)) && !feof(output)) ; while (output && !(feof(output))) { rc = fscanf(output, "%*s %llu %*s %*s %*s %*s %*s %*s %15[0-9.]", &counter, ip); if (2 == rc && EOF != rc) { /* Sanity*/ if (!inet_aton(ip, &tempaddr)) { debug(LOG_WARNING, "I was supposed to read an IP address but instead got [%s] - ignoring it", ip); continue; } debug(LOG_DEBUG, "Read incoming traffic for %s: Bytes=%llu", ip, counter); LOCK_CLIENT_LIST(); if ((p1 = client_list_find_by_ip(ip))) { if ((p1->counters.incoming - p1->counters.incoming_history) < counter) { p1->counters.incoming = p1->counters.incoming_history + counter; debug(LOG_DEBUG, "%s - Updated counter.incoming to %llu bytes", ip, counter); } } else { debug(LOG_ERR, "iptables_fw_counters_update(): Could not find %s in client list, this should not happen unless if the gateway crashed", ip); debug(LOG_ERR, "Preventively deleting firewall rules for %s in table %s", ip, TABLE_WIFIDOG_OUTGOING); iptables_fw_destroy_mention("mangle", TABLE_WIFIDOG_OUTGOING, ip); debug(LOG_ERR, "Preventively deleting firewall rules for %s in table %s", ip, TABLE_WIFIDOG_INCOMING); iptables_fw_destroy_mention("mangle", TABLE_WIFIDOG_INCOMING, ip); } UNLOCK_CLIENT_LIST(); } } pclose(output); debug(LOG_DEBUG, "end iptables_fw_counters_update\n\n"); return 1; }
/**Probably a misnomer, this function actually refreshes the entire client list's traffic counter, re-authenticates every client with the central server and update's the central servers traffic counters and notifies it if a client has logged-out. * @todo Make this function smaller and use sub-fonctions */ void fw_sync_with_authserver(void) { t_authresponse authresponse; t_client *p1, *p2, *worklist, *tmp; s_config *config = config_get_config(); if (-1 == iptables_fw_counters_update()) { debug(LOG_ERR, "Could not get counters from firewall!"); return; } LOCK_CLIENT_LIST(); /* XXX Ideally, from a thread safety PoV, this function should build a list of client pointers, * iterate over the list and have an explicit "client still valid" check while list is locked. * That way clients can disappear during the cycle with no risk of trashing the heap or getting * a SIGSEGV. */ client_list_dup(&worklist); UNLOCK_CLIENT_LIST(); for (p1 = p2 = worklist; NULL != p1; p1 = p2) { p2 = p1->next; /* Ping the client, if he responds it'll keep activity on the link. * However, if the firewall blocks it, it will not help. The suggested * way to deal witht his is to keep the DHCP lease time extremely * short: Shorter than config->checkinterval * config->clienttimeout */ icmp_ping(p1->ip); /* Update the counters on the remote server only if we have an auth server */ if (config->auth_servers != NULL) { auth_server_request(&authresponse, REQUEST_TYPE_COUNTERS, p1->ip, p1->mac, p1->token, p1->counters.incoming, p1->counters.outgoing, p1->counters.incoming_delta, p1->counters.outgoing_delta); } time_t current_time = time(NULL); debug(LOG_INFO, "Checking client %s for timeout: Last updated %ld (%ld seconds ago), timeout delay %ld seconds, current time %ld, ", p1->ip, p1->counters.last_updated, current_time - p1->counters.last_updated, config->checkinterval * config->clienttimeout, current_time); if (p1->counters.last_updated + (config->checkinterval * config->clienttimeout) <= current_time) { /* Timing out user */ debug(LOG_INFO, "%s - Inactive for more than %ld seconds, removing client and denying in firewall", p1->ip, config->checkinterval * config->clienttimeout); LOCK_CLIENT_LIST(); tmp = client_list_find_by_client(p1); if (NULL != tmp) { logout_client(tmp); } else { debug(LOG_NOTICE, "Client was already removed. Not logging out."); } UNLOCK_CLIENT_LIST(); } else { /* * This handles any change in * the status this allows us * to change the status of a * user while he's connected * * Only run if we have an auth server * configured! */ LOCK_CLIENT_LIST(); tmp = client_list_find_by_client(p1); if (NULL == tmp) { UNLOCK_CLIENT_LIST(); debug(LOG_NOTICE, "Client was already removed. Skipping auth processing"); continue; /* Next client please */ } if (config->auth_servers != NULL) { switch (authresponse.authcode) { case AUTH_DENIED: debug(LOG_NOTICE, "%s - Denied. Removing client and firewall rules", tmp->ip); fw_deny(tmp); client_list_delete(tmp); break; case AUTH_VALIDATION_FAILED: debug(LOG_NOTICE, "%s - Validation timeout, now denied. Removing client and firewall rules", tmp->ip); fw_deny(tmp); client_list_delete(tmp); break; case AUTH_ALLOWED: if (tmp->fw_connection_state != FW_MARK_KNOWN) { debug(LOG_INFO, "%s - Access has changed to allowed, refreshing firewall and clearing counters", tmp->ip); //WHY did we deny, then allow!?!? benoitg 2007-06-21 //fw_deny(tmp->ip, tmp->mac, tmp->fw_connection_state); /* XXX this was possibly to avoid dupes. */ if (tmp->fw_connection_state != FW_MARK_PROBATION) { tmp->counters.incoming_delta = tmp->counters.outgoing_delta = tmp->counters.incoming = tmp->counters.outgoing = 0; } else { //We don't want to clear counters if the user was in validation, it probably already transmitted data.. debug(LOG_INFO, "%s - Skipped clearing counters after all, the user was previously in validation", tmp->ip); } fw_allow(tmp, FW_MARK_KNOWN); } break; case AUTH_VALIDATION: /* * Do nothing, user * is in validation * period */ debug(LOG_INFO, "%s - User in validation period", tmp->ip); break; case AUTH_ERROR: debug(LOG_WARNING, "Error communicating with auth server - leaving %s as-is for now", tmp->ip); break; default: debug(LOG_ERR, "I do not know about authentication code %d", authresponse.authcode); break; } } UNLOCK_CLIENT_LIST(); } } client_list_destroy(worklist); }
static void wdctl_restart(int afd) { int sock, fd; char *sock_name; struct sockaddr_un sa_un; s_config * conf = NULL; t_client * client = NULL; char * tempstring = NULL; pid_t pid; ssize_t written; socklen_t len; conf = config_get_config(); debug(LOG_NOTICE, "Will restart myself"); /* * First, prepare the internal socket */ memset(&sa_un, 0, sizeof(sa_un)); sock_name = conf->internal_sock; debug(LOG_DEBUG, "Socket name: %s", sock_name); if (strlen(sock_name) > (sizeof(sa_un.sun_path) - 1)) { /* TODO: Die handler with logging.... */ debug(LOG_ERR, "INTERNAL socket name too long"); return; } debug(LOG_DEBUG, "Creating socket"); sock = socket(PF_UNIX, SOCK_STREAM, 0); debug(LOG_DEBUG, "Got internal socket %d", sock); /* If it exists, delete... Not the cleanest way to deal. */ unlink(sock_name); debug(LOG_DEBUG, "Filling sockaddr_un"); strcpy(sa_un.sun_path, sock_name); /* XXX No size check because we check a few lines before. */ sa_un.sun_family = AF_UNIX; debug(LOG_DEBUG, "Binding socket (%s) (%d)", sa_un.sun_path, strlen(sock_name)); /* Which to use, AF_UNIX, PF_UNIX, AF_LOCAL, PF_LOCAL? */ if (bind(sock, (struct sockaddr *)&sa_un, strlen(sock_name) + sizeof(sa_un.sun_family))) { debug(LOG_ERR, "Could not bind internal socket: %s", strerror(errno)); return; } if (listen(sock, 5)) { debug(LOG_ERR, "Could not listen on internal socket: %s", strerror(errno)); return; } /* * The internal socket is ready, fork and exec ourselves */ debug(LOG_DEBUG, "Forking in preparation for exec()..."); pid = safe_fork(); if (pid > 0) { /* Parent */ /* Wait for the child to connect to our socket :*/ debug(LOG_DEBUG, "Waiting for child to connect on internal socket"); len = sizeof(sa_un); if ((fd = accept(sock, (struct sockaddr *)&sa_un, &len)) == -1){ debug(LOG_ERR, "Accept failed on internal socket: %s", strerror(errno)); close(sock); return; } close(sock); debug(LOG_DEBUG, "Received connection from child. Sending them all existing clients"); /* The child is connected. Send them over the socket the existing clients */ LOCK_CLIENT_LIST(); client = client_get_first_client(); while (client) { /* Send this client */ safe_asprintf(&tempstring, "CLIENT|ip=%s|mac=%s|token=%s|fw_connection_state=%u|fd=%d|counters_incoming=%llu|counters_outgoing=%llu|counters_last_updated=%lu\n", client->ip, client->mac, client->token, client->fw_connection_state, client->fd, client->counters.incoming, client->counters.outgoing, client->counters.last_updated); debug(LOG_DEBUG, "Sending to child client data: %s", tempstring); len = 0; while (len != strlen(tempstring)) { written = write(fd, (tempstring + len), strlen(tempstring) - len); if (written == -1) { debug(LOG_ERR, "Failed to write client data to child: %s", strerror(errno)); free(tempstring); break; } else { len += written; } } free(tempstring); client = client->next; } UNLOCK_CLIENT_LIST(); close(fd); debug(LOG_INFO, "Sent all existing clients to child. Committing suicide!"); shutdown(afd, 2); close(afd); /* Our job in life is done. Commit suicide! */ wdctl_stop(afd); } else { /* Child */ close(wdctl_socket_server); close(icmp_fd); close(sock); shutdown(afd, 2); close(afd); debug(LOG_NOTICE, "Re-executing myself (%s)", restartargv[0]); setsid(); execvp(restartargv[0], restartargv); /* If we've reached here the exec() failed - die quickly and silently */ debug(LOG_ERR, "I failed to re-execute myself: %s", strerror(errno)); debug(LOG_ERR, "Exiting without cleanup"); exit(1); } }
/* * @return A string containing human-readable status text. MUST BE free()d by caller */ char * get_status_text() { char buffer[STATUS_BUF_SIZ]; ssize_t len; s_config *config; t_auth_serv *auth_server; t_client *first; int count; unsigned long int uptime = 0; unsigned int days = 0, hours = 0, minutes = 0, seconds = 0; t_trusted_mac *p; len = 0; snprintf(buffer, (sizeof(buffer) - len), "WiFiDog status\n\n"); len = strlen(buffer); uptime = time(NULL) - started_time; days = uptime / (24 * 60 * 60); uptime -= days * (24 * 60 * 60); hours = uptime / (60 * 60); uptime -= hours * (60 * 60); minutes = uptime / 60; uptime -= minutes * 60; seconds = uptime; snprintf((buffer + len), (sizeof(buffer) - len), "Version: " VERSION "\n"); len = strlen(buffer); snprintf((buffer + len), (sizeof(buffer) - len), "Uptime: %ud %uh %um %us\n", days, hours, minutes, seconds); len = strlen(buffer); snprintf((buffer + len), (sizeof(buffer) - len), "Has been restarted: "); len = strlen(buffer); if (restart_orig_pid) { snprintf((buffer + len), (sizeof(buffer) - len), "yes (from PID %d)\n", restart_orig_pid); len = strlen(buffer); } else { snprintf((buffer + len), (sizeof(buffer) - len), "no\n"); len = strlen(buffer); } snprintf((buffer + len), (sizeof(buffer) - len), "Internet Connectivity: %s\n", (is_online() ? "yes" : "no")); len = strlen(buffer); snprintf((buffer + len), (sizeof(buffer) - len), "Auth server reachable: %s\n", (is_auth_online() ? "yes" : "no")); len = strlen(buffer); snprintf((buffer + len), (sizeof(buffer) - len), "Clients served this session: %lu\n\n", served_this_session); len = strlen(buffer); LOCK_CLIENT_LIST(); first = client_get_first_client(); if (first == NULL) { count = 0; } else { count = 1; while (first->next != NULL) { first = first->next; count++; } } snprintf((buffer + len), (sizeof(buffer) - len), "%d clients " "connected.\n", count); len = strlen(buffer); first = client_get_first_client(); count = 0; while (first != NULL) { snprintf((buffer + len), (sizeof(buffer) - len), "\nClient %d\n", count); len = strlen(buffer); snprintf((buffer + len), (sizeof(buffer) - len), " IP: %s MAC: %s\n", first->ip, first->mac); len = strlen(buffer); snprintf((buffer + len), (sizeof(buffer) - len), " Token: %s\n", first->token); len = strlen(buffer); snprintf((buffer + len), (sizeof(buffer) - len), " Downloaded: %llu\n Uploaded: %llu\n" , first->counters.incoming, first->counters.outgoing); len = strlen(buffer); count++; first = first->next; } UNLOCK_CLIENT_LIST(); config = config_get_config(); if (config->trustedmaclist != NULL) { snprintf((buffer + len), (sizeof(buffer) - len), "\nTrusted MAC addresses:\n"); len = strlen(buffer); for (p = config->trustedmaclist; p != NULL; p = p->next) { snprintf((buffer + len), (sizeof(buffer) - len), " %s\n", p->mac); len = strlen(buffer); } } snprintf((buffer + len), (sizeof(buffer) - len), "\nAuthentication servers:\n"); len = strlen(buffer); LOCK_CONFIG(); for (auth_server = config->auth_servers; auth_server != NULL; auth_server = auth_server->next) { snprintf((buffer + len), (sizeof(buffer) - len), " Host: %s (%s)\n", auth_server->authserv_hostname, auth_server->last_ip); len = strlen(buffer); } UNLOCK_CONFIG(); return safe_strdup(buffer); }
/* @internal * @brief During gateway restart, connects to the parent process via the internal socket * Downloads from it the active client list */ void get_clients_from_parent(void) { int sock; struct sockaddr_un sa_un; s_config * config = NULL; char linebuffer[MAX_BUF]; int len = 0; char *running1 = NULL; char *running2 = NULL; char *token1 = NULL; char *token2 = NULL; char onechar; char *command = NULL; char *key = NULL; char *value = NULL; t_client * client = NULL; t_client * lastclient = NULL; config = config_get_config(); debug(LOG_INFO, "Connecting to parent to download clients"); /* Connect to socket */ sock = socket(AF_UNIX, SOCK_STREAM, 0); memset(&sa_un, 0, sizeof(sa_un)); sa_un.sun_family = AF_UNIX; strncpy(sa_un.sun_path, config->internal_sock, (sizeof(sa_un.sun_path) - 1)); if (connect(sock, (struct sockaddr *)&sa_un, strlen(sa_un.sun_path) + sizeof(sa_un.sun_family))) { debug(LOG_ERR, "Failed to connect to parent (%s) - client list not downloaded", strerror(errno)); return; } debug(LOG_INFO, "Connected to parent. Downloading clients"); LOCK_CLIENT_LIST(); command = NULL; memset(linebuffer, 0, sizeof(linebuffer)); len = 0; client = NULL; /* Get line by line */ while (read(sock, &onechar, 1) == 1) { if (onechar == '\n') { /* End of line */ onechar = '\0'; } linebuffer[len++] = onechar; if (!onechar) { /* We have a complete entry in linebuffer - parse it */ debug(LOG_DEBUG, "Received from parent: [%s]", linebuffer); running1 = linebuffer; while ((token1 = strsep(&running1, "|")) != NULL) { if (!command) { /* The first token is the command */ command = token1; } else { /* Token1 has something like "foo=bar" */ running2 = token1; key = value = NULL; while ((token2 = strsep(&running2, "=")) != NULL) { if (!key) { key = token2; } else if (!value) { value = token2; } } } if (strcmp(command, "CLIENT") == 0) { /* This line has info about a client in the client list */ if (!client) { /* Create a new client struct */ client = safe_malloc(sizeof(t_client)); memset(client, 0, sizeof(t_client)); } } if (key && value) { if (strcmp(command, "CLIENT") == 0) { /* Assign the key into the appropriate slot in the connection structure */ if (strcmp(key, "ip") == 0) { client->ip = safe_strdup(value); } else if (strcmp(key, "mac") == 0) { client->mac = safe_strdup(value); } else if (strcmp(key, "token") == 0) { client->token = safe_strdup(value); } else if (strcmp(key, "fw_connection_state") == 0) { client->fw_connection_state = atoi(value); } else if (strcmp(key, "fd") == 0) { client->fd = atoi(value); } else if (strcmp(key, "counters_incoming") == 0) { client->counters.incoming_history = atoll(value); client->counters.incoming = client->counters.incoming_history; } else if (strcmp(key, "counters_outgoing") == 0) { client->counters.outgoing_history = atoll(value); client->counters.outgoing = client->counters.outgoing_history; } else if (strcmp(key, "counters_last_updated") == 0) { client->counters.last_updated = atol(value); } else { debug(LOG_NOTICE, "I don't know how to inherit key [%s] value [%s] from parent", key, value); } } } } /* End of parsing this command */ if (client) { /* Add this client to the client list */ if (!firstclient) { firstclient = client; lastclient = firstclient; } else { lastclient->next = client; lastclient = client; } } /* Clean up */ command = NULL; memset(linebuffer, 0, sizeof(linebuffer)); len = 0; client = NULL; } } UNLOCK_CLIENT_LIST(); debug(LOG_INFO, "Client list downloaded successfully from parent"); close(sock); }
/** 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; }
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; }