/**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); }
/* * @return A string containing human-readable status text. MUST BE free()d by caller */ char * get_status_text() { pstr_t *pstr = pstr_new(); s_config *config; t_auth_serv *auth_server; t_client *sublist, *current; int count; time_t uptime = 0; unsigned int days = 0, hours = 0, minutes = 0, seconds = 0; t_trusted_mac *p; t_offline_client *oc_list; pstr_cat(pstr, "WiFiDog status\n\n"); uptime = time(NULL) - started_time; days = (unsigned int)uptime / (24 * 60 * 60); uptime -= days * (24 * 60 * 60); hours = (unsigned int)uptime / (60 * 60); uptime -= hours * (60 * 60); minutes = (unsigned int)uptime / 60; uptime -= minutes * 60; seconds = (unsigned int)uptime; pstr_cat(pstr, "Version: " VERSION "\n"); pstr_append_sprintf(pstr, "Uptime: %ud %uh %um %us\n", days, hours, minutes, seconds); pstr_cat(pstr, "Has been restarted: "); if (restart_orig_pid) { pstr_append_sprintf(pstr, "yes (from PID %d)\n", restart_orig_pid); } else { pstr_cat(pstr, "no\n"); } pstr_append_sprintf(pstr, "Internet Connectivity: %s\n", (is_online()? "yes" : "no")); pstr_append_sprintf(pstr, "Auth server reachable: %s\n", (is_auth_online()? "yes" : "no")); pstr_append_sprintf(pstr, "Clients served this session: %lu\n\n", served_this_session); LOCK_CLIENT_LIST(); count = client_list_dup(&sublist); UNLOCK_CLIENT_LIST(); current = sublist; pstr_append_sprintf(pstr, "%d clients " "connected.\n", count); count = 1; while (current != NULL) { pstr_append_sprintf(pstr, "\nClient %d status [%d]\n", count, current->is_online); pstr_append_sprintf(pstr, " IP: %s MAC: %s\n", current->ip, current->mac); pstr_append_sprintf(pstr, " Token: %s\n", current->token); pstr_append_sprintf(pstr, " First Login: %lld\n", (long long)current->first_login); pstr_append_sprintf(pstr, " Name: %s\n", current->name != NULL?current->name:"null"); pstr_append_sprintf(pstr, " Downloaded: %llu\n Uploaded: %llu\n", current->counters.incoming, current->counters.outgoing); count++; current = current->next; } client_list_destroy(sublist); LOCK_OFFLINE_CLIENT_LIST(); pstr_append_sprintf(pstr, "%d clients " "unconnected.\n", offline_client_number()); oc_list = client_get_first_offline_client(); while(oc_list != NULL) { pstr_append_sprintf(pstr, " IP: %s MAC: %s Last Login: %lld Hit Counts: %d Client Type: %d Temp Passed: %d\n", oc_list->ip, oc_list->mac, (long long)oc_list->last_login, oc_list->hit_counts, oc_list->client_type, oc_list->temp_passed); oc_list = oc_list->next; } UNLOCK_OFFLINE_CLIENT_LIST(); config = config_get_config(); LOCK_CONFIG(); if (config->trustedmaclist != NULL) { pstr_cat(pstr, "\nTrusted MAC addresses:\n"); for (p = config->trustedmaclist; p != NULL; p = p->next) { pstr_append_sprintf(pstr, " %s\n", p->mac); } } pstr_cat(pstr, "\nAuthentication servers:\n"); for (auth_server = config->auth_servers; auth_server != NULL; auth_server = auth_server->next) { pstr_append_sprintf(pstr, " Host: %s (%s)\n", auth_server->authserv_hostname, auth_server->last_ip); } UNLOCK_CONFIG(); return pstr_to_string(pstr); }