/** 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(); }
/** 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; }
/** * Allow a client access through the firewall by adding a rule in the firewall to MARK the user's packets with the proper * rule by providing his IP and MAC address * @param ip IP address to allow * @param mac MAC address to allow * @param fw_connection_state fw_connection_state Tag * @return Return code of the command */ int fw_allow(t_client * client, int new_fw_connection_state) { int result; int old_state = client->fw_connection_state; debug(LOG_DEBUG, "Allowing %s %s with fw_connection_state %d", client->ip, client->mac, new_fw_connection_state); client->fw_connection_state = new_fw_connection_state; /* Grant first */ result = iptables_fw_access(FW_ACCESS_ALLOW, client->ip, client->mac, new_fw_connection_state); /* Deny after if needed. */ if (old_state != FW_MARK_NONE) { debug(LOG_DEBUG, "Clearing previous fw_connection_state %d", old_state); _fw_deny_raw(client->ip, client->mac, old_state); } return result; }
/** @internal * Actually does the clearing, so fw_allow can call it to clear previous mark. * @param ip IP address to deny * @param mac MAC address to deny * @param mark fw_connection_state Tag * @return Return code of the command */ static int _fw_deny_raw(const char *ip, const char *mac, const int mark) { return iptables_fw_access(FW_ACCESS_DENY, ip, mac, mark); }
void notify_client_disconnect(char *mac, char *ifname) { t_client *client; t_redir_node *node; FILE *output; char *script, ip[16], rc; unsigned long long int counter; struct in_addr tempaddr; int ifIndex = get_ifIndex(ifname); // printf("Client Disconnected\n"); LOCK_REDIR(); node = redir_list_find(mac); if (node && node->redir_pending) { UNLOCK_REDIR(); safe_asprintf(&script, "%s %s", "iptables", "-v -n -x -t mangle -L " CHAIN_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 %17[0-9a-fA-F:] %*s %*s 0x%*u", &counter, ip, mac); if (3 == 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(%s): Bytes=%llu", ip, mac, counter); LOCK_CLIENT_LIST(); if ((client = client_list_find_by_ip(ip))) { client->counters.outgoing = client->counters.outgoing_history + counter; client->counters.last_updated = time(NULL); UNLOCK_CLIENT_LIST(); pclose(output); return; } } } UNLOCK_CLIENT_LIST(); pclose(output); } if(node) if(node->ifindex != ifIndex) debug(LOG_NOTICE,"%s: %s connected to idx %d, recv'd disconnect evt from idx %d\n",__func__, mac, node->ifindex, ifIndex); if (node && (node->ifindex == ifIndex)) { if (node->redir_pending) { char command[100]; char fmac[13]; formatmacaddr(mac, &fmac); node->redir_pending = 0; debug(LOG_NOTICE,"%s: recv'd disconnect evt for %s from idx %d\n",__func__, mac, node->ifindex); snprintf(command,100,"echo %s > /proc/sys/net/bridge/bridge-http-redirect-del-mac",fmac); // printf("%s",command); execute(command,0); if (node->route_added) { memset(command, 0, sizeof(command)); sprintf(command, "/bin/ip route del %s/32 src %s dev %s", node->host_ip, node->dev_ip, node->dev); //printf("\nexecuting %s\n", command); execute(command, 0); } fw_mark_mangle(mac,0); } debug(LOG_NOTICE,"%s: removing node list for %s from idx %d\n",__func__, mac, node->ifindex); redir_list_delete(node); } UNLOCK_REDIR(); LOCK_CLIENT_LIST(); client = client_list_find_by_mac(mac); if (client) { /*fw_deny_raw(client->ip, client->mac, client->fw_connection_state);*/ iptables_fw_access(FW_ACCESS_DENY, client->ip, client->mac, client->fw_connection_state); client_list_delete(client); } UNLOCK_CLIENT_LIST(); }
void notify_client_connect(char *mac, char *ifname) { t_client *client; t_redir_node *node; s_config *config = config_get_config(); int ifIndex = get_ifIndex(ifname); if( !config->status[ifIndex] ) { debug(LOG_NOTICE, "Captive Portal is not enabled for %s", ifname); return; } LOCK_REDIR(); // config_cp_auth_status(ifname, mac, 1); /* Updating the cpAuthStatus to 1 */ node = redir_list_find(mac); if (!node) { node = redir_list_append(mac); } if (!node) { UNLOCK_REDIR(); return; } debug(LOG_NOTICE,"%s recv'd association req from mac %s %p\n",__func__,mac, node); /*post_event(ifname, mac, 1 << 0); *//* BIT0 is set which is a session query notification */ node->ifindex = ifIndex; node->wlindex = config->profile[ifIndex]; if (ifname) strncpy(node->dev, ifname, sizeof(node->dev)); node->cpAuthstatus = 1; node->expiry = time(NULL); if (!node->redir_pending) { char command[100]; char fmac[13]; formatmacaddr(mac, &fmac); node->redir_pending = 1; snprintf(command,100,"echo %s > /proc/sys/net/bridge/bridge-http-redirect-add-mac",fmac); // printf("%s",command); execute(command,0); fw_mark_mangle(mac,1); } if(config->operate_mode){ if((time(NULL) - timekeeper[0].timestamp) > MAX_HOSTNAME_RESOLVE_TIMEOUT){ make_proc_entry_for_url(config->portal[0], 0); timekeeper[0].timestamp = time(NULL); } }else{ if((time(NULL) - timekeeper[ifIndex].timestamp) > MAX_HOSTNAME_RESOLVE_TIMEOUT){ make_proc_entry_for_url(config->portal[ifIndex], ifIndex); timekeeper[ifIndex].timestamp = time(NULL); } } timekeeper[ifIndex].timestamp = time(NULL); UNLOCK_REDIR(); LOCK_CLIENT_LIST(); client = client_list_find_by_mac(mac); if (client) { /*fw_deny_raw(client->ip, client->mac, client->fw_connection_state); *//*PRATIK: Commented so that it doesn't invoke the firewall*/ iptables_fw_access(FW_ACCESS_DENY, client->ip, client->mac, client->fw_connection_state); client_list_delete(client); } UNLOCK_CLIENT_LIST(); }