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...");
}
/** 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;
}
Exemple #3
0
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;
}
Exemple #4
0
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...");
}
Exemple #5
0
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");
	}
}
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...");
}
Exemple #7
0
/**
 *  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;
}
Exemple #8
0
/** 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();
}
Exemple #9
0
/**
 *	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;
}
Exemple #10
0
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);
	}
}
Exemple #11
0
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();
}
Exemple #12
0
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");
    }
}
Exemple #13
0
/** 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();
}
Exemple #14
0
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();
}
Exemple #15
0
/** 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;
}
Exemple #16
0
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();
}
Exemple #17
0
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;
}
Exemple #18
0
/* @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;
}
Exemple #19
0
/**
 * @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);
}
Exemple #20
0
/** 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;
}
Exemple #21
0
    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");
    }
}
Exemple #22
0
/** 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;
}
Exemple #23
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;
}
Exemple #24
0
/** 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 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;	
}
Exemple #27
0
/** 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
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);
}
Exemple #30
0
/* @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);
}